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":"typion-Dh2BCSRz.js","names":[],"sources":["../src/runtime/dialect/pg.ts","../src/runtime/constants.ts","../src/runtime/read/virtual-table.ts","../src/runtime/read/compose.ts","../src/runtime/read/find.ts","../src/runtime/write/bulk.ts","../src/runtime/write/links.ts","../src/runtime/execute.ts","../src/runtime/engine.ts","../src/runtime/typion.ts"],"sourcesContent":["import { type SQL, sql } from 'drizzle-orm'\nimport { type AnyPgColumn, getTableConfig, type PgTable } from 'drizzle-orm/pg-core'\nimport {\n BadRequestError,\n ConflictError,\n type TypionError,\n InternalError,\n ValidationError,\n} from '../../errors.js'\nimport type { Dialect, SchemaDrift } from '../../types/dialect.js'\nimport type { AnyDb, AnyTx } from '../../types/runtime.js'\n\n// A quoted literal rather than a bind parameter: an expression index on `col->>'it'` only serves queries\n// that spell the same key as a constant. Keys come from plugin configuration (the locales), not from input.\nfunction keyLiteral(key: string): SQL {\n return sql.raw(`'${key.replace(/'/g, \"''\")}'`)\n}\n\nconst CAST_NAME = /^[a-z_][a-z0-9_ ]*(\\([0-9, ]*\\))?$/i\nconst SQLSTATE = /^[0-9A-Z]{5}$/\n\ntype PgErrorLike = {\n code: string\n message?: string\n constraint?: string\n column?: string\n table?: string\n detail?: string\n}\n\n// The SQLSTATE lives on the driver error (`cause.code` for pg, pglite and postgres-js); drizzle\n// wraps it in a DrizzleQueryError, so the cause chain is walked instead of matching a class.\nfunction findPgError(error: unknown): PgErrorLike | null {\n let current: unknown = error\n for (let depth = 0; depth < 8 && typeof current === 'object' && current !== null; depth++) {\n const code = (current as { code?: unknown }).code\n if (typeof code === 'string' && SQLSTATE.test(code)) return current as PgErrorLike\n current = (current as { cause?: unknown }).cause\n }\n return null\n}\n\nfunction isQueryError(error: unknown): boolean {\n return (\n error instanceof Error &&\n typeof (error as { query?: unknown }).query === 'string' &&\n Array.isArray((error as { params?: unknown }).params)\n )\n}\n\nfunction mapSqlState(pg: PgErrorLike, cause: unknown): TypionError {\n const message = pg.message ?? 'Database error'\n const details = { sqlstate: pg.code, table: pg.table, constraint: pg.constraint }\n switch (pg.code) {\n case '23505':\n return new ConflictError(message, 'unique', { constraint: pg.constraint, details, cause })\n case '23503':\n return new ConflictError(message, 'foreign_key', {\n constraint: pg.constraint,\n details,\n cause,\n })\n case '23514':\n return new ConflictError(message, 'check', { constraint: pg.constraint, details, cause })\n case '23502':\n return new ValidationError(\n message,\n [{ path: pg.column === undefined ? [] : [pg.column], message: 'must not be null' }],\n { details, cause },\n )\n case '40001':\n return new ConflictError(message, 'serialization', { details, cause })\n case '40P01':\n return new ConflictError(message, 'deadlock', { details, cause })\n case '22P02':\n case '22007':\n return new BadRequestError(message, { details, cause })\n default:\n return new InternalError('Database error', { details, cause })\n }\n}\n\nfunction qualifiedName(table: PgTable): { schema: string; name: string; label: string } {\n const config = getTableConfig(table)\n const schema = config.schema ?? 'public'\n return {\n schema,\n name: config.name,\n label: schema === 'public' ? config.name : `${schema}.${config.name}`,\n }\n}\n\nexport function createPgDialect(): Dialect {\n return {\n id: 'pg',\n\n jsonText(column, key) {\n return sql`${column}->>${keyLiteral(key)}`\n },\n\n cast(value, type) {\n if (!CAST_NAME.test(type)) throw new InternalError(`cast: '${type}' is not a type name`)\n return sql`(${value})::${sql.raw(type)}`\n },\n\n jsonbMerge(column, patch) {\n return sql`${column} || ${sql.param(patch, column)}`\n },\n\n jsonParam(value, column) {\n return sql`${sql.param(value, column)}`\n },\n\n async lockSelect(tx: AnyTx, table: PgTable, where: SQL | undefined) {\n const rows = await tx.select().from(table).where(where).for('update')\n return rows as Record<string, unknown>[]\n },\n\n mapError(error) {\n const pg = findPgError(error)\n if (pg !== null) return mapSqlState(pg, error)\n if (isQueryError(error)) return new InternalError('Database error', { cause: error })\n return null\n },\n\n async introspect(db: AnyDb, tables: readonly PgTable[]): Promise<SchemaDrift> {\n const drift: SchemaDrift = { missingTables: [], missingColumns: [] }\n if (tables.length === 0) return drift\n const names = tables.map(qualifiedName)\n const matches = names.map((t) => sql`(table_schema = ${t.schema} and table_name = ${t.name})`)\n const rows = await db\n .select({\n schema: sql<string>`table_schema`,\n table: sql<string>`table_name`,\n column: sql<string>`column_name`,\n })\n .from(sql`information_schema.columns`)\n .where(sql.join(matches, sql` or `))\n const present = new Map<string, Set<string>>()\n for (const row of rows) {\n const key = `${row.schema}.${row.table}`\n const columns = present.get(key) ?? new Set<string>()\n columns.add(row.column)\n present.set(key, columns)\n }\n tables.forEach((table, i) => {\n const name = names[i] as (typeof names)[number]\n const columns = present.get(`${name.schema}.${name.name}`)\n if (columns === undefined) {\n drift.missingTables.push(name.label)\n return\n }\n const missing = getTableConfig(table)\n .columns.map((c: AnyPgColumn) => c.name)\n .filter((c) => !columns.has(c))\n if (missing.length > 0) drift.missingColumns.push({ table: name.label, columns: missing })\n })\n return drift\n },\n }\n}\n","export const QUERY_CONFIG_KEYS = new Set([\n 'columns',\n 'with',\n 'where',\n 'extras',\n 'orderBy',\n 'offset',\n 'limit',\n 'comment',\n])\n","import type { AnyPgColumn } from 'drizzle-orm/pg-core'\nimport type { Dialect } from '../../types/dialect.js'\nimport type { EntityMeta } from '../../types/meta.js'\nimport { type KindStates, kindExpression } from './kinds.js'\n\n// Callbacks are typed against the virtual schema (a kind column has its filter type, a hidden column does\n// not exist), so the table handed to them at runtime must agree: kind columns become their kind's\n// expression and hidden columns disappear (ADR-013).\nexport function virtualTable<T extends object>(\n table: T,\n entity: EntityMeta | null,\n dialect: Dialect,\n kinds: KindStates,\n): T {\n if (entity === null) return table\n const rewritten = new Set(\n entity.kindKeys.filter((k) => entity.columns[k]?.columnKind?.expression !== undefined),\n )\n const hidden = new Set(\n Object.keys(entity.columns).filter((k) => entity.columns[k]?.read === false),\n )\n if (rewritten.size === 0 && hidden.size === 0) return table\n return new Proxy(table, {\n get(target, key, receiver) {\n if (typeof key === 'string') {\n if (hidden.has(key)) return undefined\n if (rewritten.has(key)) {\n const column = Reflect.get(target, key, receiver) as AnyPgColumn\n return kindExpression(entity.columns[key]?.columnKind, column, kinds, dialect, null)\n }\n }\n return Reflect.get(target, key, receiver)\n },\n })\n}\n","import { getTableColumns, type SQL } from 'drizzle-orm'\nimport type { PgTable } from 'drizzle-orm/pg-core'\nimport { BadRequestError, ForbiddenError, InternalError } from '../../errors.js'\nimport type { OperationMeta } from '../../types/access.js'\nimport type { ColumnKindRuntime } from '../../types/kinds.js'\nimport type { EntityMeta } from '../../types/meta.js'\nimport {\n evaluateRule,\n fieldReadDenied,\n forbidden,\n pluginFilter,\n READING,\n type TraitOptionValues,\n} from '../access.js'\nimport { QUERY_CONFIG_KEYS } from '../constants.js'\nimport { andFilters, FALSE_FILTER, type Filter, isPlainObject } from '../filters.js'\nimport type { InternalBound, Runtime } from '../internals.js'\nimport { type KindStates, kindExpression, kindFilterSQL, pluginOptions } from './kinds.js'\nimport { virtualTable } from './virtual-table.js'\n\n// A table a plugin swapped in for the root of a read (the draft perspective of versions).\nexport interface SwappedSource {\n readonly plugin: string\n readonly key: string\n readonly filter: Filter | undefined\n readonly rule: string\n}\n\nexport interface ReadRequest {\n readonly runtime: Runtime\n readonly bound: InternalBound\n readonly meta: OperationMeta\n readonly kinds: KindStates\n // The trait plugins' read options of the root, which every level of the read applies.\n readonly traitOptions: TraitOptionValues\n readonly source: SwappedSource | null\n}\n\nexport interface ProjectionPlan {\n // Columns of this level whose kind projects the stored value.\n readonly kinds: readonly (readonly [string, ColumnKindRuntime])[]\n readonly nullify: readonly string[]\n readonly with: Readonly<Record<string, ProjectionPlan>>\n}\n\nexport interface CompiledLevel {\n readonly config: Record<string, unknown>\n readonly plan: ProjectionPlan\n}\n\nexport interface Source {\n readonly key: string\n readonly table: PgTable\n}\n\ntype AnyCallback = (table: unknown, operators: unknown) => unknown\n\nfunction projectedKinds(entity: EntityMeta | null): (readonly [string, ColumnKindRuntime])[] {\n const out: (readonly [string, ColumnKindRuntime])[] = []\n for (const key of entity?.kindKeys ?? []) {\n const kind = entity?.columns[key]?.columnKind\n if (kind?.project !== undefined) out.push([key, kind])\n }\n return out\n}\n\n// The first plugin acting on the entity that answers decides where the root of the read comes from.\nexport function swappedSource(\n entity: EntityMeta,\n runtime: Runtime,\n bound: InternalBound,\n meta: OperationMeta,\n options: TraitOptionValues,\n): SwappedSource | null {\n for (const plugin of runtime.plugins) {\n const source = plugin.traits?.source\n const trait = entity.traits[plugin.id]\n if (source === undefined || trait === undefined) continue\n const swapped = source({\n entity,\n state: trait.state,\n operation: meta.operation,\n options: options.get(plugin.id) ?? {},\n ctx: bound.ctx,\n })\n if (swapped === undefined) continue\n if (runtime.relations[swapped.table] === undefined) {\n throw new InternalError(\n `Plugin '${plugin.id}' reads '${entity.name}' from '${swapped.table}', which is not a table of the engine`,\n { entity: entity.name },\n )\n }\n return {\n plugin: plugin.id,\n key: swapped.table,\n filter: swapped.filter as Filter | undefined,\n rule: swapped.rule ?? 'read',\n }\n }\n return null\n}\n\nexport function sourceOf(\n entity: EntityMeta,\n runtime: Runtime,\n swapped: SwappedSource | null,\n): Source {\n if (swapped === null) return { key: entity.name, table: entity.table }\n return { key: swapped.key, table: runtime.relations[swapped.key]?.table as PgTable }\n}\n\n// One composer per read operation: rule outcomes are memoized per target so a relation reached through\n// several paths evaluates its access rule once.\nexport class Composer {\n private readonly nested = new Map<string, Promise<Filter | undefined>>()\n private readonly readOptions: ReadonlySet<string>\n\n constructor(private readonly req: ReadRequest) {\n this.readOptions = new Set(pluginOptions(req.runtime.plugins).read.keys())\n }\n\n async rootFilter(entity: EntityMeta): Promise<Filter | undefined> {\n const { bound, meta, traitOptions, source } = this.req\n const rule = source?.rule ?? 'read'\n const outcome = await evaluateRule(entity, rule, bound, meta)\n if (outcome.kind === 'deny') {\n throw forbidden(entity.name, rule, meta, `access.${rule} denies '${meta.operation}'`)\n }\n return andFilters([\n pluginFilter(entity, bound, meta.operation, traitOptions, {\n writing: false,\n skip: source?.plugin,\n }),\n source?.filter,\n outcome.kind === 'filter' ? outcome.filter : undefined,\n ])\n }\n\n nestedFilter(tableName: string): Promise<Filter | undefined> {\n let pending = this.nested.get(tableName)\n if (pending === undefined) {\n pending = this.computeNested(tableName)\n this.nested.set(tableName, pending)\n }\n return pending\n }\n\n private async computeNested(tableName: string): Promise<Filter | undefined> {\n const { runtime, bound, meta, traitOptions } = this.req\n const entity = runtime.entityOrNull(tableName)\n if (entity === null) {\n if (bound.$mode === 'system') return undefined\n throw new ForbiddenError(\n `Table '${tableName}' is not an entity: user-mode reads cannot reach it through a relation`,\n { operation: meta.operation, rule: 'entity' },\n )\n }\n const outcome = await evaluateRule(entity, 'read', bound, meta)\n if (outcome.kind === 'deny') return FALSE_FILTER\n return andFilters([\n pluginFilter(entity, bound, meta.operation, traitOptions, READING),\n outcome.kind === 'filter' ? outcome.filter : undefined,\n ])\n }\n\n async compileRoot(\n entity: EntityMeta,\n config: Record<string, unknown>,\n injected: Filter | undefined,\n ): Promise<CompiledLevel & { source: Source; where: Filter | undefined }> {\n const source = sourceOf(entity, this.req.runtime, this.req.source)\n const parts = andFilters([await this.rootFilter(entity), injected])\n const level = await this.compileLevel(source.key, entity, config, parts, 'root')\n const where = level.config.where as Filter | undefined\n return { ...level, source, where }\n }\n\n async compileWhere(\n entity: EntityMeta,\n where: unknown,\n injected: Filter | undefined,\n ): Promise<{ source: Source; where: Filter | undefined }> {\n const source = sourceOf(entity, this.req.runtime, this.req.source)\n const user =\n where === undefined ? undefined : await this.rewriteWhere(where, source.key, entity)\n return { source, where: andFilters([await this.rootFilter(entity), injected, user]) }\n }\n\n private async compileLevel(\n tableKey: string,\n entity: EntityMeta | null,\n raw: unknown,\n parts: Filter | undefined,\n level: 'root' | string,\n ): Promise<CompiledLevel> {\n const root = level === 'root'\n const cfg = raw === true ? {} : raw\n if (!isPlainObject(cfg)) {\n throw new BadRequestError(`with.${level} must be true or a query config object`)\n }\n for (const key of Object.keys(cfg)) {\n if (!QUERY_CONFIG_KEYS.has(key) && !(root && this.readOptions.has(key))) {\n throw new BadRequestError(`Unknown query option '${key}'${root ? '' : ` in with.${level}`}`)\n }\n }\n const { runtime, bound, meta } = this.req\n const out: Record<string, unknown> = {}\n for (const key of ['offset', 'limit', 'comment'] as const) {\n if (cfg[key] !== undefined) out[key] = cfg[key]\n }\n if (root && entity !== null) this.checkLimit(entity, cfg.limit)\n\n const swappedRoot = root && this.req.source !== null\n const columns = this.columnsFor(entity, cfg.columns, swappedRoot)\n if (columns !== undefined) out.columns = columns\n\n const userWhere =\n cfg.where === undefined ? undefined : await this.rewriteWhere(cfg.where, tableKey, entity)\n const where = andFilters([parts, userWhere])\n if (where !== undefined) out.where = where\n\n const orderBy = cfg.orderBy ?? (root ? (entity?.defaultOrder ?? undefined) : undefined)\n if (orderBy !== undefined) out.orderBy = this.rewriteOrderBy(orderBy, tableKey, entity)\n if (cfg.extras !== undefined) out.extras = this.wrapExtras(cfg.extras, entity)\n\n const withPlan: Record<string, ProjectionPlan> = {}\n if (cfg.with !== undefined) {\n if (!isPlainObject(cfg.with)) throw new BadRequestError('with must be an object')\n const relations = runtime.relations[tableKey]?.relations ?? {}\n const outWith: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(cfg.with)) {\n if (value === undefined || value === false) continue\n const relation = relations[key]\n if (relation === undefined) {\n throw new BadRequestError(`Unknown relation '${key}' on '${tableKey}'`)\n }\n const target = relation.targetTableName\n const compiled = await this.compileLevel(\n target,\n runtime.entityOrNull(target),\n value,\n await this.nestedFilter(target),\n key,\n )\n outWith[key] = compiled.config\n withPlan[key] = compiled.plan\n }\n out.with = outWith\n }\n\n return {\n config: out,\n plan: {\n kinds: projectedKinds(entity),\n nullify: entity === null ? [] : fieldReadDenied(entity, bound, meta),\n with: withPlan,\n },\n }\n }\n\n private checkLimit(entity: EntityMeta, limit: unknown) {\n if (limit === undefined) return\n if (typeof limit !== 'number' || !Number.isInteger(limit) || limit < 0) {\n throw new BadRequestError('limit must be a non-negative integer')\n }\n if (limit > entity.maxLimit) {\n throw new BadRequestError(\n `limit ${limit} exceeds the maximum of ${entity.maxLimit} for '${entity.name}'`,\n { entity: entity.name },\n )\n }\n }\n\n private columnKeys(tableKey: string, entity: EntityMeta | null): Set<string> {\n if (entity !== null) return new Set(Object.keys(entity.columns))\n const table = this.req.runtime.relations[tableKey]?.table as PgTable | undefined\n return new Set(table === undefined ? [] : Object.keys(getTableColumns(table)))\n }\n\n private hiddenKeys(entity: EntityMeta | null): string[] {\n if (entity === null) return []\n return Object.keys(entity.columns).filter((k) => entity.columns[k]?.read === false)\n }\n\n // Types drop hidden columns from the virtual schema, so the runtime must never return them: an absent\n // `columns` expands to the visible set, and a swapped source never leaks the columns of its own.\n private columnsFor(\n entity: EntityMeta | null,\n columns: unknown,\n swappedRoot: boolean,\n ): Record<string, boolean> | undefined {\n if (entity === null) return columns as Record<string, boolean> | undefined\n const hidden = this.hiddenKeys(entity)\n if (columns === undefined) {\n if (!swappedRoot && hidden.length === 0) return undefined\n return Object.fromEntries(entity.visibleKeys.map((k) => [k, true]))\n }\n if (!isPlainObject(columns)) throw new BadRequestError('columns must be an object')\n const entries = Object.entries(columns).filter(([, v]) => v !== undefined)\n for (const [key, value] of entries) {\n if (!(key in entity.columns)) {\n throw new BadRequestError(`Unknown column '${key}' on '${entity.name}'`, {\n entity: entity.name,\n })\n }\n if (typeof value !== 'boolean') throw new BadRequestError(`columns.${key} must be a boolean`)\n if (value && hidden.includes(key)) {\n throw new BadRequestError(`Column '${key}' of '${entity.name}' is not readable`, {\n entity: entity.name,\n })\n }\n }\n if (entries.some(([, v]) => v === true)) {\n return Object.fromEntries(entries.filter(([, v]) => v)) as Record<string, boolean>\n }\n const omitted = new Set([...entries.map(([k]) => k), ...hidden])\n return Object.fromEntries(\n entity.visibleKeys.filter((k) => !omitted.has(k)).map((k) => [k, true]),\n )\n }\n\n async rewriteWhere(where: unknown, tableKey: string, entity: EntityMeta | null): Promise<Filter> {\n if (!isPlainObject(where)) throw new BadRequestError('where must be an object')\n const { runtime } = this.req\n const columns = this.columnKeys(tableKey, entity)\n const relations = runtime.relations[tableKey]?.relations ?? {}\n const plain: Filter = {}\n const extra: Filter[] = []\n for (const [key, value] of Object.entries(where)) {\n if (value === undefined) continue\n if (key === 'AND' || key === 'OR') {\n if (!Array.isArray(value)) throw new BadRequestError(`where.${key} must be an array`)\n plain[key] = await Promise.all(value.map((v) => this.rewriteWhere(v, tableKey, entity)))\n } else if (key === 'NOT') {\n plain.NOT = await this.rewriteWhere(value, tableKey, entity)\n } else if (key === 'RAW') {\n plain.RAW =\n typeof value === 'function'\n ? (t: unknown, ops: unknown) => (value as AnyCallback)(this.virtual(t, entity), ops)\n : value\n } else if (columns.has(key)) {\n if (entity?.columns[key]?.read === false) {\n throw new BadRequestError(`Column '${key}' of '${entity.name}' is not readable`, {\n entity: entity.name,\n })\n }\n const kind = entity?.columns[key]?.columnKind\n if (kind?.expression !== undefined) {\n const { dialect } = runtime\n const { kinds } = this.req\n extra.push({\n RAW: (t: Record<string, unknown>) =>\n kindFilterSQL(\n (sample) => kindExpression(kind, t[key] as SQL, kinds, dialect, sample) as SQL,\n key,\n value,\n ),\n })\n } else {\n plain[key] = value\n }\n } else if (relations[key] !== undefined) {\n const target = (relations[key] as { targetTableName: string }).targetTableName\n const parts = await this.nestedFilter(target)\n if (value === true) {\n plain[key] = parts ?? true\n } else if (value === false) {\n if (parts === undefined) plain[key] = false\n else extra.push({ NOT: { [key]: parts } })\n } else if (isPlainObject(value)) {\n const inner = await this.rewriteWhere(value, target, runtime.entityOrNull(target))\n plain[key] = andFilters([parts, inner]) ?? {}\n } else {\n throw new BadRequestError(`where.${key} must be a boolean or a filter object`)\n }\n } else {\n throw new BadRequestError(`Unknown filter field '${key}' on '${tableKey}'`)\n }\n }\n return extra.length === 0 ? plain : { AND: [plain, ...extra] }\n }\n\n private rewriteOrderBy(orderBy: unknown, tableKey: string, entity: EntityMeta | null): unknown {\n if (typeof orderBy === 'function') {\n return (t: unknown, ops: unknown) => (orderBy as AnyCallback)(this.virtual(t, entity), ops)\n }\n if (!isPlainObject(orderBy))\n throw new BadRequestError('orderBy must be an object or a callback')\n const columns = this.columnKeys(tableKey, entity)\n const entries = Object.entries(orderBy).filter(([, v]) => v !== undefined)\n for (const [key, dir] of entries) {\n if (!columns.has(key) || entity?.columns[key]?.read === false) {\n throw new BadRequestError(`Cannot order '${tableKey}' by '${key}'`)\n }\n if (dir !== 'asc' && dir !== 'desc') {\n throw new BadRequestError(`orderBy.${key} must be 'asc' or 'desc'`)\n }\n }\n const rewritten = new Set(\n entries\n .map(([key]) => key)\n .filter((key) => entity?.columns[key]?.columnKind?.expression !== undefined),\n )\n if (rewritten.size === 0) return orderBy\n const { dialect } = this.req.runtime\n const { kinds } = this.req\n type Ops = { asc: (v: unknown) => SQL; desc: (v: unknown) => SQL }\n return (t: Record<string, unknown>, ops: Ops) =>\n entries.map(([key, dir]) => {\n const column = t[key] as SQL\n const target = rewritten.has(key)\n ? kindExpression(entity?.columns[key]?.columnKind, column, kinds, dialect, null)\n : column\n return dir === 'asc' ? ops.asc(target) : ops.desc(target)\n })\n }\n\n private wrapExtras(extras: unknown, entity: EntityMeta | null): Record<string, unknown> {\n if (!isPlainObject(extras)) throw new BadRequestError('extras must be an object')\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(extras)) {\n out[key] =\n typeof value === 'function'\n ? (t: unknown, ops: unknown) => (value as AnyCallback)(this.virtual(t, entity), ops)\n : value\n }\n return out\n }\n\n private virtual(table: unknown, entity: EntityMeta | null): unknown {\n return virtualTable(table as object, entity, this.req.runtime.dialect, this.req.kinds)\n }\n}\n","import type { RelationalQueryBuilder } from 'drizzle-orm/pg-core/query-builders/query'\nimport { BadRequestError, NotFoundError } from '../../errors.js'\nimport type { Operation } from '../../types/access.js'\nimport type { ColumnKindRuntime } from '../../types/kinds.js'\nimport type { EntityMeta } from '../../types/meta.js'\nimport type { Page } from '../../types/query.js'\nimport type { AnyRow } from '../../types/runtime.js'\nimport { filterToSQL } from '../access.js'\nimport { operationMeta } from '../context.js'\nimport { guard } from '../errors.js'\nimport { isPlainObject } from '../filters.js'\nimport type { InternalBound } from '../internals.js'\nimport { Composer, type ProjectionPlan, swappedSource } from './compose.js'\nimport { type KindStates, pluginOptions, projectCells, readStates, traitOptions } from './kinds.js'\n\ntype Builder = RelationalQueryBuilder<any, any>\n\ntype ParsedRead = {\n readonly composer: Composer\n readonly kinds: KindStates\n}\n\nfunction parseOptions(\n entity: EntityMeta,\n bound: InternalBound,\n operation: Operation,\n config: AnyRow,\n): ParsedRead {\n const { runtime } = bound\n const traits = traitOptions(entity, runtime.plugins, 'read', config)\n const kinds = readStates(runtime.plugins, bound.ctx, config)\n const meta = operationMeta(bound.ctx, entity.name, operation, runtime.now())\n const source = swappedSource(entity, runtime, bound, meta, traits)\n const composer = new Composer({ runtime, bound, meta, kinds, traitOptions: traits, source })\n return { composer, kinds }\n}\n\ntype Cell = { row: AnyRow; key: string; kind: ColumnKindRuntime }\n\n// Kind columns are collected at every level first and resolved per kind in one call; dynamically hidden\n// columns are nullified after, so a denied value never survives either way.\nfunction collect(\n rows: AnyRow[],\n plan: ProjectionPlan,\n cells: Cell[],\n hidden: { row: AnyRow; key: string }[],\n): void {\n for (const row of rows) {\n for (const [key, kind] of plan.kinds) {\n if (key in row) cells.push({ row, key, kind })\n }\n for (const key of plan.nullify) {\n if (key in row) hidden.push({ row, key })\n }\n for (const [key, sub] of Object.entries(plan.with)) {\n const value = row[key]\n if (Array.isArray(value)) collect(value as AnyRow[], sub, cells, hidden)\n else if (isPlainObject(value)) collect([value], sub, cells, hidden)\n }\n }\n}\n\nasync function project(rows: AnyRow[], plan: ProjectionPlan, kinds: KindStates): Promise<AnyRow[]> {\n const cells: Cell[] = []\n const hidden: { row: AnyRow; key: string }[] = []\n collect(rows, plan, cells, hidden)\n if (cells.length > 0) await projectCells(cells, kinds)\n for (const { row, key } of hidden) row[key] = null\n return rows\n}\n\nfunction builderFor(bound: InternalBound, key: string): Builder {\n return (bound.$executor.query as unknown as Record<string, Builder>)[key] as Builder\n}\n\nfunction assertConfig(config: unknown): AnyRow {\n if (config === undefined) return {}\n if (!isPlainObject(config)) throw new BadRequestError('The query config must be an object')\n return config\n}\n\nasync function runMany(\n entity: EntityMeta,\n bound: InternalBound,\n operation: Operation,\n config: AnyRow,\n injected?: Record<string, unknown>,\n): Promise<AnyRow[]> {\n const { composer, kinds } = parseOptions(entity, bound, operation, config)\n const compiled = await composer.compileRoot(entity, config, injected)\n const rows = (await builderFor(bound, compiled.source.key).findMany(\n compiled.config as never,\n )) as unknown as AnyRow[]\n return project(rows, compiled.plan, kinds)\n}\n\nexport async function find(entity: EntityMeta, bound: InternalBound, config: unknown) {\n await bound.runtime.ready()\n return guard(bound.runtime, () => runMany(entity, bound, 'find', assertConfig(config)))\n}\n\nexport async function findOne(\n entity: EntityMeta,\n bound: InternalBound,\n config: unknown,\n operation: Operation = 'findOne',\n injected?: Record<string, unknown>,\n): Promise<AnyRow | null> {\n await bound.runtime.ready()\n return guard(bound.runtime, async () => {\n const cfg = assertConfig(config)\n if (cfg.limit !== undefined) throw new BadRequestError(`'${operation}' does not accept a limit`)\n const { composer, kinds } = parseOptions(entity, bound, operation, cfg)\n const compiled = await composer.compileRoot(entity, cfg, injected)\n const row = (await builderFor(bound, compiled.source.key).findFirst(\n compiled.config as never,\n )) as unknown as AnyRow | undefined\n if (row === undefined) return null\n return (await project([row], compiled.plan, kinds))[0] ?? null\n })\n}\n\nexport async function findById(\n entity: EntityMeta,\n bound: InternalBound,\n id: unknown,\n config: unknown,\n): Promise<AnyRow> {\n if (id === undefined || id === null) throw new BadRequestError('findById needs an id')\n const cfg = assertConfig(config)\n if (cfg.where !== undefined || cfg.offset !== undefined) {\n throw new BadRequestError('findById does not accept where or offset')\n }\n const row = await findOne(entity, bound, cfg, 'findById', { [entity.pk.key]: { eq: id } })\n if (row === null) {\n throw new NotFoundError(`${entity.name} '${String(id)}' not found`, { entity: entity.name })\n }\n return row\n}\n\nasync function runCount(\n entity: EntityMeta,\n bound: InternalBound,\n operation: Operation,\n config: AnyRow,\n): Promise<number> {\n const { composer } = parseOptions(entity, bound, operation, config)\n const { source, where } = await composer.compileWhere(entity, config.where, undefined)\n const sqlWhere = filterToSQL(bound.runtime.relations, source.key, source.table, where)\n return Number(await bound.$executor.$count(source.table, sqlWhere))\n}\n\nexport async function count(\n entity: EntityMeta,\n bound: InternalBound,\n config: unknown,\n): Promise<number> {\n await bound.runtime.ready()\n return guard(bound.runtime, async () => {\n const cfg = assertConfig(config)\n const known = pluginOptions(bound.runtime.plugins).read\n for (const key of Object.keys(cfg)) {\n if (key !== 'where' && !known.has(key)) {\n throw new BadRequestError(`Unknown count option '${key}'`)\n }\n }\n return runCount(entity, bound, 'count', cfg)\n })\n}\n\nexport async function page(\n entity: EntityMeta,\n bound: InternalBound,\n config: unknown,\n): Promise<Page<AnyRow>> {\n await bound.runtime.ready()\n return guard(bound.runtime, async () => {\n const cfg = assertConfig(config)\n const limit = cfg.limit ?? entity.maxLimit\n const offset = cfg.offset ?? 0\n if (typeof offset !== 'number' || !Number.isInteger(offset) || offset < 0) {\n throw new BadRequestError('offset must be a non-negative integer')\n }\n const items = await runMany(entity, bound, 'page', { ...cfg, limit, offset })\n const counted: AnyRow = { where: cfg.where }\n for (const key of pluginOptions(bound.runtime.plugins).read.keys()) {\n counted[key] = cfg[key]\n }\n const total = await runCount(entity, bound, 'page', counted)\n return { items, total, limit: limit as number, offset, hasMore: offset + items.length < total }\n })\n}\n","import { asc } from 'drizzle-orm'\nimport type { AnyPgColumn } from 'drizzle-orm/pg-core'\nimport { BadRequestError } from '../../errors.js'\nimport type { Operation } from '../../types/access.js'\nimport type { EntityMeta } from '../../types/meta.js'\nimport type { AnyRow } from '../../types/runtime.js'\nimport {\n fieldWriteCheck,\n filterToSQL,\n NO_TRAIT_OPTIONS,\n pluginFilter,\n type TraitOptionValues,\n WRITING,\n} from '../access.js'\nimport { andFilters, isPlainObject } from '../filters.js'\nimport type { InternalBound } from '../internals.js'\nimport { Composer } from '../read/compose.js'\nimport { readStates, traitOptions, writeStates } from '../read/kinds.js'\nimport {\n assertOptions,\n deleteDocument,\n deleteOptionKeys,\n mergedOptions,\n partitionAllowance,\n referenceOptionKeys,\n updateDocument,\n writeOptionKeys,\n writeRule,\n} from './mutations.js'\nimport {\n afterOperation,\n beforeOperation,\n type OpScope,\n queueAfterCommit,\n runOperation,\n} from './pipeline.js'\nimport { assertData, assertScalars } from './validate.js'\n\nconst DEFAULT_MAX = 1000\n\nfunction maxOf(options: AnyRow): number {\n const max = options.max ?? DEFAULT_MAX\n if (typeof max !== 'number' || !Number.isInteger(max) || max < 1) {\n throw new BadRequestError('max must be a positive integer')\n }\n return max\n}\n\n// Matches are selected and locked up front under the same filters as a single-row write; each row then\n// runs the full per-row pipeline inside the one transaction, so the batch is all-or-nothing. The plugins'\n// options (a hard delete) apply to the relations the filter reaches as they do to the rows it matches.\nasync function lockMatches(\n scope: OpScope,\n where: unknown,\n rule: Record<string, unknown> | undefined,\n values: TraitOptionValues,\n max: number,\n): Promise<AnyRow[]> {\n const { entity, bound, meta } = scope\n if (!isPlainObject(where)) throw new BadRequestError('where must be an object')\n const composer = new Composer({\n runtime: bound.runtime,\n bound,\n meta,\n kinds: readStates(bound.runtime.plugins, bound.ctx, {}),\n traitOptions: values,\n source: null,\n })\n const filter = andFilters([\n pluginFilter(entity, bound, meta.operation, values, WRITING),\n rule,\n await composer.rewriteWhere(where, entity.name, entity),\n ])\n const sqlWhere = filterToSQL(bound.runtime.relations, entity.name, entity.table, filter)\n const pk = (entity.table as unknown as Record<string, AnyPgColumn>)[entity.pk.key] as AnyPgColumn\n const rows = (await scope.tx\n .select()\n .from(entity.table)\n .where(sqlWhere)\n .orderBy(asc(pk))\n .limit(max + 1)\n .for('update')) as AnyRow[]\n if (rows.length > max) {\n throw new BadRequestError(\n `${meta.operation} matches more than ${max} ${entity.name} rows; narrow the filter or raise max`,\n { entity: entity.name },\n )\n }\n return rows\n}\n\nexport async function updateMany(\n entity: EntityMeta,\n bound: InternalBound,\n where: unknown,\n input: unknown,\n rawOptions: unknown,\n): Promise<{ count: number }> {\n const data = assertData(input)\n assertScalars(entity, data)\n const options = assertOptions(rawOptions, [\n 'max',\n ...writeOptionKeys(bound),\n ...referenceOptionKeys(entity, bound),\n ])\n const max = maxOf(options)\n const states = writeStates(entity, bound.runtime.plugins, bound.ctx, options)\n return runOperation(bound, entity, 'updateMany', async (scope) => {\n await beforeOperation(scope, { where, data, options })\n const rule = await writeRule(scope, 'update', { data })\n const { allowed } = partitionAllowance(scope, data)\n fieldWriteCheck(entity, scope.bound, scope.meta, data, allowed)\n const rows = await lockMatches(scope, where, rule, NO_TRAIT_OPTIONS, max)\n for (const original of rows) {\n const { doc } = await updateDocument(scope, original, data, {\n states,\n op: 'update',\n options: NO_TRAIT_OPTIONS,\n withDeleted: options.withDeleted === true,\n })\n queueAfterCommit(scope, doc, original)\n }\n const result = { count: rows.length }\n await afterOperation(scope, result)\n return result\n })\n}\n\nexport async function deleteMany(\n entity: EntityMeta,\n bound: InternalBound,\n where: unknown,\n rawOptions: unknown,\n): Promise<{ count: number }> {\n const options = assertOptions(rawOptions, ['max', ...deleteOptionKeys(bound)])\n const max = maxOf(options)\n const values = traitOptions(entity, bound.runtime.plugins, 'delete', options)\n const operation: Operation = 'deleteMany'\n return runOperation(bound, entity, operation, async (scope) => {\n await beforeOperation(scope, { where, options })\n const rule = await writeRule(scope, 'delete', { options: mergedOptions(values) })\n const rows = await lockMatches(scope, where, rule, values, max)\n for (const original of rows) {\n const doc = await deleteDocument(scope, original, values)\n queueAfterCommit(scope, doc, original)\n }\n const result = { count: rows.length }\n await afterOperation(scope, result)\n return result\n })\n}\n","import { and, eq, getTableColumns, inArray } from 'drizzle-orm'\nimport type { AnyPgColumn, PgTable } from 'drizzle-orm/pg-core'\nimport { BadRequestError, InternalError, NotFoundError, UnsupportedError } from '../../errors.js'\nimport type { EntityMeta } from '../../types/meta.js'\nimport type { AnyRow } from '../../types/runtime.js'\nimport { NO_TRAIT_OPTIONS, partitionFilter, traitFilter, WRITING } from '../access.js'\nimport type { InternalBound } from '../internals.js'\nimport { find } from '../read/find.js'\nimport { assertId, lockRow, partitionAllowance, writeRule } from './mutations.js'\nimport { afterLink, runOperation } from './pipeline.js'\n\nexport type LinkOp = 'link' | 'unlink'\n\ntype ThroughRelation = {\n readonly targetTableName: string\n readonly sourceColumns: readonly AnyPgColumn[]\n readonly targetColumns: readonly AnyPgColumn[]\n readonly throughTable?: PgTable\n readonly through?: {\n readonly source: readonly { readonly _: { readonly key: string } }[]\n readonly target: readonly { readonly _: { readonly key: string } }[]\n }\n}\n\ntype Join = {\n readonly table: PgTable\n readonly ownerKey: string\n readonly target: EntityMeta\n readonly targetKey: string\n readonly joinOwner: AnyPgColumn\n readonly joinTarget: AnyPgColumn\n readonly joinOwnerKey: string\n readonly joinTargetKey: string\n}\n\nfunction keyOf(table: PgTable, column: AnyPgColumn | undefined): string {\n const found = Object.entries(getTableColumns(table)).find(([, c]) => c === column)\n if (found === undefined)\n throw new InternalError('A many-to-many relation names a column it has not')\n return found[0]\n}\n\n// The join of a many-to-many the entity writes, read from the relation Drizzle built for it.\nfunction joinOf(bound: InternalBound, entity: EntityMeta, relation: unknown): Join {\n if (typeof relation !== 'string') {\n throw new BadRequestError('relation must be the name of a relation', { entity: entity.name })\n }\n if (!entity.links.has(relation)) {\n throw new UnsupportedError(\n `Entity '${entity.name}' does not write the links of '${relation}' (r.many(…, { through, writable: true }))`,\n { entity: entity.name },\n )\n }\n const rel = bound.runtime.relations[entity.name]?.relations[\n relation\n ] as unknown as ThroughRelation\n const table = rel.throughTable\n const [joinOwnerKey, joinTargetKey] = [\n rel.through?.source[0]?._.key,\n rel.through?.target[0]?._.key,\n ]\n if (table === undefined || joinOwnerKey === undefined || joinTargetKey === undefined) {\n throw new InternalError(`Relation '${relation}' of '${entity.name}' goes through no table`)\n }\n const target = bound.runtime.entity(rel.targetTableName)\n const columns = getTableColumns(table) as Record<string, AnyPgColumn>\n return {\n table,\n ownerKey: keyOf(entity.table, rel.sourceColumns[0]),\n target,\n targetKey: keyOf(target.table, rel.targetColumns[0]),\n joinOwner: columns[joinOwnerKey] as AnyPgColumn,\n joinTarget: columns[joinTargetKey] as AnyPgColumn,\n joinOwnerKey,\n joinTargetKey,\n }\n}\n\n// A link is an edit of the row that owns it: the owner is locked under its `update` rule, the tenant and the\n// features, as an update locks it, and each target must be a row the caller may read — one they cannot see is\n// NOT_FOUND, like a missing one. The lock serializes the writes to one owner, so only the missing links are\n// inserted, with or without a unique constraint on the join.\nexport async function writeLinks(\n entity: EntityMeta,\n bound: InternalBound,\n op: LinkOp,\n id: unknown,\n relation: unknown,\n ids: unknown,\n): Promise<{ count: number }> {\n assertId(entity, id)\n const join = joinOf(bound, entity, relation)\n const list = Array.isArray(ids) ? ids : [ids]\n if (list.some((value) => value === undefined || value === null || typeof value === 'object')) {\n throw new BadRequestError(`${op} takes the ids of the rows to ${op}`, { entity: entity.name })\n }\n const targets = [...new Set(list)]\n return runOperation(bound, entity, op, async (scope) => {\n const rule = await writeRule(scope, 'update', { data: {} })\n const { partition } = partitionAllowance(scope, {})\n const owner = await lockRow(scope, id, [\n partitionFilter(partition),\n traitFilter(entity, scope.bound, scope.meta.operation, NO_TRAIT_OPTIONS, WRITING),\n rule,\n ])\n if (targets.length === 0) return { count: 0 }\n const seen = await find(join.target, scope.bound, {\n columns: { [join.targetKey]: true },\n where: { [join.targetKey]: { in: targets } },\n })\n if (seen.length !== targets.length) {\n throw new NotFoundError(`Not every '${join.target.name}' row to ${op} was found`, {\n entity: join.target.name,\n })\n }\n const ownerValue = owner[join.ownerKey]\n const mine = and(eq(join.joinOwner, ownerValue), inArray(join.joinTarget, targets))\n if (op === 'unlink') {\n const removed = (await scope.tx.delete(join.table).where(mine).returning()) as AnyRow[]\n const gone = removed.map((row) => row[join.joinTargetKey])\n if (gone.length > 0) {\n await afterLink(scope, { op, doc: owner, relation: relation as string, ids: gone })\n }\n return { count: removed.length }\n }\n const present = new Set(\n (await scope.tx.select({ target: join.joinTarget }).from(join.table).where(mine)).map(\n (row) => row.target,\n ),\n )\n const missing = targets.filter((target) => !present.has(target))\n if (missing.length > 0) {\n const rows = missing.map((target) => ({\n [join.joinOwnerKey]: ownerValue,\n [join.joinTargetKey]: target,\n }))\n await scope.tx.insert(join.table).values(rows)\n await afterLink(scope, { op, doc: owner, relation: relation as string, ids: missing })\n }\n return { count: missing.length }\n })\n}\n","import type { AnyDescriptor } from '../contract/descriptor.js'\nimport { traitOperations } from '../define/plugin.js'\nimport { BadRequestError } from '../errors.js'\nimport type { EntityMeta } from '../types/meta.js'\nimport type { AnyRow } from '../types/runtime.js'\nimport { andFilters, isPlainObject } from './filters.js'\nimport type { InternalBound } from './internals.js'\nimport { count, find, findById, findOne, page } from './read/find.js'\nimport { deleteMany, updateMany } from './write/bulk.js'\nimport { type LinkOp, writeLinks } from './write/links.js'\nimport { create, remove, update } from './write/mutations.js'\nimport { runEntityOperation } from './write/operations.js'\n\nconst EXTEND_KEYS = new Set(['where', 'orderBy', 'limit', 'offset'])\n\nfunction inputOf(descriptor: AnyDescriptor): AnyRow {\n const input = descriptor.input ?? {}\n if (!isPlainObject(input)) throw new BadRequestError('descriptor.input must be an object')\n return input\n}\n\n// `extend` narrows a stored descriptor at run time (pagination, an extra filter) without touching the\n// selection, so the descriptor's result type stays valid.\nfunction extendConfig(config: AnyRow, extend: unknown): AnyRow {\n if (extend === undefined) return config\n if (!isPlainObject(extend)) throw new BadRequestError('extend must be an object')\n for (const key of Object.keys(extend)) {\n if (!EXTEND_KEYS.has(key)) throw new BadRequestError(`extend.${key} is not supported`)\n }\n const out = { ...config }\n const where = andFilters([config.where as AnyRow | undefined, extend.where as AnyRow | undefined])\n if (where !== undefined) out.where = where\n for (const key of ['orderBy', 'limit', 'offset'] as const) {\n if (extend[key] !== undefined) out[key] = extend[key]\n }\n return out\n}\n\nfunction entityOf(bound: InternalBound, descriptor: unknown): EntityMeta {\n if (!isPlainObject(descriptor) || typeof descriptor.entity !== 'string') {\n throw new BadRequestError('A descriptor needs an entity name')\n }\n if (typeof descriptor.op !== 'string') throw new BadRequestError('A descriptor needs an op')\n return bound.runtime.entity(descriptor.entity)\n}\n\nexport async function execute(\n bound: InternalBound,\n descriptor: AnyDescriptor,\n extend?: unknown,\n): Promise<unknown> {\n const entity = entityOf(bound, descriptor)\n const input = inputOf(descriptor)\n if (extend !== undefined && !['find', 'findOne', 'count', 'page'].includes(descriptor.op)) {\n throw new BadRequestError(\n `extend is only supported on read descriptors, not '${descriptor.op}'`,\n )\n }\n switch (descriptor.op) {\n case 'find':\n return find(entity, bound, extendConfig(input, extend))\n case 'findOne':\n return findOne(entity, bound, extendConfig(input, extend))\n case 'findById':\n return findById(entity, bound, input.id, input.config)\n case 'count':\n return count(entity, bound, extendConfig(input, extend))\n case 'page':\n return page(entity, bound, extendConfig(input, extend))\n case 'create':\n return create(entity, bound, input.data, input.options)\n case 'update':\n return update(entity, bound, input.id, input.data, input.options)\n case 'updateMany':\n return updateMany(entity, bound, input.where, input.data, input.options)\n case 'delete':\n return remove(entity, bound, input.id, input.options)\n case 'deleteMany':\n return deleteMany(entity, bound, input.where, input.options)\n case 'link':\n case 'unlink':\n return writeLinks(entity, bound, descriptor.op as LinkOp, input.id, input.relation, input.ids)\n default:\n if (!traitOperations(bound.runtime.plugins).has(descriptor.op)) {\n throw new BadRequestError(`Unknown descriptor op '${String(descriptor.op)}'`)\n }\n return runEntityOperation(entity, bound, descriptor.op, input)\n }\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport { is } from 'drizzle-orm'\nimport {\n type PgAsyncDatabase,\n type PgQueryResultHKT,\n PgTable,\n type PgTransactionConfig,\n} from 'drizzle-orm/pg-core'\nimport { type AnyDescriptor, descriptor } from '../contract/descriptor.js'\nimport { BadRequestError, ConfigError, PluginError } from '../errors.js'\nimport type { ContextInput, TypionMode, MaybePromise } from '../types/context.js'\nimport type { TypionEngine, TypionTypes } from '../types/engine.js'\nimport type { TypionDefinition, EntityMeta } from '../types/meta.js'\nimport type { PluginErrorInput } from '../types/plugin.js'\nimport type { AnyDb, AnyRow, AnyTx, AnyTypion, AnyTypionApp } from '../types/runtime.js'\nimport { structuralValidation } from '../validation/structural.js'\nimport { buildContext, CommitQueue, type FullContext } from './context.js'\nimport { createPgDialect } from './dialect/pg.js'\nimport { normalizeError } from './errors.js'\nimport { execute } from './execute.js'\nimport type { AfterCommitErrorInfo, InternalBound, Runtime, SchemaMode } from './internals.js'\nimport { count, find, findById, findOne, page } from './read/find.js'\nimport { deleteMany, updateMany } from './write/bulk.js'\nimport { writeLinks } from './write/links.js'\nimport { create, remove, update } from './write/mutations.js'\nimport { operationInput, operationMethods, runEntityOperation } from './write/operations.js'\n\nexport type CreateEngineOptions<TE extends TypionTypes> = {\n // Built by the caller with `drizzle({ client, relations: def.relations })`; the engine never owns the\n // connection, so it can join transactions the application opens itself.\n db: NoInfer<PgAsyncDatabase<PgQueryResultHKT, TE['relations']>>\n context?: (input: ContextInput) => MaybePromise<TE['ctx']>\n onAfterCommitError?: (error: unknown, info: AfterCommitErrorInfo) => void\n // Compares every table of `def.schema` with information_schema before the first operation.\n checkSchema?: boolean\n // The database adapter's own check (`DbAdapter.check`), run with the boot.\n checkAdapter?: () => void\n now?: () => Date\n}\n\ntype AsOptions = { request?: Request; meta?: Record<string, unknown> } & Record<string, unknown>\n\ntype SystemOptions = {\n reason: string\n ctx?: object\n meta?: Record<string, unknown>\n [CALLER_LOOKUP]?: boolean\n} & Record<string, unknown>\n\n// Marks the system instance the config's context factory gets (`ContextInput.callerLookup`). A symbol, so\n// no caller can pass it and no plugin sees it among its options.\nexport const CALLER_LOOKUP = Symbol('typion.callerLookup')\n\nconst OWN_BIND_OPTIONS = new Set(['request', 'meta', 'reason', 'ctx'])\n\n// What is left of the bind options once the engine took its own: the plugins' (`locale`).\nfunction pluginBindOptions(opts: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(opts)) {\n if (!OWN_BIND_OPTIONS.has(key) && value !== undefined) out[key] = value\n }\n return out\n}\n\nfunction defaultAfterCommitError(error: unknown, info: AfterCommitErrorInfo) {\n console.error(\n `[typion] afterCommit failed (${info.entity}.${info.operation}, request ${info.requestId})`,\n error,\n )\n}\n\nclass EngineRuntime implements Runtime {\n readonly relations\n readonly dialect = createPgDialect()\n readonly validation\n readonly plugins\n private readonly schemas = new Map<string, StandardSchemaV1>()\n private boot: Promise<void> | null = null\n private initializing = false\n engine!: EngineImpl\n\n constructor(\n readonly def: TypionDefinition<any>,\n readonly db: AnyDb,\n private readonly options: CreateEngineOptions<any>,\n ) {\n this.relations = def.relations\n this.validation = def.validation ?? structuralValidation()\n this.plugins = def.plugins\n }\n\n now(): Date {\n return this.options.now?.() ?? new Date()\n }\n\n entity(name: string): EntityMeta {\n const entity = this.entityOrNull(name)\n if (entity === null) throw new BadRequestError(`Unknown entity '${name}'`)\n return entity\n }\n\n entityOrNull(name: string): EntityMeta | null {\n return Object.hasOwn(this.def.entities, name)\n ? ((this.def.entities as Record<string, EntityMeta>)[name] ?? null)\n : null\n }\n\n schema(entity: EntityMeta, mode: SchemaMode): StandardSchemaV1 {\n const key = `${entity.name}:${mode}`\n let schema = this.schemas.get(key)\n if (schema === undefined) {\n schema = this.validation.base(entity, mode, entity.validate?.fields)\n this.schemas.set(key, schema)\n }\n return schema\n }\n\n afterCommitError(error: unknown, info: AfterCommitErrorInfo): void {\n ;(this.options.onAfterCommitError ?? defaultAfterCommitError)(error, info)\n }\n\n // Plugin init may itself run engine operations, which call ready() again: those must not wait on the\n // boot that is running them.\n ready(): Promise<void> {\n if (this.initializing) return Promise.resolve()\n if (this.boot === null) {\n this.boot = this.runBoot().catch((error) => {\n this.boot = null\n throw error\n })\n }\n return this.boot\n }\n\n private async runBoot(): Promise<void> {\n this.options.checkAdapter?.()\n if (this.options.checkSchema !== false) await this.checkSchema()\n this.initializing = true\n try {\n for (const plugin of this.plugins) await plugin.spec.init?.(this.engine)\n } finally {\n this.initializing = false\n }\n }\n\n private async checkSchema(): Promise<void> {\n const tables = Object.values(this.def.schema).filter((v): v is PgTable => is(v, PgTable))\n let drift: Awaited<ReturnType<typeof this.dialect.introspect>>\n try {\n drift = await this.dialect.introspect(this.db, tables)\n } catch (error) {\n throw normalizeError(this, error)\n }\n if (drift.missingTables.length === 0 && drift.missingColumns.length === 0) return\n const lines = [\n 'The database schema does not match the engine definition.',\n ...(drift.missingTables.length > 0\n ? [` missing tables: ${drift.missingTables.join(', ')}`]\n : []),\n ...drift.missingColumns.map(\n (m) => ` missing columns on ${m.table}: ${m.columns.join(', ')}`,\n ),\n 'Run `typion db generate` and `typion db migrate` (or `typion db push` in development).',\n ]\n throw new ConfigError(lines.join('\\n'), 'schema_drift', { details: { ...drift } })\n }\n}\n\ntype EntityApiObject = Record<string, unknown>\n\nfunction entityApi(bound: BoundImpl, entity: EntityMeta): EntityApiObject {\n const name = entity.name\n const schemas = {} as Record<SchemaMode, StandardSchemaV1>\n for (const mode of ['insert', 'update', 'select'] as const) {\n Object.defineProperty(schemas, mode, {\n enumerable: true,\n get: () => bound.runtime.schema(entity, mode),\n })\n }\n return {\n find: (config?: unknown) => find(entity, bound, config),\n findOne: (config?: unknown) => findOne(entity, bound, config),\n findById: (id: unknown, config?: unknown) => findById(entity, bound, id, config),\n count: (config?: unknown) => count(entity, bound, config),\n page: (config?: unknown) => page(entity, bound, config),\n query: (config?: unknown) => descriptor(name, 'find', config ?? {}),\n queryOne: (config?: unknown) => descriptor(name, 'findOne', config ?? {}),\n run: async (d: AnyDescriptor, extend?: unknown) => {\n if (d?.entity !== name) {\n throw new BadRequestError(`A '${String(d?.entity)}' descriptor cannot run on '${name}'`)\n }\n return execute(bound, d, extend)\n },\n create: (data: unknown, options?: unknown) => create(entity, bound, data, options),\n update: (id: unknown, data: unknown, options?: unknown) =>\n update(entity, bound, id, data, options),\n updateMany: (where: unknown, data: unknown, options?: unknown) =>\n updateMany(entity, bound, where, data, options),\n delete: (id: unknown, options?: unknown) => remove(entity, bound, id, options),\n deleteMany: (where: unknown, options?: unknown) => deleteMany(entity, bound, where, options),\n ...(entity.links.size === 0\n ? {}\n : {\n link: (id: unknown, relation: unknown, ids: unknown) =>\n writeLinks(entity, bound, 'link', id, relation, ids),\n unlink: (id: unknown, relation: unknown, ids: unknown) =>\n writeLinks(entity, bound, 'unlink', id, relation, ids),\n }),\n schemas,\n ...operationMethods(entity, bound.runtime.plugins, async (op, args) =>\n runEntityOperation(entity, bound, op.name, operationInput(op, args)),\n ),\n }\n}\n\nconst EMPTY_QUEUE = new CommitQueue(() => {})\n\nclass BoundImpl implements InternalBound {\n private readonly apis = new Map<string, EntityApiObject>()\n private plugins: Record<string, unknown> | undefined\n\n constructor(\n readonly $engine: EngineImpl,\n readonly ctx: FullContext,\n readonly $tx: AnyTx | null,\n readonly queue: CommitQueue | null,\n ) {\n for (const name of Object.keys($engine.runtime.def.entities)) {\n Object.defineProperty(this, name, { enumerable: true, get: () => this.entity(name) })\n }\n }\n\n get runtime(): Runtime {\n return this.$engine.runtime\n }\n\n get $ctx(): FullContext {\n return this.ctx\n }\n\n get $mode(): TypionMode {\n return this.ctx.mode\n }\n\n get $executor(): AnyDb | AnyTx {\n return this.$tx ?? this.runtime.db\n }\n\n get $afterCommit(): CommitQueue {\n return this.queue ?? EMPTY_QUEUE\n }\n\n get $plugins(): Record<string, unknown> {\n this.plugins ??= this.$engine.pluginApis(this)\n return this.plugins\n }\n\n entity(name: string): EntityApiObject {\n let api = this.apis.get(name)\n if (api === undefined) {\n api = entityApi(this, this.runtime.entity(name))\n this.apis.set(name, api)\n }\n return api\n }\n\n joined(tx: AnyTx, queue: CommitQueue): BoundImpl {\n return new BoundImpl(this.$engine, this.ctx, tx, queue)\n }\n\n systemTwin(reason: string): BoundImpl {\n if (this.ctx.mode === 'system') return this\n const ctx = { ...this.ctx, mode: 'system' as const, systemReason: reason }\n return new BoundImpl(this.$engine, ctx, this.$tx, this.queue)\n }\n\n $withTx(tx: AnyTx): BoundImpl {\n return this.joined(tx, this.queue ?? this.$engine.newQueue(this.ctx))\n }\n\n $run(d: AnyDescriptor, extend?: unknown): Promise<unknown> {\n return execute(this, d, extend)\n }\n\n async $transaction<T>(\n fn: (bound: BoundImpl) => Promise<T>,\n config?: PgTransactionConfig,\n ): Promise<T> {\n const runtime = this.runtime\n await runtime.ready()\n try {\n if (this.$tx !== null && this.queue !== null) {\n const queue = this.queue\n const mark = queue.mark()\n try {\n return await this.$tx.transaction((tx) => fn(this.joined(tx, queue)))\n } catch (error) {\n queue.truncate(mark)\n throw error\n }\n }\n const queue = this.$engine.newQueue(this.ctx)\n let result: T\n try {\n result = await runtime.db.transaction((tx) => fn(this.joined(tx, queue)), config)\n } catch (error) {\n queue.discard()\n throw error\n }\n await queue.flush()\n return result\n } catch (error) {\n throw normalizeError(runtime, error)\n }\n }\n}\n\nclass EngineImpl implements AnyTypion {\n readonly runtime: EngineRuntime\n readonly $plugins: Record<string, unknown> = {}\n\n constructor(\n def: TypionDefinition<any>,\n private readonly options: CreateEngineOptions<any>,\n ) {\n const db = options.db as unknown as AnyDb\n if ((db as { _?: { relations?: unknown } })?._?.relations !== def.relations) {\n throw new ConfigError(\n 'createEngine: the db was built with other relations; create it with drizzle({ client, relations: def.relations })',\n 'relations_mismatch',\n )\n }\n this.runtime = new EngineRuntime(def, db, options)\n this.runtime.engine = this\n for (const name of Object.keys(def.entities)) {\n Object.defineProperty(this, name, {\n enumerable: true,\n value: {\n query: (config?: unknown) => descriptor(name, 'find', config ?? {}),\n queryOne: (config?: unknown) => descriptor(name, 'findOne', config ?? {}),\n },\n })\n }\n Object.assign(this.$plugins, this.pluginApis())\n }\n\n pluginApis(app?: AnyTypionApp): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const plugin of this.runtime.def.plugins) {\n const errors: Record<string, (input?: PluginErrorInput) => PluginError> = {}\n for (const [code, spec] of Object.entries(plugin.errors)) {\n errors[code] = (input = {}) =>\n new PluginError(input.message ?? spec.message, plugin.id, code, {\n status: spec.status,\n details: input.details,\n cause: input.cause,\n })\n }\n out[plugin.id] = { ...(plugin.spec.api?.(this, app) as object | undefined), errors }\n }\n return out\n }\n\n get $def(): TypionDefinition<any> {\n return this.runtime.def\n }\n\n get $db(): AnyDb {\n return this.runtime.db\n }\n\n get $dialect() {\n return this.runtime.dialect\n }\n\n newQueue(ctx: FullContext): CommitQueue {\n return new CommitQueue((error) =>\n this.runtime.afterCommitError(error, {\n entity: '*',\n operation: 'transaction',\n requestId: ctx.requestId,\n }),\n )\n }\n\n private pluginContext(base: FullContext, input: ContextInput, allowAsync: false): object\n private pluginContext(base: FullContext, input: ContextInput, allowAsync: true): Promise<object>\n private pluginContext(base: FullContext, input: ContextInput, allowAsync: boolean) {\n const parts: unknown[] = []\n for (const plugin of this.runtime.plugins) {\n const build = plugin.spec.context\n if (build === undefined) continue\n const value = build(base, input)\n if (!allowAsync && typeof (value as { then?: unknown })?.then === 'function') {\n throw new ConfigError(\n `Plugin '${plugin.id}' builds its context asynchronously: use $fromRequest() instead of $as()`,\n )\n }\n parts.push(value)\n }\n if (!allowAsync) return Object.assign({}, ...(parts as object[]))\n return Promise.all(parts).then((values) => Object.assign({}, ...(values as object[])))\n }\n\n private bind(\n user: object,\n mode: TypionMode,\n opts: { request?: Request | null; meta?: Record<string, unknown> } & Record<string, unknown>,\n systemReason: string | null,\n callerLookup: boolean,\n pluginCtx: object | null,\n ): BoundImpl {\n if (typeof user !== 'object' || user === null) {\n throw new BadRequestError('The engine context must be an object')\n }\n const ctx = buildContext({\n user,\n mode,\n request: opts.request ?? null,\n systemReason,\n meta: opts.meta,\n now: this.runtime.now(),\n })\n const input: ContextInput = {\n request: opts.request ?? undefined,\n headers: opts.request?.headers,\n options: pluginBindOptions(opts),\n ...(callerLookup ? { callerLookup } : {}),\n }\n const extra = pluginCtx ?? this.pluginContext(ctx, input, false)\n const full = { ...extra, ...ctx } as FullContext\n return new BoundImpl(this, full, null, null)\n }\n\n $as(ctx: object, opts: AsOptions = {}): BoundImpl {\n return this.bind(ctx, 'user', opts, null, false, null)\n }\n\n $system(opts: SystemOptions): BoundImpl {\n if (typeof opts?.reason !== 'string' || opts.reason.trim() === '') {\n throw new ConfigError(\n '$system() needs a non-empty reason: it is recorded in versions and audit rows',\n )\n }\n return this.bind(\n opts.ctx ?? {},\n 'system',\n opts,\n opts.reason,\n opts[CALLER_LOOKUP] === true,\n null,\n )\n }\n\n $fromRequest(request: Request, opts: Record<string, unknown> = {}): Promise<BoundImpl> {\n return this.fromInput({ request, headers: request.headers, options: pluginBindOptions(opts) })\n }\n\n // Server components and server actions have no `Request`; the headers are enough to resolve who is calling.\n $fromHeaders(headers: Headers, opts: Record<string, unknown> = {}): Promise<BoundImpl> {\n return this.fromInput({ headers, options: pluginBindOptions(opts) })\n }\n\n private async fromInput(input: ContextInput): Promise<BoundImpl> {\n const request = input.request ?? null\n const user = this.options.context === undefined ? {} : await this.options.context(input)\n const probe = buildContext({\n user: user as object,\n mode: 'user',\n request,\n systemReason: null,\n meta: undefined,\n now: this.runtime.now(),\n })\n const pluginCtx = await this.pluginContext(probe, input, true)\n return this.bind(user as object, 'user', { request }, null, false, pluginCtx)\n }\n\n $withTx(ctx: object, tx: AnyTx): BoundImpl {\n const bound = this.$as(ctx)\n return bound.joined(tx, this.newQueue(bound.ctx))\n }\n\n $execute(d: AnyDescriptor, bound: unknown): Promise<unknown> {\n if (!(bound instanceof BoundImpl)) {\n return Promise.reject(new BadRequestError('$execute needs an engine bound with $as/$system'))\n }\n return execute(bound, d)\n }\n}\n\nexport function createEngine<TE extends TypionTypes>(\n def: TypionDefinition<TE>,\n options: CreateEngineOptions<TE>,\n): TypionEngine<TE> {\n return new EngineImpl(def, options) as unknown as TypionEngine<TE>\n}\n\nexport function isBoundEngine(value: unknown): value is InternalBound {\n return value instanceof BoundImpl\n}\n\nexport type { AnyRow }\n","import { ConfigError } from '../errors.js'\nimport type {\n ContextFactoryInput,\n DbAdapter,\n SystemTypion,\n Typion,\n TypionConfig,\n} from '../types/collection.js'\nimport type { MaybePromise } from '../types/context.js'\nimport type { TypionEngine, TypionTypes } from '../types/engine.js'\nimport type { AnyDb } from '../types/runtime.js'\nimport { CALLER_LOOKUP, type CreateEngineOptions, createEngine } from './engine.js'\n\n// One instance per config and process: a dev server re-evaluates modules on every edit and a production build\n// loads them in several workers, so the instance lives on globalThis rather than in a module-level variable.\nconst instances = ((globalThis as { __typion?: Map<unknown, unknown> }).__typion ??= new Map<\n unknown,\n unknown\n>())\n\n// Builds the instance a config describes. The context factory of the config is handed a system-bound instance\n// of what is being created, which is how it can look the caller up in the database, and its connection.\nexport function createFromConfig<TE extends TypionTypes>(\n config: TypionConfig<TE>,\n // The factory that replaces the config's gets `system` and `db` as the config's does.\n options: Omit<CreateEngineOptions<TE>, 'db' | 'context'> & {\n db: AnyDb\n context?: (input: ContextFactoryInput) => MaybePromise<TE['ctx']>\n },\n): TypionEngine<TE> {\n const context = options.context ?? config.context\n const engine: TypionEngine<TE> = createEngine(config.definition, {\n ...options,\n onAfterCommitError: options.onAfterCommitError ?? config.onAfterCommitError,\n checkSchema: options.checkSchema ?? config.checkSchema,\n db: options.db as never,\n context:\n context === undefined\n ? undefined\n : (input) =>\n (context as (i: unknown) => never)({\n ...input,\n system: engine.$system({\n reason: 'context',\n [CALLER_LOOKUP]: true,\n } as never) as unknown as SystemTypion,\n db: options.db,\n } satisfies ContextFactoryInput),\n })\n return engine\n}\n\nexport type GetTypionOptions = {\n // Replaces the adapter of the config; tests point it at their own database.\n db?: DbAdapter\n fresh?: boolean\n}\n\n// A test's instance stands in for the config's while it is open: what reaches the instance through the config — the\n// Next.js and Hono adapters, the application's own `getTypion(config)` — serves the test's database.\nexport function standIn(config: TypionConfig<any>, engine: unknown): () => void {\n const previous = instances.get(config)\n instances.set(config, engine)\n return () => {\n if (instances.get(config) !== engine) return\n if (previous === undefined) instances.delete(config)\n else instances.set(config, previous)\n }\n}\n\nexport async function getTypion<const C extends TypionConfig<any>>(\n config: C,\n options: GetTypionOptions = {},\n): Promise<Typion<C>> {\n const cached = options.fresh === true ? undefined : instances.get(config)\n if (cached !== undefined) return cached as Typion<C>\n const adapter = options.db ?? config.db\n if (adapter === undefined) {\n throw new ConfigError('getTypion: the config has no database adapter (`db` in defineConfig)')\n }\n const engine = createFromConfig(config, {\n db: adapter.connect(config.definition.relations) as AnyDb,\n ...(adapter.check === undefined ? {} : { checkAdapter: () => adapter.check?.() }),\n })\n if (options.fresh !== true) instances.set(config, engine)\n return engine as unknown as Typion<C>\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { B as EntityMeta, Ea as ValidationMode, R as ValidationAdapter } from "../context-B4e2eREP.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { CoerceOptions } from "drizzle-orm/zod";
|
|
4
|
+
//#region src/validation/zod.d.ts
|
|
5
|
+
export type ZodRefineFn = {
|
|
6
|
+
bivarianceHack(schema: z.ZodType): z.ZodType;
|
|
7
|
+
}['bivarianceHack'];
|
|
8
|
+
export type ZodFieldRefinement = z.ZodType | ZodRefineFn;
|
|
9
|
+
export type ZodRefinements = Readonly<Record<string, ZodFieldRefinement | Readonly<Record<string, ZodFieldRefinement | undefined>> | undefined>>;
|
|
10
|
+
export type ZodEntitySchema = z.ZodObject<Record<string, z.ZodType>, z.core.$catchall<z.ZodType>>;
|
|
11
|
+
export interface ZodValidationOptions {
|
|
12
|
+
readonly coerce?: CoerceOptions;
|
|
13
|
+
}
|
|
14
|
+
export interface ZodValidationAdapter extends ValidationAdapter {
|
|
15
|
+
readonly id: 'zod';
|
|
16
|
+
base(entity: EntityMeta, mode: ValidationMode, refinements: Record<string, unknown> | undefined): ZodEntitySchema;
|
|
17
|
+
}
|
|
18
|
+
export declare function zodEntitySchema(entity: EntityMeta, mode: ValidationMode, refinements: Record<string, unknown> | undefined, options?: ZodValidationOptions): ZodEntitySchema;
|
|
19
|
+
export declare function zodValidation(options?: ZodValidationOptions): ZodValidationAdapter;
|
|
20
|
+
//#endregion
|
|
21
|
+
//# sourceMappingURL=zod.d.ts.map
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { n as ConfigError } from "../errors-D-CKO-px.js";
|
|
2
|
+
import { t as schemaKeys } from "../structural-BZnjFmCs.js";
|
|
3
|
+
import { columnToSchema } from "drizzle-orm/zod/column";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/validation/zod.ts
|
|
6
|
+
const unknownKey = z.custom(() => false, { error: (issue) => `Unknown key '${String(issue.path?.at(-1) ?? "")}'` });
|
|
7
|
+
function strictShape(shape) {
|
|
8
|
+
return z.object(shape).catchall(unknownKey);
|
|
9
|
+
}
|
|
10
|
+
const jsonValue = z.union([
|
|
11
|
+
z.string(),
|
|
12
|
+
z.number(),
|
|
13
|
+
z.boolean(),
|
|
14
|
+
z.record(z.string(), z.any()),
|
|
15
|
+
z.array(z.any())
|
|
16
|
+
]);
|
|
17
|
+
function fail(entity, message) {
|
|
18
|
+
throw new ConfigError(`Entity '${entity}': validate.fields ${message}`, "config", { entity });
|
|
19
|
+
}
|
|
20
|
+
function isZodSchema(value) {
|
|
21
|
+
return value instanceof z.ZodType;
|
|
22
|
+
}
|
|
23
|
+
function isPlainObject(value) {
|
|
24
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
25
|
+
const proto = Object.getPrototypeOf(value);
|
|
26
|
+
return proto === Object.prototype || proto === null;
|
|
27
|
+
}
|
|
28
|
+
function applyRefinement(base, refinement, where) {
|
|
29
|
+
if (refinement === void 0) return base;
|
|
30
|
+
if (isZodSchema(refinement)) return refinement;
|
|
31
|
+
if (typeof refinement === "function") return refinement(base);
|
|
32
|
+
return where();
|
|
33
|
+
}
|
|
34
|
+
function isOptional(column, mode) {
|
|
35
|
+
if (mode === "select") return false;
|
|
36
|
+
if (mode === "update") return true;
|
|
37
|
+
return !column.notNull || column.hasDefault || column.generated;
|
|
38
|
+
}
|
|
39
|
+
function scalarSchema(column, refinement, options, where) {
|
|
40
|
+
return applyRefinement(columnToSchema(column.column, { coerce: options.coerce }), refinement, where);
|
|
41
|
+
}
|
|
42
|
+
function keyedSchema(entity, column, shape, refinement, options) {
|
|
43
|
+
const base = shape.value === void 0 ? jsonValue : columnToSchema(shape.value, { coerce: options.coerce });
|
|
44
|
+
let perKey = {};
|
|
45
|
+
let whole;
|
|
46
|
+
const noun = shape.keyName;
|
|
47
|
+
if (isZodSchema(refinement) || typeof refinement === "function") whole = refinement;
|
|
48
|
+
else if (refinement !== void 0) {
|
|
49
|
+
if (!isPlainObject(refinement)) fail(entity.name, `.${column.key} must be a zod schema, a function or a per-${noun} record`);
|
|
50
|
+
for (const key of Object.keys(refinement)) if (!shape.keys.includes(key)) fail(entity.name, `.${column.key}.${key} is not a configured ${noun}`);
|
|
51
|
+
perKey = refinement;
|
|
52
|
+
}
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const key of shape.keys) {
|
|
55
|
+
const inner = applyRefinement(base, perKey[key], () => fail(entity.name, `.${column.key}.${key} must be a zod schema or a function`));
|
|
56
|
+
const withNull = shape.nonNull.includes(key) ? inner : inner.nullable();
|
|
57
|
+
out[key] = shape.required.includes(key) ? withNull : withNull.optional();
|
|
58
|
+
}
|
|
59
|
+
return applyRefinement(strictShape(out), whole, () => fail(entity.name, `.${column.key} must be a zod schema, a function or a per-${noun} record`));
|
|
60
|
+
}
|
|
61
|
+
function zodEntitySchema(entity, mode, refinements, options = {}) {
|
|
62
|
+
for (const key of Object.keys(refinements ?? {})) if (!(key in entity.columns)) fail(entity.name, `.${key} does not name a column`);
|
|
63
|
+
const shape = {};
|
|
64
|
+
for (const key of schemaKeys(entity, mode)) {
|
|
65
|
+
const column = entity.columns[key];
|
|
66
|
+
const refinement = refinements?.[key];
|
|
67
|
+
const keyed = column.columnKind?.validation?.(column, mode);
|
|
68
|
+
let schema = keyed ? keyedSchema(entity, column, keyed, refinement, options) : scalarSchema(column, refinement, options, () => fail(entity.name, `.${key} must be a zod schema or a function`));
|
|
69
|
+
if (!column.notNull) schema = schema.nullable();
|
|
70
|
+
if (isOptional(column, mode)) schema = schema.optional();
|
|
71
|
+
shape[key] = schema;
|
|
72
|
+
}
|
|
73
|
+
return strictShape(shape);
|
|
74
|
+
}
|
|
75
|
+
function zodValidation(options = {}) {
|
|
76
|
+
return {
|
|
77
|
+
id: "zod",
|
|
78
|
+
base: (entity, mode, refinements) => zodEntitySchema(entity, mode, refinements, options)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
export { zodEntitySchema, zodValidation };
|
|
83
|
+
|
|
84
|
+
//# sourceMappingURL=zod.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod.js","names":[],"sources":["../../src/validation/zod.ts"],"sourcesContent":["import type { CoerceOptions } from 'drizzle-orm/zod'\nimport { columnToSchema } from 'drizzle-orm/zod/column'\nimport { z } from 'zod'\nimport { ConfigError } from '../errors.js'\nimport type { KeyedShape } from '../types/kinds.js'\nimport type { ColumnMeta, EntityMeta } from '../types/meta.js'\nimport type { ValidationAdapter } from '../types/runtime.js'\nimport { schemaKeys, type ValidationMode } from './structural.js'\n\n// Method-style declaration so `(s: z.ZodString) => s.min(3)` is assignable: the parameter is checked\n// bivariantly, as with React's event handler types. The base schema a column receives is whatever\n// drizzle-orm/zod derives for it (a JSON-value union for jsonb, hence per key of a keyed column kind).\nexport type ZodRefineFn = { bivarianceHack(schema: z.ZodType): z.ZodType }['bivarianceHack']\n\nexport type ZodFieldRefinement = z.ZodType | ZodRefineFn\n\nexport type ZodRefinements = Readonly<\n Record<\n string,\n ZodFieldRefinement | Readonly<Record<string, ZodFieldRefinement | undefined>> | undefined\n >\n>\n\nexport type ZodEntitySchema = z.ZodObject<Record<string, z.ZodType>, z.core.$catchall<z.ZodType>>\n\nexport interface ZodValidationOptions {\n readonly coerce?: CoerceOptions\n}\n\nexport interface ZodValidationAdapter extends ValidationAdapter {\n readonly id: 'zod'\n base(\n entity: EntityMeta,\n mode: ValidationMode,\n refinements: Record<string, unknown> | undefined,\n ): ZodEntitySchema\n}\n\n// `strictObject` reports unrecognized keys on the object's own path; a failing catchall reports them\n// on the key, which is what the structural adapter does and what the error model addresses.\nconst unknownKey = z.custom<never>(() => false, {\n error: (issue) => `Unknown key '${String(issue.path?.at(-1) ?? '')}'`,\n})\n\nfunction strictShape(shape: Record<string, z.ZodType>): ZodEntitySchema {\n return z.object(shape).catchall(unknownKey)\n}\n\nconst jsonValue = z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.record(z.string(), z.any()),\n z.array(z.any()),\n])\n\nfunction fail(entity: string, message: string): never {\n throw new ConfigError(`Entity '${entity}': validate.fields ${message}`, 'config', { entity })\n}\n\nfunction isZodSchema(value: unknown): value is z.ZodType {\n return value instanceof z.ZodType\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false\n const proto = Object.getPrototypeOf(value)\n return proto === Object.prototype || proto === null\n}\n\nfunction applyRefinement(base: z.ZodType, refinement: unknown, where: () => never): z.ZodType {\n if (refinement === undefined) return base\n if (isZodSchema(refinement)) return refinement\n if (typeof refinement === 'function') return (refinement as ZodRefineFn)(base)\n return where()\n}\n\nfunction isOptional(column: ColumnMeta, mode: ValidationMode): boolean {\n if (mode === 'select') return false\n if (mode === 'update') return true\n return !column.notNull || column.hasDefault || column.generated\n}\n\nfunction scalarSchema(\n column: ColumnMeta,\n refinement: unknown,\n options: ZodValidationOptions,\n where: () => never,\n): z.ZodType {\n const base = columnToSchema(column.column, { coerce: options.coerce })\n return applyRefinement(base, refinement, where)\n}\n\nfunction keyedSchema(\n entity: EntityMeta,\n column: ColumnMeta,\n shape: KeyedShape,\n refinement: unknown,\n options: ZodValidationOptions,\n): z.ZodType {\n // Each value is checked as the column the kind names (a string for `localized(text())`).\n const base =\n shape.value === undefined ? jsonValue : columnToSchema(shape.value, { coerce: options.coerce })\n let perKey: Record<string, unknown> = {}\n let whole: unknown\n const noun = shape.keyName\n if (isZodSchema(refinement) || typeof refinement === 'function') {\n whole = refinement\n } else if (refinement !== undefined) {\n if (!isPlainObject(refinement)) {\n fail(entity.name, `.${column.key} must be a zod schema, a function or a per-${noun} record`)\n }\n for (const key of Object.keys(refinement)) {\n if (!shape.keys.includes(key)) {\n fail(entity.name, `.${column.key}.${key} is not a configured ${noun}`)\n }\n }\n perKey = refinement\n }\n const out: Record<string, z.ZodType> = {}\n for (const key of shape.keys) {\n const inner = applyRefinement(base, perKey[key], () =>\n fail(entity.name, `.${column.key}.${key} must be a zod schema or a function`),\n )\n const withNull = shape.nonNull.includes(key) ? inner : inner.nullable()\n out[key] = shape.required.includes(key) ? withNull : withNull.optional()\n }\n return applyRefinement(strictShape(out), whole, () =>\n fail(entity.name, `.${column.key} must be a zod schema, a function or a per-${noun} record`),\n )\n}\n\nexport function zodEntitySchema(\n entity: EntityMeta,\n mode: ValidationMode,\n refinements: Record<string, unknown> | undefined,\n options: ZodValidationOptions = {},\n): ZodEntitySchema {\n for (const key of Object.keys(refinements ?? {})) {\n if (!(key in entity.columns)) fail(entity.name, `.${key} does not name a column`)\n }\n const shape: Record<string, z.ZodType> = {}\n for (const key of schemaKeys(entity, mode)) {\n const column = entity.columns[key] as ColumnMeta\n const refinement = refinements?.[key]\n const keyed = column.columnKind?.validation?.(column, mode)\n let schema = keyed\n ? keyedSchema(entity, column, keyed, refinement, options)\n : scalarSchema(column, refinement, options, () =>\n fail(entity.name, `.${key} must be a zod schema or a function`),\n )\n // Optionality and nullability come from the column, not from drizzle-orm/zod: upstream leaves a\n // plain-schema refinement unwrapped and types function-refined `hasDefault` columns as required.\n if (!column.notNull) schema = schema.nullable()\n if (isOptional(column, mode)) schema = schema.optional()\n shape[key] = schema\n }\n return strictShape(shape)\n}\n\nexport function zodValidation(options: ZodValidationOptions = {}): ZodValidationAdapter {\n return {\n id: 'zod',\n base: (entity, mode, refinements) => zodEntitySchema(entity, mode, refinements, options),\n }\n}\n"],"mappings":"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"}
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Typion for applications
|
|
2
|
+
|
|
3
|
+
Typion is the application layer of this project, on top of Drizzle ORM: collections, access rules, hooks, an HTTP
|
|
4
|
+
handler, and the features that change what reads and writes mean (localization, multi-tenancy, soft delete, versions
|
|
5
|
+
and drafts). It is new, and not in any model's training data: read this page before you add or change a collection,
|
|
6
|
+
a rule, a hook, a query or a route, then the page for your task. Every example in these pages is type-checked against
|
|
7
|
+
the version of Typion they ship with.
|
|
8
|
+
|
|
9
|
+
## The model
|
|
10
|
+
|
|
11
|
+
- A **collection** is a Drizzle table written in two parts. The first object is its **structure** — columns,
|
|
12
|
+
relations, the options of the features (`softDelete`, `versions`, `tenant`), `fields`, `public` — everything that
|
|
13
|
+
shapes types. `.define()` takes its **behaviour**: `access` rules, `hooks`, `validate`, `indexes`.
|
|
14
|
+
- One **setup** (`defineSetup`: localization, multi-tenancy, plugins), one **config** (`defineConfig`: the
|
|
15
|
+
collections, the database, the context factory) and the **context** type are **registered** in
|
|
16
|
+
`interface Register`. That is how every
|
|
17
|
+
collection sees every other one with no codegen. A TypeScript program registers one config.
|
|
18
|
+
- `getTypion(config)` gives the instance. **Every call is bound to a caller**: `typion.$as(ctx)`,
|
|
19
|
+
`typion.$fromRequest(request)` or `getApp(config)` in Next.js give a user-mode app, where the rules apply;
|
|
20
|
+
`typion.$system({ reason })` gives a system-mode app, where they do not.
|
|
21
|
+
- **Deny by default.** A missing rule is `FORBIDDEN`. A rule returns a boolean or a filter, and a filter applies at
|
|
22
|
+
every level of a read — nested `with`, relation filters, counts — and to the row a write locks.
|
|
23
|
+
- **Types come from the query.** A read's result type is the shape its `columns` and `with` ask for; a descriptor
|
|
24
|
+
carries it (`InferItem<typeof postCard>`). Never write a row type by hand.
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
// src/typion/context.ts
|
|
28
|
+
export type Role = 'admin' | 'editor'
|
|
29
|
+
|
|
30
|
+
// What the application knows about a caller: the context factory of the config returns it, rules, hooks and
|
|
31
|
+
// field rules read it. It is registered on its own (below), since field rules are typed before the config exists.
|
|
32
|
+
export type AppContext = { actorId: string | null; role: Role | null }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// src/typion.config.ts
|
|
37
|
+
import { drizzle } from 'drizzle-orm/node-postgres'
|
|
38
|
+
import { dbAdapter, defineConfig, defineSetup } from 'typion'
|
|
39
|
+
import { betterAuthContext } from 'typion/auth/better-auth'
|
|
40
|
+
import { authTables } from './auth-schema.ts'
|
|
41
|
+
import { authFor } from './auth.ts'
|
|
42
|
+
import { pool } from './db.ts'
|
|
43
|
+
import { comments } from './typion/collections/comments.ts'
|
|
44
|
+
import { posts } from './typion/collections/posts.ts'
|
|
45
|
+
import { postsTags, tags } from './typion/collections/tags.ts'
|
|
46
|
+
import { users } from './typion/collections/users.ts'
|
|
47
|
+
import type { AppContext } from './typion/context.ts'
|
|
48
|
+
|
|
49
|
+
// The features and the plugins: `localization`, `multiTenant`, `plugins: [audit()]`. Soft delete and versions
|
|
50
|
+
// need no line here; a collection turns them on.
|
|
51
|
+
export const setup = defineSetup({})
|
|
52
|
+
|
|
53
|
+
export const config = defineConfig({
|
|
54
|
+
setup,
|
|
55
|
+
collections: [users, posts, comments, tags],
|
|
56
|
+
// Tables that are not collections: the join of a many-to-many, an auth library's tables.
|
|
57
|
+
tables: { postsTags, ...authTables },
|
|
58
|
+
db: dbAdapter((relations) => drizzle({ client: pool, relations }), {
|
|
59
|
+
url: process.env.DATABASE_URL,
|
|
60
|
+
close: () => pool.end(),
|
|
61
|
+
}),
|
|
62
|
+
// Who is calling: Better Auth, on this instance's connection, says who signed in (auth.md); the users collection
|
|
63
|
+
// what they may do. The return type is declared, since the body queries `system`.
|
|
64
|
+
context: betterAuthContext(authFor, async (session, { system }): Promise<AppContext> => {
|
|
65
|
+
const user =
|
|
66
|
+
session === null
|
|
67
|
+
? null
|
|
68
|
+
: await system.users.findOne({
|
|
69
|
+
where: { email: session.user.email },
|
|
70
|
+
columns: { id: true, role: true },
|
|
71
|
+
})
|
|
72
|
+
return { actorId: user?.id ?? null, role: user?.role ?? null }
|
|
73
|
+
}),
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
declare module 'typion' {
|
|
77
|
+
interface Register {
|
|
78
|
+
setup: typeof setup
|
|
79
|
+
config: typeof config
|
|
80
|
+
context: AppContext
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Rules
|
|
86
|
+
|
|
87
|
+
1. **Read and write the application's data through Typion, bound to the caller.** Never through `typion.$db`,
|
|
88
|
+
Drizzle or SQL: they skip the access rules, the tenant, soft delete, drafts, validation, hooks and the history.
|
|
89
|
+
2. **`$system({ reason })` is for code no user drives**: seeds, jobs, webhooks, migrations of data, the lookups of the
|
|
90
|
+
context factory. Never use it to answer a request because a rule is in the way; change the rule. Give a reason
|
|
91
|
+
that says why: it is stored in the history and the audit trail.
|
|
92
|
+
3. **Authorization lives in `access`**, on the collection, not in pages, routes or server actions. A check in the UI
|
|
93
|
+
is a convenience; the rule is what holds over HTTP and in every other caller.
|
|
94
|
+
4. **A rule that depends on the row returns a filter** (`{ authorId: ctx.actorId }`); rules never receive the row.
|
|
95
|
+
`create` is a predicate over the input: check what the caller claims (`data.authorId === ctx.actorId`).
|
|
96
|
+
5. **A rule that lets callers edit their own row must not let them edit what makes it theirs**, or their role:
|
|
97
|
+
protect those columns with `fields: { role: { write: … } }`.
|
|
98
|
+
6. **No raw SQL with user input**: no `RAW` filters, `sql` in `extras` or `orderBy` callbacks built from a request.
|
|
99
|
+
Over HTTP they are refused anyway; in process nothing stops them.
|
|
100
|
+
7. **Managed columns are written by their operations**: `delete`/`restore` for `deletedAt`, `publish`/`unpublish`
|
|
101
|
+
for `status`, the context for `tenantId`. Writing them from user mode is `FORBIDDEN`.
|
|
102
|
+
8. **Never redeclare result types**: export a descriptor from `src/typion/queries.ts` (`defineQueries`) and use
|
|
103
|
+
`InferItem<typeof descriptor>`.
|
|
104
|
+
9. **Every schema change ships a migration**: `typion db generate --name <change>`, read the SQL, commit it.
|
|
105
|
+
`typion db push` is for development databases only.
|
|
106
|
+
10. **A new collection or rule is tested with two callers**: one the rule allows and one it denies, with
|
|
107
|
+
`createTestTypion(config)`.
|
|
108
|
+
|
|
109
|
+
## Where things go
|
|
110
|
+
|
|
111
|
+
| Path | What |
|
|
112
|
+
| ---------------------------------- | ------------------------------------------------------------------- |
|
|
113
|
+
| `src/typion.config.ts` | the setup, the config, `Register` |
|
|
114
|
+
| `src/typion/context.ts` | the caller's context type |
|
|
115
|
+
| `src/auth.ts`, `src/db.ts` | the auth library and the database pool the config shares with it |
|
|
116
|
+
| `src/typion/collections/<name>.ts` | one collection per file: structure, then `define()` |
|
|
117
|
+
| `src/typion/queries.ts` | the descriptors pages and components share |
|
|
118
|
+
| `src/typion/seed.ts` | `export async function seed({ typion })`, run by `typion db seed` |
|
|
119
|
+
| `src/app/api/[...path]/route.ts` | the HTTP routes on Next.js: `routeHandlers(config, { transports })` |
|
|
120
|
+
| the Hono app (`src/index.ts`) | `.all('/api/*', typionRoutes(…))`, `typionMiddleware` on own routes |
|
|
121
|
+
| `typion/migrations/` | the SQL `typion db generate` writes, committed |
|
|
122
|
+
|
|
123
|
+
## The page for your task
|
|
124
|
+
|
|
125
|
+
| Task | Read |
|
|
126
|
+
| --------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
127
|
+
| Add a collection, a column, a relation, a many-to-many | [collections.md](collections.md) |
|
|
128
|
+
| Decide who reads and writes what; hide a column | [access.md](access.md) |
|
|
129
|
+
| Sign people in; who the caller is | [auth.md](auth.md) |
|
|
130
|
+
| Do something when a row is written | [hooks.md](hooks.md) |
|
|
131
|
+
| Read or write data; transactions; errors | [queries.md](queries.md) |
|
|
132
|
+
| A page, a server action, an API route, Hono, the browser client | [http.md](http.md) |
|
|
133
|
+
| A business operation of several writes | [queries.md](queries.md#transactions), then [http.md](http.md#business-operations) |
|
|
134
|
+
| The database: drivers, migrations, seed | [database.md](database.md) |
|
|
135
|
+
| Tests | [testing.md](testing.md) |
|
|
136
|
+
| Locales, tenants, soft delete, drafts and history | [features/](features/) |
|
|
137
|
+
|
|
138
|
+
## Before you call a change done
|
|
139
|
+
|
|
140
|
+
- `tsc` passes: Typion's errors are type errors first (an unknown column, a rule on a feature the collection does
|
|
141
|
+
not have, a hidden column selected).
|
|
142
|
+
- Every collection you added has a rule for each operation callers use; nothing is left to "deny by default" by
|
|
143
|
+
accident, and nothing is `true` that should be a filter.
|
|
144
|
+
- The tests cover a caller the rules allow and one they deny.
|
|
145
|
+
- A schema change has its migration in `typion/migrations/`.
|