protobuf codec with static type inference jsr.io/@mary/protobuf
typescript jsr
TypeScript 100.0%
12 1 0

Clone this repository

https://tangled.org/mary.my.id/pkg-protobuf https://tangled.org/did:plc:ia76kvnndjutgedggx2ibrem/pkg-protobuf
git@tangled.org:mary.my.id/pkg-protobuf git@tangled.org:did:plc:ia76kvnndjutgedggx2ibrem/pkg-protobuf

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

protobuf#

JSR | source code

protobuf codec with static type inference.

import * as p from '@mary/protobuf';

// basic usage
{
	const Person = p.message({
		id: p.int64(),
		name: p.string(),
		email: p.optional(p.string()),
		tags: p.repeated(p.string()),
	}, {
		id: 1,
		name: 2,
		email: 3,
		tags: 4,
	});

	const person: p.InferInput<typeof Person> = {
		id: 123n,
		name: 'alice',
		email: 'alice@example.com',
		tags: ['developer', 'rust'],
	};

	const encoded = p.encode(Person, person);
	const decoded = p.decode(Person, encoded);
	//    ^? p.InferOutput<typeof Person>

	const result = p.tryDecode(Person, buffer);

	if (result.ok) {
		result.value;
	} else {
		result.message;
		result.issues;
	}
}

// nested and self-referential messages
{
	const Address = p.message({
		street: p.string(),
		city: p.string(),
		zipCode: p.optional(p.string()),
	}, {
		street: 1,
		city: 2,
		zipCode: 3,
	});

	const Place = p.message({
		name: p.string(),
		address: Address,
	}, {
		name: 1,
		address: 2,
	});

	const Node = p.message({
		value: p.int32(),
		get next() {
			return p.optional(Node);
		},
	}, {
		value: 1,
		next: 2,
	});
}

// oneof fields
{
	const TextContent = p.message({
		body: p.string(),
	}, { body: 1 });

	const ImageContent = p.message({
		url: p.string(),
		width: p.int32(),
	}, { url: 1, width: 2 });

	const Post = p.message({
		title: p.string(),
		content: p.oneof({
			text: TextContent,
			image: ImageContent,
		}),
	}, {
		title: 1,
		content: { text: 2, image: 3 },
	});

	const post: p.InferInput<typeof Post> = {
		title: 'Hello',
		content: { case: 'text', value: { body: 'world' } },
	};

	const encoded = p.encode(Post, post);
	const decoded = p.decode(Post, encoded);
	//    ^? { title: string, content?: { case: 'text', value: ... } | { case: 'image', value: ... } }
}

non-features#

  • enums support: use int32() instead for open enums
  • extensions support: not supported
  • groups support: use nested messages instead
  • code generation: no intent