### Install Olgitbridge Source: https://github.com/chazeon/olgitbridge/blob/main/README.md Clone the repository, navigate to the directory, and install dependencies using npm. This is the initial setup step for the olgitbridge. ```bash git clone https://gitlab.com/chazeon/olgitbridge.git cd olgitbridge npm install ``` -------------------------------- ### Starting the Olgitbridge Server Source: https://context7.com/chazeon/olgitbridge/llms.txt Commands to start the Olgitbridge server. Use `authbind` to bind to privileged ports (80/443) without root. The server listens on the configured port. ```bash # Plain start node src/server.js ``` ```bash # Using authbind to bind port 80/443 without root authbind node src/server.js ``` ```bash # Expected console output # [*] listening on port 5000 ``` -------------------------------- ### Run Sample Echo Server Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/README.md Starts a sample WebSocket echo server using Ruby. The first argument specifies the domain from which HTML pages can connect. ```bash $ ruby web-socket-ruby/samples/echo_server.rb example.com 10081 ``` -------------------------------- ### Start Olgitbridge Server Source: https://github.com/chazeon/olgitbridge/blob/main/README.md Start the olgitbridge server using Node.js. If running on ports 80 or 443, consider using authbind for elevated privileges. ```bash authbind node src/server.js ``` -------------------------------- ### Build WebSocketMain.swf Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/README.md Instructions for building the WebSocketMain.swf file using the Flex 4 SDK. Ensure you have the SDK installed before running the build script. ```bash cd flash-src ./build.sh ``` -------------------------------- ### Olgitbridge Configuration (`config.js`) Source: https://context7.com/chazeon/olgitbridge/llms.txt Defines runtime settings for Olgitbridge, including Overleaf server URL, data directories, cache timeouts, SSL configuration, and port settings. Edit this file before starting the server or building the Docker image. ```javascript // config.js const config = module.exports = { forward: { }, ssl: { } }; // URL of the target Overleaf CE/Pro server config.olServer = 'http://overleaf.example.com'; // Base directory for all working data (must be absolute, trailing slash required) config.baseDir = '/var/olgitbridge/'; // Subdirectories (derived from baseDir automatically) config.bluesDir = config.baseDir + 'blues/'; // blueprint copies from Overleaf config.hashDir = config.baseDir + 'hash/'; // zip content hashes (change detection) config.padsDir = config.baseDir + 'pads/'; // working-tree git clones config.reposDir = config.baseDir + 'repos/'; // bare git repositories served to clients // How long (ms) to cache a previous downsync before re-downloading from Overleaf config.downSyncTimeout = 30000; // TLS — set enable: true and provide paths to key/cert files for HTTPS config.ssl.enable = false; config.ssl.key = '/etc/ssl/private/server.key'; config.ssl.cert = '/etc/ssl/certs/server.crt'; // Port the git bridge listens on (use 443 for direct HTTPS) config.port = 5000; // Optional: forward plain HTTP requests to the HTTPS endpoint config.forward.enable = false; config.forward.target = 'https://gitbridge.example.com'; config.forward.port = 80; ``` -------------------------------- ### Olgitbridge Server Startup Logic Source: https://context7.com/chazeon/olgitbridge/llms.txt Internal server startup logic that ensures necessary directories exist and creates an HTTP or HTTPS server based on the SSL configuration. The `serve` function handles all incoming requests. ```javascript // Internally, server startup looks like this: const start = async function() { // Ensure working directories exist for (let dir of [reposDir, padsDir, bluesDir, hashDir]) { try { await fs.mkdir(dir); } catch (e) { if (e.code !== 'EEXIST') throw e; } } if (config.ssl.enable) { const httpsOptions = { key: await fs.readFile(config.ssl.key), cert: await fs.readFile(config.ssl.cert), }; https.createServer(httpsOptions, serve).listen(config.port); } else { http.createServer(serve).listen(config.port); } console.log('[*] listening on port', config.port); }; start(); ``` -------------------------------- ### Basic Connection and Event Handling Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Demonstrates how to establish a connection to a socket.io server, listen for events like 'connect', 'custom event', and 'disconnect', and send basic messages. ```APIDOC ## Basic Usage ### Description Connect to a socket.io server and handle basic events. ### Code Example ```js var socket = io.connect('http://domain.com'); socket.on('connect', function () { // socket connected }); socket.on('custom event', function () { // server emitted a custom event }); socket.on('disconnect', function () { // socket disconnected }); socket.send('hi there'); ``` ``` -------------------------------- ### Initialize and Connect WebSocket Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/sample.html Sets up the WebSocket connection and event handlers. Ensure WEB_SOCKET_SWF_LOCATION is correctly set to the path of WebSocketMain.swf. ```javascript WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; WEB_SOCKET_DEBUG = true; var ws; function init() { ws = new WebSocket("ws://localhost:10081/"); ws.onopen = function() { output("onopen"); }; ws.onmessage = function(e) { output("onmessage: " + e.data); }; ws.onclose = function() { output("onclose"); }; ws.onerror = function() { output("onerror"); }; } ``` -------------------------------- ### io.connect(uri, [options]) Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Establishes a connection to the socket.io server. Allows configuration of various connection options. ```APIDOC ## io.connect ### Description Connects to a socket.io server with optional configuration. ### Signature ```js io.connect(uri, [options]); ``` ### Parameters #### uri (string) The server URI to connect to. #### options (object) Optional configuration object. ##### Options: - *resource* (string): The resource name for socket.io connections. - *transports* (array): An array of transport methods to attempt, in order of preference. Example: `['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling']` - *'connect timeout'* (number): Milliseconds to wait for a transport to establish a connection before timing out. Default: `5000`. - *'try multiple transports'* (boolean): Whether to try other transports if the initial one times out. Default: `true`. - *reconnect* (boolean): Whether to automatically attempt to reconnect if the connection is lost. Default: `true`. - *'reconnection delay'* (number): Milliseconds to wait before the first reconnection attempt. Subsequent attempts use exponential backoff. Default: `500`. - *'max reconnection attempts'* (number): The number of reconnection attempts to make before giving up. Default: `10`. ### Properties - *options* (object): The merged default and provided options. - *connected* (boolean): Indicates if the socket is currently connected. - *connecting* (boolean): Indicates if the socket is currently attempting to connect. - *reconnecting* (boolean): Indicates if the socket is currently in the process of reconnecting. - *transport* (object): The current transport instance. ### Methods - *connect(λ)*: Establishes a connection. If a callback function `λ` is provided, it will be executed once the connection is established. - *send(message)*: Sends a string message to the server. - *disconnect*: Closes the connection to the server. - *on(event, λ)*: Adds a listener function `λ` for a specific event `event`. - *once(event, λ)*: Adds a one-time listener function `λ` for a specific event `event`. The listener is removed after it is triggered. - *removeListener(event, λ)*: Removes a specific listener function `λ` for a given event `event`. ### Events - *connect*: Fired when the connection is successfully established. - *connecting(transport_type)*: Fired when a connection attempt is made, with the transport type. - *connect_failed*: Fired when a connection attempt times out after all possible transports have been tried (if `tryTransportsOnConnectTimeout` is set). - *message(message)*: Fired when a message is received from the server. - *close*: Fired when the connection is closed. Note: Some transports may fire this for temporary disconnections. - *disconnect*: Fired when the connection is considered disconnected. - *reconnect(transport_type, reconnectionAttempts)*: Fired when the connection has been re-established. - *reconnecting(reconnectionDelay, reconnectionAttempts)*: Fired when a reconnection attempt is made, providing the delay for the next attempt. - *reconnect_failed*: Fired when all reconnection attempts have failed. ``` -------------------------------- ### Utilizing Namespaces Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Shows how to connect to specific namespaces on the server by including the namespace in the connection URI. ```APIDOC ## Namespaces ### Description Connect to different namespaces on the socket.io server. ### Code Example ```js // Connect to the '/chat' namespace var chat = io.connect('http://localhost/chat'); chat.on('connect', function () { // chat socket connected }); // Connect to the '/news' namespace (auto-detects host) var news = io.connect('/news'); news.on('connect', function () { // news socket connected }); ``` ``` -------------------------------- ### Basic Socket.IO Connection and Event Handling Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Connect to a Socket.IO server and listen for connection, custom events, and disconnection. ```javascript var socket = io.connect('http://domain.com'); socket.on('connect', function () { // socket connected }); socket.on('custom event', function () { // server emitted a custom event }); socket.on('disconnect', function () { // socket disconnected }); socket.send('hi there'); ``` -------------------------------- ### Join Project via Socket.IO - olops.joinProject Source: https://context7.com/chazeon/olgitbridge/llms.txt Connects to the Overleaf real-time server via Socket.IO, emits 'joinProject', and returns the full project metadata, including the root folder structure. ```APIDOC ## Join Project via Socket.IO — `olops.joinProject` Connects to the Overleaf real-time server using a vendored Socket.IO client, emits `joinProject`, and returns the full project metadata object (including `rootFolder`). Retries automatically on timeout. ```js const projectInfo = await olops.joinProject( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1' ); // projectInfo.rootFolder[0] contains the full recursive file/folder tree: // { // _id: 'abc', name: 'rootFolder', // docs: [{ _id: '...', name: 'main.tex' }, ...], // fileRefs: [{ _id: '...', name: 'figure.png' }, ...], // folders: [{ _id: '...', name: 'sections', docs: [...], ... }] // } ``` ``` -------------------------------- ### Integrate web-socket-js in HTML Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/README.md Includes the necessary JavaScript libraries and demonstrates how to instantiate and use the WebSocket client, mimicking the native WebSocket API. ```html ``` -------------------------------- ### Socket.IO Client Connection Options Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Configuration options for establishing a Socket.IO connection, including resource, transports, timeouts, and reconnection settings. ```javascript io.connect(uri, [options]); ``` ```javascript ['websocket', 'flashsocket', 'htmlfile', 'xhr-multipart', 'xhr-polling', 'jsonp-polling'] ``` ```javascript 5000 ``` ```javascript true ``` ```javascript true ``` ```javascript 500 ``` ```javascript 10 ``` -------------------------------- ### Async Spawn Git Commands Source: https://context7.com/chazeon/olgitbridge/llms.txt Use this utility to execute Git commands asynchronously. It resolves with combined stdout/stderr on success (exit code 0) or rejects with the output string on failure. Ensure the `aspawn` module is imported. ```javascript const aspawn = require('./src/aspawn'); // Resolves with combined output string on success const output = await aspawn('/usr/bin/git', ['status'], { cwd: '/tmp/myrepo' }); console.log(output); // "On branch main" nothing to commit..." // Rejects with the combined output string on non-zero exit try { await aspawn('/usr/bin/git', ['push'], { cwd: '/tmp/myrepo' }); } catch (err) { console.error('git push failed:', err); // err is a string, not an Error object } ``` -------------------------------- ### Git Operations — src/git.js Source: https://context7.com/chazeon/olgitbridge/llms.txt Provides an async wrapper for system Git commands: init, clone, pull, and save (stage, commit, push). Errors like 'nothing to commit' are logged, not thrown. ```javascript const git = require('./src/git'); // Initialise a new bare repository (used when a project is first accessed) await git.init('/var/olgitbridge/repos/63f1a2b3c4d5e6f7a8b9c0d1/'); // Clone the bare repo into the pad directory (working tree for file diffs) await git.clone( '/var/olgitbridge/repos/63f1a2b3c4d5e6f7a8b9c0d1/', '/var/olgitbridge/pads/' ); // Pull latest commits from origin (called after every git-receive-pack) await git.pull('/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/'); // Stage everything, commit, and push back to the bare repo // (used to commit a fresh downsync from Overleaf) await git.save('[1]', '/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/', 'synced by olgitbridge'); // git errors (e.g. "nothing to commit") are caught and logged, not thrown ``` -------------------------------- ### Join Project via Socket.IO Source: https://context7.com/chazeon/olgitbridge/llms.txt Connects to the Overleaf real-time server using a Socket.IO client, emits the 'joinProject' event, and returns the full project metadata. It includes automatic retries on timeout. ```javascript const projectInfo = await olops.joinProject( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1' ); // projectInfo.rootFolder[0] contains the full recursive file/folder tree: // { // _id: 'abc', name: 'rootFolder', // docs: [{ _id: '...', name: 'main.tex' }, ...], // fileRefs: [{ _id: '...', name: 'figure.png' }, ...], // folders: [{ _id: '...', name: 'sections', docs: [...], ... }] // } ``` -------------------------------- ### Upsync Logic — src/upsync.js Source: https://context7.com/chazeon/olgitbridge/llms.txt Compares local pad directory with Overleaf state to upload changes, new files, and remove deleted files. Requires project info (id, padDir, blueDir) and an Overleaf client. ```javascript const upsync = require('./src/upsync'); // project must have: id, padDir, blueDir // project.info and project.tree are populated internally by joinProject/buildTree await upsync(client, 'http://overleaf.example.com', project); // Actions taken per file: // padData !== blueData → POST /project/:id/upload?folder_id=:folderId (update) // file in pad, not blue → POST /project/:id/upload?folder_id=:folderId (new file) // file in blue, not pad → DELETE /project/:id/doc/:id (or /file/, /folder/) ``` -------------------------------- ### Downsync Overleaf Project Source: https://context7.com/chazeon/olgitbridge/llms.txt Downloads the current Overleaf project as a zip, computes a content hash, and compares it to a cached hash. It only unpacks to pad and blueprint directories if the content has changed. ```javascript const downsync = require('./src/downsync'); // Returns true → zip was new, pad/blue directories updated, caller should git-commit // Returns false → zip hash identical to last run, no work done const changed = await downsync(client, 'http://overleaf.example.com', project); if (changed) { // project.padDir now contains the latest Overleaf files // project.blueDir is an identical copy used later as a diff baseline for upsync await git.save(count, project.padDir, 'synced by olgitbridge'); } ``` -------------------------------- ### Zip Download - olops.downloadZip Source: https://context7.com/chazeon/olgitbridge/llms.txt Downloads the project as a zip file from the Overleaf server using the project ID and returns the raw binary buffer. ```APIDOC ## Zip Download — `olops.downloadZip` Downloads `GET /Project//download/zip` and returns the raw binary buffer. The project ID is the same hex string visible in the Overleaf project URL. ```js const zipBuffer = await olops.downloadZip( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1' // project_id ); // zipBuffer is a Buffer/ArrayBuffer; pass to unzipper for extraction: const { Open } = require('unzipper'); const directory = await Open.buffer(zipBuffer); await directory.extract({ path: '/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/' }); ``` ``` -------------------------------- ### Docker Deployment Commands Source: https://context7.com/chazeon/olgitbridge/llms.txt Commands for building and running the Olgitbridge Docker image. Mount `/var/olgitbridge/` to persist data. For HTTPS, bind-mount SSL certificate files. ```bash # Build the image (edit config.js first) docker build -t olgitbridge . ``` ```bash # Run with persisted data volume docker run -d \ --name olgitbridge \ -p 5000:5000 \ -v /host/data/olgitbridge:/var/olgitbridge \ olgitbridge ``` ```bash # Run with HTTPS (bind-mount cert files) docker run -d \ --name olgitbridge \ -p 443:443 \ -v /host/data/olgitbridge:/var/olgitbridge \ -v /etc/letsencrypt/live/example.com:/certs:ro \ olgitbridge ``` -------------------------------- ### Utilizing Namespaces for Multiple Sockets Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Connect to different namespaces on the server to manage multiple independent sockets. The host can be auto-detected if not specified. ```javascript var chat = io.connect('http://localhost/chat'); chat.on('connect', function () { // chat socket connected }); var news = io.connect('/news'); // io.connect auto-detects host news.on('connect', function () { // news socket connected }); ``` -------------------------------- ### Build File Tree — `olops.buildTree` Source: https://context7.com/chazeon/olgitbridge/llms.txt Converts a nested folder structure into a flat, name-keyed tree for efficient lookups. This is essential for the upsync logic. ```APIDOC ## Build File Tree — `olops.buildTree` ### Description Converts the nested `rootFolder` structure returned by `joinProject` into a flat, name-keyed tree used by the upsync logic for O(1) lookups. ### Usage ```js const tree = olops.buildTree(projectInfo.rootFolder[0]); ``` ### Returns A recursive object representing the file tree: ```json { "type": "folder", "id": "abc", "name": "rootFolder", "subs": { "main.tex": { "type": "doc", "id": "...", "name": "main.tex", "branch": "" }, "figure.png": { "type": "file", "id": "...", "name": "figure.png", "branch": "" }, "sections": { "type": "folder", "id": "...", "name": "sections", "subs": { ... } } } } ``` ``` -------------------------------- ### Git Operations — `src/git.js` Source: https://context7.com/chazeon/olgitbridge/llms.txt Provides an async wrapper for system Git commands, including init, clone, pull, and save (stage, commit, push). ```APIDOC ## Git Operations — `src/git.js` ### Description A thin async wrapper around the system `git` binary (`/usr/bin/git`) covering the four operations olgitbridge needs: initialise a bare repo, clone it, pull, and stage-commit-push. ### Operations 1. **Initialize Bare Repository** Used when a project is first accessed. ```js await git.init('/var/olgitbridge/repos/63f1a2b3c4d5e6f7a8b9c0d1/'); ``` 2. **Clone Repository** Clones the bare repo into the pad directory (working tree for file diffs). ```js await git.clone( '/var/olgitbridge/repos/63f1a2b3c4d5e6f7a8b9c0d1/', '/var/olgitbridge/pads/' ); ``` 3. **Pull Changes** Pulls latest commits from origin. Called after every `git-receive-pack`. ```js await git.pull('/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/'); ``` 4. **Save Changes** Stages everything, commits, and pushes back to the bare repo. Used to commit a fresh downsync from Overleaf. ```js await git.save('[1]', '/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/', 'synced by olgitbridge'); ``` ### Error Handling Git errors (e.g., "nothing to commit") are caught and logged, not thrown. ``` -------------------------------- ### Upsync — `src/upsync.js` Source: https://context7.com/chazeon/olgitbridge/llms.txt Synchronizes the local pad directory with the Overleaf project state. It uploads changed/new files and removes deleted files from Overleaf. ```APIDOC ## Upsync — `src/upsync.js` ### Description After a `git push`, compares the pad directory (updated working tree) against the blueprint directory (last known Overleaf state) and uploads only the changed or added files. Removes from Overleaf any files deleted locally. ### Usage ```js const upsync = require('./src/upsync'); // project must have: id, padDir, blueDir // project.info and project.tree are populated internally by joinProject/buildTree await upsync(client, 'http://overleaf.example.com', project); ``` ### Actions - **Update/New File**: If `padData !== blueData` or file exists in pad but not blue, `POST /project/:id/upload?folder_id=:folderId` is used. - **Delete File**: If file exists in blue but not pad, `DELETE /project/:id/doc/:id` (or `/file/`, `/folder/`) is used. ``` -------------------------------- ### Include and Instantiate XMLHttpRequest Source: https://github.com/chazeon/olgitbridge/blob/main/lib/xmlhttprequest/README.md Include the module in your project and create an instance of the XMLHttpRequest object. Ensure you use the lowercase string "xmlhttprequest" in your require() call, especially on case-sensitive file systems. ```javascript var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; var xhr = new XMLHttpRequest(); ``` -------------------------------- ### Emitting Custom Events Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Illustrates how to emit custom events to the server with associated data. ```APIDOC ## Emitting Custom Events ### Description Send custom events to the server with optional data. ### Code Example ```js var socket = io.connect(); socket.emit('server custom event', { my: 'data' }); ``` ``` -------------------------------- ### Download Project Zip Buffer Source: https://context7.com/chazeon/olgitbridge/llms.txt Downloads the Overleaf project zip file from the specified project ID and returns the raw binary buffer. This buffer can then be passed to an unzipper for extraction. ```javascript const zipBuffer = await olops.downloadZip( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1' // project_id ); // zipBuffer is a Buffer/ArrayBuffer; pass to unzipper for extraction: const { Open } = require('unzipper'); const directory = await Open.buffer(zipBuffer); await directory.extract({ path: '/var/olgitbridge/pads/63f1a2b3c4d5e6f7a8b9c0d1/' }); ``` -------------------------------- ### Build File Tree — olops.buildTree Source: https://context7.com/chazeon/olgitbridge/llms.txt Converts a nested folder structure into a flat, name-keyed tree for efficient lookups. The output is a recursive object representing the project's file hierarchy. ```javascript const tree = olops.buildTree(projectInfo.rootFolder[0]); // Returns a recursive object: // { // type: 'folder', id: 'abc', name: 'rootFolder', // subs: { // 'main.tex': { type: 'doc', id: '...', name: 'main.tex', branch: }, // 'figure.png': { type: 'file', id: '...', name: 'figure.png', branch: }, // 'sections': { type: 'folder', id: '...', name: 'sections', subs: { ... } } // } // } ``` -------------------------------- ### Add Folder — `olops.addFolder` Source: https://context7.com/chazeon/olgitbridge/llms.txt Creates a new folder within an Overleaf project. It returns the new folder's ID, which can be used for subsequent uploads. ```APIDOC ## Add Folder — `olops.addFolder` ### Description Creates a new folder inside an Overleaf project by POSTing to `/project/:id/folder`. Returns the new folder's `_id` for use in subsequent uploads. ### Usage ```js const res = await olops.addFolder( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1', // project_id 'parent_folder_id_here', // parent folder_id 'sections' // new folder name ); const newFolderId = res.data._id; ``` ### Behavior If the folder already exists, `upsync` catches 'file already exists' and returns the sentinel string 'EXISTS' instead of throwing. ``` -------------------------------- ### Downsync - src/downsync.js Source: https://context7.com/chazeon/olgitbridge/llms.txt Downloads the Overleaf project as a zip, computes a content hash, and unpacks files only if the content has changed since the last run. ```APIDOC ## Downsync — `src/downsync.js` Downloads the current Overleaf project as a zip, computes a content hash (path + size + CRC32 of each entry), compares it to the cached hash, and only unpacks to the pad and blueprint directories when content has changed. ```js const downsync = require('./src/downsync'); // Returns true → zip was new, pad/blue directories updated, caller should git-commit // Returns false → zip hash identical to last run, no work done const changed = await downsync(client, 'http://overleaf.example.com', project); if (changed) { // project.padDir now contains the latest Overleaf files // project.blueDir is an identical copy used later as a diff baseline for upsync await git.save(count, project.padDir, 'synced by olgitbridge'); } ``` ``` -------------------------------- ### Add Folder — olops.addFolder Source: https://context7.com/chazeon/olgitbridge/llms.txt Creates a new folder within an Overleaf project. Returns the new folder's ID for subsequent operations. Handles existing folders by returning 'EXISTS' instead of throwing. ```javascript const res = await olops.addFolder( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1', // project_id 'parent_folder_id_here', // parent folder_id 'sections' // new folder name ); const newFolderId = res.data._id; // If the folder already exists, upsync catches 'file already exists' // and returns the sentinel string 'EXISTS' instead of throwing. ``` -------------------------------- ### Cloning an Overleaf Project via Git Source: https://context7.com/chazeon/olgitbridge/llms.txt Clones an Overleaf project using its project ID. Git will prompt for Overleaf email and password for authentication. The `.git` suffix is also accepted. ```bash # Clone a project — git will prompt for Overleaf email and password git clone http://gitbridge.example.com:5000/ # or with .git suffix (both are accepted): git clone http://gitbridge.example.com:5000/.git ``` ```bash # Example with inline credentials (not recommended for production) git clone http://user@example.com:password@gitbridge.example.com:5000/63f1a2b3c4d5e6f7a8b9c0d1 ``` -------------------------------- ### HTTP Basic Authentication - handleAuth Source: https://context7.com/chazeon/olgitbridge/llms.txt Handles HTTP Basic Authentication for incoming requests. It checks for the Authorization header, decodes credentials, and serializes concurrent user requests. ```APIDOC ## HTTP Basic Authentication — `handleAuth` On every request the server challenges git clients with HTTP 401 if no `Authorization` header is present, then uses the supplied Overleaf credentials to log in. A per-user semaphore ensures only one concurrent session per email address. ```js // Internally inside src/server.js — called on every incoming request const handleAuth = async function(req, res, client, project_id) { let auth = req.headers.authorization; if (!auth) { // 401 triggers git's credential helper to prompt the user res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="olgitbridge"' }); res.end('Authorization is needed'); return false; } // Decode "Basic base64(email:password)" auth = Buffer.from(auth.replace(/^Basic /, ''), 'base64').toString('utf8').split(':'); const email = auth[0]; const password = auth[1]; // Serialise concurrent requests from the same user const uflag = await users.get(email); try { await olops.login(client, olServer, email, password); await olops.getProjectPage(client, olServer, project_id); } catch(e) { users.release(email, uflag); if (e.response.status === 401) { res.writeHead(401, 'Unauthorized'); res.end(); return; } throw e; } return Object.freeze({ email, uflag }); }; ``` ``` -------------------------------- ### Handle HTTP Basic Authentication Source: https://context7.com/chazeon/olgitbridge/llms.txt Handles incoming HTTP requests, checks for the Authorization header, and decodes Overleaf credentials. It serializes concurrent requests from the same user and throws a 401 error if authentication fails. ```javascript const handleAuth = async function(req, res, client, project_id) { let auth = req.headers.authorization; if (!auth) { // 401 triggers git's credential helper to prompt the user res.writeHead(401, { 'WWW-Authenticate': 'Basic realm="olgitbridge"' }); res.end('Authorization is needed'); return false; } // Decode "Basic base64(email:password)" auth = Buffer.from(auth.replace(/^Basic /, ''), 'base64').toString('utf8').split(':'); const email = auth[0]; const password = auth[1]; // Serialise concurrent requests from the same user const uflag = await users.get(email); try { await olops.login(client, olServer, email, password); await olops.getProjectPage(client, olServer, project_id); } catch(e) { users.release(email, uflag); if (e.response.status === 401) { res.writeHead(401, 'Unauthorized'); res.end(); return; } throw e; } return Object.freeze({ email, uflag }); }; ``` -------------------------------- ### Overleaf Login with Axios Client Source: https://context7.com/chazeon/olgitbridge/llms.txt Logs into Overleaf by fetching the login page, extracting the CSRF token, and POSTing credentials. The axios client automatically retains the session cookie. ```javascript const olops = require('./src/olops'); const client = olops.client(); // axios instance with cookie jar await olops.login(client, 'http://overleaf.example.com', 'alice@example.com', 's3cr3t'); // Session cookie is now stored in the client's CookieJar and sent on all subsequent requests. // Throws with e.response.status === 401 if credentials are wrong. ``` -------------------------------- ### CSRF Token Extraction - olops.getProjectPage Source: https://context7.com/chazeon/olgitbridge/llms.txt Fetches the project page after login to extract the CSRF token from the meta tag and sets it as a default header for the axios client. ```APIDOC ## CSRF Token Extraction — `olops.getProjectPage` Fetches `/project/` after login and stores the CSRF token found in the page's `` tag as a default header on the axios client, making it available for all subsequent mutating API calls. ```js await olops.getProjectPage(client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1'); // After this call: // client.defaults.headers.common['x-csrf-token'] === '' ``` ``` -------------------------------- ### Upload File — olops.upload Source: https://context7.com/chazeon/olgitbridge/llms.txt Uploads a single file or document to Overleaf via multipart/form-data POST. Requires Overleaf client, project ID, folder ID, filename, and file data as a Buffer. Throws errors on non-2xx responses. ```javascript const data = await fs.readFile('/var/olgitbridge/pads//main.tex'); await olops.upload( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1', // project_id 'root_folder_id_here', // folder_id (from buildTree) 'main.tex', // filename data // Buffer ); // Throws Error(' ') on non-2xx responses ``` -------------------------------- ### Extract CSRF Token from Project Page Source: https://context7.com/chazeon/olgitbridge/llms.txt Fetches the Overleaf project page after login and extracts the CSRF token from a meta tag. This token is then set as a default header for subsequent mutating API calls. ```javascript await olops.getProjectPage(client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1'); // After this call: // client.defaults.headers.common['x-csrf-token'] === '' ``` -------------------------------- ### Pushing Changes to Overleaf via Git Source: https://context7.com/chazeon/olgitbridge/llms.txt Commits and pushes local changes back to Overleaf. Olgitbridge compares the push against the last downloaded blueprint and uploads only the modified files. ```bash # Make changes and push back to Overleaf cd 63f1a2b3c4d5e6f7a8b9c0d1 echo "\section{New Section}" >> main.tex git add main.tex git commit -m "Add new section" git push # olgitbridge diffs the push against the last downloaded blueprint # and uploads only the changed files back to Overleaf ``` -------------------------------- ### Set SWF Location for Cross-Domain Hosting Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/README.md Configure the JavaScript to point to the SWF file when hosting HTML and SWF files on different domains. This allows cross-domain communication but reduces security by allowing arbitrary TCP data. ```javascript WEB_SOCKET_SWF_LOCATION = "URL of your WebSocketMainInsecure.swf"; ``` -------------------------------- ### Forcing Disconnection Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Demonstrates how to manually disconnect the socket client from the server. ```APIDOC ## Forcing Disconnection ### Description Manually close the connection to the socket.io server. ### Code Example ```js var socket = io.connect(); socket.on('connect', function () { socket.disconnect(); }); ``` ``` -------------------------------- ### File Upload — `olops.upload` Source: https://context7.com/chazeon/olgitbridge/llms.txt Uploads a single file or document to Overleaf using a multipart/form-data POST request to the project's upload endpoint. ```APIDOC ## File Upload — `olops.upload` ### Description Uploads a single file or document to Overleaf using a `multipart/form-data` POST to the project upload endpoint. ### Usage ```js const data = await fs.readFile('/var/olgitbridge/pads//main.tex'); await olops.upload( client, 'http://overleaf.example.com', '63f1a2b3c4d5e6f7a8b9c0d1', // project_id 'root_folder_id_here', // folder_id (from buildTree) 'main.tex', // filename data // Buffer ); ``` ### Error Handling Throws `Error(' ')` on non-2xx responses. ``` -------------------------------- ### Overleaf Logout - olops.logout Source: https://context7.com/chazeon/olgitbridge/llms.txt Logs out of the Overleaf session by fetching the project dashboard for a fresh CSRF token and then POSTing to the logout endpoint. ```APIDOC ## Overleaf Logout — `olops.logout` Fetches the project dashboard (to obtain a fresh CSRF token) and then POSTs to `/logout`, cleanly ending the Overleaf session. ```js // Called automatically at the end of every git request await olops.logout(client, 'http://overleaf.example.com'); // The session cookie is invalidated on the Overleaf server. ``` ``` -------------------------------- ### Overleaf Login - olops.login Source: https://context7.com/chazeon/olgitbridge/llms.txt Logs into Overleaf by fetching the login page, extracting the CSRF token, and POSTing credentials. The axios client automatically manages the session cookie. ```APIDOC ## Overleaf Login — `olops.login` Fetches the Overleaf login page, extracts the CSRF token from a hidden form field, and POSTs credentials. The axios client retains the session cookie automatically via `tough-cookie`. ```js const olops = require('./src/olops'); const client = olops.client(); // axios instance with cookie jar await olops.login(client, 'http://overleaf.example.com', 'alice@example.com', 's3cr3t'); // Session cookie is now stored in the client's CookieJar and sent on all subsequent requests. // Throws with e.response.status === 401 if credentials are wrong. ``` ``` -------------------------------- ### Semaphore — `src/semaphore.js` Source: https://context7.com/chazeon/olgitbridge/llms.txt A promise-based FIFO semaphore designed to serialize concurrent requests, ensuring that operations like Git or user requests are processed sequentially. ```APIDOC ## Semaphore — `src/semaphore.js` ### Description A promise-based FIFO semaphore used to serialise concurrent git or user requests. Each `request()` call returns a unique frozen flag object; the same flag must be passed to `release()`. ### Usage ```js const Semaphore = require('./src/semaphore'); const sem = new Semaphore(); async function worker(id) { const flag = await sem.request(); // blocks if another worker holds the semaphore try { console.log(`Worker ${id} has the lock`); await doExclusiveWork(); } finally { sem.release(flag); // MUST pass the same flag returned by request() } } // Concurrent calls are queued and served in FIFO order Promise.all([worker(1), worker(2), worker(3)]); // Output: Worker 1 has the lock → Worker 2 has the lock → Worker 3 has the lock ``` ``` -------------------------------- ### Enable Debugging for web-socket-js Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/README.md Enables debug logging for the web-socket-js library. This is useful for troubleshooting by outputting errors to the browser's developer console. ```javascript WEB_SOCKET_DEBUG = true; ``` -------------------------------- ### Emitting Custom Events Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Emit custom events to the server with associated data. This allows for more structured communication beyond the default 'message' event. ```javascript var socket = io.connect(); socket.emit('server custom event', { my: 'data' }); ``` -------------------------------- ### Send Message via WebSocket Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/sample.html Sends a message from an input field to the WebSocket server. The message is then logged to the console. ```javascript function onSubmit() { var input = document.getElementById("input"); ws.send(input.value); output("send: " + input.value); input.value = ""; input.focus(); } ``` -------------------------------- ### Overleaf Logout Source: https://context7.com/chazeon/olgitbridge/llms.txt Logs out of the Overleaf session by fetching the project dashboard for a CSRF token and then POSTing to the logout endpoint. This invalidates the session cookie on the server. ```javascript // Called automatically at the end of every git request await olops.logout(client, 'http://overleaf.example.com'); // The session cookie is invalidated on the Overleaf server. ``` -------------------------------- ### Semaphore for Concurrency Control — src/semaphore.js Source: https://context7.com/chazeon/olgitbridge/llms.txt A promise-based FIFO semaphore to serialize concurrent requests. Each request returns a flag that must be passed to release(). ```javascript const Semaphore = require('./src/semaphore'); const sem = new Semaphore(); async function worker(id) { const flag = await sem.request(); // blocks if another worker holds the semaphore try { console.log(`Worker ${id} has the lock`); await doExclusiveWork(); } finally { sem.release(flag); // MUST pass the same flag returned by request() } } // Concurrent calls are queued and served in FIFO order Promise.all([worker(1), worker(2), worker(3)]); // Output: Worker 1 has the lock → Worker 2 has the lock → Worker 3 has the lock ``` -------------------------------- ### Output Log Messages Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/sample.html Appends messages to the log element on the page, escaping HTML special characters to prevent rendering issues. ```javascript function output(str) { var log = document.getElementById("log"); var escaped = str.replace(/&/, "&").replace(//, ">").replace(/"/, """); log.innerHTML = escaped + "
" + log.innerHTML; } ``` -------------------------------- ### Delete Entity — `olops.remove` Source: https://context7.com/chazeon/olgitbridge/llms.txt Deletes a document, binary file, or folder from an Overleaf project using the appropriate REST endpoint. ```APIDOC ## Delete Entity — `olops.remove` ### Description Deletes a document, binary file, or folder from an Overleaf project using the appropriate REST endpoint. ### Usage ```js // Remove a doc await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'doc', 'doc_id_here'); // Remove a binary file await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'file', 'file_id_here'); // Remove a folder (recursively on Overleaf's side) await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'folder', 'folder_id_here'); ``` ### Error Handling Throws `Error()` for unknown entity types. ``` -------------------------------- ### Delete Entity — olops.remove Source: https://context7.com/chazeon/olgitbridge/llms.txt Deletes a document, binary file, or folder from an Overleaf project using the appropriate REST endpoint. Throws an error for unknown entity types. ```javascript // Remove a doc await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'doc', 'doc_id_here'); // Remove a binary file await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'file', 'file_id_here'); // Remove a folder (recursively on Overleaf's side) await olops.remove(client, 'http://overleaf.example.com', '63f1a2...', 'folder', 'folder_id_here'); // Throws Error() for unknown entity types ``` -------------------------------- ### Forcing Disconnection Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/README.md Manually disconnect the socket from the server. This is often done within a 'connect' event handler to immediately close the connection. ```javascript var socket = io.connect(); socket.on('connect', function () { socket.disconnect(); }); ``` -------------------------------- ### Close WebSocket Connection Source: https://github.com/chazeon/olgitbridge/blob/main/lib/socket.io-client/lib/vendor/web-socket-js/sample.html Closes the active WebSocket connection. ```javascript function onCloseClick() { ws.close(); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.