Skip to content

feat(plugins): implement plugin loader and integration points#135

Merged
sasagar merged 1 commit intofeature/plugin-event-busfrom
feature/plugin-loader
Jan 28, 2026
Merged

feat(plugins): implement plugin loader and integration points#135
sasagar merged 1 commit intofeature/plugin-event-busfrom
feature/plugin-loader

Conversation

@sasagar
Copy link
Collaborator

@sasagar sasagar commented Jan 27, 2026

Summary

This PR implements Phase 2 of the plugin system: Plugin Loader and Integration Points.

Depends on: #134 (Phase 1 - Event Bus)

Changes

  • PluginLoader class (packages/backend/src/plugins/loader.ts)

    • Discovers and loads plugins from filesystem
    • Handles plugin lifecycle (onLoad/onUnload)
    • Dependency resolution with topological sort
    • Version compatibility checking
    • Enable/disable functionality
  • Plugin Configuration Storage

    • InMemoryPluginConfigStorage for development/testing
    • DatabasePluginConfigStorage for production (persistent)
    • New plugin_configs table in database schema
  • Plugin System Initialization (packages/backend/src/plugins/init.ts)

    • Integrates with app startup
    • Registers plugin routes under /api/x/{pluginId}/
    • Registers plugin middleware
    • Provides ActivityPub handler registration
  • App Integration (packages/backend/src/index.ts)

    • Plugin system initialization on startup
    • Graceful shutdown with plugin unloading
    • Environment variable configuration (PLUGINS_ENABLED, PLUGINS_DIR)

Plugin Directory Structure

Plugins are loaded from the ./plugins directory (configurable via PLUGINS_DIR):

plugins/
├── my-plugin/
│   ├── plugin.json    # or package.json
│   └── index.js       # Plugin entry point
└── another-plugin/
    ├── plugin.json
    └── index.js

Environment Variables

  • PLUGINS_ENABLED: Set to "false" to disable plugin system (default: enabled)
  • PLUGINS_DIR: Plugin directory path (default: "./plugins")
  • INSTANCE_NAME: Instance name passed to plugin context

Test plan

  • All 26 PluginLoader unit tests passing
  • All 1012 backend tests passing
  • TypeScript type checking passes
  • Manual testing with sample plugin

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • main
  • dev

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sasagar sasagar force-pushed the feature/plugin-event-bus branch from b6ec65c to ad0b799 Compare January 27, 2026 17:50
@sasagar sasagar force-pushed the feature/plugin-loader branch from 85c8d41 to c189281 Compare January 27, 2026 22:15
@sasagar sasagar force-pushed the feature/plugin-event-bus branch 2 times, most recently from 1979651 to d83663b Compare January 28, 2026 01:07
- Add PluginLoader class for plugin discovery and lifecycle management
- Implement DatabasePluginConfigStorage for persistent config
- Add plugin routes for admin API
- Support both array and object formats for plugin dependencies
- Provide proper PluginContext to ActivityPub handlers
- Fix TypeScript errors in test files
@sasagar sasagar force-pushed the feature/plugin-event-bus branch from d83663b to e1b6e9d Compare January 28, 2026 01:09
@sasagar sasagar force-pushed the feature/plugin-loader branch from c189281 to 1615cb0 Compare January 28, 2026 01:09
@sasagar sasagar merged commit 9c5f474 into feature/plugin-event-bus Jan 28, 2026
5 checks passed
@sasagar sasagar deleted the feature/plugin-loader branch January 28, 2026 01:34
sasagar added a commit that referenced this pull request Jan 28, 2026
* feat(plugins): implement event bus foundation for plugin system

- Add typed EventBus class with before/after event patterns
- Define plugin type interfaces (PluginUser, PluginNote, PluginFollow, PluginActivity)
- Use Visibility union type for type safety in note visibility
- Implement event payload types for all lifecycle events
- Add note lifecycle events: beforeCreate, afterCreate, beforeDelete, afterDelete
- Add user lifecycle events: beforeRegister, afterRegister, beforeLogin, afterLogin, afterLogout
- Add follow lifecycle events: afterCreate, afterDelete
- Add ActivityPub events: beforeInbox, afterInbox, beforeDelivery, afterDelivery
- Add moderation events: userSuspended, noteDeleted
- Integrate EventBus into DI container and middleware
- Emit events in NoteService, AuthService, FollowService
- Apply modifiedPayload from beforeCreate/beforeRegister events
- Remove PII (email) from user:beforeRegister payload
- Remove PII (ipAddress, userAgent) from user:beforeLogin payload
- Add shared toPluginUser/toPluginNote utility functions
- Add test helper factory functions
- Document composite followId format for delete events
- Document emitBefore error handling behavior

* feat(plugins): implement plugin loader and integration points (#135)

- Add PluginLoader class for plugin discovery and lifecycle management
- Implement DatabasePluginConfigStorage for persistent config
- Add plugin routes for admin API
- Support both array and object formats for plugin dependencies
- Provide proper PluginContext to ActivityPub handlers
- Fix TypeScript errors in test files

* feat(plugins): implement frontend plugin slots, admin UI, and sample plugin (#138)

Frontend Plugin System:
- Add PluginRegistry singleton for managing plugin state
- Create PluginSlot component for rendering plugin-provided components
- Define slot types (19 locations: note, compose, profile, settings, admin, etc.)
- Export public API from lib/plugins/index.ts

Admin Plugin Management:
- Add /admin/plugins page for viewing and managing plugins
- Enable/disable plugins through admin interface
- Display plugin status and version
- Add Plugins link to AdminNav

Sample Plugin:
- Add hello-world sample plugin demonstrating:
  - Plugin manifest (plugin.json)
  - Event subscriptions (note:afterCreate)
  - Custom API routes (/api/x/hello-world/)
  - Configuration storage
- Add plugins/README.md with development documentation
- Add comment explaining context unavailability in onUnload

Backend Updates:
- Add plugin routes at /api/plugins
- Add enabled check middleware for plugin routes (404 when disabled)
- Add enabled check for ActivityPub handlers
- Fix logger signature to accept variadic args
- Add manifest.id vs plugin.id mismatch validation
- Add PII comment for afterLogin event
- Remove sensitive fields (error, loadedAt) from public plugin endpoints
- Add description to plugin list API response

README Documentation:
- Update Phase 7 status to Complete
- Add Plugin System feature description
- Add Plugin Development documentation link
- Fix slot count (19 locations)

* chore(deps): update dependencies

Frontend:
- waku: 1.0.0-alpha.2 → 1.0.0-alpha.3
- jotai: 2.16.0 → 2.17.0
- @lingui/*: 5.7.0 → 5.9.0
- react/react-dom: 19.2.3 → 19.2.4
- react-hook-form: 7.68.0 → 7.71.1
- lucide-react: 0.561.0 → 0.563.0
- katex: 0.16.27 → 0.16.28

Backend:
- hono: 4.11.1 → 4.11.7
- zod: 4.2.1 → 4.3.6
- pino: 10.1.0 → 10.3.0
- pg: 8.16.3 → 8.17.2
- ioredis: 5.8.2 → 5.9.2
- bullmq: 5.66.1 → 5.67.2
- @aws-sdk/client-s3: 3.954.0 → 3.975.0
- mysql2: 3.16.0 → 3.16.2
- better-sqlite3: 12.5.0 → 12.6.2

Dev Tools:
- oxlint: 1.33.0 → 1.42.0
- @playwright/test: 1.57.0 → 1.58.0
- @types/bun: 1.3.4 → 1.3.7
- typedoc: 0.28.15 → 0.28.16
- vitest: 4.0.16 → 4.0.18

Jotai v2.17.0 deprecates loadable, setSelf, and removes
unstable_onInit, but these are not used in our codebase.

* fix: address CodeRabbit review comments

- Move pluginLoader middleware before routes for proper execution order
- Add db parameter to initializePluginSystem for persistent config storage
- Remove unused getAll/setMultiple methods from DatabasePluginConfigStorage
- Fix Database type to use NodePgDatabase instead of PostgresJsDatabase

* fix: address additional CodeRabbit review comments

- Use top-level await for plugin initialization to avoid race conditions
- Fix middleware type in loader.ts (unknown[] → MiddlewareHandler[])
- Remove unnecessary type cast in init.ts
- Track plugin handler errors in compositeHandler for accurate metrics

* fix: address additional plugin system review comments

- Wrap plugin middleware with runtime enabled check to skip when disabled
- Fix loadManifest to ignore npm object-form dependencies in package.json
  (only array-form plugin IDs are accepted from package.json)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments