Files
openclaw/extensions/reef/protocol/canonical.ts
Peter Steinberger 882b2fe900 feat(channels): bundle Reef guarded claw-to-claw channel (#106232)
* feat(channels): bundle Reef guarded claw-to-claw channel

Moves the Reef channel extension from openclaw/reef into the bundled extensions tree with the wire protocol vendored under extensions/reef/protocol. Includes channelConfigs manifest metadata, runtime status reporting via setStatus/buildAccountSnapshot, abort-aware inbox shutdown, monotonic device-auth timestamps, and immutable-model guard admission (dated snapshots plus documented gpt-5.6 ids).

* fix(reef): pin zod exactly per dependency pin guard

* style(reef): satisfy extension lint gates

Curly braces in vendored protocol, explicit type re-exports, typed catch callbacks, Object.assign over map-spread, abort-aware loop restructure.

* fix(reef): CI gates — knip workspace, boundary tsconfig, facade imports, cycle break, contract baselines

- knip: reef workspace project includes vendored protocol/ (owns noble deps)
- tsconfig: conform to canonical extension package-boundary include/exclude; add @openclaw/plugin-sdk devDependency
- imports: channel-inbound/channel-outbound facades instead of deprecated subpaths
- protocol: home ReplayStore contract in envelope.ts to break the envelope<->replay type cycle
- baselines: reef in unguarded runtime-api list; regenerate bundled channel config metadata

* feat(reef): plugin catalog cover art, channel label, changelog revert

* fix(reef): drop unused error-class exports, register lint suppression

* fix(reef): knip entry surface for vendored protocol, explicit WebSocketLike export
2026-07-13 05:17:44 -07:00

35 lines
1.1 KiB
TypeScript

import { sha256 } from "@noble/hashes/sha2.js";
import { hex, utf8 } from "./encoding.js";
export function canonicalJson(value: unknown): string {
if (value === null || typeof value === "boolean" || typeof value === "string") {
return JSON.stringify(value);
}
if (typeof value === "number") {
if (!Number.isFinite(value)) {
throw new TypeError("canonical JSON requires finite numbers");
}
return JSON.stringify(value);
}
if (Array.isArray(value)) {
return `[${value.map(canonicalJson).join(",")}]`;
}
if (typeof value === "object") {
const record = value as Record<string, unknown>;
const entries = Object.keys(record)
.filter((key) => record[key] !== undefined)
.toSorted()
.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`);
return `{${entries.join(",")}}`;
}
throw new TypeError("unsupported canonical JSON value");
}
export function canonicalBytes(value: unknown): Uint8Array {
return utf8(canonicalJson(value));
}
export function sha256Hex(value: Uint8Array): string {
return hex(sha256(value));
}