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.

Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +25 -0
  3. package/README.md +217 -0
  4. package/assets/olcx-mark.svg +22 -0
  5. package/dist/auth/projectAuth.d.ts +19 -0
  6. package/dist/auth/projectAuth.js +163 -0
  7. package/dist/auth/projectAuth.js.map +1 -0
  8. package/dist/auth/redact.d.ts +3 -0
  9. package/dist/auth/redact.js +7 -0
  10. package/dist/auth/redact.js.map +1 -0
  11. package/dist/auth/types.d.ts +10 -0
  12. package/dist/auth/types.js +4 -0
  13. package/dist/auth/types.js.map +1 -0
  14. package/dist/backend/index.d.ts +6 -0
  15. package/dist/backend/index.js +2 -0
  16. package/dist/backend/index.js.map +1 -0
  17. package/dist/backend/olcli/client.d.ts +329 -0
  18. package/dist/backend/olcli/client.js +1757 -0
  19. package/dist/backend/olcli/client.js.map +1 -0
  20. package/dist/backend/olcli/index.d.ts +2 -0
  21. package/dist/backend/olcli/index.js +2 -0
  22. package/dist/backend/olcli/index.js.map +1 -0
  23. package/dist/backend/overleafBackend.d.ts +41 -0
  24. package/dist/backend/overleafBackend.js +200 -0
  25. package/dist/backend/overleafBackend.js.map +1 -0
  26. package/dist/backend/types.d.ts +73 -0
  27. package/dist/backend/types.js +2 -0
  28. package/dist/backend/types.js.map +1 -0
  29. package/dist/cli-behavior.d.ts +14 -0
  30. package/dist/cli-behavior.js +59 -0
  31. package/dist/cli-behavior.js.map +1 -0
  32. package/dist/cli.d.ts +30 -0
  33. package/dist/cli.js +441 -0
  34. package/dist/cli.js.map +1 -0
  35. package/dist/commands/auth.d.ts +21 -0
  36. package/dist/commands/auth.js +104 -0
  37. package/dist/commands/auth.js.map +1 -0
  38. package/dist/commands/compile.d.ts +7 -0
  39. package/dist/commands/compile.js +73 -0
  40. package/dist/commands/compile.js.map +1 -0
  41. package/dist/commands/doctor.d.ts +11 -0
  42. package/dist/commands/doctor.js +9 -0
  43. package/dist/commands/doctor.js.map +1 -0
  44. package/dist/commands/endpoint.d.ts +23 -0
  45. package/dist/commands/endpoint.js +69 -0
  46. package/dist/commands/endpoint.js.map +1 -0
  47. package/dist/commands/init.d.ts +14 -0
  48. package/dist/commands/init.js +48 -0
  49. package/dist/commands/init.js.map +1 -0
  50. package/dist/commands/status.d.ts +4 -0
  51. package/dist/commands/status.js +5 -0
  52. package/dist/commands/status.js.map +1 -0
  53. package/dist/commands/sync.d.ts +26 -0
  54. package/dist/commands/sync.js +139 -0
  55. package/dist/commands/sync.js.map +1 -0
  56. package/dist/commands/watch.d.ts +28 -0
  57. package/dist/commands/watch.js +124 -0
  58. package/dist/commands/watch.js.map +1 -0
  59. package/dist/compile/compileFlow.d.ts +32 -0
  60. package/dist/compile/compileFlow.js +290 -0
  61. package/dist/compile/compileFlow.js.map +1 -0
  62. package/dist/compile/pdfOutput.d.ts +12 -0
  63. package/dist/compile/pdfOutput.js +64 -0
  64. package/dist/compile/pdfOutput.js.map +1 -0
  65. package/dist/config/ignoreRules.d.ts +5 -0
  66. package/dist/config/ignoreRules.js +53 -0
  67. package/dist/config/ignoreRules.js.map +1 -0
  68. package/dist/config/overleafProject.d.ts +9 -0
  69. package/dist/config/overleafProject.js +61 -0
  70. package/dist/config/overleafProject.js.map +1 -0
  71. package/dist/config/projectConfig.d.ts +6 -0
  72. package/dist/config/projectConfig.js +180 -0
  73. package/dist/config/projectConfig.js.map +1 -0
  74. package/dist/config/projectRoot.d.ts +1 -0
  75. package/dist/config/projectRoot.js +36 -0
  76. package/dist/config/projectRoot.js.map +1 -0
  77. package/dist/config/types.d.ts +50 -0
  78. package/dist/config/types.js +34 -0
  79. package/dist/config/types.js.map +1 -0
  80. package/dist/config/vscode.d.ts +10 -0
  81. package/dist/config/vscode.js +134 -0
  82. package/dist/config/vscode.js.map +1 -0
  83. package/dist/diagnostics/doctor.d.ts +8 -0
  84. package/dist/diagnostics/doctor.js +209 -0
  85. package/dist/diagnostics/doctor.js.map +1 -0
  86. package/dist/diagnostics/status.d.ts +6 -0
  87. package/dist/diagnostics/status.js +110 -0
  88. package/dist/diagnostics/status.js.map +1 -0
  89. package/dist/diagnostics/types.d.ts +33 -0
  90. package/dist/diagnostics/types.js +2 -0
  91. package/dist/diagnostics/types.js.map +1 -0
  92. package/dist/endpoint/overleafEndpoint.d.ts +36 -0
  93. package/dist/endpoint/overleafEndpoint.js +105 -0
  94. package/dist/endpoint/overleafEndpoint.js.map +1 -0
  95. package/dist/errors.d.ts +32 -0
  96. package/dist/errors.js +53 -0
  97. package/dist/errors.js.map +1 -0
  98. package/dist/sync/apply.d.ts +14 -0
  99. package/dist/sync/apply.js +92 -0
  100. package/dist/sync/apply.js.map +1 -0
  101. package/dist/sync/conflicts.d.ts +7 -0
  102. package/dist/sync/conflicts.js +59 -0
  103. package/dist/sync/conflicts.js.map +1 -0
  104. package/dist/sync/ignore.d.ts +5 -0
  105. package/dist/sync/ignore.js +74 -0
  106. package/dist/sync/ignore.js.map +1 -0
  107. package/dist/sync/plan.d.ts +3 -0
  108. package/dist/sync/plan.js +197 -0
  109. package/dist/sync/plan.js.map +1 -0
  110. package/dist/sync/snapshot.d.ts +13 -0
  111. package/dist/sync/snapshot.js +82 -0
  112. package/dist/sync/snapshot.js.map +1 -0
  113. package/dist/sync/state.d.ts +16 -0
  114. package/dist/sync/state.js +214 -0
  115. package/dist/sync/state.js.map +1 -0
  116. package/dist/sync/types.d.ts +113 -0
  117. package/dist/sync/types.js +4 -0
  118. package/dist/sync/types.js.map +1 -0
  119. package/dist/testing/fakeBackend.d.ts +27 -0
  120. package/dist/testing/fakeBackend.js +213 -0
  121. package/dist/testing/fakeBackend.js.map +1 -0
  122. package/dist/watch/queue.d.ts +2 -0
  123. package/dist/watch/queue.js +91 -0
  124. package/dist/watch/queue.js.map +1 -0
  125. package/dist/watch/types.d.ts +52 -0
  126. package/dist/watch/types.js +2 -0
  127. package/dist/watch/types.js.map +1 -0
  128. package/dist/watch/watcher.d.ts +6 -0
  129. package/dist/watch/watcher.js +58 -0
  130. package/dist/watch/watcher.js.map +1 -0
  131. package/dist/watch/workflow.d.ts +30 -0
  132. package/dist/watch/workflow.js +62 -0
  133. package/dist/watch/workflow.js.map +1 -0
  134. package/docs/architecture.md +603 -0
  135. package/docs/auth.md +65 -0
  136. package/docs/cli-behavior.md +95 -0
  137. package/docs/compile.md +51 -0
  138. package/docs/design.md +82 -0
  139. package/docs/endpoint.md +84 -0
  140. package/docs/npm-packaging.md +148 -0
  141. package/docs/quickdev-queue-audit.md +193 -0
  142. package/docs/release-gates.md +119 -0
  143. package/docs/release-notes-v1.md +97 -0
  144. package/docs/security.md +61 -0
  145. package/docs/sync-state.md +305 -0
  146. package/docs/sync.md +50 -0
  147. package/docs/troubleshooting.md +124 -0
  148. package/docs/usage.md +184 -0
  149. package/examples/minimal-paper/.olcx/auth.local.example.json +7 -0
  150. package/examples/minimal-paper/.olcx/config.json +23 -0
  151. package/examples/minimal-paper/README.md +88 -0
  152. package/examples/minimal-paper/main.tex +23 -0
  153. package/package.json +66 -0
  154. package/src/backend/olcli/LICENSE +21 -0
  155. package/src/backend/olcli/README.md +26 -0
@@ -0,0 +1,209 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { createOlcliOverleafBackend } from "../backend/index.js";
4
+ import { redactForStatus } from "../auth/redact.js";
5
+ import { EXIT_CODES } from "../errors.js";
6
+ import { collectProjectStatus } from "./status.js";
7
+ const REQUIRED_SECRET_IGNORE_ENTRIES = [
8
+ ".olcx/auth.local.json",
9
+ ".olcx/*.local.json",
10
+ ".olcx/*.secret.json",
11
+ ];
12
+ const INIT_NEXT = "olcx init --project <overleaf-project-url-or-id>";
13
+ const AUTH_NEXT = "olcx auth --from-env OLCX_OVERLEAF_SESSION";
14
+ const GITIGNORE_NEXT = "add .olcx/auth.local.json, .olcx/*.local.json, and .olcx/*.secret.json to .gitignore";
15
+ const RUNTIME_NEXT = "npm run typecheck";
16
+ export async function runDoctorDiagnostics(options) {
17
+ const status = await collectProjectStatus({ cwd: options.cwd });
18
+ const checks = [
19
+ createNodeCheck(options.nodeVersion ?? process.versions.node),
20
+ {
21
+ level: "pass",
22
+ name: "Project root",
23
+ message: status.projectRoot,
24
+ },
25
+ createConfigCheck(status.config),
26
+ createEndpointCheck(status.config),
27
+ createAuthCheck(status.auth),
28
+ createBackendCheck(options.backendAvailable ?? typeof createOlcliOverleafBackend === "function"),
29
+ await createGitignoreCheck(status.projectRoot),
30
+ createPdfOutputCheck(status.config),
31
+ {
32
+ level: "warn",
33
+ name: "Auth validity",
34
+ message: "not checked by offline doctor; Overleaf may reject expired sessions later",
35
+ },
36
+ ];
37
+ return {
38
+ checks,
39
+ ...selectDoctorOutcome(checks, status),
40
+ };
41
+ }
42
+ export function formatDoctorReport(report) {
43
+ const lines = [
44
+ "olcx doctor",
45
+ ...report.checks.map((check) => `[${check.level}] ${redactForStatus(check.name)}: ${redactForStatus(check.message)}`),
46
+ ];
47
+ if (report.exitCode !== EXIT_CODES.SUCCESS) {
48
+ lines.push(`Error: ${redactForStatus(report.errorMessage ?? "olcx doctor found problems.")}`);
49
+ if (report.next !== undefined) {
50
+ lines.push(`Next: ${redactForStatus(report.next)}`);
51
+ }
52
+ }
53
+ return lines.join("\n") + "\n";
54
+ }
55
+ function createNodeCheck(version) {
56
+ if (nodeMajor(version) >= 20) {
57
+ return {
58
+ level: "pass",
59
+ name: "Node.js",
60
+ message: `${version} satisfies >=20`,
61
+ };
62
+ }
63
+ return {
64
+ level: "fail",
65
+ name: "Node.js",
66
+ message: `${version} does not satisfy >=20`,
67
+ next: RUNTIME_NEXT,
68
+ };
69
+ }
70
+ function createConfigCheck(config) {
71
+ if (config.state === "configured") {
72
+ return {
73
+ level: "pass",
74
+ name: "Config",
75
+ message: ".olcx/config.json is valid",
76
+ };
77
+ }
78
+ return {
79
+ level: "fail",
80
+ name: "Config",
81
+ message: config.state === "missing" ? "missing .olcx/config.json" : "invalid .olcx/config.json",
82
+ next: INIT_NEXT,
83
+ };
84
+ }
85
+ function createAuthCheck(auth) {
86
+ if (auth.state === "present") {
87
+ return {
88
+ level: "pass",
89
+ name: "Auth file",
90
+ message: ".olcx/auth.local.json is valid",
91
+ };
92
+ }
93
+ return {
94
+ level: "fail",
95
+ name: "Auth file",
96
+ message: auth.state === "missing" ? "missing .olcx/auth.local.json" : "invalid .olcx/auth.local.json",
97
+ next: AUTH_NEXT,
98
+ };
99
+ }
100
+ function createEndpointCheck(config) {
101
+ if (config.state === "configured") {
102
+ return {
103
+ level: "pass",
104
+ name: "Overleaf endpoint",
105
+ message: config.overleafBaseUrl ?? "unknown",
106
+ };
107
+ }
108
+ return {
109
+ level: "warn",
110
+ name: "Overleaf endpoint",
111
+ message: "unknown until project config is valid",
112
+ };
113
+ }
114
+ function createBackendCheck(backendAvailable) {
115
+ if (backendAvailable) {
116
+ return {
117
+ level: "pass",
118
+ name: "Backend module",
119
+ message: "olcli adapter available",
120
+ };
121
+ }
122
+ return {
123
+ level: "fail",
124
+ name: "Backend module",
125
+ message: "olcli adapter unavailable",
126
+ next: RUNTIME_NEXT,
127
+ };
128
+ }
129
+ async function createGitignoreCheck(projectRoot) {
130
+ const missing = await missingSecretIgnoreEntries(projectRoot);
131
+ if (missing.length === 0) {
132
+ return {
133
+ level: "pass",
134
+ name: "Git ignore",
135
+ message: "local auth patterns are ignored",
136
+ };
137
+ }
138
+ return {
139
+ level: "fail",
140
+ name: "Git ignore",
141
+ message: `missing ${missing.join(", ")}`,
142
+ next: GITIGNORE_NEXT,
143
+ };
144
+ }
145
+ function createPdfOutputCheck(config) {
146
+ if (config.state === "configured") {
147
+ return {
148
+ level: "pass",
149
+ name: "PDF output",
150
+ message: `configured ${config.pdfPath}`,
151
+ };
152
+ }
153
+ return {
154
+ level: "warn",
155
+ name: "PDF output",
156
+ message: "unknown until project config is valid",
157
+ };
158
+ }
159
+ function selectDoctorOutcome(checks, status) {
160
+ const runtimeFailure = checks.find((check) => check.level === "fail" && (check.name === "Node.js" || check.name === "Backend module"));
161
+ if (runtimeFailure !== undefined) {
162
+ return {
163
+ exitCode: EXIT_CODES.INTERNAL_ERROR,
164
+ errorMessage: "olcx doctor found local runtime problems.",
165
+ next: runtimeFailure.next ?? RUNTIME_NEXT,
166
+ };
167
+ }
168
+ const configFailure = checks.find((check) => check.level === "fail" && (check.name === "Config" || check.name === "Git ignore"));
169
+ if (configFailure !== undefined) {
170
+ return {
171
+ exitCode: EXIT_CODES.CONFIG_ERROR,
172
+ errorMessage: "olcx doctor found project configuration problems.",
173
+ next: status.config.state === "configured" ? configFailure.next ?? GITIGNORE_NEXT : INIT_NEXT,
174
+ };
175
+ }
176
+ const authFailure = checks.find((check) => check.level === "fail" && check.name === "Auth file");
177
+ if (authFailure !== undefined) {
178
+ return {
179
+ exitCode: EXIT_CODES.AUTH_ERROR,
180
+ errorMessage: "olcx doctor found auth problems.",
181
+ next: authFailure.next ?? AUTH_NEXT,
182
+ };
183
+ }
184
+ return { exitCode: EXIT_CODES.SUCCESS };
185
+ }
186
+ async function missingSecretIgnoreEntries(projectRoot) {
187
+ let content = "";
188
+ try {
189
+ content = await readFile(join(projectRoot, ".gitignore"), "utf8");
190
+ }
191
+ catch (error) {
192
+ if (!isNodeError(error, "ENOENT")) {
193
+ throw error;
194
+ }
195
+ }
196
+ const entries = new Set(content
197
+ .split(/\r?\n/)
198
+ .map((line) => line.trim())
199
+ .filter((line) => line.length > 0));
200
+ return REQUIRED_SECRET_IGNORE_ENTRIES.filter((entry) => !entries.has(entry));
201
+ }
202
+ function nodeMajor(version) {
203
+ const major = Number.parseInt(version.split(".")[0] ?? "", 10);
204
+ return Number.isFinite(major) ? major : 0;
205
+ }
206
+ function isNodeError(error, code) {
207
+ return typeof error === "object" && error !== null && error.code === code;
208
+ }
209
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/diagnostics/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ProjectStatusReport } from "./types.js";
2
+ export interface CollectProjectStatusOptions {
3
+ cwd: string;
4
+ }
5
+ export declare function collectProjectStatus(options: CollectProjectStatusOptions): Promise<ProjectStatusReport>;
6
+ export declare function formatProjectStatus(report: ProjectStatusReport): string;
@@ -0,0 +1,110 @@
1
+ import { readProjectAuth, summarizeProjectAuth } from "../auth/projectAuth.js";
2
+ import { redactForStatus } from "../auth/redact.js";
3
+ import { readProjectConfig, summarizeProjectConfig } from "../config/projectConfig.js";
4
+ import { findProjectRoot } from "../config/projectRoot.js";
5
+ import { isOlcxError } from "../errors.js";
6
+ const INIT_NEXT = "olcx init --project <overleaf-project-url-or-id>";
7
+ const AUTH_NEXT = "olcx auth --from-env OLCX_OVERLEAF_SESSION";
8
+ export async function collectProjectStatus(options) {
9
+ const projectRoot = await findProjectRoot(options.cwd);
10
+ const config = await collectConfigStatus(projectRoot);
11
+ const auth = await collectAuthStatus(projectRoot);
12
+ const next = unique([
13
+ config.state === "configured" ? undefined : INIT_NEXT,
14
+ auth.state === "present" ? undefined : AUTH_NEXT,
15
+ ]);
16
+ return {
17
+ projectRoot,
18
+ config,
19
+ auth,
20
+ next,
21
+ };
22
+ }
23
+ export function formatProjectStatus(report) {
24
+ const lines = [
25
+ "olcx status",
26
+ `Project root: ${redactForStatus(report.projectRoot)}`,
27
+ `Project binding: ${report.config.state}`,
28
+ `Project id: ${report.config.hasProjectId ? "present" : "missing"}`,
29
+ ...(report.config.state === "configured" && report.config.overleafBaseUrl !== undefined
30
+ ? [`Overleaf endpoint: ${redactForStatus(report.config.overleafBaseUrl)}`]
31
+ : []),
32
+ `PDF output: ${redactForStatus(report.config.pdfPath)}`,
33
+ `Auth: ${report.auth.state}`,
34
+ `Account: ${redactForStatus(report.auth.accountLabel)}`,
35
+ ];
36
+ if (report.auth.state === "present" && report.auth.source !== undefined) {
37
+ lines.push(`Auth source: ${redactForStatus(report.auth.source)}`);
38
+ }
39
+ if (report.auth.state === "present" && report.auth.updatedAt !== undefined) {
40
+ lines.push(`Auth updated: ${redactForStatus(report.auth.updatedAt)}`);
41
+ }
42
+ for (const next of report.next) {
43
+ lines.push(`Next: ${redactForStatus(next)}`);
44
+ }
45
+ return lines.join("\n") + "\n";
46
+ }
47
+ async function collectConfigStatus(projectRoot) {
48
+ try {
49
+ const config = await readProjectConfig(projectRoot);
50
+ const summary = summarizeProjectConfig(config);
51
+ return {
52
+ state: "configured",
53
+ hasProjectId: summary.hasProjectId === true,
54
+ overleafBaseUrl: String(summary.overleaf?.baseUrl ?? "unknown"),
55
+ pdfPath: String(summary.pdfPath ?? "unknown"),
56
+ };
57
+ }
58
+ catch (error) {
59
+ if (isOlcxError(error) && error.code === "PROJECT_CONFIG_NOT_FOUND") {
60
+ return {
61
+ state: "missing",
62
+ hasProjectId: false,
63
+ pdfPath: "unknown",
64
+ reason: redactForStatus(error.message),
65
+ };
66
+ }
67
+ if (isOlcxError(error) && error.code === "PROJECT_CONFIG_INVALID") {
68
+ return {
69
+ state: "invalid",
70
+ hasProjectId: false,
71
+ pdfPath: "unknown",
72
+ reason: redactForStatus(error.message),
73
+ };
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+ async function collectAuthStatus(projectRoot) {
79
+ try {
80
+ const auth = await readProjectAuth(projectRoot);
81
+ const summary = summarizeProjectAuth(auth);
82
+ return {
83
+ state: "present",
84
+ accountLabel: summary.accountLabel,
85
+ source: summary.source,
86
+ updatedAt: summary.updatedAt,
87
+ };
88
+ }
89
+ catch (error) {
90
+ if (isOlcxError(error) && error.code === "PROJECT_AUTH_NOT_FOUND") {
91
+ return {
92
+ state: "missing",
93
+ accountLabel: "unknown",
94
+ reason: redactForStatus(error.message),
95
+ };
96
+ }
97
+ if (isOlcxError(error) && error.code === "PROJECT_AUTH_INVALID") {
98
+ return {
99
+ state: "invalid",
100
+ accountLabel: "unknown",
101
+ reason: redactForStatus(error.message),
102
+ };
103
+ }
104
+ throw error;
105
+ }
106
+ }
107
+ function unique(values) {
108
+ return [...new Set(values.filter((value) => value !== undefined))];
109
+ }
110
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/diagnostics/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { ExitCode } from "../errors.js";
2
+ export type DiagnosticState = "configured" | "present" | "missing" | "invalid" | "not-checked";
3
+ export type DiagnosticLevel = "pass" | "warn" | "fail";
4
+ export interface ProjectStatusReport {
5
+ projectRoot: string;
6
+ config: {
7
+ state: "configured" | "missing" | "invalid";
8
+ hasProjectId: boolean;
9
+ overleafBaseUrl?: string;
10
+ pdfPath: string;
11
+ reason?: string;
12
+ };
13
+ auth: {
14
+ state: "present" | "missing" | "invalid";
15
+ accountLabel: string;
16
+ source?: string;
17
+ updatedAt?: string;
18
+ reason?: string;
19
+ };
20
+ next: string[];
21
+ }
22
+ export interface DiagnosticCheck {
23
+ level: DiagnosticLevel;
24
+ name: string;
25
+ message: string;
26
+ next?: string;
27
+ }
28
+ export interface DoctorReport {
29
+ checks: DiagnosticCheck[];
30
+ exitCode: ExitCode;
31
+ errorMessage?: string;
32
+ next?: string;
33
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/diagnostics/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,36 @@
1
+ import type { OverleafBaseUrl } from "../config/types.js";
2
+ export type OverleafEndpointAlias = "www" | "cn";
3
+ export interface OverleafEndpointDefinition {
4
+ alias: OverleafEndpointAlias;
5
+ baseUrl: OverleafBaseUrl;
6
+ probeUrl: `${OverleafBaseUrl}/project`;
7
+ }
8
+ export interface EndpointProbeResult {
9
+ alias: OverleafEndpointAlias;
10
+ baseUrl: OverleafBaseUrl;
11
+ available: boolean;
12
+ latencyMs: number;
13
+ status?: number;
14
+ failureReason?: string;
15
+ }
16
+ export type FetchLike = (url: string, init?: RequestInit) => Promise<{
17
+ status: number;
18
+ ok: boolean;
19
+ }>;
20
+ export declare const OVERLEAF_ENDPOINTS: readonly OverleafEndpointDefinition[];
21
+ export declare function normalizeOverleafBaseUrl(value: string): OverleafBaseUrl;
22
+ export declare function endpointAliasFromBaseUrl(baseUrl: OverleafBaseUrl): OverleafEndpointAlias;
23
+ export declare function resolveEndpointInput(value: string): OverleafEndpointDefinition;
24
+ export declare function probeOverleafEndpoint(input: {
25
+ endpoint: OverleafEndpointDefinition;
26
+ timeoutMs: number;
27
+ fetchImpl?: FetchLike;
28
+ now?: () => number;
29
+ }): Promise<EndpointProbeResult>;
30
+ export declare function testOverleafEndpoints(input?: {
31
+ timeoutMs?: number;
32
+ fetchImpl?: FetchLike;
33
+ now?: () => number;
34
+ }): Promise<EndpointProbeResult[]>;
35
+ export declare function selectFastestAvailableEndpoint(results: EndpointProbeResult[]): EndpointProbeResult | undefined;
36
+ export declare function formatEndpointProbeResult(result: EndpointProbeResult): string;
@@ -0,0 +1,105 @@
1
+ import { createOlcxError, redactSensitive } from "../cli-behavior.js";
2
+ export const OVERLEAF_ENDPOINTS = [
3
+ { alias: "www", baseUrl: "https://www.overleaf.com", probeUrl: "https://www.overleaf.com/project" },
4
+ { alias: "cn", baseUrl: "https://cn.overleaf.com", probeUrl: "https://cn.overleaf.com/project" },
5
+ ];
6
+ export function normalizeOverleafBaseUrl(value) {
7
+ const normalized = value.trim().replace(/\/+$/, "");
8
+ if (normalized === "https://www.overleaf.com" || normalized === "https://cn.overleaf.com") {
9
+ return normalized;
10
+ }
11
+ throw createOlcxError({
12
+ code: "USER_INPUT_ERROR",
13
+ message: "Unsupported Overleaf endpoint.",
14
+ hint: "Use endpoint alias www or cn.",
15
+ details: { value },
16
+ });
17
+ }
18
+ export function endpointAliasFromBaseUrl(baseUrl) {
19
+ return baseUrl === "https://cn.overleaf.com" ? "cn" : "www";
20
+ }
21
+ export function resolveEndpointInput(value) {
22
+ const normalized = value.trim().toLowerCase();
23
+ const endpoint = OVERLEAF_ENDPOINTS.find((candidate) => candidate.alias === normalized || candidate.baseUrl === normalized);
24
+ if (endpoint === undefined) {
25
+ throw createOlcxError({
26
+ code: "USER_INPUT_ERROR",
27
+ message: "Unsupported Overleaf endpoint.",
28
+ hint: "Use endpoint alias www or cn.",
29
+ details: { accepted: ["www", "cn"], value },
30
+ });
31
+ }
32
+ return endpoint;
33
+ }
34
+ export async function probeOverleafEndpoint(input) {
35
+ const fetchImpl = input.fetchImpl ?? ((url, init) => fetch(url, init));
36
+ const now = input.now ?? Date.now;
37
+ const controller = new AbortController();
38
+ const timeout = setTimeout(() => controller.abort(), input.timeoutMs);
39
+ const started = now();
40
+ try {
41
+ const response = await fetchImpl(input.endpoint.probeUrl, {
42
+ method: "GET",
43
+ redirect: "manual",
44
+ signal: controller.signal,
45
+ headers: { "User-Agent": "olcx-endpoint-probe" },
46
+ });
47
+ const latencyMs = Math.max(0, Math.round(now() - started));
48
+ if (response.status < 500) {
49
+ return {
50
+ alias: input.endpoint.alias,
51
+ baseUrl: input.endpoint.baseUrl,
52
+ available: true,
53
+ latencyMs,
54
+ status: response.status,
55
+ };
56
+ }
57
+ return {
58
+ alias: input.endpoint.alias,
59
+ baseUrl: input.endpoint.baseUrl,
60
+ available: false,
61
+ latencyMs,
62
+ status: response.status,
63
+ failureReason: `http ${response.status}`,
64
+ };
65
+ }
66
+ catch (error) {
67
+ const latencyMs = Math.max(0, Math.round(now() - started));
68
+ const failureReason = error instanceof Error && error.name === "AbortError"
69
+ ? `timeout after ${input.timeoutMs}ms`
70
+ : redactEndpointFailureReason(error instanceof Error ? error.message : String(error));
71
+ return {
72
+ alias: input.endpoint.alias,
73
+ baseUrl: input.endpoint.baseUrl,
74
+ available: false,
75
+ latencyMs,
76
+ failureReason,
77
+ };
78
+ }
79
+ finally {
80
+ clearTimeout(timeout);
81
+ }
82
+ }
83
+ function redactEndpointFailureReason(value) {
84
+ return redactSensitive(value).replace(/<redacted-secret>/g, "<redacted-value>").slice(0, 200);
85
+ }
86
+ export async function testOverleafEndpoints(input = {}) {
87
+ const timeoutMs = input.timeoutMs ?? 5000;
88
+ return Promise.all(OVERLEAF_ENDPOINTS.map((endpoint) => probeOverleafEndpoint({
89
+ endpoint,
90
+ timeoutMs,
91
+ fetchImpl: input.fetchImpl,
92
+ now: input.now,
93
+ })));
94
+ }
95
+ export function selectFastestAvailableEndpoint(results) {
96
+ return results
97
+ .filter((result) => result.available)
98
+ .sort((left, right) => left.latencyMs - right.latencyMs)[0];
99
+ }
100
+ export function formatEndpointProbeResult(result) {
101
+ const status = result.status === undefined ? "" : ` status ${result.status}`;
102
+ const failure = result.failureReason === undefined ? "" : ` ${result.failureReason}`;
103
+ return `- ${result.alias} ${result.baseUrl} ${result.available ? "available" : "unavailable"} ${result.latencyMs}ms${status}${failure}`;
104
+ }
105
+ //# sourceMappingURL=overleafEndpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overleafEndpoint.js","sourceRoot":"","sources":["../../src/endpoint/overleafEndpoint.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ export declare const EXIT_CODES: {
2
+ readonly SUCCESS: 0;
3
+ readonly INTERNAL_ERROR: 1;
4
+ readonly USER_INPUT_ERROR: 2;
5
+ readonly CONFIG_ERROR: 3;
6
+ readonly AUTH_ERROR: 4;
7
+ readonly NETWORK_ERROR: 5;
8
+ readonly SYNC_CONFLICT: 6;
9
+ readonly COMPILE_FAILED: 7;
10
+ };
11
+ export type ExitCodeName = keyof typeof EXIT_CODES;
12
+ export type ExitCode = (typeof EXIT_CODES)[ExitCodeName];
13
+ export type OlcxErrorCode = "USER_INPUT_ERROR" | "PROJECT_CONFIG_NOT_FOUND" | "PROJECT_CONFIG_INVALID" | "PROJECT_AUTH_NOT_FOUND" | "PROJECT_AUTH_INVALID" | "BACKEND_AUTH_FAILED" | "BACKEND_NETWORK_ERROR" | "BACKEND_PROTOCOL_ERROR" | "SYNC_CONFLICT" | "SYNC_UNSAFE_OPERATION" | "COMPILE_FAILED" | "COMPILE_TIMEOUT" | "IO_ERROR" | "INTERNAL_ERROR";
14
+ export declare const ERROR_CODE_EXIT_CODES: Record<OlcxErrorCode, ExitCode>;
15
+ export interface OlcxError extends Error {
16
+ name: "OlcxError";
17
+ code: OlcxErrorCode;
18
+ exitCode: ExitCode;
19
+ hint?: string;
20
+ details?: Record<string, unknown>;
21
+ cause?: unknown;
22
+ }
23
+ export interface CreateOlcxErrorInput {
24
+ code: OlcxErrorCode;
25
+ message: string;
26
+ hint?: string;
27
+ details?: Record<string, unknown>;
28
+ cause?: unknown;
29
+ }
30
+ export declare function mapErrorCodeToExitCode(code: OlcxErrorCode): ExitCode;
31
+ export declare function createOlcxError(input: CreateOlcxErrorInput): OlcxError;
32
+ export declare function isOlcxError(error: unknown): error is OlcxError;
package/dist/errors.js ADDED
@@ -0,0 +1,53 @@
1
+ export const EXIT_CODES = {
2
+ SUCCESS: 0,
3
+ INTERNAL_ERROR: 1,
4
+ USER_INPUT_ERROR: 2,
5
+ CONFIG_ERROR: 3,
6
+ AUTH_ERROR: 4,
7
+ NETWORK_ERROR: 5,
8
+ SYNC_CONFLICT: 6,
9
+ COMPILE_FAILED: 7,
10
+ };
11
+ export const ERROR_CODE_EXIT_CODES = {
12
+ USER_INPUT_ERROR: EXIT_CODES.USER_INPUT_ERROR,
13
+ PROJECT_CONFIG_NOT_FOUND: EXIT_CODES.CONFIG_ERROR,
14
+ PROJECT_CONFIG_INVALID: EXIT_CODES.CONFIG_ERROR,
15
+ PROJECT_AUTH_NOT_FOUND: EXIT_CODES.AUTH_ERROR,
16
+ PROJECT_AUTH_INVALID: EXIT_CODES.AUTH_ERROR,
17
+ BACKEND_AUTH_FAILED: EXIT_CODES.AUTH_ERROR,
18
+ BACKEND_NETWORK_ERROR: EXIT_CODES.NETWORK_ERROR,
19
+ BACKEND_PROTOCOL_ERROR: EXIT_CODES.NETWORK_ERROR,
20
+ SYNC_CONFLICT: EXIT_CODES.SYNC_CONFLICT,
21
+ SYNC_UNSAFE_OPERATION: EXIT_CODES.SYNC_CONFLICT,
22
+ COMPILE_FAILED: EXIT_CODES.COMPILE_FAILED,
23
+ COMPILE_TIMEOUT: EXIT_CODES.COMPILE_FAILED,
24
+ IO_ERROR: EXIT_CODES.INTERNAL_ERROR,
25
+ INTERNAL_ERROR: EXIT_CODES.INTERNAL_ERROR,
26
+ };
27
+ export function mapErrorCodeToExitCode(code) {
28
+ return ERROR_CODE_EXIT_CODES[code];
29
+ }
30
+ export function createOlcxError(input) {
31
+ const error = new Error(input.message);
32
+ error.name = "OlcxError";
33
+ error.code = input.code;
34
+ error.exitCode = mapErrorCodeToExitCode(input.code);
35
+ if (input.hint !== undefined) {
36
+ error.hint = input.hint;
37
+ }
38
+ if (input.details !== undefined) {
39
+ error.details = input.details;
40
+ }
41
+ if (input.cause !== undefined) {
42
+ error.cause = input.cause;
43
+ }
44
+ return error;
45
+ }
46
+ export function isOlcxError(error) {
47
+ return (typeof error === "object" &&
48
+ error !== null &&
49
+ error.name === "OlcxError" &&
50
+ typeof error.code === "string" &&
51
+ typeof error.exitCode === "number");
52
+ }
53
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,CAAC;IACV,cAAc,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC;IACnB,YAAY,EAAE,CAAC;IACf,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,CAAC;IAChB,aAAa,EAAE,CAAC;IAChB,cAAc,EAAE,CAAC;CACT,CAAC;AAqBX,MAAM,CAAC,MAAM,qBAAqB,GAAoC;IACpE,gBAAgB,EAAE,UAAU,CAAC,gBAAgB;IAC7C,wBAAwB,EAAE,UAAU,CAAC,YAAY;IACjD,sBAAsB,EAAE,UAAU,CAAC,YAAY;IAC/C,sBAAsB,EAAE,UAAU,CAAC,UAAU;IAC7C,oBAAoB,EAAE,UAAU,CAAC,UAAU;IAC3C,mBAAmB,EAAE,UAAU,CAAC,UAAU;IAC1C,qBAAqB,EAAE,UAAU,CAAC,aAAa;IAC/C,sBAAsB,EAAE,UAAU,CAAC,aAAa;IAChD,aAAa,EAAE,UAAU,CAAC,aAAa;IACvC,qBAAqB,EAAE,UAAU,CAAC,aAAa;IAC/C,cAAc,EAAE,UAAU,CAAC,cAAc;IACzC,eAAe,EAAE,UAAU,CAAC,cAAc;IAC1C,QAAQ,EAAE,UAAU,CAAC,cAAc;IACnC,cAAc,EAAE,UAAU,CAAC,cAAc;CAC1C,CAAC;AAmBF,MAAM,UAAU,sBAAsB,CAAC,IAAmB;IACxD,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAc,CAAC;IACpD,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC;IACzB,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,KAAK,CAAC,QAAQ,GAAG,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAC1B,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAChC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAChC,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACb,KAA4B,CAAC,IAAI,KAAK,WAAW;QAClD,OAAQ,KAA4B,CAAC,IAAI,KAAK,QAAQ;QACtD,OAAQ,KAAgC,CAAC,QAAQ,KAAK,QAAQ,CAC/D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type ProjectAuth } from "../auth/types.js";
2
+ import { type OverleafBackend } from "../backend/types.js";
3
+ import { type RemoteFileSnapshot, type SyncPlan } from "./types.js";
4
+ export interface ApplySyncPlanResult {
5
+ uploaded: Map<string, RemoteFileSnapshot>;
6
+ downloaded: string[];
7
+ }
8
+ export declare function applySyncPlan(input: {
9
+ projectRoot: string;
10
+ backend: OverleafBackend;
11
+ projectId: string;
12
+ auth: ProjectAuth;
13
+ plan: SyncPlan;
14
+ }): Promise<ApplySyncPlanResult>;