Browse Source

fix(web): document remote welcome constraints

ZiyaZhang 2 tháng trước cách đây
mục cha
commit
59d923395a

+ 5 - 1
apps/web/tests/scaffold.ts

@@ -166,7 +166,11 @@ export interface LaunchOptions {
   }
   /** Leave the current welcome notice unacknowledged; ordinary scenarios publish it as complete before browser boot. */
   welcomeNoticePending?: boolean
-  /** Browse through this trusted non-loopback hostname while the test server stays bound to loopback. */
+  /**
+   * Browse through a trusted non-loopback hostname that the browser resolves
+   * to loopback (for example `*.localhost`). The test server stays bound to
+   * 127.0.0.1; a non-resolving authority fails before Host trust is exercised.
+   */
   remoteAuthority?: string
 }
 

+ 2 - 2
packages/client/connection/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write packages/client/connection/README.md
-README.md: c8b7c4787cbcbf6a202fb944459a589fcadd7c8d
-README.zh.md: 693420183ffa4fb20e1fecbff523a12261a45d45
+README.md: 522ae6a14a3b4b07e7f2917133d16a5e83433f69
+README.zh.md: 4eaed862df678997b328d7a4ddcab1f5254c7c60

+ 1 - 1
packages/client/connection/README.md

@@ -2,7 +2,7 @@
 
 English | [中文](README.zh.md)
 
-Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` seam, and the loop's sink/config types. The node half's `/api` route pins the privileged method set (`host.pickDirectory`, `host.openPath`, and the whole configuration plane — `settings.describe`/`update`/`replace`/`mutate` and `credentials.describe`/`set`/`unset`, reads included, since describing returns the exposed configuration and probing an arbitrary reference reports where a credential comes from) to loopback by passing the trust fence with an empty trust list — a declared `trustedHosts` authority reaches every other method, while these stay loopback-local until a real authentication layer exists. The platform subclasses (WebApiClient/FixtureApiClient), the ConnectionController loop, and the fixture data source are package-internal — apply selects and drives them; tests reach them via src. Contract: api-contracts v3 §3.
+Wire consumer layer: the client plugin's apply mounts `ctx.connection` (shared api client + single-consumer stream-loop starter); the export face carries the wire contract types, the `AbstractApiClient` seam, and the loop's sink/config types. The dedicated `./loopback-hostname` source subpath exposes the zero-dependency predicate shared by the `/api` Host fence and browser welcome-persistence selection; client bundlers inline this source entry, while plain Node cannot load it directly, so it must remain browser-safe and dependency-free. The node half's `/api` route pins the privileged method set (`host.pickDirectory`, `host.openPath`, and the whole configuration plane — `settings.describe`/`update`/`replace`/`mutate` and `credentials.describe`/`set`/`unset`, reads included, since describing returns the exposed configuration and probing an arbitrary reference reports where a credential comes from) to loopback by passing the trust fence with an empty trust list — a declared `trustedHosts` authority reaches every other method, while these stay loopback-local until a real authentication layer exists. The platform subclasses (WebApiClient/FixtureApiClient), the ConnectionController loop, and the fixture data source are package-internal — apply selects and drives them; tests reach them via src. Contract: api-contracts v3 §3.
 
 ## /api browser-trust fence
 

+ 1 - 1
packages/client/connection/README.zh.md

@@ -2,7 +2,7 @@
 
 [English](README.md) | 中文
 
-协议消费层:客户端插件的 apply 会挂载 `ctx.connection`(共享 API 客户端 + 单消费方流循环启动器);导出表层携带协议契约类型、`AbstractApiClient` seam,以及循环的 sink/配置类型。node 半侧的 `/api` 路由让特权方法集(`host.pickDirectory`、`host.openPath`,以及整个配置面——`settings.describe`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`,读取也在内,因为 describe 会返回已暴露的配置,而探测任意引用会报出某条凭据来自何处)以空信任表过信任 fence,从而钉在回环——已声明的 `trustedHosts` 授权可达其余全部方法,而这些方法在真正的认证层出现之前仍只限回环本机。平台子类(WebApiClient/FixtureApiClient)、ConnectionController 循环和 fixture 数据源都属于包内部:apply 负责选择并驱动它们,测试则通过 src 访问。契约:api-contracts v3 §3。
+协议消费层:客户端插件的 apply 会挂载 `ctx.connection`(共享 API 客户端 + 单消费方流循环启动器);导出表层携带协议契约类型、`AbstractApiClient` seam,以及循环的 sink/配置类型。专用的 `./loopback-hostname` 源码子路径导出 `/api` Host fence 与浏览器欢迎页持久化选择共用的零依赖判定函数;客户端 bundler 会内联这一源码入口,而 plain Node 无法直接加载它,因此它必须保持浏览器安全且零依赖。node 半侧的 `/api` 路由让特权方法集(`host.pickDirectory`、`host.openPath`,以及整个配置面——`settings.describe`/`update`/`replace`/`mutate` 与 `credentials.describe`/`set`/`unset`,读取也在内,因为 describe 会返回已暴露的配置,而探测任意引用会报出某条凭据来自何处)以空信任表过信任 fence,从而钉在回环——已声明的 `trustedHosts` 授权可达其余全部方法,而这些方法在真正的认证层出现之前仍只限回环本机。平台子类(WebApiClient/FixtureApiClient)、ConnectionController 循环和 fixture 数据源都属于包内部:apply 负责选择并驱动它们,测试则通过 src 访问。契约:api-contracts v3 §3。
 
 ## /api 浏览器信任栅栏
 

+ 9 - 0
packages/client/connection/src/loopback-hostname.ts

@@ -1,3 +1,12 @@
+/**
+ * Browser-safe, zero-dependency loopback classification shared by the `/api`
+ * Host fence and browser welcome-persistence selection. The dedicated
+ * `./loopback-hostname` source subpath is inlined into client bundles instead
+ * of loaded by plain Node, so this module must not add Node-only or runtime
+ * dependencies.
+ * @module @deepseek-ai/dsh-client-connection/loopback-hostname
+ */
+
 /**
  * Whether a normalized URL hostname names the local loopback authority.
  * @param hostname - WHATWG URL hostname (IPv6 literals retain brackets).

+ 3 - 1
packages/client/ui-settings-general/src/client/welcome-store.ts

@@ -117,7 +117,9 @@ export class WelcomeNoticeStore {
 }
 
 /**
- * Refresh only after the welcome step has begun reading durable state.
+ * Refresh only after welcome state has left idle. A memory-mode load retains
+ * acknowledgement so reconnect and settings-change refreshes do not reopen a
+ * process-local notice.
  * @param controller - welcome state owner whose current status decides whether to load.
  */
 export function refreshWelcomeIfLoaded(controller: WelcomeNoticeStore): void {