feat(plugins): sandboxed page/widget frames + trekBridge (M3)

Plugins can now render UI. Page plugins appear as a nav entry and open a
full-page sandboxed iframe; the frame talks to TREK only over the postMessage
bridge.

- Server serves plugin client assets at /plugin-frame/:id/* with a strict path
  guard and a locked-down, per-plugin CSP (default-src none; connect-src limited
  to declared outbound hosts; sandbox WITHOUT allow-same-origin -> opaque origin,
  so the frame can't read the session cookie or the parent DOM). Global CSP
  frameSrc relaxed from 'none' to 'self' for exactly these frames.
- GET /api/plugins feed lists active plugins for the client.
- Client: pluginStore + PluginFrame (the trekBridge host) authenticates every
  inbound message by SENDER WINDOW IDENTITY (event.source), not by a claimed id
  or origin; pushes context (theme/locale/tripId/userId), validates navigation,
  renders notifications as text, resizes widgets, and proxies trek:invoke to the
  plugin's own routes host-side (session cookie stays with the host).
- Page route /plugins/:id + Navbar nav injection for page plugins.

Dashboard widget slot and the trek:request core-data bridge are deferred to a
later slice.
This commit is contained in:
mauriceboe
2026-07-03 17:12:56 +02:00
parent d823ac443b
commit 037eb8a209
38 changed files with 603 additions and 8 deletions
+1
View File
@@ -178,6 +178,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'فشل الحفظ',
'admin.tabs.addons': 'الإضافات',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -157,6 +157,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Falha ao salvar',
'admin.tabs.addons': 'Complementos',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -158,6 +158,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Uložení se nezdařilo',
'admin.tabs.addons': 'Doplňky',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -160,6 +160,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Fehler beim Speichern',
'admin.tabs.addons': 'Addons',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin nicht gefunden',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Plugins von Drittanbietern auf deiner Instanz installieren und verwalten.',
'admin.plugins.disabledTitle': 'Plugins sind deaktiviert',
+1
View File
@@ -212,6 +212,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Failed to save',
'admin.tabs.addons': 'Addons',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -159,6 +159,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Error al guardar',
'admin.tabs.addons': 'Complementos',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -161,6 +161,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Erreur de sauvegarde',
'admin.tabs.addons': 'Extensions',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -206,6 +206,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Αποτυχία αποθήκευσης',
'admin.tabs.addons': 'Πρόσθετα',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -160,6 +160,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Nem sikerült menteni',
'admin.tabs.addons': 'Bővítmények',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -202,6 +202,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Gagal menyimpan',
'admin.tabs.addons': 'Addon',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -159,6 +159,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Impossibile salvare',
'admin.tabs.addons': 'Moduli',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -191,6 +191,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': '保存に失敗しました',
'admin.tabs.addons': 'アドオン',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -197,6 +197,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': '저장 실패',
'admin.tabs.addons': '애드온',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -160,6 +160,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Fout bij opslaan',
'admin.tabs.addons': 'Add-ons',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -153,6 +153,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Nie udało się zapisać szablonu',
'admin.tabs.addons': 'Dodatki',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -160,6 +160,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Ошибка сохранения',
'admin.tabs.addons': 'Дополнения',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -212,6 +212,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Det gick inte att spara',
'admin.tabs.addons': 'Tillägg',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -204,6 +204,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Kaydedilemedi',
'admin.tabs.addons': 'Eklentiler',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -160,6 +160,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Помилка збереження',
'admin.tabs.addons': 'Дополнения',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -212,6 +212,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Không lưu được',
'admin.tabs.addons': 'Tiện ích bổ sung',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -194,6 +194,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': '儲存失敗',
'admin.tabs.addons': '擴充套件',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',
+1
View File
@@ -155,6 +155,7 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': '保存失败',
'admin.tabs.addons': '扩展',
'admin.tabs.plugins': 'Plugins',
'plugins.notFound': 'Plugin not found',
'admin.plugins.title': 'Plugins',
'admin.plugins.subtitle': 'Install and manage third-party plugins on your instance.',
'admin.plugins.disabledTitle': 'Plugins are disabled',