* [editor-core] share the blob hash and the doc-vs-file rule
The git blob hash and the rule that decides whether a file is a doc or a binary
file both have to reach the same answer in every service that writes to history,
so they move into overleaf-editor-core rather than being spelled out again on
each side.
blob_utils takes over lib/blob_string_length.js: hashing and the string-length
rule answered two halves of the same question -- what history needs to know
about content before it can store it -- and each carried the same warning about
staying off index.js, which is bundled for the browser. One module states it
once, and blobForFile joins them, describing content on disk as the blob it
amounts to. The hashing functions are flat rather than a namespace of their own:
in a module that also holds the string-length rule, a bare fromStream says
nothing about what it makes. history-v1's blob store and recover_zip follow the
module to its new name.
file_type_detector holds the doc-vs-file rule, Node-only and deep-imported for
the same reason. It takes textExtensions, editableFilenames and maxDocLength as
configuration rather than reading settings: the limit is web's 2 MiB and not
editor-core's own 3 MiB, and the surrogate check covers both halves of a pair
where editor-core's covers the high half.
buildSetContentOperations' test spelled the blob header out for itself, with the
separator as a literal NUL byte, which had git reading the file as binary. It
hashes through blobHashFromString now, so it does not spell the header at all.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [editor-core] name the client a change came from on the origin itself
`EditorOrigin` carried an `editorId` that only an editor change could have. What
the id is for -- recognising a change again, so history does not apply a resend
twice and the client does not apply its own change back -- is a property of the
client that submitted it rather than of what it did, so it moves onto `Origin` as
an optional `historyClientId` and `EditorOrigin` goes.
- `Origin` takes `(kind, historyClientId)` and answers `getHistoryClientId()`;
`dropHistoryClientId()` is what the chunk store uses to strip the id from all
but a client's latest change, which now leaves the rest of the origin alone --
a restore that a client submitted stays a restore.
- `toRaw` is built a layer at a time: the base writes the kind and the id, a
subclass spreads that and adds the fields it owns.
- The named kinds are their own schemas and discriminate on `kind`, so a payload
claiming one is checked against that shape and the error says what it got
wrong. The catch-all cannot join them -- its kind is any string -- so it sits
alongside and is refined to refuse the named kinds, which it used to swallow:
`{kind: 'restore'}` validated as a kind and nothing else, then read back as a
restore that recorded nothing about what it restored.
- `lib/origin/*.js` gains `// @ts-check`. Without it the annotations in there
were decorative: the lazily required subclasses were `any`, so nothing handed
to them was checked, and `fromRaw` narrows with `in` to drop the catch-all
variant, which a kind check cannot.
The callers that stamp the id -- real-time's handshake flag, web's applyChange
body -- come with the rest of the branch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [editor-core] recognise a change a writer that is not an editor placed
The counterpart of `isSameEditorChange` for writers that are not an editor
client: an integration that commits a batch on a user's behalf has to recognise
that batch coming back, because a lost response does not say whether the commit
landed and resubmitting one that did applies its removes twice.
It compares the same three fields, and for the same reason -- a rebase rewrites a
change's operations but leaves its origin, authors and timestamp alone -- with
the timestamp compared as a point in time rather than as a string, so that two
spellings of the same instant cannot read as different changes. github-sync is
the first caller, and comes with the rest of the branch.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [editor-core] load an editable file's content, or say it has none
Only an editable file has content: any other kind is bytes addressed by hash, and
hollow data records the size of content it does not have. Both answer
`getContent()` with null, so every caller that wants the content of a doc loaded
it, checked the data's class, and reached for its own error when the check failed.
`File#loadEager` does that once and answers the data that always has the content.
`buildSetContentOperations` takes a `ReadWriteBlobStore` -- everything but
looking a blob up by hash, which is all it takes to build operations over content
-- so a caller holding a store that cannot answer `getBlob` can still use it. Its
metadata argument is `FileMetadata` rather than `Object`, which is what the schema
already says a file's metadata is.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* [editor-core] say that a pair of operations that do not fit is unprocessable
compose and transform threw a bare Error when the two operations do not describe
the same content. Everything that answers a client for these -- history-v1's
import routes, the git-bridge push, project-history's resync -- decides on
UnprocessableError, so a bare Error reached them as an internal failure: a 500,
which reads as worth retrying, for a pair that fails the same way every time.
A client that resubmits on a 500 resubmits forever.
The guards that cannot be reached through the API keep their bare Error: a
TextOperation composed with something that is not one, and the branch whose
message says it should not happen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* [history-v1] hash blobs with the rule editor-core holds
storage/lib/blob_hash.js was a bluebird-era implementation of the same git blob
hash editor-core holds, exported from the storage barrel and used across the
storage layer, the api and the tests. All of it reads the shared rule now, and
the test that existed only to check the copy is gone -- editor-core's suite
covers the same non-ASCII case.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GitOrigin-RevId: 5a0c1e9a06170a0164c01a26a7bb2d205726d531
The hash of empty content is a property of the content rather than of anything
stored: every project's empty file has it, whether or not a blob was ever written
under it, and a file may reference it before anything has. Eight blob stores were
each paying a lookup -- a database query, an HTTP request, a read of a cache that
offline mode may be the only thing standing in for -- to be told what the hash
already says, and clsi had already reinvented the answer on its own.
overleaf-editor-core gains BlobStoreBase, which answers getString for that hash
and delegates the rest to the fetchString its subclasses provide. getObject comes
with it: four stores spelled out the same JSON.parse of getString, and a fifth
wrapped it in a log line.
Adopted by history-v1's BlobStore, BackupBlobStore, HashCheckBlobStore and
recover_zip's RecoveryBlobStore, by project-history's BlobStore, by clsi's
BlobStore, and by web's HistoryBlobStore, SimpleBlobStore and FrontendBlobStore.
history-v1 keeps its own answers in getStream, getBlob and getBlobs, which no
other store implements. Writing and copying a blob are untouched, so a project
that wrote empty content still has a blob for it and a read answers the same
either way.
Two paths could not handle a project holding a tracked change or a comment at
all. Loading such a file needs the ranges blob its rangesHash points at, and
hashing one again needs to write it back, so a store missing getObject or
putObject fails outright:
- recover_zip died on `blobStore.getObject is not a function`, making every such
project unrecoverable. The test covering it asserts a tracked delete is absent
from the zip, which the script already asked for and never reached.
- GET /projects/:project_id/latest/hashed_content returned 500 from the same
cause, then would have hit a missing putObject in snapshot.store.
HashCheckBlobStore becomes a class over the base and gains putObject.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
GitOrigin-RevId: c84f62465beff6cf77ffac26aa772984e1b554cb
* [saas-e2e] conversion: wait for initial compile before looking at PDF
* [eslint-plugin] s/before/beforeWithReRunOnTestRetry/ in e2e tests
* [server-ce] remove filestore migration scripts and E2E tests
* [server-ce] test: trim down upgrading tests to 5.x -> latest
GitOrigin-RevId: 2426ec4a4f3d67a5e0e7850ea84a942ae4619f94
* [migrations] only apply non-blocking migrations in CI
* [migrations] use "yarn run migrations" instead of "npm run migrations"
GitOrigin-RevId: d9f96db398adf2febcd82333295fb8d5eab741bb
* add script to finalise broken history-v1 chunks
* use history-id instead of project-id
* update project-id to history-id in tests
* silence unwanted event emitter warnings
* fix up test for historyId
GitOrigin-RevId: 58d2a768f1eff296e921e2ed985f6faf3929f619
* upgrade from eslint version 8 to eslint version 10
* remove unsupported eslint-env directive
* include jsx files in latexqc linting
* use basePath and extends to maintain paths in writefull eslint
* fix yarn.lock
with ./bin/yarn install
* preserve existing glob patterns in web eslint config
* restore original comments
* fix worker path
* corrected comment about eslint-plugin-mocha
* remove unused imports
* remove unused import of includeIgnoreFile
* switch to individual eslit.config.mjs files
* fix lint errors on eslint.config.mjs in web
* update build scripts for eslint.config.mjs
* update volumes for RUN_LINTING_CI_MONOREPO in web Makefile
updated manually as this makefile is not autogenerated
the RUN_LINTING_CI_MONOREPO command is only used for prettier, not eslint, but updating for consistency.
* migrate from mocha/no-skipped-tests to mocha/no-pending-tests
see https://github.com/lo1tuma/eslint-plugin-mocha/pull/365
"rule no-skipped-tests has been removed, its functionality has been merged into the existing no-pending-tests rule"
GitOrigin-RevId: 2c8f25c8049a0dba374a51df1214286bb5093a51
* [history-v1] add endpoint for downloading latest zip
* [web] address review feedback
* [web] tests: do not overwrite db.projects.overleaf, extend it
* [web] set includeReferer flag from downloading zip
GitOrigin-RevId: e63e549f004230086f82eccf03b43fd62bde6071
* [history-v1] fix re-running test_acceptance_run
Preserve the contents of the migrations collection. Deleting the entries
does not "undo" the migrations. On re-run east would try applying all
migrations and fail as things were already applied.
* [history-v1] remove guard migration before running tests
GitOrigin-RevId: e6eeafd58215e5148dd70c37c7a87d84e0a12bf3
* [monorepo] record ERROR/FATAL log messages in junit report
* [web] put SaaS specific code behind feature flag
* [web] use split test cache for getting user assignments
The unit tests needed updating as they did not replicate any of the
mongo filtering. The acceptance tests cover this logic.
* [web] make better use of existing indexes
* [web] avoid col-scan in tests of notifications module
* [web] remove cleanup of empty feedbacks collection
* [web] add assertion for reason of rejected request in launchpad test
* [web] add missing indexes
* [web] enable mongo notablescan
* [web] make emailNotifications tests compatible with notablescan
GitOrigin-RevId: b888f2feeb3a0e915f068ae1c4ea23ec17821221
* [migrations] make old migrations compatible with --notablescan in mongo
Re-running the migration for db.users.emails.reversedHostname on all
Server Pro/CE users will not be harmfull.
* [monorepo] enable mongo notablescan for all services but web
GitOrigin-RevId: e2a710c9de08de9ac2aa9df1f3082d5f1c33ea05
* fix: correct typedef for Document in helpers.mjs
* add move-migrations codemod
* update migration paths to use shared migrations directory
* move migrations to shared location
* fix: update Dockerfile and docker-compose.ci.yml to include migrations directory
* feat: add migrations tool to workspaces in package.json
* [monorepo] Fix order of docker ignore rules
* [web] remove unused docker ignore file
* [monorepo] replace old references to migrations folder
* [server-ce] copy migrations from new place
* [migrations] Inline web scripts
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [migrations] move three web scripts over
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [migrations] add missing collection
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [migrations] remove lodash dependency
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [migrations] avoid mongodb-legacy dependency
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [monorepo] run migrations from tools/migrations
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [migrations] simplify migration for adding gitBridge feature to users
* [monorepo] run migrations from tests in all the services
* [migrations] add Jenkins pipeline for linting/formatting
* [monorepo] fixup running web migrations everywhere
* [monorepo] trigger Jenkins builds on changes to mongo migrations
* [migrations] add Jenkins pipeline for linting/formatting
* [monorepo] build scripts: update devDependencies before deps scanning
* [monorepo] build scripts: formerly depend on tools/migrations
* [monorepo] run eslint on .mjs files
* [migrations] enable more eslint rules and fix all the errors
* [rake] fix migrations:list task
---------
Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: 14cf69cc1b9405bbc75adbb9a000e555500e0614
* Use snapshot timestamp, remove request for paths at version
* Add timestamp to core Snapshot object
* Avoid mutating function argument
* Explain assumption about editable files
* snapshot.toRaw() in getContentAtVersion
* fix project-history acceptance test
* fix history_v1 test
* fix web tests
* Include the snapshot timestamp in stored chunks
---------
Co-authored-by: Eric Mc Sween <5454374+emcsween@users.noreply.github.com>
GitOrigin-RevId: 376a53e1f927cb56544e6782b47d80345655038c
* Upgrade `aws-sdk` to v3
Also vendored nodemailer-ses-transport
* Moved default region to CE settings
* Ensure timeout is added to `requestHandler` and `region` is populated
* fix unsigned header in signed URL request
The x-amz-acl header is not needed when using the signed request,
as ACL are already defined when creating the signed URL in
PutObjectCommand constructor.
* Add default AWS region for latexqc service
* remove unnecessary region in compose files
* Use AWS_REGION=us-west-2 for history-v1
* prevent retries uploading streams with PutObjectCommand
* Remove AWS SDK JS message suppression
GitOrigin-RevId: 6fda6f02160023ffed76143397bbd965f86a9509
* [history-v1] add endpoint for getting blob stats of projects
* [web] display project history blob size on admin pages
* [web] break down history storage size by text and binary blob
GitOrigin-RevId: bfa4d56cf2c503d03005c13a0f7ac38158156cd2
* [history-v1] add migrations record after full binary file migration
* [server-pro] add hotfix 5.5.5
* [server-ce] test: build hotfix 5.5.5 and use it in tests
GitOrigin-RevId: fb84e5710c59f466a3305de5f32f78e0ac9ce15d
* [history-v1] use String.padStart instead of lodash.padStart
* [web] download binary files in clsi from filestore via new endpoints
* [server-ce] tests: Cypress.env() is parsing boolean values
* [server-ce] tests: run history migration as root
GitOrigin-RevId: bdf6c0e542531ccc4b3f13d2ed68ca0d31e580e9
* [history-v1] put logs of back_fill_file_hash script in /var/log/overleaf
* [history-v1] do not leave tmp dir behind when using --report
* [history-v1] extend --report with number of files to check/missing
* [history-v1] move all the options into command line flags
Change default values:
- concurrency to 10
- concurrent batches to 1
- stream high water mark to 1MiB
* [web] find_malformed_filetrees: log progress on stderr
* [history-v1] fix percentage of projects that need back-filling
GitOrigin-RevId: ebd7889840f97b24eda43774ffe7524998fb634b
* [history-v1] move MockFilestore into shared place
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
* [history-v1] make back_fill_file_hash_fix_up compatible with Server Pro
---------
Co-authored-by: Brian Gough <brian.gough@overleaf.com>
GitOrigin-RevId: 70ea57e1503031d9f14dcd60c4c110e746450587
add support for fetching files via http from filestore in back_fill_file_hash script and tests
GitOrigin-RevId: 8dea6383ed6fe9ee6786a5695e2deee93b1cdd84