From 5835cc821a5b1e359b1aed5e960d083d9f29a0b9 Mon Sep 17 00:00:00 2001 From: reaatech Date: Sun, 7 Jun 2026 23:28:17 +0000 Subject: [PATCH] fix(tighten-type-usage-replace-lazy-any-unknown-with-true-types): close #27 All checks pass. Changed `createMessageResult: undefined as unknown` to `createMessageResult: undefined as Record | Promise | undefined` in `packages/mcp-bridge/src/a2a-to-mcp.test.ts:39`, replacing the lazy `unknown` assertion with an honest union type that covers both fixture shapes the field is assigned to (a generic object in `beforeEach` and a rejected `Promise` in the sampling-failure test). --- ...azy-any-unknown-with-true-types-issue27.md | 11 ++++ packages/client/src/client-unit.test.ts | 16 +++--- packages/mcp-bridge/src/a2a-to-mcp.test.ts | 50 +++++++++++-------- packages/mcp-bridge/src/mcp-to-a2a.test.ts | 28 +++++------ packages/observability/src/telemetry.test.ts | 21 ++++++-- packages/persistence/src/postgres.test.ts | 44 ++++++++++------ packages/persistence/src/postgres.ts | 2 +- packages/persistence/src/redis.test.ts | 7 +-- packages/server/src/hono.test.ts | 12 +++-- packages/server/src/rate-limiter.test.ts | 8 ++- packages/server/src/sse-redis.test.ts | 34 ++++++------- 11 files changed, 145 insertions(+), 88 deletions(-) create mode 100644 .changeset/repobot-tighten-type-usage-replace-lazy-any-unknown-with-true-types-issue27.md diff --git a/.changeset/repobot-tighten-type-usage-replace-lazy-any-unknown-with-true-types-issue27.md b/.changeset/repobot-tighten-type-usage-replace-lazy-any-unknown-with-true-types-issue27.md new file mode 100644 index 0000000..cba1624 --- /dev/null +++ b/.changeset/repobot-tighten-type-usage-replace-lazy-any-unknown-with-true-types-issue27.md @@ -0,0 +1,11 @@ +--- +"@reaatech/a2a-reference-client": patch +"@reaatech/a2a-reference-mcp-bridge": patch +"@reaatech/a2a-reference-observability": patch +"@reaatech/a2a-reference-persistence": patch +"@reaatech/a2a-reference-server": patch +--- + +Fix: Tighten type usage: replace lazy any/unknown with true types + +Closes #27 diff --git a/packages/client/src/client-unit.test.ts b/packages/client/src/client-unit.test.ts index ac1268e..5fe35e2 100644 --- a/packages/client/src/client-unit.test.ts +++ b/packages/client/src/client-unit.test.ts @@ -175,7 +175,7 @@ describe('A2AClient unit tests', () => { ); const client = new A2AClient({ baseUrl: 'http://localhost:3000', fetchImpl: mockFetch }); - const events: unknown[] = []; + const events: Array> = []; for await (const event of client.sendSubscribe({ messageId: '1', role: 'user', @@ -206,7 +206,7 @@ describe('A2AClient unit tests', () => { ); const client = new A2AClient({ baseUrl: 'http://localhost:3000', fetchImpl: mockFetch }); - const events: unknown[] = []; + const events: Array> = []; for await (const event of client.subscribe('t1')) { events.push(event); } @@ -221,13 +221,15 @@ describe('A2AClient unit tests', () => { const read = vi.fn().mockRejectedValue(new Error('Stream error')); const mockBody = { getReader: () => ({ read, releaseLock }), - } as unknown as ReadableStream; + } as unknown as { + getReader: () => { read: ReturnType; releaseLock: ReturnType }; + }; const mockResponse = { ok: true, body: mockBody, headers: new Headers({ 'content-type': 'text/event-stream' }), - } as unknown as Response; + } as unknown as { ok: boolean; body: unknown; headers: Headers }; const mockFetch = vi .fn() @@ -310,7 +312,7 @@ describe('A2AClient unit tests', () => { ok: true, body: null, headers: new Headers({ 'content-type': 'text/event-stream' }), - } as unknown as Response; + } as unknown as { ok: boolean; body: null; headers: Headers }; const mockFetch = vi .fn() @@ -362,7 +364,7 @@ describe('A2AClient unit tests', () => { ); const client = new A2AClient({ baseUrl: 'http://localhost:3000', fetchImpl: mockFetch }); - const events: unknown[] = []; + const events: Array> = []; for await (const event of client.sendSubscribe({ messageId: '1', role: 'user', @@ -505,7 +507,7 @@ describe('A2AClient unit tests', () => { ok: true, body: null, headers: new Headers({ 'content-type': 'text/event-stream' }), - } as unknown as Response; + } as unknown as { ok: boolean; body: null; headers: Headers }; const mockFetch = vi .fn() diff --git a/packages/mcp-bridge/src/a2a-to-mcp.test.ts b/packages/mcp-bridge/src/a2a-to-mcp.test.ts index 2cf45eb..7fb20aa 100644 --- a/packages/mcp-bridge/src/a2a-to-mcp.test.ts +++ b/packages/mcp-bridge/src/a2a-to-mcp.test.ts @@ -3,7 +3,10 @@ import type { AgentCard, Skill } from '@reaatech/a2a-reference-core'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { A2aAsMcpServer } from './a2a-to-mcp.js'; -const mockHandlers = new Map Promise>(); +const mockHandlers = new Map< + string, + (request: Record) => Promise> +>(); // Mutable mock state for A2AClient const mockA2AState = vi.hoisted(() => ({ @@ -21,23 +24,19 @@ const mockA2AState = vi.hoisted(() => ({ { url: 'http://localhost:3000', protocolBinding: 'a2a', protocolVersion: '0.3.0' }, ], } as AgentCard, - sendMessageResult: { id: 'task-1', status: { state: 'submitted' } } as unknown, + sendMessageResult: { id: 'task-1', status: { state: 'submitted' } } as Record, getTaskResult: { id: 'task-1', status: { state: 'completed' }, artifacts: [{ name: 'result', parts: [{ kind: 'text', text: '42' }] }], - } as unknown, + } as Record, subscribeEvents: [] as Array, })); // Mutable mock state for MCP Server const mockServerState = vi.hoisted(() => ({ - clientCapabilities: undefined as { sampling?: unknown } | undefined, - createMessageResult: { - model: 'test-model', - role: 'assistant', - content: { type: 'text', text: 'User input' }, - } as unknown, + clientCapabilities: undefined as { sampling?: Record } | undefined, + createMessageResult: undefined as Record | Promise | undefined, })); // Mock the A2AClient @@ -59,15 +58,20 @@ vi.mock('@modelcontextprotocol/sdk/server/index.js', () => ({ Server: vi.fn().mockImplementation(() => ({ setRequestHandler: vi .fn() - .mockImplementation((schema: unknown, handler: (req: unknown) => Promise) => { - const key = - schema === ListToolsRequestSchema - ? 'listTools' - : schema === CallToolRequestSchema - ? 'callTool' - : 'unknown'; - mockHandlers.set(key, handler); - }), + .mockImplementation( + ( + schema: unknown, + handler: (req: Record) => Promise>, + ) => { + const key = + schema === ListToolsRequestSchema + ? 'listTools' + : schema === CallToolRequestSchema + ? 'callTool' + : 'unknown'; + mockHandlers.set(key, handler); + }, + ), connect: vi.fn().mockResolvedValue(undefined), close: vi.fn().mockResolvedValue(undefined), getClientCapabilities: vi.fn().mockImplementation(() => mockServerState.clientCapabilities), @@ -155,7 +159,9 @@ describe('A2aAsMcpServer', () => { await server.initialize(); const listHandler = mockHandlers.get('listTools'); if (!listHandler) throw new Error('Missing listTools handler'); - const result = (await listHandler({} as never)) as { tools: Array<{ inputSchema: unknown }> }; + const result = (await listHandler({} as never)) as { + tools: Array<{ inputSchema: Record | undefined }>; + }; expect(result.tools[0].inputSchema).toEqual({ type: 'object', properties: { expression: { type: 'string' } }, @@ -170,7 +176,9 @@ describe('A2aAsMcpServer', () => { await server.initialize(); const listHandler = mockHandlers.get('listTools'); if (!listHandler) throw new Error('Missing listTools handler'); - const result = (await listHandler({} as never)) as { tools: Array<{ inputSchema: unknown }> }; + const result = (await listHandler({} as never)) as { + tools: Array<{ inputSchema: Record | undefined }>; + }; expect(result.tools[0].inputSchema).toEqual({ type: 'object', properties: { @@ -263,7 +271,7 @@ describe('A2aAsMcpServer', () => { id: 'task-1', status: { state: 'completed' }, artifacts: [{ name: 'result', parts: [{ kind: 'text', text: 'Hello, User' }] }], - } as unknown; + } as Record; mockServerState.clientCapabilities = { sampling: {} }; diff --git a/packages/mcp-bridge/src/mcp-to-a2a.test.ts b/packages/mcp-bridge/src/mcp-to-a2a.test.ts index ed5acc6..3c1cc5b 100644 --- a/packages/mcp-bridge/src/mcp-to-a2a.test.ts +++ b/packages/mcp-bridge/src/mcp-to-a2a.test.ts @@ -51,7 +51,7 @@ describe('McpToolAdapter', () => { }); // Replace the internal client with our mock - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); const card = adapter.getAgentCard(); @@ -94,7 +94,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); const card = adapter.getAgentCard(); @@ -133,7 +133,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); const artifacts = await adapter.executeTask( @@ -182,7 +182,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await adapter.executeTask( @@ -228,7 +228,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await adapter.executeTask( @@ -274,7 +274,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); const artifacts = await adapter.executeTask( @@ -317,7 +317,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await expect( @@ -360,7 +360,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await expect( @@ -399,7 +399,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.disconnect(); expect(mockClient.close).toHaveBeenCalled(); }); @@ -428,7 +428,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await expect( @@ -466,7 +466,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await expect( @@ -503,7 +503,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); const artifacts = await adapter.executeTask( @@ -540,7 +540,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await adapter.executeTask( @@ -574,7 +574,7 @@ describe('McpToolAdapter', () => { }, }); - (adapter as unknown as Record).client = mockClient; + (adapter as unknown as { client: typeof mockClient }).client = mockClient; await adapter.initialize(); await adapter.executeTask( diff --git a/packages/observability/src/telemetry.test.ts b/packages/observability/src/telemetry.test.ts index bedce43..2615a51 100644 --- a/packages/observability/src/telemetry.test.ts +++ b/packages/observability/src/telemetry.test.ts @@ -101,7 +101,10 @@ describe('setTelemetryProvider', () => { startSpan() { return new NoopSpan(); }, - async startActiveSpan(_name: string, ...args: unknown[]) { + async startActiveSpan( + _name: string, + ...args: [Record | TelemetrySpan, ...unknown[]] + ) { const fn = args.length === 2 ? args[1] : args[0]; const result = await (fn as (span: TelemetrySpan) => Promise)(new NoopSpan()); return result; @@ -147,7 +150,8 @@ describe('getTracer', () => { }); it('passes name and version to provider', () => { - const spy = vi.fn<(...args: unknown[]) => ReturnType>(); + const spy = + vi.fn<(...args: [string?, string?]) => ReturnType>(); const provider: TelemetryProvider = { getTracer: spy, getMeter() { @@ -183,14 +187,17 @@ describe('getMeter', () => { }); it('passes name and version to provider', () => { - const spy = vi.fn<(...args: unknown[]) => ReturnType>(); + const spy = vi.fn<(...args: [string?, string?]) => ReturnType>(); const provider: TelemetryProvider = { getTracer() { return { startSpan() { return new NoopSpan(); }, - async startActiveSpan(_name: string, ...args: unknown[]) { + async startActiveSpan( + _name: string, + ...args: [Record | TelemetrySpan, ...unknown[]] + ) { const fn = args.length === 2 ? args[1] : args[0]; return (fn as (span: TelemetrySpan) => Promise)(new NoopSpan()); }, @@ -300,7 +307,11 @@ describe('withTaskSpan', () => { it('includes task attributes in the span options', async () => { const startActiveSpanSpy = vi.fn( - async (_name: string, _options: unknown, fn: (span: TelemetrySpan) => Promise) => { + async ( + _name: string, + _options: Record, + fn: (span: TelemetrySpan) => Promise, + ) => { return fn(new NoopSpan()); }, ); diff --git a/packages/persistence/src/postgres.test.ts b/packages/persistence/src/postgres.test.ts index 151ea28..146a086 100644 --- a/packages/persistence/src/postgres.test.ts +++ b/packages/persistence/src/postgres.test.ts @@ -24,7 +24,7 @@ beforeEach(() => { }); function createStore() { - return new PostgresTaskStore({ pool: mockPool as any }); + return new PostgresTaskStore({ pool: mockPool as unknown as import('pg').Pool }); } function taskRow(overrides: Record = {}) { @@ -85,18 +85,32 @@ const fullTask: Task = { describe('constructor', () => { it('escapes schema name correctly', () => { - const s = new PostgresTaskStore({ pool: mockPool as any, schemaName: 'test"schema' }); - expect((s as any).taskTable).toContain('"test""schema"'); - expect((s as any).artifactTable).toContain('"test""schema"'); - expect((s as any).historyTable).toContain('"test""schema"'); + const s = new PostgresTaskStore({ + pool: mockPool as unknown as import('pg').Pool, + schemaName: 'test"schema', + }); + const internals = s as unknown as { + taskTable: string; + artifactTable: string; + historyTable: string; + }; + expect(internals.taskTable).toContain('"test""schema"'); + expect(internals.artifactTable).toContain('"test""schema"'); + expect(internals.historyTable).toContain('"test""schema"'); }); it('uses default table prefix when not provided', () => { - const s = new PostgresTaskStore({ pool: mockPool as any }); - expect((s as any).tablePrefix).toBe('a2a'); - expect((s as any).taskTable).toContain('"a2a_tasks"'); - expect((s as any).artifactTable).toContain('"a2a_artifacts"'); - expect((s as any).historyTable).toContain('"a2a_history"'); + const s = new PostgresTaskStore({ pool: mockPool as unknown as import('pg').Pool }); + const internals = s as unknown as { + tablePrefix: string; + taskTable: string; + artifactTable: string; + historyTable: string; + }; + expect(internals.tablePrefix).toBe('a2a'); + expect(internals.taskTable).toContain('"a2a_tasks"'); + expect(internals.artifactTable).toContain('"a2a_artifacts"'); + expect(internals.historyTable).toContain('"a2a_history"'); }); }); @@ -216,7 +230,7 @@ describe('create', () => { await expect(createStore().create(fullTask)).rejects.toThrow('boom'); - const rollbackCall = mockClient.query.mock.calls.find((c: unknown[]) => c[0] === 'ROLLBACK'); + const rollbackCall = mockClient.query.mock.calls.find((c) => (c as [string])[0] === 'ROLLBACK'); expect(rollbackCall).toBeDefined(); }); }); @@ -295,7 +309,7 @@ describe('get', () => { expect(result?.principal).toBeUndefined(); expect(result?.tenantId).toBeUndefined(); expect(result?.status.message).toBeDefined(); - expect((result?.status.message as any).role).toBe('user'); + expect((result?.status.message as { role: string }).role).toBe('user'); expect(result?.metadata).toEqual({ foo: 'bar' }); }); @@ -588,7 +602,7 @@ describe('addHistory', () => { }), ).rejects.toThrow('select fail'); - const rollbackCall = mockClient.query.mock.calls.find((c: unknown[]) => c[0] === 'ROLLBACK'); + const rollbackCall = mockClient.query.mock.calls.find((c) => (c as [string])[0] === 'ROLLBACK'); expect(rollbackCall).toBeDefined(); }); }); @@ -641,7 +655,7 @@ describe('addArtifact', () => { }), ).rejects.toThrow('insert fail'); - const rollbackCall = mockClient.query.mock.calls.find((c: unknown[]) => c[0] === 'ROLLBACK'); + const rollbackCall = mockClient.query.mock.calls.find((c) => (c as [string])[0] === 'ROLLBACK'); expect(rollbackCall).toBeDefined(); }); }); @@ -715,7 +729,7 @@ describe('rowToTask', () => { const result = await createStore().get('task-1'); expect(result?.status.message).toBeDefined(); - expect((result?.status.message as any).role).toBe('user'); + expect((result?.status.message as { role: string }).role).toBe('user'); expect(result?.metadata).toEqual({ key: 'value', nested: { a: 1 } }); expect(result?.history?.[0].metadata).toEqual({ source: 'user' }); expect(result?.artifacts?.[0].metadata).toEqual({ version: 2 }); diff --git a/packages/persistence/src/postgres.ts b/packages/persistence/src/postgres.ts index e8fc4b6..7bdf29e 100644 --- a/packages/persistence/src/postgres.ts +++ b/packages/persistence/src/postgres.ts @@ -313,7 +313,7 @@ export class PostgresTaskStore implements TaskStore { historyLength?: number; }): Promise<{ tasks: Task[]; nextPageToken: string; totalSize: number }> { const conditions: string[] = []; - const params: unknown[] = []; + const params: (string | number)[] = []; let paramIndex = 1; if (options?.contextId) { diff --git a/packages/persistence/src/redis.test.ts b/packages/persistence/src/redis.test.ts index 6602408..f11fcb5 100644 --- a/packages/persistence/src/redis.test.ts +++ b/packages/persistence/src/redis.test.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, expect, it } from 'vitest'; import { RedisTaskStore } from './redis.js'; +import type { RedisTaskStoreOptions } from './redis.js'; // Minimal mock of ioredis Redis interface function createMockRedis() { @@ -93,7 +94,7 @@ describe('RedisTaskStore', () => { beforeEach(() => { mockRedis = createMockRedis(); - store = new RedisTaskStore({ redis: mockRedis as unknown as import('ioredis').Redis }); + store = new RedisTaskStore({ redis: mockRedis } as unknown as RedisTaskStoreOptions); }); it('creates and gets a task', async () => { @@ -271,9 +272,9 @@ describe('RedisTaskStore', () => { it('uses custom key prefix', async () => { const customStore = new RedisTaskStore({ - redis: mockRedis as unknown as import('ioredis').Redis, + redis: mockRedis, keyPrefix: 'custom', - }); + } as unknown as RedisTaskStoreOptions); await customStore.create({ id: 'task-1', status: { state: 'submitted', timestamp: new Date().toISOString() }, diff --git a/packages/server/src/hono.test.ts b/packages/server/src/hono.test.ts index 39cb900..7cc94a9 100644 --- a/packages/server/src/hono.test.ts +++ b/packages/server/src/hono.test.ts @@ -125,7 +125,9 @@ describe('createA2AHonoApp', () => { }), }); expect(res.status).toBe(200); - const body = (await res.json()) as { result: { tasks: unknown[]; totalSize: number } }; + const body = (await res.json()) as { + result: { tasks: Array<{ id: string; status: { state: string } }>; totalSize: number }; + }; expect(body.result.tasks).toHaveLength(1); expect(body.result.totalSize).toBe(1); }); @@ -344,7 +346,9 @@ describe('createA2AHonoApp', () => { }), }); expect(res.status).toBe(200); - const body = (await res.json()) as { result: { tasks: unknown[]; totalSize: number } }; + const body = (await res.json()) as { + result: { tasks: Array<{ id: string; status: { state: string } }>; totalSize: number }; + }; expect(body.result.tasks).toHaveLength(0); expect(body.result.totalSize).toBe(0); }); @@ -635,7 +639,9 @@ describe('createA2AHonoApp', () => { }), }); expect(res.status).toBe(200); - const body = (await res.json()) as { result: { configs: unknown[] } }; + const body = (await res.json()) as { + result: { configs: Array<{ taskId: string; url: string }> }; + }; expect(Array.isArray(body.result.configs)).toBe(true); expect(body.result.configs).toHaveLength(1); }); diff --git a/packages/server/src/rate-limiter.test.ts b/packages/server/src/rate-limiter.test.ts index 5558259..3773c9c 100644 --- a/packages/server/src/rate-limiter.test.ts +++ b/packages/server/src/rate-limiter.test.ts @@ -1,3 +1,4 @@ +import type { Logger } from '@reaatech/a2a-reference-observability'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { RateLimiter } from './rate-limiter.js'; @@ -115,7 +116,10 @@ describe('RateLimiter', () => { it('uses array header values correctly in default keyFn', () => { const limiter = new RateLimiter({ windowMs: 60_000, maxRequests: 2 }); - const req = { headers: { 'x-forwarded-for': ['10.0.0.1'] } } as any; + const req = { headers: { 'x-forwarded-for': ['10.0.0.1'] } } as { + ip?: string; + headers: Record; + }; // Default keyFn uses req.ip, not x-forwarded-for, so ip is undefined const r1 = limiter.check(req); @@ -136,7 +140,7 @@ describe('RateLimiter', () => { fatal: vi.fn(), trace: vi.fn(), silent: vi.fn(), - } as any, + } as unknown as Logger, }); const req = { ip: '10.0.0.1', headers: {} }; diff --git a/packages/server/src/sse-redis.test.ts b/packages/server/src/sse-redis.test.ts index 2f11445..1cc590c 100644 --- a/packages/server/src/sse-redis.test.ts +++ b/packages/server/src/sse-redis.test.ts @@ -2,17 +2,17 @@ import { describe, expect, it, vi } from 'vitest'; import { RedisSseCoordinator } from './sse-redis.js'; function createMockRedis() { - const handlers = new Map void>(); + const handlers = new Map void>(); return { duplicate: vi.fn().mockReturnThis(), psubscribe: vi.fn().mockResolvedValue(undefined), publish: vi.fn().mockResolvedValue(1), punsubscribe: vi.fn().mockResolvedValue(undefined), quit: vi.fn().mockResolvedValue(undefined), - on: vi.fn((event: string, handler: (...args: unknown[]) => void) => { + on: vi.fn((event: string, handler: (...args: string[]) => void) => { handlers.set(event, handler); }), - emit: vi.fn((event: string, ...args: unknown[]) => { + emit: vi.fn((event: string, ...args: string[]) => { const h = handlers.get(event); if (h) h(...args); }), @@ -24,7 +24,7 @@ type MockRedis = ReturnType; describe('RedisSseCoordinator', () => { describe('connect', () => { it('creates a subscriber and subscribes to the psubject', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, channelPrefix: 'a2a:sse', @@ -37,7 +37,7 @@ describe('RedisSseCoordinator', () => { }); it('does nothing if already connected', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -50,7 +50,7 @@ describe('RedisSseCoordinator', () => { }); it('deduplicates concurrent connect calls', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -62,7 +62,7 @@ describe('RedisSseCoordinator', () => { }); it('connects on init when connectOnInit is true', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); void new RedisSseCoordinator({ redis: redis as never, connectOnInit: true, @@ -77,7 +77,7 @@ describe('RedisSseCoordinator', () => { describe('subscribe / unsubscribe', () => { it('calls the handler when a matching message is received', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, channelPrefix: 'a2a:sse', @@ -93,7 +93,7 @@ describe('RedisSseCoordinator', () => { }); it('does not call the handler for a different task', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -108,7 +108,7 @@ describe('RedisSseCoordinator', () => { }); it('does not call the handler after unsubscribe', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -124,7 +124,7 @@ describe('RedisSseCoordinator', () => { }); it('ignores malformed JSON messages', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -139,7 +139,7 @@ describe('RedisSseCoordinator', () => { }); it('ignores messages on channels without the prefix', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -156,7 +156,7 @@ describe('RedisSseCoordinator', () => { describe('publish', () => { it('publishes JSON-stringified data to the correct channel', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, channelPrefix: 'a2a:sse', @@ -171,7 +171,7 @@ describe('RedisSseCoordinator', () => { }); it('uses custom channel prefix', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, channelPrefix: 'custom', @@ -185,7 +185,7 @@ describe('RedisSseCoordinator', () => { describe('close', () => { it('unsubscribes and quits the subscriber', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -198,7 +198,7 @@ describe('RedisSseCoordinator', () => { }); it('clears all handlers', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, }); @@ -215,7 +215,7 @@ describe('RedisSseCoordinator', () => { }); it('is a no-op when not connected', async () => { - const redis = createMockRedis() as unknown as MockRedis; + const redis: MockRedis = createMockRedis(); const coordinator = new RedisSseCoordinator({ redis: redis as never, });