import type { IncomingMessage, ServerResponse } from 'node:http'; import { type PreviewProxyResolution } from './preview-proxy.js'; export interface PreviewGuardPageOptions { authenticated(req: IncomingMessage): boolean; resolve(sessionId: string): PreviewProxyResolution; /** Mint the path-scoped capability for this request's identity. Null fails * the page closed rather than falling back to a cookie-authenticated * (and therefore same-origin-usable) content URL. */ mintContentCapability(req: IncomingMessage, sessionId: string): { token: string; expiresAt: number; } | null; /** * P1-11:给这张壳现签一枚绑定当前认证会话的 CSRF 票据。壳自己会 POST * unlock/activity/lock,是控制类端点的合法调用方之一,必须带票据;返回 null * 时壳照常渲染(预览只读可用),解锁按钮会被服务端 403 挡住。 */ mintCsrfToken?(req: IncomingMessage): string | null; /** * P2(readonly 解锁按钮):这个身份到底能不能解锁交互。必填,调用方必须显式 * 用与工作台按钮同一份能力投影(`projectWorkbenchOperationCapabilities` 的 * `canInteract`)回答,不给隐式默认值——漏接就编译不过,而不是悄悄把按钮画给 * 只读身份。 */ canInteract(req: IncomingMessage): boolean; } export interface PreviewGuardRenderOptions { /** 渲染时刻(毫秒),只用于算 capability 续期倒计时。默认 `Date.now()`。 */ now?: number; /** P1-11:本壳自己 POST 控制端点时带的一次性 CSRF 票据。 */ csrfToken?: string | null; /** * P2:该身份能否解锁交互。false(平台 teammate/guest 这类 readonly 身份)时 * 壳里根本不渲染解锁/锁定按钮——那两个 POST 只会被服务端 403,画出来是把 * 「点了才知道没权限」当交互;同时壳内部把交互态钉死在关闭状态,任何 * `mode: 'interactive'` 的状态响应都掀不开蒙层。渲染按钮不等于放大权限, * 不渲染也不等于额外收紧:服务端门禁始终是唯一权威。 */ canInteract: boolean; } export declare function previewGuardHtml(sessionId: string, capability: { token: string; expiresAt: number; }, options: PreviewGuardRenderOptions): string; /** * Serve only the descriptor root. All subpaths and the reserved iframe content * request continue through the hardened preview proxy unchanged. */ export declare function createPreviewGuardPage(options: PreviewGuardPageOptions): { handle(req: IncomingMessage, res: ServerResponse, url: URL): boolean; }; //# sourceMappingURL=preview-guard-page.d.ts.map