feat(subscribe): wrap yields in ResponseEnvelope

- Change subscribe() return type to AsyncGenerator<ResponseEnvelope, void, unknown>
- Check isResponseEnvelope() on each yielded value: pass through if already an envelope
- Wrap raw values with localEnvelope(value, operationId) with fresh timestamp per yield
- Preserve generator cleanup (generator.return()) in finally block
- Preserve existing spec/handler not-found error behavior
- Add 13 tests covering wrapping, passthrough, timestamps, mixed yields, early termination
This commit is contained in:
2026-05-11 02:06:20 +00:00
parent e111e1b4d8
commit 6290feffb0
2 changed files with 304 additions and 2 deletions

View File

@@ -1,12 +1,13 @@
import type { OperationContext } from "./types.js";
import { OperationRegistry } from "./registry.js";
import { type ResponseEnvelope, isResponseEnvelope, localEnvelope } from "./response-envelope.js";
export async function* subscribe(
registry: OperationRegistry,
operationId: string,
input: unknown,
context: OperationContext,
): AsyncGenerator<unknown, void, unknown> {
): AsyncGenerator<ResponseEnvelope, void, unknown> {
const spec = registry.getSpec(operationId);
if (!spec) {
@@ -23,7 +24,11 @@ export async function* subscribe(
try {
for await (const value of generator) {
yield value;
if (isResponseEnvelope(value)) {
yield value;
} else {
yield localEnvelope(value, operationId);
}
}
} finally {
if (generator.return) {