90 lines
4.5 KiB
TypeScript
90 lines
4.5 KiB
TypeScript
/**
|
||
* Session ID tag translation helpers for the CCR v2 compat layer.
|
||
*
|
||
* Lives in its own file (rather than workSecret.ts) so that sessionHandle.ts
|
||
* and replBridgeTransport.ts (bridge.mjs entry points) can import from
|
||
* workSecret.ts without pulling in these retag functions.
|
||
*
|
||
* The isCseShimEnabled kill switch is injected via setCseShimGate() to avoid
|
||
* a static import of bridgeEnabled.ts → growthbook.ts → config.ts — all
|
||
* banned from the sdk.mjs bundle (scripts/build-agent-sdk.sh). Callers that
|
||
* already import bridgeEnabled.ts register the gate; the SDK path never does,
|
||
* so the shim defaults to active (matching isCseShimEnabled()'s own default).
|
||
* CCR v2 compat 层的会话 ID 标签转换辅助函数。
|
||
*
|
||
* 生活在自己的文件中(而非 workSecret.ts),以便 sessionHandle.ts
|
||
* 和 replBridgeTransport.ts(bridge.mjs 入口点)可以从 workSecret.ts 导入,
|
||
* 而无需引入这些 retag 函数。
|
||
*
|
||
* isCseShimEnabled kill switch 通过 setCseShimGate() 注入,以避免
|
||
* bridgeEnabled.ts → growthbook.ts → config.ts 的静态导入 — 所有这些
|
||
* 都从 sdk.mjs bundle 中禁止(scripts/build-agent-sdk.sh)。已经导入
|
||
* bridgeEnabled.ts 的调用者注册门禁;SDK 路径从不这样做,
|
||
* 因此 shim 默认为 active(匹配 isCseShimEnabled() 自身的默认值)。
|
||
*/
|
||
|
||
let _isCseShimEnabled: (() => boolean) | undefined
|
||
|
||
/**
|
||
* Register the GrowthBook gate for the cse_ shim. Called from bridge
|
||
* init code that already imports bridgeEnabled.ts.
|
||
* 为 cse_ shim 注册 GrowthBook 门禁。从已经导入 bridgeEnabled.ts 的
|
||
* bridge init 代码调用。
|
||
*/
|
||
export function setCseShimGate(gate: () => boolean): void {
|
||
_isCseShimEnabled = gate
|
||
}
|
||
|
||
/**
|
||
* Re-tag a `cse_*` session ID to `session_*` for use with the v1 compat API.
|
||
*
|
||
* Worker endpoints (/v1/code/sessions/{id}/worker/*) want `cse_*`; that's
|
||
* what the work poll delivers. Client-facing compat endpoints
|
||
* (/v1/sessions/{id}, /v1/sessions/{id}/archive, /v1/sessions/{id}/events)
|
||
* want `session_*` — compat/convert.go:27 validates TagSession. Same UUID,
|
||
* different costume. No-op for IDs that aren't `cse_*`.
|
||
*
|
||
* bridgeMain holds one sessionId variable for both worker registration and
|
||
* session-management calls. It arrives as `cse_*` from the work poll under
|
||
* the compat gate, so archiveSession/fetchSessionTitle need this re-tag.
|
||
* 将 `cse_*` session ID 重新标记为 `session_*`,用于 v1 compat API。
|
||
*
|
||
* Worker endpoints(/v1/code/sessions/{id}/worker/*)需要 `cse_*`;
|
||
* 这是 work poll 提供的内容。面向客户端的 compat endpoints
|
||
*(/v1/sessions/{id}, /v1/sessions/{id}/archive, /v1/sessions/{id}/events)
|
||
* 需要 `session_*` — compat/convert.go:27 验证 TagSession。同一个 UUID,
|
||
* 不同的 costume。对于不是 `cse_*` 的 ID 无操作。
|
||
*
|
||
* bridgeMain 为 worker 注册和会话管理调用持有一个 sessionId 变量。
|
||
* 在 compat 门禁下,它作为 `cse_*` 从 work poll 到达,
|
||
* 因此 archiveSession/fetchSessionTitle 需要这个重新标记。
|
||
*/
|
||
export function toCompatSessionId(id: string): string {
|
||
if (!id.startsWith('cse_')) return id
|
||
if (_isCseShimEnabled && !_isCseShimEnabled()) return id
|
||
return 'session_' + id.slice('cse_'.length)
|
||
}
|
||
|
||
/**
|
||
* Re-tag a `session_*` session ID to `cse_*` for infrastructure-layer calls.
|
||
*
|
||
* Inverse of toCompatSessionId. POST /v1/environments/{id}/bridge/reconnect
|
||
* lives below the compat layer: once ccr_v2_compat_enabled is on server-side,
|
||
* it looks sessions up by their infra tag (`cse_*`). createBridgeSession still
|
||
* returns `session_*` (compat/convert.go:41) and that's what bridge-pointer
|
||
* stores — so perpetual reconnect passes the wrong costume and gets "Session
|
||
* not found" back. Same UUID, wrong tag. No-op for IDs that aren't `session_*`.
|
||
* 将 `session_*` session ID 重新标记为 `cse_*`,用于基础设施层调用。
|
||
*
|
||
* toCompatSessionId 的反向。POST /v1/environments/{id}/bridge/reconnect
|
||
* 位于 compat 层之下:一旦 ccr_v2_compat_enabled 在服务器端开启,
|
||
* 它通过 infra tag(`cse_*`)查找会话。createBridgeSession 仍然返回
|
||
* `session_*`(compat/convert.go:41),这是 bridge-pointer 存储的 —
|
||
* 因此永久 reconnect 传递了错误的 costume 并得到"Session not found"。
|
||
* 同一个 UUID,错误的标签。对于不是 `session_*` 的 ID 无操作。
|
||
*/
|
||
export function toInfraSessionId(id: string): string {
|
||
if (!id.startsWith('session_')) return id
|
||
return 'cse_' + id.slice('session_'.length)
|
||
}
|