From b43d0934f7d4b76ca207b7470176f6f36505239c Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:17:11 +0800 Subject: [PATCH] test(web): keep credential fixtures package-local --- .../api/gateway/tests/browser-credentials.ts | 17 +++++++++ .../gateway/tests/gateway-stream.host.spec.ts | 4 +-- .../api/gateway/tests/gateway.host.spec.ts | 4 +-- .../tests/browser-auth.host.spec.ts | 31 ++-------------- .../connection/tests/browser-credentials.ts | 36 +++++++++++++++++++ .../connection/tests/node-half.host.spec.ts | 12 +++---- 6 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 packages/api/gateway/tests/browser-credentials.ts create mode 100644 packages/client/connection/tests/browser-credentials.ts diff --git a/packages/api/gateway/tests/browser-credentials.ts b/packages/api/gateway/tests/browser-credentials.ts new file mode 100644 index 0000000000..8661983ea8 --- /dev/null +++ b/packages/api/gateway/tests/browser-credentials.ts @@ -0,0 +1,17 @@ +import type { Context } from '@deepseek-ai/cordis' + +/** Provide an in-memory credential-record owner for a mounted Connection plugin. */ +export function provideBrowserCredentials(ctx: Context): void { + const records = new Map() + ctx.provide('credentials', { + async modifyRecord( + key: unknown, + mutate: (current: unknown) => Promise, + ): Promise { + const current = records.get(key) + const next = await mutate(current) + if (next !== undefined) records.set(key, next) + return next ?? current + }, + } as never) +} diff --git a/packages/api/gateway/tests/gateway-stream.host.spec.ts b/packages/api/gateway/tests/gateway-stream.host.spec.ts index 01fcc81b0f..d7289783d3 100644 --- a/packages/api/gateway/tests/gateway-stream.host.spec.ts +++ b/packages/api/gateway/tests/gateway-stream.host.spec.ts @@ -14,7 +14,7 @@ import { TypertRemoteFailure, } from '@deepseek-ai/dsh-typert-protocol' import TypertRegistry from '@deepseek-ai/dsh-typert-registry' -import { MemoryCredentials } from '../../../credentials/credentials/tests/memory.ts' +import { provideBrowserCredentials } from './browser-credentials.ts' import TypertGatewayService, { TypertGatewayError, type TypertRemoteEventDispatch, @@ -969,7 +969,7 @@ async function setup(transport: boolean): Promise<{ readonly ctx: Context; reado roots.push(ctx) if (transport) { await ctx.plugin(WebServer, { host: '127.0.0.1', port: 0 }) - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) } await ctx.plugin(TypertRegistry) await ctx.plugin(TypertGatewayService) diff --git a/packages/api/gateway/tests/gateway.host.spec.ts b/packages/api/gateway/tests/gateway.host.spec.ts index 0798765e98..c0455bba10 100644 --- a/packages/api/gateway/tests/gateway.host.spec.ts +++ b/packages/api/gateway/tests/gateway.host.spec.ts @@ -18,7 +18,7 @@ import { } from '@deepseek-ai/dsh-typert-protocol' import TypertRegistry, { type TypertContribution } from '@deepseek-ai/dsh-typert-registry' import TypertGatewayService, { TypertGatewayError } from '@deepseek-ai/dsh-api-gateway' -import { MemoryCredentials } from '../../../credentials/credentials/tests/memory.ts' +import { provideBrowserCredentials } from './browser-credentials.ts' interface FixtureAgent { readonly id: string @@ -1168,7 +1168,7 @@ describe('TypertGatewayService', () => { it('dispatches claimed invocations through /api and leaves unclaimed endpoints to its fallback', async () => { const ctx = new Context().extend({ fixtureScope: 'http-caller' }) const routes: WebRoute[] = [] - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes) as WebServer) const connectionFiber = ctx.plugin({ inject: [...connectionInject], apply: applyConnection }) await connectionFiber diff --git a/packages/client/connection/tests/browser-auth.host.spec.ts b/packages/client/connection/tests/browser-auth.host.spec.ts index 885b726b69..3f06672ff1 100644 --- a/packages/client/connection/tests/browser-auth.host.spec.ts +++ b/packages/client/connection/tests/browser-auth.host.spec.ts @@ -2,37 +2,10 @@ import { createHmac } from 'node:crypto' import { afterEach, describe, expect, it, vi } from 'vitest' -import type { CredentialProvider, CredentialRecord } from '@deepseek-ai/dsh-credentials' +import type { CredentialProvider } from '@deepseek-ai/dsh-credentials' import { BrowserAuth } from '../src/browser-auth.ts' import type { ConnectionIndexRequest, ConnectionIndexResponse } from '../src/rpc.ts' - -class RecordCredentials { - record: CredentialRecord | undefined - discardWrites = false - reads = 0 - modifies = 0 - - readRecord(): Promise { - this.reads += 1 - return Promise.resolve(this.record) - } - - async modifyRecord( - _key: unknown, - mutate: (current: CredentialRecord | undefined) => Promise, - ): Promise { - this.modifies += 1 - const next = await mutate(this.record) - if (this.discardWrites) return undefined - if (next !== undefined) this.record = next - return this.record - } - - deleteRecord(): Promise { - this.record = undefined - return Promise.resolve() - } -} +import { RecordCredentials } from './browser-credentials.ts' function signedCookie(store: RecordCredentials, name: string, payload: unknown): string { const body = typeof payload === 'string' diff --git a/packages/client/connection/tests/browser-credentials.ts b/packages/client/connection/tests/browser-credentials.ts new file mode 100644 index 0000000000..3739101648 --- /dev/null +++ b/packages/client/connection/tests/browser-credentials.ts @@ -0,0 +1,36 @@ +import type { Context } from '@deepseek-ai/cordis' +import type { CredentialProvider, CredentialRecord } from '@deepseek-ai/dsh-credentials' + +/** Mutable credential-record double for Connection authentication tests. */ +export class RecordCredentials { + record: CredentialRecord | undefined + discardWrites = false + reads = 0 + modifies = 0 + + readRecord(): Promise { + this.reads += 1 + return Promise.resolve(this.record) + } + + async modifyRecord( + _key: unknown, + mutate: (current: CredentialRecord | undefined) => Promise, + ): Promise { + this.modifies += 1 + const next = await mutate(this.record) + if (this.discardWrites) return undefined + if (next !== undefined) this.record = next + return this.record + } + + deleteRecord(): Promise { + this.record = undefined + return Promise.resolve() + } +} + +/** Provide the record operations Connection needs during authentication setup. */ +export function provideBrowserCredentials(ctx: Context): void { + ctx.provide('credentials', new RecordCredentials() as unknown as CredentialProvider) +} diff --git a/packages/client/connection/tests/node-half.host.spec.ts b/packages/client/connection/tests/node-half.host.spec.ts index 6442b83145..75691394ed 100644 --- a/packages/client/connection/tests/node-half.host.spec.ts +++ b/packages/client/connection/tests/node-half.host.spec.ts @@ -12,7 +12,7 @@ import { RpcId, type ClientRequest } from '@deepseek-ai/dsh-host-apiproxy/api' import type { WebServer, WebRoute, WebUpgradeRoute } from '@deepseek-ai/dsh-host-webserver' import { API_PATH, apply, inject, type HostConnectionHandle } from '../src/index.ts' import { DEFAULT_MAX_REQUEST_BODY_BYTES } from '../src/http-bridge.ts' -import { MemoryCredentials } from '../../../credentials/credentials/tests/memory.ts' +import { provideBrowserCredentials } from './browser-credentials.ts' /** Structural webServer fake recording both route registries. */ function fakeHttpServer( @@ -92,7 +92,7 @@ async function mounted(config?: { trustedHosts?: string[] }): Promise<{ const ctx = new Context() const routes: WebRoute[] = [] const upgrades: WebUpgradeRoute[] = [] - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes, upgrades) as WebServer) ctx.provide('apiProxy', {} as unknown as ApiProxy) const fiber = ctx.plugin({ inject: [...inject], apply }, config) @@ -141,7 +141,7 @@ describe('connection node half', () => { const routes: WebRoute[] = [] const upgrades: WebUpgradeRoute[] = [] const ctx = new Context() - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes, upgrades) as WebServer) ctx.provide('apiProxy', {} as unknown as ApiProxy) const fiber = ctx.plugin({ inject: [...inject], apply }, { trustedHosts: ['harness.internal/path'] }) @@ -247,7 +247,7 @@ describe('connection node half', () => { it('provides a disposable dedicated RPC channel without requiring apiProxy', async () => { const ctx = new Context() const routes: WebRoute[] = [] - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes, []) as WebServer) const fiber = ctx.plugin({ inject: [...inject], apply }) await fiber.await() @@ -296,7 +296,7 @@ describe('connection node half', () => { it('dispatches claimed /api endpoints before the API Proxy fallback and withdraws the claim', async () => { const ctx = new Context() const routes: WebRoute[] = [] - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes, []) as WebServer) ctx.provide('apiProxy', {} as unknown as ApiProxy) const fiber = ctx.plugin({ inject: [...inject], apply }, { trustedHosts: ['harness.example'] }) @@ -381,7 +381,7 @@ describe('connection node half', () => { it('applies the configured trust fence and JSON envelope checks to generic channels', async () => { const ctx = new Context() const routes: WebRoute[] = [] - await ctx.plugin(MemoryCredentials) + provideBrowserCredentials(ctx) ctx.provide('webServer', fakeHttpServer(routes, []) as WebServer) const fiber = ctx.plugin({ inject: [...inject], apply }, { trustedHosts: ['harness.example'] }) await fiber.await()