Skip to content

Scripting

varc module reference

Use binary-safe keyspace, stream, time, diff, byte, and deterministic fixture helpers designed for Redis and Valkey workflows.

The varc: namespace contains application-native modules for Redis and Valkey data. They are pure, embedded, and available to every execution class.

Strings passed to byte-oriented functions are encoded as UTF-8. Uint8Array and ArrayBuffer inputs are copied, so the helpers do not retain a mutable view into the caller’s buffer.

ModuleUse it forVersionAvailable inLicenseUpstream
varc:bytesConvert, concatenate, and compare binary-safe values.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site
varc:diffDescribe byte, line, and JSON changes with bounded data structures.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site
varc:keyspaceSplit, join, inspect, and Redis-glob-match binary keys.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site
varc:seedGenerate deterministic fixture data from a repeatable seed.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site
varc:streamsParse and compare Redis stream IDs without losing integer precision.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site
varc:timeDecode Redis TTL replies and parse or format compact durations.1.0.0Scripts, Macros, Transformers, DashboardsUNLICENSEDProject site

Bytes

Import from varc:bytes:

import { from, toString, concat, compare, equals } from "varc:bytes";

All functions accept BytesLike = Uint8Array | ArrayBuffer | string.

Function Return Behavior
from(value) Uint8Array Encode a string as UTF-8 or copy a byte/buffer input.
toString(value) string Decode the bytes as UTF-8 text.
concat(...values) Uint8Array Join values without a separator.
compare(left, right) -1, 0, or 1 Compare unsigned bytes lexicographically, then length.
equals(left, right) boolean Test byte-for-byte equality.
import { concat, equals, toString } from "varc:bytes";

const key = concat("customer", new Uint8Array([58]), "42");
return { text: toString(key), matches: equals(key, "customer:42") };

toString is for data known to represent text. Use base64 or hex when arbitrary bytes must round-trip through a string.

Diff

Import from varc:diff:

import { diffBytes, diffLines, diffJson } from "varc:diff";
Function Return
diffBytes(before, after) { offset, before, after }[]
diffLines(before, after) { kind: "equal" | "add" | "remove", line }[]
diffJson(before, after, path?) { path, before?, after? }[]

diffBytes reports only changed offsets. A missing byte at either end is represented by null. Equal inputs return an empty array.

diffLines splits on newline characters and uses a stable longest-common-subsequence diff. It retains equal lines so a renderer can reconstruct both sides.

diffJson recursively compares arrays and objects, sorts keys for stable output, and uses escaped JSON Pointer paths. Primitive or type changes are reported at the current path; the root path is /.

import { diffJson } from "varc:diff";

return diffJson({ profile: { name: "Ada", enabled: false } }, { profile: { name: "Ada", enabled: true } });
// [{ path: "/profile/enabled", before: false, after: true }]

These helpers build their result in memory. Keep inputs comfortably within the execution class’s memory and output limits.

Keyspace

Import from varc:keyspace:

import { equals, split, join, prefixes, matches } from "varc:keyspace";

The default separator is ":", but every byte-oriented function accepts a string, Uint8Array, or ArrayBuffer separator.

Function Return Behavior
equals(left, right) boolean Byte-for-byte equality.
split(key, separator?) Uint8Array[] Split without decoding the key; empty sections are preserved.
join(parts, separator?) Uint8Array Join binary-safe parts.
prefixes(key, separator?) Uint8Array[] Return each cumulative hierarchy prefix, including the full key.
matches(pattern, key) boolean Apply Redis-style glob matching to bytes.

An empty separator passed to split or prefixes throws TypeError. matches supports *, ?, character classes, ranges, negated classes, and backslash escapes.

import { prefixes, matches } from "varc:keyspace";
import { toString } from "varc:bytes";

const key = new TextEncoder().encode("customer:42:profile");
return {
  matches: matches("customer:*:profile", key),
  parents: prefixes(key).map(toString),
};

Seed

createSeededRandom(seed) from varc:seed creates a deterministic generator:

import { createSeededRandom } from "varc:seed";

const random = createSeededRandom("invoice-fixture-v1");
return {
  id: random.uuid(),
  attempt: random.int(1, 5),
  score: random.float(),
  token: random.bytes(8),
  region: random.pick(["eu-west", "us-east", "ap-south"]),
  order: random.shuffle([1, 2, 3, 4]),
};
Method Behavior
float() Return a value in [0, 1).
int(min, max) Return an inclusive safe integer between min and max.
bytes(length) Return deterministic bytes for a non-negative safe length.
pick(values) Return one item; an empty list throws RangeError.
shuffle(values) Return a shuffled copy without mutating the input.
uuid() Return an RFC 4122 version-4-shaped deterministic UUID.

The seed is SHA-256-derived and the sequence uses xoshiro128**. This is for repeatable fixtures and demonstrations, not passwords, tokens, signatures, or any other security decision. Use randomBytes or crypto.getRandomValues when unpredictability is required.

Streams

Import Redis stream ID helpers from varc:streams:

import { parseId, formatId, compareIds, nextId, previousId, isAutoId } from "varc:streams";
interface StreamId {
  milliseconds: bigint;
  sequence: bigint;
}
Function Return Behavior
parseId(value) StreamId Parse an exact milliseconds-sequence ID.
formatId(value) string Format two unsigned 64-bit parts.
compareIds(left, right) -1, 0, or 1 Compare by milliseconds, then sequence.
nextId(value) string Return the immediate unsigned 64-bit successor.
previousId(value) string | null Return the predecessor, or null for 0-0.
isAutoId(value) boolean Recognize * and valid milliseconds-* forms.

Parsing rejects malformed IDs and parts outside the unsigned 64-bit range. nextId throws when both components are already at their maximum.

import { compareIds, nextId, parseId } from "varc:streams";

const start = parseId("1710000000000-42");
return {
  after: nextId(start),
  ordered: compareIds(start, "1710000000001-0") < 0,
};

Time

Import from varc:time:

import { decodeTtl, parseDuration, formatDuration } from "varc:time";

decodeTtl(milliseconds) turns a Redis PTTL reply into a discriminated union:

type TtlState = { kind: "missing" } | { kind: "persistent" } | { kind: "expires"; milliseconds: number };

-2 becomes missing, -1 becomes persistent, and a non-negative safe integer becomes expires. Any other input throws RangeError.

parseDuration(value) accepts plain milliseconds or combined ms, s, m, h, d, and w units. formatDuration(milliseconds) returns the matching compact whole-unit form.

import { decodeTtl, formatDuration, parseDuration } from "varc:time";

const ttl = decodeTtl(await redis.pttl("session:42"));
return {
  ttl,
  retryAfter: parseDuration("1m 30s"),
  retention: formatDuration(7 * 24 * 60 * 60 * 1000),
};

Durations must resolve to non-negative safe integer milliseconds. Invalid text, negative values, and values outside the safe range fail explicitly.