Buf/protoc plugin that emits TypeScript contract Input interfaces from protovalidate-enabled protobuf definitions. Required/optional properties follow (buf.validate.field).required; google./buf. packages are skipped by default. Use alongside protoc-gen-es/protobuf-es with the same out path.
- Node.js 22+,
pnpm10+, Buf CLI - Install (consumer project):
pnpm add -D @gaudiy/protoc-gen-ts-contract - Working from this repo:
pnpm install && pnpm -C packages/ts-contract-plugin build
version: v2
plugins:
- remote: buf.build/bufbuild/es:v2.10.1
out: ./gen
include_imports: true
opt:
- target=ts
- name: ts-contract
path: ./node_modules/.bin/protoc-gen-ts-contract
out: ./gen
opt:
- target=ts # required
# - skip_pkg=google.* # override defaultsSteps (consumer project): pnpm install → pnpm exec buf generate --template buf.gen.yaml
Steps (this repo): pnpm install → pnpm -C packages/ts-contract-plugin build → pnpm example:gen (writes protobuf-es + contracts under example/gen/).
protoc \
--plugin=protoc-gen-ts-contract=./node_modules/.bin/protoc-gen-ts-contract \
--ts-contract_out=gen \
--ts-contract_opt=target=ts \
-I proto \
proto/fixtures/orders/v1/order.protoGenerated fixtures/orders/v1/order_contract.ts:
// @generated by protoc-gen-ts-contract
import type { MoneyInput } from "../../common/v1/common_contract";
import type { Status } from "../../common/v1/common_pb";
export interface OrderInput {
id: string;
total?: MoneyInput;
status?: Status;
}import { OrderSchema, Status } from "./gen/fixtures/orders/v1/order_pb";
import { create, toBinary, toJson } from "@bufbuild/protobuf";
import type { OrderInput } from "./gen/fixtures/orders/v1/order.contract";
const order: OrderInput = {
id: "order-123",
total: { currencyCode: "USD", units: "10" },
status: Status.PENDING,
};
const message = create(OrderSchema, order);- Workspace:
pnpm build | lint | test | clean - Package:
pnpm -C packages/ts-contract-plugin build|lint|test|clean - Rebuild the plugin before regenerating fixtures.