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
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
(function initStorageDb(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory(require('./storageRunActions'), require('./runInputQueue')
|
|
3
|
+
module.exports = factory(require('./storageRunActions'), require('./runInputQueue'),
|
|
4
|
+
require('./settlementFacts'), require('./storageSessionClaims'));
|
|
4
5
|
} else {
|
|
5
|
-
root.
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
root.CodexOverleafModuleRegistry.define('StorageDb', [
|
|
7
|
+
'StorageRunActions',
|
|
8
|
+
'RunInputQueue',
|
|
9
|
+
'SettlementFacts',
|
|
10
|
+
'StorageSessionClaims'
|
|
11
|
+
], factory);
|
|
12
|
+
}
|
|
13
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function storageDbFactory(StorageRunActions, RunInputQueue, SettlementFacts, StorageSessionClaims) {
|
|
8
14
|
'use strict';
|
|
9
|
-
if (!StorageRunActions?.compactRunsForStorage || !StorageRunActions?.compactRunActionPayload || !StorageRunActions?.compactProviderSnapshot || !StorageRunActions?.compactStructuredEventValue || !StorageRunActions?.hashString || !RunInputQueue?.compactForStorage) {
|
|
15
|
+
if (!StorageRunActions?.compactRunsForStorage || !StorageRunActions?.compactRunActionPayload || !StorageRunActions?.compactProviderSnapshot || !StorageRunActions?.compactStructuredEventValue || !StorageRunActions?.hashString || !RunInputQueue?.compactForStorage || !SettlementFacts?.compactSettlementFacts || !StorageSessionClaims?.createSessionClaimer) {
|
|
10
16
|
throw new Error('Codex Overleaf storage run-action helpers are unavailable.');
|
|
11
17
|
}
|
|
12
18
|
// IndexedDB versions are monotonic; v2.0 RC profiles have already opened v3.
|
|
@@ -127,6 +133,7 @@
|
|
|
127
133
|
};
|
|
128
134
|
});
|
|
129
135
|
}
|
|
136
|
+
var claimSessionsForAccount = StorageSessionClaims.createSessionClaimer(openDb, function () { return IDBKeyRange; });
|
|
130
137
|
|
|
131
138
|
function putRecord(storeName, record) {
|
|
132
139
|
return openDb().then(function (db) {
|
|
@@ -280,7 +287,7 @@
|
|
|
280
287
|
history: compactHistoryForStorage(input.history),
|
|
281
288
|
runs: compactRunsForStorage(input.runs, options),
|
|
282
289
|
task: normalizeDisplayTextForStorage(input.task, SESSION_STORAGE_LIMITS.taskChars),
|
|
283
|
-
mode:
|
|
290
|
+
mode: normalizeCurrentMode(input.mode), providerId: typeof input.providerId === 'string' && input.providerId ? input.providerId : 'builtin',
|
|
284
291
|
model: typeof input.model === 'string' ? input.model : '',
|
|
285
292
|
reasoningEffort: typeof input.reasoningEffort === 'string' ? input.reasoningEffort : '',
|
|
286
293
|
speedTier: typeof input.speedTier === 'string' ? input.speedTier : '',
|
|
@@ -429,13 +436,17 @@
|
|
|
429
436
|
|
|
430
437
|
// --- Helpers ---
|
|
431
438
|
|
|
439
|
+
function normalizeCurrentMode(mode) {
|
|
440
|
+
return mode === 'auto' ? 'auto' : 'ask';
|
|
441
|
+
}
|
|
442
|
+
|
|
432
443
|
function extractLightweightPrefs(state, projectId) {
|
|
433
444
|
var prefs = {
|
|
434
445
|
storageSchemaVersion: TARGET_SCHEMA_VERSION, providerId: typeof state.providerId === 'string' && state.providerId ? state.providerId : 'builtin',
|
|
435
446
|
model: typeof state.model === 'string' ? state.model : '',
|
|
436
447
|
reasoningEffort: typeof state.reasoningEffort === 'string' ? state.reasoningEffort : '',
|
|
437
448
|
speedTier: typeof state.speedTier === 'string' ? state.speedTier : '',
|
|
438
|
-
mode:
|
|
449
|
+
mode: normalizeCurrentMode(state.mode),
|
|
439
450
|
locale: typeof state.locale === 'string' ? state.locale : '',
|
|
440
451
|
requireReviewing: state.requireReviewing !== false,
|
|
441
452
|
autoRecompile: state.autoRecompile !== false,
|
|
@@ -688,6 +699,12 @@
|
|
|
688
699
|
if (VALID_TRACKED_CHANGE_STATUSES[run.trackedChangeStatus] === true) {
|
|
689
700
|
compact.trackedChangeStatus = run.trackedChangeStatus;
|
|
690
701
|
}
|
|
702
|
+
var settlement = run.settlement && typeof run.settlement === 'object'
|
|
703
|
+
? run.settlement
|
|
704
|
+
: run.settlementFacts;
|
|
705
|
+
if (settlement && typeof settlement === 'object') {
|
|
706
|
+
compact.settlement = compactStructuredEventValueForStorage(SettlementFacts.compactSettlementFacts(settlement), 0);
|
|
707
|
+
}
|
|
691
708
|
return compact;
|
|
692
709
|
}
|
|
693
710
|
|
|
@@ -1301,11 +1318,9 @@
|
|
|
1301
1318
|
}
|
|
1302
1319
|
|
|
1303
1320
|
// --- Utilities ---
|
|
1304
|
-
|
|
1305
1321
|
function generateId(prefix) {
|
|
1306
1322
|
return prefix + '_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(2, 8);
|
|
1307
1323
|
}
|
|
1308
|
-
|
|
1309
1324
|
function safeJsonStringify(value) {
|
|
1310
1325
|
try {
|
|
1311
1326
|
return JSON.stringify(value) || '';
|
|
@@ -1313,7 +1328,6 @@
|
|
|
1313
1328
|
return '[unserializable]';
|
|
1314
1329
|
}
|
|
1315
1330
|
}
|
|
1316
|
-
|
|
1317
1331
|
var hashString = StorageRunActions.hashString;
|
|
1318
1332
|
|
|
1319
1333
|
return {
|
|
@@ -1325,6 +1339,7 @@
|
|
|
1325
1339
|
putRecords: putRecords,
|
|
1326
1340
|
getRecord: getRecord,
|
|
1327
1341
|
getAllByIndex: getAllByIndex,
|
|
1342
|
+
claimSessionsForAccount: claimSessionsForAccount,
|
|
1328
1343
|
deleteRecord: deleteRecord,
|
|
1329
1344
|
deleteByIndex: deleteByIndex,
|
|
1330
1345
|
clearStore: clearStore,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
(function initStorageMigration(root, factory) {
|
|
2
2
|
if (typeof module === 'object' && module.exports) {
|
|
3
|
-
module.exports = factory();
|
|
3
|
+
module.exports = factory(require('./storageDb'));
|
|
4
4
|
} else {
|
|
5
|
-
root.
|
|
5
|
+
root.CodexOverleafModuleRegistry.define('StorageMigration', ['StorageDb'], factory);
|
|
6
6
|
}
|
|
7
|
-
})(typeof globalThis !== 'undefined' ? globalThis : window, function storageMigrationFactory() {
|
|
7
|
+
})(typeof globalThis !== 'undefined' ? globalThis : window, function storageMigrationFactory(StorageDb) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
var PREFS_KEY = 'codexOverleafPrefs';
|
|
@@ -13,74 +13,249 @@
|
|
|
13
13
|
var MAX_DELETED_SESSION_IDS_PER_PROJECT = 100;
|
|
14
14
|
var CUSTOM_INSTRUCTIONS_MAX_CHARS = 12000;
|
|
15
15
|
var PROJECT_PREF_KEY_MAX_CHARS = 160;
|
|
16
|
+
var PROJECT_SCOPED_PREF_MAPS = [
|
|
17
|
+
'activeSessionByProject',
|
|
18
|
+
'experimentalOtByProject',
|
|
19
|
+
'customInstructionsByProject',
|
|
20
|
+
'governanceRulesByProject',
|
|
21
|
+
'selectedLocalSkillIdsByProject'
|
|
22
|
+
];
|
|
23
|
+
var projectPreferenceLockTails = {};
|
|
16
24
|
|
|
17
|
-
function
|
|
18
|
-
var
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
function buildScopedProjectPreferenceKey(accountScopeId, projectId) {
|
|
26
|
+
var account = compactScopePart(accountScopeId);
|
|
27
|
+
var project = compactScopePart(projectId);
|
|
28
|
+
return account && project ? 'account:' + account + ':project:' + project : '';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function compactScopePart(value) {
|
|
32
|
+
var text = normalizeTextField(value, PROJECT_PREF_KEY_MAX_CHARS);
|
|
33
|
+
if (!text) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
var encoded = encodeURIComponent(text);
|
|
37
|
+
if (encoded.length <= 64) {
|
|
38
|
+
return encoded;
|
|
39
|
+
}
|
|
40
|
+
return encoded.slice(0, 48) + '-' + hashText(encoded);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function hashText(value) {
|
|
44
|
+
var hash = 2166136261;
|
|
45
|
+
for (var i = 0; i < value.length; i++) {
|
|
46
|
+
hash ^= value.charCodeAt(i);
|
|
47
|
+
hash = Math.imul(hash, 16777619);
|
|
48
|
+
}
|
|
49
|
+
return (hash >>> 0).toString(36);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function withProjectPreferenceLock(projectId, work) {
|
|
53
|
+
var lockName = 'codex-overleaf-project-prefs:' + compactScopePart(projectId);
|
|
54
|
+
var lockManager = typeof navigator !== 'undefined' && navigator && navigator.locks;
|
|
55
|
+
if (lockManager && typeof lockManager.request === 'function') {
|
|
56
|
+
return lockManager.request(lockName, work);
|
|
57
|
+
}
|
|
58
|
+
var previous = projectPreferenceLockTails[lockName] || Promise.resolve();
|
|
59
|
+
var current = previous.then(work, work);
|
|
60
|
+
projectPreferenceLockTails[lockName] = current;
|
|
61
|
+
return current.finally(function () {
|
|
62
|
+
if (projectPreferenceLockTails[lockName] === current) {
|
|
63
|
+
delete projectPreferenceLockTails[lockName];
|
|
36
64
|
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
37
67
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
function copyPreferenceValue(value) {
|
|
69
|
+
if (!value || typeof value !== 'object') {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(JSON.stringify(value));
|
|
74
|
+
} catch (_error) {
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function claimLegacyProjectPreferences(prefs, accountScopeId, projectId) {
|
|
80
|
+
var scopedKey = buildScopedProjectPreferenceKey(accountScopeId, projectId);
|
|
81
|
+
var next = normalizePrefs(prefs);
|
|
82
|
+
var changed = false;
|
|
83
|
+
PROJECT_SCOPED_PREF_MAPS.forEach(function (mapName) {
|
|
84
|
+
var source = next[mapName] && typeof next[mapName] === 'object'
|
|
85
|
+
? Object.assign({}, next[mapName])
|
|
86
|
+
: {};
|
|
87
|
+
if (Object.prototype.hasOwnProperty.call(source, projectId)) {
|
|
88
|
+
if (!Object.prototype.hasOwnProperty.call(source, scopedKey)) {
|
|
89
|
+
source[scopedKey] = copyPreferenceValue(source[projectId]);
|
|
90
|
+
}
|
|
91
|
+
delete source[projectId];
|
|
92
|
+
changed = true;
|
|
93
|
+
}
|
|
94
|
+
next[mapName] = source;
|
|
95
|
+
});
|
|
96
|
+
return { prefs: next, changed: changed };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function buildProjectPreferenceView(prefs, accountScopeId, projectId) {
|
|
100
|
+
var source = normalizePrefs(prefs);
|
|
101
|
+
var scopedKey = buildScopedProjectPreferenceKey(accountScopeId, projectId);
|
|
102
|
+
var view = Object.assign({}, source);
|
|
103
|
+
PROJECT_SCOPED_PREF_MAPS.forEach(function (mapName) {
|
|
104
|
+
var sourceMap = source[mapName] && typeof source[mapName] === 'object'
|
|
105
|
+
? source[mapName]
|
|
106
|
+
: {};
|
|
107
|
+
var projectMap = {};
|
|
108
|
+
if (Object.prototype.hasOwnProperty.call(sourceMap, scopedKey)) {
|
|
109
|
+
projectMap[projectId] = copyPreferenceValue(sourceMap[scopedKey]);
|
|
51
110
|
}
|
|
111
|
+
view[mapName] = projectMap;
|
|
112
|
+
});
|
|
113
|
+
return normalizePrefs(view);
|
|
114
|
+
}
|
|
52
115
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
116
|
+
function mergeScopedProjectPreferences(existingPrefs, incomingPrefs, accountScopeId, projectId) {
|
|
117
|
+
var existing = normalizePrefs(existingPrefs);
|
|
118
|
+
var incoming = normalizePrefs(incomingPrefs);
|
|
119
|
+
var scopedKey = buildScopedProjectPreferenceKey(accountScopeId, projectId);
|
|
120
|
+
var next = Object.assign({}, existing, incoming);
|
|
121
|
+
PROJECT_SCOPED_PREF_MAPS.forEach(function (mapName) {
|
|
122
|
+
var storedMap = existing[mapName] && typeof existing[mapName] === 'object'
|
|
123
|
+
? Object.assign({}, existing[mapName])
|
|
124
|
+
: {};
|
|
125
|
+
var incomingMap = incoming[mapName] && typeof incoming[mapName] === 'object'
|
|
126
|
+
? incoming[mapName]
|
|
127
|
+
: {};
|
|
128
|
+
if (Object.prototype.hasOwnProperty.call(incomingMap, projectId)) {
|
|
129
|
+
storedMap[scopedKey] = copyPreferenceValue(incomingMap[projectId]);
|
|
130
|
+
}
|
|
131
|
+
delete storedMap[projectId];
|
|
132
|
+
next[mapName] = storedMap;
|
|
133
|
+
});
|
|
134
|
+
return normalizePrefs(next);
|
|
135
|
+
}
|
|
56
136
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
137
|
+
function runMigrationIfNeeded(projectId, legacyStorageKey, accountScopeId) {
|
|
138
|
+
projectId = normalizeProjectPrefKey(projectId);
|
|
139
|
+
var normalizedAccountScopeId = normalizeTextField(accountScopeId, PROJECT_PREF_KEY_MAX_CHARS);
|
|
140
|
+
if (!normalizedAccountScopeId || !projectId) {
|
|
141
|
+
return Promise.resolve({
|
|
142
|
+
prefs: normalizePrefs({}),
|
|
143
|
+
sessions: [],
|
|
144
|
+
activeSessionId: '',
|
|
145
|
+
migrated: false,
|
|
146
|
+
reason: 'account_scope_unavailable'
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return withProjectPreferenceLock(projectId, function () {
|
|
150
|
+
return chrome.storage.local.get(null).then(function (stored) {
|
|
151
|
+
var claimed = claimLegacyProjectPreferences(
|
|
152
|
+
stored[PREFS_KEY] || {},
|
|
153
|
+
normalizedAccountScopeId,
|
|
154
|
+
projectId
|
|
63
155
|
);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
156
|
+
var storedPrefs = claimed.prefs;
|
|
157
|
+
var persistClaim = claimed.changed
|
|
158
|
+
? chrome.storage.local.set({ [PREFS_KEY]: storedPrefs })
|
|
159
|
+
: Promise.resolve();
|
|
160
|
+
return persistClaim.then(function () {
|
|
161
|
+
var prefs = buildProjectPreferenceView(
|
|
162
|
+
storedPrefs,
|
|
163
|
+
normalizedAccountScopeId,
|
|
164
|
+
projectId
|
|
165
|
+
);
|
|
166
|
+
var tombstones = collectSessionTombstones(stored);
|
|
167
|
+
var deletedSessionIds = getDeletedSessionIds(tombstones, projectId);
|
|
168
|
+
var schemaVersion = prefs.storageSchemaVersion || 0;
|
|
169
|
+
|
|
170
|
+
if (schemaVersion >= StorageDb.TARGET_SCHEMA_VERSION) {
|
|
171
|
+
var activeSessionByProject = prefs.activeSessionByProject || {};
|
|
172
|
+
var activeSessionId = activeSessionByProject[projectId] || '';
|
|
173
|
+
if (typeof StorageDb.claimSessionsForAccount !== 'function') {
|
|
174
|
+
return Promise.reject(Object.assign(
|
|
175
|
+
new Error('Atomic legacy-session claiming is unavailable.'),
|
|
176
|
+
{ code: 'scoped_claim_unavailable' }
|
|
177
|
+
));
|
|
178
|
+
}
|
|
179
|
+
return StorageDb.claimSessionsForAccount(
|
|
180
|
+
projectId,
|
|
181
|
+
normalizedAccountScopeId,
|
|
182
|
+
deletedSessionIds
|
|
183
|
+
).then(function (visibleSessions) {
|
|
184
|
+
var visibleActiveSessionId = visibleSessions.some(function (session) {
|
|
185
|
+
return session && session.id === activeSessionId;
|
|
186
|
+
})
|
|
187
|
+
? activeSessionId
|
|
188
|
+
: visibleSessions.length
|
|
189
|
+
? visibleSessions[visibleSessions.length - 1].id
|
|
190
|
+
: '';
|
|
191
|
+
return {
|
|
192
|
+
prefs: prefs,
|
|
193
|
+
sessions: visibleSessions,
|
|
194
|
+
activeSessionId: visibleActiveSessionId,
|
|
195
|
+
migrated: false
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Migration v0 → v1
|
|
201
|
+
var legacyBlob = stored[legacyStorageKey] || {};
|
|
202
|
+
var legacySessions = Array.isArray(legacyBlob.sessions) ? legacyBlob.sessions : [];
|
|
203
|
+
var migratedSessions = [];
|
|
204
|
+
|
|
205
|
+
for (var i = 0; i < legacySessions.length; i++) {
|
|
206
|
+
var legacy = legacySessions[i];
|
|
207
|
+
if (!legacy || !legacy.id) { continue; }
|
|
208
|
+
if (deletedSessionIds.indexOf(legacy.id) !== -1) { continue; }
|
|
209
|
+
var record = StorageDb.buildSessionRecord(
|
|
210
|
+
buildLegacySessionRecordInput(projectId, legacyBlob, legacy, normalizedAccountScopeId)
|
|
211
|
+
);
|
|
212
|
+
migratedSessions.push(record);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
var putPromise = migratedSessions.length
|
|
216
|
+
? StorageDb.putRecords('sessions', migratedSessions)
|
|
217
|
+
: Promise.resolve([]);
|
|
218
|
+
|
|
219
|
+
return putPromise.then(function () {
|
|
220
|
+
var newPrefs = StorageDb.extractLightweightPrefs(legacyBlob, projectId);
|
|
221
|
+
newPrefs.activeSessionByProject = StorageDb.buildActiveSessionByProject(
|
|
222
|
+
{},
|
|
223
|
+
projectId,
|
|
224
|
+
legacyBlob.activeSessionId || (migratedSessions.length ? migratedSessions[migratedSessions.length - 1].id : '')
|
|
225
|
+
);
|
|
226
|
+
var mergedPrefs = mergeScopedProjectPreferences(
|
|
227
|
+
storedPrefs,
|
|
228
|
+
newPrefs,
|
|
229
|
+
normalizedAccountScopeId,
|
|
230
|
+
projectId
|
|
231
|
+
);
|
|
232
|
+
var prefsView = buildProjectPreferenceView(
|
|
233
|
+
mergedPrefs,
|
|
234
|
+
normalizedAccountScopeId,
|
|
235
|
+
projectId
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
return chrome.storage.local.set({ [PREFS_KEY]: mergedPrefs }).then(function () {
|
|
239
|
+
return chrome.storage.local.remove(legacyStorageKey).catch(function () {});
|
|
240
|
+
}).then(function () {
|
|
241
|
+
return {
|
|
242
|
+
prefs: prefsView,
|
|
243
|
+
sessions: migratedSessions,
|
|
244
|
+
activeSessionId: prefsView.activeSessionByProject[projectId] || '',
|
|
245
|
+
migrated: true
|
|
246
|
+
};
|
|
247
|
+
});
|
|
248
|
+
});
|
|
75
249
|
});
|
|
76
250
|
});
|
|
77
251
|
});
|
|
78
252
|
}
|
|
79
253
|
|
|
80
|
-
function buildLegacySessionRecordInput(projectId, legacyBlob, legacy) {
|
|
254
|
+
function buildLegacySessionRecordInput(projectId, legacyBlob, legacy, accountScopeId) {
|
|
81
255
|
return {
|
|
82
256
|
id: legacy.id,
|
|
83
257
|
projectId: projectId,
|
|
258
|
+
accountScopeId: accountScopeId,
|
|
84
259
|
title: legacy.title || '',
|
|
85
260
|
titleSource: legacy.titleSource === 'manual' ? 'manual' : 'auto',
|
|
86
261
|
codexThreadId: '',
|
|
@@ -100,13 +275,51 @@
|
|
|
100
275
|
};
|
|
101
276
|
}
|
|
102
277
|
|
|
103
|
-
function savePrefs(prefs) {
|
|
104
|
-
|
|
278
|
+
function savePrefs(prefs, accountScopeId, projectId) {
|
|
279
|
+
var account = normalizeTextField(accountScopeId, PROJECT_PREF_KEY_MAX_CHARS);
|
|
280
|
+
var project = normalizeProjectPrefKey(projectId);
|
|
281
|
+
if (!account && !project) {
|
|
282
|
+
return chrome.storage.local.set({ [PREFS_KEY]: normalizePrefs(prefs) });
|
|
283
|
+
}
|
|
284
|
+
if (!account || !project) {
|
|
285
|
+
return Promise.reject(Object.assign(
|
|
286
|
+
new Error('Scoped project preferences require account and project identity.'),
|
|
287
|
+
{ code: 'account_scope_unavailable' }
|
|
288
|
+
));
|
|
289
|
+
}
|
|
290
|
+
return withProjectPreferenceLock(project, function () {
|
|
291
|
+
return chrome.storage.local.get([PREFS_KEY]).then(function (stored) {
|
|
292
|
+
var claimed = claimLegacyProjectPreferences(stored[PREFS_KEY] || {}, account, project);
|
|
293
|
+
var next = mergeScopedProjectPreferences(claimed.prefs, prefs, account, project);
|
|
294
|
+
return chrome.storage.local.set({ [PREFS_KEY]: next });
|
|
295
|
+
});
|
|
296
|
+
});
|
|
105
297
|
}
|
|
106
298
|
|
|
107
|
-
function loadPrefs() {
|
|
108
|
-
|
|
109
|
-
|
|
299
|
+
function loadPrefs(accountScopeId, projectId) {
|
|
300
|
+
var account = normalizeTextField(accountScopeId, PROJECT_PREF_KEY_MAX_CHARS);
|
|
301
|
+
var project = normalizeProjectPrefKey(projectId);
|
|
302
|
+
if (!account && !project) {
|
|
303
|
+
return chrome.storage.local.get([PREFS_KEY]).then(function (stored) {
|
|
304
|
+
return normalizePrefs(stored[PREFS_KEY] || {});
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
if (!account || !project) {
|
|
308
|
+
return Promise.reject(Object.assign(
|
|
309
|
+
new Error('Scoped project preferences require account and project identity.'),
|
|
310
|
+
{ code: 'account_scope_unavailable' }
|
|
311
|
+
));
|
|
312
|
+
}
|
|
313
|
+
return withProjectPreferenceLock(project, function () {
|
|
314
|
+
return chrome.storage.local.get([PREFS_KEY]).then(function (stored) {
|
|
315
|
+
var claimed = claimLegacyProjectPreferences(stored[PREFS_KEY] || {}, account, project);
|
|
316
|
+
var persisted = claimed.changed
|
|
317
|
+
? chrome.storage.local.set({ [PREFS_KEY]: claimed.prefs })
|
|
318
|
+
: Promise.resolve();
|
|
319
|
+
return persisted.then(function () {
|
|
320
|
+
return buildProjectPreferenceView(claimed.prefs, account, project);
|
|
321
|
+
});
|
|
322
|
+
});
|
|
110
323
|
});
|
|
111
324
|
}
|
|
112
325
|
|
|
@@ -278,6 +491,7 @@
|
|
|
278
491
|
return {
|
|
279
492
|
PREFS_KEY: PREFS_KEY,
|
|
280
493
|
SESSION_TOMBSTONES_KEY: SESSION_TOMBSTONES_KEY,
|
|
494
|
+
buildScopedProjectPreferenceKey: buildScopedProjectPreferenceKey,
|
|
281
495
|
runMigrationIfNeeded: runMigrationIfNeeded,
|
|
282
496
|
savePrefs: savePrefs,
|
|
283
497
|
loadPrefs: loadPrefs,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
(function initStorageSessionClaims(root, factory) {
|
|
2
|
+
var api = factory();
|
|
3
|
+
if (typeof module === 'object' && module.exports) module.exports = api;
|
|
4
|
+
if (root) root.CodexOverleafStorageSessionClaims = api;
|
|
5
|
+
})(typeof globalThis !== 'undefined' ? globalThis : this, function storageSessionClaimsFactory() {
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function createSessionClaimer(openDb, getKeyRange) {
|
|
9
|
+
return function claimSessionsForAccount(projectId, accountScopeId, deletedSessionIds) {
|
|
10
|
+
var normalizedProjectId = typeof projectId === 'string' ? projectId.trim() : '';
|
|
11
|
+
var normalizedAccountScopeId = typeof accountScopeId === 'string' ? accountScopeId.trim() : '';
|
|
12
|
+
if (!normalizedProjectId || !normalizedAccountScopeId) {
|
|
13
|
+
return Promise.reject(Object.assign(
|
|
14
|
+
new Error('A project and account scope are required to claim legacy sessions.'),
|
|
15
|
+
{ code: !normalizedAccountScopeId ? 'account_scope_unavailable' : 'project_scope_unavailable' }
|
|
16
|
+
));
|
|
17
|
+
}
|
|
18
|
+
var deleted = {};
|
|
19
|
+
(Array.isArray(deletedSessionIds) ? deletedSessionIds : []).forEach(function (id) {
|
|
20
|
+
if (typeof id === 'string' && id) deleted[id] = true;
|
|
21
|
+
});
|
|
22
|
+
return openDb().then(function (db) {
|
|
23
|
+
return new Promise(function (resolve, reject) {
|
|
24
|
+
var visible = [];
|
|
25
|
+
var tx = db.transaction('sessions', 'readwrite');
|
|
26
|
+
var store = tx.objectStore('sessions');
|
|
27
|
+
var index = store.index('projectId');
|
|
28
|
+
var request = index.openCursor(getKeyRange().only(normalizedProjectId));
|
|
29
|
+
request.onsuccess = function (event) {
|
|
30
|
+
var cursor = event.target.result;
|
|
31
|
+
if (!cursor) return;
|
|
32
|
+
var record = cursor.value;
|
|
33
|
+
if (record && !deleted[record.id]) {
|
|
34
|
+
var recordScopeId = typeof record.accountScopeId === 'string'
|
|
35
|
+
? record.accountScopeId.trim()
|
|
36
|
+
: '';
|
|
37
|
+
if (recordScopeId === normalizedAccountScopeId) {
|
|
38
|
+
visible.push(record);
|
|
39
|
+
} else if (!recordScopeId) {
|
|
40
|
+
var claimed = Object.assign({}, record, {
|
|
41
|
+
accountScopeId: normalizedAccountScopeId,
|
|
42
|
+
accountScopeUnavailable: false
|
|
43
|
+
});
|
|
44
|
+
cursor.update(claimed);
|
|
45
|
+
visible.push(claimed);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
cursor.continue();
|
|
49
|
+
};
|
|
50
|
+
request.onerror = function (event) { reject(event.target.error); };
|
|
51
|
+
tx.oncomplete = function () { resolve(visible); };
|
|
52
|
+
tx.onerror = function (event) { reject(event.target.error || tx.error); };
|
|
53
|
+
tx.onabort = function (event) { reject(event.target.error || tx.error); };
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return Object.freeze({ createSessionClaimer: createSessionClaimer });
|
|
60
|
+
});
|
|
@@ -87,6 +87,10 @@
|
|
|
87
87
|
authorizedVersion: safeVersion(value.authorizedVersion),
|
|
88
88
|
authorizationId: safeId(value.authorizationId),
|
|
89
89
|
authorizedAt: finiteNumber(value.authorizedAt),
|
|
90
|
+
revokingAuthorizationId: safeId(value.revokingAuthorizationId),
|
|
91
|
+
revokingVersion: safeVersion(value.revokingVersion),
|
|
92
|
+
revokingTransactionId: safeId(value.revokingTransactionId),
|
|
93
|
+
revokingAt: finiteNumber(value.revokingAt),
|
|
90
94
|
lastPromptedVersion: safeVersion(value.lastPromptedVersion),
|
|
91
95
|
lastPromptedAt: finiteNumber(value.lastPromptedAt)
|
|
92
96
|
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
(function initUpdateRevocationIntent(root, factory) {
|
|
2
|
+
const api = factory();
|
|
3
|
+
if (typeof module === "object" && module.exports) {
|
|
4
|
+
module.exports = api;
|
|
5
|
+
}
|
|
6
|
+
if (root) {
|
|
7
|
+
root.CodexOverleafUpdateRevocation = api;
|
|
8
|
+
}
|
|
9
|
+
})(typeof globalThis !== "undefined" ? globalThis : this, function createUpdateRevocationIntent() {
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
function safeString(value) {
|
|
13
|
+
return typeof value === "string" ? value.trim() : "";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function safeTime(value, fallback = 0) {
|
|
17
|
+
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function begin(consentState, updateState, now = Date.now()) {
|
|
21
|
+
const consent = consentState && typeof consentState === "object" ? consentState : {};
|
|
22
|
+
const update = updateState && typeof updateState === "object" ? updateState : {};
|
|
23
|
+
return {
|
|
24
|
+
...consent,
|
|
25
|
+
revokingAuthorizationId: safeString(consent.authorizationId),
|
|
26
|
+
revokingVersion:
|
|
27
|
+
safeString(consent.authorizedVersion) || safeString(update.latestVersion),
|
|
28
|
+
revokingTransactionId: safeString(update.transactionId),
|
|
29
|
+
revokingAt: safeTime(now)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function prepareAuthorization(consentState, authorizationId, targetVersion, now = Date.now()) {
|
|
34
|
+
const consent = consentState && typeof consentState === "object" ? consentState : {};
|
|
35
|
+
return {
|
|
36
|
+
...consent,
|
|
37
|
+
revokingAuthorizationId: safeString(authorizationId),
|
|
38
|
+
revokingVersion: safeString(targetVersion),
|
|
39
|
+
revokingTransactionId: "",
|
|
40
|
+
revokingAt: safeTime(now)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function hasPending(consentState) {
|
|
45
|
+
const consent = consentState && typeof consentState === "object" ? consentState : {};
|
|
46
|
+
return Boolean(
|
|
47
|
+
safeString(consent.revokingAuthorizationId) &&
|
|
48
|
+
safeString(consent.revokingVersion)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function clear(consentState) {
|
|
53
|
+
const consent = consentState && typeof consentState === "object" ? consentState : {};
|
|
54
|
+
return {
|
|
55
|
+
...consent,
|
|
56
|
+
revokingAuthorizationId: "",
|
|
57
|
+
revokingVersion: "",
|
|
58
|
+
revokingTransactionId: "",
|
|
59
|
+
revokingAt: 0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function complete(updateState, consentState, options = {}) {
|
|
64
|
+
const update = updateState && typeof updateState === "object" ? updateState : {};
|
|
65
|
+
const consent = consentState && typeof consentState === "object" ? consentState : {};
|
|
66
|
+
const now = safeTime(options.now, Date.now());
|
|
67
|
+
const snoozeMs = safeTime(options.snoozeMs);
|
|
68
|
+
const version =
|
|
69
|
+
safeString(consent.revokingVersion) ||
|
|
70
|
+
safeString(consent.authorizedVersion) ||
|
|
71
|
+
safeString(update.latestVersion);
|
|
72
|
+
return {
|
|
73
|
+
updateState: {
|
|
74
|
+
...update,
|
|
75
|
+
state: "update_available",
|
|
76
|
+
transactionId: "",
|
|
77
|
+
stagedPath: "",
|
|
78
|
+
stagedAt: 0,
|
|
79
|
+
applyingAt: 0,
|
|
80
|
+
awaitingHealthAt: 0,
|
|
81
|
+
blocker: "",
|
|
82
|
+
blockers: [],
|
|
83
|
+
blockingReason: "",
|
|
84
|
+
code: "",
|
|
85
|
+
message: "",
|
|
86
|
+
error: null,
|
|
87
|
+
postponeUntil: safeTime(options.postponeUntil),
|
|
88
|
+
postponeGuardVersion: version
|
|
89
|
+
},
|
|
90
|
+
consentState: clear({
|
|
91
|
+
...consent,
|
|
92
|
+
mode: "snoozed",
|
|
93
|
+
snoozedVersion: version,
|
|
94
|
+
snoozedUntil: now + snoozeMs,
|
|
95
|
+
authorizedVersion: "",
|
|
96
|
+
authorizationId: "",
|
|
97
|
+
authorizedAt: 0
|
|
98
|
+
})
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return Object.freeze({
|
|
103
|
+
begin,
|
|
104
|
+
prepareAuthorization,
|
|
105
|
+
hasPending,
|
|
106
|
+
clear,
|
|
107
|
+
complete
|
|
108
|
+
});
|
|
109
|
+
});
|