mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-24 10:21:15 +00:00
* 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
35 lines
1.1 KiB
TypeScript
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));
|
|
}
|