annotation-kit 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +75 -0
- package/README.md +114 -2
- package/README.zh-CN.md +112 -0
- package/dist/annotation-kit.css +157 -0
- package/dist/chunks/references-ukB-tSle.js +1126 -0
- package/dist/chunks/references-ukB-tSle.js.map +1 -0
- package/dist/electron/element-context.cjs +72 -0
- package/dist/electron/guest-preload.cjs +327 -0
- package/dist/electron.js +394 -0
- package/dist/electron.js.map +1 -0
- package/dist/index.js +910 -0
- package/dist/index.js.map +1 -0
- package/dist/react.js +2282 -0
- package/dist/react.js.map +1 -0
- package/dist/styles.d.ts +2 -0
- package/dist/types/address.d.ts +53 -0
- package/dist/types/address.d.ts.map +1 -0
- package/dist/types/client/Workbench.d.ts +11 -0
- package/dist/types/client/Workbench.d.ts.map +1 -0
- package/dist/types/client/composer/PacketPreview.d.ts +12 -0
- package/dist/types/client/composer/PacketPreview.d.ts.map +1 -0
- package/dist/types/client/composer/ReferenceCard.d.ts +12 -0
- package/dist/types/client/composer/ReferenceCard.d.ts.map +1 -0
- package/dist/types/client/composer/attachments.d.ts +10 -0
- package/dist/types/client/composer/attachments.d.ts.map +1 -0
- package/dist/types/client/composer/commit.d.ts +4 -0
- package/dist/types/client/composer/commit.d.ts.map +1 -0
- package/dist/types/client/composer/packets.d.ts +53 -0
- package/dist/types/client/composer/packets.d.ts.map +1 -0
- package/dist/types/client/composer/reference-presentation.d.ts +4 -0
- package/dist/types/client/composer/reference-presentation.d.ts.map +1 -0
- package/dist/types/client/error-copy.d.ts +69 -0
- package/dist/types/client/error-copy.d.ts.map +1 -0
- package/dist/types/client/errors.d.ts +10 -0
- package/dist/types/client/errors.d.ts.map +1 -0
- package/dist/types/client/files/FileSelectionAction.d.ts +7 -0
- package/dist/types/client/files/FileSelectionAction.d.ts.map +1 -0
- package/dist/types/client/files/SelectionCard.d.ts +14 -0
- package/dist/types/client/files/SelectionCard.d.ts.map +1 -0
- package/dist/types/client/files/document-workflow.d.ts +34 -0
- package/dist/types/client/files/document-workflow.d.ts.map +1 -0
- package/dist/types/client/files/pages/DocumentChrome.d.ts +30 -0
- package/dist/types/client/files/pages/DocumentChrome.d.ts.map +1 -0
- package/dist/types/client/files/pages/PageSelectionAction.d.ts +7 -0
- package/dist/types/client/files/pages/PageSelectionAction.d.ts.map +1 -0
- package/dist/types/client/files/pages/batches.d.ts +21 -0
- package/dist/types/client/files/pages/batches.d.ts.map +1 -0
- package/dist/types/client/files/pages/geometry.d.ts +16 -0
- package/dist/types/client/files/pages/geometry.d.ts.map +1 -0
- package/dist/types/client/files/pages/image-store.d.ts +8 -0
- package/dist/types/client/files/pages/image-store.d.ts.map +1 -0
- package/dist/types/client/files/pages/images.d.ts +41 -0
- package/dist/types/client/files/pages/images.d.ts.map +1 -0
- package/dist/types/client/files/pages/interaction.d.ts +55 -0
- package/dist/types/client/files/pages/interaction.d.ts.map +1 -0
- package/dist/types/client/files/pages/selection.d.ts +25 -0
- package/dist/types/client/files/pages/selection.d.ts.map +1 -0
- package/dist/types/client/files/pages/snapshot.d.ts +31 -0
- package/dist/types/client/files/pages/snapshot.d.ts.map +1 -0
- package/dist/types/client/files/references.d.ts +80 -0
- package/dist/types/client/files/references.d.ts.map +1 -0
- package/dist/types/client/files/selection.d.ts +11 -0
- package/dist/types/client/files/selection.d.ts.map +1 -0
- package/dist/types/client/files/sheets/SheetRecovery.d.ts +12 -0
- package/dist/types/client/files/sheets/SheetRecovery.d.ts.map +1 -0
- package/dist/types/client/files/sheets/SheetSurface.d.ts +27 -0
- package/dist/types/client/files/sheets/SheetSurface.d.ts.map +1 -0
- package/dist/types/client/files/sheets/geometry.d.ts +30 -0
- package/dist/types/client/files/sheets/geometry.d.ts.map +1 -0
- package/dist/types/client/files/sheets/navigation.d.ts +4 -0
- package/dist/types/client/files/sheets/navigation.d.ts.map +1 -0
- package/dist/types/client/files/sheets/snapshot.d.ts +45 -0
- package/dist/types/client/files/sheets/snapshot.d.ts.map +1 -0
- package/dist/types/client/locales.d.ts +148 -0
- package/dist/types/client/locales.d.ts.map +1 -0
- package/dist/types/client/messages/SentAnnotations.d.ts +18 -0
- package/dist/types/client/messages/SentAnnotations.d.ts.map +1 -0
- package/dist/types/client/messages/presentation.d.ts +39 -0
- package/dist/types/client/messages/presentation.d.ts.map +1 -0
- package/dist/types/client/model.d.ts +68 -0
- package/dist/types/client/model.d.ts.map +1 -0
- package/dist/types/client/quoted-context.d.ts +3 -0
- package/dist/types/client/quoted-context.d.ts.map +1 -0
- package/dist/types/client/responses/ResponseCard.d.ts +12 -0
- package/dist/types/client/responses/ResponseCard.d.ts.map +1 -0
- package/dist/types/client/responses/ResponseOverlay.d.ts +7 -0
- package/dist/types/client/responses/ResponseOverlay.d.ts.map +1 -0
- package/dist/types/client/responses/composer.d.ts +11 -0
- package/dist/types/client/responses/composer.d.ts.map +1 -0
- package/dist/types/client/responses/controller.d.ts +39 -0
- package/dist/types/client/responses/controller.d.ts.map +1 -0
- package/dist/types/client/responses/references.d.ts +62 -0
- package/dist/types/client/responses/references.d.ts.map +1 -0
- package/dist/types/client/responses/selection.d.ts +43 -0
- package/dist/types/client/responses/selection.d.ts.map +1 -0
- package/dist/types/electron/bridge.d.mts +45 -0
- package/dist/types/electron/bridge.d.mts.map +1 -0
- package/dist/types/electron/build-preload.d.mts +4 -0
- package/dist/types/electron/build-preload.d.mts.map +1 -0
- package/dist/types/electron/element-context.d.cts +7 -0
- package/dist/types/electron/element-context.d.cts.map +1 -0
- package/dist/types/electron/guest-preload.d.cts +2 -0
- package/dist/types/electron/guest-preload.d.cts.map +1 -0
- package/dist/types/electron/index.d.ts +5 -0
- package/dist/types/electron/index.d.ts.map +1 -0
- package/dist/types/host-contracts.d.ts +104 -0
- package/dist/types/host-contracts.d.ts.map +1 -0
- package/dist/types/index.d.ts +32 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/react.d.ts +14 -0
- package/dist/types/react.d.ts.map +1 -0
- package/dist/types/shared/desktop.d.ts +75 -0
- package/dist/types/shared/desktop.d.ts.map +1 -0
- package/dist/types/shared/surface.d.ts +11 -0
- package/dist/types/shared/surface.d.ts.map +1 -0
- package/dist/types/ui/icons.d.ts +11 -0
- package/dist/types/ui/icons.d.ts.map +1 -0
- package/dist/types/ui/regions.d.ts +28 -0
- package/dist/types/ui/regions.d.ts.map +1 -0
- package/package.json +83 -3
package/dist/electron.js
ADDED
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { join, dirname, resolve, relative, sep } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
function createAnnotationChannels(prefix = "annotation-kit") {
|
|
6
|
+
return Object.freeze({
|
|
7
|
+
setMode: `${prefix}:annotation-set-mode`,
|
|
8
|
+
capture: `${prefix}:annotation-capture`,
|
|
9
|
+
event: `${prefix}:annotation-event`,
|
|
10
|
+
guestSelection: `${prefix}:annotation-guest-selection`,
|
|
11
|
+
guestPainted: `${prefix}:annotation-guest-painted`,
|
|
12
|
+
guestCommand: `${prefix}:annotation-guest-command`
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
const ANNOTATION_IPC = createAnnotationChannels();
|
|
16
|
+
const MAX_TEXT = 2048;
|
|
17
|
+
const MAX_SELECTOR = 2048;
|
|
18
|
+
const PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];
|
|
19
|
+
function validRect(rect, viewport) {
|
|
20
|
+
return rect && typeof rect === "object" && !Array.isArray(rect) && ["x", "y", "width", "height"].every((key) => Number.isFinite(rect[key])) && rect.width > 0 && rect.height > 0 && rect.x >= 0 && rect.y >= 0 && rect.x + rect.width <= viewport.width + 1 && rect.y + rect.height <= viewport.height + 1;
|
|
21
|
+
}
|
|
22
|
+
function validSelection(value, guestUrl) {
|
|
23
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !["element", "region"].includes(value.kind) || typeof value.url !== "string" || value.url !== guestUrl || typeof value.title !== "string" || value.title.length > MAX_TEXT || typeof value.selector !== "undefined" && (typeof value.selector !== "string" || value.selector.length > MAX_SELECTOR) || typeof value.text !== "undefined" && (typeof value.text !== "string" || value.text.length > MAX_TEXT) || typeof value.element !== "undefined" && !validElement(value.element)) return false;
|
|
24
|
+
const viewport = value.viewport;
|
|
25
|
+
return viewport && Number.isFinite(viewport.width) && Number.isFinite(viewport.height) && viewport.width > 0 && viewport.height > 0 && viewport.width <= 1e5 && viewport.height <= 1e5 && value.scroll && Number.isFinite(value.scroll.x) && Number.isFinite(value.scroll.y) && validRect(value.rect, viewport) && (value.anchor === void 0 || value.anchor && Number.isFinite(value.anchor.x) && Number.isFinite(value.anchor.y) && value.anchor.x >= 0 && value.anchor.y >= 0 && value.anchor.x <= viewport.width && value.anchor.y <= viewport.height);
|
|
26
|
+
}
|
|
27
|
+
function validControl(value) {
|
|
28
|
+
return value && typeof value === "object" && !Array.isArray(value) && typeof value.tagName === "string" && value.tagName.length <= 128 && (value.role === void 0 || typeof value.role === "string" && value.role.length <= 1024) && value.attributes && typeof value.attributes === "object" && !Array.isArray(value.attributes) && Object.entries(value.attributes).length <= 16 && Object.entries(value.attributes).every(([key, text]) => key.length <= 64 && typeof text === "string" && text.length <= 1024);
|
|
29
|
+
}
|
|
30
|
+
function validElement(value) {
|
|
31
|
+
return validControl(value) && typeof value.path === "string" && value.path.length <= MAX_SELECTOR && typeof value.frame === "string" && value.frame.length <= 1024 && (value.controls === void 0 || Array.isArray(value.controls) && value.controls.length <= 8 && value.controls.every(validControl));
|
|
32
|
+
}
|
|
33
|
+
function pngSize(bytes) {
|
|
34
|
+
if (bytes.length < 24 || PNG_SIGNATURE.some((byte, index) => bytes[index] !== byte)) {
|
|
35
|
+
throw new Error("annotation-kit: annotation capture did not return PNG");
|
|
36
|
+
}
|
|
37
|
+
const width = bytes.readUInt32BE(16);
|
|
38
|
+
const height = bytes.readUInt32BE(20);
|
|
39
|
+
if (!width || !height) throw new Error("annotation-kit: annotation PNG has no dimensions");
|
|
40
|
+
return { width, height };
|
|
41
|
+
}
|
|
42
|
+
function installDesktopAnnotations(policy, ipcMain, randomUUID, options = {}) {
|
|
43
|
+
const ANNOTATION_IPC2 = createAnnotationChannels(options.channelPrefix);
|
|
44
|
+
const sourceOf = options.sourceOf ?? (() => "browser");
|
|
45
|
+
const identitySource = options.identitySource ?? "browser";
|
|
46
|
+
let identityUsed = false;
|
|
47
|
+
const pendingPaints = /* @__PURE__ */ new Map();
|
|
48
|
+
const rejectPending = (guest, reason) => {
|
|
49
|
+
for (const [requestId, pending] of pendingPaints) {
|
|
50
|
+
if (pending.guest !== guest) continue;
|
|
51
|
+
pendingPaints.delete(requestId);
|
|
52
|
+
pending.reject(new Error(reason));
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const leaseForGuest = (guest) => [...policy.leases.values()].find((lease) => lease.guest === guest);
|
|
56
|
+
const publish = (lease, kind, extra = {}) => {
|
|
57
|
+
if (!lease.owner.isDestroyed()) lease.owner.send(ANNOTATION_IPC2.event, {
|
|
58
|
+
lease: lease.id,
|
|
59
|
+
documentEpoch: lease.annotation?.epoch ?? "",
|
|
60
|
+
kind,
|
|
61
|
+
source: sourceOf(lease),
|
|
62
|
+
...extra
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const activeLease = (event, id) => {
|
|
66
|
+
if (!policy.ownsApplicationFrame(event) || typeof id !== "string") {
|
|
67
|
+
throw new Error("annotation-kit: annotation requires an owned application main frame");
|
|
68
|
+
}
|
|
69
|
+
const lease = policy.leases.get(id);
|
|
70
|
+
if (!lease || lease.owner !== event.sender || !lease.guest || lease.guest.isDestroyed()) {
|
|
71
|
+
throw new Error("annotation-kit: annotation guest lease is unavailable");
|
|
72
|
+
}
|
|
73
|
+
return lease;
|
|
74
|
+
};
|
|
75
|
+
const supportedDocument = (lease) => {
|
|
76
|
+
const url = lease.guest.getURL();
|
|
77
|
+
if (!URL.canParse(url) || !["http:", "https:"].includes(new URL(url).protocol)) {
|
|
78
|
+
throw new Error("annotation-kit: annotation needs a loaded web page");
|
|
79
|
+
}
|
|
80
|
+
if (options.isSourceReady && !options.isSourceReady(lease)) {
|
|
81
|
+
throw new Error("annotation-kit: host identity cleanup is in progress");
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const visibleApplication = async (lease) => {
|
|
85
|
+
if (await lease.owner.executeJavaScript("document.visibilityState", true) !== "visible") {
|
|
86
|
+
throw new Error("annotation-kit: bring the application window to the foreground before saving an annotation screenshot");
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
ipcMain?.handle(ANNOTATION_IPC2.setMode, (event, id, mode) => {
|
|
90
|
+
const lease = activeLease(event, id);
|
|
91
|
+
supportedDocument(lease);
|
|
92
|
+
if (!["off", "element", "region"].includes(mode)) throw new Error("annotation-kit: invalid annotation mode");
|
|
93
|
+
if (!lease.annotation) lease.annotation = { epoch: randomUUID(), mode: "off", selection: void 0 };
|
|
94
|
+
rejectPending(lease.guest, "annotation-kit: annotation mode changed during capture");
|
|
95
|
+
lease.annotation.mode = mode;
|
|
96
|
+
lease.annotation.selection = void 0;
|
|
97
|
+
if (mode !== "off") {
|
|
98
|
+
lease.annotation.everActive = true;
|
|
99
|
+
if (sourceOf(lease) === identitySource) identityUsed = true;
|
|
100
|
+
}
|
|
101
|
+
lease.guest.send(ANNOTATION_IPC2.guestCommand, { kind: "mode", mode, epoch: lease.annotation.epoch });
|
|
102
|
+
return { documentEpoch: lease.annotation.epoch };
|
|
103
|
+
});
|
|
104
|
+
ipcMain?.handle(ANNOTATION_IPC2.capture, async (event, id, epoch, selection, number) => {
|
|
105
|
+
const lease = activeLease(event, id);
|
|
106
|
+
supportedDocument(lease);
|
|
107
|
+
await visibleApplication(lease);
|
|
108
|
+
if (typeof epoch !== "string" || epoch !== lease.annotation?.epoch || !Number.isSafeInteger(number) || number < 1 || number > 999 || !validSelection(selection, lease.guest.getURL()) || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection) || lease.annotation.mode !== selection.kind && !(lease.annotation.mode === "element" && selection.kind === "region")) {
|
|
109
|
+
throw new Error("annotation-kit: annotation selection is stale");
|
|
110
|
+
}
|
|
111
|
+
const guest = lease.guest;
|
|
112
|
+
const requestId = randomUUID();
|
|
113
|
+
const painted = new Promise((resolve2, reject) => {
|
|
114
|
+
const timer = setTimeout(() => {
|
|
115
|
+
pendingPaints.delete(requestId);
|
|
116
|
+
reject(new Error("annotation-kit: annotation marker timed out"));
|
|
117
|
+
}, 3e3);
|
|
118
|
+
pendingPaints.set(requestId, {
|
|
119
|
+
guest,
|
|
120
|
+
epoch,
|
|
121
|
+
resolve: () => {
|
|
122
|
+
clearTimeout(timer);
|
|
123
|
+
resolve2();
|
|
124
|
+
},
|
|
125
|
+
reject: (error) => {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
reject(error);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
guest.send(ANNOTATION_IPC2.guestCommand, { kind: "paint", epoch, requestId, selection, number });
|
|
132
|
+
try {
|
|
133
|
+
await painted;
|
|
134
|
+
if (policy.leases.get(id) !== lease || lease.guest !== guest || guest.isDestroyed() || lease.annotation?.epoch !== epoch || guest.getURL() !== selection.url || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {
|
|
135
|
+
throw new Error("annotation-kit: annotation page changed before capture");
|
|
136
|
+
}
|
|
137
|
+
let captureTimeout;
|
|
138
|
+
const image = await Promise.race([
|
|
139
|
+
guest.capturePage(),
|
|
140
|
+
new Promise((_resolve, reject) => {
|
|
141
|
+
captureTimeout = setTimeout(() => reject(new Error("annotation-kit: annotation screenshot timed out")), 1e4);
|
|
142
|
+
})
|
|
143
|
+
]).finally(() => clearTimeout(captureTimeout));
|
|
144
|
+
const png = image.toPNG();
|
|
145
|
+
if (png.length === 0) throw new Error("annotation-kit: annotation screenshot is empty");
|
|
146
|
+
const { width, height } = pngSize(png);
|
|
147
|
+
if (policy.leases.get(id) !== lease || lease.annotation?.epoch !== epoch || guest.isDestroyed() || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {
|
|
148
|
+
throw new Error("annotation-kit: annotation page changed during capture");
|
|
149
|
+
}
|
|
150
|
+
const verifyId = randomUUID();
|
|
151
|
+
const verified = new Promise((resolve2, reject) => {
|
|
152
|
+
const timer = setTimeout(() => {
|
|
153
|
+
pendingPaints.delete(verifyId);
|
|
154
|
+
reject(new Error("annotation-kit: annotation verification timed out"));
|
|
155
|
+
}, 3e3);
|
|
156
|
+
pendingPaints.set(verifyId, {
|
|
157
|
+
guest,
|
|
158
|
+
epoch,
|
|
159
|
+
resolve: () => {
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
resolve2();
|
|
162
|
+
},
|
|
163
|
+
reject: (error) => {
|
|
164
|
+
clearTimeout(timer);
|
|
165
|
+
reject(error);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
guest.send(ANNOTATION_IPC2.guestCommand, { kind: "verify", epoch, requestId: verifyId, selection });
|
|
170
|
+
try {
|
|
171
|
+
await verified;
|
|
172
|
+
} finally {
|
|
173
|
+
pendingPaints.delete(verifyId);
|
|
174
|
+
}
|
|
175
|
+
if (policy.leases.get(id) !== lease || lease.annotation?.epoch !== epoch || guest.isDestroyed() || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {
|
|
176
|
+
throw new Error("annotation-kit: annotation page changed during capture");
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
png: Uint8Array.from(png),
|
|
180
|
+
width,
|
|
181
|
+
height,
|
|
182
|
+
viewportWidth: selection.viewport.width,
|
|
183
|
+
viewportHeight: selection.viewport.height
|
|
184
|
+
};
|
|
185
|
+
} finally {
|
|
186
|
+
pendingPaints.delete(requestId);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
if (typeof ipcMain?.on === "function") ipcMain.on(ANNOTATION_IPC2.guestSelection, (event, payload) => {
|
|
190
|
+
const lease = leaseForGuest(event.sender);
|
|
191
|
+
if (!lease || event.senderFrame !== event.sender.mainFrame || lease.owner.isDestroyed() || !lease.annotation || lease.annotation.mode === "off" || payload?.epoch !== lease.annotation.epoch) return;
|
|
192
|
+
if (payload.escape === true) {
|
|
193
|
+
lease.annotation.mode = "off";
|
|
194
|
+
lease.annotation.selection = void 0;
|
|
195
|
+
rejectPending(lease.guest, "annotation-kit: annotation cancelled");
|
|
196
|
+
lease.guest.send(ANNOTATION_IPC2.guestCommand, { kind: "mode", mode: "off", epoch: lease.annotation.epoch });
|
|
197
|
+
publish(lease, "mode-ended");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (payload.selection === null) {
|
|
201
|
+
lease.annotation.selection = void 0;
|
|
202
|
+
rejectPending(lease.guest, "annotation-kit: annotation viewport changed");
|
|
203
|
+
publish(lease, "selection-cleared");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (payload?.selection?.kind !== lease.annotation.mode && !(lease.annotation.mode === "element" && payload?.selection?.kind === "region") || !validSelection(payload.selection, lease.guest.getURL())) return;
|
|
207
|
+
lease.annotation.selection = payload.selection;
|
|
208
|
+
publish(lease, "selection", { selection: payload.selection });
|
|
209
|
+
});
|
|
210
|
+
if (typeof ipcMain?.on === "function") ipcMain.on(ANNOTATION_IPC2.guestPainted, (event, payload) => {
|
|
211
|
+
const pending = pendingPaints.get(payload?.requestId);
|
|
212
|
+
if (!pending || pending.guest !== event.sender || event.senderFrame !== event.sender.mainFrame || pending.epoch !== payload.epoch) return;
|
|
213
|
+
pendingPaints.delete(payload.requestId);
|
|
214
|
+
if (typeof payload.error === "string") pending.reject(new Error("annotation-kit: annotation page changed; select the target again"));
|
|
215
|
+
else pending.resolve();
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
attached(lease) {
|
|
219
|
+
lease.annotation = { epoch: randomUUID(), mode: "off", selection: void 0, everActive: false };
|
|
220
|
+
},
|
|
221
|
+
navigation(lease) {
|
|
222
|
+
if (!lease.annotation) return;
|
|
223
|
+
if (lease.guest) rejectPending(lease.guest, "annotation-kit: annotation page changed during capture");
|
|
224
|
+
const everActive = lease.annotation.everActive;
|
|
225
|
+
lease.annotation = { epoch: randomUUID(), mode: "off", selection: void 0, everActive };
|
|
226
|
+
if (lease.guest && !lease.guest.isDestroyed()) {
|
|
227
|
+
lease.guest.send(
|
|
228
|
+
ANNOTATION_IPC2.guestCommand,
|
|
229
|
+
{ kind: "mode", mode: "off", epoch: lease.annotation.epoch }
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
if (everActive) publish(lease, "navigation");
|
|
233
|
+
},
|
|
234
|
+
disposed(lease) {
|
|
235
|
+
if (lease.guest) rejectPending(lease.guest, "annotation-kit: annotation guest closed during capture");
|
|
236
|
+
if (lease.annotation?.everActive) publish(lease, "disposed");
|
|
237
|
+
},
|
|
238
|
+
identityCleared() {
|
|
239
|
+
if (!identityUsed) return;
|
|
240
|
+
identityUsed = false;
|
|
241
|
+
for (const owner of policy.owners) {
|
|
242
|
+
if (!owner.isDestroyed()) owner.send(ANNOTATION_IPC2.event, {
|
|
243
|
+
lease: "",
|
|
244
|
+
documentEpoch: "",
|
|
245
|
+
kind: "identity-cleared",
|
|
246
|
+
source: identitySource
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const moduleDirectory = dirname(fileURLToPath(import.meta.url));
|
|
253
|
+
const PLACEHOLDER = "/* AIONE_REACT_GRAB_PRIMITIVES */ null";
|
|
254
|
+
function renderAnnotationGuestPreload({ channelPrefix = "annotation-kit" } = {}) {
|
|
255
|
+
const annotationsRequire = createRequire(import.meta.url);
|
|
256
|
+
const assets = existsSync(join(moduleDirectory, "electron", "guest-preload.cjs")) ? join(moduleDirectory, "electron") : moduleDirectory;
|
|
257
|
+
const manifest = annotationsRequire("react-grab/package.json");
|
|
258
|
+
if (manifest.version !== "0.2.0") throw new Error("annotation-kit: react-grab primitive version must remain 0.2.0");
|
|
259
|
+
const license = readFileSync(join(dirname(annotationsRequire.resolve("react-grab/package.json")), "LICENSE"), "utf8");
|
|
260
|
+
if (!license.includes("MIT License") || license.includes("*/")) {
|
|
261
|
+
throw new Error("annotation-kit: react-grab license changed; review the preload bundle");
|
|
262
|
+
}
|
|
263
|
+
const entry = annotationsRequire.resolve("react-grab/primitives");
|
|
264
|
+
const dist = dirname(entry);
|
|
265
|
+
const modules = /* @__PURE__ */ new Map();
|
|
266
|
+
const keyFor = (path) => `./${relative(dist, path).split(sep).join("/")}`;
|
|
267
|
+
const visit = (path) => {
|
|
268
|
+
const key = keyFor(path);
|
|
269
|
+
if (modules.has(key)) return;
|
|
270
|
+
if (!key.startsWith("./") || key.includes("../") || !key.endsWith(".cjs")) {
|
|
271
|
+
throw new Error(`annotation-kit: react-grab primitive escaped its CJS distribution: ${key}`);
|
|
272
|
+
}
|
|
273
|
+
const code = readFileSync(path, "utf8");
|
|
274
|
+
const dependencies = {};
|
|
275
|
+
for (const match of code.matchAll(/require\([`'"]([^`'"]+)[`'"]\)/g)) {
|
|
276
|
+
const dependency = match[1];
|
|
277
|
+
if (!dependency.startsWith("./")) {
|
|
278
|
+
throw new Error(`annotation-kit: react-grab primitive gained an external dependency: ${dependency}`);
|
|
279
|
+
}
|
|
280
|
+
const target = resolve(dirname(path), dependency);
|
|
281
|
+
dependencies[dependency] = keyFor(target);
|
|
282
|
+
visit(target);
|
|
283
|
+
}
|
|
284
|
+
modules.set(key, { code, dependencies });
|
|
285
|
+
};
|
|
286
|
+
visit(entry);
|
|
287
|
+
const factories = [...modules.entries()].map(([key, value]) => `${JSON.stringify(key)}: [function(require, module, exports) {
|
|
288
|
+
${value.code}
|
|
289
|
+
}, ${JSON.stringify(value.dependencies)}]`).join(",\n");
|
|
290
|
+
const bundled = `(() => {
|
|
291
|
+
/* react-grab 0.2.0 license:
|
|
292
|
+
${license}
|
|
293
|
+
*/
|
|
294
|
+
const modules = {${factories}}
|
|
295
|
+
const cache = Object.create(null)
|
|
296
|
+
function load(id) {
|
|
297
|
+
if (cache[id]) return cache[id].exports
|
|
298
|
+
const entry = modules[id]
|
|
299
|
+
if (!entry) throw new Error('aione annotation primitive module is unavailable')
|
|
300
|
+
const module = { exports: {} }
|
|
301
|
+
cache[id] = module
|
|
302
|
+
entry[0](specifier => load(entry[1][specifier]), module, module.exports)
|
|
303
|
+
return module.exports
|
|
304
|
+
}
|
|
305
|
+
return load(${JSON.stringify(keyFor(entry))})
|
|
306
|
+
})()`;
|
|
307
|
+
const source = readFileSync(join(assets, "guest-preload.cjs"), "utf8");
|
|
308
|
+
if (source.split(PLACEHOLDER).length !== 2) throw new Error("annotation-kit: guest primitive hook changed");
|
|
309
|
+
const contextSource = readFileSync(join(assets, "element-context.cjs"), "utf8");
|
|
310
|
+
const contextPlaceholder = "/* AIONE_ELEMENT_CONTEXT */ null";
|
|
311
|
+
if (source.split(contextPlaceholder).length !== 2) throw new Error("annotation-kit: guest element context hook changed");
|
|
312
|
+
return source.replace(PLACEHOLDER, () => bundled).replace(
|
|
313
|
+
contextPlaceholder,
|
|
314
|
+
() => `(() => { const module = { exports: {} };
|
|
315
|
+
${contextSource}
|
|
316
|
+
return module.exports })()`
|
|
317
|
+
).replaceAll("aione-desktop:", `${channelPrefix}:`);
|
|
318
|
+
}
|
|
319
|
+
var elementContext_1;
|
|
320
|
+
var hasRequiredElementContext;
|
|
321
|
+
function requireElementContext() {
|
|
322
|
+
if (hasRequiredElementContext) return elementContext_1;
|
|
323
|
+
hasRequiredElementContext = 1;
|
|
324
|
+
const attributeNames = ["id", "name", "type", "placeholder", "aria-label", "aria-labelledby", "aria-describedby", "title", "alt", "href"];
|
|
325
|
+
const bounded = (value) => String(value ?? "").trim().slice(0, 1024);
|
|
326
|
+
function roleOf(element) {
|
|
327
|
+
const explicit = element.getAttribute("role");
|
|
328
|
+
if (explicit) return bounded(explicit);
|
|
329
|
+
const tag = element.tagName.toLowerCase();
|
|
330
|
+
if (tag === "textarea") return "textbox";
|
|
331
|
+
if (tag === "select") return element.multiple ? "listbox" : "combobox";
|
|
332
|
+
if (tag === "button") return "button";
|
|
333
|
+
if (tag === "a" && element.hasAttribute("href")) return "link";
|
|
334
|
+
if (tag === "img") return "img";
|
|
335
|
+
if (tag !== "input") return void 0;
|
|
336
|
+
const type = element.type.toLowerCase();
|
|
337
|
+
if (["button", "submit", "reset", "image"].includes(type)) return "button";
|
|
338
|
+
if (["checkbox", "radio"].includes(type)) return type;
|
|
339
|
+
if (type === "number") return "spinbutton";
|
|
340
|
+
if (type === "range") return "slider";
|
|
341
|
+
if (type === "search") return "searchbox";
|
|
342
|
+
if (["hidden", "password", "file", "color", "date", "time"].includes(type)) return void 0;
|
|
343
|
+
return "textbox";
|
|
344
|
+
}
|
|
345
|
+
function describe(element) {
|
|
346
|
+
const tagName = element.tagName.toLowerCase();
|
|
347
|
+
const attributes = {};
|
|
348
|
+
for (const name of attributeNames) {
|
|
349
|
+
if (element.hasAttribute(name)) attributes[name] = bounded(element.getAttribute(name));
|
|
350
|
+
}
|
|
351
|
+
const sensitive = element.type === "password" || element.type === "hidden" || element.type === "file" || /(?:password|one-time-code|cc-)/i.test(element.getAttribute("autocomplete") || "");
|
|
352
|
+
if (!sensitive && ["input", "textarea", "select"].includes(tagName)) attributes.value = bounded(element.value);
|
|
353
|
+
if (["checkbox", "radio"].includes(element.type)) attributes.checked = String(element.checked);
|
|
354
|
+
const labels = element.labels ? [...element.labels].map((label) => bounded(label.innerText ?? label.textContent)).filter(Boolean).join(" ") : "";
|
|
355
|
+
if (labels) attributes.label = bounded(labels);
|
|
356
|
+
const role = roleOf(element);
|
|
357
|
+
return { tagName, ...role ? { role } : {}, attributes };
|
|
358
|
+
}
|
|
359
|
+
function elementContext2(element, frame = "top document") {
|
|
360
|
+
const path = [];
|
|
361
|
+
let node = element;
|
|
362
|
+
for (let depth = 0; node && depth < 12; depth++) {
|
|
363
|
+
path.unshift(node.tagName.toLowerCase());
|
|
364
|
+
const parent = node.parentElement;
|
|
365
|
+
if (parent) node = parent;
|
|
366
|
+
else {
|
|
367
|
+
const root = node.getRootNode();
|
|
368
|
+
if (root.host) {
|
|
369
|
+
path.unshift("shadow-root");
|
|
370
|
+
node = root.host;
|
|
371
|
+
} else break;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
const controls = [];
|
|
375
|
+
for (const control of element.querySelectorAll('input, textarea, select, button, [role="textbox"], [role="combobox"]')) {
|
|
376
|
+
if (controls.length === 8) break;
|
|
377
|
+
if (control.type === "hidden" || control.hidden || control.getClientRects().length === 0) continue;
|
|
378
|
+
controls.push(describe(control));
|
|
379
|
+
}
|
|
380
|
+
return { ...describe(element), path: path.join(" > "), frame: bounded(frame), ...controls.length ? { controls } : {} };
|
|
381
|
+
}
|
|
382
|
+
elementContext_1 = { elementContext: elementContext2 };
|
|
383
|
+
return elementContext_1;
|
|
384
|
+
}
|
|
385
|
+
var elementContextExports = /* @__PURE__ */ requireElementContext();
|
|
386
|
+
const elementContext = elementContextExports.elementContext;
|
|
387
|
+
export {
|
|
388
|
+
ANNOTATION_IPC,
|
|
389
|
+
createAnnotationChannels,
|
|
390
|
+
elementContext,
|
|
391
|
+
installDesktopAnnotations,
|
|
392
|
+
renderAnnotationGuestPreload
|
|
393
|
+
};
|
|
394
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"electron.js","sources":["../src/electron/bridge.mjs","../src/electron/build-preload.mjs","../src/electron/element-context.cjs"],"sourcesContent":["/** Native side of the annotation bridge. No visited page receives this API. */\nexport function createAnnotationChannels(prefix = 'annotation-kit') {\n return Object.freeze({\n setMode: `${prefix}:annotation-set-mode`, capture: `${prefix}:annotation-capture`,\n event: `${prefix}:annotation-event`, guestSelection: `${prefix}:annotation-guest-selection`,\n guestPainted: `${prefix}:annotation-guest-painted`, guestCommand: `${prefix}:annotation-guest-command`,\n })\n}\nexport const ANNOTATION_IPC = createAnnotationChannels()\n\nconst MAX_TEXT = 2048\nconst MAX_SELECTOR = 2048\nconst PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10]\n\nfunction validRect(rect, viewport) {\n return rect && typeof rect === 'object' && !Array.isArray(rect)\n && ['x', 'y', 'width', 'height'].every(key => Number.isFinite(rect[key]))\n && rect.width > 0 && rect.height > 0 && rect.x >= 0 && rect.y >= 0\n && rect.x + rect.width <= viewport.width + 1 && rect.y + rect.height <= viewport.height + 1\n}\n\nfunction validSelection(value, guestUrl) {\n if (!value || typeof value !== 'object' || Array.isArray(value)\n || !['element', 'region'].includes(value.kind)\n || typeof value.url !== 'string' || value.url !== guestUrl\n || typeof value.title !== 'string' || value.title.length > MAX_TEXT\n || typeof value.selector !== 'undefined' && (typeof value.selector !== 'string' || value.selector.length > MAX_SELECTOR)\n || typeof value.text !== 'undefined' && (typeof value.text !== 'string' || value.text.length > MAX_TEXT)\n || typeof value.element !== 'undefined' && !validElement(value.element)) return false\n const viewport = value.viewport\n return viewport && Number.isFinite(viewport.width) && Number.isFinite(viewport.height)\n && viewport.width > 0 && viewport.height > 0 && viewport.width <= 100000 && viewport.height <= 100000\n && value.scroll && Number.isFinite(value.scroll.x) && Number.isFinite(value.scroll.y)\n && validRect(value.rect, viewport)\n && (value.anchor === undefined || value.anchor && Number.isFinite(value.anchor.x) && Number.isFinite(value.anchor.y)\n && value.anchor.x >= 0 && value.anchor.y >= 0 && value.anchor.x <= viewport.width && value.anchor.y <= viewport.height)\n}\n\nfunction validControl(value) {\n return value && typeof value === 'object' && !Array.isArray(value)\n && typeof value.tagName === 'string' && value.tagName.length <= 128\n && (value.role === undefined || typeof value.role === 'string' && value.role.length <= 1024)\n && value.attributes && typeof value.attributes === 'object' && !Array.isArray(value.attributes)\n && Object.entries(value.attributes).length <= 16\n && Object.entries(value.attributes).every(([key, text]) => key.length <= 64 && typeof text === 'string' && text.length <= 1024)\n}\n\nfunction validElement(value) {\n return validControl(value) && typeof value.path === 'string' && value.path.length <= MAX_SELECTOR\n && typeof value.frame === 'string' && value.frame.length <= 1024\n && (value.controls === undefined || Array.isArray(value.controls) && value.controls.length <= 8 && value.controls.every(validControl))\n}\n\nfunction pngSize(bytes) {\n if (bytes.length < 24 || PNG_SIGNATURE.some((byte, index) => bytes[index] !== byte)) {\n throw new Error('annotation-kit: annotation capture did not return PNG')\n }\n const width = bytes.readUInt32BE(16)\n const height = bytes.readUInt32BE(20)\n if (!width || !height) throw new Error('annotation-kit: annotation PNG has no dimensions')\n return { width, height }\n}\n\n/**\n * @template {{ id: string, owner: any, guest?: any, annotation?: any }} L\n * @param {{ leases: ReadonlyMap<string, L>, owners: ReadonlySet<any>, ownsApplicationFrame(event: any): boolean }} policy\n * @param {any} ipcMain Electron's IpcMain, supplied by the owning application.\n * @param {() => string} randomUUID\n * @param {{ channelPrefix?: string, sourceOf?: (lease: L) => string, identitySource?: string, isSourceReady?: (lease: L) => boolean }} [options]\n */\nexport function installDesktopAnnotations(policy, ipcMain, randomUUID, options = {}) {\n const ANNOTATION_IPC = createAnnotationChannels(options.channelPrefix)\n const sourceOf = options.sourceOf ?? (() => 'browser')\n const identitySource = options.identitySource ?? 'browser'\n let identityUsed = false\n const pendingPaints = new Map()\n const rejectPending = (guest, reason) => {\n for (const [requestId, pending] of pendingPaints) {\n if (pending.guest !== guest) continue\n pendingPaints.delete(requestId)\n pending.reject(new Error(reason))\n }\n }\n const leaseForGuest = guest => [...policy.leases.values()].find(lease => lease.guest === guest)\n const publish = (lease, kind, extra = {}) => {\n if (!lease.owner.isDestroyed()) lease.owner.send(ANNOTATION_IPC.event, {\n lease: lease.id, documentEpoch: lease.annotation?.epoch ?? '', kind,\n source: sourceOf(lease), ...extra,\n })\n }\n const activeLease = (event, id) => {\n if (!policy.ownsApplicationFrame(event) || typeof id !== 'string') {\n throw new Error('annotation-kit: annotation requires an owned application main frame')\n }\n const lease = policy.leases.get(id)\n if (!lease || lease.owner !== event.sender || !lease.guest || lease.guest.isDestroyed()) {\n throw new Error('annotation-kit: annotation guest lease is unavailable')\n }\n return lease\n }\n const supportedDocument = lease => {\n const url = lease.guest.getURL()\n if (!URL.canParse(url) || !['http:', 'https:'].includes(new URL(url).protocol)) {\n throw new Error('annotation-kit: annotation needs a loaded web page')\n }\n if (options.isSourceReady && !options.isSourceReady(lease)) {\n throw new Error('annotation-kit: host identity cleanup is in progress')\n }\n }\n const visibleApplication = async lease => {\n if (await lease.owner.executeJavaScript('document.visibilityState', true) !== 'visible') {\n throw new Error('annotation-kit: bring the application window to the foreground before saving an annotation screenshot')\n }\n }\n ipcMain?.handle(ANNOTATION_IPC.setMode, (event, id, mode) => {\n const lease = activeLease(event, id)\n supportedDocument(lease)\n if (!['off', 'element', 'region'].includes(mode)) throw new Error('annotation-kit: invalid annotation mode')\n if (!lease.annotation) lease.annotation = { epoch: randomUUID(), mode: 'off', selection: undefined }\n rejectPending(lease.guest, 'annotation-kit: annotation mode changed during capture')\n lease.annotation.mode = mode\n lease.annotation.selection = undefined\n if (mode !== 'off') {\n lease.annotation.everActive = true\n if (sourceOf(lease) === identitySource) identityUsed = true\n }\n lease.guest.send(ANNOTATION_IPC.guestCommand, { kind: 'mode', mode, epoch: lease.annotation.epoch })\n return { documentEpoch: lease.annotation.epoch }\n })\n ipcMain?.handle(ANNOTATION_IPC.capture, async (event, id, epoch, selection, number) => {\n const lease = activeLease(event, id)\n supportedDocument(lease)\n await visibleApplication(lease)\n if (typeof epoch !== 'string' || epoch !== lease.annotation?.epoch\n || !Number.isSafeInteger(number) || number < 1 || number > 999\n || !validSelection(selection, lease.guest.getURL())\n || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)\n || (lease.annotation.mode !== selection.kind\n && !(lease.annotation.mode === 'element' && selection.kind === 'region'))) {\n throw new Error('annotation-kit: annotation selection is stale')\n }\n const guest = lease.guest\n const requestId = randomUUID()\n const painted = new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingPaints.delete(requestId)\n reject(new Error('annotation-kit: annotation marker timed out'))\n }, 3000)\n pendingPaints.set(requestId, { guest, epoch,\n resolve: () => { clearTimeout(timer); resolve() },\n reject: error => { clearTimeout(timer); reject(error) } })\n })\n guest.send(ANNOTATION_IPC.guestCommand, { kind: 'paint', epoch, requestId, selection, number })\n try {\n await painted\n if (policy.leases.get(id) !== lease || lease.guest !== guest || guest.isDestroyed()\n || lease.annotation?.epoch !== epoch || guest.getURL() !== selection.url\n || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {\n throw new Error('annotation-kit: annotation page changed before capture')\n }\n let captureTimeout\n const image = await Promise.race([\n guest.capturePage(),\n new Promise((_resolve, reject) => {\n captureTimeout = setTimeout(() => reject(new Error('annotation-kit: annotation screenshot timed out')), 10000)\n }),\n ]).finally(() => clearTimeout(captureTimeout))\n const png = image.toPNG()\n if (png.length === 0) throw new Error('annotation-kit: annotation screenshot is empty')\n const { width, height } = pngSize(png)\n if (policy.leases.get(id) !== lease || lease.annotation?.epoch !== epoch || guest.isDestroyed()\n || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {\n throw new Error('annotation-kit: annotation page changed during capture')\n }\n const verifyId = randomUUID()\n const verified = new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n pendingPaints.delete(verifyId)\n reject(new Error('annotation-kit: annotation verification timed out'))\n }, 3000)\n pendingPaints.set(verifyId, { guest, epoch,\n resolve: () => { clearTimeout(timer); resolve() },\n reject: error => { clearTimeout(timer); reject(error) } })\n })\n guest.send(ANNOTATION_IPC.guestCommand, { kind: 'verify', epoch, requestId: verifyId, selection })\n try { await verified } finally { pendingPaints.delete(verifyId) }\n if (policy.leases.get(id) !== lease || lease.annotation?.epoch !== epoch || guest.isDestroyed()\n || JSON.stringify(selection) !== JSON.stringify(lease.annotation.selection)) {\n throw new Error('annotation-kit: annotation page changed during capture')\n }\n return { png: Uint8Array.from(png), width, height,\n viewportWidth: selection.viewport.width, viewportHeight: selection.viewport.height }\n } finally { pendingPaints.delete(requestId) }\n })\n if (typeof ipcMain?.on === 'function') ipcMain.on(ANNOTATION_IPC.guestSelection, (event, payload) => {\n const lease = leaseForGuest(event.sender)\n if (!lease || event.senderFrame !== event.sender.mainFrame || lease.owner.isDestroyed()\n || !lease.annotation || lease.annotation.mode === 'off'\n || payload?.epoch !== lease.annotation.epoch) return\n if (payload.escape === true) {\n lease.annotation.mode = 'off'\n lease.annotation.selection = undefined\n rejectPending(lease.guest, 'annotation-kit: annotation cancelled')\n lease.guest.send(ANNOTATION_IPC.guestCommand, { kind: 'mode', mode: 'off', epoch: lease.annotation.epoch })\n publish(lease, 'mode-ended')\n return\n }\n if (payload.selection === null) {\n lease.annotation.selection = undefined\n rejectPending(lease.guest, 'annotation-kit: annotation viewport changed')\n publish(lease, 'selection-cleared')\n return\n }\n if ((payload?.selection?.kind !== lease.annotation.mode\n && !(lease.annotation.mode === 'element' && payload?.selection?.kind === 'region'))\n || !validSelection(payload.selection, lease.guest.getURL())) return\n lease.annotation.selection = payload.selection\n publish(lease, 'selection', { selection: payload.selection })\n })\n if (typeof ipcMain?.on === 'function') ipcMain.on(ANNOTATION_IPC.guestPainted, (event, payload) => {\n const pending = pendingPaints.get(payload?.requestId)\n if (!pending || pending.guest !== event.sender || event.senderFrame !== event.sender.mainFrame\n || pending.epoch !== payload.epoch) return\n pendingPaints.delete(payload.requestId)\n if (typeof payload.error === 'string') pending.reject(new Error('annotation-kit: annotation page changed; select the target again'))\n else pending.resolve()\n })\n return {\n attached(lease) {\n lease.annotation = { epoch: randomUUID(), mode: 'off', selection: undefined, everActive: false }\n },\n navigation(lease) {\n if (!lease.annotation) return\n if (lease.guest) rejectPending(lease.guest, 'annotation-kit: annotation page changed during capture')\n const everActive = lease.annotation.everActive\n lease.annotation = { epoch: randomUUID(), mode: 'off', selection: undefined, everActive }\n if (lease.guest && !lease.guest.isDestroyed()) {\n lease.guest.send(ANNOTATION_IPC.guestCommand,\n { kind: 'mode', mode: 'off', epoch: lease.annotation.epoch })\n }\n if (everActive) publish(lease, 'navigation')\n },\n disposed(lease) {\n if (lease.guest) rejectPending(lease.guest, 'annotation-kit: annotation guest closed during capture')\n if (lease.annotation?.everActive) publish(lease, 'disposed')\n },\n identityCleared() {\n if (!identityUsed) return\n identityUsed = false\n for (const owner of policy.owners) {\n if (!owner.isDestroyed()) owner.send(ANNOTATION_IPC.event, {\n lease: '', documentEpoch: '', kind: 'identity-cleared', source: identitySource,\n })\n }\n },\n }\n}\n","/** Bundle the pinned MIT react-grab primitives into one sandbox-compatible CJS preload. */\nimport { readFileSync, existsSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join, relative, resolve, sep } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst moduleDirectory = dirname(fileURLToPath(import.meta.url))\nconst PLACEHOLDER = '/* AIONE_REACT_GRAB_PRIMITIVES */ null'\n\nexport function renderAnnotationGuestPreload({ channelPrefix = 'annotation-kit' } = {}) {\n const annotationsRequire = createRequire(import.meta.url)\n const assets = existsSync(join(moduleDirectory, 'electron', 'guest-preload.cjs')) ? join(moduleDirectory, 'electron') : moduleDirectory\n const manifest = annotationsRequire('react-grab/package.json')\n if (manifest.version !== '0.2.0') throw new Error('annotation-kit: react-grab primitive version must remain 0.2.0')\n const license = readFileSync(join(dirname(annotationsRequire.resolve('react-grab/package.json')), 'LICENSE'), 'utf8')\n if (!license.includes('MIT License') || license.includes('*/')) {\n throw new Error('annotation-kit: react-grab license changed; review the preload bundle')\n }\n const entry = annotationsRequire.resolve('react-grab/primitives')\n const dist = dirname(entry)\n const modules = new Map()\n const keyFor = path => `./${relative(dist, path).split(sep).join('/')}`\n const visit = path => {\n const key = keyFor(path)\n if (modules.has(key)) return\n if (!key.startsWith('./') || key.includes('../') || !key.endsWith('.cjs')) {\n throw new Error(`annotation-kit: react-grab primitive escaped its CJS distribution: ${key}`)\n }\n const code = readFileSync(path, 'utf8')\n const dependencies = {}\n for (const match of code.matchAll(/require\\([`'\"]([^`'\"]+)[`'\"]\\)/g)) {\n const dependency = match[1]\n if (!dependency.startsWith('./')) {\n throw new Error(`annotation-kit: react-grab primitive gained an external dependency: ${dependency}`)\n }\n const target = resolve(dirname(path), dependency)\n dependencies[dependency] = keyFor(target)\n visit(target)\n }\n modules.set(key, { code, dependencies })\n }\n visit(entry)\n const factories = [...modules.entries()].map(([key, value]) =>\n `${JSON.stringify(key)}: [function(require, module, exports) {\\n${value.code}\\n}, ${JSON.stringify(value.dependencies)}]`).join(',\\n')\n const bundled = `(() => {\\n /* react-grab 0.2.0 license:\\n${license}\\n */\\n const modules = {${factories}}\\n const cache = Object.create(null)\\n function load(id) {\\n if (cache[id]) return cache[id].exports\\n const entry = modules[id]\\n if (!entry) throw new Error('aione annotation primitive module is unavailable')\\n const module = { exports: {} }\\n cache[id] = module\\n entry[0](specifier => load(entry[1][specifier]), module, module.exports)\\n return module.exports\\n }\\n return load(${JSON.stringify(keyFor(entry))})\\n})()`\n const source = readFileSync(join(assets, 'guest-preload.cjs'), 'utf8')\n if (source.split(PLACEHOLDER).length !== 2) throw new Error('annotation-kit: guest primitive hook changed')\n const contextSource = readFileSync(join(assets, 'element-context.cjs'), 'utf8')\n const contextPlaceholder = '/* AIONE_ELEMENT_CONTEXT */ null'\n if (source.split(contextPlaceholder).length !== 2) throw new Error('annotation-kit: guest element context hook changed')\n return source.replace(PLACEHOLDER, () => bundled).replace(contextPlaceholder,\n () => `(() => { const module = { exports: {} };\\n${contextSource}\\nreturn module.exports })()`)\n .replaceAll('aione-desktop:', `${channelPrefix}:`)\n}\n","/* Pure DOM projection, bundled into the sandboxed guest and shared with DOM tests. */\n'use strict'\n\nconst attributeNames = ['id', 'name', 'type', 'placeholder', 'aria-label', 'aria-labelledby', 'aria-describedby', 'title', 'alt', 'href']\nconst bounded = value => String(value ?? '').trim().slice(0, 1024)\n\nfunction roleOf(element) {\n const explicit = element.getAttribute('role')\n if (explicit) return bounded(explicit)\n const tag = element.tagName.toLowerCase()\n if (tag === 'textarea') return 'textbox'\n if (tag === 'select') return element.multiple ? 'listbox' : 'combobox'\n if (tag === 'button') return 'button'\n if (tag === 'a' && element.hasAttribute('href')) return 'link'\n if (tag === 'img') return 'img'\n if (tag !== 'input') return undefined\n const type = element.type.toLowerCase()\n if (['button', 'submit', 'reset', 'image'].includes(type)) return 'button'\n if (['checkbox', 'radio'].includes(type)) return type\n if (type === 'number') return 'spinbutton'\n if (type === 'range') return 'slider'\n if (type === 'search') return 'searchbox'\n if (['hidden', 'password', 'file', 'color', 'date', 'time'].includes(type)) return undefined\n return 'textbox'\n}\n\nfunction describe(element) {\n const tagName = element.tagName.toLowerCase()\n /** @type {Record<string, string>} */\n const attributes = {}\n for (const name of attributeNames) {\n if (element.hasAttribute(name)) attributes[name] = bounded(element.getAttribute(name))\n }\n // Passwords and payment/autofill secrets are never copied into text context.\n const sensitive = element.type === 'password' || element.type === 'hidden' || element.type === 'file'\n || /(?:password|one-time-code|cc-)/i.test(element.getAttribute('autocomplete') || '')\n if (!sensitive && ['input', 'textarea', 'select'].includes(tagName)) attributes.value = bounded(element.value)\n if (['checkbox', 'radio'].includes(element.type)) attributes.checked = String(element.checked)\n const labels = element.labels ? [...element.labels].map(label => bounded(label.innerText ?? label.textContent)).filter(Boolean).join(' ') : ''\n if (labels) attributes.label = bounded(labels)\n const role = roleOf(element)\n return { tagName, ...(role ? { role } : {}), attributes }\n}\n\n/**\n * @param {Element} element\n * @param {string} [frame]\n * @returns {import('../shared/desktop.ts').BrowserAnnotationElement}\n */\nfunction elementContext(element, frame = 'top document') {\n const path = []\n let node = element\n for (let depth = 0; node && depth < 12; depth++) {\n path.unshift(node.tagName.toLowerCase())\n const parent = node.parentElement\n if (parent) node = parent\n else {\n const root = node.getRootNode()\n if (root.host) { path.unshift('shadow-root'); node = root.host }\n else break\n }\n }\n const controls = []\n for (const control of element.querySelectorAll('input, textarea, select, button, [role=\"textbox\"], [role=\"combobox\"]')) {\n if (controls.length === 8) break\n if (control.type === 'hidden' || control.hidden || control.getClientRects().length === 0) continue\n controls.push(describe(control))\n }\n return { ...describe(element), path: path.join(' > '), frame: bounded(frame), ...(controls.length ? { controls } : {}) }\n}\n\nmodule.exports = { elementContext }\n"],"names":["ANNOTATION_IPC","resolve","elementContext"],"mappings":"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"}
|