cesr
Version:
[](https://www.npmjs.com/package/cesr) [](https://github.com/lenkan/cesr-js/blob/main/LICENSE) [ • 5.24 kB
JavaScript
import { decodeBase64Int, encodeBase64Int } from "./encoding-base64.js";
import { decodeUtf8 } from "./encoding-utf8.js";
const REGEX_VERSION_STRING_PROTOCOL = /^[A-Z]{4}$/;
const REGEX_VERSION_JSON = /^\{"v":"(.*?)".*$/;
const Kind = {
JSON: "JSON",
CBOR: "CBOR",
MSGPACK: "MGPK",
CESR: "CESR",
};
const KIND_VALUES = new Set(Object.values(Kind));
function encodeHexInt(value, length) {
if (value >= 16 ** length) {
throw new Error(`Value exceeds maximum for hex encoding. Expected value < ${16 ** length} for length ${length}, got ${value}`);
}
return value.toString(16).padStart(length, "0");
}
export class VersionString {
protocol;
major;
minor;
kind;
legacy;
size;
constructor(init) {
if (!REGEX_VERSION_STRING_PROTOCOL.test(init.protocol)) {
throw new Error(`Protocol must be 4 uppercase characters. Expected format: /^[A-Z]{4}$/, got "${init.protocol}"`);
}
const kind = init.kind ?? "JSON";
if (!KIND_VALUES.has(kind)) {
throw new Error(`Encoding kind must be one of ${Array.from(KIND_VALUES).join(", ")}, got "${kind}"`);
}
// TODO: Remove when other kinds are supported
if (kind !== "JSON") {
throw new Error(`Unsupported encoding kind "${kind}", only JSON format is supported for now`);
}
if (init.size !== undefined && init.size < 0) {
throw new Error(`Size must be non-negative. Expected size >= 0, got ${init.size}`);
}
this.protocol = init.protocol;
this.major = init.major ?? 1;
this.minor = init.minor ?? 0;
this.kind = kind;
this.legacy = init.legacy ?? true;
this.size = init.size ?? 0;
}
get text() {
return VersionString.encode(this);
}
/**
* Extrats and parses the version string from a message payload
* @param input
*/
static extract(input) {
if (typeof input !== "string") {
input = decodeUtf8(input.slice(0, 24));
}
const match = input.match(REGEX_VERSION_JSON);
if (!match) {
const preview = typeof input === "string" ? input.slice(0, 50) : String(input).slice(0, 50);
throw new Error(`Unable to extract "v" field. Expected JSON object with "v" property at start (format: {"v":"..."}), got "${preview}${input.length > 50 ? "..." : ""}"`);
}
return VersionString.parse(match[1]);
}
/**
* Parses a version string into a {@link VersionString} object
*
* @param input The version string
* @returns The parsed {@link VersionString} object
*/
static parse(input) {
if (input.endsWith(".") && input.length === 16) {
const protocol = input.slice(0, 4);
const major = decodeBase64Int(input.slice(4, 5));
const minor = decodeBase64Int(input.slice(5, 7));
const kind = input.slice(7, 11);
const size = decodeBase64Int(input.slice(12, 15));
return new VersionString({
protocol,
major,
minor,
legacy: false,
kind,
size,
});
}
if (input.endsWith("_") && input.length === 17) {
const protocol = input.slice(0, 4);
const major = parseInt(input.slice(4, 5), 16);
const minor = parseInt(input.slice(5, 6), 16);
const format = input.slice(6, 10);
const size = parseInt(input.slice(10, 16), 16);
return new VersionString({
protocol,
major,
minor,
kind: format,
size,
legacy: true,
});
}
throw new Error(`Invalid version string format. Expected 17-char legacy format (ending with "_") or 16-char modern format (ending with "."), got "${input}"`);
}
static encode(init) {
const protocol = init.protocol;
const major = init.major ?? 1;
const minor = init.minor ?? 0;
const format = init.kind ?? "JSON";
if (init.legacy) {
const version = `${encodeHexInt(major, 1)}${encodeHexInt(minor, 1)}`;
const size = encodeHexInt(init.size ?? 0, 6);
return `${protocol}${version}${format}${size}_`;
}
const version = `${encodeBase64Int(major, 1)}${encodeBase64Int(minor, 2)}`;
const size = encodeBase64Int(init.size ?? 0, 4);
return `${protocol}${version}${format}${size}.`;
}
static KERI_LEGACY = new VersionString({
protocol: "KERI",
major: 1,
minor: 0,
kind: "JSON",
legacy: true,
}).text;
static KERI = new VersionString({
protocol: "KERI",
major: 2,
minor: 0,
kind: "JSON",
legacy: false,
}).text;
static ACDC_LEGACY = new VersionString({
protocol: "ACDC",
major: 1,
minor: 0,
kind: "JSON",
legacy: true,
}).text;
static ACDC = new VersionString({
protocol: "ACDC",
major: 1,
minor: 0,
kind: "JSON",
legacy: false,
}).text;
}