Compare commits

..
37 Commits
Author SHA1 Message Date
yu-i-i 3503a7d887 Fixes only for v5.4.1-ext-v3 2025-05-22 21:26:27 +02:00
yu-i-i 77b37b7cf8 Update README.md: Changes to Template Gallery and Sandboxed Compiles, v5.4.1-ext-v3 2025-05-22 21:26:27 +02:00
yu-i-i 047268b79d Template Gallery: replace markdown-it with marked 2025-05-22 04:12:38 +02:00
yu-i-i 527f60316a Refactor Template Gallery; resolves #38 and #39
- Replace free-text license input with a select box
- Improve visual presentation of modals and enhance keyboard interaction
2025-05-14 15:57:27 +02:00
yu-i-i b6eafbcc0a Refactor Sandboxed Compiles 2025-05-14 15:56:06 +02:00
yu-i-i ddd2789933 README.md: v5.4.0-v2 2025-05-05 11:20:48 +02:00
yu-i-i 7e91256ae3 Symbol Palette: improve keyboard input experience 2025-05-05 11:20:48 +02:00
yu-i-i ea2c644695 Symbol Palette: get rid of @reach/tabs 2025-05-05 11:20:48 +02:00
yu-i-i 281174eee9 Add 'poll' to clsi seccomp profile, fixes minted. Thanks, David. 2025-05-05 11:20:48 +02:00
yu-i-i de65f2b785 Update README.md: Template Gallery 2025-05-05 11:20:48 +02:00
yu-i-i 9d9fbf06c4 Make Template Gallery optional; rename environment variables 2025-05-05 11:20:47 +02:00
yu-i-i 39ae15bda0 Add Template Gallery support 2025-05-05 11:19:40 +02:00
yu-i-i f9d7148b6c Enable From External URL feature 2025-05-05 04:55:53 +02:00
yu-i-i dbc3bbe9aa Minor changes in README.md 2025-05-05 04:48:17 +02:00
yu-i-i 6495cb3c76 Track changes / comments: update backend to support frontend changes 2025-05-05 04:48:17 +02:00
yu-i-i 76e9829b73 Allow EXTERNAL_AUTH to be undefined, fixes #26 2025-05-05 04:48:17 +02:00
yu-i-i 8ef6ad5c8e Clarify OIDC redirect URI in README.md (closes #28) 2025-05-05 04:48:17 +02:00
yu-i-i bbcdcce617 Symbol palette: switch to 'OL' UI components and apply minor cosmetic changes 2025-05-05 04:48:16 +02:00
yu-i-i 66b2de0750 Clarify OVERLEAF_OIDC_USER_ID_FIELD parameter usage (closes #24) 2025-05-05 04:48:16 +02:00
yu-i-i 7615dbef54 Make OVERLEAF_OIDC_USER_ID_FIELD support 'email' as a value 2025-05-05 04:48:16 +02:00
yu-i-i 0ff64f51b5 See upstream commit 42ee56e 2025-05-05 04:48:16 +02:00
yu-i-i 4a4957651f Fix glitches in symbol palette after switching to Bootstrap 5 2025-05-05 04:48:16 +02:00
yu-i-i 3414417298 Whitelist /oidc/login endpoint, fixes #21 2025-05-05 04:48:16 +02:00
yu-i-i cafe99d116 Update README.md (add ENV variables to control SAML signature validation) 2025-05-05 04:48:16 +02:00
yu-i-i 3a609993be Add ENV variables to control SAML signature validation 2025-05-05 04:48:16 +02:00
yu-i-i bcf43a4582 Update README.md 2025-05-05 04:48:16 +02:00
yu-i-i 1ee25c02b1 Re-export doLogout (was removed from exports in commit b9fb636). 2025-05-05 04:48:15 +02:00
yu-i-i 0e3af1c01b Refactor authentication code; add OIDC support 2025-05-05 04:48:15 +02:00
yu-i-i cd8e28b462 Allow adding extra flags to LaTeX compiler through environment variable 2025-05-05 04:48:15 +02:00
yu-i-i 035f7c894c Update README.md 2025-05-05 04:48:15 +02:00
yu-i-i 173bcce718 Enable LDAP and SAML authentication support 2025-05-05 04:48:15 +02:00
yu-i-i e56d52905b Enable Symbol Palette 2025-05-05 04:48:15 +02:00
yu-i-i d19eb59548 Allow selecting a TeX Live image for a project 2025-05-05 04:48:14 +02:00
Sam Van den Vonder 7513da4518 Enable Sandboxed Compiles feature 2025-05-05 04:48:14 +02:00
yu-i-i 8c1a06eb94 Enable autocomplete of reference keys feature 2025-05-05 04:48:14 +02:00
yu-i-i c345c0c940 Enable track changes and comments feature 2025-05-05 04:48:14 +02:00
yu-i-i c0651bc13d Redirect non-existing links to Overleaf page 2025-05-05 04:48:14 +02:00
4186 changed files with 205703 additions and 245689 deletions
-25
View File
@@ -1,25 +0,0 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[Makefile]
indent_style = tab
[*.go]
indent_style = tab
[*.{pug,coffee}]
indent_style = tab
[*.{pug,patch}]
trim_trailing_whitespace = false
[Jenkinsfile]
insert_final_newline = false
max_line_length = off
+44
View File
@@ -0,0 +1,44 @@
<!--
Note: If you are using www.overleaf.com and have a problem,
or if you would like to request a new feature please contact
the support team at support@overleaf.com
This form should only be used to report bugs in the
Community Edition release of Overleaf.
-->
<!-- BUG REPORT TEMPLATE -->
## Steps to Reproduce
<!-- Describe the steps leading up to when / where you found the bug. -->
<!-- Screenshots may be helpful here. -->
1.
2.
3.
## Expected Behaviour
<!-- What should have happened when you completed the steps above? -->
## Observed Behaviour
<!-- What actually happened when you completed the steps above? -->
<!-- Screenshots may be helpful here. -->
## Context
<!-- How has this issue affected you? What were you trying to accomplish? -->
## Technical Info
<!-- Provide any technical details that may be applicable (or N/A if not applicable). -->
* URL:
* Browser Name and version:
* Operating System and version (desktop or mobile):
* Signed in as:
* Project and/or file:
## Analysis
<!--- Optionally, document investigation of / suggest a fix for the bug, e.g. 'comes from this line / commit' -->
-53
View File
@@ -1,53 +0,0 @@
---
name: Bug report
about: Report a bug
title: ''
labels: type:bug
assignees: ''
---
<!--
Note: If you are using www.overleaf.com and have a problem,
or if you would like to request a new feature please contact
the support team at support@overleaf.com
This form should only be used to report bugs in the
Community Edition release of Overleaf.
-->
<!-- BUG REPORT TEMPLATE -->
## Steps to Reproduce
<!-- Describe the steps leading up to when / where you found the bug. -->
<!-- Screenshots may be helpful here. -->
1.
2.
3.
## Expected Behaviour
<!-- What should have happened when you completed the steps above? -->
## Observed Behaviour
<!-- What actually happened when you completed the steps above? -->
<!-- Screenshots may be helpful here. -->
## Context
<!-- How has this issue affected you? What were you trying to accomplish? -->
## Technical Info
<!-- Provide any technical details that may be applicable (or N/A if not applicable). -->
* URL:
* Browser Name and version:
* Operating System and version (desktop or mobile):
* Signed in as:
* Project and/or file:
## Analysis
<!--- Optionally, document investigation of / suggest a fix for the bug, e.g. 'comes from this line / commit' -->
+1 -1
View File
@@ -8,4 +8,4 @@
## Contributor Agreement
- [ ] I confirm I have signed the [Contributor License Agreement](https://github.com/overleaf/overleaf/blob/main/CONTRIBUTING.md#contributor-license-agreement)
- [ ] I confirm I have signed the [Contributor License Agreement](https://github.com/overleaf/overleaf/blob/master/CONTRIBUTING.md#contributor-license-agreement)
+1007 -19
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -42,7 +42,7 @@ To do this, use the included `bin/dev` script:
bin/dev
```
This will start all services using `node --watch`, which will automatically monitor the code and restart the services as necessary.
This will start all services using `nodemon`, which will automatically monitor the code and restart the services as necessary.
To improve performance, you can start only a subset of the services in development mode by providing a space-separated list to the `bin/dev` script:
@@ -77,6 +77,7 @@ each service:
| `filestore` | 9235 |
| `notifications` | 9236 |
| `real-time` | 9237 |
| `references` | 9238 |
| `history-v1` | 9239 |
| `project-history` | 9240 |
+1 -4
View File
@@ -6,18 +6,15 @@ DOCUMENT_UPDATER_HOST=document-updater
FILESTORE_HOST=filestore
GRACEFUL_SHUTDOWN_DELAY_SECONDS=0
HISTORY_V1_HOST=history-v1
HISTORY_REDIS_HOST=redis
LISTEN_ADDRESS=0.0.0.0
MONGO_HOST=mongo
MONGO_URL=mongodb://mongo/sharelatex?directConnection=true
NOTIFICATIONS_HOST=notifications
PROJECT_HISTORY_HOST=project-history
QUEUES_REDIS_HOST=redis
DSMP_REDIS_HOST=redis
REALTIME_HOST=real-time
REDIS_HOST=redis
REFERENCES_HOST=references
SESSION_SECRET=foo
V1_HISTORY_HOST=history-v1
WEBPACK_HOST=webpack
WEB_API_PASSWORD=overleaf
WEB_API_USER=overleaf
+14 -3
View File
@@ -80,14 +80,14 @@ services:
- ../services/history-v1/migrations:/overleaf/services/history-v1/migrations
notifications:
command: ["node", "--watch", "app.ts"]
command: ["node", "--watch", "app.js"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
- "127.0.0.1:9236:9229"
volumes:
- ../services/notifications/app:/overleaf/services/notifications/app
- ../services/notifications/app.ts:/overleaf/services/notifications/app.ts
- ../services/notifications/app.js:/overleaf/services/notifications/app.js
- ../services/notifications/config:/overleaf/services/notifications/config
project-history:
@@ -112,8 +112,19 @@ services:
- ../services/real-time/app.js:/overleaf/services/real-time/app.js
- ../services/real-time/config:/overleaf/services/real-time/config
references:
command: ["node", "--watch", "app.js"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
- "127.0.0.1:9238:9229"
volumes:
- ../services/references/app:/overleaf/services/references/app
- ../services/references/config:/overleaf/services/references/config
- ../services/references/app.js:/overleaf/services/references/app.js
web:
command: ["node", "--watch", "app.mjs", "--watch-locales"]
command: ["node", "--watch", "app.js", "--watch-locales"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
+15 -6
View File
@@ -1,5 +1,6 @@
volumes:
clsi-cache:
clsi-output:
filestore-public-files:
filestore-template-files:
filestore-uploads:
@@ -25,16 +26,15 @@ services:
env_file:
- dev.env
environment:
- DOCKER_RUNNER=true
- TEXLIVE_IMAGE=texlive-full # docker build texlive -t texlive-full
- SANDBOXED_COMPILES=true
- SANDBOXED_COMPILES_HOST_DIR_COMPILES=${PWD}/compiles
- SANDBOXED_COMPILES_HOST_DIR_OUTPUT=${PWD}/output
- COMPILES_HOST_DIR=${PWD}/compiles
user: root
volumes:
- ${PWD}/compiles:/overleaf/services/clsi/compiles
- ${PWD}/output:/overleaf/services/clsi/output
- ${DOCKER_SOCKET_PATH:-/var/run/docker.sock}:/var/run/docker.sock
- clsi-cache:/overleaf/services/clsi/cache
- clsi-output:/overleaf/services/clsi/output
contacts:
build:
@@ -69,6 +69,7 @@ services:
- filestore-public-files:/overleaf/services/filestore/public_files
- filestore-template-files:/overleaf/services/filestore/template_files
- filestore-uploads:/overleaf/services/filestore/uploads
- filestore-user-files:/overleaf/services/filestore/user_files
history-v1:
build:
@@ -122,7 +123,7 @@ services:
dockerfile: services/real-time/Dockerfile
env_file:
- dev.env
redis:
image: redis:5
ports:
@@ -130,6 +131,13 @@ services:
volumes:
- redis-data:/data
references:
build:
context: ..
dockerfile: services/references/Dockerfile
env_file:
- dev.env
web:
build:
context: ..
@@ -139,7 +147,7 @@ services:
- dev.env
environment:
- APP_NAME=Overleaf Community Edition
- ENABLED_LINKED_FILE_TYPES=project_file,project_output_file
- ENABLED_LINKED_FILE_TYPES=project_file,project_output_file,url
- EMAIL_CONFIRMATION_DISABLED=true
- NODE_ENV=development
- OVERLEAF_ALLOW_PUBLIC_ACCESS=true
@@ -160,6 +168,7 @@ services:
- notifications
- project-history
- real-time
- references
webpack:
build:
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 587 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+5 -12
View File
@@ -1,3 +1,4 @@
version: '2.2'
services:
sharelatex:
restart: always
@@ -31,7 +32,7 @@ services:
OVERLEAF_REDIS_HOST: redis
REDIS_HOST: redis
ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file'
ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file,url'
# Enables Thumbnail generation using ImageMagick
ENABLE_CONVERSIONS: 'true'
@@ -72,19 +73,11 @@ services:
## Server Pro ##
################
## The Community Edition is intended for use in environments where all users are trusted and is not appropriate for
## scenarios where isolation of users is required. Sandboxed Compiles are not available in the Community Edition,
## so the following environment variables must be commented out to avoid compile issues.
##
## Sandboxed Compiles: https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles
## Sandboxed Compiles: https://github.com/overleaf/overleaf/wiki/Server-Pro:-Sandboxed-Compiles
SANDBOXED_COMPILES: 'true'
### Bind-mount source for /var/lib/overleaf/data/compiles inside the container.
SANDBOXED_COMPILES_HOST_DIR_COMPILES: '/home/user/sharelatex_data/data/compiles'
### Bind-mount source for /var/lib/overleaf/data/output inside the container.
SANDBOXED_COMPILES_HOST_DIR_OUTPUT: '/home/user/sharelatex_data/data/output'
### Backwards compatibility (before Server Pro 5.5)
DOCKER_RUNNER: 'true'
SANDBOXED_COMPILES_SIBLING_CONTAINERS: 'true'
### Bind-mount source for /var/lib/overleaf/data/compiles inside the container.
SANDBOXED_COMPILES_HOST_DIR: '/home/user/sharelatex_data/data/compiles'
## Works with test LDAP server shown at bottom of docker compose
# OVERLEAF_LDAP_URL: 'ldap://ldap:389'
@@ -0,0 +1 @@
node_modules/
@@ -0,0 +1,46 @@
compileFolder
Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
.DS_Store?
ehthumbs.db
Icon?
Thumbs.db
/node_modules/*
data/*/*
**.swp
/log.json
hash_folder
.npmrc
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/access-token-encryptor/**
package-lock.json
package.json
patches/**
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
@@ -0,0 +1,6 @@
{
"ui": "bdd",
"recursive": "true",
"reporter": "spec",
"require": "test/setup.js"
}
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/access-token-encryptor/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/access-token-encryptor/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'access-token-encryptor-eslint', name: 'access-token-encryptor eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/access-token-encryptor/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/access-token-encryptor monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'access-token-encryptor test results', testResults: 'libraries/access-token-encryptor/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/access-token-encryptor/reports'
sh 'make clean_jenkins -j10'
}
}
}
@@ -1,8 +1,10 @@
access-token-encryptor
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
@@ -5,8 +5,8 @@
"main": "index.js",
"scripts": {
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
"test:ci": "npm run test:unit",
@@ -22,8 +22,6 @@
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"sandboxed-module": "^2.0.4",
"typescript": "^5.0.4"
}
@@ -1,8 +0,0 @@
module.exports = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
},
}
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+3
View File
@@ -0,0 +1,3 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc
@@ -1,8 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/o-error/**
package-lock.json
package.json
patches/**
-13
View File
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
+6
View File
@@ -0,0 +1,6 @@
{
"ui": "bdd",
"recursive": "true",
"reporter": "spec",
"require": "test/setup.js"
}
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/fetch-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/fetch-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'fetch-utils-eslint', name: 'fetch-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/fetch-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/fetch-utils monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'fetch-utils test results', testResults: 'libraries/fetch-utils/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/fetch-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+3 -1
View File
@@ -1,8 +1,10 @@
fetch-utils
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
+13 -19
View File
@@ -23,11 +23,11 @@ async function fetchJson(url, opts = {}) {
}
async function fetchJsonWithResponse(url, opts = {}) {
const { fetchOpts, detachSignal } = parseOpts(opts)
const { fetchOpts } = parseOpts(opts)
fetchOpts.headers = fetchOpts.headers ?? {}
fetchOpts.headers.Accept = fetchOpts.headers.Accept ?? 'application/json'
const response = await performRequest(url, fetchOpts, detachSignal)
const response = await performRequest(url, fetchOpts)
if (!response.ok) {
const body = await maybeGetResponseBody(response)
throw new RequestFailedError(url, opts, response, body)
@@ -53,8 +53,8 @@ async function fetchStream(url, opts = {}) {
}
async function fetchStreamWithResponse(url, opts = {}) {
const { fetchOpts, abortController, detachSignal } = parseOpts(opts)
const response = await performRequest(url, fetchOpts, detachSignal)
const { fetchOpts, abortController } = parseOpts(opts)
const response = await performRequest(url, fetchOpts)
if (!response.ok) {
const body = await maybeGetResponseBody(response)
@@ -76,8 +76,8 @@ async function fetchStreamWithResponse(url, opts = {}) {
* @throws {RequestFailedError} if the response has a failure status code
*/
async function fetchNothing(url, opts = {}) {
const { fetchOpts, detachSignal } = parseOpts(opts)
const response = await performRequest(url, fetchOpts, detachSignal)
const { fetchOpts } = parseOpts(opts)
const response = await performRequest(url, fetchOpts)
if (!response.ok) {
const body = await maybeGetResponseBody(response)
throw new RequestFailedError(url, opts, response, body)
@@ -108,9 +108,9 @@ async function fetchRedirect(url, opts = {}) {
* @throws {RequestFailedError} if the response has a non redirect status code or missing Location header
*/
async function fetchRedirectWithResponse(url, opts = {}) {
const { fetchOpts, detachSignal } = parseOpts(opts)
const { fetchOpts } = parseOpts(opts)
fetchOpts.redirect = 'manual'
const response = await performRequest(url, fetchOpts, detachSignal)
const response = await performRequest(url, fetchOpts)
if (response.status < 300 || response.status >= 400) {
const body = await maybeGetResponseBody(response)
throw new RequestFailedError(url, opts, response, body)
@@ -142,8 +142,8 @@ async function fetchString(url, opts = {}) {
}
async function fetchStringWithResponse(url, opts = {}) {
const { fetchOpts, detachSignal } = parseOpts(opts)
const response = await performRequest(url, fetchOpts, detachSignal)
const { fetchOpts } = parseOpts(opts)
const response = await performRequest(url, fetchOpts)
if (!response.ok) {
const body = await maybeGetResponseBody(response)
throw new RequestFailedError(url, opts, response, body)
@@ -178,14 +178,13 @@ function parseOpts(opts) {
const abortController = new AbortController()
fetchOpts.signal = abortController.signal
let detachSignal = () => {}
if (opts.signal) {
detachSignal = abortOnSignal(abortController, opts.signal)
abortOnSignal(abortController, opts.signal)
}
if (opts.body instanceof Readable) {
abortOnDestroyedRequest(abortController, fetchOpts.body)
}
return { fetchOpts, abortController, detachSignal }
return { fetchOpts, abortController }
}
function setupJsonBody(fetchOpts, json) {
@@ -209,9 +208,6 @@ function abortOnSignal(abortController, signal) {
abortController.abort(signal.reason)
}
signal.addEventListener('abort', listener)
return () => {
signal.removeEventListener('abort', listener)
}
}
function abortOnDestroyedRequest(abortController, stream) {
@@ -230,12 +226,11 @@ function abortOnDestroyedResponse(abortController, response) {
})
}
async function performRequest(url, fetchOpts, detachSignal) {
async function performRequest(url, fetchOpts) {
let response
try {
response = await fetch(url, fetchOpts)
} catch (err) {
detachSignal()
if (fetchOpts.body instanceof Readable) {
fetchOpts.body.destroy()
}
@@ -244,7 +239,6 @@ async function performRequest(url, fetchOpts, detachSignal) {
method: fetchOpts.method ?? 'GET',
})
}
response.body.on('close', detachSignal)
if (fetchOpts.body instanceof Readable) {
response.body.on('close', () => {
if (!fetchOpts.body.readableEnded) {
+3 -5
View File
@@ -5,8 +5,8 @@
"main": "index.js",
"scripts": {
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
"test:ci": "npm run test:unit",
@@ -16,14 +16,12 @@
"author": "Overleaf (https://www.overleaf.com)",
"license": "AGPL-3.0-only",
"devDependencies": {
"@types/node-fetch": "^2.6.13",
"@types/node-fetch": "^2.6.11",
"body-parser": "^1.20.3",
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"express": "^4.21.2",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"typescript": "^5.0.4"
},
"dependencies": {
@@ -1,8 +0,0 @@
module.exports = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
},
}
@@ -1,9 +1,6 @@
const { expect } = require('chai')
const fs = require('node:fs')
const events = require('node:events')
const { FetchError, AbortError } = require('node-fetch')
const { Readable } = require('node:stream')
const { pipeline } = require('node:stream/promises')
const { once } = require('node:events')
const { TestServer } = require('./helpers/TestServer')
const selfsigned = require('selfsigned')
@@ -206,31 +203,6 @@ describe('fetch-utils', function () {
).to.be.rejectedWith(AbortError)
expect(stream.destroyed).to.be.true
})
it('detaches from signal on success', async function () {
const signal = AbortSignal.timeout(10_000)
for (let i = 0; i < 20; i++) {
const s = await fetchStream(this.url('/hello'), { signal })
expect(events.getEventListeners(signal, 'abort')).to.have.length(1)
await pipeline(s, fs.createWriteStream('/dev/null'))
expect(events.getEventListeners(signal, 'abort')).to.have.length(0)
}
})
it('detaches from signal on error', async function () {
const signal = AbortSignal.timeout(10_000)
for (let i = 0; i < 20; i++) {
try {
await fetchStream(this.url('/500'), { signal })
} catch (err) {
if (err instanceof RequestFailedError && err.response.status === 500)
continue
throw err
} finally {
expect(events.getEventListeners(signal, 'abort')).to.have.length(0)
}
}
})
})
describe('fetchNothing', function () {
@@ -419,16 +391,9 @@ async function* infiniteIterator() {
async function abortOnceReceived(func, server) {
const controller = new AbortController()
const promise = func(controller.signal)
expect(events.getEventListeners(controller.signal, 'abort')).to.have.length(1)
await once(server.events, 'request-received')
controller.abort()
try {
return await promise
} finally {
expect(events.getEventListeners(controller.signal, 'abort')).to.have.length(
0
)
}
return await promise
}
async function expectRequestAborted(req) {
+1 -2
View File
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+3
View File
@@ -0,0 +1,3 @@
node_modules
.npmrc
-9
View File
@@ -1,9 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/logger/**
libraries/o-error/**
package-lock.json
package.json
patches/**
-13
View File
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
+3
View File
@@ -0,0 +1,3 @@
{
"require": "test/setup.js"
}
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/logger/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/logger/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'logger-eslint', name: 'logger eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/logger/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/logger monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'logger test results', testResults: 'libraries/logger/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/logger/reports'
sh 'make clean_jenkins -j10'
}
}
}
+3 -1
View File
@@ -1,8 +1,10 @@
logger
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
+2 -2
View File
@@ -11,7 +11,7 @@ const LoggingManager = {
/**
* @param {string} name - The name of the logger
*/
initialize(name, options = {}) {
initialize(name) {
this.isProduction =
(process.env.NODE_ENV || '').toLowerCase() === 'production'
const isTest = (process.env.NODE_ENV || '').toLowerCase() === 'test'
@@ -27,7 +27,7 @@ const LoggingManager = {
req: Serializers.req,
res: Serializers.res,
},
streams: options.streams ?? [this._getOutputStreamConfig()],
streams: [this._getOutputStreamConfig()],
})
this._setupRingBuffer()
this._setupLogLevelChecker()
+2 -4
View File
@@ -13,8 +13,8 @@
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"test:ci": "npm run test:unit",
"test:unit": "mocha --exit test/**/*.{js,cjs}",
"types:check": "tsc --noEmit"
@@ -28,8 +28,6 @@
"devDependencies": {
"chai": "^4.3.6",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"sandboxed-module": "^2.0.4",
"sinon": "^9.2.4",
"sinon-chai": "^3.7.0",
@@ -1,8 +0,0 @@
module.exports = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
},
}
+1 -2
View File
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+3
View File
@@ -0,0 +1,3 @@
node_modules
.npmrc
-7
View File
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/metrics/**
package-lock.json
package.json
patches/**
-13
View File
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/metrics/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/metrics/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'metrics-eslint', name: 'metrics eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/metrics/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/metrics monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'metrics test results', testResults: 'libraries/metrics/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/metrics/reports'
sh 'make clean_jenkins -j10'
}
}
}
+3 -1
View File
@@ -1,8 +1,10 @@
metrics
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
+1 -1
View File
@@ -75,4 +75,4 @@ class RequestLogger {
}
}
module.exports = { monitor, RequestLogger }
module.exports.monitor = monitor
-4
View File
@@ -5,8 +5,6 @@
* before any other module to support code instrumentation.
*/
const metricsModuleImportStartTime = performance.now()
const APP_NAME = process.env.METRICS_APP_NAME || 'unknown'
const BUILD_VERSION = process.env.BUILD_VERSION
const ENABLE_PROFILE_AGENT = process.env.ENABLE_PROFILE_AGENT === 'true'
@@ -105,5 +103,3 @@ function recordProcessStart() {
const metrics = require('.')
metrics.inc('process_startup')
}
module.exports = { metricsModuleImportStartTime }
+4 -6
View File
@@ -9,7 +9,7 @@
"main": "index.js",
"dependencies": {
"@google-cloud/opentelemetry-cloud-trace-exporter": "^2.1.0",
"@google-cloud/profiler": "^6.0.3",
"@google-cloud/profiler": "^6.0.0",
"@opentelemetry/api": "^1.4.1",
"@opentelemetry/auto-instrumentations-node": "^0.39.1",
"@opentelemetry/exporter-trace-otlp-http": "^0.41.2",
@@ -24,17 +24,15 @@
"bunyan": "^1.0.0",
"chai": "^4.3.6",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"sandboxed-module": "^2.0.4",
"sinon": "^9.2.4",
"typescript": "^5.0.4"
},
"scripts": {
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"test:unit": "mocha --exit test/**/*.{js,cjs}",
"test:acceptance": "mocha --recursive --exit --grep=$MOCHA_GREP test/acceptance",
"test:acceptance": "mocha --reporter spec --recursive --exit --grep=$MOCHA_GREP test/acceptance",
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
@@ -1,8 +0,0 @@
module.exports = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
},
}
-1
View File
@@ -1 +0,0 @@
// no setup yet
+1 -2
View File
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+3
View File
@@ -0,0 +1,3 @@
# managed by monorepo$ bin/update_build_scripts
.npmrc
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/mongo-utils/**
package-lock.json
package.json
patches/**
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-72
View File
@@ -1,72 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/mongo-utils/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/mongo-utils/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'mongo-utils-eslint', name: 'mongo-utils eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/mongo-utils/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/mongo-utils monorepo npm run types:check'
}
}
}
}
}
post {
cleanup {
sh 'rm -rf libraries/mongo-utils/reports'
sh 'make clean_jenkins -j10'
}
}
}
+43 -57
View File
@@ -16,7 +16,6 @@ let VERBOSE_LOGGING
let BATCH_RANGE_START
let BATCH_RANGE_END
let BATCH_MAX_TIME_SPAN_IN_MS
let BATCHED_UPDATE_RUNNING = false
/**
* @typedef {import("mongodb").Collection} Collection
@@ -35,7 +34,6 @@ let BATCHED_UPDATE_RUNNING = false
* @property {string} [BATCH_RANGE_START]
* @property {string} [BATCH_SIZE]
* @property {string} [VERBOSE_LOGGING]
* @property {(progress: string) => Promise<void>} [trackProgress]
*/
/**
@@ -211,71 +209,59 @@ async function batchedUpdate(
update,
projection,
findOptions,
batchedUpdateOptions = {}
batchedUpdateOptions
) {
// only a single batchedUpdate can run at a time due to global variables
if (BATCHED_UPDATE_RUNNING) {
throw new Error('batchedUpdate is already running')
ID_EDGE_PAST = await getIdEdgePast(collection)
if (!ID_EDGE_PAST) {
console.warn(
`The collection ${collection.collectionName} appears to be empty.`
)
return 0
}
try {
BATCHED_UPDATE_RUNNING = true
ID_EDGE_PAST = await getIdEdgePast(collection)
if (!ID_EDGE_PAST) {
console.warn(
`The collection ${collection.collectionName} appears to be empty.`
)
return 0
}
refreshGlobalOptionsForBatchedUpdate(batchedUpdateOptions)
const { trackProgress = async progress => console.warn(progress) } =
batchedUpdateOptions
refreshGlobalOptionsForBatchedUpdate(batchedUpdateOptions)
findOptions = findOptions || {}
findOptions.readPreference = READ_PREFERENCE_SECONDARY
findOptions = findOptions || {}
findOptions.readPreference = READ_PREFERENCE_SECONDARY
projection = projection || { _id: 1 }
let nextBatch
let updated = 0
let start = BATCH_RANGE_START
projection = projection || { _id: 1 }
let nextBatch
let updated = 0
let start = BATCH_RANGE_START
while (start !== BATCH_RANGE_END) {
let end = getNextEnd(start)
nextBatch = await getNextBatch(
collection,
query,
start,
end,
projection,
findOptions
)
if (nextBatch.length > 0) {
end = nextBatch[nextBatch.length - 1]._id
updated += nextBatch.length
while (start !== BATCH_RANGE_END) {
let end = getNextEnd(start)
nextBatch = await getNextBatch(
collection,
query,
start,
end,
projection,
findOptions
)
if (nextBatch.length > 0) {
end = nextBatch[nextBatch.length - 1]._id
updated += nextBatch.length
if (VERBOSE_LOGGING) {
console.log(
`Running update on batch with ids ${JSON.stringify(
nextBatch.map(entry => entry._id)
)}`
)
}
await trackProgress(
`Running update on batch ending ${renderObjectId(end)}`
if (VERBOSE_LOGGING) {
console.log(
`Running update on batch with ids ${JSON.stringify(
nextBatch.map(entry => entry._id)
)}`
)
if (typeof update === 'function') {
await update(nextBatch)
} else {
await performUpdate(collection, nextBatch, update)
}
} else {
console.error(`Running update on batch ending ${renderObjectId(end)}`)
}
if (typeof update === 'function') {
await update(nextBatch)
} else {
await performUpdate(collection, nextBatch, update)
}
await trackProgress(`Completed batch ending ${renderObjectId(end)}`)
start = end
}
return updated
} finally {
BATCHED_UPDATE_RUNNING = false
console.error(`Completed batch ending ${renderObjectId(end)}`)
start = end
}
return updated
}
/**
+3 -1
View File
@@ -1,8 +1,10 @@
mongo-utils
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
-5
View File
@@ -1,5 +0,0 @@
// @ts-check
const { cleanupTestDatabase, dropTestDatabase } = require('./test-utils')
module.exports = { cleanupTestDatabase, dropTestDatabase }
+2 -4
View File
@@ -6,8 +6,8 @@
"scripts": {
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"test:unit": "mocha --exit test/**/*.{js,cjs}",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
"test:ci": "npm run test:unit",
@@ -22,8 +22,6 @@
"devDependencies": {
"chai": "^4.3.6",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"sandboxed-module": "^2.0.4",
"sinon": "^9.2.4",
"sinon-chai": "^3.7.0",
-55
View File
@@ -1,55 +0,0 @@
// @ts-check
/**
* @import { MongoClient } from 'mongodb'
* @import { MongoClient as LegacyMongoClient } from 'mongodb-legacy'
*/
/**
* Delete all data from the test Mongo database
*
* This doesn't drop the collections, so indexes are preserved.
*
* @param {MongoClient | LegacyMongoClient} mongoClient
*/
async function cleanupTestDatabase(mongoClient) {
ensureTestDatabase(mongoClient)
const db = mongoClient.db()
const allCollections = await db.collections()
const collections = allCollections.filter(
coll => coll.collectionName !== 'migrations'
)
await Promise.all(collections.map(coll => coll.deleteMany({})))
}
/**
* Drop the test Monto database
*
* This drops the whole database, including indexes.
*
* @param {MongoClient | LegacyMongoClient } mongoClient
*/
async function dropTestDatabase(mongoClient) {
ensureTestDatabase(mongoClient)
await mongoClient.db().dropDatabase()
}
/**
* Ensure that the given client is connected to a test database.
*
* This should be called before performing destructive operations on the test
* database.
*
* @param {MongoClient | LegacyMongoClient } mongoClient
*/
function ensureTestDatabase(mongoClient) {
const dbName = mongoClient.db().databaseName
const env = process.env.NODE_ENV
if (dbName !== 'test-overleaf' || env !== 'test') {
throw new Error(
`Refusing to clear database '${dbName}' in environment '${env}'`
)
}
}
module.exports = { cleanupTestDatabase, dropTestDatabase }
+11
View File
@@ -0,0 +1,11 @@
const chai = require('chai')
const sinonChai = require('sinon-chai')
const SandboxedModule = require('sandboxed-module')
// Chai configuration
chai.should()
chai.use(sinonChai)
SandboxedModule.configure({
globals: { Buffer, JSON, console, process },
})
+1 -2
View File
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+9
View File
@@ -0,0 +1,9 @@
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
+5
View File
@@ -0,0 +1,5 @@
.nyc_output
coverage
node_modules/
.npmrc
-7
View File
@@ -1,7 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/o-error/**
package-lock.json
package.json
patches/**
-13
View File
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/o-error/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/o-error/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'o-error-eslint', name: 'o-error eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/o-error/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/o-error monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'o-error test results', testResults: 'libraries/o-error/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/o-error/reports'
sh 'make clean_jenkins -j10'
}
}
}
+3 -1
View File
@@ -1,8 +1,10 @@
o-error
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
+10 -27
View File
@@ -1,34 +1,20 @@
// @ts-check
/**
* Light-weight helpers for handling JavaScript Errors in node.js and the
* browser.
*/
class OError extends Error {
/**
* The error that is the underlying cause of this error
*
* @type {unknown}
*/
cause
/**
* List of errors encountered as the callback chain is unwound
*
* @type {TaggedError[] | undefined}
*/
_oErrorTags
/**
* @param {string} message as for built-in Error
* @param {Object} [info] extra data to attach to the error
* @param {unknown} [cause] the internal error that caused this error
* @param {Error} [cause] the internal error that caused this error
*/
constructor(message, info, cause) {
super(message)
this.name = this.constructor.name
if (info) this.info = info
if (cause) this.cause = cause
/** @private @type {Array<TaggedError> | undefined} */
this._oErrorTags // eslint-disable-line
}
/**
@@ -45,7 +31,7 @@ class OError extends Error {
/**
* Wrap the given error, which caused this error.
*
* @param {unknown} cause the internal error that caused this error
* @param {Error} cause the internal error that caused this error
* @return {this}
*/
withCause(cause) {
@@ -79,16 +65,13 @@ class OError extends Error {
* }
* }
*
* @template {unknown} E
* @param {E} error the error to tag
* @param {Error} error the error to tag
* @param {string} [message] message with which to tag `error`
* @param {Object} [info] extra data with wich to tag `error`
* @return {E} the modified `error` argument
* @return {Error} the modified `error` argument
*/
static tag(error, message, info) {
const oError = /** @type {{ _oErrorTags: TaggedError[] | undefined }} */ (
error
)
const oError = /** @type{OError} */ (error)
if (!oError._oErrorTags) oError._oErrorTags = []
@@ -119,7 +102,7 @@ class OError extends Error {
*
* If an info property is repeated, the last one wins.
*
* @param {unknown} error any error (may or may not be an `OError`)
* @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @return {Object}
*/
static getFullInfo(error) {
@@ -146,7 +129,7 @@ class OError extends Error {
* Return the `stack` property from `error`, including the `stack`s for any
* tagged errors added with `OError.tag` and for any `cause`s.
*
* @param {unknown} error any error (may or may not be an `OError`)
* @param {Error | null | undefined} error any error (may or may not be an `OError`)
* @return {string}
*/
static getFullStack(error) {
@@ -160,7 +143,7 @@ class OError extends Error {
stack += `\n${oError._oErrorTags.map(tag => tag.stack).join('\n')}`
}
const causeStack = OError.getFullStack(oError.cause)
const causeStack = oError.cause && OError.getFullStack(oError.cause)
if (causeStack) {
stack += '\ncaused by:\n' + indent(causeStack)
}
+3 -5
View File
@@ -18,8 +18,8 @@
],
"scripts": {
"build": "npm run --silent test",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
@@ -32,11 +32,9 @@
"repository": "github:overleaf/o-error",
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/node": "^18.19.123",
"@types/node": "^18.17.4",
"chai": "^4.3.6",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"typescript": "^5.0.4"
}
}
@@ -1,8 +0,0 @@
module.exports = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
mochaFile: `reports/junit-mocha-${process.env.MOCHA_GREP}.xml`,
includePending: true,
jenkinsMode: true,
},
}
@@ -1,7 +1,7 @@
const { expect } = require('chai')
const { promisify } = require('node:util')
const OError = require('../..')
const OError = require('..')
const {
expectError,
@@ -268,11 +268,6 @@ describe('utils', function () {
expect(OError.getFullInfo(null)).to.deep.equal({})
})
it('works when given a string', function () {
const err = 'not an error instance'
expect(OError.getFullInfo(err)).to.deep.equal({})
})
it('works on a normal error', function () {
const err = new Error('foo')
expect(OError.getFullInfo(err)).to.deep.equal({})
@@ -1,6 +1,6 @@
const { expect } = require('chai')
const OError = require('../..')
const OError = require('..')
const {
expectError,
expectFullStackWithoutStackFramesToEqual,
@@ -35,14 +35,6 @@ describe('OError', function () {
expect(err2.cause.message).to.equal('cause 2')
})
it('accepts non-Error causes', function () {
const err1 = new OError('foo', {}, 'not-an-error')
expect(err1.cause).to.equal('not-an-error')
const err2 = new OError('foo').withCause('not-an-error')
expect(err2.cause).to.equal('not-an-error')
})
it('handles a custom error type with a cause', function () {
function doSomethingBadInternally() {
throw new Error('internal error')
-1
View File
@@ -1 +0,0 @@
// no setup yet
+61
View File
@@ -0,0 +1,61 @@
const { expect } = require('chai')
const OError = require('../..')
/**
* @param {Error} e
* @param {any} expected
*/
exports.expectError = function OErrorExpectError(e, expected) {
expect(
e.name,
"error should set the name property to the error's name"
).to.equal(expected.name)
expect(
e instanceof expected.klass,
'error should be an instance of the error type'
).to.be.true
expect(
e instanceof Error,
'error should be an instance of the built-in Error type'
).to.be.true
expect(
require('node:util').types.isNativeError(e),
'error should be recognised by util.types.isNativeError'
).to.be.true
expect(
e.toString(),
'toString should return the default error message formatting'
).to.equal(expected.message)
expect(e.stack, 'error should have a stack trace').to.not.be.empty
expect(
/** @type {string} */ (e.stack).split('\n')[0],
'stack should start with the default error message formatting'
).to.match(new RegExp(`^${expected.name}:`))
expect(
/** @type {string} */ (e.stack).split('\n')[1],
'first stack frame should be the function where the error was thrown'
).to.match(expected.firstFrameRx)
}
/**
* @param {Error} error
* @param {String[]} expected
*/
exports.expectFullStackWithoutStackFramesToEqual = function (error, expected) {
const fullStack = OError.getFullStack(error)
const fullStackWithoutFrames = fullStack
.split('\n')
.filter(line => !/^\s+at\s/.test(line))
expect(
fullStackWithoutFrames,
'full stack without frames should equal'
).to.deep.equal(expected)
}
@@ -1,61 +0,0 @@
const { expect } = require('chai')
const OError = require('../../..')
/**
* @param {Error} e
* @param {any} expected
*/
exports.expectError = function OErrorExpectError(e, expected) {
expect(
e.name,
"error should set the name property to the error's name"
).to.equal(expected.name)
expect(
e instanceof expected.klass,
'error should be an instance of the error type'
).to.be.true
expect(
e instanceof Error,
'error should be an instance of the built-in Error type'
).to.be.true
expect(
require('node:util').types.isNativeError(e),
'error should be recognised by util.types.isNativeError'
).to.be.true
expect(
e.toString(),
'toString should return the default error message formatting'
).to.equal(expected.message)
expect(e.stack, 'error should have a stack trace').to.not.be.empty
expect(
/** @type {string} */ (e.stack).split('\n')[0],
'stack should start with the default error message formatting'
).to.match(new RegExp(`^${expected.name}:`))
expect(
/** @type {string} */ (e.stack).split('\n')[1],
'first stack frame should be the function where the error was thrown'
).to.match(expected.firstFrameRx)
}
/**
* @param {Error} error
* @param {String[]} expected
*/
exports.expectFullStackWithoutStackFramesToEqual = function (error, expected) {
const fullStack = OError.getFullStack(error)
const fullStackWithoutFrames = fullStack
.split('\n')
.filter(line => !/^\s+at\s/.test(line))
expect(
fullStackWithoutFrames,
'full stack without frames should equal'
).to.deep.equal(expected)
}
+1 -2
View File
@@ -2,7 +2,6 @@
"extends": "../../tsconfig.backend.json",
"include": [
"**/*.js",
"**/*.cjs",
"**/*.ts"
"**/*.cjs"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules/
+4
View File
@@ -0,0 +1,4 @@
/node_modules
*.swp
.npmrc
@@ -1,12 +0,0 @@
# Autogenerated by build scripts. Do not edit.
.eslint*
.prettier*
libraries/fetch-utils/**
libraries/logger/**
libraries/metrics/**
libraries/o-error/**
libraries/object-persistor/**
libraries/stream-utils/**
package-lock.json
package.json
patches/**
-13
View File
@@ -1,13 +0,0 @@
let reporterOptions = {}
if (process.env.CI) {
reporterOptions = {
reporter: '/overleaf/node_modules/mocha-multi-reporters',
'reporter-options': ['configFile=./test/mocha-multi-reporters.cjs'],
}
}
const all = {
require: 'test/setup.js',
...reporterOptions,
}
module.exports = all
+6
View File
@@ -0,0 +1,6 @@
{
"ui": "bdd",
"recursive": "true",
"reporter": "spec",
"require": "./test/Init"
}
+1 -1
View File
@@ -1 +1 @@
22.18.0
20.18.2
-82
View File
@@ -1,82 +0,0 @@
// Autogenerated by build scripts. Do not edit.
pipeline {
agent {
node {
label 'jenkins-agent-web'
customWorkspace '/workspace'
}
}
options {
timestamps()
timeout(time: 15, unit: 'MINUTES')
}
environment {
BRANCH_NAME = "${env.CHANGE_BRANCH ? env.CHANGE_BRANCH : env.BRANCH_NAME}"
JENKINS_BUILD_NUMBER = "${BUILD_NUMBER}"
BUILD_NUMBER = "${SHORT_SHA}_${BUILD_NUMBER}"
COMMIT_SHA = "${GIT_COMMIT}"
SHORT_SHA = "${GIT_COMMIT.take(7)}"
}
stages {
stage('Stage 1') {
parallel {
stage('Install monorepo') {
steps {
retry(count: 3) {
sh 'make monorepo_setup'
}
}
}
stage('Create reports folder') {
steps {
sh 'mkdir libraries/object-persistor/reports'
}
}
}
}
stage('Stage 2') {
parallel {
stage('Lint') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run lint -- --format json --output-file reports/eslint.json'
}
post {
always {
sh """
sed -i 's_"filePath":"/overleaf_"filePath":"/workspace_g' libraries/object-persistor/reports/eslint.json
"""
recordIssues checksAnnotationScope: 'ALL', enabledForFailure: true, failOnError: true, id: 'object-persistor-eslint', name: 'object-persistor eslint', qualityGates: [[integerThreshold: 1, threshold: 1.0, type: 'TOTAL']], sourceCodeRetention: 'LAST_BUILD', tools: [esLint(pattern: 'libraries/object-persistor/reports/eslint.json')]
}
}
}
stage('Format') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run format'
}
}
stage('Typecheck') {
steps {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run types:check'
}
}
stage('Test') {
steps {
retry(count: 3) {
sh 'bin/run -w /overleaf/libraries/object-persistor monorepo npm run test:ci'
}
}
}
}
}
}
post {
always {
junit checksName: 'object-persistor test results', testResults: 'libraries/object-persistor/reports/junit-*.xml'
}
cleanup {
sh 'rm -rf libraries/object-persistor/reports'
sh 'make clean_jenkins -j10'
}
}
}
+9 -5
View File
@@ -46,7 +46,7 @@ Uploads a stream to the backend.
- `key`: The key for the uploaded object
- `readStream`: The data stream to upload
- `opts` (optional):
- `sourceMd5`: The md5 hash of the source data, if known. The uploaded data will be compared against this and the operation will fail if it does not match. If omitted, the md5 is calculated as the data is uploaded instead, and verified against the backend. This is not supported in `S3Persistor` as it performs [its own integrity protections](https://aws.amazon.com/blogs/aws/introducing-default-data-integrity-protections-for-new-objects-in-amazon-s3/). Setting `sourceMd5` with `S3Persistor` will result in an error being thrown.
- `sourceMd5`: The md5 hash of the source data, if known. The uploaded data will be compared against this and the operation will fail if it does not match. If omitted, the md5 is calculated as the data is uploaded instead, and verified against the backend.
- `contentType`: The content type to write in the object metadata
- `contentEncoding`: The content encoding to write in the object metadata
@@ -264,10 +264,8 @@ For the `FS` persistor, the `bucketName` should be the full path to the folder o
- `s3.key` (required): The AWS access key ID
- `s3.secret` (required): The AWS secret access key
- `s3.partSize`: The part size for S3 uploads. Defaults to 100 megabytes.
- `s3.httpOptions`: HTTP Options passed to the [`NodeHttpHandler` constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-smithy-node-http-handler/Class/NodeHttpHandler/)
- For backwards compatibility reasons, the `timeout` property that was passed to the [S3 constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property) before migrating to AWS SDK v3 is now passed to the `NodeHttpHandler` constructor as `connectionTimeout`.
- `s3.maxRetries` (legacy): The number of times the S3 client will retry in case of an error
- `s3.maxAttempts`: The number of times the S3 client will attempt to perform the operation in case there are errors. Default value is 3.
- `s3.httpOptions`: HTTP options passed directly to the [S3 constructor](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#constructor-property).
- `s3.maxRetries`: The number of times the S3 client will retry in case of an error
- `s3.endpoint`: For testing - overrides the S3 endpoint to use a different service (e.g. a fake S3 server)
- `s3.pathStyle`: For testing - use old path-style URLs, for services that do not support subdomain-based access
@@ -282,6 +280,12 @@ For the `FS` persistor, the `bucketName` should be the full path to the folder o
}
```
#### Notes
In order for server-side MD5 generation to work, uploads must be below the `partSize`. Otherwise a multipart upload will be used, and the S3 `eTag` which is used to retrieve the MD5 will not be the MD5 hash of the uploaded object. In these cases, we download the data and calculate the MD5 manually.
For verification during upload, we use S3's checksum mechanism to verify the integrity of the uploaded data, but when explicitly retrieving the md5 hash this will download the entire object if its size is above the part size.
### GCS-specific parameters
GCS authentication is configured automatically via the local service account, or the `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
+3 -1
View File
@@ -1,8 +1,10 @@
object-persistor
--dependencies=None
--docker-repos=gcr.io/overleaf-ops
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
--node-version=22.18.0
--node-version=20.18.2
--public-repo=False
--script-version=4.5.0
+3 -8
View File
@@ -6,8 +6,8 @@
"scripts": {
"test": "npm run lint && npm run format && npm run types:check && npm run test:unit",
"test:unit": "mocha --exit test/**/*.{js,cjs}",
"lint": "eslint --ext .cjs,.js,.jsx,.mjs,.ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .cjs,.js,.jsx,.mjs,.ts .",
"lint": "eslint --ext .js --ext .cjs --ext .ts --max-warnings 0 --format unix .",
"lint:fix": "eslint --fix --ext .js --ext .cjs --ext .ts .",
"format": "prettier --list-different $PWD/'**/*.{js,cjs,ts}'",
"format:fix": "prettier --write $PWD/'**/*.{js,cjs,ts}'",
"test:ci": "npm run test:unit",
@@ -20,15 +20,12 @@
"author": "Overleaf (https://www.overleaf.com/)",
"license": "AGPL-3.0",
"dependencies": {
"@aws-sdk/client-s3": "^3.864.0",
"@aws-sdk/lib-storage": "^3.864.0",
"@aws-sdk/node-http-handler": "^3.370.0",
"@aws-sdk/s3-request-presigner": "^3.864.0",
"@google-cloud/storage": "^6.10.1",
"@overleaf/logger": "*",
"@overleaf/metrics": "*",
"@overleaf/o-error": "*",
"@overleaf/stream-utils": "*",
"aws-sdk": "^2.1691.0",
"fast-crc32c": "overleaf/node-fast-crc32c#aae6b2a4c7a7a159395df9cc6c38dfde702d6f51",
"glob": "^7.1.6",
"range-parser": "^1.2.1",
@@ -38,8 +35,6 @@
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"mocha": "^11.1.0",
"mocha-junit-reporter": "^2.2.1",
"mocha-multi-reporters": "^1.5.1",
"mock-fs": "^5.2.0",
"mongodb": "6.12.0",
"sandboxed-module": "^2.0.4",

Some files were not shown because too many files have changed in this diff Show More