Files
operations/src/env.ts
glm-5.1 3150a49578 feat(registry-envelope-integration): update execute(), call, subscribe, env to return ResponseEnvelope
- OperationRegistry.execute() now returns Promise<ResponseEnvelope<TOutput>>
- Applies shared result pipeline: detect → wrap → normalize → validate
- Uses KindGuard.IsUnknown() to check if Value.Cast should be applied
- PendingRequestMap.call() returns Promise<ResponseEnvelope>
- PendingRequestMap.respond() validates envelope via isResponseEnvelope()
- CallHandler captures handler result, wraps, normalizes, validates, publishes
- CallEventSchema call.responded.output changed to ResponseEnvelopeSchema
- subscribe() yields ResponseEnvelope with isResponseEnvelope() passthrough
- OperationEnv inner functions return Promise<ResponseEnvelope>
- Tests updated for all new return types and behaviors
- 171 tests passing, build and lint clean
2026-05-11 02:19:05 +00:00

57 lines
1.7 KiB
TypeScript

import { OperationType } from "./types.js";
import type { OperationContext, OperationEnv, Identity } from "./types.js";
import type { OperationRegistry } from "./registry.js";
import type { ResponseEnvelope } from "./response-envelope.js";
import { getLogger } from "@logtape/logtape";
const logger = getLogger("operations:env");
export interface CallMap {
call(operationId: string, input: unknown, options?: { parentRequestId?: string; deadline?: number; identity?: Identity }): Promise<ResponseEnvelope>;
}
export interface EnvOptions {
registry: OperationRegistry;
context: OperationContext;
allowedNamespaces?: string[];
callMap?: CallMap;
}
export function buildEnv(options: EnvOptions): OperationEnv {
const { registry, context, allowedNamespaces, callMap } = options;
const specs = registry.getAllSpecs();
const namespaces: OperationEnv = {};
for (const spec of specs) {
if (allowedNamespaces && !allowedNamespaces.includes(spec.namespace)) {
continue;
}
if (spec.type === OperationType.SUBSCRIPTION) {
continue;
}
if (!namespaces[spec.namespace]) {
namespaces[spec.namespace] = {};
}
const operationId = `${spec.namespace}.${spec.name}`;
if (callMap) {
namespaces[spec.namespace][spec.name] = async (input: unknown) => {
logger.debug(`Call protocol: ${operationId}`);
return await callMap.call(operationId, input, {
parentRequestId: context.requestId,
});
};
} else {
namespaces[spec.namespace][spec.name] = async (input: unknown) => {
logger.debug(`Executing: ${operationId}`);
return await registry.execute(operationId, input, context);
};
}
}
return namespaces;
}