codex-overleaf-link 2.2.1 → 2.3.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/README.md +25 -23
- package/extension/bootstrap/manifest.template.json +1 -1
- package/extension/runtime-manifest.json +5 -71
- package/extension/src/background.js +67 -63
- package/extension/src/backgroundUpdateCoordinator.js +128 -66
- package/extension/src/content/applyResultFormatters.js +2 -3
- package/extension/src/content/composerPanel.js +0 -2
- package/extension/src/content/contentRuntime.js +757 -1558
- package/extension/src/content/contextTray.js +4 -6
- package/extension/src/content/diagnosticsController.js +1 -2
- package/extension/src/content/diffReviewPanel.js +14 -13
- package/extension/src/content/generated/content.bundle.js +41605 -0
- package/extension/src/content/generated/content.bundle.meta.json +103 -0
- package/extension/src/content/legacyGlobalRegistry.js +129 -0
- package/extension/src/content/markdownText.js +17 -17
- package/extension/src/content/mathText.js +155 -9
- package/extension/src/content/modelPicker.js +1 -1
- package/extension/src/content/modelPickerSupport.js +10 -5
- package/extension/src/content/moduleRegistryKernel.js +125 -0
- package/extension/src/content/nativeCompatibilityController.js +313 -0
- package/extension/src/content/otWarmMirror.js +8 -6
- package/extension/src/content/pageBridgeClient.js +224 -0
- package/extension/src/content/panelMaintenance.js +8 -3
- package/extension/src/content/postNavigationSettlementPersistence.js +100 -0
- package/extension/src/content/projectProviderSelection.js +4 -12
- package/extension/src/content/projectSessionCleanup.js +3 -3
- package/extension/src/content/providerSettingsCoordinator.js +59 -26
- package/extension/src/content/providerSettingsDialog.js +30 -18
- package/extension/src/content/recentProjects.js +15 -23
- package/extension/src/content/runGuidanceController.js +1 -1
- package/extension/src/content/runQueueScheduler.js +129 -29
- package/extension/src/content/runSettlementPersistence.js +51 -0
- package/extension/src/content/runTimelineView.js +17 -8
- package/extension/src/content/scopedPersistenceCoordinator.js +100 -0
- package/extension/src/content/scopedPersistenceDetachedCommit.js +47 -0
- package/extension/src/content/scopedPersistencePanelState.js +111 -0
- package/extension/src/content/sessionManager.js +15 -12
- package/extension/src/content/sessionPersistence.js +67 -8
- package/extension/src/content/updateNotice.js +10 -4
- package/extension/src/content/writebackOrchestrator.js +89 -68
- package/extension/src/contentScript.js +5 -1
- package/extension/src/page/trackedChangesLifecycle.js +16 -5
- package/extension/src/page/writebackRouter.js +6 -2
- package/extension/src/pageBridge.js +47 -98
- package/extension/src/shared/agentTranscript.js +18 -8
- package/extension/src/shared/compatibility.js +1 -1
- package/extension/src/shared/governanceRules.js +1 -1
- package/extension/src/shared/i18n.js +2 -4
- package/extension/src/shared/managedUpdateProjection.js +337 -0
- package/extension/src/shared/nativeRequestIdentity.js +60 -0
- package/extension/src/shared/otText.js +0 -19
- package/extension/src/shared/pageRpcContract.js +136 -0
- package/extension/src/shared/runExecutionSnapshot.js +187 -0
- package/extension/src/shared/runExecutionSnapshotCodec.js +171 -0
- package/extension/src/shared/runInputQueue.js +81 -34
- package/extension/src/shared/scopedPersistenceBrowserAdapter.js +79 -0
- package/extension/src/shared/scopedPersistenceQueuePolicy.js +200 -0
- package/extension/src/shared/scopedPersistenceReceipt.js +60 -0
- package/extension/src/shared/scopedPersistenceTransaction.js +241 -0
- package/extension/src/shared/sessionState.js +110 -59
- package/extension/src/shared/settlementFacts.js +351 -0
- package/extension/src/shared/storageDb.js +25 -10
- package/extension/src/shared/storageMigration.js +275 -61
- package/extension/src/shared/storageSessionClaims.js +60 -0
- package/extension/src/shared/updateConsent.js +4 -0
- package/extension/src/shared/updateRevocationIntent.js +109 -0
- package/extension/src/shared/writebackEvidenceProjection.js +150 -0
- package/extension/src/shared/writebackOperationEvidence.js +153 -0
- package/extension/src/shared/writebackSettlement.js +727 -0
- package/extension/styles/panel.css +18 -8
- package/native-host/src/codexPromptAssembly.js +1 -1
- package/native-host/src/codexRuntimeIdentity.js +1 -1
- package/native-host/src/codexSessionRunner.js +7 -13
- package/native-host/src/index.js +3 -69
- package/native-host/src/managedInstall.js +50 -8
- package/native-host/src/nativeTransportEnvelope.js +148 -0
- package/native-host/src/taskRunnerRuntime.js +14 -84
- package/native-host/src/updateManager.js +36 -1
- package/package.json +13 -5
|
@@ -266,8 +266,6 @@
|
|
|
266
266
|
writeMode: 'Write mode',
|
|
267
267
|
modeAsk: 'Ask',
|
|
268
268
|
modeAskTitle: 'Read and analyze only. Do not write to Overleaf.',
|
|
269
|
-
modeConfirm: 'Suggest',
|
|
270
|
-
modeConfirmTitle: 'Show a change plan first, then write after approval.',
|
|
271
269
|
modeAuto: 'Auto',
|
|
272
270
|
modeAutoTitle: 'Write directly after authorization. Deletes still require confirmation.',
|
|
273
271
|
addContext: 'Add @ context',
|
|
@@ -403,6 +401,7 @@
|
|
|
403
401
|
refreshProbeDone: 'Refreshed: {status}',
|
|
404
402
|
refreshProbeFailed: 'Refresh failed. Reload Overleaf and try again.',
|
|
405
403
|
processedFailed: 'Failed {elapsed}',
|
|
404
|
+
processedCancelled: 'Cancelled {elapsed}',
|
|
406
405
|
processing: 'Running {elapsed}',
|
|
407
406
|
processed: 'Done {elapsed}',
|
|
408
407
|
restoredRunStoppedTitle: 'Stopped tracking this run after a page refresh',
|
|
@@ -779,8 +778,6 @@
|
|
|
779
778
|
writeMode: '写入模式',
|
|
780
779
|
modeAsk: '只问不改',
|
|
781
780
|
modeAskTitle: '只读取和分析,不写入 Overleaf',
|
|
782
|
-
modeConfirm: '建议修改',
|
|
783
|
-
modeConfirmTitle: '先给出修改方案,确认后写入',
|
|
784
781
|
modeAuto: '自动写入',
|
|
785
782
|
modeAutoTitle: '授权后直接写入,删除仍需确认',
|
|
786
783
|
addContext: '添加 @ 上下文',
|
|
@@ -916,6 +913,7 @@
|
|
|
916
913
|
refreshProbeDone: '已重新检测:{status}',
|
|
917
914
|
refreshProbeFailed: '检测失败:请刷新 Overleaf 页面后重试',
|
|
918
915
|
processedFailed: '处理失败 {elapsed}',
|
|
916
|
+
processedCancelled: '已取消 {elapsed}',
|
|
919
917
|
processing: '处理中 {elapsed}',
|
|
920
918
|
processed: '已处理 {elapsed}',
|
|
921
919
|
restoredRunStoppedTitle: '页面刷新后已停止跟踪这轮任务',
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
(function initCodexOverleafManagedUpdateProjection(root) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const PHASE_ALIASES = Object.freeze({
|
|
5
|
+
waiting: 'waiting_for_idle',
|
|
6
|
+
waiting_for_safe_point: 'waiting_for_idle',
|
|
7
|
+
awaiting_health_check: 'awaiting_health',
|
|
8
|
+
health_checking: 'awaiting_health'
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const PHASES = Object.freeze([
|
|
12
|
+
'idle',
|
|
13
|
+
'up_to_date',
|
|
14
|
+
'checking',
|
|
15
|
+
'update_available',
|
|
16
|
+
'downloading',
|
|
17
|
+
'staged',
|
|
18
|
+
'waiting_for_idle',
|
|
19
|
+
'applying',
|
|
20
|
+
'awaiting_health',
|
|
21
|
+
'committed',
|
|
22
|
+
'failed',
|
|
23
|
+
'rolling_back',
|
|
24
|
+
'rolled_back',
|
|
25
|
+
'deferred'
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const PHASE_TIMEOUTS = Object.freeze({
|
|
29
|
+
checking: 30 * 1000,
|
|
30
|
+
downloading: 2 * 60 * 1000,
|
|
31
|
+
applying: 90 * 1000,
|
|
32
|
+
awaiting_health: 2 * 60 * 1000,
|
|
33
|
+
rolling_back: 60 * 1000
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const PROGRESS = Object.freeze({
|
|
37
|
+
checking: 8,
|
|
38
|
+
update_available: 0,
|
|
39
|
+
downloading: 25,
|
|
40
|
+
staged: 48,
|
|
41
|
+
waiting_for_idle: 55,
|
|
42
|
+
applying: 75,
|
|
43
|
+
awaiting_health: 90,
|
|
44
|
+
committed: 100,
|
|
45
|
+
rolled_back: 100
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const ACTIVE_STAGE = Object.freeze({
|
|
49
|
+
downloading: 0,
|
|
50
|
+
staged: 1,
|
|
51
|
+
waiting_for_idle: 1,
|
|
52
|
+
applying: 2,
|
|
53
|
+
awaiting_health: 2,
|
|
54
|
+
committed: 3
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const ACTIVE_PHASES = Object.freeze({
|
|
58
|
+
update_page: Object.freeze([
|
|
59
|
+
'checking',
|
|
60
|
+
'downloading',
|
|
61
|
+
'staged',
|
|
62
|
+
'waiting_for_idle',
|
|
63
|
+
'applying',
|
|
64
|
+
'awaiting_health'
|
|
65
|
+
]),
|
|
66
|
+
panel: Object.freeze([
|
|
67
|
+
'downloading',
|
|
68
|
+
'staged',
|
|
69
|
+
'waiting_for_idle',
|
|
70
|
+
'applying',
|
|
71
|
+
'awaiting_health'
|
|
72
|
+
])
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const TRANSITIONS = Object.freeze({
|
|
76
|
+
idle: Object.freeze(['checking']),
|
|
77
|
+
up_to_date: Object.freeze(['checking', 'idle']),
|
|
78
|
+
checking: Object.freeze(['idle', 'up_to_date', 'update_available', 'failed']),
|
|
79
|
+
update_available: Object.freeze(['checking', 'downloading', 'deferred', 'failed']),
|
|
80
|
+
downloading: Object.freeze(['staged', 'failed']),
|
|
81
|
+
staged: Object.freeze(['waiting_for_idle', 'applying', 'update_available', 'deferred', 'failed']),
|
|
82
|
+
waiting_for_idle: Object.freeze(['applying', 'update_available', 'deferred', 'failed']),
|
|
83
|
+
applying: Object.freeze(['staged', 'awaiting_health', 'rolling_back', 'failed']),
|
|
84
|
+
awaiting_health: Object.freeze(['staged', 'committed', 'rolling_back', 'failed']),
|
|
85
|
+
committed: Object.freeze(['checking', 'idle']),
|
|
86
|
+
failed: Object.freeze(['checking', 'rolling_back', 'update_available', 'idle']),
|
|
87
|
+
rolling_back: Object.freeze(['rolled_back', 'failed']),
|
|
88
|
+
rolled_back: Object.freeze(['checking', 'idle']),
|
|
89
|
+
deferred: Object.freeze(['checking', 'update_available', 'idle'])
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
function asObject(value) {
|
|
93
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function unwrap(value) {
|
|
97
|
+
const source = asObject(value);
|
|
98
|
+
return source.state && typeof source.state === 'object' && !Array.isArray(source.state)
|
|
99
|
+
? source.state
|
|
100
|
+
: source;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function normalizePhase(value) {
|
|
104
|
+
const normalized = String(value || 'idle').trim().toLowerCase().replace(/[- ]+/g, '_');
|
|
105
|
+
return PHASE_ALIASES[normalized] || normalized || 'idle';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function phaseOf(value) {
|
|
109
|
+
if (typeof value === 'string') {
|
|
110
|
+
return normalizePhase(value);
|
|
111
|
+
}
|
|
112
|
+
const source = unwrap(value);
|
|
113
|
+
return normalizePhase(source.phase || source.status || source.state || source.lifecycle || 'idle');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function normalizeBlockers(values, normalizeFn) {
|
|
117
|
+
if (typeof normalizeFn === 'function') {
|
|
118
|
+
return normalizeFn(values);
|
|
119
|
+
}
|
|
120
|
+
const result = [];
|
|
121
|
+
const seen = new Set();
|
|
122
|
+
for (const value of Array.isArray(values) ? values : [values]) {
|
|
123
|
+
const code = String(value || '').trim();
|
|
124
|
+
if (!code || seen.has(code)) continue;
|
|
125
|
+
seen.add(code);
|
|
126
|
+
result.push(code);
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function normalize(value, options = {}) {
|
|
132
|
+
const source = unwrap(value);
|
|
133
|
+
const currentVersion = String(
|
|
134
|
+
source.currentVersion || options.currentVersion || source.latestVersion || ''
|
|
135
|
+
).replace(/^v/i, '');
|
|
136
|
+
const latestVersion = String(
|
|
137
|
+
source.latestVersion || source.targetVersion || currentVersion
|
|
138
|
+
).replace(/^v/i, '');
|
|
139
|
+
const blockers = normalizeBlockers(
|
|
140
|
+
Array.isArray(source.blockers) ? source.blockers : (source.blocker ? [source.blocker] : []),
|
|
141
|
+
options.normalizeBlockers
|
|
142
|
+
);
|
|
143
|
+
return {
|
|
144
|
+
...source,
|
|
145
|
+
state: phaseOf(source),
|
|
146
|
+
managed: source.managed !== false,
|
|
147
|
+
currentVersion,
|
|
148
|
+
latestVersion,
|
|
149
|
+
etag: String(source.etag || ''),
|
|
150
|
+
lastCheckedAt: Number(source.lastCheckedAt || 0),
|
|
151
|
+
stagedAt: Number(source.stagedAt || 0),
|
|
152
|
+
postponeUntil: Number(source.postponeUntil || 0),
|
|
153
|
+
transactionId: String(source.transactionId || ''),
|
|
154
|
+
blocker: blockers[0] || '',
|
|
155
|
+
blockers,
|
|
156
|
+
code: String(source.code || ''),
|
|
157
|
+
message: String(source.message || '').slice(0, 300),
|
|
158
|
+
phaseStartedAt: Number(source.phaseStartedAt || 0),
|
|
159
|
+
deadlineAt: Number(source.deadlineAt || 0),
|
|
160
|
+
heartbeatAt: Number(source.heartbeatAt || 0)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function getPhaseTimeoutMs(value) {
|
|
165
|
+
return Number(PHASE_TIMEOUTS[phaseOf(value)] || 0);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function ensurePhaseMetadata(value, options = {}) {
|
|
169
|
+
const normalized = normalize(value, options);
|
|
170
|
+
const phase = phaseOf(normalized);
|
|
171
|
+
const timeoutMs = getPhaseTimeoutMs(phase);
|
|
172
|
+
if (!timeoutMs) {
|
|
173
|
+
return {
|
|
174
|
+
...normalized,
|
|
175
|
+
phaseStartedAt: 0,
|
|
176
|
+
deadlineAt: 0,
|
|
177
|
+
heartbeatAt: 0
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const now = Number(options.now || Date.now());
|
|
181
|
+
const phaseStartedAt = Number(normalized.phaseStartedAt || now);
|
|
182
|
+
return {
|
|
183
|
+
...normalized,
|
|
184
|
+
phaseStartedAt,
|
|
185
|
+
deadlineAt: Number(normalized.deadlineAt || (phaseStartedAt + timeoutMs)),
|
|
186
|
+
heartbeatAt: Number(normalized.heartbeatAt || now)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function transition(previous, patch, options = {}) {
|
|
191
|
+
const prior = normalize(previous, options);
|
|
192
|
+
const nextSource = buildTransitionSource(prior, patch, options);
|
|
193
|
+
const nextPhase = phaseOf(nextSource);
|
|
194
|
+
const previousPhase = phaseOf(prior);
|
|
195
|
+
if (nextPhase !== previousPhase) {
|
|
196
|
+
nextSource.phaseStartedAt = 0;
|
|
197
|
+
nextSource.deadlineAt = 0;
|
|
198
|
+
nextSource.heartbeatAt = 0;
|
|
199
|
+
}
|
|
200
|
+
const transitioned = ensurePhaseMetadata(nextSource, options);
|
|
201
|
+
if (getPhaseTimeoutMs(nextPhase)) {
|
|
202
|
+
transitioned.heartbeatAt = Number(options.now || Date.now());
|
|
203
|
+
}
|
|
204
|
+
return transitioned;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function transitionCommand(previous, patch, options = {}) {
|
|
208
|
+
const prior = normalize(previous, options);
|
|
209
|
+
const nextSource = buildTransitionSource(prior, patch, options);
|
|
210
|
+
const previousPhase = phaseOf(prior);
|
|
211
|
+
const nextPhase = phaseOf(nextSource);
|
|
212
|
+
if (!isLegalTransition(previousPhase, nextPhase)) {
|
|
213
|
+
const error = new Error(`Illegal managed update transition: ${previousPhase} -> ${nextPhase}`);
|
|
214
|
+
error.code = 'managed_update_transition_invalid';
|
|
215
|
+
error.from = previousPhase;
|
|
216
|
+
error.to = nextPhase;
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
return transition(prior, nextSource, { ...options, merge: false });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function buildTransitionSource(prior, patch, options = {}) {
|
|
223
|
+
return options.merge === false
|
|
224
|
+
? asObject(patch)
|
|
225
|
+
: { ...prior, ...asObject(patch) };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isLegalTransition(from, to) {
|
|
229
|
+
const fromPhase = phaseOf(from);
|
|
230
|
+
const toPhase = phaseOf(to);
|
|
231
|
+
if (fromPhase === toPhase) return true;
|
|
232
|
+
return (TRANSITIONS[fromPhase] || []).includes(toPhase);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function reconcile(value, transaction, options = {}) {
|
|
236
|
+
const state = normalize(value, options);
|
|
237
|
+
const native = asObject(transaction);
|
|
238
|
+
if (native.state === 'rolled_back') {
|
|
239
|
+
return {
|
|
240
|
+
action: 'reload_tabs',
|
|
241
|
+
state: transition(state, {
|
|
242
|
+
state: 'rolled_back',
|
|
243
|
+
currentVersion: native.sourceVersion || state.currentVersion,
|
|
244
|
+
transactionId: native.id || state.transactionId,
|
|
245
|
+
code: native.reasonCode || state.code || 'update_rolled_back'
|
|
246
|
+
}, options)
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
if (native.state === 'committed') {
|
|
250
|
+
const targetVersion = native.targetVersion || state.latestVersion || state.currentVersion;
|
|
251
|
+
return {
|
|
252
|
+
action: 'reload_tabs',
|
|
253
|
+
state: transition(state, {
|
|
254
|
+
state: 'committed',
|
|
255
|
+
currentVersion: targetVersion,
|
|
256
|
+
latestVersion: targetVersion,
|
|
257
|
+
transactionId: '',
|
|
258
|
+
blocker: '',
|
|
259
|
+
blockers: [],
|
|
260
|
+
code: '',
|
|
261
|
+
message: ''
|
|
262
|
+
}, options)
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
if (native.state === 'staged' && ['applying', 'awaiting_health'].includes(phaseOf(state))) {
|
|
266
|
+
return {
|
|
267
|
+
action: 'retry_install',
|
|
268
|
+
state: transition(state, {
|
|
269
|
+
state: 'staged',
|
|
270
|
+
transactionId: native.id || state.transactionId,
|
|
271
|
+
blocker: '',
|
|
272
|
+
blockers: [],
|
|
273
|
+
code: '',
|
|
274
|
+
message: ''
|
|
275
|
+
}, options)
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
if (!native.state && ['applying', 'awaiting_health', 'rolling_back'].includes(phaseOf(state))) {
|
|
279
|
+
return {
|
|
280
|
+
action: 'none',
|
|
281
|
+
state: transition(state, {
|
|
282
|
+
state: 'failed',
|
|
283
|
+
code: 'update_transaction_lost',
|
|
284
|
+
message: options.transactionLostMessage
|
|
285
|
+
|| 'The managed update transaction could not be recovered. Use the manual update command.'
|
|
286
|
+
}, options)
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return { action: 'none', state };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function progressFor(value) {
|
|
293
|
+
const source = asObject(value);
|
|
294
|
+
const raw = asObject(source.progress).percent
|
|
295
|
+
?? asObject(source.progress).value
|
|
296
|
+
?? source.progressPercent
|
|
297
|
+
?? (typeof source.progress === 'number' ? source.progress : undefined);
|
|
298
|
+
if (Number.isFinite(Number(raw))) {
|
|
299
|
+
const numeric = Number(raw);
|
|
300
|
+
return Math.max(0, Math.min(100, numeric <= 1 ? numeric * 100 : numeric));
|
|
301
|
+
}
|
|
302
|
+
return Number(PROGRESS[phaseOf(value)] || 0);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function activeStageFor(value) {
|
|
306
|
+
return ACTIVE_STAGE[phaseOf(value)] ?? -1;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function activePhases(surface = 'update_page') {
|
|
310
|
+
return [...(ACTIVE_PHASES[surface] || ACTIVE_PHASES.update_page)];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function isActive(value, surface = 'update_page') {
|
|
314
|
+
return activePhases(surface).includes(phaseOf(value));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
root.CodexOverleafManagedUpdateProjection = Object.freeze({
|
|
318
|
+
ACTIVE_PHASES,
|
|
319
|
+
PHASE_ALIASES,
|
|
320
|
+
PHASE_TIMEOUTS,
|
|
321
|
+
PHASES,
|
|
322
|
+
PROGRESS,
|
|
323
|
+
TRANSITIONS,
|
|
324
|
+
activePhases,
|
|
325
|
+
activeStageFor,
|
|
326
|
+
ensurePhaseMetadata,
|
|
327
|
+
getPhaseTimeoutMs,
|
|
328
|
+
isActive,
|
|
329
|
+
isLegalTransition,
|
|
330
|
+
normalize,
|
|
331
|
+
phaseOf,
|
|
332
|
+
progressFor,
|
|
333
|
+
reconcile,
|
|
334
|
+
transition,
|
|
335
|
+
transitionCommand
|
|
336
|
+
});
|
|
337
|
+
})(typeof window !== 'undefined' ? window : globalThis);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
(function initNativeRequestIdentity(root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === "object" && module.exports) {
|
|
4
|
+
module.exports = api;
|
|
5
|
+
}
|
|
6
|
+
if (root) {
|
|
7
|
+
root.CodexOverleafNativeRequestIdentity = api;
|
|
8
|
+
}
|
|
9
|
+
})(typeof globalThis !== "undefined" ? globalThis : this, function createNativeRequestIdentity() {
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
const MAX_REQUEST_ID_CHARS = 160;
|
|
13
|
+
|
|
14
|
+
function invalidIdentity(value) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
error: {
|
|
18
|
+
code: "native_request_id_invalid",
|
|
19
|
+
message:
|
|
20
|
+
`Native request id must be a finite number or a non-empty string no longer than ${MAX_REQUEST_ID_CHARS} characters.`,
|
|
21
|
+
details: {
|
|
22
|
+
actualType: value === null ? "null" : typeof value,
|
|
23
|
+
actualLength: typeof value === "string" ? value.length : null,
|
|
24
|
+
limit: MAX_REQUEST_ID_CHARS
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function validate(value) {
|
|
31
|
+
if (typeof value === "number") {
|
|
32
|
+
return Number.isFinite(value) ? { ok: true, id: value } : invalidIdentity(value);
|
|
33
|
+
}
|
|
34
|
+
if (typeof value !== "string" || value.length === 0 || value.length > MAX_REQUEST_ID_CHARS) {
|
|
35
|
+
return invalidIdentity(value);
|
|
36
|
+
}
|
|
37
|
+
return { ok: true, id: value };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function resolve(value, randomUUID) {
|
|
41
|
+
if (value === undefined || value === null || value === "") {
|
|
42
|
+
const generate =
|
|
43
|
+
typeof randomUUID === "function"
|
|
44
|
+
? randomUUID
|
|
45
|
+
: typeof crypto !== "undefined" && typeof crypto.randomUUID === "function"
|
|
46
|
+
? () => crypto.randomUUID()
|
|
47
|
+
: null;
|
|
48
|
+
if (!generate) {
|
|
49
|
+
return invalidIdentity(value);
|
|
50
|
+
}
|
|
51
|
+
return validate(generate());
|
|
52
|
+
}
|
|
53
|
+
return validate(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
MAX_REQUEST_ID_CHARS,
|
|
58
|
+
resolve
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -274,28 +274,9 @@
|
|
|
274
274
|
|
|
275
275
|
function hashText(text) {
|
|
276
276
|
const value = String(text ?? '');
|
|
277
|
-
const nodeCrypto = getNodeCrypto();
|
|
278
|
-
if (nodeCrypto) {
|
|
279
|
-
return nodeCrypto.createHash('sha256').update(value, 'utf8').digest('hex');
|
|
280
|
-
}
|
|
281
277
|
return sha256Hex(utf8Bytes(value));
|
|
282
278
|
}
|
|
283
279
|
|
|
284
|
-
function getNodeCrypto() {
|
|
285
|
-
if (typeof require !== 'function') {
|
|
286
|
-
return null;
|
|
287
|
-
}
|
|
288
|
-
try {
|
|
289
|
-
return require('node:crypto');
|
|
290
|
-
} catch (error) {
|
|
291
|
-
try {
|
|
292
|
-
return require('crypto');
|
|
293
|
-
} catch (fallbackError) {
|
|
294
|
-
return null;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
280
|
function normalizePath(value) {
|
|
300
281
|
return String(value || '')
|
|
301
282
|
.replace(/\s+/g, ' ')
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
(function (root, factory) {
|
|
2
|
+
var api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafPageRpcContract = api;
|
|
5
|
+
})(typeof window !== 'undefined' ? window : (typeof globalThis !== 'undefined' ? globalThis : this), function () {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
var REVISION = '2026-07-31-page-rpc-contract-v14';
|
|
9
|
+
var METHODS = freezeCatalog({
|
|
10
|
+
initializeCapability: entry('bridge.initialize', 'control', 'none', 'default', false, 'none'),
|
|
11
|
+
probe: entry('bridge.probe', 'read', 'none', 'default', false, 'safe'),
|
|
12
|
+
cancelActiveWrite: entry('write.cancel', 'control', 'none', 'default', false, 'idempotent'),
|
|
13
|
+
getProjectSnapshot: entry('snapshot.read', 'read', 'none', 'snapshot', true, 'safe'),
|
|
14
|
+
getProjectFileList: entry('snapshot.list', 'read', 'none', 'file_list', true, 'safe'),
|
|
15
|
+
invalidateProjectSnapshot: entry('snapshot.invalidate', 'cache', 'none', 'default', false, 'idempotent'),
|
|
16
|
+
createCheckpoint: entry('checkpoint.create', 'page_state', 'none', 'default', false, 'no_retry'),
|
|
17
|
+
ensureReviewing: entry('reviewing.enable', 'page_state', 'optional', 'default', true, 'idempotent'),
|
|
18
|
+
ensureEditing: entry('reviewing.disable', 'page_state', 'optional', 'default', true, 'idempotent'),
|
|
19
|
+
applyOperations: entry('document.write', 'document', 'required', 'writeback', true, 'no_retry'),
|
|
20
|
+
jumpToPosition: entry('editor.navigate', 'navigation', 'required', 'default', false, 'idempotent'),
|
|
21
|
+
rejectTrackedChanges: entry('tracked_changes.reject', 'document', 'required', 'lifecycle', true, 'no_retry'),
|
|
22
|
+
acceptTrackedChanges: entry('tracked_changes.accept', 'document', 'required', 'lifecycle', true, 'no_retry'),
|
|
23
|
+
triggerCompile: entry('compile.trigger', 'page_state', 'required', 'compile', false, 'no_retry'),
|
|
24
|
+
getCompileLog: entry('compile.log', 'read', 'required', 'compile', true, 'safe'),
|
|
25
|
+
getCompileState: entry('compile.state', 'read', 'none', 'default', false, 'safe'),
|
|
26
|
+
waitForSaveState: entry('save.wait', 'read', 'none', 'default', true, 'safe'),
|
|
27
|
+
startOtObserver: entry('ot.start', 'observer', 'none', 'default', false, 'idempotent'),
|
|
28
|
+
stopOtObserver: entry('ot.stop', 'observer', 'none', 'default', false, 'idempotent'),
|
|
29
|
+
getOtStatus: entry('ot.status', 'read', 'none', 'default', false, 'safe'),
|
|
30
|
+
drainOtEvents: entry('ot.drain', 'observer', 'none', 'default', false, 'no_retry')
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function entry(capability, mutation, projectIdentity, timeoutClass, cancellable, retryClass) {
|
|
34
|
+
return {
|
|
35
|
+
capability: capability,
|
|
36
|
+
mutation: mutation,
|
|
37
|
+
projectIdentity: projectIdentity,
|
|
38
|
+
timeoutClass: timeoutClass,
|
|
39
|
+
cancellation: cancellable ? 'content_abort' : 'none',
|
|
40
|
+
retryClass: retryClass,
|
|
41
|
+
failureClass: mutation === 'document' ? 'write' : mutation
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getMethod(name) {
|
|
46
|
+
return typeof name === 'string' && METHODS[name] ? METHODS[name] : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function listMethods() {
|
|
50
|
+
return Object.keys(METHODS);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function isCancellable(name) {
|
|
54
|
+
return getMethod(name)?.cancellation === 'content_abort';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function requiresProjectIdentity(name) {
|
|
58
|
+
return getMethod(name)?.projectIdentity === 'required';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resolveTimeoutMs(name, overrides) {
|
|
62
|
+
overrides = overrides || {};
|
|
63
|
+
var timeoutClass = getMethod(name)?.timeoutClass || 'default';
|
|
64
|
+
var defaults = {
|
|
65
|
+
default: 8000,
|
|
66
|
+
snapshot: 70000,
|
|
67
|
+
file_list: 35000,
|
|
68
|
+
compile: 75000,
|
|
69
|
+
lifecycle: 120000,
|
|
70
|
+
writeback: 45000
|
|
71
|
+
};
|
|
72
|
+
var candidate = Number(overrides[timeoutClass]);
|
|
73
|
+
return Number.isFinite(candidate) && candidate > 0 ? candidate : defaults[timeoutClass];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function resolveDispatchPolicy(name, overrides) {
|
|
77
|
+
var method = getMethod(name);
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
timeoutMs: resolveTimeoutMs(name, overrides),
|
|
80
|
+
cancellation: method ? method.cancellation : 'none',
|
|
81
|
+
retryClass: method ? method.retryClass : 'none',
|
|
82
|
+
automaticAttempts: 1
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function capabilityReport() {
|
|
87
|
+
var report = {};
|
|
88
|
+
listMethods().forEach(function (name) {
|
|
89
|
+
var method = METHODS[name];
|
|
90
|
+
report[name] = {
|
|
91
|
+
capability: method.capability,
|
|
92
|
+
mutation: method.mutation,
|
|
93
|
+
projectIdentity: method.projectIdentity,
|
|
94
|
+
retryClass: method.retryClass,
|
|
95
|
+
timeoutClass: method.timeoutClass,
|
|
96
|
+
cancellation: method.cancellation
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
return report;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function withCapabilityReport(capabilities) {
|
|
103
|
+
return Object.assign({}, capabilities || {}, { pageRpc: capabilityReport() });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function normalizeFailure(method, error) {
|
|
107
|
+
var contract = getMethod(method);
|
|
108
|
+
var message = error && error.message ? error.message : String(error || 'Page bridge request failed');
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
code: 'page_bridge_dispatch_failed',
|
|
112
|
+
error: message,
|
|
113
|
+
rpcMethod: typeof method === 'string' ? method : '',
|
|
114
|
+
failureClass: contract ? contract.failureClass : 'unknown'
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function freezeCatalog(catalog) {
|
|
119
|
+
Object.keys(catalog).forEach(function (name) { Object.freeze(catalog[name]); });
|
|
120
|
+
return Object.freeze(catalog);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return Object.freeze({
|
|
124
|
+
METHODS: METHODS,
|
|
125
|
+
REVISION: REVISION,
|
|
126
|
+
capabilityReport: capabilityReport,
|
|
127
|
+
getMethod: getMethod,
|
|
128
|
+
isCancellable: isCancellable,
|
|
129
|
+
listMethods: listMethods,
|
|
130
|
+
normalizeFailure: normalizeFailure,
|
|
131
|
+
requiresProjectIdentity: requiresProjectIdentity,
|
|
132
|
+
resolveDispatchPolicy: resolveDispatchPolicy,
|
|
133
|
+
resolveTimeoutMs: resolveTimeoutMs,
|
|
134
|
+
withCapabilityReport: withCapabilityReport
|
|
135
|
+
});
|
|
136
|
+
});
|