420 Commits

Author SHA1 Message Date
Tom Moor 053693b9d5 fix: Spurious post-import edits (#12620) 2026-06-07 21:13:23 -04:00
Tom Moor 9b8acf3efb Remove unnecessary default parameter values from function signatures (#12617)
* Fix remaining no-useless-default-assignment lint warnings

* Promote no-useless-default-assignment lint rule to error
2026-06-07 15:46:01 -04:00
Tom Moor 0d198294eb fix: Improve patch merging of links in table cells (#12614)
* fix: Improve merging of links in table cells through patch

* PR feedback
2026-06-07 12:09:44 -04:00
Tom Moor 492af6683b Add document restore functionality to MCP tools (#12575)
* Add restore_document MCP tool and archived/trashed listing

Closes the delete/restore asymmetry in the MCP server: previously documents
could be archived or trashed via delete_document but never recovered.

- Add restore_document tool to recover archived or trashed documents,
  optionally into a different collection.
- Add a status option ("archived" | "trashed") to list_documents so agents
  can discover what to restore.
- Extract the documents.restore route logic into a shared documentRestorer
  command, used by both the REST endpoint and the MCP tool.

https://claude.ai/code/session_01HpFcYtgEZJ96iaFMuGGCmc

* Use type-only import for Document in documentRestorer

https://claude.ai/code/session_01HpFcYtgEZJ96iaFMuGGCmc

* Revert archived/trashed status option on list_documents

Keeps the restore_document tool and shared documentRestorer command;
removes the list_documents status filter and its tests.

https://claude.ai/code/session_01HpFcYtgEZJ96iaFMuGGCmc

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-06 15:08:52 -04:00
Tom Moor b23a39bd39 Add email verification check during sign-in flow (#12605)
* Add email verification check during sign-in flow

* Add support for Entra External ID with OIDC standard verification claim
2026-06-06 08:01:26 -04:00
Tom Moor 60bf47ede0 fix: Prevent foreign key violation when permanently deleting a team (#12527)
The attachment cleanup loop used findAllInBatches, which advances an
OFFSET each iteration. Because the callback deletes each batch, the
remaining rows shift backwards and the advancing offset skips over them,
leaving attachments that still reference the team. team.destroy() then
failed with attachments_teamId_fkey.

Page from offset 0 until no attachments remain, and remove the now
redundant per-user attachment delete so the loop is the single
authoritative cleanup.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 20:47:18 -04:00
Tom Moor fecca544f9 chore: Normalize permission logic between API/MCP doc creation (#12517) 2026-05-28 22:42:40 -04:00
Tom Moor b9addda229 perf: Reduce deletion batch size (#12474) 2026-05-26 20:12:26 -04:00
Tom Moor 03950af3b7 fix: TypeError when document.collaboratorIds is null (#12471)
Guard against null collaboratorIds when persisting collaborative
updates; the DB column has no default and can be NULL on older rows.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 19:56:56 -04:00
Tom Moor 879d2b8198 fix: Allow connecting additional auth providers on custom domain (#12364)
* fix: Unable to link secondary auth provider on custom domain

* doc

* chore: Custom -> Apex transfer token

* Refactor, address security concerns

* Ensure OAuth intent is single-use

* Secure OAuth state actor binding

* Use scrypt for OAuth actor session binding
2026-05-16 19:56:21 -04:00
Tom Moor 6bd775eb84 fix: Batch document deletes when emptying trash (#12328)
* fix: Batch document deletes when emptying trash

Splits the final parentDocumentId clear and destroy in documentPermanentDeleter
into chunks of 100 to keep the exclusive lock window on the documents table
short, preventing concurrent web SELECTs from queueing behind a single large
DELETE.

* fix: Skip parentDocumentId clear for documents restored mid-flight

Re-checks deletedAt in the database before clearing parentDocumentId on
children, so a parent restored between the caller's query and now keeps its
children attached.
2026-05-12 20:31:12 -04:00
Tom Moor 9c26535815 Auto-subscribe mentioned users to document (#12235)
* Auto-subscribe mentioned users to documnet

* Add tests for mention auto-subscribe and a buildMention factory

* Add tests that prior unsubscribes are respected when mentioned

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Batch mention subscriptions into a single transaction

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 21:33:55 -04:00
Tom Moor 091346dfe8 chore: Migrate to vitest (#12272)
* wip

* Remove obsolete snapshots

* simplify

* chore(test): Convert mocks to TypeScript and tighten fetch mock types

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* Remove unneccessary patches

* Migrate to msw instead of custom fetch mock

* Address PR review comments

- Split chained vi.useFakeTimers().setSystemTime() into separate calls.
- Switch test setup to dynamic imports so EventEmitter.defaultMaxListeners
  assignment runs before module init (static imports were hoisted above it).
- Drop redundant NODE_ENV guard in monkeyPatchSequelizeErrorsForJest; its
  sole caller already gates on env.isTest.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 21:10:51 -04:00
Tom Moor 0139b91b5d chore: Replace lodash with es-toolkit (#12281)
* chore: Replace lodash with es-toolkit

Migrate all direct lodash imports to es-toolkit/compat for a smaller,
faster, lodash-compatible utility library. Transitive lodash usage from
other packages remains unchanged.

* fix: Restore isPlainObject semantics in CanCan policy

The lodash migration aliased `isObject` to `lodash/isPlainObject` and
the codemod incorrectly mapped the local name to es-toolkit's `isObject`,
which also returns true for arrays and functions. This caused condition
objects in policy definitions to be skipped, breaking authorization
checks across the codebase.

* fix: Restore unicode-aware length counting in validators

es-toolkit/compat's size() returns string.length, while lodash's _.size()
counts unicode code points. Switch to [...value].length to preserve the
previous behavior so multi-byte characters like emoji count as one.
2026-05-06 21:03:47 -04:00
Tom Moor 4c2b62ef6a fix: should change lastModifiedById when republishing doc (#12227)
* fix: should change lastModifiedById when republishing an already published document

* test: Use same-team creator in republish attribution test

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 12:06:31 +00:00
Tom Moor 57308c46af chore: resolve lint warnings (no-explicit-any, no-redundant-type-constituents, no-base-to-string) (#12209)
* chore: resolve no-redundant-type-constituents and test/mock no-explicit-any warnings

Clears 36 lint warnings: all 5 no-redundant-type-constituents, 6
no-misused-spread (via narrowing getPartitionWhereClause's return type
to WhereAttributeHash), and 25 no-explicit-any in test/mock files.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: resolve no-base-to-string warnings in tests

Convert userProvisioner try/catch error assertions to Jest's
.rejects.toThrow() idiom, and cast webhook test body to string.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: resolve no-explicit-any warnings in cancan and tracing

Tighten types in the cancan policy framework and tracing decorators.
Constructor / generic-function upper bounds keep `any` where TypeScript
variance requires it, scoped to single-line oxlint-disable comments.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 22:55:30 -04:00
Tom Moor 4c85c4d08d chore: resolve unbound-method lint warnings in tests (#12204)
Capture jest mock references in local variables instead of asserting
against unbound method references on mocked classes/instances.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-28 20:50:25 -04:00
Tom Moor 8e371ea263 Add argument to suppressEmail when inviting users through API (#12082)
* Add argument to suppressEmails wehn inviting users

* Skip InviteSent flag when suppressEmail is set

Keeps the resend-invite counter accurate so users.resendInvite can
still deliver the first email when the initial invite was silent.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 20:26:12 -04:00
Tom Moor 88ae883bd1 chore: Simplify deleted team handling in teamProvisioner (#12036) 2026-04-13 22:47:24 -04:00
wmTJc9IK0Q 21d4816a00 Copy fullWidth property when duplicating documents (#11980)
* Add fullWidth property copying to document duplication

Agent-Logs-Url: https://github.com/wmTJc9IK0Q/outline/sessions/6f30db31-b386-4c3d-8f04-db4dacfc2cdc

Co-authored-by: wmTJc9IK0Q <171362836+wmTJc9IK0Q@users.noreply.github.com>

* Fix lint errors in tests

Agent-Logs-Url: https://github.com/wmTJc9IK0Q/outline/sessions/6f30db31-b386-4c3d-8f04-db4dacfc2cdc

Co-authored-by: wmTJc9IK0Q <171362836+wmTJc9IK0Q@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Remove unnecessary declaration

---------

Co-authored-by: anthropic-code-agent[bot] <242468646+Claude@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-09 20:58:04 -04:00
Tom Moor c0ebed66f5 feat: Add patch support to MCP (#11987) 2026-04-09 20:57:02 -04:00
Tom Moor a411e08f1f chore: Address code quality findings (#11960)
* chore: Address code quality findings

* Round 2, quality findings

* fix: Add fallback for MediaQueryList.addEventListener in test env

The jsdom test environment doesn't implement addEventListener on
MediaQueryList. Prefer addEventListener but fall back to the
deprecated addListener when unavailable.
2026-04-04 16:11:10 -04:00
Tom Moor b2aad71cb4 chore: Move welcome email to processor (#11939)
* chore: Move welcome email to processor

* fix: Restore welcome email on invite acceptance
2026-04-02 20:16:47 -04:00
Tom Moor 0b213bd6b8 feat: Map document creator to existing users during JSON import (#11879)
* feat: Map creator/updater IDs to existing users during JSON import

When importing documents from JSON, resolve the original document author
to an internal user by matching on user ID first, then email, falling
back to the importing user. Results are cached to avoid redundant queries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Add negative caching for user resolution during import

Cache misses (not just hits) in resolveUserId so that repeated lookups
for users that don't exist in the target team are served from cache
instead of hitting the database for every document.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: Fix resolveUserId JSDoc to match actual behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-27 08:42:32 -04:00
Tom Moor 793804cd0d feat: Strip comments from presentation mode (#11860)
* feat: Strip comment marks from documents in presentation mode

Move removeMarks to shared ProsemirrorHelper and use it to strip comment
marks before rendering slides. Make server ProsemirrorHelper extend the
shared class to eliminate duplication and remove SharedProsemirrorHelper
imports from server code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Use Set for mark lookup and cloneDeep for browser compat

Use a Set for O(1) mark lookups in removeMarks traversal. Replace
structuredClone with lodash/cloneDeep to support older browsers
that lack the native API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: Add tests for ProsemirrorHelper.removeMarks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:21:43 -04:00
Tom Moor 5693618de4 Add translation hooks to transactional emails (#11785)
* First pass

* fix: Missing translations

* fix: Missing translations

* welcome

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* translations

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-20 23:28:51 -04:00
Igor Loskutov 64dc5e8ea7 fix: guard against concurrent restore in documentPermanentDeleter (#11775)
* fix: guard against concurrent restore in documentPermanentDeleter

* fix: bake deletedAt check into documentPermanentDeleter destroy WHERE clause
2026-03-18 08:33:09 -04:00
Tom Moor 1a893b0e45 Group sync framework (#11684)
Adds group sync from external authentication providers, allowing team group memberships to be automatically managed based on provider data on sign-in in the future.
2026-03-14 23:02:20 -04:00
Tom Moor 350f69e194 fix: Stale collaborator IDs (#11749) 2026-03-14 09:38:38 -04:00
Tom Moor 1b88189f9c fix: INSERT into subscriptions deadlocked transactions (#11667) 2026-03-05 18:53:13 -05:00
Tom Moor 749bf49ebe fix: Avatar upload (#11624)
* fix: Avatar upload

* Restore internal public ACL
2026-03-03 08:06:17 -05:00
Copilot 1c52a3e7da Fix custom emoji UUID escaping in API document creation (#11594)
* Initial plan

* Add custom emoji UUID parsing support

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Fix custom emoji UUID parsing - working solution

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Add JSDoc and improve code quality based on review

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Add JSON content verification to custom emoji test

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
2026-02-27 19:32:06 -05:00
Tom Moor 7be893f9a3 Refactor templates (#11027)
closes #8674
2026-02-20 18:53:00 -05:00
Tom Moor 7824f6b363 feat: Allow creating new doc before/after (#11453) 2026-02-14 17:24:52 -05:00
Copilot c382e1233b Convert markdown frontmatter to YAML codeblocks on import (#11420)
* Initial plan

* Add frontmatter to YAML codeblock conversion

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Add edge case tests and fix frontmatter regex, install types

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Address code review feedback - improve template literal readability

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
2026-02-12 18:32:15 -05:00
Tom Moor 1488341f66 fix: Remove unnecessary loading of authentication rows in userProvisioner (#11413)
* fix: Remove unneccessary loading of authentication rows in userProvisioner

* test
2026-02-11 18:45:47 -05:00
Tom Moor bb128318da perf: Remove turndown (#11331)
* Remove turndown

* Refactor htmlToProsemirror

* fix: Bug in CSV import

* refactor
2026-01-31 20:56:36 -05:00
Tom Moor 49f918e7f5 perf: Remove Markdown conversion when importing HTML (#11315)
* wip

* fix: Remove unused variable in ProsemirrorHelper.extractEmojiFromStart

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* test

* DRY

* Restore cleanup

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 16:26:33 -05:00
Tom Moor 00fb4d1af7 chore: Update node style imports (#11277)
- crypto → node:crypto
  - fs → node:fs
  - fs/promises → node:fs/promises
  - path → node:path
  - http → node:http
  - https → node:https
  - stream → node:stream
  - buffer → node:buffer
  - url → node:url
  - os → node:os
  - net → node:net
  - dns → node:dns
  - events → node:events
  - readline → node:readline
  - querystring → node:querystring
  - util → node:util
2026-01-26 20:51:50 -05:00
Tom Moor 1cc4d879dc fix: Sync API changes to clients in realtime (#11186)
* fix: Sync API changes to clients in realtime

* Add editMode parameter

* rename

* Add error handling

* refactor
2026-01-19 13:28:44 -05:00
Tom Moor 094ff17f74 fix: Update auth provider instead of throwing (#11131) 2026-01-13 19:58:47 -05:00
Newton 2d1092a2ca feat: Use signed urls in "copy as markdown" (#10821)
* feat: Use signed urls (ttl configurable) for attachment urls in "copy markdown"

* make signed urls a parameter, not a instance configuration

* feat(fix): copy as markdown: refactor toMarkdown (use signed urls)

* attempt to fix tests failing

* adjust markdown exporting in revisions too

* formatting

---------

Co-authored-by: Tom Moor <tom@getoutline.com>
2026-01-10 21:42:44 -05:00
Tom Moor 7663c2a643 feat: Add backlinks to publicly shared documents (#11141)
* Add backlinks support for publicly shared documents

Include backlinks in the documents.info API response for publicly shared documents, filtering to only show backlinks that exist within the shared tree.

Changes:
- Add findSourceDocumentIdsInSharedTree method to Relationship model to find backlinks within allowed document IDs
- Export getAllIdsInSharedTree helper from shareLoader for reuse
- Update presentDocument to accept and include backlinkIds in response
- Modify documents.info endpoint to fetch and include backlinks for public shares
- Add backlinkIds property to Document model and update backlinks getter to use it when available

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* refactor

* refactor

* wip

* tsc

* fix: Signed-out view throw, spacing

* revert

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 16:18:45 -05:00
Tom Moor b123762e86 chore: Remove collection.url, fix post-signin redirect (#11139) 2026-01-10 16:19:23 +00:00
Tom Moor a3b2615edf chore: Remove future public bucket usage (#10977)
* No longer upload avatars to public bucket

* Public redirect

* tests

* test

* test
2025-12-24 20:24:58 -05:00
Tom Moor fbd4ded5b4 feat: Add authentication provider management (#10997)
* Gemini first-pass

* Prevent post-connect login

* stash

* stash

* Add OIDC logo

* Separate security page

* test

* Update icon

* test

* ui

* Add extra guards for disabling auth provider

* refactor

* test
2025-12-24 09:09:24 -05:00
Tom Moor d67b881b93 fix: Appending content via API (#10998)
* fix: Appending content via API

closes #10936

* Append without newline
2025-12-23 21:48:25 -05:00
Tom Moor bf45e97641 chore: Enforce type import consistency (#10968)
* Update types

* fix circular dep

* type imports

* lint type imports and --fix
2025-12-19 23:07:02 -05:00
Tom Moor 2b84770b0d fix: path in sitemap.xml for root node on domain share (#10957) 2025-12-18 18:12:15 -05:00
Tom Moor 206df6afd7 perf: Reducing database contention (#10926)
* perf: Remove findOrCreate in views.create

* findOrCreate for subscriptionCreator

* test

* Remove findOrCreate for document,collection,group memberships

* tsc
2025-12-16 04:58:21 -05:00