* perf: Avoid correlated subquery in Slack hooks user lookup
Query UserAuthentication directly by indexed providerId and load the
associated User and Team, instead of driving from User.findOne with a
required hasMany include — which Sequelize translates into a correlated
subquery that scans the users table.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix: Scope Slack fallback user lookup to matching AuthenticationProvider
The fallback in findUserForRequest matched any UserAuthentication with
the same providerId, which is only unique per (providerId, userId).
A colliding external user id from another workspace or provider could
resolve a user from the wrong team. Constrain via the AuthenticationProvider
join (name = "slack", providerId = serviceTeamId).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* 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
* 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>
* 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.
* chore: resolve no-explicit-any lint warnings in plugins
Replaces uses of `any` in the plugins directory with concrete types,
`unknown`, or structured type assertions, addressing the remaining
typescript-eslint(no-explicit-any) warnings flagged by oxlint.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: address review feedback in GitLabIssueProvider
Drop trailing semicolon from log string and add early return in
`destroyNamespace` when neither `user_id` nor `full_path` is present
to avoid an unnecessary full-scan transaction.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* feat: Extract search into pluggable provider system
Refactors the monolithic SearchHelper into a pluggable search provider
architecture, enabling alternative search backends (Elasticsearch,
Turbopuffer, etc.) while preserving PostgreSQL full-text search as the
default. The SEARCH_PROVIDER env var selects the active provider.
- Add BaseSearchProvider abstract class and SearchProviderManager
- Add Hook.SearchProvider to the plugin system
- Move PostgreSQL search logic into plugins/postgres-search/
- Add SearchIndexProcessor for event-driven index sync
- Update all callers to use the provider manager directly
- Keep SearchHelper as a deprecated thin wrapper for backwards compat
Closes#11347
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: Remove deprecated SearchHelper wrapper
All callers now use SearchProviderManager directly, so the thin
delegation wrapper is no longer needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: Rename postgres-search plugin to search-postgres
Renames the plugin folder and id so that future search provider plugins
(e.g. search-elasticsearch, search-turbopuffer) will be colocated
alphabetically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: Remove special-case plugin import from SearchProviderManager
Make PluginManager.loadPlugins resilient to individual plugin load
failures so SearchProviderManager can use the standard getHooks path
without needing to directly import the search-postgres plugin.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: Add missing search provider tests for full coverage parity
Adds all tests that existed in the old SearchHelper.test.ts but were missing
from PostgresSearchProvider.test.ts, including searchTitlesForUser status
filters, collection filtering, group memberships, and sorting tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feedback
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* OAuth
* store logo
* unfurl support
* refresh token
* support for list
* embed list
* mention menu for all embeds in a list
* multi-level list
* logo
* account level connection
* tsc
* Update Icon.tsx
* coderabbit feedback
* RFC 6749 suggestion
---------
Co-authored-by: Tom Moor <tom@getoutline.com>
* shares.info, collections.info, documents.info
* shares.list, shares.create, shares.update
* shares.sitemap
* parity with existing document shared screen
* collection share popover
* parent share and table
* collection scene
* collection link in sidebar
* sidebar and breadcrumb collection link click
* collection link click in editor
* meta
* more meta + 404 page
* map internal link, remove showLastUpdated option
* fix shares.list pagination
* show last updated
* shareLoader tests
* lint
* sidebar context for collection link
* badge in shares table
* fix existing tests
* tsc
* update failing test snapshot
* env
* signed url for collection attachments
* include collection content in SSR for screen readers
* search
* drafts can be shared
* review
* tsc, remove old shared-doc scene
* tweaks
* DRY
* refactor loader
* Remove share/collection urls
* fix: Collection overview should not be editable when viewing shared link and logged in
* Tweak public breadcrumb
* fix: Deleted documents should never be exposed through share
* empty sharedTree array where includeChildDocuments is false
* revert includeChildDocs guard for logical correctness + SSR bug fix
* fix: check document is part of share
---------
Co-authored-by: Tom Moor <tom@getoutline.com>
* fix: extract domain from user email in Slack authentication
Fixes#9641 - Slack auth fails when OIDC is enabled
* Added tests for domain extraction functionality
Added parseEmail import
* Fix Slack OIDC authentication to retain original subdomain logic (profile.team.domain) while adding domain extraction from user email
* Update slack.ts
---------
Co-authored-by: Tom Moor <tom@getoutline.com>
* Upgrade Prettier to v3.6.2 and eslint-plugin-prettier to v5.5.1
- Upgraded prettier from ^2.8.8 to ^3.6.2 (latest version)
- Upgraded eslint-plugin-prettier from ^4.2.1 to ^5.5.1 for compatibility
- Applied automatic formatting changes from new Prettier version
- All existing ESLint and Prettier configurations remain compatible
* Applied automatic fixes
* Trigger CI
---------
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
* Update Switch component onChange handler to use boolean callback
- Remove synthetic event handling from Switch component
- Update onChange signature to (checked: boolean) => void
- Update all call points across the codebase:
- PublicAccess.tsx: Updated handlers for indexing, showLastModified, and published switches
- Security.tsx: Created individual handlers for all security preferences
- Preferences.tsx: Created individual handlers for user preferences
- CollectionForm.tsx: Added createSwitchRegister helper for react-hook-form compatibility
- TemplatizeDialog: Updated publish handler
- DocumentMenu.tsx: Added handlers for embeds and full-width toggles
- Search.tsx: Updated SearchTitlesFilter handler
- Application.tsx: Added createSwitchRegister helper
- Details.tsx: Updated public branding handler
- Features.tsx: Created individual handlers for seamless edit and commenting
- OAuthClientForm.tsx: Added createSwitchRegister helper
- Maintained backward compatibility with react-hook-form
- Improved type safety and code clarity
* Fix ESLint floating promise errors
- Add void operator to onChange call in CollectionForm.tsx
- Add void operator to document.save call in DocumentMenu.tsx
These changes fix the @typescript-eslint/no-floating-promises errors
while maintaining the existing functionality.
* Fix Switch component onChange handlers in remaining files
- Updated DocumentCopy.tsx handlers to use boolean parameter
- Updated Notifications.tsx to use closure pattern for event types
- Updated SlackListItem.tsx to use closure pattern for event names
- All TypeScript errors resolved
* Refactor createSwitchRegister into utils/forms
- Created shared utility function in app/utils/forms.ts
- Removed duplicate implementations from CollectionForm, Application, and OAuthClientForm
- Updated all usage points to use the shared utility
- Improved TypeScript typing with Record<string, unknown>
- Fixed imports and removed unused variables
- Maintained existing functionality while reducing code duplication
* Fix TypeScript errors in createSwitchRegister utility
- Updated generic constraint from Record<string, unknown> to FieldValues
- Added Path import from react-hook-form for proper type safety
- Fixed parameter type from keyof TFormData to Path<TFormData>
- Improved type compatibility with react-hook-form's UseFormRegister
Resolves TypeScript compilation errors in CI pipeline.
* Remove unnecessary handlePublishChange callbacks
- Removed handlePublishChange wrapper in DocumentCopy.tsx
- Removed handlePublishChange wrapper in TemplatizeDialog/index.tsx
- Updated Switch components to use setPublish directly
- Simplified code by leveraging boolean callback from Switch component
Since Switch now passes boolean directly, no need for intermediate callbacks.
* Address review feedback: simplify callbacks and fix fullWidth behavior
1. DocumentCopy.tsx:
- Remove handleRecursiveChange callback wrapper
- Use setRecursive directly with Switch component
2. DocumentMenu.tsx:
- Add void user.save() to persist user preference
- Add document.fullWidth = checked for optimistic update behavior
Both changes leverage the boolean callback from Switch component properly.
* Update Security.tsx
* i18n
---------
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
* Upgrade @typescript-eslint dependencies from v6.21.0 to v8.33.0
- Updated @typescript-eslint/eslint-plugin from ^6.21.0 to ^8.33.0
- Updated @typescript-eslint/parser from ^6.21.0 to ^8.33.0
- Tested linting functionality to ensure compatibility
- This brings the latest TypeScript ESLint features and bug fixes
* lint
* tsc
---------
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>