feat(env): complete envelope integration for buildEnv - propagate identity in call protocol mode and add comprehensive tests

- Pass context.identity through to callMap.call() in call protocol mode
  for proper identity propagation in nested operation calls
- Add identity propagation test coverage for both with-identity and
  without-identity scenarios
- Add test for parentRequestId propagation through callMap
- Add test for PendingRequestMap as callMap integration
- Add test for pre-built ResponseEnvelope pass-through in direct mode
- Add test for Value.Cast normalization via execute in direct mode
- Add test for empty registry, namespace grouping, and local source
  metadata verification
- All 216 tests passing, build and lint clean
This commit is contained in:
2026-05-11 02:37:44 +00:00
parent 7a25cb9c0c
commit d74b750ecb
2 changed files with 217 additions and 2 deletions

View File

@@ -1,8 +1,9 @@
import { describe, it, expect } from "vitest";
import { describe, it, expect, vi } from "vitest";
import { OperationRegistry, OperationType, buildEnv, type IOperationDefinition, type OperationContext } from "../src/index.js";
import * as Type from "@alkdev/typebox";
import { PendingRequestMap } from "../src/call.js";
import { localEnvelope, isResponseEnvelope, type ResponseEnvelope } from "../src/response-envelope.js";
import { localEnvelope, httpEnvelope, isResponseEnvelope, type ResponseEnvelope } from "../src/response-envelope.js";
import type { Identity } from "../src/types.js";
function makeOperation(name: string, handler?: any): IOperationDefinition {
return {
@@ -39,6 +40,55 @@ describe("buildEnv", () => {
expect(result.data).toEqual({ result: "test" });
});
it("returns ResponseEnvelope with local source from direct mode", async () => {
const registry = new OperationRegistry();
registry.register(makeOperation("op1"));
const env = buildEnv({
registry,
context: {} as OperationContext,
});
const result = await env.test.op1({ value: "hello" });
expect(isResponseEnvelope(result)).toBe(true);
expect(result.meta.source).toBe("local");
if (result.meta.source === "local") {
expect(result.meta.operationId).toBe("test.op1");
expect(typeof result.meta.timestamp).toBe("number");
}
expect(result.data).toEqual({ result: "hello" });
});
it("passes pre-built ResponseEnvelope through from handler in direct mode", async () => {
const registry = new OperationRegistry();
const httpEnv = httpEnvelope({ items: [1, 2, 3] }, {
statusCode: 200,
headers: { "content-type": "application/json" },
contentType: "application/json",
});
registry.register({
name: "httpOp",
namespace: "test",
version: "1.0.0",
type: OperationType.QUERY,
description: "http op",
inputSchema: Type.Object({ value: Type.String() }),
outputSchema: Type.Unknown(),
accessControl: { requiredScopes: [] },
handler: async () => httpEnv,
});
const env = buildEnv({
registry,
context: {} as OperationContext,
});
const result = await env.test.httpOp({ value: "x" });
expect(isResponseEnvelope(result)).toBe(true);
expect(result.meta.source).toBe("http");
expect(result.data).toEqual({ items: [1, 2, 3] });
});
it("filters out SUBSCRIPTION operations", () => {
const registry = new OperationRegistry();
registry.register(makeOperation("query"));
@@ -94,4 +144,168 @@ describe("buildEnv", () => {
expect(isResponseEnvelope(result)).toBe(true);
expect(result.data).toEqual({ result: "routed: test.readFile" });
});
it("passes parentRequestId through callMap in call protocol mode", async () => {
const registry = new OperationRegistry();
registry.register(makeOperation("op1"));
let capturedOptions: any = null;
const callMap = {
call: async (opId: string, input: unknown, opts?: any): Promise<ResponseEnvelope> => {
capturedOptions = opts;
return localEnvelope({ result: "ok" }, opId);
},
};
const context: OperationContext = {
requestId: "parent-req-123",
};
const env = buildEnv({
registry,
context,
callMap,
});
await env.test.op1({ value: "test" });
expect(capturedOptions).not.toBeNull();
expect(capturedOptions.parentRequestId).toBe("parent-req-123");
});
it("passes identity through callMap in call protocol mode", async () => {
const registry = new OperationRegistry();
registry.register(makeOperation("op1"));
let capturedOptions: any = null;
const callMap = {
call: async (opId: string, input: unknown, opts?: any): Promise<ResponseEnvelope> => {
capturedOptions = opts;
return localEnvelope({ result: "ok" }, opId);
},
};
const identity: Identity = { id: "user1", scopes: ["read"] };
const context: OperationContext = {
requestId: "parent-req-456",
identity,
};
const env = buildEnv({
registry,
context,
callMap,
});
await env.test.op1({ value: "test" });
expect(capturedOptions).not.toBeNull();
expect(capturedOptions.parentRequestId).toBe("parent-req-456");
expect(capturedOptions.identity).toEqual(identity);
});
it("does not pass identity when context has no identity in call protocol mode", async () => {
const registry = new OperationRegistry();
registry.register(makeOperation("op1"));
let capturedOptions: any = null;
const callMap = {
call: async (opId: string, input: unknown, opts?: any): Promise<ResponseEnvelope> => {
capturedOptions = opts;
return localEnvelope({ result: "ok" }, opId);
},
};
const context: OperationContext = {
requestId: "parent-req-789",
};
const env = buildEnv({
registry,
context,
callMap,
});
await env.test.op1({ value: "test" });
expect(capturedOptions).not.toBeNull();
expect(capturedOptions.parentRequestId).toBe("parent-req-789");
expect(capturedOptions.identity).toBeUndefined();
});
it("works with PendingRequestMap as callMap", async () => {
const registry = new OperationRegistry();
registry.register(makeOperation("echo"));
const callMap = new PendingRequestMap();
const env = buildEnv({
registry,
context: {} as OperationContext,
callMap,
});
const callPromise = env.test.echo({ value: "hello" });
const requestId = [...(callMap as any).requests.keys()][0];
callMap.respond(requestId, localEnvelope({ result: "echoed" }, "test.echo"));
const result = await callPromise;
expect(isResponseEnvelope(result)).toBe(true);
expect(result.data).toEqual({ result: "echoed" });
expect(result.meta.source).toBe("local");
});
it("returns empty env when registry has no specs", () => {
const registry = new OperationRegistry();
const env = buildEnv({
registry,
context: {} as OperationContext,
});
expect(Object.keys(env)).toHaveLength(0);
});
it("groups operations by namespace", () => {
const registry = new OperationRegistry();
registry.register(makeOperation("op1"));
registry.register({
...makeOperation("op2"),
namespace: "other",
});
const env = buildEnv({
registry,
context: {} as OperationContext,
});
expect(env.test).toBeDefined();
expect(env.other).toBeDefined();
expect(env.test.op1).toBeDefined();
expect(env.other.op2).toBeDefined();
});
it("Value.Cast normalization applies in direct mode via execute", async () => {
const registry = new OperationRegistry();
registry.register({
name: "withDefaults",
namespace: "test",
version: "1.0.0",
type: OperationType.QUERY,
description: "op with default fields",
inputSchema: Type.Object({ value: Type.String() }),
outputSchema: Type.Object({ name: Type.String(), count: Type.Number({ default: 0 }) }),
accessControl: { requiredScopes: [] },
handler: async () => ({ name: "test" }),
});
const env = buildEnv({
registry,
context: {} as OperationContext,
});
const result = await env.test.withDefaults({ value: "x" });
expect(isResponseEnvelope(result)).toBe(true);
expect(result.data).toEqual({ name: "test", count: 0 });
});
});