9715 Commits

Author SHA1 Message Date
Tor Anders Johansen e325867716 feat(mcp): add fullWidth parameter to create_document and update_document tools (#12338)
The fullWidth field is already persisted on the Document model and
supported in the REST API schemas (DocumentsCreateSchema, DocumentsUpdateSchema),
but the built-in MCP server did not expose it.

This patch adds fullWidth as an optional boolean parameter to both
create_document and update_document MCP tools, passing it through to
documentCreator and documentUpdater respectively.
2026-05-13 08:32:40 -04:00
Tom Moor bc6aa11f5d fix: Table cell selection should not show in print (#12334) 2026-05-13 08:24:49 -04:00
Tom Moor 7c070df942 fix: Correct locking in comment anchor for update (#12332)
* fix: Lock error on MCP anchorText comment creation

* refactor
2026-05-12 22:22:52 -04:00
Tom Moor 925a43bd36 feat: Inline comment support (#12322)
* feat: Inline comment support

* fix: wrap inline comment mark and creation in transaction with row lock

* fix: lock document row when anchoring, error on failed anchor, use uuid import
2026-05-12 21:22:38 -04:00
Tom Moor 6e99dff3c2 chore: Upgrade Mermaid (#12331) 2026-05-12 21:22:20 -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 42a0958322 test: Fix flaky comments.list ordering assertion (#12329)
Two comments built back-to-back could share a millisecond-precision
createdAt, leaving the DESC-ordered result non-deterministic. Pass
explicit createdAt values so the assertion on body.data[1] is stable.
2026-05-12 20:03:54 -04:00
Tom Moor 935e0bb7b9 chore: Fix all no-misused-spread lint warnings (#12327) 2026-05-12 17:30:08 -04:00
Tom Moor 871cb52a23 fix: Print includes extra blank page (#12326)
closes #12324
2026-05-12 12:15:25 +00:00
Tom Moor 58f031c7e9 fix: Crash on misconfigured file storage env (#12325)
closes #12323
2026-05-12 12:07:08 +00:00
dependabot[bot] fc01deeefd chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1 (#12320)
* chore(deps-dev): bump oxlint-tsgolint from 0.14.2 to 0.22.1

Bumps [oxlint-tsgolint](https://github.com/oxc-project/tsgolint) from 0.14.2 to 0.22.1.
- [Release notes](https://github.com/oxc-project/tsgolint/releases)
- [Commits](https://github.com/oxc-project/tsgolint/compare/v0.14.2...v0.22.1)

---
updated-dependencies:
- dependency-name: oxlint-tsgolint
  dependency-version: 0.22.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore: Switch tsconfig to bundler resolution for tsgolint 0.22.1

oxlint-tsgolint 0.22.1 removed support for moduleResolution=node10
(the alias for "node"). Switch to "bundler" with resolvePackageJsonExports
disabled so packages whose exports field omits a types condition still
resolve. Update markdown-it type imports to sub-paths since the package's
.d.mts entry only re-exports a subset of named types.

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

* fix: Resolve type-aware lint errors caught by tsgolint 0.22.1

oxlint-tsgolint 0.22.1 catches several await-thenable, no-floating-promises,
and no-meaningless-void-operator cases the prior 0.14.2 missed:

- Drop redundant inner `await` from Promise.all([await x, await y]) call sites
  so the array entries are real Promises rather than already-resolved values.
- Replace Promise.all wrappers around synchronous presenters (presentEvent,
  presentTemplate, presentPublicTeam) with plain map / direct calls.
- Wrap non-promise branches of ternaries inside Promise.all with
  Promise.resolve so the array remains thenable across both arms.
- Add `void` to the unawaited provider.connect() in the auth-failed retry
  chain, and remove `void` from the disconnect() call which returns void.

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-12 07:59:13 -04:00
Tom Moor 3109f49b40 feat: Allow MCP to access signed attachment urls through fetch tool (#12315)
* feat: Add ability for MCP to access signed attachment urls through fetch tool

* Potential fix for pull request finding

* fix: non-admin cannot fetch attachments
2026-05-11 22:16:20 -04:00
dependabot[bot] dab06d4dfa chore(deps): bump i18next-fs-backend from 2.6.4 to 2.6.5 (#12319) 2026-05-11 20:19:11 -04:00
dependabot[bot] dcddab47e1 chore(deps): bump koa-compress from 5.1.1 to 5.2.1 (#12318) 2026-05-11 20:17:56 -04:00
dependabot[bot] 0eee576b81 chore(deps): bump the aws group with 5 updates (#12317) 2026-05-11 20:17:07 -04:00
Tom Moor 51a1d3bf50 perf: Cache decorations in editor plugins (#12030)
Avoid full document traversal on every keystroke by mapping decorations
through the transaction when no relevant nodes changed. Uses
changedDescendants to detect when a heading, image, or code_inline-marked
text actually changes; otherwise the existing DecorationSet is mapped to
new positions cheaply.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 11:09:57 -04:00
Tom Moor ff3b3ce552 fix: Allow empty string in optional MCP fields (#12310)
* fix: Allow empty string in optional fields

* fix: Preserve empty strings for content fields in MCP tools

Address review feedback by reverting content/text fields (description, document
text, comment text) back to z.string().optional() so callers can intentionally
clear values via "". optionalString() is reserved for identifier and query
fields where "" is not a meaningful input.
2026-05-10 10:47:24 -04:00
Tom Moor ab42e4fda8 chore(deps): Remove js-yaml resolution that no longer prevents downgrades (#12309)
The "js-yaml": "^4.1.1" resolution is now a no-op — every package that
requests js-yaml in the dep graph already asks for ^4.1.0 or ^4.1.1, both
of which naturally resolve to 4.1.1. Removing the resolution does not
change any installed version.

Audited the remaining resolutions; all still prevent a lower version from
being installed (or are intentional dedupe pins for @types/* and
prosemirror-transform per #12304, plus the i18next-parser compatibility
pin from #12307).

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-10 09:32:30 -04:00
Tom Moor 2cb47aa421 chore(deps): Bump i18next-parser to 9.4.0 to fix pre-commit hook (#12307)
i18next-parser 8.13.0 used a default import for cheerio, which broke
when cheerio dropped its default export. 9.x switched to a namespace
import. Pin the parser's transitive i18next to ^23.16.8 so plural keys
continue to be emitted in compatibilityJSON v3 format expected by the
runtime (i18next 22.5.1).
2026-05-09 13:53:45 -04:00
Tom Moor 7ff1c84530 chore: Short-circuit common scanner/crawler routes (#12306)
* Shortcircuit common scanner/crawler routes

* PR feedback, remove query strings
2026-05-09 11:32:17 -04:00
dependabot[bot] fba1bcef87 chore(deps): bump hono from 4.12.16 to 4.12.18 (#12305)
Bumps [hono](https://github.com/honojs/hono) from 4.12.16 to 4.12.18.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.16...v4.12.18)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.18
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-09 09:09:36 -04:00
Tom Moor 4548fc00bf chore(deps): Remove resolutions that no longer prevent downgrades (#12304)
* chore(deps): Remove resolutions that no longer prevent downgrades

Audited each resolution by removing it and running yarn install to check
whether any package would resolve to a lower version. Removed 31 entries
that were no-ops because the natural resolution already satisfies (or
exceeds) the resolution target — caret ranges that npm now publishes a
matching or higher version for, and one fast-xml-parser pin where the
underlying dependency moved.

Kept 13 entries: those that still prevent a regression, plus the @types/*
and prosemirror-transform pins that exist to dedupe transitive copies
against the project's own pinned versions.

* chore(deps): Bump @babel/preset-env to 7.29.5 to address GHSA-fv7c-fp4j-7gwp

@babel/plugin-transform-modules-systemjs <=7.29.3 generates arbitrary
code when compiling malicious input. Upgrading @babel/preset-env to
^7.29.5 brings in the patched ^7.29.4 transitively.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-09 09:02:50 -04:00
Tom Moor 7a75433bdc fix: Move OIDC redirect to useEffect (#12301) 2026-05-09 08:42:53 -04:00
Salihu b4cbb39f17 feat: request document access (#10825)
* feat: Request document access

Allow users without permission to a document to request access. Notifies
document managers via in-app notification and email; managers can grant
or dismiss the request.

- Adds AccessRequest model, migration, policy, presenter
- Adds accessRequests.create/info/approve/dismiss endpoints
- Adds DocumentAccessRequestNotificationsTask + email
- Adds Error403 request flow with loading state and pending indicator
- Auto-opens notifications popover via ?notifications=true (used in email)
- Adds SplitButton primitive for permission selection in notifications
- Refactors useConsumeQueryParam hook

* refactor

* fix: Make approve/dismiss idempotent on access requests

Return success when the access request has already been dismissed, or
when the user already has document membership at approve time, instead
of throwing 400. Avoids racy double-clicks on notification actions
producing user-visible errors.

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

* Minor fixes

---------

Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 08:42:47 -04:00
Tom Moor 56c3267186 Update popularity scoring to use document_insights table as data source (#12103)
* Update popularity scoring to use document_insights as data source

* Use UTC dates and guard against future-dated insights

Derive threshold/today as UTC day boundaries to match how document_insights.date is written, and add an upper bound to prevent future-dated rollups from collapsing the decay denominator.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 23:22:00 -04:00
Tom Moor 3670a918bb chore: Catch other types of client aborted error (#12303)
* chore: Catch other types of client aborted error

* Add EPIPE
2026-05-08 22:32:54 -04:00
Mark Steward fa990a33c0 Only preconnect to S3 if it's being used (#12298) 2026-05-08 14:41:32 -04:00
dependabot[bot] 8248fafe70 chore(deps): bump fast-uri from 3.1.0 to 3.1.2 (#12300)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/fastify/fast-uri/releases)
- [Commits](https://github.com/fastify/fast-uri/compare/v3.1.0...v3.1.2)

---
updated-dependencies:
- dependency-name: fast-uri
  dependency-version: 3.1.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 14:41:20 -04:00
dependabot[bot] a346e6dee6 chore(deps): bump fast-xml-builder from 1.1.5 to 1.1.8 (#12299)
Bumps [fast-xml-builder](https://github.com/NaturalIntelligence/fast-xml-builder) from 1.1.5 to 1.1.8.
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-builder/blob/main/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-builder/compare/v1.1.5...v1.1.8)

---
updated-dependencies:
- dependency-name: fast-xml-builder
  dependency-version: 1.1.8
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-08 14:32:14 -04:00
Tom Moor 571463710e Add support for data uri for images (#12294)
* Add support for data uri for images

* hoist
2026-05-08 09:10:32 -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 8371d709dd fix: Regression in client plugins not loading (#12291) 2026-05-07 15:44:30 -04:00
Tom Moor 4aa1c3289a chore: Add MCP user flag (#12290)
* Add MCP flag

* PR feedback
2026-05-07 08:34:54 -04:00
Tom Moor 87029a3ad7 chore(deps): bump ip-address to 10.2.0 to address XSS advisory (#12286)
* chore(deps): bump ip-address to 10.2.0 to address XSS advisory
2026-05-07 08:22:07 -04:00
Tom Moor d02659d325 chore: Remove stale Jest references from docs and comments (#12285)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 21:55:07 -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 4387f3ced7 fix: Resolve console warnings for rtl DOM attribute and untracked MobX read (#12284)
- Use transient `$rtl` prop on Meta styled component so it isn't forwarded to the DOM
- Wrap ActionButton in observer so action visibility checks read MobX computed values inside a reactive context

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 20:48:13 -04:00
dependabot[bot] 9ddb57f1d3 chore(deps): bump hono from 4.12.12 to 4.12.16 (#12283)
Bumps [hono](https://github.com/honojs/hono) from 4.12.12 to 4.12.16.
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.12...v4.12.16)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.16
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-06 20:34:40 -04:00
Tom Moor ad7e6c98ab chore: Vendor request-filtering-agent (#12266)
* chore: Vendor request-filtering-agent

* fix: honor fetch timeout and undefined allow list in proxy pre-flight

Default allowIPAddressList to [] so an unset ALLOWED_PRIVATE_IP_ADDRESSES
env var doesn't overwrite the agent's default and crash on .length, and
race the pre-flight DNS lookup against the request's abort signal so the
configured fetch timeout applies to slow DNS resolution.

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 20:26:52 -04:00
Tom Moor 0f3f7b8da7 refactor: Remove useDictionary hook in favor of i18next t directly (#12282)
Plumbed `dictionary` props through editor components, menus, extensions,
and nodes. Replaces with `useTranslation()` in React contexts and direct
`t` imports from i18next elsewhere.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 20:24:50 -04:00
Tom Moor 4883071059 Allow viewers to create and access API keys (#12278)
* Allow viewers to create and access API keys

Still guarded by their view permissions

* Drop Member role gate from apiKeys routes

Lets viewers reach the createApiKey/listApiKeys/delete policy checks now
that the policy itself permits them. Updates CleanupDemotedUserTask to
retain viewer keys and adds coverage for viewer create + guest reject.

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

* Tighten apiKeys test assertions and broaden viewer coverage

- Use not.toBeNull() instead of toBeTruthy() for retention check
- Add viewer coverage for apiKeys.list and apiKeys.delete

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 19:35:59 -04:00
Tom Moor e0bc08478d feat: Add system preference to open desktop app on startup (#12279)
* feat: Adds toggle to open desktop app on startup

* Remove name hardcoding

* refactor
2026-05-06 19:29:42 -04:00
Tom Moor cc25790c81 Add mobile drawer support to notifications popover (#12276)
* fix: Open notifications in a bottom drawer on mobile

Match the mobile context menu pattern by rendering the notifications
panel as a Vaul bottom drawer below the tablet breakpoint, while
keeping the existing Radix popover on desktop.

* fix: Notification drawer opens at correct height on mobile

Skip the height animation while bounds is unmeasured to avoid a
feedback loop between framer-motion's animation toward 0 and the
ResizeObserver re-targeting it. Eagerly import Notifications so first
paint has real content for the initial measurement, and bump its
minHeight to 75vh on mobile to match other bottom drawers.

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-06 07:42:53 -04:00
Tom Moor 41031aa7e6 Optimize icon picker for mobile with responsive sizing (#12275)
* Increase emoji picker cell size on mobile

Mobile uses a 40px button with a 32px emoji glyph (vs. 32px / 24px on
desktop), so roughly 8 emojis fit across a typical phone screen for
easier touch targeting.

https://claude.ai/code/session_017Rrv75Rc6eZ7eb2iNpZxpu

* tweaks

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-05 23:37:15 -04:00
Tom Moor 913322c0d5 fix: Search highlights not rendering in Firefox (#12273)
@emotion/stylis compiles top-level `::highlight(name)` rules inside a
styled component as a compound selector `.parent::highlight(name)`,
which only matches highlights on the editor container element itself.
Chrome applies these leniently, but Firefox correctly requires the
originating element to contain the highlighted text. Prefixing with
`&` forces a descendant combinator so descendant elements containing
the highlighted text are matched.

Closes #12270
2026-05-05 17:44:10 -04:00
Tom Moor 3562056d72 Reduce minimum table col width to 25px (#12269) 2026-05-05 08:40:36 -04:00
Tom Moor e7623eeade fix: Cannot select doc text in version history (#12268)
* fix: Cannot select doc text in version history

* PR feedback, use deco cache
2026-05-05 08:35:26 -04:00
Tom Moor 0df6c4947a chore(test): Performance (#12267)
* chore(test): drop no-op per-test Redis flushall

The afterEach created a fresh ioredis-mock client and flushed it, which
doesn't clear state held by clients elsewhere in the test. Removing the
hook saves a few ms across thousands of test cases.

* Cache Jest transform cache
2026-05-05 08:26:55 -04:00
Tom Moor a7c95b8d7e chore(ci): Parallelize jobs and remove serial setup gate (#12265)
Drop the dedicated setup job that blocked every other job for ~60s,
extract the install steps into a reusable composite action, drop the
unnecessary bundle-size dependency on types, and switch test-server
sharding to Jest's native --shard flag.
2026-05-05 07:50:53 -04:00