@open-mercato/core 0.6.7-develop.6785.1.1dd7cfac55 → 0.6.7-develop.6795.1.8a3f27921c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities.ids.generated.js +1 -0
  3. package/dist/generated/entities.ids.generated.js.map +2 -2
  4. package/dist/modules/auth/backend/settings/page.js +14 -9
  5. package/dist/modules/auth/backend/settings/page.js.map +2 -2
  6. package/dist/modules/customers/cli.js +17 -7
  7. package/dist/modules/customers/cli.js.map +2 -2
  8. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +229 -216
  9. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  10. package/dist/modules/customers/search.js +50 -29
  11. package/dist/modules/customers/search.js.map +2 -2
  12. package/dist/modules/data_sync/api/mappings/[id]/route.js +22 -9
  13. package/dist/modules/data_sync/api/mappings/[id]/route.js.map +2 -2
  14. package/dist/modules/data_sync/api/mappings/route.js +13 -4
  15. package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
  16. package/dist/modules/data_sync/api/options.js +7 -2
  17. package/dist/modules/data_sync/api/options.js.map +2 -2
  18. package/dist/modules/data_sync/api/run.js +7 -2
  19. package/dist/modules/data_sync/api/run.js.map +2 -2
  20. package/dist/modules/data_sync/api/runs/[id]/cancel.js +8 -3
  21. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  22. package/dist/modules/data_sync/api/runs/[id]/retry.js +7 -2
  23. package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
  24. package/dist/modules/data_sync/api/runs/[id]/route.js +8 -3
  25. package/dist/modules/data_sync/api/runs/[id]/route.js.map +2 -2
  26. package/dist/modules/data_sync/api/runs.js +7 -2
  27. package/dist/modules/data_sync/api/runs.js.map +2 -2
  28. package/dist/modules/data_sync/api/schedules/[id]/route.js +19 -6
  29. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  30. package/dist/modules/data_sync/api/schedules/route.js +13 -4
  31. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  32. package/dist/modules/data_sync/api/validate.js +9 -4
  33. package/dist/modules/data_sync/api/validate.js.map +2 -2
  34. package/dist/modules/design_system/acl.js +9 -0
  35. package/dist/modules/design_system/acl.js.map +7 -0
  36. package/dist/modules/design_system/backend/design-system/page.js +11 -0
  37. package/dist/modules/design_system/backend/design-system/page.js.map +7 -0
  38. package/dist/modules/design_system/backend/design-system/page.meta.js +15 -0
  39. package/dist/modules/design_system/backend/design-system/page.meta.js.map +7 -0
  40. package/dist/modules/design_system/gallery/components/CodeSnippet.js +52 -0
  41. package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +7 -0
  42. package/dist/modules/design_system/gallery/components/EntryCard.js +63 -0
  43. package/dist/modules/design_system/gallery/components/EntryCard.js.map +7 -0
  44. package/dist/modules/design_system/gallery/components/GalleryShell.js +163 -0
  45. package/dist/modules/design_system/gallery/components/GalleryShell.js.map +7 -0
  46. package/dist/modules/design_system/gallery/components/VariantPreview.js +9 -0
  47. package/dist/modules/design_system/gallery/components/VariantPreview.js.map +7 -0
  48. package/dist/modules/design_system/gallery/entries/banners.js +186 -0
  49. package/dist/modules/design_system/gallery/entries/banners.js.map +7 -0
  50. package/dist/modules/design_system/gallery/entries/buttons.js +361 -0
  51. package/dist/modules/design_system/gallery/entries/buttons.js.map +7 -0
  52. package/dist/modules/design_system/gallery/entries/charts.js +457 -0
  53. package/dist/modules/design_system/gallery/entries/charts.js.map +7 -0
  54. package/dist/modules/design_system/gallery/entries/dates.js +306 -0
  55. package/dist/modules/design_system/gallery/entries/dates.js.map +7 -0
  56. package/dist/modules/design_system/gallery/entries/detail.js +358 -0
  57. package/dist/modules/design_system/gallery/entries/detail.js.map +7 -0
  58. package/dist/modules/design_system/gallery/entries/display.js +785 -0
  59. package/dist/modules/design_system/gallery/entries/display.js.map +7 -0
  60. package/dist/modules/design_system/gallery/entries/feedback.js +658 -0
  61. package/dist/modules/design_system/gallery/entries/feedback.js.map +7 -0
  62. package/dist/modules/design_system/gallery/entries/filters.js +505 -0
  63. package/dist/modules/design_system/gallery/entries/filters.js.map +7 -0
  64. package/dist/modules/design_system/gallery/entries/foundations.js +453 -0
  65. package/dist/modules/design_system/gallery/entries/foundations.js.map +7 -0
  66. package/dist/modules/design_system/gallery/entries/icons.js +140 -0
  67. package/dist/modules/design_system/gallery/entries/icons.js.map +7 -0
  68. package/dist/modules/design_system/gallery/entries/inputs.js +1217 -0
  69. package/dist/modules/design_system/gallery/entries/inputs.js.map +7 -0
  70. package/dist/modules/design_system/gallery/entries/messages.js +334 -0
  71. package/dist/modules/design_system/gallery/entries/messages.js.map +7 -0
  72. package/dist/modules/design_system/gallery/entries/navigation.js +475 -0
  73. package/dist/modules/design_system/gallery/entries/navigation.js.map +7 -0
  74. package/dist/modules/design_system/gallery/entries/notifications.js +257 -0
  75. package/dist/modules/design_system/gallery/entries/notifications.js.map +7 -0
  76. package/dist/modules/design_system/gallery/entries/overlays.js +576 -0
  77. package/dist/modules/design_system/gallery/entries/overlays.js.map +7 -0
  78. package/dist/modules/design_system/gallery/entries/scaffolding.js +378 -0
  79. package/dist/modules/design_system/gallery/entries/scaffolding.js.map +7 -0
  80. package/dist/modules/design_system/gallery/entries/schedule.js +297 -0
  81. package/dist/modules/design_system/gallery/entries/schedule.js.map +7 -0
  82. package/dist/modules/design_system/gallery/registry.js +139 -0
  83. package/dist/modules/design_system/gallery/registry.js.map +7 -0
  84. package/dist/modules/design_system/gallery/types.js +1 -0
  85. package/dist/modules/design_system/gallery/types.js.map +7 -0
  86. package/dist/modules/design_system/index.js +9 -0
  87. package/dist/modules/design_system/index.js.map +7 -0
  88. package/dist/modules/design_system/setup.js +14 -0
  89. package/dist/modules/design_system/setup.js.map +7 -0
  90. package/dist/modules/inbox_ops/search.js +15 -4
  91. package/dist/modules/inbox_ops/search.js.map +2 -2
  92. package/dist/modules/integrations/api/[id]/credentials/route.js +11 -5
  93. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  94. package/dist/modules/integrations/api/[id]/health/route.js +6 -3
  95. package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
  96. package/dist/modules/integrations/api/[id]/route.js +6 -3
  97. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  98. package/dist/modules/integrations/api/[id]/state/route.js +6 -3
  99. package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
  100. package/dist/modules/integrations/api/[id]/version/route.js +6 -3
  101. package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
  102. package/dist/modules/integrations/api/logs/route.js +6 -3
  103. package/dist/modules/integrations/api/logs/route.js.map +2 -2
  104. package/dist/modules/integrations/api/route.js +6 -3
  105. package/dist/modules/integrations/api/route.js.map +2 -2
  106. package/dist/modules/integrations/api/umes-read.js +2 -2
  107. package/dist/modules/integrations/api/umes-read.js.map +2 -2
  108. package/dist/modules/integrations/lib/organization-scope.js +2 -9
  109. package/dist/modules/integrations/lib/organization-scope.js.map +2 -2
  110. package/dist/modules/messages/search.js +10 -5
  111. package/dist/modules/messages/search.js.map +2 -2
  112. package/dist/modules/query_index/data/entities.js +2 -1
  113. package/dist/modules/query_index/data/entities.js.map +2 -2
  114. package/dist/modules/query_index/lib/engine.js +32 -50
  115. package/dist/modules/query_index/lib/engine.js.map +2 -2
  116. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js +17 -0
  117. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js.map +7 -0
  118. package/generated/entities.ids.generated.ts +1 -0
  119. package/package.json +16 -16
  120. package/src/modules/auth/backend/settings/page.tsx +17 -8
  121. package/src/modules/customers/cli.ts +17 -7
  122. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +24 -13
  123. package/src/modules/customers/i18n/de.json +17 -0
  124. package/src/modules/customers/i18n/en.json +17 -0
  125. package/src/modules/customers/i18n/es.json +17 -0
  126. package/src/modules/customers/i18n/pl.json +17 -0
  127. package/src/modules/customers/search.ts +59 -27
  128. package/src/modules/data_sync/AGENTS.md +1 -0
  129. package/src/modules/data_sync/api/mappings/[id]/route.ts +22 -9
  130. package/src/modules/data_sync/api/mappings/route.ts +13 -4
  131. package/src/modules/data_sync/api/options.ts +7 -2
  132. package/src/modules/data_sync/api/run.ts +7 -2
  133. package/src/modules/data_sync/api/runs/[id]/cancel.ts +8 -3
  134. package/src/modules/data_sync/api/runs/[id]/retry.ts +7 -2
  135. package/src/modules/data_sync/api/runs/[id]/route.ts +8 -3
  136. package/src/modules/data_sync/api/runs.ts +7 -2
  137. package/src/modules/data_sync/api/schedules/[id]/route.ts +19 -6
  138. package/src/modules/data_sync/api/schedules/route.ts +13 -4
  139. package/src/modules/data_sync/api/validate.ts +9 -4
  140. package/src/modules/design_system/AGENTS.md +34 -0
  141. package/src/modules/design_system/acl.ts +5 -0
  142. package/src/modules/design_system/backend/design-system/page.meta.ts +11 -0
  143. package/src/modules/design_system/backend/design-system/page.tsx +14 -0
  144. package/src/modules/design_system/gallery/components/CodeSnippet.tsx +55 -0
  145. package/src/modules/design_system/gallery/components/EntryCard.tsx +95 -0
  146. package/src/modules/design_system/gallery/components/GalleryShell.tsx +206 -0
  147. package/src/modules/design_system/gallery/components/VariantPreview.tsx +15 -0
  148. package/src/modules/design_system/gallery/entries/banners.tsx +226 -0
  149. package/src/modules/design_system/gallery/entries/buttons.tsx +422 -0
  150. package/src/modules/design_system/gallery/entries/charts.tsx +518 -0
  151. package/src/modules/design_system/gallery/entries/dates.tsx +325 -0
  152. package/src/modules/design_system/gallery/entries/detail.tsx +403 -0
  153. package/src/modules/design_system/gallery/entries/display.tsx +893 -0
  154. package/src/modules/design_system/gallery/entries/feedback.tsx +746 -0
  155. package/src/modules/design_system/gallery/entries/filters.tsx +570 -0
  156. package/src/modules/design_system/gallery/entries/foundations.tsx +529 -0
  157. package/src/modules/design_system/gallery/entries/icons.tsx +168 -0
  158. package/src/modules/design_system/gallery/entries/inputs.tsx +1516 -0
  159. package/src/modules/design_system/gallery/entries/messages.tsx +339 -0
  160. package/src/modules/design_system/gallery/entries/navigation.tsx +573 -0
  161. package/src/modules/design_system/gallery/entries/notifications.tsx +285 -0
  162. package/src/modules/design_system/gallery/entries/overlays.tsx +677 -0
  163. package/src/modules/design_system/gallery/entries/scaffolding.tsx +430 -0
  164. package/src/modules/design_system/gallery/entries/schedule.tsx +307 -0
  165. package/src/modules/design_system/gallery/registry.ts +152 -0
  166. package/src/modules/design_system/gallery/types.ts +32 -0
  167. package/src/modules/design_system/i18n/.hardcoded-allowlist.json +71 -0
  168. package/src/modules/design_system/i18n/de.json +46 -0
  169. package/src/modules/design_system/i18n/en.json +46 -0
  170. package/src/modules/design_system/i18n/es.json +46 -0
  171. package/src/modules/design_system/i18n/pl.json +46 -0
  172. package/src/modules/design_system/index.ts +7 -0
  173. package/src/modules/design_system/setup.ts +12 -0
  174. package/src/modules/inbox_ops/i18n/de.json +3 -0
  175. package/src/modules/inbox_ops/i18n/en.json +3 -0
  176. package/src/modules/inbox_ops/i18n/es.json +3 -0
  177. package/src/modules/inbox_ops/i18n/pl.json +3 -0
  178. package/src/modules/inbox_ops/search.ts +20 -4
  179. package/src/modules/integrations/api/[id]/credentials/route.ts +11 -5
  180. package/src/modules/integrations/api/[id]/health/route.ts +6 -3
  181. package/src/modules/integrations/api/[id]/route.ts +6 -3
  182. package/src/modules/integrations/api/[id]/state/route.ts +6 -3
  183. package/src/modules/integrations/api/[id]/version/route.ts +6 -3
  184. package/src/modules/integrations/api/logs/route.ts +6 -3
  185. package/src/modules/integrations/api/route.ts +6 -3
  186. package/src/modules/integrations/api/umes-read.ts +2 -2
  187. package/src/modules/integrations/lib/organization-scope.ts +5 -25
  188. package/src/modules/messages/i18n/de.json +2 -0
  189. package/src/modules/messages/i18n/en.json +2 -0
  190. package/src/modules/messages/i18n/es.json +2 -0
  191. package/src/modules/messages/i18n/pl.json +2 -0
  192. package/src/modules/messages/search.ts +11 -5
  193. package/src/modules/query_index/data/entities.ts +7 -0
  194. package/src/modules/query_index/lib/engine.ts +40 -63
  195. package/src/modules/query_index/migrations/.snapshot-open-mercato.json +12 -0
  196. package/src/modules/query_index/migrations/Migration20260731105052_query_index.ts +35 -0
@@ -0,0 +1,46 @@
1
+ {
2
+ "design_system.entries.button.description": "Disparador de acción principal con toda la escala de variantes y tamaños del DS.",
3
+ "design_system.entries.buttonGroup.description": "Grupo unido de botones de acción relacionados que comparten un borde.",
4
+ "design_system.entries.fancyButton.description": "Botón con degradado, de estilo promocional, para acciones destacadas.",
5
+ "design_system.entries.iconButton.description": "Botón cuadrado solo con icono; siempre requiere un aria-label.",
6
+ "design_system.entries.linkButton.description": "Enlace de texto con estilo de control del DS.",
7
+ "design_system.entries.socialButton.description": "Botón de autenticación con colores de marca para inicio de sesión social.",
8
+ "design_system.families.banners": "Avisos y llamadas",
9
+ "design_system.families.buttons": "Botones",
10
+ "design_system.families.charts": "Gráficos",
11
+ "design_system.families.dates": "Fechas y hora",
12
+ "design_system.families.detail": "Secciones de detalle",
13
+ "design_system.families.display": "Visualización de datos",
14
+ "design_system.families.feedback": "Retroalimentación",
15
+ "design_system.families.filters": "Filtros",
16
+ "design_system.families.foundations": "Fundamentos",
17
+ "design_system.families.icons": "Iconos",
18
+ "design_system.families.inputs": "Campos de formulario",
19
+ "design_system.families.messages": "Mensajes",
20
+ "design_system.families.navigation": "Navegación",
21
+ "design_system.families.notifications": "Notificaciones",
22
+ "design_system.families.overlays": "Superposiciones",
23
+ "design_system.families.scaffolding": "Estructura de página",
24
+ "design_system.families.schedule": "Agenda",
25
+ "design_system.gallery.copied": "Fragmento copiado al portapapeles",
26
+ "design_system.gallery.copy": "Copiar código",
27
+ "design_system.gallery.copyFailed": "No se pudo copiar el fragmento",
28
+ "design_system.gallery.familiesGroup": "Familias",
29
+ "design_system.gallery.familyContents": "Componentes de esta familia",
30
+ "design_system.gallery.iconCopied": "Copiado: {snippet}",
31
+ "design_system.gallery.iconCopyJsx": "Copiar JSX (lucide-react)",
32
+ "design_system.gallery.iconCopyMeta": "Copiar nombre para page.meta icon",
33
+ "design_system.gallery.iconCountAll": "{total} iconos",
34
+ "design_system.gallery.iconCountFiltered": "{visible} de {total} iconos",
35
+ "design_system.gallery.iconSearchPlaceholder": "Filtrar iconos…",
36
+ "design_system.gallery.loadFailed": "No se pudo cargar esta familia",
37
+ "design_system.gallery.noResults": "Ningún componente coincide con la búsqueda",
38
+ "design_system.gallery.openInFigma": "Abrir en Figma",
39
+ "design_system.gallery.retry": "Reintentar",
40
+ "design_system.gallery.searchPlaceholder": "Buscar componentes…",
41
+ "design_system.gallery.usageDo": "Haz",
42
+ "design_system.gallery.usageDont": "Evita",
43
+ "design_system.gallery.viewDocs": "Ver documentación",
44
+ "design_system.nav.group": "Desarrollador",
45
+ "design_system.nav.title": "Sistema de diseño"
46
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "design_system.entries.button.description": "Podstawowy przycisk akcji z pełną skalą wariantów i rozmiarów DS.",
3
+ "design_system.entries.buttonGroup.description": "Połączona grupa powiązanych przycisków akcji ze wspólnym obramowaniem.",
4
+ "design_system.entries.fancyButton.description": "Gradientowy przycisk o marketingowym charakterze dla wyróżnionych akcji.",
5
+ "design_system.entries.iconButton.description": "Kwadratowy przycisk z samą ikoną; zawsze wymaga aria-label.",
6
+ "design_system.entries.linkButton.description": "Tekstowy odnośnik w stylu kontrolki DS.",
7
+ "design_system.entries.socialButton.description": "Przycisk logowania w kolorach marki dla logowania społecznościowego.",
8
+ "design_system.families.banners": "Banery i wskazówki",
9
+ "design_system.families.buttons": "Przyciski",
10
+ "design_system.families.charts": "Wykresy",
11
+ "design_system.families.dates": "Daty i czas",
12
+ "design_system.families.detail": "Sekcje szczegółów",
13
+ "design_system.families.display": "Prezentacja danych",
14
+ "design_system.families.feedback": "Informacje zwrotne",
15
+ "design_system.families.filters": "Filtry",
16
+ "design_system.families.foundations": "Fundamenty",
17
+ "design_system.families.icons": "Ikony",
18
+ "design_system.families.inputs": "Pola formularzy",
19
+ "design_system.families.messages": "Wiadomości",
20
+ "design_system.families.navigation": "Nawigacja",
21
+ "design_system.families.notifications": "Powiadomienia",
22
+ "design_system.families.overlays": "Nakładki",
23
+ "design_system.families.scaffolding": "Szkielet strony",
24
+ "design_system.families.schedule": "Harmonogram",
25
+ "design_system.gallery.copied": "Fragment skopiowany do schowka",
26
+ "design_system.gallery.copy": "Kopiuj kod",
27
+ "design_system.gallery.copyFailed": "Nie udało się skopiować fragmentu",
28
+ "design_system.gallery.familiesGroup": "Rodziny",
29
+ "design_system.gallery.familyContents": "Komponenty w tej rodzinie",
30
+ "design_system.gallery.iconCopied": "Skopiowano: {snippet}",
31
+ "design_system.gallery.iconCopyJsx": "Kopiuj JSX (lucide-react)",
32
+ "design_system.gallery.iconCopyMeta": "Kopiuj nazwę do page.meta icon",
33
+ "design_system.gallery.iconCountAll": "Ikony: {total}",
34
+ "design_system.gallery.iconCountFiltered": "{visible} z {total} ikon",
35
+ "design_system.gallery.iconSearchPlaceholder": "Filtruj ikony…",
36
+ "design_system.gallery.loadFailed": "Nie udało się załadować tej rodziny",
37
+ "design_system.gallery.noResults": "Żaden komponent nie pasuje do wyszukiwania",
38
+ "design_system.gallery.openInFigma": "Otwórz w Figmie",
39
+ "design_system.gallery.retry": "Spróbuj ponownie",
40
+ "design_system.gallery.searchPlaceholder": "Szukaj komponentów…",
41
+ "design_system.gallery.usageDo": "Rób",
42
+ "design_system.gallery.usageDont": "Unikaj",
43
+ "design_system.gallery.viewDocs": "Zobacz dokumentację",
44
+ "design_system.nav.group": "Deweloper",
45
+ "design_system.nav.title": "Design system"
46
+ }
@@ -0,0 +1,7 @@
1
+ import type { ModuleInfo } from '@open-mercato/shared/modules/registry'
2
+
3
+ export const metadata: ModuleInfo = {
4
+ name: 'design_system',
5
+ title: 'Design system gallery',
6
+ description: 'Live, in-app component gallery for the Open Mercato design system.',
7
+ }
@@ -0,0 +1,12 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ export const setup: ModuleSetupConfig = {
4
+ defaultRoleFeatures: {
5
+ // View-only module: the gallery reads no tenant data, so the grant is safe
6
+ // to hand out broadly. Superadmin is covered by wildcard grants.
7
+ admin: ['design_system.view'],
8
+ employee: ['design_system.view'],
9
+ },
10
+ }
11
+
12
+ export default setup
@@ -162,6 +162,9 @@
162
162
  "inbox_ops.reply.send": "Antwort senden",
163
163
  "inbox_ops.reply.sending": "Wird gesendet...",
164
164
  "inbox_ops.reply.sent_success": "Antwort erfolgreich gesendet",
165
+ "inbox_ops.search.fallback.title": "Posteingang-Vorschlag",
166
+ "inbox_ops.search.subtitle.template": "Konfidenz: {{confidence}} · Status: {{status}}",
167
+ "inbox_ops.search.subtitle.templateWithCategory": "Konfidenz: {{confidence}} · Status: {{status}} · Kategorie: {{category}}",
165
168
  "inbox_ops.sender_unknown": "Unbekannt",
166
169
  "inbox_ops.settings.active": "Aktiv",
167
170
  "inbox_ops.settings.copied": "Kopiert",
@@ -162,6 +162,9 @@
162
162
  "inbox_ops.reply.send": "Send Reply",
163
163
  "inbox_ops.reply.sending": "Sending...",
164
164
  "inbox_ops.reply.sent_success": "Reply sent successfully",
165
+ "inbox_ops.search.fallback.title": "Inbox Proposal",
166
+ "inbox_ops.search.subtitle.template": "Confidence: {{confidence}} · Status: {{status}}",
167
+ "inbox_ops.search.subtitle.templateWithCategory": "Confidence: {{confidence}} · Status: {{status}} · Category: {{category}}",
165
168
  "inbox_ops.sender_unknown": "Unknown",
166
169
  "inbox_ops.settings.active": "Active",
167
170
  "inbox_ops.settings.copied": "Copied",
@@ -162,6 +162,9 @@
162
162
  "inbox_ops.reply.send": "Enviar respuesta",
163
163
  "inbox_ops.reply.sending": "Enviando...",
164
164
  "inbox_ops.reply.sent_success": "Respuesta enviada correctamente",
165
+ "inbox_ops.search.fallback.title": "Propuesta de bandeja",
166
+ "inbox_ops.search.subtitle.template": "Confianza: {{confidence}} · Estado: {{status}}",
167
+ "inbox_ops.search.subtitle.templateWithCategory": "Confianza: {{confidence}} · Estado: {{status}} · Categoría: {{category}}",
165
168
  "inbox_ops.sender_unknown": "Desconocido",
166
169
  "inbox_ops.settings.active": "Activo",
167
170
  "inbox_ops.settings.copied": "Copiado",
@@ -162,6 +162,9 @@
162
162
  "inbox_ops.reply.send": "Wy\u015blij odpowied\u017a",
163
163
  "inbox_ops.reply.sending": "Wysy\u0142anie...",
164
164
  "inbox_ops.reply.sent_success": "Odpowied\u017a wys\u0142ana pomy\u015blnie",
165
+ "inbox_ops.search.fallback.title": "Propozycja skrzynki",
166
+ "inbox_ops.search.subtitle.template": "Pewność: {{confidence}} · Status: {{status}}",
167
+ "inbox_ops.search.subtitle.templateWithCategory": "Pewność: {{confidence}} · Status: {{status}} · Kategoria: {{category}}",
165
168
  "inbox_ops.sender_unknown": "Nieznany",
166
169
  "inbox_ops.settings.active": "Aktywny",
167
170
  "inbox_ops.settings.copied": "Skopiowano",
@@ -4,6 +4,7 @@ import type {
4
4
  SearchResultPresenter,
5
5
  SearchIndexSource,
6
6
  } from '@open-mercato/shared/modules/search'
7
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
8
 
8
9
  type SearchContext = SearchBuildContext & {
9
10
  tenantId: string
@@ -30,6 +31,14 @@ export const searchConfig: SearchModuleConfig = {
30
31
  const record = ctx.record
31
32
  if (!record.summary) return null
32
33
 
34
+ const { t } = await resolveTranslations()
35
+ const confidence = String(record.confidence ?? '')
36
+ const status = String(record.status ?? '')
37
+ const category = record.category ? String(record.category) : ''
38
+ const subtitle = category
39
+ ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} · Status: {{status}} · Category: {{category}}', { confidence, status, category })
40
+ : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} · Status: {{status}}', { confidence, status })
41
+
33
42
  return {
34
43
  text: String(record.summary || ''),
35
44
  fields: {
@@ -39,8 +48,8 @@ export const searchConfig: SearchModuleConfig = {
39
48
  detected_language: record.detected_language,
40
49
  },
41
50
  presenter: {
42
- title: String(record.summary || 'Inbox Proposal').slice(0, 80),
43
- subtitle: `Confidence: ${record.confidence} - Status: ${record.status}${record.category ? ` - Category: ${record.category}` : ''}`,
51
+ title: String(record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),
52
+ subtitle,
44
53
  icon: 'inbox',
45
54
  },
46
55
  checksumSource: {
@@ -53,9 +62,16 @@ export const searchConfig: SearchModuleConfig = {
53
62
  }
54
63
  },
55
64
  formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {
65
+ const { t } = await resolveTranslations()
66
+ const confidence = String(ctx.record.confidence ?? '')
67
+ const status = String(ctx.record.status ?? '')
68
+ const category = ctx.record.category ? String(ctx.record.category) : ''
69
+ const subtitle = category
70
+ ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} · Status: {{status}} · Category: {{category}}', { confidence, status, category })
71
+ : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} · Status: {{status}}', { confidence, status })
56
72
  return {
57
- title: String(ctx.record.summary || 'Inbox Proposal').slice(0, 80),
58
- subtitle: `Confidence: ${ctx.record.confidence} - Status: ${ctx.record.status}${ctx.record.category ? ` - Category: ${ctx.record.category}` : ''}`,
73
+ title: String(ctx.record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),
74
+ subtitle,
59
75
  icon: 'inbox',
60
76
  }
61
77
  },
@@ -21,7 +21,7 @@ import {
21
21
  runIntegrationMutationGuardAfterSuccess,
22
22
  runIntegrationMutationGuards,
23
23
  } from '../../guards'
24
- import { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'
24
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
25
25
 
26
26
  const idParamsSchema = z.object({ id: z.string().min(1) })
27
27
 
@@ -45,10 +45,13 @@ function resolveParams(ctx: { params?: Promise<{ id?: string }> | { id?: string
45
45
 
46
46
  export async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
47
47
  const auth = await getAuthFromRequest(req)
48
- const organizationId = resolveIntegrationsOrganizationId(auth)
49
- if (!auth?.tenantId || !organizationId) {
48
+ if (!auth?.tenantId) {
50
49
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
51
50
  }
51
+ const organizationId = resolveActiveOrganizationId(auth)
52
+ if (!organizationId) {
53
+ return organizationScopeRequiredResponse()
54
+ }
52
55
 
53
56
  const rawParams = await resolveParams(ctx)
54
57
  const parsedParams = idParamsSchema.safeParse(rawParams)
@@ -91,10 +94,13 @@ export async function GET(req: Request, ctx: { params?: Promise<{ id?: string }>
91
94
 
92
95
  export async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
93
96
  const auth = await getAuthFromRequest(req)
94
- const organizationId = resolveIntegrationsOrganizationId(auth)
95
- if (!auth?.tenantId || !organizationId) {
97
+ if (!auth?.tenantId) {
96
98
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
97
99
  }
100
+ const organizationId = resolveActiveOrganizationId(auth)
101
+ if (!organizationId) {
102
+ return organizationScopeRequiredResponse()
103
+ }
98
104
 
99
105
  const rawParams = await resolveParams(ctx)
100
106
  const parsedParams = idParamsSchema.safeParse(rawParams)
@@ -9,7 +9,7 @@ import {
9
9
  runIntegrationMutationGuardAfterSuccess,
10
10
  runIntegrationMutationGuards,
11
11
  } from '../../guards'
12
- import { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'
12
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
13
13
 
14
14
  const idParamsSchema = z.object({ id: z.string().min(1) })
15
15
 
@@ -24,10 +24,13 @@ export const openApi = {
24
24
 
25
25
  export async function POST(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
26
26
  const auth = await getAuthFromRequest(req)
27
- const organizationId = resolveIntegrationsOrganizationId(auth)
28
- if (!auth?.tenantId || !organizationId) {
27
+ if (!auth?.tenantId) {
29
28
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
30
29
  }
30
+ const organizationId = resolveActiveOrganizationId(auth)
31
+ if (!organizationId) {
32
+ return organizationScopeRequiredResponse()
33
+ }
31
34
 
32
35
  const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')
33
36
  ? await (ctx.params as Promise<{ id?: string }>)
@@ -12,7 +12,7 @@ import {
12
12
  integrationApiRoutePaths,
13
13
  runIntegrationsReadBeforeInterceptors,
14
14
  } from '../umes-read'
15
- import { resolveIntegrationsOrganizationId } from '../../lib/organization-scope'
15
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
16
16
 
17
17
  const idParamsSchema = z.object({ id: z.string().min(1) })
18
18
 
@@ -27,10 +27,13 @@ export const openApi = {
27
27
 
28
28
  export async function GET(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
29
29
  const auth = await getAuthFromRequest(req)
30
- const organizationId = resolveIntegrationsOrganizationId(auth)
31
- if (!auth?.tenantId || !organizationId) {
30
+ if (!auth?.tenantId) {
32
31
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
33
32
  }
33
+ const organizationId = resolveActiveOrganizationId(auth)
34
+ if (!organizationId) {
35
+ return organizationScopeRequiredResponse()
36
+ }
34
37
 
35
38
  const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')
36
39
  ? await (ctx.params as Promise<{ id?: string }>)
@@ -13,7 +13,7 @@ import {
13
13
  runIntegrationMutationGuardAfterSuccess,
14
14
  runIntegrationMutationGuards,
15
15
  } from '../../guards'
16
- import { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'
16
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
17
17
 
18
18
  const idParamsSchema = z.object({ id: z.string().min(1) })
19
19
 
@@ -28,10 +28,13 @@ export const openApi = {
28
28
 
29
29
  export async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
30
30
  const auth = await getAuthFromRequest(req)
31
- const organizationId = resolveIntegrationsOrganizationId(auth)
32
- if (!auth?.tenantId || !organizationId) {
31
+ if (!auth?.tenantId) {
33
32
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
34
33
  }
34
+ const organizationId = resolveActiveOrganizationId(auth)
35
+ if (!organizationId) {
36
+ return organizationScopeRequiredResponse()
37
+ }
35
38
 
36
39
  const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')
37
40
  ? await (ctx.params as Promise<{ id?: string }>)
@@ -14,7 +14,7 @@ import {
14
14
  runIntegrationMutationGuardAfterSuccess,
15
15
  runIntegrationMutationGuards,
16
16
  } from '../../guards'
17
- import { resolveIntegrationsOrganizationId } from '../../../lib/organization-scope'
17
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
18
18
 
19
19
  const idParamsSchema = z.object({ id: z.string().min(1) })
20
20
 
@@ -29,10 +29,13 @@ export const openApi = {
29
29
 
30
30
  export async function PUT(req: Request, ctx: { params?: Promise<{ id?: string }> | { id?: string } }) {
31
31
  const auth = await getAuthFromRequest(req)
32
- const organizationId = resolveIntegrationsOrganizationId(auth)
33
- if (!auth?.tenantId || !organizationId) {
32
+ if (!auth?.tenantId) {
34
33
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
35
34
  }
35
+ const organizationId = resolveActiveOrganizationId(auth)
36
+ if (!organizationId) {
37
+ return organizationScopeRequiredResponse()
38
+ }
36
39
 
37
40
  const rawParams = (ctx.params && typeof (ctx.params as Promise<unknown>).then === 'function')
38
41
  ? await (ctx.params as Promise<{ id?: string }>)
@@ -8,7 +8,7 @@ import {
8
8
  integrationApiRoutePaths,
9
9
  runIntegrationsReadBeforeInterceptors,
10
10
  } from '../umes-read'
11
- import { resolveIntegrationsOrganizationId } from '../../lib/organization-scope'
11
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
12
12
 
13
13
  export const metadata = {
14
14
  GET: { requireAuth: true, requireFeatures: ['integrations.manage'] },
@@ -21,10 +21,13 @@ export const openApi = {
21
21
 
22
22
  export async function GET(req: Request) {
23
23
  const auth = await getAuthFromRequest(req)
24
- const organizationId = resolveIntegrationsOrganizationId(auth)
25
- if (!auth?.tenantId || !organizationId) {
24
+ if (!auth?.tenantId) {
26
25
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
27
26
  }
27
+ const organizationId = resolveActiveOrganizationId(auth)
28
+ if (!organizationId) {
29
+ return organizationScopeRequiredResponse()
30
+ }
28
31
 
29
32
  const container = await createRequestContainer()
30
33
  const beforeInterceptors = await runIntegrationsReadBeforeInterceptors({
@@ -14,7 +14,7 @@ import {
14
14
  integrationApiRoutePaths,
15
15
  runIntegrationsReadBeforeInterceptors,
16
16
  } from './umes-read'
17
- import { resolveIntegrationsOrganizationId } from '../lib/organization-scope'
17
+ import { organizationScopeRequiredResponse, resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
18
18
 
19
19
  export const metadata = {
20
20
  GET: { requireAuth: true, requireFeatures: ['integrations.view'] },
@@ -47,10 +47,13 @@ function matchesSearchQuery(
47
47
 
48
48
  export async function GET(req: Request) {
49
49
  const auth = await getAuthFromRequest(req)
50
- const organizationId = resolveIntegrationsOrganizationId(auth)
51
- if (!auth?.tenantId || !organizationId) {
50
+ if (!auth?.tenantId) {
52
51
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
53
52
  }
53
+ const organizationId = resolveActiveOrganizationId(auth)
54
+ if (!organizationId) {
55
+ return organizationScopeRequiredResponse()
56
+ }
54
57
 
55
58
  const url = new URL(req.url)
56
59
  const parsedQuery = listIntegrationsQuerySchema.safeParse(Object.fromEntries(url.searchParams.entries()))
@@ -4,7 +4,7 @@ import type { AwilixContainer } from 'awilix'
4
4
  import { runApiInterceptorsAfter, runApiInterceptorsBefore, type RunInterceptorsBeforeResult } from '@open-mercato/shared/lib/crud/interceptor-runner'
5
5
  import { applyResponseEnrichers, applyResponseEnricherToRecord } from '@open-mercato/shared/lib/crud/enricher-runner'
6
6
  import type { ApiInterceptorMethod, InterceptorRequest } from '@open-mercato/shared/lib/crud/api-interceptor'
7
- import { resolveIntegrationsOrganizationId } from '../lib/organization-scope'
7
+ import { resolveActiveOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
8
8
 
9
9
  export const integrationApiRoutePaths = {
10
10
  list: 'integrations',
@@ -67,7 +67,7 @@ function mergeAdditiveBody(
67
67
 
68
68
  function getEnricherContext(input: ReadRouteContext) {
69
69
  return {
70
- organizationId: resolveIntegrationsOrganizationId(input.auth) as string,
70
+ organizationId: resolveActiveOrganizationId(input.auth) as string,
71
71
  tenantId: input.auth.tenantId as string,
72
72
  userId: input.auth.sub ?? '',
73
73
  em: input.container.resolve('em') as EntityManager,
@@ -1,27 +1,7 @@
1
- type OrganizationScopedAuth = {
2
- orgId?: string | null
3
- actorOrgId?: unknown
4
- } | null | undefined
5
-
6
1
  /**
7
- * Resolves the organization an integrations request is scoped to.
8
- *
9
- * Integrations are configured per organization — `integration_credentials` and
10
- * `integration_states` both require a non-null `organization_id` — so there is no
11
- * meaningful "all organizations" view of this module. When an operator selects that
12
- * option the super-admin cookie override clears `auth.orgId` and preserves the actor's
13
- * own organization in `actorOrgId`; fall back to it so the module keeps showing the
14
- * operator's own configuration instead of failing.
15
- *
16
- * Answering 401 for that case is not merely wrong but self-perpetuating: `apiFetch`
17
- * reads 401 as an expired session and redirects through `/api/auth/session/refresh`,
18
- * which succeeds and returns to the same page, reloading forever.
2
+ * @deprecated Moved to `@open-mercato/shared/lib/auth/organizationScope` as
3
+ * `resolveActiveOrganizationId`, because `data_sync` needs the same resolution and
4
+ * `integrations` is not the right owner for it. This alias stays for third-party
5
+ * modules that already import from here.
19
6
  */
20
- export function resolveIntegrationsOrganizationId(auth: OrganizationScopedAuth): string | null {
21
- if (!auth) return null
22
- const selected = auth.orgId
23
- if (typeof selected === 'string' && selected.trim().length > 0) return selected
24
- const actorOrgId = auth.actorOrgId
25
- if (typeof actorOrgId === 'string' && actorOrgId.trim().length > 0) return actorOrgId
26
- return null
27
- }
7
+ export { resolveActiveOrganizationId as resolveIntegrationsOrganizationId } from '@open-mercato/shared/lib/auth/organizationScope'
@@ -213,6 +213,8 @@
213
213
  "messages.replyBody": "Antwort",
214
214
  "messages.saveDraft": "Entwurf speichern",
215
215
  "messages.savingDraft": "Entwurf wird gespeichert...",
216
+ "messages.search.badge.message": "Nachricht",
217
+ "messages.search.fallback.title": "Nachricht",
216
218
  "messages.searchPlaceholder": "Nachrichten suchen",
217
219
  "messages.send": "Senden",
218
220
  "messages.sendViaEmail": "Auch per E-Mail senden",
@@ -213,6 +213,8 @@
213
213
  "messages.replyBody": "Reply",
214
214
  "messages.saveDraft": "Save draft",
215
215
  "messages.savingDraft": "Saving draft...",
216
+ "messages.search.badge.message": "Message",
217
+ "messages.search.fallback.title": "Message",
216
218
  "messages.searchPlaceholder": "Search messages",
217
219
  "messages.send": "Send",
218
220
  "messages.sendViaEmail": "Also send via email",
@@ -213,6 +213,8 @@
213
213
  "messages.replyBody": "Respuesta",
214
214
  "messages.saveDraft": "Guardar borrador",
215
215
  "messages.savingDraft": "Guardando borrador...",
216
+ "messages.search.badge.message": "Mensaje",
217
+ "messages.search.fallback.title": "Mensaje",
216
218
  "messages.searchPlaceholder": "Buscar mensajes",
217
219
  "messages.send": "Enviar",
218
220
  "messages.sendViaEmail": "Enviar también por correo",
@@ -213,6 +213,8 @@
213
213
  "messages.replyBody": "Odpowiedź",
214
214
  "messages.saveDraft": "Zapisz szkic",
215
215
  "messages.savingDraft": "Zapisywanie szkicu...",
216
+ "messages.search.badge.message": "Wiadomość",
217
+ "messages.search.fallback.title": "Wiadomość",
216
218
  "messages.searchPlaceholder": "Szukaj wiadomości",
217
219
  "messages.send": "Wyślij",
218
220
  "messages.sendViaEmail": "Wyślij także e-mailem",
@@ -4,6 +4,8 @@ import type {
4
4
  SearchIndexSource,
5
5
  SearchResultPresenter,
6
6
  } from '@open-mercato/shared/modules/search'
7
+ import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
8
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
7
9
 
8
10
  function appendLine(lines: string[], label: string, value: unknown) {
9
11
  if (value === null || value === undefined) return
@@ -31,8 +33,8 @@ function snippet(value: unknown, max = 140): string | undefined {
31
33
  return `${trimmed.slice(0, max - 3)}...`
32
34
  }
33
35
 
34
- function buildMessagePresenter(record: Record<string, unknown>): SearchResultPresenter {
35
- const title = pickString(record.subject) ?? 'Message'
36
+ function buildMessagePresenter(translate: TranslateFn, record: Record<string, unknown>): SearchResultPresenter {
37
+ const title = pickString(record.subject) ?? translate('messages.search.fallback.title', 'Message')
36
38
  const body = snippet(record.body)
37
39
  const externalName = pickString(record.external_name, record.externalName)
38
40
  const subtitle = [externalName, body].filter(Boolean).join(' · ') || undefined
@@ -40,7 +42,7 @@ function buildMessagePresenter(record: Record<string, unknown>): SearchResultPre
40
42
  title: String(title),
41
43
  subtitle,
42
44
  icon: 'mail',
43
- badge: 'Message',
45
+ badge: translate('messages.search.badge.message', 'Message'),
44
46
  }
45
47
  }
46
48
 
@@ -51,6 +53,7 @@ export const searchConfig: SearchModuleConfig = {
51
53
  enabled: true,
52
54
  priority: 5,
53
55
  buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {
56
+ const { t } = await resolveTranslations()
54
57
  const record = ctx.record
55
58
  const lines: string[] = []
56
59
  appendLine(lines, 'Subject', record.subject)
@@ -59,7 +62,7 @@ export const searchConfig: SearchModuleConfig = {
59
62
  if (!lines.length) return null
60
63
  return {
61
64
  text: lines,
62
- presenter: buildMessagePresenter(record),
65
+ presenter: buildMessagePresenter(t, record),
63
66
  checksumSource: {
64
67
  record: {
65
68
  subject: record.subject,
@@ -70,7 +73,10 @@ export const searchConfig: SearchModuleConfig = {
70
73
  },
71
74
  }
72
75
  },
73
- formatResult: async (ctx) => buildMessagePresenter(ctx.record),
76
+ formatResult: async (ctx) => {
77
+ const { t } = await resolveTranslations()
78
+ return buildMessagePresenter(t, ctx.record)
79
+ },
74
80
  resolveUrl: async (ctx) => {
75
81
  const id = pickString(ctx.record.id)
76
82
  return id ? `/backend/messages/${encodeURIComponent(id)}` : null
@@ -255,6 +255,13 @@ export class IndexerStatusLog {
255
255
  @Index({ name: 'search_tokens_lookup_idx', properties: ['entityType', 'field', 'tokenHash', 'tenantId', 'organizationId'] })
256
256
  @Index({ name: 'search_tokens_entity_idx', properties: ['entityType', 'entityId'] })
257
257
  @Index({ name: 'search_tokens_tenant_token_hash_idx', properties: ['tenantId', 'tokenHash'] })
258
+ // Serves the availability probe ("does this scope have any tokens?") as a pure
259
+ // B-tree prefix seek, making the MISS as cheap as the hit — neither existing
260
+ // index can (lookup_idx buries tenant_id behind field/token_hash), which is how
261
+ // the probe degraded to a seq scan on large tables (#4723). Requires the
262
+ // index-usable `= / IS NULL` predicates the availability resolver emits; see
263
+ // .ai/specs/2026-07-31-search-token-probe-index.md.
264
+ @Index({ name: 'search_tokens_presence_idx', properties: ['entityType', 'tenantId', 'organizationId'] })
258
265
  export class SearchToken {
259
266
  @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
260
267
  id!: string