mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 22:01:11 +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
66 lines
1.7 KiB
TypeScript
66 lines
1.7 KiB
TypeScript
import { randomBytes } from "@noble/hashes/utils.js";
|
|
|
|
const CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
|
|
export interface UlidFactoryOptions {
|
|
clock?: () => number;
|
|
rng?: (length: number) => Uint8Array;
|
|
}
|
|
|
|
export function createMonotonicUlidFactory(options: UlidFactoryOptions = {}): () => string {
|
|
const clock = options.clock ?? Date.now;
|
|
const rng = options.rng ?? randomBytes;
|
|
let lastTime = -1;
|
|
let randomness = new Uint8Array(10);
|
|
return () => {
|
|
const now = Math.floor(clock());
|
|
if (!Number.isSafeInteger(now) || now < 0 || now > 0xffffffffffff) {
|
|
throw new Error("invalid ULID clock");
|
|
}
|
|
if (now > lastTime) {
|
|
const generated = rng(10);
|
|
if (generated.length !== 10) {
|
|
throw new Error("invalid ULID rng");
|
|
}
|
|
randomness = generated.slice();
|
|
lastTime = now;
|
|
} else {
|
|
increment(randomness);
|
|
}
|
|
return encodeTime(lastTime) + encodeRandom(randomness);
|
|
};
|
|
}
|
|
|
|
function increment(value: Uint8Array): void {
|
|
for (let index = value.length - 1; index >= 0; index--) {
|
|
value[index] = (value[index]! + 1) & 0xff;
|
|
if (value[index] !== 0) {
|
|
return;
|
|
}
|
|
}
|
|
throw new Error("ULID monotonic overflow");
|
|
}
|
|
|
|
function encodeTime(time: number): string {
|
|
let value = BigInt(time);
|
|
let output = "";
|
|
for (let index = 0; index < 10; index++) {
|
|
output = CROCKFORD[Number(value & 31n)]! + output;
|
|
value >>= 5n;
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function encodeRandom(bytes: Uint8Array): string {
|
|
let value = 0n;
|
|
for (const byte of bytes) {
|
|
value = (value << 8n) | BigInt(byte);
|
|
}
|
|
let output = "";
|
|
for (let index = 0; index < 16; index++) {
|
|
output = CROCKFORD[Number(value & 31n)]! + output;
|
|
value >>= 5n;
|
|
}
|
|
return output;
|
|
}
|