From 57343cfeb8eaa3bea4151b4d59a54509a914483a Mon Sep 17 00:00:00 2001 From: ZiyaZhang <199893125+ZiyaZhang@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:30:53 -0700 Subject: [PATCH] fix(web): expose loopback policy safely --- packages/client/connection/package.json | 1 + packages/client/connection/src/client/index.ts | 2 -- packages/client/tsdown.client.ts | 2 +- packages/client/ui-settings-general/src/client/index.ts | 3 ++- scripts/client-bundle-purity.spec.ts | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/client/connection/package.json b/packages/client/connection/package.json index d86b2bdf2a..f2842ec061 100644 --- a/packages/client/connection/package.json +++ b/packages/client/connection/package.json @@ -19,6 +19,7 @@ "types": "./lib/types/client/index.d.ts", "default": "./lib/client.js" }, + "./loopback-hostname": "./src/loopback-hostname.ts", "./src/*": "./src/*", "./package.json": "./package.json" }, diff --git a/packages/client/connection/src/client/index.ts b/packages/client/connection/src/client/index.ts index daa20f1672..a7ebfbbd86 100644 --- a/packages/client/connection/src/client/index.ts +++ b/packages/client/connection/src/client/index.ts @@ -9,8 +9,6 @@ import { ConnectionController, type ConnectionConfig, type ConnectionSinks, type import { FixtureApiClient } from './fixture.ts' import { WebApiClient } from './web-api-client.ts' -export { isLoopbackHostname } from '../loopback-hostname.ts' - // ---- Contract re-exports (browser-safe apiproxy channels + core types) ---- export type { ApiProxy, SessionsApi, SessionSearchItem, SessionSummary, HostApi, EventsApi, MuxFrame, HostFrame, diff --git a/packages/client/tsdown.client.ts b/packages/client/tsdown.client.ts index 2ff1856b3d..fad00fe4f0 100644 --- a/packages/client/tsdown.client.ts +++ b/packages/client/tsdown.client.ts @@ -28,7 +28,7 @@ const CSS_VIRTUAL_SUFFIX = '.mjs' * Everything else under @deepseek-ai/* is either a module-table entry * (external) or a leak the purity gate rejects. */ -export const INLINE_SAFE = /^@deepseek-ai\/dsh-(host-apiproxy|session|llm|tools|brand)(\/|$)/ +export const INLINE_SAFE = /^(?:@deepseek-ai\/dsh-(?:host-apiproxy|session|llm|tools|brand)(?:\/|$)|@deepseek-ai\/dsh-client-connection\/loopback-hostname$)/ /** * Documented TEMPORARY exemption, not a platform module (hence not in diff --git a/packages/client/ui-settings-general/src/client/index.ts b/packages/client/ui-settings-general/src/client/index.ts index c0c0fb569f..6a7510d4ac 100644 --- a/packages/client/ui-settings-general/src/client/index.ts +++ b/packages/client/ui-settings-general/src/client/index.ts @@ -7,7 +7,8 @@ */ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client' import { deferRegistration } from '@deepseek-ai/dsh-client-ui-slots' -import { isLoopbackHostname, type ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client' +import type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client' +import { isLoopbackHostname } from '@deepseek-ai/dsh-client-connection/loopback-hostname' import { bindSnapshotSelector } from '@deepseek-ai/dsh-client-web-react' // Type-only: pulls the shell's SlotMap merges (trigger/header/section/item). import type {} from '@deepseek-ai/dsh-client-ui-settings/client' diff --git a/scripts/client-bundle-purity.spec.ts b/scripts/client-bundle-purity.spec.ts index d70964bdba..2eef1ba5ef 100644 --- a/scripts/client-bundle-purity.spec.ts +++ b/scripts/client-bundle-purity.spec.ts @@ -53,6 +53,7 @@ describe('client bundle purity gate', () => { expect(resolveId('@deepseek-ai/dsh-host-apiproxy/api')).toBeNull() expect(resolveId('@deepseek-ai/dsh-session/surface')).toBeNull() expect(resolveId('@deepseek-ai/dsh-brand')).toBeNull() + expect(resolveId('@deepseek-ai/dsh-client-connection/loopback-hostname')).toBeNull() }) it('throws on any other @deepseek-ai leak', () => {