
Security News
Socket Releases Free Certified Patches for Nuxt Security Vulnerabilities
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.
@prisma-next/sql-contract-ts
Status: Current SQL TypeScript contract authoring surface
This package owns the SQL TypeScript authoring API for Prisma Next.
This package is part of the SQL family namespace (packages/2-sql/2-authoring/contract-ts) and provides:
defineContract(...)./contract-builder: field.column(...), field.generated(...), field.namedType(...), plus model(...) and rel.*field.id.uuidv7String(), field.text(), field.temporal.createdAt(), field.temporal.updatedAt(), plus pack-contributed entity-type helpers at top level alongside the built-in model / rel (e.g. enum({ name, values }))ContracttypescriptContract(...) for prisma-next.config.tsdescriptor.contractSerializer.deserializeContract(json))This is the current SQL TypeScript authoring implementation. Shared descriptor types live in @prisma-next/contract-authoring. Contract validation flows through the per-target descriptor's contractSerializer SPI (e.g. postgresTarget.contractSerializer.deserializeContract), or via the canonical façade (postgres<Contract>(...)).
./contract-builder exports the stable structural DSL (defineContract, field, model, rel)defineContract(config, (helpers) => ...) synthesizes helpers.field.* and helpers.type.* from the selected family, target, and extension packs@prisma-next/contract-authoring provides the target-neutral descriptor types used by the DSL and by authoring-adjacent packsContributor-facing lowering notes and detailed warning semantics live in DEVELOPING.md.
flowchart LR
builderInput[TypeScript contract input] --> sqlContractTs[@prisma-next/sql-contract-ts]
sqlContractTs --> authoringCore[@prisma-next/contract-authoring]
sqlContractTs --> sqlTypes[@prisma-next/sql-contract/types]
sqlContractTs --> contract[SQL Contract]
./contract-builder - SQL contract DSL (defineContract, field, model, rel)./config-types - typescriptContract(...) config helperDirect imports expose the base structural helpers. Use this surface when you want to author with explicit column descriptors, explicit generators, or named storage types.
Built-in ID helpers from @prisma-next/ids already return the generated-field spec accepted by field.generated(...), so field.generated(uuidv4()) is a valid structural DSL call.
import { textColumn, timestamptzColumn } from '@prisma-next/adapter-postgres/column-types';
import sqlFamily from '@prisma-next/family-sql/pack';
import { uuidv4 } from '@prisma-next/ids';
import { defineContract, field, model, rel } from '@prisma-next/sql-contract-ts/contract-builder';
import postgresPack from '@prisma-next/target-postgres/pack';
const User = model('User', {
fields: {
id: field.generated(uuidv4()).id(),
email: field.column(textColumn).unique(),
createdAt: field.column(timestamptzColumn).defaultSql('now()'),
},
})
.relations({
posts: rel.hasMany('Post', { by: 'userId' }),
})
.sql({
table: 'app_user',
});
const Post = model('Post', {
fields: {
id: field.generated(uuidv4()).id(),
userId: field.column(textColumn),
title: field.column(textColumn),
},
})
.relations({
user: rel.belongsTo(User, { from: 'userId', to: 'id' }),
})
.sql({
table: 'blog_post',
});
export const contract = defineContract({
family: sqlFamily,
target: postgresPack,
naming: { tables: 'snake_case', columns: 'snake_case' },
models: {
User,
Post,
},
});
Pack-provided helper presets are available through the callback overload. This is the surface that exposes field.id.*, field.text(), field.temporal.createdAt(), field.temporal.updatedAt(), type.sql.String(...), and extension helpers such as type.pgvector.Vector(...).
import pgvector from '@prisma-next/extension-pgvector/pack';
import sqlFamily from '@prisma-next/family-sql/pack';
import { defineContract, enumType, member } from '@prisma-next/sql-contract-ts/contract-builder';
import postgresPack from '@prisma-next/target-postgres/pack';
const pgText = { codecId: 'pg/text@1', nativeType: 'text' } as const;
const Role = enumType('role', pgText, member('USER', 'user'), member('ADMIN', 'admin'));
export const contract = defineContract(
{
family: sqlFamily,
target: postgresPack,
extensions: { pgvector },
},
({ type, field, model, rel }) => {
const types = {
ShortName: type.sql.String(35),
Embedding1536: type.pgvector.Vector(1536),
} as const;
const User = model('User', {
fields: {
id: field.id.uuidv7String().sql({ id: { name: 'user_pkey' } }),
shortName: field.namedType(types.ShortName),
role: field.namedType(Role),
embedding: field.namedType(types.Embedding1536).optional(),
createdAt: field.temporal.createdAt(),
updatedAt: field.temporal.updatedAt(),
},
});
const Post = model('Post', {
fields: {
id: field.id.uuidv7String(),
authorId: field.uuidString(),
title: field.text(),
},
});
return {
enums: { role: Role },
types,
models: {
User: User.relations({
posts: rel.hasMany(Post, { by: 'authorId' }),
}).sql({
table: 'user',
}),
Post: Post.relations({
author: rel.belongsTo(User, { from: 'authorId', to: 'id' }),
}).sql({
table: 'post',
}),
},
};
},
);
Single-field constraints are usually most readable inline on the field, while compound constraints live in .attributes(...) or model-level .sql(...).
const Membership = model('Membership', {
fields: {
orgId: field.column(textColumn).column('org_id'),
userId: field.column(textColumn).column('user_id'),
role: field.column(textColumn),
},
})
.attributes(({ fields, constraints }) => ({
id: constraints.id([fields.orgId, fields.userId], { name: 'membership_pkey' }),
uniques: [
constraints.unique([fields.orgId, fields.role], {
name: 'membership_org_role_key',
}),
],
}))
.sql({ table: 'membership' });
constraints.index (inside model .sql(...) under indexes: [...]) has two forms:
constraints.index([cols.email], { unique: true, where: '(archived_at IS NULL)', name: 'users_email_active' })
constraints.index({ expression: 'eql_v3.eq_term(email)', name: 'users_email_eq' })
constraints.index(cols | [cols...], options?). Options: unique?, where? (partial-index predicate, WHERE body without the keyword), name? xor map?, and — when the target pack registers index types — type? paired with its options? (e.g. type: 'hash', options: {}). The pack-typed arm requires the options key at compile time; PSL accepts type: without options: (absent validates as {}) — both lower to the same IR.constraints.index({ expression, ...options }). The expression is the whole CREATE INDEX element list as one opaque string; name or map is required (no default name can be derived from an expression). Same remaining options as the fields form.name: declares a managed index: the physical name is <name>_<8-hex content hash>, and renames plan as ALTER INDEX … RENAME. map: adopts an exact physical name verbatim (no hash) — intended for objects captured by contract infer. Combining map: with a SQL body (expression/where) emits the PN_EXACT_NAME_BODY_COMPARISON warning at build time: drift detection byte-compares the authored text against Postgres's reprinted form, which is only reliable for infer-captured text. Prefer name: for hand-authored bodies.
field.column(...), field.generated(...), field.namedType(...), plus model(...) and rel.*field.id.uuidv4String(), field.id.uuidv7String(), field.id.nanoid({ size }), field.uuidString(), field.text(), field.timestamp(), field.temporal.createdAt(), field.temporal.updatedAt(), and type.* (Postgres also adds field.uuidNative(), field.id.uuidv4Native(), field.id.uuidv7Native() — these emit pg/uuid@1)field.temporal.createdAt() lowers to a target storage now() default, while field.temporal.updatedAt() lowers to the target-owned timestampNow execution default for create and non-empty update mutations.field.sql(...) and rel.belongsTo(...).sql({ fk })field.namedType(types.Role), User.refs.id, and User.ref('id') when those tokens are availableUse the root-level foreignKeyDefaults option when a contract wants non-default FK materialization:
const contract = defineContract({
family: sqlFamily,
target: postgresPack,
foreignKeyDefaults: { constraint: true, index: false },
models: {
// ...
},
});
Per-FK overrides still live next to the FK authoring site, either via constraints.foreignKey(...) inside model .sql(...) or via rel.belongsTo(...).sql({ fk: ... }). See ADR 161.
Contract JSON validation flows through the per-target descriptor's
contractSerializer SPI; this package focuses on authoring and lowering.
End-user app code typically goes through the canonical façade
(postgres<Contract>(...)), which threads the descriptor SPI internally.
import postgres from '@prisma-next/postgres/runtime';
import contractJson from './contract.json' with { type: 'json' };
import type { Contract, TypeMaps } from './contract.d';
const db = postgres<Contract, TypeMaps>({
contractJson,
url: process.env['DATABASE_URL']!,
});
For advanced consumers that need direct access to the SPI:
import postgresTarget from '@prisma-next/target-postgres/control';
import type { Contract } from './contract.d';
const contract = postgresTarget.contractSerializer.deserializeContract(
contractJson,
) as Contract;
Use typescriptContract from this package when wiring TS-authored contracts in prisma-next.config.ts.
import { defineConfig } from '@prisma-next/cli/config-types';
import { typescriptContract } from '@prisma-next/sql-contract-ts/config-types';
import { contract } from './src/prisma/contract';
export default defineConfig({
contract: typescriptContract(contract, 'src/prisma/contract.json'),
});
Optional third argument (options bag) for typescriptContract / typescriptContractFromPath, and defaultControlPolicy on emptyContract:
typescriptContract(contract, 'src/prisma/contract.json', { defaultControlPolicy: 'external' });
The specifier value applies only when the loaded contract omits defaultControlPolicy (a value authored on the contract module wins).
@prisma-next/config - ContractConfig types used by typescriptContract(...)@prisma-next/contract-authoring - Shared descriptor types@prisma-next/framework-components - Pack refs, authoring contributions, and codec lookup types@prisma-next/sql-contract - SQL contract types and validation targetUnit tests for the authoring DSL live in this package. Broader integration tests that span authoring, emission, CLI, and runtime packages live in @prisma-next/integration-tests.
@prisma-next/sql-contract-tscontractSerializer.deserializeContract(...) (or via the canonical façade)@prisma-next/contract-authoring - Shared target-neutral authoring descriptor types@prisma-next/sql-contract-psl - PSL parser-output to SQL contract interpreter@prisma-next/sql-contract-psl/provider - SQL PSL-first prismaContract() helperFAQs
SQL-specific TypeScript contract authoring surface for Prisma Next
The npm package @prisma-next/sql-contract-ts receives a total of 16,115 weekly downloads. As such, @prisma-next/sql-contract-ts popularity was classified as popular.
We found that @prisma-next/sql-contract-ts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket releases free Certified Patches for high-severity Nuxt vulnerabilities, including server-side remote code execution through server island props.

Security News
An open letter signed by 50 companies, from NVIDIA and Microsoft to Mistral and Hugging Face, urges Washington not to restrict open weight AI.

Security News
/Research
A fake corepack.org site is impersonating the Node.js tool and delivers an infostealer and proxyware to developers who download it.