@aloth/olcli 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -19,11 +19,40 @@ export class OverleafClient {
19
19
  cookies;
20
20
  csrf;
21
21
  baseUrl;
22
+ verbose = false;
23
+ // Cache per-project folder trees so repeated uploads in sync/upload calls
24
+ // don't re-fetch the tree via Socket.IO on every file.
25
+ folderTreeCache = new Map();
22
26
  constructor(credentials) {
23
27
  this.cookies = credentials.cookies;
24
28
  this.csrf = credentials.csrf;
25
29
  this.baseUrl = credentials.baseUrl || DEFAULT_BASE_URL;
26
30
  }
31
+ /** Enable or disable verbose request/response logging to stderr. */
32
+ setVerbose(v) {
33
+ this.verbose = v;
34
+ }
35
+ /**
36
+ * Resolve (and cache) the folder tree for a project. Falls back to a
37
+ * minimal tree containing only the root folder when the Socket.IO probe
38
+ * fails (e.g. self-hosted Overleaf without that endpoint).
39
+ */
40
+ async getOrLoadFolderTree(projectId) {
41
+ const cached = this.folderTreeCache.get(projectId);
42
+ if (cached)
43
+ return cached;
44
+ let tree = await this.getFolderTreeFromSocket(projectId);
45
+ if (!tree) {
46
+ const rootId = await this.getRootFolderId(projectId);
47
+ tree = { '': rootId };
48
+ }
49
+ this.folderTreeCache.set(projectId, tree);
50
+ return tree;
51
+ }
52
+ /** Drop the cached folder tree for a project (e.g. after rename/delete). */
53
+ invalidateFolderTree(projectId) {
54
+ this.folderTreeCache.delete(projectId);
55
+ }
27
56
  projectUrl() {
28
57
  return `${this.baseUrl}/project`;
29
58
  }
@@ -127,6 +156,12 @@ export class OverleafClient {
127
156
  }
128
157
  }
129
158
  }
159
+ logVerbose(...args) {
160
+ if (this.verbose) {
161
+ // eslint-disable-next-line no-console
162
+ console.error('[olcli]', ...args);
163
+ }
164
+ }
130
165
  async httpRequest(url, options = {}) {
131
166
  const method = options.method || 'GET';
132
167
  const timeoutMs = options.timeoutMs ?? 10000;
@@ -158,6 +193,7 @@ export class OverleafClient {
158
193
  const status = res.statusCode || 0;
159
194
  const resHeaders = res.headers;
160
195
  if (status >= 300 && status < 400 && res.headers.location && redirectsLeft > 0) {
196
+ this.logVerbose(`${method} ${reqUrl} -> ${status} redirect -> ${res.headers.location}`);
161
197
  const redirectUrl = new URL(res.headers.location, reqUrl).toString();
162
198
  res.resume();
163
199
  doRequest(redirectUrl, redirectsLeft - 1).then(resolve, reject);
@@ -176,10 +212,21 @@ export class OverleafClient {
176
212
  body = JSON.parse(buffer.toString('utf-8'));
177
213
  }
178
214
  catch (e) {
215
+ this.logVerbose(`${method} ${reqUrl} -> ${status} (invalid JSON, ${buffer.length} bytes)`);
179
216
  return reject(new Error(`Failed to parse JSON response from ${reqUrl}`));
180
217
  }
181
218
  }
182
- resolve({ status, ok: status >= 200 && status < 300, headers: resHeaders, body });
219
+ const ok = status >= 200 && status < 300;
220
+ if (this.verbose) {
221
+ const ct = (resHeaders['content-type'] || '');
222
+ let snippet = '';
223
+ if (!ok) {
224
+ const text = expect === 'buffer' ? '' : (typeof body === 'string' ? body : JSON.stringify(body));
225
+ snippet = text ? ` body=${text.slice(0, 200).replace(/\s+/g, ' ')}` : '';
226
+ }
227
+ this.logVerbose(`${method} ${reqUrl} -> ${status} (${buffer.length}B ${ct})${snippet}`);
228
+ }
229
+ resolve({ status, ok, headers: resHeaders, body });
183
230
  });
184
231
  res.on('error', reject);
185
232
  });
@@ -476,8 +523,11 @@ export class OverleafClient {
476
523
  if (!pdfFile) {
477
524
  throw new Error('No PDF output found');
478
525
  }
526
+ // Overleaf's CDN requires ?clsiserverid=<id> for build-output downloads.
527
+ // Without it the build URL 404s. See: https://github.com/aloth/olcli/issues/22
528
+ const qs = data.clsiServerId ? `?clsiserverid=${encodeURIComponent(data.clsiServerId)}` : '';
479
529
  return {
480
- pdfUrl: `${this.baseUrl}${pdfFile.url}`,
530
+ pdfUrl: `${this.baseUrl}${pdfFile.url}${qs}`,
481
531
  logs: data.compileGroup ? [`Compile group: ${data.compileGroup}`] : []
482
532
  };
483
533
  }
@@ -554,6 +604,225 @@ export class OverleafClient {
554
604
  }
555
605
  return packets;
556
606
  }
607
+ encodeSocketIoEvent(id, name, args) {
608
+ return `5:${id}+::${JSON.stringify({ name, args })}`;
609
+ }
610
+ parseSocketIoAck(packet, id) {
611
+ const match = packet.match(/^6:::(\d+)(.*)$/);
612
+ if (!match || Number.parseInt(match[1], 10) !== id) {
613
+ return null;
614
+ }
615
+ let payload = match[2] || '';
616
+ if (payload.startsWith('+')) {
617
+ payload = payload.slice(1);
618
+ }
619
+ if (!payload)
620
+ return [];
621
+ const args = JSON.parse(payload);
622
+ return Array.isArray(args) ? args : [args];
623
+ }
624
+ decodeOverleafUtf8(text) {
625
+ return Buffer.from(text, 'binary').toString('utf-8');
626
+ }
627
+ generateCommentThreadId() {
628
+ const timestamp = Math.floor(Date.now() / 1000).toString(16).padStart(8, '0');
629
+ const machine = Math.floor(Math.random() * 0xffffff).toString(16).padStart(6, '0');
630
+ const pid = Math.floor(Math.random() * 0x7fff).toString(16).padStart(4, '0');
631
+ return `${timestamp}${machine}${pid}000001`;
632
+ }
633
+ positionToLineColumn(content, position) {
634
+ const prefix = content.slice(0, position);
635
+ const lines = prefix.split('\n');
636
+ return {
637
+ line: lines.length,
638
+ column: lines[lines.length - 1].length + 1
639
+ };
640
+ }
641
+ buildCommentContext(content, line, contextLines = 0) {
642
+ if (contextLines <= 0)
643
+ return undefined;
644
+ const lines = content.split('\n');
645
+ const lineIndex = line - 1;
646
+ const beforeStart = Math.max(0, lineIndex - contextLines);
647
+ const afterEnd = Math.min(lines.length, lineIndex + contextLines + 1);
648
+ return {
649
+ startLine: beforeStart + 1,
650
+ endLine: afterEnd,
651
+ before: lines.slice(beforeStart, lineIndex),
652
+ line: lines[lineIndex] || '',
653
+ after: lines.slice(lineIndex + 1, afterEnd)
654
+ };
655
+ }
656
+ collectProjectDocs(projectInfo) {
657
+ const docs = [];
658
+ function walk(folder, folderPath) {
659
+ for (const doc of folder.docs || []) {
660
+ docs.push({
661
+ id: doc._id,
662
+ path: folderPath ? `${folderPath}/${doc.name}` : doc.name
663
+ });
664
+ }
665
+ for (const child of folder.folders || []) {
666
+ const childPath = folderPath ? `${folderPath}/${child.name}` : child.name;
667
+ walk(child, childPath);
668
+ }
669
+ }
670
+ for (const folder of projectInfo.rootFolder || []) {
671
+ walk(folder, '');
672
+ }
673
+ return docs;
674
+ }
675
+ async openProjectSocket(projectId) {
676
+ const handshakeUrl = `${this.baseUrl}/socket.io/1/?projectId=${encodeURIComponent(projectId)}&t=${Date.now()}`;
677
+ const handshakeResponse = await this.httpRequest(handshakeUrl, {
678
+ headers: { 'Cookie': this.getCookieHeader(), 'User-Agent': USER_AGENT },
679
+ expect: 'text',
680
+ timeoutMs: 5000
681
+ });
682
+ if (!handshakeResponse.ok) {
683
+ throw new Error(`Failed to open project socket: ${handshakeResponse.status}`);
684
+ }
685
+ this.applySetCookieHeaders(handshakeResponse.headers['set-cookie']);
686
+ const sid = handshakeResponse.body.trim().split(':')[0];
687
+ if (!sid) {
688
+ throw new Error('Failed to open project socket: missing session id');
689
+ }
690
+ const session = {
691
+ sid,
692
+ projectId,
693
+ pollUrl: () => `${this.baseUrl}/socket.io/1/xhr-polling/${sid}?projectId=${encodeURIComponent(projectId)}&t=${Date.now()}`
694
+ };
695
+ for (let attempt = 0; attempt < 8; attempt++) {
696
+ const packets = await this.pollProjectSocket(session);
697
+ if (packets.some(packet => {
698
+ if (!packet.startsWith('5:::'))
699
+ return false;
700
+ try {
701
+ return JSON.parse(packet.slice(4))?.name === 'joinProjectResponse';
702
+ }
703
+ catch {
704
+ return false;
705
+ }
706
+ })) {
707
+ return session;
708
+ }
709
+ }
710
+ throw new Error('Project socket did not return joinProjectResponse');
711
+ }
712
+ async pollProjectSocket(session) {
713
+ const response = await this.httpRequest(session.pollUrl(), {
714
+ headers: { 'Cookie': this.getCookieHeader(), 'User-Agent': USER_AGENT },
715
+ expect: 'text',
716
+ timeoutMs: 7000
717
+ });
718
+ if (!response.ok) {
719
+ throw new Error(`Socket poll failed: ${response.status}`);
720
+ }
721
+ this.applySetCookieHeaders(response.headers['set-cookie']);
722
+ const packets = this.decodeSocketIoPayload(response.body);
723
+ for (const packet of packets) {
724
+ if (packet.startsWith('2::')) {
725
+ const heartbeatResponse = await this.httpRequest(session.pollUrl(), {
726
+ method: 'POST',
727
+ headers: {
728
+ 'Cookie': this.getCookieHeader(),
729
+ 'User-Agent': USER_AGENT,
730
+ 'Content-Type': 'text/plain;charset=UTF-8'
731
+ },
732
+ body: '2::',
733
+ expect: 'text',
734
+ timeoutMs: 5000
735
+ });
736
+ this.applySetCookieHeaders(heartbeatResponse.headers['set-cookie']);
737
+ }
738
+ }
739
+ return packets;
740
+ }
741
+ async postProjectSocketPacket(session, packet) {
742
+ const response = await this.httpRequest(session.pollUrl(), {
743
+ method: 'POST',
744
+ headers: {
745
+ 'Cookie': this.getCookieHeader(),
746
+ 'User-Agent': USER_AGENT,
747
+ 'Content-Type': 'text/plain;charset=UTF-8'
748
+ },
749
+ body: packet,
750
+ expect: 'text',
751
+ timeoutMs: 5000
752
+ });
753
+ if (!response.ok) {
754
+ throw new Error(`Socket post failed: ${response.status}`);
755
+ }
756
+ this.applySetCookieHeaders(response.headers['set-cookie']);
757
+ }
758
+ async socketRpc(session, name, args) {
759
+ const id = Math.floor(Math.random() * 0x7fffffff);
760
+ await this.postProjectSocketPacket(session, this.encodeSocketIoEvent(id, name, args));
761
+ for (let attempt = 0; attempt < 10; attempt++) {
762
+ const packets = await this.pollProjectSocket(session);
763
+ for (const packet of packets) {
764
+ const ackArgs = this.parseSocketIoAck(packet, id);
765
+ if (ackArgs) {
766
+ const [error, ...result] = ackArgs;
767
+ if (error) {
768
+ const message = typeof error === 'string' ? error : error.message || JSON.stringify(error);
769
+ throw new Error(`${name} failed: ${message}`);
770
+ }
771
+ return result;
772
+ }
773
+ }
774
+ }
775
+ throw new Error(`${name} did not return an acknowledgement`);
776
+ }
777
+ async closeProjectSocket(session) {
778
+ try {
779
+ await this.postProjectSocketPacket(session, '0::');
780
+ }
781
+ catch {
782
+ // Best-effort socket cleanup only.
783
+ }
784
+ }
785
+ normalizeJoinedDocument(docId, args) {
786
+ const [lines, version, _updates, ranges, type = 'sharejs-text-ot'] = args;
787
+ if (type === 'history-ot') {
788
+ const content = typeof lines?.content === 'string' ? lines.content : '';
789
+ return {
790
+ docId,
791
+ lines: content.split('\n'),
792
+ content,
793
+ version,
794
+ ranges: lines,
795
+ type
796
+ };
797
+ }
798
+ const decodedLines = Array.isArray(lines)
799
+ ? lines.map((line) => this.decodeOverleafUtf8(line))
800
+ : [];
801
+ const decodedRanges = ranges || {};
802
+ for (const comment of decodedRanges.comments || []) {
803
+ if (comment?.op?.c) {
804
+ comment.op.c = this.decodeOverleafUtf8(comment.op.c);
805
+ }
806
+ }
807
+ return {
808
+ docId,
809
+ lines: decodedLines,
810
+ content: decodedLines.join('\n'),
811
+ version,
812
+ ranges: decodedRanges,
813
+ type
814
+ };
815
+ }
816
+ async joinDocument(session, docId) {
817
+ const args = await this.socketRpc(session, 'joinDoc', [
818
+ docId,
819
+ {
820
+ encodeRanges: true,
821
+ supportsHistoryOT: true
822
+ }
823
+ ]);
824
+ return this.normalizeJoinedDocument(docId, args);
825
+ }
557
826
  /**
558
827
  * Extract root folder ID from a Socket.IO event packet (joinProjectResponse).
559
828
  */
@@ -914,11 +1183,15 @@ export class OverleafClient {
914
1183
  async uploadFile(projectId, folderId, fileName, content, folderTree) {
915
1184
  // Extract just the filename without path
916
1185
  const baseName = fileName.split('/').pop() || fileName;
917
- // Resolve target folder: if fileName has a directory part and we have a folderTree, use it
1186
+ // Resolve target folder: if fileName has a directory part, place the file there.
1187
+ // Lazy-load + cache the folder tree when caller didn't supply one, so external
1188
+ // callers (and our own `upload`/`sync` paths) don't silently dump files into root.
1189
+ // See: https://github.com/aloth/olcli/issues/22 follow-up + 0.3.1 upload-fix.
918
1190
  const dirPart = fileName.includes('/') ? fileName.split('/').slice(0, -1).join('/') : '';
919
1191
  let targetFolderId;
920
- if (dirPart && folderTree) {
921
- targetFolderId = await this.resolveFolderId(projectId, folderTree, dirPart);
1192
+ if (dirPart) {
1193
+ const tree = folderTree || await this.getOrLoadFolderTree(projectId);
1194
+ targetFolderId = await this.resolveFolderId(projectId, tree, dirPart);
922
1195
  }
923
1196
  else {
924
1197
  targetFolderId = folderId || await this.getRootFolderId(projectId);
@@ -1168,6 +1441,247 @@ export class OverleafClient {
1168
1441
  }
1169
1442
  throw new Error(`File not found in archive: ${path}`);
1170
1443
  }
1444
+ async getCommentThreads(projectId) {
1445
+ const response = await this.httpRequest(`${this.baseUrl}/project/${projectId}/threads`, {
1446
+ headers: this.getHeaders(),
1447
+ expect: 'json'
1448
+ });
1449
+ if (!response.ok) {
1450
+ throw new Error(`Failed to fetch comment threads: ${response.status}`);
1451
+ }
1452
+ this.applySetCookieHeaders(response.headers['set-cookie']);
1453
+ return response.body;
1454
+ }
1455
+ async listComments(projectId, options = {}) {
1456
+ const status = options.status || 'all';
1457
+ const contextLines = options.contextLines || 0;
1458
+ const projectInfo = await this.getProjectInfo(projectId);
1459
+ const docs = this.collectProjectDocs(projectInfo);
1460
+ const threads = await this.getCommentThreads(projectId);
1461
+ const comments = [];
1462
+ const session = await this.openProjectSocket(projectId);
1463
+ try {
1464
+ for (const doc of docs) {
1465
+ const joinedDoc = await this.joinDocument(session, doc.id);
1466
+ if (joinedDoc.type === 'history-ot') {
1467
+ for (const comment of joinedDoc.ranges.comments || []) {
1468
+ const ranges = comment.ranges || [];
1469
+ const firstRange = ranges[0];
1470
+ if (!firstRange)
1471
+ continue;
1472
+ const selectedText = ranges
1473
+ .map((range) => joinedDoc.content.slice(range.pos, range.pos + range.length))
1474
+ .join('');
1475
+ const location = this.positionToLineColumn(joinedDoc.content, firstRange.pos);
1476
+ const thread = threads[comment.id] || { messages: [] };
1477
+ const resolved = Boolean(comment.resolved || thread.resolved);
1478
+ comments.push({
1479
+ threadId: comment.id,
1480
+ docId: doc.id,
1481
+ path: doc.path,
1482
+ position: firstRange.pos,
1483
+ line: location.line,
1484
+ column: location.column,
1485
+ selectedText,
1486
+ resolved,
1487
+ messages: thread.messages || [],
1488
+ context: this.buildCommentContext(joinedDoc.content, location.line, contextLines)
1489
+ });
1490
+ }
1491
+ continue;
1492
+ }
1493
+ for (const comment of joinedDoc.ranges.comments || []) {
1494
+ const op = comment.op || {};
1495
+ const threadId = op.t || comment.id;
1496
+ if (!threadId || typeof op.p !== 'number')
1497
+ continue;
1498
+ const selectedText = typeof op.c === 'string'
1499
+ ? op.c
1500
+ : joinedDoc.content.slice(op.p, op.p + (op.c?.length || 0));
1501
+ const location = this.positionToLineColumn(joinedDoc.content, op.p);
1502
+ const thread = threads[threadId] || { messages: [] };
1503
+ const resolved = Boolean(comment.resolved || op.resolved || thread.resolved);
1504
+ comments.push({
1505
+ threadId,
1506
+ docId: doc.id,
1507
+ path: doc.path,
1508
+ position: op.p,
1509
+ line: location.line,
1510
+ column: location.column,
1511
+ selectedText,
1512
+ resolved,
1513
+ messages: thread.messages || [],
1514
+ context: this.buildCommentContext(joinedDoc.content, location.line, contextLines)
1515
+ });
1516
+ }
1517
+ }
1518
+ }
1519
+ finally {
1520
+ await this.closeProjectSocket(session);
1521
+ }
1522
+ return comments
1523
+ .filter(comment => {
1524
+ if (status === 'all')
1525
+ return true;
1526
+ return status === 'resolved' ? comment.resolved : !comment.resolved;
1527
+ })
1528
+ .sort((a, b) => a.path.localeCompare(b.path) || a.position - b.position);
1529
+ }
1530
+ async resolveComment(projectId, threadId) {
1531
+ const comment = await this.findComment(projectId, threadId);
1532
+ const response = await this.httpRequest(`${this.baseUrl}/project/${projectId}/doc/${comment.docId}/thread/${threadId}/resolve`, {
1533
+ method: 'POST',
1534
+ headers: this.getHeaders(true),
1535
+ body: '',
1536
+ expect: 'text'
1537
+ });
1538
+ if (!response.ok) {
1539
+ throw new Error(`Failed to resolve comment: ${response.status}`);
1540
+ }
1541
+ this.applySetCookieHeaders(response.headers['set-cookie']);
1542
+ return comment;
1543
+ }
1544
+ async reopenComment(projectId, threadId) {
1545
+ const comment = await this.findComment(projectId, threadId);
1546
+ const response = await this.httpRequest(`${this.baseUrl}/project/${projectId}/doc/${comment.docId}/thread/${threadId}/reopen`, {
1547
+ method: 'POST',
1548
+ headers: this.getHeaders(true),
1549
+ body: '',
1550
+ expect: 'text'
1551
+ });
1552
+ if (!response.ok) {
1553
+ throw new Error(`Failed to reopen comment: ${response.status}`);
1554
+ }
1555
+ this.applySetCookieHeaders(response.headers['set-cookie']);
1556
+ return comment;
1557
+ }
1558
+ async deleteComment(projectId, threadId) {
1559
+ const comment = await this.findComment(projectId, threadId);
1560
+ const response = await this.httpRequest(`${this.baseUrl}/project/${projectId}/doc/${comment.docId}/thread/${threadId}`, {
1561
+ method: 'DELETE',
1562
+ headers: this.getHeaders(true),
1563
+ body: '',
1564
+ expect: 'text'
1565
+ });
1566
+ if (!response.ok) {
1567
+ throw new Error(`Failed to delete comment: ${response.status}`);
1568
+ }
1569
+ this.applySetCookieHeaders(response.headers['set-cookie']);
1570
+ return comment;
1571
+ }
1572
+ async findComment(projectId, threadId) {
1573
+ const comments = await this.listComments(projectId);
1574
+ const comment = comments.find(item => item.threadId === threadId);
1575
+ if (!comment) {
1576
+ throw new Error(`Comment thread not found: ${threadId}`);
1577
+ }
1578
+ return comment;
1579
+ }
1580
+ resolveCommentSelection(doc, options) {
1581
+ if (options.selectedText) {
1582
+ const occurrence = options.occurrence || 1;
1583
+ let fromIndex = 0;
1584
+ let position = -1;
1585
+ for (let index = 0; index < occurrence; index++) {
1586
+ position = doc.content.indexOf(options.selectedText, fromIndex);
1587
+ if (position === -1)
1588
+ break;
1589
+ fromIndex = position + options.selectedText.length;
1590
+ }
1591
+ if (position === -1) {
1592
+ throw new Error(`Selected text not found in ${options.filePath}`);
1593
+ }
1594
+ return { position, selectedText: options.selectedText };
1595
+ }
1596
+ let position = options.position;
1597
+ if (position == null) {
1598
+ if (options.line == null || options.column == null) {
1599
+ throw new Error('Add comment requires either --text, --position, or both --line and --column');
1600
+ }
1601
+ const lines = doc.content.split('\n');
1602
+ if (options.line < 1 || options.line > lines.length) {
1603
+ throw new Error(`Line out of range: ${options.line}`);
1604
+ }
1605
+ if (options.column < 1 || options.column > lines[options.line - 1].length + 1) {
1606
+ throw new Error(`Column out of range: ${options.column}`);
1607
+ }
1608
+ position = lines.slice(0, options.line - 1).reduce((sum, line) => sum + line.length + 1, 0) + options.column - 1;
1609
+ }
1610
+ const length = options.length || 1;
1611
+ if (position < 0 || position + length > doc.content.length) {
1612
+ throw new Error('Comment selection is outside the document');
1613
+ }
1614
+ return {
1615
+ position,
1616
+ selectedText: doc.content.slice(position, position + length)
1617
+ };
1618
+ }
1619
+ async addComment(projectId, options) {
1620
+ const projectInfo = await this.getProjectInfo(projectId);
1621
+ const docs = this.collectProjectDocs(projectInfo);
1622
+ const normalizedPath = options.filePath.replace(/^\//, '');
1623
+ const doc = docs.find(item => item.path === normalizedPath || item.path.replace(/^\//, '') === normalizedPath);
1624
+ if (!doc) {
1625
+ throw new Error(`Doc not found: ${options.filePath}`);
1626
+ }
1627
+ const session = await this.openProjectSocket(projectId);
1628
+ try {
1629
+ const joinedDoc = await this.joinDocument(session, doc.id);
1630
+ const selection = this.resolveCommentSelection(joinedDoc, options);
1631
+ const threadId = this.generateCommentThreadId();
1632
+ await this.postCommentMessage(projectId, threadId, options.content);
1633
+ const op = joinedDoc.type === 'history-ot'
1634
+ ? {
1635
+ commentId: threadId,
1636
+ ranges: [{ pos: selection.position, length: selection.selectedText.length }]
1637
+ }
1638
+ : {
1639
+ c: selection.selectedText,
1640
+ p: selection.position,
1641
+ t: threadId
1642
+ };
1643
+ await this.socketRpc(session, 'applyOtUpdate', [doc.id, {
1644
+ doc: doc.id,
1645
+ op: [op],
1646
+ v: joinedDoc.version
1647
+ }]);
1648
+ const location = this.positionToLineColumn(joinedDoc.content, selection.position);
1649
+ return {
1650
+ threadId,
1651
+ docId: doc.id,
1652
+ path: doc.path,
1653
+ position: selection.position,
1654
+ line: location.line,
1655
+ column: location.column,
1656
+ selectedText: selection.selectedText,
1657
+ resolved: false,
1658
+ messages: []
1659
+ };
1660
+ }
1661
+ finally {
1662
+ await this.closeProjectSocket(session);
1663
+ }
1664
+ }
1665
+ async postCommentMessage(projectId, threadId, content) {
1666
+ const response = await this.httpRequest(`${this.baseUrl}/project/${projectId}/thread/${threadId}/messages`, {
1667
+ method: 'POST',
1668
+ headers: this.getHeaders(true),
1669
+ body: JSON.stringify({ content }),
1670
+ expect: 'text'
1671
+ });
1672
+ if (!response.ok) {
1673
+ throw new Error(`Failed to post comment message: ${response.status}`);
1674
+ }
1675
+ this.applySetCookieHeaders(response.headers['set-cookie']);
1676
+ if (!response.body)
1677
+ return null;
1678
+ try {
1679
+ return JSON.parse(response.body);
1680
+ }
1681
+ catch {
1682
+ return null;
1683
+ }
1684
+ }
1171
1685
  /**
1172
1686
  * Compile project and get all output files
1173
1687
  */
@@ -1189,13 +1703,16 @@ export class OverleafClient {
1189
1703
  this.applySetCookieHeaders(response.headers['set-cookie']);
1190
1704
  const data = response.body;
1191
1705
  const pdfFile = data.outputFiles?.find((f) => f.type === 'pdf');
1706
+ // Overleaf's CDN requires ?clsiserverid=<id> for build-output downloads.
1707
+ // Without it every output (pdf/log/bbl/...) 404s. See issue #22.
1708
+ const qs = data.clsiServerId ? `?clsiserverid=${encodeURIComponent(data.clsiServerId)}` : '';
1192
1709
  return {
1193
1710
  status: data.status,
1194
- pdfUrl: pdfFile ? `${this.baseUrl}${pdfFile.url}` : undefined,
1711
+ pdfUrl: pdfFile ? `${this.baseUrl}${pdfFile.url}${qs}` : undefined,
1195
1712
  outputFiles: (data.outputFiles || []).map((f) => ({
1196
1713
  path: f.path,
1197
1714
  type: f.type,
1198
- url: `${this.baseUrl}${f.url}`
1715
+ url: `${this.baseUrl}${f.url}${qs}`
1199
1716
  }))
1200
1717
  };
1201
1718
  }