Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.xandrlabs.ai/llms.txt

Use this file to discover all available pages before exploring further.

canonicalize() converts a JavaScript value to a deterministic JSON string following RFC 8785 JSON Canonicalization Scheme (JCS). It sorts object keys alphabetically at every nesting level, preserves array order, and produces no insignificant whitespace. Because the output is fully deterministic, two logically equivalent objects always produce the same string — and therefore the same hash. This function is the foundation of every identity derivation primitive in the ALX Protocol. kbHashFromEnvelope, domainHashFromObject, artifactHashFromPayload, and the CID helpers all call canonicalize() internally. If you are implementing a cross-language conformance check, your serializer must reproduce the reference output byte-for-byte.
import { canonicalize } from "@alx/protocol";

Signature

function canonicalize(value: unknown): string

Parameters

value
unknown
required
The value to serialize. Accepts booleans, finite numbers, strings, arrays, and plain objects (recursively). All object keys are sorted lexicographically. Array element order is preserved.The following inputs are rejected and throw immediately:
  • null — not allowed anywhere in the value tree
  • BigInt — not a JSON-safe type
  • Non-finite numbers (Infinity, -Infinity, NaN)
  • Any other non-JSON-representable type (e.g. undefined, functions, symbols)

Return value

result
string
A canonical JSON string with no insignificant whitespace. Object keys are sorted alphabetically. The output is valid UTF-8 and safe to pass directly to a hash function.

Example

import { canonicalize } from "@alx/protocol";

const envelope = {
  type: "practice",
  domain: "software.security",
  sources: ["0xabc123", "0xdef456"],
  tier: "open",
};

const canonical = canonicalize(envelope);
// '{"domain":"software.security","sources":["0xabc123","0xdef456"],"tier":"open","type":"practice"}'
Notice that the keys appear in alphabetical order (domainsourcestiertype), regardless of their insertion order in the source object.

Error cases

canonicalize() throws a synchronous Error for any input that cannot be represented in canonical JSON:
// null — throws: "Null values are not allowed in canonical input"
canonicalize(null);

// BigInt — throws: "BigInt values are not allowed in canonical input"
canonicalize(42n);

// Non-finite number — throws: "Non-finite number in canonical input"
canonicalize(Infinity);
canonicalize(NaN);

// Unsupported type — throws: "Unsupported type for canonicalization"
canonicalize(undefined);
null nested inside an object or array also throws, so validate your input before passing it to canonicalize().

Notes

  • The output conforms to RFC 8785 JCS semantics. Conformance is verified against the golden test vectors in test-vectors/canonical/ — matching those vectors byte-for-byte is the conformance gate for independent implementations.
  • Integers are serialized without a decimal point (42, not 42.0). Non-integer finite numbers use standard JSON.stringify representation.
  • Do not call canonicalize() on an envelope that still contains its kbHash field. Strip kbHash before hashing so that the identity computation is not circular. Use kbHashFromEnvelope(), which performs this normalization for you.