test(web): keep credential fixtures package-local

This commit is contained in:
Tianyi Cui
2026-08-25 14:23:47 +08:00
parent 9c964848cd
commit b43d0934f7
6 changed files with 65 additions and 39 deletions
@@ -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<unknown, unknown>()
ctx.provide('credentials', {
async modifyRecord(
key: unknown,
mutate: (current: unknown) => Promise<unknown>,
): Promise<unknown> {
const current = records.get(key)
const next = await mutate(current)
if (next !== undefined) records.set(key, next)
return next ?? current
},
} as never)
}
@@ -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)
@@ -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
@@ -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<CredentialRecord | undefined> {
this.reads += 1
return Promise.resolve(this.record)
}
async modifyRecord(
_key: unknown,
mutate: (current: CredentialRecord | undefined) => Promise<CredentialRecord | undefined>,
): Promise<CredentialRecord | undefined> {
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<void> {
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'
@@ -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<CredentialRecord | undefined> {
this.reads += 1
return Promise.resolve(this.record)
}
async modifyRecord(
_key: unknown,
mutate: (current: CredentialRecord | undefined) => Promise<CredentialRecord | undefined>,
): Promise<CredentialRecord | undefined> {
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<void> {
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)
}
@@ -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()