overleaf-codex 0.1.0-rc.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.
Potentially problematic release.
This version of overleaf-codex might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/NOTICE.md +25 -0
- package/README.md +217 -0
- package/assets/olcx-mark.svg +22 -0
- package/dist/auth/projectAuth.d.ts +19 -0
- package/dist/auth/projectAuth.js +163 -0
- package/dist/auth/projectAuth.js.map +1 -0
- package/dist/auth/redact.d.ts +3 -0
- package/dist/auth/redact.js +7 -0
- package/dist/auth/redact.js.map +1 -0
- package/dist/auth/types.d.ts +10 -0
- package/dist/auth/types.js +4 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/backend/index.d.ts +6 -0
- package/dist/backend/index.js +2 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/olcli/client.d.ts +329 -0
- package/dist/backend/olcli/client.js +1757 -0
- package/dist/backend/olcli/client.js.map +1 -0
- package/dist/backend/olcli/index.d.ts +2 -0
- package/dist/backend/olcli/index.js +2 -0
- package/dist/backend/olcli/index.js.map +1 -0
- package/dist/backend/overleafBackend.d.ts +41 -0
- package/dist/backend/overleafBackend.js +200 -0
- package/dist/backend/overleafBackend.js.map +1 -0
- package/dist/backend/types.d.ts +73 -0
- package/dist/backend/types.js +2 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/cli-behavior.d.ts +14 -0
- package/dist/cli-behavior.js +59 -0
- package/dist/cli-behavior.js.map +1 -0
- package/dist/cli.d.ts +30 -0
- package/dist/cli.js +441 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/auth.d.ts +21 -0
- package/dist/commands/auth.js +104 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/compile.d.ts +7 -0
- package/dist/commands/compile.js +73 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.js +9 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/endpoint.d.ts +23 -0
- package/dist/commands/endpoint.js +69 -0
- package/dist/commands/endpoint.js.map +1 -0
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.js +48 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/status.d.ts +4 -0
- package/dist/commands/status.js +5 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +26 -0
- package/dist/commands/sync.js +139 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/watch.d.ts +28 -0
- package/dist/commands/watch.js +124 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/compile/compileFlow.d.ts +32 -0
- package/dist/compile/compileFlow.js +290 -0
- package/dist/compile/compileFlow.js.map +1 -0
- package/dist/compile/pdfOutput.d.ts +12 -0
- package/dist/compile/pdfOutput.js +64 -0
- package/dist/compile/pdfOutput.js.map +1 -0
- package/dist/config/ignoreRules.d.ts +5 -0
- package/dist/config/ignoreRules.js +53 -0
- package/dist/config/ignoreRules.js.map +1 -0
- package/dist/config/overleafProject.d.ts +9 -0
- package/dist/config/overleafProject.js +61 -0
- package/dist/config/overleafProject.js.map +1 -0
- package/dist/config/projectConfig.d.ts +6 -0
- package/dist/config/projectConfig.js +180 -0
- package/dist/config/projectConfig.js.map +1 -0
- package/dist/config/projectRoot.d.ts +1 -0
- package/dist/config/projectRoot.js +36 -0
- package/dist/config/projectRoot.js.map +1 -0
- package/dist/config/types.d.ts +50 -0
- package/dist/config/types.js +34 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config/vscode.d.ts +10 -0
- package/dist/config/vscode.js +134 -0
- package/dist/config/vscode.js.map +1 -0
- package/dist/diagnostics/doctor.d.ts +8 -0
- package/dist/diagnostics/doctor.js +209 -0
- package/dist/diagnostics/doctor.js.map +1 -0
- package/dist/diagnostics/status.d.ts +6 -0
- package/dist/diagnostics/status.js +110 -0
- package/dist/diagnostics/status.js.map +1 -0
- package/dist/diagnostics/types.d.ts +33 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/endpoint/overleafEndpoint.d.ts +36 -0
- package/dist/endpoint/overleafEndpoint.js +105 -0
- package/dist/endpoint/overleafEndpoint.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/sync/apply.d.ts +14 -0
- package/dist/sync/apply.js +92 -0
- package/dist/sync/apply.js.map +1 -0
- package/dist/sync/conflicts.d.ts +7 -0
- package/dist/sync/conflicts.js +59 -0
- package/dist/sync/conflicts.js.map +1 -0
- package/dist/sync/ignore.d.ts +5 -0
- package/dist/sync/ignore.js +74 -0
- package/dist/sync/ignore.js.map +1 -0
- package/dist/sync/plan.d.ts +3 -0
- package/dist/sync/plan.js +197 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/snapshot.d.ts +13 -0
- package/dist/sync/snapshot.js +82 -0
- package/dist/sync/snapshot.js.map +1 -0
- package/dist/sync/state.d.ts +16 -0
- package/dist/sync/state.js +214 -0
- package/dist/sync/state.js.map +1 -0
- package/dist/sync/types.d.ts +113 -0
- package/dist/sync/types.js +4 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/testing/fakeBackend.d.ts +27 -0
- package/dist/testing/fakeBackend.js +213 -0
- package/dist/testing/fakeBackend.js.map +1 -0
- package/dist/watch/queue.d.ts +2 -0
- package/dist/watch/queue.js +91 -0
- package/dist/watch/queue.js.map +1 -0
- package/dist/watch/types.d.ts +52 -0
- package/dist/watch/types.js +2 -0
- package/dist/watch/types.js.map +1 -0
- package/dist/watch/watcher.d.ts +6 -0
- package/dist/watch/watcher.js +58 -0
- package/dist/watch/watcher.js.map +1 -0
- package/dist/watch/workflow.d.ts +30 -0
- package/dist/watch/workflow.js +62 -0
- package/dist/watch/workflow.js.map +1 -0
- package/docs/architecture.md +603 -0
- package/docs/auth.md +65 -0
- package/docs/cli-behavior.md +95 -0
- package/docs/compile.md +51 -0
- package/docs/design.md +82 -0
- package/docs/endpoint.md +84 -0
- package/docs/npm-packaging.md +148 -0
- package/docs/quickdev-queue-audit.md +193 -0
- package/docs/release-gates.md +119 -0
- package/docs/release-notes-v1.md +97 -0
- package/docs/security.md +61 -0
- package/docs/sync-state.md +305 -0
- package/docs/sync.md +50 -0
- package/docs/troubleshooting.md +124 -0
- package/docs/usage.md +184 -0
- package/examples/minimal-paper/.olcx/auth.local.example.json +7 -0
- package/examples/minimal-paper/.olcx/config.json +23 -0
- package/examples/minimal-paper/README.md +88 -0
- package/examples/minimal-paper/main.tex +23 -0
- package/package.json +66 -0
- package/src/backend/olcli/LICENSE +21 -0
- package/src/backend/olcli/README.md +26 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { redactSensitive } from "../cli-behavior.js";
|
|
4
|
+
import { createOlcxError } from "../errors.js";
|
|
5
|
+
import { normalizeSyncPath } from "./ignore.js";
|
|
6
|
+
import { CONFLICT_REPORT_PATH, CONTENT_DIGEST_ALGORITHM, SYNC_STATE_PATH, } from "./types.js";
|
|
7
|
+
export function createEmptySyncState(updatedAt) {
|
|
8
|
+
return {
|
|
9
|
+
schemaVersion: 1,
|
|
10
|
+
hashAlgorithm: CONTENT_DIGEST_ALGORITHM,
|
|
11
|
+
updatedAt,
|
|
12
|
+
files: {},
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function getSyncStatePath(projectRoot) {
|
|
16
|
+
return join(projectRoot, SYNC_STATE_PATH);
|
|
17
|
+
}
|
|
18
|
+
export function getConflictReportPath(projectRoot) {
|
|
19
|
+
return join(projectRoot, CONFLICT_REPORT_PATH);
|
|
20
|
+
}
|
|
21
|
+
export async function readSyncState(projectRoot, options = {}) {
|
|
22
|
+
try {
|
|
23
|
+
const raw = await readFile(getSyncStatePath(projectRoot), "utf8");
|
|
24
|
+
return validateSyncState(JSON.parse(raw));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (isNodeError(error, "ENOENT")) {
|
|
28
|
+
return createEmptySyncState((options.now ?? (() => new Date()))().toISOString());
|
|
29
|
+
}
|
|
30
|
+
if (error instanceof SyntaxError || error instanceof Error) {
|
|
31
|
+
throw createOlcxError({
|
|
32
|
+
code: "PROJECT_CONFIG_INVALID",
|
|
33
|
+
message: "Sync state is invalid.",
|
|
34
|
+
hint: "Remove .olcx/state/sync.json or run olcx sync after resolving the state issue.",
|
|
35
|
+
details: {
|
|
36
|
+
path: SYNC_STATE_PATH,
|
|
37
|
+
reason: error.message,
|
|
38
|
+
},
|
|
39
|
+
cause: error,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
throw createOlcxError({
|
|
43
|
+
code: "IO_ERROR",
|
|
44
|
+
message: "Unable to read sync state.",
|
|
45
|
+
hint: "Check permissions for .olcx/state/sync.json and try again.",
|
|
46
|
+
details: { path: SYNC_STATE_PATH },
|
|
47
|
+
cause: error,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function writeSyncState(projectRoot, state) {
|
|
52
|
+
const validated = validateSyncState(state);
|
|
53
|
+
const path = getSyncStatePath(projectRoot);
|
|
54
|
+
await mkdir(dirname(path), { recursive: true });
|
|
55
|
+
await writeFile(path, `${JSON.stringify(validated, null, 2)}\n`, "utf8");
|
|
56
|
+
}
|
|
57
|
+
export async function writeConflictReport(projectRoot, report) {
|
|
58
|
+
const path = getConflictReportPath(projectRoot);
|
|
59
|
+
await mkdir(dirname(path), { recursive: true });
|
|
60
|
+
await writeFile(path, `${redactSensitive(report)}\n`, "utf8");
|
|
61
|
+
}
|
|
62
|
+
export async function clearConflictReport(projectRoot) {
|
|
63
|
+
try {
|
|
64
|
+
await rm(getConflictReportPath(projectRoot));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
if (isNodeError(error, "ENOENT")) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export function buildNextSyncState(input) {
|
|
74
|
+
const files = {};
|
|
75
|
+
for (const operation of input.plan.operations) {
|
|
76
|
+
const entry = stateEntryForOperation(operation, input.appliedAt, input.uploadResults);
|
|
77
|
+
if (entry) {
|
|
78
|
+
files[entry.path] = entry;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return validateSyncState({
|
|
82
|
+
schemaVersion: 1,
|
|
83
|
+
hashAlgorithm: input.previous.hashAlgorithm,
|
|
84
|
+
updatedAt: input.appliedAt,
|
|
85
|
+
files,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function stateEntryForOperation(operation, appliedAt, uploadResults) {
|
|
89
|
+
const path = normalizeSyncPath(operation.path);
|
|
90
|
+
if (operation.type === "upload") {
|
|
91
|
+
if (!operation.local?.contentHash) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
const remote = uploadResults?.get(path) ?? operation.remote;
|
|
95
|
+
return compactEntry({
|
|
96
|
+
path,
|
|
97
|
+
contentHash: operation.local.contentHash,
|
|
98
|
+
size: operation.local.size ?? remote?.size,
|
|
99
|
+
localModifiedAt: operation.local.modifiedAt,
|
|
100
|
+
remoteModifiedAt: remote?.modifiedAt,
|
|
101
|
+
remoteId: remote?.remoteId,
|
|
102
|
+
remoteRevision: remote?.revision,
|
|
103
|
+
syncedAt: appliedAt,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (operation.type === "download") {
|
|
107
|
+
if (!operation.remote?.contentHash) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return compactEntry({
|
|
111
|
+
path,
|
|
112
|
+
contentHash: operation.remote.contentHash,
|
|
113
|
+
size: operation.remote.size,
|
|
114
|
+
localModifiedAt: appliedAt,
|
|
115
|
+
remoteModifiedAt: operation.remote.modifiedAt,
|
|
116
|
+
remoteId: operation.remote.remoteId,
|
|
117
|
+
remoteRevision: operation.remote.revision,
|
|
118
|
+
syncedAt: appliedAt,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (operation.type === "unchanged") {
|
|
122
|
+
const contentHash = operation.local?.contentHash ?? operation.remote?.contentHash ?? operation.base?.contentHash;
|
|
123
|
+
const exists = operation.local?.exists === true || operation.remote?.exists === true;
|
|
124
|
+
if (!exists || !contentHash) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
return compactEntry({
|
|
128
|
+
path,
|
|
129
|
+
contentHash,
|
|
130
|
+
size: operation.local?.size ?? operation.remote?.size ?? operation.base?.size,
|
|
131
|
+
localModifiedAt: operation.local?.modifiedAt ?? operation.base?.localModifiedAt,
|
|
132
|
+
remoteModifiedAt: operation.remote?.modifiedAt ?? operation.base?.remoteModifiedAt,
|
|
133
|
+
remoteId: operation.remote?.remoteId ?? operation.base?.remoteId,
|
|
134
|
+
remoteRevision: operation.remote?.revision ?? operation.base?.remoteRevision,
|
|
135
|
+
syncedAt: appliedAt,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
function compactEntry(entry) {
|
|
141
|
+
return Object.fromEntries(Object.entries(entry).filter(([, value]) => value !== undefined));
|
|
142
|
+
}
|
|
143
|
+
function validateSyncState(value) {
|
|
144
|
+
assertRecord(value, "sync state");
|
|
145
|
+
if (value.schemaVersion !== 1) {
|
|
146
|
+
throw new Error("schemaVersion must be 1");
|
|
147
|
+
}
|
|
148
|
+
if (value.hashAlgorithm !== CONTENT_DIGEST_ALGORITHM) {
|
|
149
|
+
throw new Error('hashAlgorithm must be "sha256"');
|
|
150
|
+
}
|
|
151
|
+
const updatedAt = requireNonEmptyString(value.updatedAt, "updatedAt");
|
|
152
|
+
const rawFiles = requireRecord(value.files, "files");
|
|
153
|
+
const files = {};
|
|
154
|
+
for (const [key, rawEntry] of Object.entries(rawFiles)) {
|
|
155
|
+
const entry = validateSyncStateEntry(rawEntry, key);
|
|
156
|
+
files[entry.path] = entry;
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
schemaVersion: 1,
|
|
160
|
+
hashAlgorithm: CONTENT_DIGEST_ALGORITHM,
|
|
161
|
+
updatedAt,
|
|
162
|
+
files,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function validateSyncStateEntry(value, key) {
|
|
166
|
+
assertRecord(value, `files.${key}`);
|
|
167
|
+
const path = normalizeSyncPath(requireNonEmptyString(value.path ?? key, `files.${key}.path`));
|
|
168
|
+
const contentHash = requireNonEmptyString(value.contentHash, `files.${key}.contentHash`);
|
|
169
|
+
const syncedAt = requireNonEmptyString(value.syncedAt, `files.${key}.syncedAt`);
|
|
170
|
+
return compactEntry({
|
|
171
|
+
path,
|
|
172
|
+
contentHash,
|
|
173
|
+
size: optionalNumber(value.size, `files.${key}.size`),
|
|
174
|
+
localModifiedAt: optionalString(value.localModifiedAt, `files.${key}.localModifiedAt`),
|
|
175
|
+
remoteModifiedAt: optionalString(value.remoteModifiedAt, `files.${key}.remoteModifiedAt`),
|
|
176
|
+
remoteId: optionalString(value.remoteId, `files.${key}.remoteId`),
|
|
177
|
+
remoteRevision: optionalString(value.remoteRevision, `files.${key}.remoteRevision`),
|
|
178
|
+
syncedAt,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function assertRecord(value, field) {
|
|
182
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
183
|
+
throw new Error(`${field} must be an object`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function requireRecord(value, field) {
|
|
187
|
+
assertRecord(value, field);
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
function requireNonEmptyString(value, field) {
|
|
191
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
192
|
+
throw new Error(`${field} must be a non-empty string`);
|
|
193
|
+
}
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
function optionalString(value, field) {
|
|
197
|
+
if (value === undefined) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
return requireNonEmptyString(value, field);
|
|
201
|
+
}
|
|
202
|
+
function optionalNumber(value, field) {
|
|
203
|
+
if (value === undefined) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
207
|
+
throw new Error(`${field} must be a non-negative number`);
|
|
208
|
+
}
|
|
209
|
+
return value;
|
|
210
|
+
}
|
|
211
|
+
function isNodeError(error, code) {
|
|
212
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/sync/state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export declare const SYNC_STATE_PATH: ".olcx/state/sync.json";
|
|
2
|
+
export declare const CONFLICT_REPORT_PATH: ".olcx/state/conflicts.json";
|
|
3
|
+
export declare const CONTENT_DIGEST_ALGORITHM: "sha256";
|
|
4
|
+
export type SyncOperationType = "upload" | "download" | "deleteLocal" | "deleteRemote" | "unchanged" | "conflict" | "ignored";
|
|
5
|
+
export type SyncConflictReason = "both-modified" | "local-modified-remote-deleted" | "remote-modified-local-deleted" | "unsafe-delete" | "unsupported";
|
|
6
|
+
export interface SyncSideSnapshot {
|
|
7
|
+
path: string;
|
|
8
|
+
exists: boolean;
|
|
9
|
+
contentHash?: string;
|
|
10
|
+
size?: number;
|
|
11
|
+
modifiedAt?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface LocalFileSnapshot extends SyncSideSnapshot {
|
|
14
|
+
ignored?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface RemoteFileSnapshot extends SyncSideSnapshot {
|
|
17
|
+
remoteId?: string;
|
|
18
|
+
revision?: string;
|
|
19
|
+
binary?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface SyncStateEntry {
|
|
22
|
+
path: string;
|
|
23
|
+
contentHash: string;
|
|
24
|
+
size?: number;
|
|
25
|
+
localModifiedAt?: string;
|
|
26
|
+
remoteModifiedAt?: string;
|
|
27
|
+
remoteId?: string;
|
|
28
|
+
remoteRevision?: string;
|
|
29
|
+
syncedAt: string;
|
|
30
|
+
}
|
|
31
|
+
export interface SyncStateFile {
|
|
32
|
+
schemaVersion: 1;
|
|
33
|
+
hashAlgorithm: typeof CONTENT_DIGEST_ALGORITHM;
|
|
34
|
+
updatedAt: string;
|
|
35
|
+
files: Record<string, SyncStateEntry>;
|
|
36
|
+
}
|
|
37
|
+
export interface SyncOperation {
|
|
38
|
+
type: SyncOperationType;
|
|
39
|
+
path: string;
|
|
40
|
+
reason: string;
|
|
41
|
+
local?: LocalFileSnapshot;
|
|
42
|
+
remote?: RemoteFileSnapshot;
|
|
43
|
+
base?: SyncStateEntry;
|
|
44
|
+
conflictReason?: SyncConflictReason;
|
|
45
|
+
}
|
|
46
|
+
export interface SyncConflict {
|
|
47
|
+
path: string;
|
|
48
|
+
reason: SyncConflictReason;
|
|
49
|
+
local?: LocalFileSnapshot;
|
|
50
|
+
remote?: RemoteFileSnapshot;
|
|
51
|
+
base?: SyncStateEntry;
|
|
52
|
+
recommendation: string;
|
|
53
|
+
}
|
|
54
|
+
export interface SyncPlanSummary {
|
|
55
|
+
upload: number;
|
|
56
|
+
download: number;
|
|
57
|
+
deleteLocal: number;
|
|
58
|
+
deleteRemote: number;
|
|
59
|
+
unchanged: number;
|
|
60
|
+
conflict: number;
|
|
61
|
+
ignored: number;
|
|
62
|
+
}
|
|
63
|
+
export interface SyncPlan {
|
|
64
|
+
projectId: string;
|
|
65
|
+
createdAt: string;
|
|
66
|
+
dryRun: boolean;
|
|
67
|
+
operations: SyncOperation[];
|
|
68
|
+
conflicts: SyncConflict[];
|
|
69
|
+
summary: SyncPlanSummary;
|
|
70
|
+
}
|
|
71
|
+
export interface SyncPlanInput {
|
|
72
|
+
projectId: string;
|
|
73
|
+
createdAt: string;
|
|
74
|
+
dryRun: boolean;
|
|
75
|
+
state: SyncStateFile;
|
|
76
|
+
localFiles: LocalFileSnapshot[];
|
|
77
|
+
remoteFiles: RemoteFileSnapshot[];
|
|
78
|
+
userIgnorePatterns?: string[];
|
|
79
|
+
allowDeletes?: boolean;
|
|
80
|
+
}
|
|
81
|
+
export interface ConflictReportFileDigest {
|
|
82
|
+
contentHash?: string;
|
|
83
|
+
size?: number;
|
|
84
|
+
modifiedAt?: string;
|
|
85
|
+
remoteId?: string;
|
|
86
|
+
revision?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface ConflictReportEntry {
|
|
89
|
+
path: string;
|
|
90
|
+
reason: SyncConflictReason;
|
|
91
|
+
local?: ConflictReportFileDigest;
|
|
92
|
+
remote?: ConflictReportFileDigest;
|
|
93
|
+
base?: {
|
|
94
|
+
contentHash: string;
|
|
95
|
+
size?: number;
|
|
96
|
+
syncedAt: string;
|
|
97
|
+
};
|
|
98
|
+
suggestedCommands: string[];
|
|
99
|
+
manualSteps: string[];
|
|
100
|
+
}
|
|
101
|
+
export interface ConflictReport {
|
|
102
|
+
schemaVersion: 1;
|
|
103
|
+
generatedAt: string;
|
|
104
|
+
reportPath: typeof CONFLICT_REPORT_PATH;
|
|
105
|
+
syncStatePath: typeof SYNC_STATE_PATH;
|
|
106
|
+
watch: {
|
|
107
|
+
paused: boolean;
|
|
108
|
+
reason: "sync-conflict";
|
|
109
|
+
resumeCommand: "olcx watch";
|
|
110
|
+
};
|
|
111
|
+
conflicts: ConflictReportEntry[];
|
|
112
|
+
manualSteps: string[];
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sync/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,uBAAgC,CAAC;AAChE,MAAM,CAAC,MAAM,oBAAoB,GAAG,4BAAqC,CAAC;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAiB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { OverleafBackend } from "../backend/types.js";
|
|
2
|
+
type FakeFailureKind = "auth" | "network" | "compile" | "pdf";
|
|
3
|
+
type FakeOperation = keyof OverleafBackend;
|
|
4
|
+
export interface FakeFileSeed {
|
|
5
|
+
path: string;
|
|
6
|
+
text?: string;
|
|
7
|
+
bytes?: Uint8Array;
|
|
8
|
+
binary?: boolean;
|
|
9
|
+
modifiedAt?: string;
|
|
10
|
+
revision?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface FakeProjectSeed {
|
|
13
|
+
projectId: string;
|
|
14
|
+
files?: FakeFileSeed[];
|
|
15
|
+
pdfBytes?: Uint8Array;
|
|
16
|
+
fastPdfBytes?: Uint8Array;
|
|
17
|
+
compileStatus?: "success" | "failure" | "timeout";
|
|
18
|
+
fastCompileStatus?: "success" | "failure" | "timeout";
|
|
19
|
+
fastRestoreFailure?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface FakeOverleafBackendOptions {
|
|
22
|
+
now?: string;
|
|
23
|
+
projects?: FakeProjectSeed[];
|
|
24
|
+
failures?: Partial<Record<FakeOperation, FakeFailureKind>>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createFakeOverleafBackend(options?: FakeOverleafBackendOptions): OverleafBackend;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { createOlcxError } from "../errors.js";
|
|
2
|
+
const DEFAULT_NOW = "2026-06-25T08:00:00.000Z";
|
|
3
|
+
const DEFAULT_PDF = Buffer.from("%PDF-1.4\n% fake olcx pdf\n", "utf8");
|
|
4
|
+
export function createFakeOverleafBackend(options = {}) {
|
|
5
|
+
return new FakeOverleafBackend(options);
|
|
6
|
+
}
|
|
7
|
+
class FakeOverleafBackend {
|
|
8
|
+
now;
|
|
9
|
+
failures;
|
|
10
|
+
projects;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.now = options.now ?? DEFAULT_NOW;
|
|
13
|
+
this.failures = options.failures ?? {};
|
|
14
|
+
this.projects = new Map((options.projects ?? []).map((project) => [project.projectId, toStoredProject(project, this.now)]));
|
|
15
|
+
}
|
|
16
|
+
async validateAuth(input) {
|
|
17
|
+
this.failIfConfigured("validateAuth");
|
|
18
|
+
this.assertAuth(input.auth);
|
|
19
|
+
return {
|
|
20
|
+
authenticated: true,
|
|
21
|
+
accountLabel: input.auth.accountLabel,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async listFiles(input) {
|
|
25
|
+
this.failIfConfigured("listFiles");
|
|
26
|
+
this.assertAuth(input.auth);
|
|
27
|
+
const project = this.getProject(input.projectId);
|
|
28
|
+
return [...project.files.values()].map((file) => toRemoteFile(file)).sort((a, b) => a.path.localeCompare(b.path));
|
|
29
|
+
}
|
|
30
|
+
async downloadFile(input) {
|
|
31
|
+
this.failIfConfigured("downloadFile");
|
|
32
|
+
this.assertAuth(input.auth);
|
|
33
|
+
const project = this.getProject(input.projectId);
|
|
34
|
+
const file = project.files.get(normalizePath(input.path));
|
|
35
|
+
if (!file) {
|
|
36
|
+
throw createOlcxError({
|
|
37
|
+
code: "BACKEND_PROTOCOL_ERROR",
|
|
38
|
+
message: `Remote file was not found: ${normalizePath(input.path)}`,
|
|
39
|
+
hint: "Run olcx sync --dry-run to refresh the remote file listing.",
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return new Uint8Array(file.bytes);
|
|
43
|
+
}
|
|
44
|
+
async uploadFile(input) {
|
|
45
|
+
this.failIfConfigured("uploadFile");
|
|
46
|
+
this.assertAuth(input.auth);
|
|
47
|
+
const project = this.getProject(input.projectId);
|
|
48
|
+
const path = normalizePath(input.path);
|
|
49
|
+
const remoteId = project.files.get(path)?.remoteId ?? `fake-remote-${project.nextRemoteId++}`;
|
|
50
|
+
const file = {
|
|
51
|
+
path,
|
|
52
|
+
bytes: new Uint8Array(input.bytes),
|
|
53
|
+
binary: isBinaryPath(path),
|
|
54
|
+
remoteId,
|
|
55
|
+
modifiedAt: this.now,
|
|
56
|
+
revision: `rev-${remoteId}`,
|
|
57
|
+
};
|
|
58
|
+
project.files.set(path, file);
|
|
59
|
+
return toRemoteFile(file);
|
|
60
|
+
}
|
|
61
|
+
async deleteFile(input) {
|
|
62
|
+
this.failIfConfigured("deleteFile");
|
|
63
|
+
this.assertAuth(input.auth);
|
|
64
|
+
const project = this.getProject(input.projectId);
|
|
65
|
+
project.files.delete(normalizePath(input.path));
|
|
66
|
+
}
|
|
67
|
+
async compile(input) {
|
|
68
|
+
this.failIfConfigured("compile");
|
|
69
|
+
this.assertAuth(input.auth);
|
|
70
|
+
const project = this.getProject(input.projectId);
|
|
71
|
+
const fastMode = input.fastMode === true;
|
|
72
|
+
const compileStatus = fastMode ? project.fastCompileStatus : project.compileStatus;
|
|
73
|
+
if (compileStatus !== "success") {
|
|
74
|
+
return {
|
|
75
|
+
status: compileStatus,
|
|
76
|
+
projectId: input.projectId,
|
|
77
|
+
logs: [{ level: "error", message: fastMode ? "Fake Overleaf fast fallback compile failed." : "Fake Overleaf compile failed." }],
|
|
78
|
+
warnings: [],
|
|
79
|
+
elapsedMs: 0,
|
|
80
|
+
fallbackUsed: fastMode,
|
|
81
|
+
error: createOlcxError({
|
|
82
|
+
code: compileStatus === "timeout" ? "COMPILE_TIMEOUT" : "COMPILE_FAILED",
|
|
83
|
+
message: fastMode ? "Fake Overleaf fast fallback compile failed." : "Fake Overleaf compile failed.",
|
|
84
|
+
hint: "Inspect the fake compile logs in the test assertion.",
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
status: fastMode ? "fallback-success" : "success",
|
|
90
|
+
projectId: input.projectId,
|
|
91
|
+
pdfBytes: new Uint8Array(fastMode ? project.fastPdfBytes : project.pdfBytes),
|
|
92
|
+
logs: [
|
|
93
|
+
{
|
|
94
|
+
level: "info",
|
|
95
|
+
message: fastMode ? "Fake Overleaf fast fallback compile succeeded." : "Fake Overleaf compile succeeded.",
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
warnings: fastMode
|
|
99
|
+
? ["Fast/draft fallback PDF: generated with fake draft mode; images may be omitted or simplified."]
|
|
100
|
+
: [],
|
|
101
|
+
elapsedMs: 0,
|
|
102
|
+
fallbackUsed: fastMode,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async beginFastCompile(input) {
|
|
106
|
+
this.assertAuth(input.auth);
|
|
107
|
+
const project = this.getProject(input.projectId);
|
|
108
|
+
return {
|
|
109
|
+
strategy: "project-settings",
|
|
110
|
+
compileOptions: { fastMode: true },
|
|
111
|
+
restore: async () => {
|
|
112
|
+
if (project.fastRestoreFailure) {
|
|
113
|
+
throw createOlcxError({
|
|
114
|
+
code: "COMPILE_FAILED",
|
|
115
|
+
message: "Fake backend failed to restore fast compile settings.",
|
|
116
|
+
hint: "Inspect the fake backend restore failure test setup.",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return { status: "restored" };
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
async downloadPdf(input) {
|
|
124
|
+
this.failIfConfigured("downloadPdf");
|
|
125
|
+
this.assertAuth(input.auth);
|
|
126
|
+
return new Uint8Array(this.getProject(input.projectId).pdfBytes);
|
|
127
|
+
}
|
|
128
|
+
failIfConfigured(operation) {
|
|
129
|
+
const failure = this.failures[operation];
|
|
130
|
+
if (!failure)
|
|
131
|
+
return;
|
|
132
|
+
throw fakeFailure(operation, failure);
|
|
133
|
+
}
|
|
134
|
+
assertAuth(auth) {
|
|
135
|
+
if (!auth.sessionCookie) {
|
|
136
|
+
throw createOlcxError({
|
|
137
|
+
code: "PROJECT_AUTH_INVALID",
|
|
138
|
+
message: "Fake backend received invalid auth.",
|
|
139
|
+
hint: "Provide a fake non-empty session cookie in the test.",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
getProject(projectId) {
|
|
144
|
+
const project = this.projects.get(projectId);
|
|
145
|
+
if (!project) {
|
|
146
|
+
throw createOlcxError({
|
|
147
|
+
code: "BACKEND_PROTOCOL_ERROR",
|
|
148
|
+
message: "Fake backend project was not found.",
|
|
149
|
+
hint: "Seed the fake backend with the project id used by the test.",
|
|
150
|
+
details: { projectId: "<redacted-project-id>" },
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return project;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function toStoredProject(seed, now) {
|
|
157
|
+
let nextRemoteId = 1;
|
|
158
|
+
const files = new Map();
|
|
159
|
+
for (const file of seed.files ?? []) {
|
|
160
|
+
const path = normalizePath(file.path);
|
|
161
|
+
const remoteId = `fake-remote-${nextRemoteId++}`;
|
|
162
|
+
const bytes = file.bytes ?? Buffer.from(file.text ?? "", "utf8");
|
|
163
|
+
files.set(path, {
|
|
164
|
+
path,
|
|
165
|
+
bytes: new Uint8Array(bytes),
|
|
166
|
+
binary: file.binary ?? isBinaryPath(path),
|
|
167
|
+
remoteId,
|
|
168
|
+
modifiedAt: file.modifiedAt ?? now,
|
|
169
|
+
revision: file.revision ?? `rev-${remoteId}`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
projectId: seed.projectId,
|
|
174
|
+
files,
|
|
175
|
+
pdfBytes: new Uint8Array(seed.pdfBytes ?? DEFAULT_PDF),
|
|
176
|
+
fastPdfBytes: new Uint8Array(seed.fastPdfBytes ?? seed.pdfBytes ?? DEFAULT_PDF),
|
|
177
|
+
compileStatus: seed.compileStatus ?? "success",
|
|
178
|
+
fastCompileStatus: seed.fastCompileStatus ?? seed.compileStatus ?? "success",
|
|
179
|
+
fastRestoreFailure: seed.fastRestoreFailure ?? false,
|
|
180
|
+
nextRemoteId,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function toRemoteFile(file) {
|
|
184
|
+
return {
|
|
185
|
+
path: file.path,
|
|
186
|
+
kind: "file",
|
|
187
|
+
remoteId: file.remoteId,
|
|
188
|
+
size: file.bytes.byteLength,
|
|
189
|
+
modifiedAt: file.modifiedAt,
|
|
190
|
+
revision: file.revision,
|
|
191
|
+
binary: file.binary,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function fakeFailure(operation, failure) {
|
|
195
|
+
const codeByFailure = {
|
|
196
|
+
auth: "BACKEND_AUTH_FAILED",
|
|
197
|
+
network: "BACKEND_NETWORK_ERROR",
|
|
198
|
+
compile: "COMPILE_FAILED",
|
|
199
|
+
pdf: "COMPILE_FAILED",
|
|
200
|
+
};
|
|
201
|
+
return createOlcxError({
|
|
202
|
+
code: codeByFailure[failure],
|
|
203
|
+
message: `Fake backend ${failure} failure during ${String(operation)}.`,
|
|
204
|
+
hint: "Adjust the fake backend failure configuration in the test.",
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function normalizePath(path) {
|
|
208
|
+
return path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
209
|
+
}
|
|
210
|
+
function isBinaryPath(path) {
|
|
211
|
+
return /\.(pdf|png|jpg|jpeg|gif|eps|svg)$/i.test(path);
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=fakeBackend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fakeBackend.js","sourceRoot":"","sources":["../../src/testing/fakeBackend.ts"],"names":[],"mappings":"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"}
|