codex-overleaf-link 1.8.6 → 1.9.0
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/README.md +45 -21
- package/bin/codex-overleaf-link.mjs +58 -0
- package/extension/assets/icons/codex-overleaf-dialog-icon.png +0 -0
- package/extension/assets/icons/codex-overleaf-icon.png +0 -0
- package/extension/assets/icons/icon128.png +0 -0
- package/extension/assets/icons/icon16.png +0 -0
- package/extension/assets/icons/icon32.png +0 -0
- package/extension/assets/icons/icon48.png +0 -0
- package/extension/bootstrap/background.js +404 -0
- package/extension/bootstrap/manifest.template.json +51 -0
- package/extension/bootstrap/popup.css +26 -0
- package/extension/bootstrap/popup.html +38 -0
- package/extension/bootstrap/popup.js +44 -0
- package/extension/bootstrap/runtimeContext.js +2 -0
- package/extension/runtime-manifest.json +60 -0
- package/extension/src/background.js +532 -0
- package/extension/src/content/applyResultFormatters.js +387 -0
- package/extension/src/content/composerAttachments.js +522 -0
- package/extension/src/content/composerPanel.js +254 -0
- package/extension/src/content/contentRuntime.js +8895 -0
- package/extension/src/content/contextTray.js +686 -0
- package/extension/src/content/diagnosticsController.js +659 -0
- package/extension/src/content/diagnosticsPanel.js +342 -0
- package/extension/src/content/diffReviewPanel.js +797 -0
- package/extension/src/content/localSkillsPanel.js +280 -0
- package/extension/src/content/markdownText.js +606 -0
- package/extension/src/content/mirrorHealth.js +92 -0
- package/extension/src/content/modelPicker.js +489 -0
- package/extension/src/content/nativeChannel.js +62 -0
- package/extension/src/content/otWarmMirror.js +964 -0
- package/extension/src/content/otWarmMirrorController.js +174 -0
- package/extension/src/content/panelMaintenance.js +367 -0
- package/extension/src/content/panelRenderer.js +253 -0
- package/extension/src/content/recentProjects.js +1063 -0
- package/extension/src/content/reviewHunks.js +247 -0
- package/extension/src/content/runController.js +242 -0
- package/extension/src/content/runTimelineView.js +1126 -0
- package/extension/src/content/sessionManager.js +487 -0
- package/extension/src/content/sessionPanel.js +263 -0
- package/extension/src/content/settingsPanel.js +527 -0
- package/extension/src/content/themeController.js +91 -0
- package/extension/src/content/updateIdle.js +67 -0
- package/extension/src/content/writebackController.js +300 -0
- package/extension/src/content/writebackOrchestrator.js +850 -0
- package/extension/src/contentScript.js +8 -0
- package/extension/src/page/compileBridge.js +460 -0
- package/extension/src/page/overleafCapabilities.js +100 -0
- package/extension/src/page/overleafEditor.js +282 -0
- package/extension/src/page/overleafProjectSnapshot.js +234 -0
- package/extension/src/page/overleafRealtimeObserver.js +491 -0
- package/extension/src/page/pageBridgeCapability.js +71 -0
- package/extension/src/page/snapshotRouter.js +948 -0
- package/extension/src/page/trackedChangesLifecycle.js +1506 -0
- package/extension/src/page/treeOperations.js +1584 -0
- package/extension/src/page/writeGuard.js +142 -0
- package/extension/src/page/writebackRouter.js +1934 -0
- package/extension/src/pageBridge.js +2224 -0
- package/extension/src/popup.js +247 -0
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/styles/panel.css +4048 -0
- package/native-host/src/index.js +9 -2
- package/native-host/src/managedInstall.js +393 -0
- package/native-host/src/managedLauncherRuntime.js +71 -0
- package/native-host/src/nativeHostPlatform.js +16 -0
- package/native-host/src/runtimeInstaller.js +6 -1
- package/native-host/src/taskRunnerRuntime.js +8 -0
- package/native-host/src/updateArchive.js +253 -0
- package/native-host/src/updateManager.js +548 -0
- package/native-host/src/updateTrust.js +156 -0
- package/package.json +11 -2
- package/scripts/install-managed.mjs +64 -0
- package/scripts/uninstall-managed.mjs +48 -0
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
(function initOverleafRealtimeObserver(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory(root);
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafRealtimeObserver = factory(root);
|
|
6
|
+
}
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function overleafRealtimeObserverFactory(root) {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const STRATEGY_ACTIVE_EDITOR = 'active-editor';
|
|
11
|
+
const CHANNEL_ROOT_NAMES = ['overleaf', 'Overleaf', '_ide', 'OL'];
|
|
12
|
+
const BASELINE_REFRESH_EVENT_TYPES = ['click', 'focusin', 'change'];
|
|
13
|
+
const CHANNEL_KEY_PATTERN = /socket|websocket|channel|realtime|collab|share|ot|doc|editor|connection|event|broadcast|presence/i;
|
|
14
|
+
const SENSITIVE_KEY_PATTERN = /^(content|previousContent|nextContent|text|body|raw|rawContent|source|sourceText)$/i;
|
|
15
|
+
|
|
16
|
+
function create(deps = {}) {
|
|
17
|
+
const pageWindow = deps.window || getDefaultWindow();
|
|
18
|
+
const pageDocument = Object.prototype.hasOwnProperty.call(deps, 'document')
|
|
19
|
+
? deps.document
|
|
20
|
+
: getDefaultDocument();
|
|
21
|
+
const events = [];
|
|
22
|
+
let activePath = '';
|
|
23
|
+
let lastContent = '';
|
|
24
|
+
let running = false;
|
|
25
|
+
let listenersAttached = false;
|
|
26
|
+
let statusName = 'off';
|
|
27
|
+
let statusReason = '';
|
|
28
|
+
let lastEventAt = null;
|
|
29
|
+
let lastErrorCode = '';
|
|
30
|
+
let channelCandidates = [];
|
|
31
|
+
|
|
32
|
+
function start(_params = {}) {
|
|
33
|
+
clearQueuedEvents();
|
|
34
|
+
channelCandidates = collectChannelCandidates(pageWindow);
|
|
35
|
+
if (!canAttachDocumentListeners()) {
|
|
36
|
+
running = false;
|
|
37
|
+
markUnavailable('missing_document');
|
|
38
|
+
return getStatus();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
running = true;
|
|
42
|
+
refreshActiveBaseline();
|
|
43
|
+
attachDocumentListeners();
|
|
44
|
+
return getStatus();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function stop() {
|
|
48
|
+
detachDocumentListeners();
|
|
49
|
+
clearQueuedEvents();
|
|
50
|
+
running = false;
|
|
51
|
+
statusName = 'off';
|
|
52
|
+
statusReason = '';
|
|
53
|
+
return getStatus();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getStatus() {
|
|
57
|
+
const status = {
|
|
58
|
+
status: statusName,
|
|
59
|
+
state: statusName,
|
|
60
|
+
running,
|
|
61
|
+
strategy: STRATEGY_ACTIVE_EDITOR,
|
|
62
|
+
activePath,
|
|
63
|
+
queuedEventCount: events.length,
|
|
64
|
+
lastEventAt,
|
|
65
|
+
lastErrorCode,
|
|
66
|
+
channelCandidates: cloneChannelCandidates(channelCandidates)
|
|
67
|
+
};
|
|
68
|
+
if (statusName === 'unavailable' && statusReason) {
|
|
69
|
+
status.reason = statusReason;
|
|
70
|
+
}
|
|
71
|
+
return status;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function drainEvents() {
|
|
75
|
+
const drained = events.slice();
|
|
76
|
+
clearQueuedEvents();
|
|
77
|
+
return drained;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function clearQueuedEvents() {
|
|
81
|
+
events.length = 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function canAttachDocumentListeners() {
|
|
85
|
+
return Boolean(pageDocument && typeof pageDocument.addEventListener === 'function');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function attachDocumentListeners() {
|
|
89
|
+
if (listenersAttached) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
pageDocument.addEventListener('input', handleEditorInput, true);
|
|
93
|
+
for (const type of BASELINE_REFRESH_EVENT_TYPES) {
|
|
94
|
+
pageDocument.addEventListener(type, handleBaselineRefreshEvent, true);
|
|
95
|
+
}
|
|
96
|
+
listenersAttached = true;
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function detachDocumentListeners() {
|
|
101
|
+
if (!listenersAttached || !pageDocument || typeof pageDocument.removeEventListener !== 'function') {
|
|
102
|
+
listenersAttached = false;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
pageDocument.removeEventListener('input', handleEditorInput, true);
|
|
106
|
+
for (const type of BASELINE_REFRESH_EVENT_TYPES) {
|
|
107
|
+
pageDocument.removeEventListener(type, handleBaselineRefreshEvent, true);
|
|
108
|
+
}
|
|
109
|
+
listenersAttached = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function refreshActiveBaseline() {
|
|
113
|
+
const pathResult = readActivePath();
|
|
114
|
+
if (!pathResult.ok) {
|
|
115
|
+
handleActivePathUnavailable(pathResult.reason);
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const textResult = readEditorText();
|
|
120
|
+
if (!textResult.ok) {
|
|
121
|
+
markUnavailable(textResult.reason);
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
activePath = pathResult.path;
|
|
126
|
+
lastContent = textResult.text;
|
|
127
|
+
markObserving();
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function handleBaselineRefreshEvent() {
|
|
132
|
+
if (!running) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const pathResult = readActivePath();
|
|
137
|
+
if (!pathResult.ok) {
|
|
138
|
+
handleActivePathUnavailable(pathResult.reason);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (pathResult.path === activePath) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const textResult = readEditorText();
|
|
146
|
+
if (!textResult.ok) {
|
|
147
|
+
markUnavailable(textResult.reason);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
activePath = pathResult.path;
|
|
152
|
+
lastContent = textResult.text;
|
|
153
|
+
markObserving();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function handleEditorInput() {
|
|
157
|
+
if (!running) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const pathResult = readActivePath();
|
|
162
|
+
if (!pathResult.ok) {
|
|
163
|
+
handleActivePathUnavailable(pathResult.reason);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const textResult = readEditorText();
|
|
168
|
+
if (!textResult.ok) {
|
|
169
|
+
markUnavailable(textResult.reason);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const nextContent = textResult.text;
|
|
174
|
+
if (pathResult.path !== activePath) {
|
|
175
|
+
// Fallback for file switches that were not preceded by a selection/focus event.
|
|
176
|
+
activePath = pathResult.path;
|
|
177
|
+
lastContent = nextContent;
|
|
178
|
+
markObserving();
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (nextContent === lastContent) {
|
|
183
|
+
markObserving();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const observedAt = resolveObservedAt();
|
|
188
|
+
const otText = resolveOtText(deps, pageWindow, root);
|
|
189
|
+
if (!otText || typeof otText.normalizeObservedTextEvent !== 'function') {
|
|
190
|
+
markUnavailable('missing_ot_text');
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const event = otText.normalizeObservedTextEvent({
|
|
195
|
+
path: activePath,
|
|
196
|
+
previousContent: lastContent,
|
|
197
|
+
nextContent,
|
|
198
|
+
observedAt,
|
|
199
|
+
source: STRATEGY_ACTIVE_EDITOR
|
|
200
|
+
});
|
|
201
|
+
if (event && event.ok === true) {
|
|
202
|
+
const queuedEvent = sanitizeObservedEvent(event);
|
|
203
|
+
events.push(queuedEvent);
|
|
204
|
+
lastEventAt = queuedEvent.observedAt || observedAt;
|
|
205
|
+
markObserving();
|
|
206
|
+
} else {
|
|
207
|
+
lastErrorCode = event?.reason || 'normalize_observed_text_event_failed';
|
|
208
|
+
}
|
|
209
|
+
lastContent = nextContent;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function handleActivePathUnavailable(reason) {
|
|
213
|
+
if (reason === 'missing_active_path') {
|
|
214
|
+
activePath = '';
|
|
215
|
+
lastContent = '';
|
|
216
|
+
}
|
|
217
|
+
markUnavailable(reason);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function readActivePath() {
|
|
221
|
+
if (typeof deps.getActiveFilePath !== 'function') {
|
|
222
|
+
return {
|
|
223
|
+
ok: false,
|
|
224
|
+
reason: 'missing_active_path'
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
try {
|
|
228
|
+
const path = normalizePath(deps.getActiveFilePath());
|
|
229
|
+
if (!path) {
|
|
230
|
+
return {
|
|
231
|
+
ok: false,
|
|
232
|
+
reason: 'missing_active_path'
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
ok: true,
|
|
237
|
+
path
|
|
238
|
+
};
|
|
239
|
+
} catch (_error) {
|
|
240
|
+
return {
|
|
241
|
+
ok: false,
|
|
242
|
+
reason: 'read_active_path_failed'
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function readEditorText() {
|
|
248
|
+
if (typeof deps.readActiveEditorText !== 'function') {
|
|
249
|
+
return {
|
|
250
|
+
ok: false,
|
|
251
|
+
reason: 'missing_editor_reader'
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
return {
|
|
256
|
+
ok: true,
|
|
257
|
+
text: String(deps.readActiveEditorText() ?? '')
|
|
258
|
+
};
|
|
259
|
+
} catch (_error) {
|
|
260
|
+
return {
|
|
261
|
+
ok: false,
|
|
262
|
+
reason: 'read_active_editor_failed'
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function resolveObservedAt() {
|
|
268
|
+
let value;
|
|
269
|
+
try {
|
|
270
|
+
value = typeof deps.now === 'function' ? deps.now() : Date.now();
|
|
271
|
+
} catch (_error) {
|
|
272
|
+
value = Date.now();
|
|
273
|
+
}
|
|
274
|
+
return validDateToIso(value) || validDateToIso(Date.now()) || new Date().toISOString();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function markObserving() {
|
|
278
|
+
statusName = 'observing';
|
|
279
|
+
statusReason = '';
|
|
280
|
+
lastErrorCode = '';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function markUnavailable(reason) {
|
|
284
|
+
statusName = 'unavailable';
|
|
285
|
+
statusReason = reason;
|
|
286
|
+
lastErrorCode = reason;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
drainEvents,
|
|
291
|
+
getStatus,
|
|
292
|
+
start,
|
|
293
|
+
stop
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function collectChannelCandidates(pageWindow) {
|
|
298
|
+
if (!pageWindow || typeof pageWindow !== 'object') {
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const candidates = [];
|
|
303
|
+
for (const rootName of CHANNEL_ROOT_NAMES) {
|
|
304
|
+
const descriptor = getDescriptor(pageWindow, rootName);
|
|
305
|
+
const value = descriptor && Object.prototype.hasOwnProperty.call(descriptor, 'value')
|
|
306
|
+
? descriptor.value
|
|
307
|
+
: undefined;
|
|
308
|
+
if (!isInspectableObject(value)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const keyPaths = collectCandidateKeyPaths(value);
|
|
313
|
+
if (keyPaths.length) {
|
|
314
|
+
candidates.push({
|
|
315
|
+
root: rootName,
|
|
316
|
+
keyPaths
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return candidates;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function collectCandidateKeyPaths(value) {
|
|
324
|
+
const seen = typeof WeakSet === 'function' ? new WeakSet() : null;
|
|
325
|
+
const keyPaths = [];
|
|
326
|
+
walk(value, '', 0);
|
|
327
|
+
return Array.from(new Set(keyPaths)).slice(0, 80);
|
|
328
|
+
|
|
329
|
+
function walk(current, prefix, depth) {
|
|
330
|
+
if (!isInspectableObject(current) || depth > 2) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (seen) {
|
|
334
|
+
if (seen.has(current)) {
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
seen.add(current);
|
|
338
|
+
}
|
|
339
|
+
const descriptors = getDescriptors(current);
|
|
340
|
+
if (isDomLikeDescriptorMap(descriptors)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
for (const key of Object.keys(descriptors)) {
|
|
345
|
+
const descriptor = descriptors[key];
|
|
346
|
+
const keyPath = prefix ? `${prefix}.${key}` : key;
|
|
347
|
+
if (isChannelCandidateKey(key)) {
|
|
348
|
+
keyPaths.push(keyPath);
|
|
349
|
+
}
|
|
350
|
+
if (depth < 2 && descriptor && Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
351
|
+
walk(descriptor.value, keyPath, depth + 1);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function isChannelCandidateKey(key) {
|
|
358
|
+
return key.length <= 80
|
|
359
|
+
&& !SENSITIVE_KEY_PATTERN.test(key)
|
|
360
|
+
&& CHANNEL_KEY_PATTERN.test(key);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function getDescriptor(value, key) {
|
|
364
|
+
try {
|
|
365
|
+
return Object.getOwnPropertyDescriptor(value, key) || null;
|
|
366
|
+
} catch (_error) {
|
|
367
|
+
return null;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function getDescriptors(value) {
|
|
372
|
+
try {
|
|
373
|
+
return Object.getOwnPropertyDescriptors(value);
|
|
374
|
+
} catch (_error) {
|
|
375
|
+
return {};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function cloneChannelCandidates(candidates) {
|
|
380
|
+
return candidates.map(candidate => ({
|
|
381
|
+
root: candidate.root,
|
|
382
|
+
keyPaths: candidate.keyPaths.slice()
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function isInspectableObject(value) {
|
|
387
|
+
return Boolean(value && typeof value === 'object');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function isDomLikeDescriptorMap(descriptors) {
|
|
391
|
+
return isDomMarkerDescriptor(descriptors.nodeType)
|
|
392
|
+
|| isDomMarkerDescriptor(descriptors.ownerDocument)
|
|
393
|
+
|| isDomFunctionDescriptor(descriptors.querySelectorAll)
|
|
394
|
+
|| isDomFunctionDescriptor(descriptors.addEventListener);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function isDomMarkerDescriptor(descriptor) {
|
|
398
|
+
if (!descriptor) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
if (!Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
return Boolean(descriptor.value);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function isDomFunctionDescriptor(descriptor) {
|
|
408
|
+
if (!descriptor) {
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
if (!Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
return typeof descriptor.value === 'function';
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function sanitizeObservedEvent(event) {
|
|
418
|
+
return {
|
|
419
|
+
path: event.path,
|
|
420
|
+
baseHash: event.baseHash,
|
|
421
|
+
nextHash: event.nextHash,
|
|
422
|
+
nextContent: event.nextContent,
|
|
423
|
+
ops: Array.isArray(event.ops) ? event.ops.map(cloneTextOp) : [],
|
|
424
|
+
observedAt: event.observedAt,
|
|
425
|
+
observedVersion: event.observedVersion ?? null,
|
|
426
|
+
source: event.source
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function cloneTextOp(op) {
|
|
431
|
+
return op && typeof op === 'object' && !Array.isArray(op)
|
|
432
|
+
? { ...op }
|
|
433
|
+
: op;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function validDateToIso(value) {
|
|
437
|
+
try {
|
|
438
|
+
const date = new Date(value);
|
|
439
|
+
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
440
|
+
} catch (_error) {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function normalizePath(value) {
|
|
446
|
+
return String(value || '')
|
|
447
|
+
.replace(/\s+/g, ' ')
|
|
448
|
+
.replace(/\\/g, '/')
|
|
449
|
+
.trim()
|
|
450
|
+
.replace(/^\/+/, '');
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function getDefaultWindow() {
|
|
454
|
+
if (typeof window !== 'undefined') {
|
|
455
|
+
return window;
|
|
456
|
+
}
|
|
457
|
+
return root || {};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function getDefaultDocument() {
|
|
461
|
+
if (typeof document !== 'undefined') {
|
|
462
|
+
return document;
|
|
463
|
+
}
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function resolveOtText(deps, pageWindow, rootObject) {
|
|
468
|
+
if (deps.otText) {
|
|
469
|
+
return deps.otText;
|
|
470
|
+
}
|
|
471
|
+
if (pageWindow?.CodexOverleafOtText) {
|
|
472
|
+
return pageWindow.CodexOverleafOtText;
|
|
473
|
+
}
|
|
474
|
+
if (rootObject?.CodexOverleafOtText) {
|
|
475
|
+
return rootObject.CodexOverleafOtText;
|
|
476
|
+
}
|
|
477
|
+
if (typeof require === 'function') {
|
|
478
|
+
try {
|
|
479
|
+
return require('../shared/otText');
|
|
480
|
+
} catch (_error) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
return {
|
|
488
|
+
collectChannelCandidates,
|
|
489
|
+
create
|
|
490
|
+
};
|
|
491
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
(function initPageBridgeCapability(root, factory) {
|
|
2
|
+
if (typeof module === 'object' && module.exports) {
|
|
3
|
+
module.exports = factory();
|
|
4
|
+
} else {
|
|
5
|
+
root.CodexOverleafPageBridgeCapability = factory();
|
|
6
|
+
}
|
|
7
|
+
})(typeof window !== 'undefined' ? window : globalThis, function pageBridgeCapabilityFactory() {
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
function create() {
|
|
11
|
+
const state = {
|
|
12
|
+
capability: ''
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
initializePageBridgeCapability(capability) {
|
|
17
|
+
return initializePageBridgeCapability(state, capability);
|
|
18
|
+
},
|
|
19
|
+
hasValidPageBridgeCapability(capability) {
|
|
20
|
+
return hasValidPageBridgeCapability(state, capability);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function initializePageBridgeCapability(state, capability) {
|
|
26
|
+
if (!isValidPageBridgeCapability(capability)) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
code: 'invalid_page_bridge_capability',
|
|
30
|
+
error: 'Invalid page bridge capability'
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (!state.capability) {
|
|
34
|
+
state.capability = capability;
|
|
35
|
+
return { ok: true };
|
|
36
|
+
}
|
|
37
|
+
if (capability === state.capability) {
|
|
38
|
+
return { ok: true, alreadyInitialized: true };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
code: 'page_bridge_capability_already_initialized',
|
|
43
|
+
error: 'Page bridge capability is already initialized'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function hasValidPageBridgeCapability(state, capability) {
|
|
48
|
+
return Boolean(state.capability && capability === state.capability);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isValidPageBridgeCapability(capability) {
|
|
52
|
+
return typeof capability === 'string'
|
|
53
|
+
&& capability.length >= 16
|
|
54
|
+
&& capability.length <= 256
|
|
55
|
+
&& !/[\u0000-\u001f\u007f]/.test(capability);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function buildUnauthorizedBridgeResult() {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
code: 'page_bridge_unauthorized',
|
|
62
|
+
error: 'Page bridge request is not authorized'
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
buildUnauthorizedBridgeResult,
|
|
68
|
+
create,
|
|
69
|
+
isValidPageBridgeCapability
|
|
70
|
+
};
|
|
71
|
+
});
|