* Migration and index setup script * Helper script to clear linked library * Pull users collections * Implementing get items from users zotero library * Initial zotero sync client * Pulling users overleaf collection * Pulling users overleaf collection * Initial sync pull from Zotero to Library * Sync and import workflow from Zotero into Library * Using user getter and setter for updating user library info * Using new collection for library sync states * Adding tests for new sync functionality * Harden Zotero sync route * Simplify Zotero sync state read and skip accounting Fold the ensure+get double round-trip in sync-state discovery into one findOneAndUpdate, and derive itemsSkipped from items.length - itemsInserted instead of a running counter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Redact URL-encoded token secret from OAuth1 request logs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fixing type failure * Rename upsertZoteroReferences to importZoteroReferences The method is insert-only; the bulkWrite upsert just makes re-runs idempotent rather than updating, so the name now reflects that. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Validate librarySyncStates reads with zod Replace the `as` / `as unknown as` casts in getLibrarySyncState and ensureLibrarySyncState with a zod schema parse, matching LibraryReferenceRepository. Types are now derived from the schema. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Defer Zotero sync watermark until pagination exists Don't record lastSyncedVersion after a single-page sync: committing the page-1 version before pagination (#34286) lands would let incremental sync (#34282) skip items beyond the first page. Drops the commitSyncState call and toVersion from SyncResult; the version envelope is left for the follow-ups. commitSyncState stays in the repository for #34282. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Extract OAuth1Transport from OAuth1Handler Lift the OAuth1 client/config registry, getAccessToken, redactSecret and classifyOAuth1Error into oauth1/OAuth1Transport.js, plus a signedGet helper for provider modules to reuse. OAuth1Handler now imports them; its method bodies are unchanged. Test mocks move to esmock's global scope so they reach the transport, with Errors pinned for instanceof checks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Move Zotero collections/items into a per-provider ZoteroProvider Carve the Zotero-only operations out of the generic OAuth1 handler into providers/ZoteroProvider.js, dispatched via providers/ProviderRegistry.js. ReferenceProviderHandler now resolves the provider from the registry and throws UnsupportedOperationError (mapped to 501) for providers without the operation, instead of bolting Zotero-only methods onto OAuth1Handler. Zotero's collectionsUri/itemsTopUri are read from settings by ZoteroProvider rather than copied into the shared OAuth1 registry. Removes getCollections/ getUsersItemsChanges (and their tests) from OAuth1Handler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Add ZoteroProvider unit tests and unsupported-provider coverage Cover ZoteroProvider collections/items parsing, header envelope and malformed-payload rejection, and assert ReferenceProviderHandler throws UnsupportedOperationError for providers without a sync implementation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Make addSyncedCollection idempotent Only push a synced collection when its key isn't already recorded, so a repeat sync can't create duplicate syncedCollections entries regardless of the caller-side guard. Adds a sequential test asserting no duplicate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Hardcode Zotero library endpoint paths, derive host from site Move the collections/items-top endpoints out of settings and into ZoteroProvider as path constants, taking only the host from the provider's `site`. Aligns Zotero `site` with the other providers (API host) and avoids adding per-endpoint config points. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Make Zotero sync routes explicit, 404 unknown providers Hardcode the collections/items routes to /zotero rather than a generic /:ref_provider, so a non-Zotero request 404s on the missing route instead of returning a misleading 501. Drop the UnsupportedOperationError 501 branch, reverting OAuth2 unsupported ops to their prior 500. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> GitOrigin-RevId: 50e16a9c46f995c2e9db6eed50ef81c3a71ea71d
Migrations
Migrations for the app environment live in this folder, and use the East migration framework.
We have a yarn script which wraps east: yarn run migrations -- ...
For example:
yarn run migrations -- list -t 'server-ce'
For SAAS, use the rake tasks for staging/production
rake deploy:migrations:list[staging]
Environments and Tags
Overleaf is deployed in three different environments:
server-ce: community edition installations (the base system)server-pro: server pro installationssaas: the production overleaf site
All migrations are tagged with the environments they should run in.
For example, a migration that should run in every environment would be tagged with ['server-ce', 'server-pro', 'saas'].
When invoking east, we specify the relevant tags with the -t or --tags flag.
Our adapter will refuse to run if this flag is not set.
Creating new migrations
To create a new migration, run:
yarn run migrations -- create <migration name>
This command will create a new migration file in the migrations folder, based on a template. The template provides
migrate and rollback methods, which are run by the east binary when running the migrations. rollback should
undo the changes made in migrate.
Running scripts as a migration
To run a script in a migration file, look at migrations/20190730093801_script_example.js, which runs the script
scripts/example/script_for_migration.mjs. This uses a method where the script can be run standalone via node, or
through the migrations' mechanism.
Running migrations
To run all migrations in a server-ce environment:
yarn run migrations -- migrate -t 'server-ce'
# Note: They are run by default on container start.
To run all migrations in a SAAS environment use the rake task:
# list first and check that only your newly added migration is shown. If not, ask in the dev channel for help.
rake deploy:migrations:list[staging]
# After confirming the listing, run the migrations
rake deploy:migrations[staging]
To run all migrations in the dev-env:
make services/web/migrate
# Note: "make install" will pick them up as well
The -t flag also works with other east commands like rollback, and list.
For other options, or for information on how to roll migrations back, take a look at the East documentation.
Tips
Try to use Mongo directly via the db object instead of using Mongoose models. Migrations will need to run in the
future, and model files can change. It's unwise to make the migrations depend on code which might change.
Note: Running east rollback without any arguments rolls back all migrations, which you may well not want.