返回 DeepSeek-Reasonix
documents.ts
根目录 / desktop / electron / src / main / browser / documents.ts
1 import { randomBytes } from "node:crypto";
2
3 export interface FrameBinding {
4 prefix: string;
5 frameTreeNodeId: number;
6 docId: string;
7 }
8
9 // One snapshot of one document version. The token is the only handle Go ever
10 // sees; the snapshotId is what the page-side registry was stamped with.
11 export interface DocumentBinding {
12 tabId: string;
13 epoch: number;
14 snapshotId: string;
15 frames: FrameBinding[];
16 }
17
18 export interface ParsedRef {
19 prefix: string;
20 ref: string;
21 }
22
23 const REF_PATTERN = /^(f\d+)?(e\d+)$/;
24
25 export function parseRef(ref: string): ParsedRef | null {
26 const match = REF_PATTERN.exec(ref);
27 if (!match) return null;
28 return { prefix: match[1] ?? "", ref };
29 }
30
31 export function randomToken(bytes = 16): string {
32 return randomBytes(bytes).toString("hex");
33 }
34
35 export class DocumentRegistry {
36 private readonly byToken = new Map<string, DocumentBinding>();
37 private readonly byTab = new Map<string, string>();
38
39 constructor(private readonly mint: () => string = randomToken) {}
40
41 // A new snapshot replaces the tab's previous token: refs from an older
42 // snapshot must fail as stale rather than land on a re-rendered page.
43 issue(binding: DocumentBinding): string {
44 this.invalidateTab(binding.tabId);
45 const token = this.mint();
46 this.byToken.set(token, binding);
47 this.byTab.set(binding.tabId, token);
48 return token;
49 }
50
51 // After an action left the document intact the same refs stay valid, so
52 // the binding is re-issued under a fresh token and the old one retired.
53 rotate(token: string): string | null {
54 const binding = this.byToken.get(token);
55 if (!binding) return null;
56 this.byToken.delete(token);
57 const next = this.mint();
58 this.byToken.set(next, binding);
59 this.byTab.set(binding.tabId, next);
60 return next;
61 }
62
63 lookup(token: string): DocumentBinding | undefined {
64 return this.byToken.get(token);
65 }
66
67 currentToken(tabId: string): string | undefined {
68 return this.byTab.get(tabId);
69 }
70
71 invalidateTab(tabId: string): void {
72 const token = this.byTab.get(tabId);
73 if (token !== undefined) this.byToken.delete(token);
74 this.byTab.delete(tabId);
75 }
76
77 clear(): void {
78 this.byToken.clear();
79 this.byTab.clear();
80 }
81 }
82
82 lines TYPESCRIPT