feat(registry): add fail-closed runtime lookup

This commit is contained in:
chick
2026-07-17 01:34:13 +08:00
parent 7b91dbbad1
commit 243565a75e
4 changed files with 244 additions and 1 deletions
+9
View File
@@ -0,0 +1,9 @@
export {
OperationRegistry,
RuntimeRegistryError,
listOperations,
operationRegistry,
requireExecutableOperation,
requireOperation,
} from './runtime-registry.ts';
export type { RuntimeOperationDescriptor, RuntimeRegistryErrorCode } from './runtime-registry.ts';
@@ -0,0 +1,122 @@
import { operationAcceptanceOverrides58e2204 } from './acceptance-58e2204.ts';
import { upstream58e2204Operations } from './upstream-58e2204.ts';
export type RuntimeRegistryErrorCode = 'UNKNOWN_OPERATION' | 'DEDICATED_FLOW_REQUIRED';
export class RuntimeRegistryError extends Error {
readonly code: RuntimeRegistryErrorCode;
constructor(code: RuntimeRegistryErrorCode, message: string) {
super(message);
this.name = 'RuntimeRegistryError';
this.code = code;
}
}
type UpstreamOperation = (typeof upstream58e2204Operations)[number];
type AcceptanceOverride = Record<string, unknown> & { uiStrategy?: unknown };
export type RuntimeOperationDescriptor = Readonly<
UpstreamOperation & {
module: UpstreamOperation['upstreamDomain'];
uiStrategy: string;
}
>;
const OPERATION_ID_PATTERN = /^[A-Za-z][A-Za-z0-9]*$/;
const EXPECTED_OPERATION_COUNT = 117;
function deepFreeze<T>(value: T): T {
if (value === null || typeof value !== 'object' || Object.isFrozen(value)) return value;
for (const child of Object.values(value)) deepFreeze(child);
return Object.freeze(value);
}
function unknownOperation(operationId: unknown): RuntimeRegistryError {
const rendered = typeof operationId === 'string' && operationId ? operationId : '<invalid>';
return new RuntimeRegistryError('UNKNOWN_OPERATION', `Unknown operation: ${rendered}`);
}
/** Runtime-only, operationId-keyed projection of the frozen audited registry. */
export class OperationRegistry {
readonly #byOperationId: ReadonlyMap<string, RuntimeOperationDescriptor>;
readonly #operations: readonly RuntimeOperationDescriptor[];
constructor(
operations: readonly UpstreamOperation[],
acceptanceOverrides: Readonly<Record<string, AcceptanceOverride>>,
) {
const sourceById = new Map<string, UpstreamOperation>();
for (const operation of operations) {
const id = operation.operationId;
if (!OPERATION_ID_PATTERN.test(id)) throw new Error(`invalid operationId in registry: ${id}`);
if (sourceById.has(id)) throw new Error(`duplicate operationId: ${id}`);
sourceById.set(id, operation);
}
if (sourceById.size !== EXPECTED_OPERATION_COUNT) {
throw new Error(
`runtime registry must contain exactly ${EXPECTED_OPERATION_COUNT} operations`,
);
}
const descriptors: RuntimeOperationDescriptor[] = [];
for (const id of [...sourceById.keys()].sort()) {
if (!Object.hasOwn(acceptanceOverrides, id)) {
throw new Error(`missing acceptance override: ${id}`);
}
const acceptance = acceptanceOverrides[id];
if (!acceptance || typeof acceptance.uiStrategy !== 'string' || !acceptance.uiStrategy) {
throw new Error(`missing acceptance override: ${id}`);
}
const operation = sourceById.get(id)!;
const descriptor = structuredClone({
...operation,
module: operation.upstreamDomain,
uiStrategy: acceptance.uiStrategy,
}) as RuntimeOperationDescriptor;
descriptors.push(deepFreeze(descriptor));
}
this.#operations = Object.freeze(descriptors);
this.#byOperationId = new Map(
descriptors.map((descriptor) => [descriptor.operationId, descriptor]),
);
Object.freeze(this);
}
listOperations(): readonly RuntimeOperationDescriptor[] {
return this.#operations;
}
requireOperation(operationId: string): RuntimeOperationDescriptor {
if (typeof operationId !== 'string' || !OPERATION_ID_PATTERN.test(operationId)) {
throw unknownOperation(operationId);
}
const operation = this.#byOperationId.get(operationId);
if (!operation) throw unknownOperation(operationId);
return operation;
}
requireExecutableOperation(operationId: string): RuntimeOperationDescriptor {
const operation = this.requireOperation(operationId);
if (operation.executionPolicy === 'dedicatedFlow') {
throw new RuntimeRegistryError(
'DEDICATED_FLOW_REQUIRED',
`Operation requires a dedicated flow: ${operationId}`,
);
}
return operation;
}
}
export const operationRegistry = new OperationRegistry(
upstream58e2204Operations,
operationAcceptanceOverrides58e2204,
);
export const listOperations = (): readonly RuntimeOperationDescriptor[] =>
operationRegistry.listOperations();
export const requireOperation = (operationId: string): RuntimeOperationDescriptor =>
operationRegistry.requireOperation(operationId);
export const requireExecutableOperation = (operationId: string): RuntimeOperationDescriptor =>
operationRegistry.requireExecutableOperation(operationId);