Skip to content

@protoutil/core

A set of utilities for working with protobuf types. These utilities assume you are using protobuf-es to work with messages.

Terminal window
npm install @protoutil/core

The package has two entry points:

Entry PointImport PathContents
Core@protoutil/coreCheckSum, Fields, integer validators, error classes
Well-Known Types@protoutil/core/wktDuration, FieldMask, Timestamp

The checksum function calculates a non-cryptographic checksum for a given message. Any two messages with identical values produce identical checksums. Internally, this is used for pagination page tokens and ETags in the @protoutil/aip package.

import { checksum } from "@protoutil/core";
const message1 = create(MySchema, { foo: "bar" });
const checksum1 = checksum(MySchema, message1);
const message2 = create(MySchema, { foo: "bar" });
const checksum2 = checksum(MySchema, message2);
const message3 = create(MySchema, { baz: "quz" });
const checksum3 = checksum(MySchema, message3);
checksum1 === checksum2; // true
checksum1 === checksum3; // false

The getField and setField functions get and set field values on a message, with support for oneof fields:

import { getField, setField } from "@protoutil/core";
getField(message, fieldDescriptor); // Gets the value (or returns undefined)
setField(message, fieldDescriptor, value); // Sets the value

Both functions check that the field descriptor belongs to the message’s type and throw an error on mismatch. setField does not validate the value’s type before setting.

A Duration represents a signed, fixed-length span of time represented as a count of seconds and fractions of seconds at nanosecond resolution.

Import from @protoutil/core/wkt:

import {
duration,
assertValidDuration,
isValidDuration,
durationFromString,
durationToString,
durationFromNanos,
durationNanos,
clampDuration,
durationFromTemporal,
durationTemporal,
} from "@protoutil/core/wkt";
duration(1n, 1_000_000); // 1.001 seconds
duration(315_576_000_001n); // throws — max is +-10,000 years
assertValidDuration(d); // throws if invalid
isValidDuration(d); // true/false
durationFromString("2s"); // Duration message representing 2 seconds
durationToString(d); // "1.001s"
durationFromNanos(1_000_000n); // Duration representing 1 millisecond
durationNanos(d); // BigInt nanoseconds
const min = duration(5n);
const max = duration(10n);
clampDuration(duration(15n), min, max); // returns max
clampDuration(duration(1n), min, max); // returns min
clampDuration(duration(7n), min, max); // returns original

Without arguments, clampDuration clamps to the protobuf spec range (-315,576,000,000s to +315,576,000,000s).

Conversion to/from Temporal.Duration (using temporal-polyfill):

durationFromTemporal(temporalDuration); // Duration message
durationTemporal(message); // Temporal.Duration

A Timestamp represents a point in time independent of any time zone or local calendar, encoded as a count of seconds and fractions of seconds at nanosecond resolution.

Range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.

Import from @protoutil/core/wkt:

import {
timestamp,
assertValidTimestamp,
isValidTimestamp,
timestampFromString,
timestampToString,
timestampFromNanos,
timestampNanos,
roundTimestampNanos,
clampTimestamp,
temporalTimestampNow,
timestampFromInstant,
timestampInstant,
} from "@protoutil/core/wkt";
timestamp(1n, 1_000_000); // 1.001 seconds after unix epoch
timestamp(253402300800n); // throws — max is 9999-12-31T23:59:59.999999999Z
assertValidTimestamp(ts); // throws if invalid
isValidTimestamp(ts); // true/false
timestampFromString("1970-01-01T02:07:34.000000321+07:00"); // Timestamp message
timestampToString(ts); // "1970-01-01T00:00:00.000000000Z"
timestampFromNanos(1_000_000n); // 1ms after epoch
timestampNanos(ts); // BigInt nanoseconds
const epoch = timestampFromNanos(0n);
const oneWeek = durationFromString(`${7 * 24 * 60 * 60}s`);
const oneWeekLater = timestampFromNanos(timestampNanos(epoch) + durationNanos(oneWeek));
timestampToString(oneWeekLater); // "1970-01-08T00:00:00.000Z"

Ensure nanos is an integer after calculations:

let ts = create(TimestampSchema, { nanos: 3 / 2 });
ts = roundTimestampNanos(ts);
assertValidTimestamp(ts); // does not throw
clampTimestamp(timestamp(15n), min, max); // clamp to range

Without arguments, clamps to the protobuf spec range (0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z).

temporalTimestampNow(); // Timestamp with nanosecond resolution
timestampFromInstant(instant); // from Temporal.Instant
timestampInstant(ts); // to Temporal.Instant

FieldMask represents a set of symbolic field paths used to specify a subset of fields that should be returned by a get operation or modified by an update operation.

Import from @protoutil/core/wkt:

import {
fieldMask,
assertValidFieldMask,
isValidFieldMask,
fieldMaskHasPath,
applyFieldMask,
mergeFieldMasks,
intersectFieldMasks,
} from "@protoutil/core/wkt";

All FieldMask functions accept a strict parameter (default: true). In strict mode, only spec-compliant field masks are allowed. Set strict to false to allow wildcards (*) per the AIP Guidelines.

fieldMask(MySchema, ["my_path", "my_other_path"]);
// throws if fields don't exist on MySchema
assertValidFieldMask(MySchema, fm); // throws if invalid
isValidFieldMask(MySchema, fm); // true/false
const fm = fieldMask(MySchema, ["a"]);
fieldMaskHasPath(fm, "a"); // true
fieldMaskHasPath(fm, "b"); // false
fieldMaskHasPath(fm, "a.b"); // true — "a" covers nested fields
const fm = fieldMask(MySchema, ["a"]);
applyFieldMask(MySchema, message, fm); // only "a" field populated
applyFieldMask(MySchema, message, fm, { inverse: true }); // everything EXCEPT "a"

applyFieldMask does not mutate the original message. Options:

OptionDefaultDescription
inversefalseWhen true, applies the inverse of the mask
stricttrueWhen false, allows wildcards in the mask

Combines paths — parent fields subsume their children:

const one = fieldMask(MySchema, ["a"]);
const two = fieldMask(MySchema, ["a.b", "c"]);
mergeFieldMasks(one, two); // paths: ["a", "c"]

Returns only paths present in all masks — child paths preferred over parents:

intersectFieldMasks(one, two); // paths: ["a.b"]

Import from @protoutil/core:

FunctionDescription
assertValidInt32(num)Throws if num is not a 32-bit signed integer
isValidInt32(num)Returns true if num is a 32-bit signed integer
assertValidInt64(num)Throws if num (BigInt) is not a 64-bit signed integer
isValidInt64(num)Returns true if num (BigInt) is a 64-bit signed integer
assertValidUInt32(num)Throws if num is not a 32-bit unsigned integer
isValidUInt32(num)Returns true if num is a 32-bit unsigned integer
assertValidUInt64(num)Throws if num (BigInt) is not a 64-bit unsigned integer
isValidUInt64(num)Returns true if num (BigInt) is a 64-bit unsigned integer

Import from @protoutil/core:

ClassDescription
OutOfRangeErrorIndicates a value is out of range. Properties: value, min, max.
InvalidValueErrorIndicates a value is invalid. Properties: value.

This library exports the Google protobuf unit testing schemas compiled from the protocolbuffers repository. These are useful when testing protobuf-dependent libraries.

// Main test types (proto2)
import { TestAllTypesSchema } from "@protoutil/core/unittest";
// Proto3-specific types
import { TestAllTypes_NestedEnumSchema } from "@protoutil/core/unittest/proto3";

Many additional schemas are available under @protoutil/core/unittest/* sub-paths (arena, custom-options, features, lite, etc.). Please explore the repository or file an issue if you need a schema that isn’t exported.