@open-mercato/core 0.6.8-develop.6918.1.7b3f32b0c8 → 0.6.8-develop.6925.1.cefa200fa4

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 (95) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/bootstrap.js +2 -1
  3. package/dist/bootstrap.js.map +2 -2
  4. package/dist/generated/entities/role/index.js +2 -0
  5. package/dist/generated/entities/role/index.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +1 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/helpers/integration/api.js +4 -0
  9. package/dist/helpers/integration/api.js.map +2 -2
  10. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  11. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  12. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +5 -0
  13. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
  14. package/dist/modules/audit_logs/backend/audit-logs/page.js +4 -4
  15. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  16. package/dist/modules/audit_logs/components/AuditLogsActions.js +9 -2
  17. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  18. package/dist/modules/auth/api/login.js +5 -2
  19. package/dist/modules/auth/api/login.js.map +2 -2
  20. package/dist/modules/auth/api/users/route.js +8 -5
  21. package/dist/modules/auth/api/users/route.js.map +2 -2
  22. package/dist/modules/auth/backend/users/[id]/edit/page.js +15 -1
  23. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  24. package/dist/modules/auth/backend/users/page.js +7 -1
  25. package/dist/modules/auth/backend/users/page.js.map +2 -2
  26. package/dist/modules/auth/commands/users.js +175 -76
  27. package/dist/modules/auth/commands/users.js.map +2 -2
  28. package/dist/modules/auth/data/entities.js +4 -0
  29. package/dist/modules/auth/data/entities.js.map +2 -2
  30. package/dist/modules/auth/lib/sessionIntegrity.js +1 -1
  31. package/dist/modules/auth/lib/sessionIntegrity.js.map +2 -2
  32. package/dist/modules/auth/lib/setup-app.js +1 -1
  33. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  34. package/dist/modules/auth/migrations/Migration20260728134212_auth.js +14 -0
  35. package/dist/modules/auth/migrations/Migration20260728134212_auth.js.map +7 -0
  36. package/dist/modules/catalog/search.js +8 -0
  37. package/dist/modules/catalog/search.js.map +2 -2
  38. package/dist/modules/customer_accounts/search.js +2 -0
  39. package/dist/modules/customer_accounts/search.js.map +2 -2
  40. package/dist/modules/customers/commands/deals.js +55 -8
  41. package/dist/modules/customers/commands/deals.js.map +2 -2
  42. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js +1 -1
  43. package/dist/modules/customers/components/detail/create/dealCustomFieldControl.js.map +2 -2
  44. package/dist/modules/customers/components/formConfig.js +2 -0
  45. package/dist/modules/customers/components/formConfig.js.map +2 -2
  46. package/dist/modules/inbox_ops/search.js +1 -0
  47. package/dist/modules/inbox_ops/search.js.map +2 -2
  48. package/dist/modules/messages/search.js +2 -1
  49. package/dist/modules/messages/search.js.map +2 -2
  50. package/dist/modules/planner/search.js +1 -0
  51. package/dist/modules/planner/search.js.map +2 -2
  52. package/dist/modules/resources/search.js +2 -0
  53. package/dist/modules/resources/search.js.map +2 -2
  54. package/dist/modules/sales/search.js +24 -2
  55. package/dist/modules/sales/search.js.map +2 -2
  56. package/dist/modules/staff/search.js +4 -0
  57. package/dist/modules/staff/search.js.map +2 -2
  58. package/dist/modules/wms/search.js +4 -0
  59. package/dist/modules/wms/search.js.map +2 -2
  60. package/generated/entities/role/index.ts +1 -0
  61. package/generated/entity-fields-registry.ts +1 -0
  62. package/package.json +7 -7
  63. package/src/bootstrap.ts +9 -2
  64. package/src/helpers/integration/api.ts +13 -0
  65. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +7 -0
  66. package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +9 -0
  67. package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -4
  68. package/src/modules/audit_logs/components/AuditLogsActions.tsx +20 -4
  69. package/src/modules/auth/api/login.ts +9 -2
  70. package/src/modules/auth/api/users/route.ts +8 -4
  71. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -1
  72. package/src/modules/auth/backend/users/page.tsx +11 -0
  73. package/src/modules/auth/commands/users.ts +251 -85
  74. package/src/modules/auth/data/entities.ts +3 -0
  75. package/src/modules/auth/i18n/de.json +6 -0
  76. package/src/modules/auth/i18n/en.json +6 -0
  77. package/src/modules/auth/i18n/es.json +6 -0
  78. package/src/modules/auth/i18n/ko.json +6 -0
  79. package/src/modules/auth/i18n/pl.json +6 -0
  80. package/src/modules/auth/lib/sessionIntegrity.ts +1 -1
  81. package/src/modules/auth/lib/setup-app.ts +1 -1
  82. package/src/modules/auth/migrations/.snapshot-open-mercato.json +16 -0
  83. package/src/modules/auth/migrations/Migration20260728134212_auth.ts +14 -0
  84. package/src/modules/catalog/search.ts +8 -0
  85. package/src/modules/customer_accounts/search.ts +2 -0
  86. package/src/modules/customers/commands/deals.ts +86 -14
  87. package/src/modules/customers/components/detail/create/dealCustomFieldControl.tsx +1 -1
  88. package/src/modules/customers/components/formConfig.tsx +2 -0
  89. package/src/modules/inbox_ops/search.ts +1 -0
  90. package/src/modules/messages/search.ts +2 -1
  91. package/src/modules/planner/search.ts +1 -0
  92. package/src/modules/resources/search.ts +2 -0
  93. package/src/modules/sales/search.ts +24 -2
  94. package/src/modules/staff/search.ts +4 -0
  95. package/src/modules/wms/search.ts +4 -0
@@ -8,6 +8,7 @@ const searchConfig = {
8
8
  entities: [
9
9
  {
10
10
  entityId: "inbox_ops:inbox_proposal",
11
+ aclFeatures: ["inbox_ops.proposals.view"],
11
12
  enabled: true,
12
13
  priority: 6,
13
14
  fieldPolicy: {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/inbox_ops/search.ts"],
4
- "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[search.inbox_ops] Missing tenantId in search build context')\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'inbox_ops:inbox_proposal',\n enabled: true,\n priority: 6,\n fieldPolicy: {\n searchable: ['summary', 'category'],\n excluded: ['metadata', 'participants'],\n },\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n assertTenantContext(ctx)\n const record = ctx.record\n if (!record.summary) return null\n\n const { t } = await resolveTranslations()\n const confidence = String(record.confidence ?? '')\n const status = String(record.status ?? '')\n const category = record.category ? String(record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n\n return {\n text: String(record.summary || ''),\n fields: {\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detected_language: record.detected_language,\n },\n presenter: {\n title: String(record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n },\n checksumSource: {\n summary: record.summary,\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detectedLanguage: record.detected_language,\n },\n }\n },\n formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {\n const { t } = await resolveTranslations()\n const confidence = String(ctx.record.confidence ?? '')\n const status = String(ctx.record.status ?? '')\n const category = ctx.record.category ? String(ctx.record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n return {\n title: String(ctx.record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n }\n },\n resolveUrl: async (ctx: SearchBuildContext): Promise<string | null> => {\n const id = ctx.record.id\n if (!id) return null\n return `/backend/inbox-ops/proposals/${encodeURIComponent(String(id))}`\n },\n },\n ],\n}\n\nexport const config = searchConfig\nexport default searchConfig\n"],
5
- "mappings": "AAMA,SAAS,2BAA2B;AAMpC,SAAS,oBAAoB,KAAuD;AAClF,MAAI,OAAO,IAAI,aAAa,YAAY,IAAI,SAAS,WAAW,GAAG;AACjE,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,UAAU;AAAA,QAClC,UAAU,CAAC,YAAY,cAAc;AAAA,MACvC;AAAA,MACA,aAAa,OAAO,QAA+D;AACjF,4BAAoB,GAAG;AACvB,cAAM,SAAS,IAAI;AACnB,YAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,OAAO,cAAc,EAAE;AACjD,cAAM,SAAS,OAAO,OAAO,UAAU,EAAE;AACzC,cAAM,WAAW,OAAO,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC7D,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AAErH,eAAO;AAAA,UACL,MAAM,OAAO,OAAO,WAAW,EAAE;AAAA,UACjC,QAAQ;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,mBAAmB,OAAO;AAAA,UAC5B;AAAA,UACA,WAAW;AAAA,YACT,OAAO,OAAO,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,YACnG;AAAA,YACA,MAAM;AAAA,UACR;AAAA,UACA,gBAAgB;AAAA,YACd,SAAS,OAAO;AAAA,YAChB,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,kBAAkB,OAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAmE;AACtF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,IAAI,OAAO,cAAc,EAAE;AACrD,cAAM,SAAS,OAAO,IAAI,OAAO,UAAU,EAAE;AAC7C,cAAM,WAAW,IAAI,OAAO,WAAW,OAAO,IAAI,OAAO,QAAQ,IAAI;AACrE,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AACrH,eAAO;AAAA,UACL,OAAO,OAAO,IAAI,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,UACvG;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,YAAY,OAAO,QAAoD;AACrE,cAAM,KAAK,IAAI,OAAO;AACtB,YAAI,CAAC,GAAI,QAAO;AAChB,eAAO,gCAAgC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,SAAS;AACtB,IAAO,iBAAQ;",
4
+ "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\ntype SearchContext = SearchBuildContext & {\n tenantId: string\n}\n\nfunction assertTenantContext(ctx: SearchBuildContext): asserts ctx is SearchContext {\n if (typeof ctx.tenantId !== 'string' || ctx.tenantId.length === 0) {\n throw new Error('[search.inbox_ops] Missing tenantId in search build context')\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'inbox_ops:inbox_proposal',\n aclFeatures: ['inbox_ops.proposals.view'],\n enabled: true,\n priority: 6,\n fieldPolicy: {\n searchable: ['summary', 'category'],\n excluded: ['metadata', 'participants'],\n },\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n assertTenantContext(ctx)\n const record = ctx.record\n if (!record.summary) return null\n\n const { t } = await resolveTranslations()\n const confidence = String(record.confidence ?? '')\n const status = String(record.status ?? '')\n const category = record.category ? String(record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n\n return {\n text: String(record.summary || ''),\n fields: {\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detected_language: record.detected_language,\n },\n presenter: {\n title: String(record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n },\n checksumSource: {\n summary: record.summary,\n status: record.status,\n confidence: record.confidence,\n category: record.category,\n detectedLanguage: record.detected_language,\n },\n }\n },\n formatResult: async (ctx: SearchBuildContext): Promise<SearchResultPresenter | null> => {\n const { t } = await resolveTranslations()\n const confidence = String(ctx.record.confidence ?? '')\n const status = String(ctx.record.status ?? '')\n const category = ctx.record.category ? String(ctx.record.category) : ''\n const subtitle = category\n ? t('inbox_ops.search.subtitle.templateWithCategory', 'Confidence: {{confidence}} \u00B7 Status: {{status}} \u00B7 Category: {{category}}', { confidence, status, category })\n : t('inbox_ops.search.subtitle.template', 'Confidence: {{confidence}} \u00B7 Status: {{status}}', { confidence, status })\n return {\n title: String(ctx.record.summary || t('inbox_ops.search.fallback.title', 'Inbox Proposal')).slice(0, 80),\n subtitle,\n icon: 'inbox',\n }\n },\n resolveUrl: async (ctx: SearchBuildContext): Promise<string | null> => {\n const id = ctx.record.id\n if (!id) return null\n return `/backend/inbox-ops/proposals/${encodeURIComponent(String(id))}`\n },\n },\n ],\n}\n\nexport const config = searchConfig\nexport default searchConfig\n"],
5
+ "mappings": "AAMA,SAAS,2BAA2B;AAMpC,SAAS,oBAAoB,KAAuD;AAClF,MAAI,OAAO,IAAI,aAAa,YAAY,IAAI,SAAS,WAAW,GAAG;AACjE,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,aAAa,CAAC,0BAA0B;AAAA,MACxC,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,UAAU;AAAA,QAClC,UAAU,CAAC,YAAY,cAAc;AAAA,MACvC;AAAA,MACA,aAAa,OAAO,QAA+D;AACjF,4BAAoB,GAAG;AACvB,cAAM,SAAS,IAAI;AACnB,YAAI,CAAC,OAAO,QAAS,QAAO;AAE5B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,OAAO,cAAc,EAAE;AACjD,cAAM,SAAS,OAAO,OAAO,UAAU,EAAE;AACzC,cAAM,WAAW,OAAO,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC7D,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AAErH,eAAO;AAAA,UACL,MAAM,OAAO,OAAO,WAAW,EAAE;AAAA,UACjC,QAAQ;AAAA,YACN,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,mBAAmB,OAAO;AAAA,UAC5B;AAAA,UACA,WAAW;AAAA,YACT,OAAO,OAAO,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,YACnG;AAAA,YACA,MAAM;AAAA,UACR;AAAA,UACA,gBAAgB;AAAA,YACd,SAAS,OAAO;AAAA,YAChB,QAAQ,OAAO;AAAA,YACf,YAAY,OAAO;AAAA,YACnB,UAAU,OAAO;AAAA,YACjB,kBAAkB,OAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAmE;AACtF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,aAAa,OAAO,IAAI,OAAO,cAAc,EAAE;AACrD,cAAM,SAAS,OAAO,IAAI,OAAO,UAAU,EAAE;AAC7C,cAAM,WAAW,IAAI,OAAO,WAAW,OAAO,IAAI,OAAO,QAAQ,IAAI;AACrE,cAAM,WAAW,WACb,EAAE,kDAAkD,kFAA4E,EAAE,YAAY,QAAQ,SAAS,CAAC,IAChK,EAAE,sCAAsC,sDAAmD,EAAE,YAAY,OAAO,CAAC;AACrH,eAAO;AAAA,UACL,OAAO,OAAO,IAAI,OAAO,WAAW,EAAE,mCAAmC,gBAAgB,CAAC,EAAE,MAAM,GAAG,EAAE;AAAA,UACvG;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,YAAY,OAAO,QAAoD;AACrE,cAAM,KAAK,IAAI,OAAO;AACtB,YAAI,CAAC,GAAI,QAAO;AAChB,eAAO,gCAAgC,mBAAmB,OAAO,EAAE,CAAC,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,SAAS;AACtB,IAAO,iBAAQ;",
6
6
  "names": []
7
7
  }
@@ -36,7 +36,8 @@ const searchConfig = {
36
36
  entities: [
37
37
  {
38
38
  entityId: "messages:message",
39
- enabled: true,
39
+ aclFeatures: ["messages.view"],
40
+ enabled: false,
40
41
  priority: 5,
41
42
  buildSource: async (ctx) => {
42
43
  const { t } = await resolveTranslations();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/messages/search.ts"],
4
- "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchIndexSource,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction buildMessagePresenter(translate: TranslateFn, record: Record<string, unknown>): SearchResultPresenter {\n const title = pickString(record.subject) ?? translate('messages.search.fallback.title', 'Message')\n const body = snippet(record.body)\n const externalName = pickString(record.external_name, record.externalName)\n const subtitle = [externalName, body].filter(Boolean).join(' \u00B7 ') || undefined\n return {\n title: String(title),\n subtitle,\n icon: 'mail',\n badge: translate('messages.search.badge.message', 'Message'),\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'messages:message',\n enabled: true,\n priority: 5,\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Subject', record.subject)\n appendLine(lines, 'Body', record.body)\n appendLine(lines, 'From name', record.external_name ?? record.externalName)\n if (!lines.length) return null\n return {\n text: lines,\n presenter: buildMessagePresenter(t, record),\n checksumSource: {\n record: {\n subject: record.subject,\n body: record.body,\n external_name: record.external_name ?? record.externalName,\n external_email_hash: record.external_email_hash ?? record.externalEmailHash,\n },\n },\n }\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildMessagePresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const id = pickString(ctx.record.id)\n return id ? `/backend/messages/${encodeURIComponent(id)}` : null\n },\n fieldPolicy: {\n searchable: ['subject', 'body', 'external_name'],\n hashOnly: ['external_email'],\n excluded: ['action_data', 'action_result'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "AAOA,SAAS,2BAA2B;AAEpC,SAAS,WAAW,OAAiB,OAAe,OAAgB;AAClE,MAAI,UAAU,QAAQ,UAAU,OAAW;AAC3C,QAAM,OAAO,MAAM,QAAQ,KAAK,IAC5B,MAAM,IAAI,CAAC,SAAU,SAAS,QAAQ,SAAS,SAAY,KAAK,OAAO,IAAI,CAAE,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI,IACvG,OAAO,UAAU,WAAW,KAAK,UAAU,KAAK,IAAI,OAAO,KAAK;AACrE,MAAI,CAAC,KAAK,KAAK,EAAG;AAClB,QAAM,KAAK,GAAG,KAAK,KAAK,IAAI,EAAE;AAChC;AAEA,SAAS,cAAc,YAA2C;AAChE,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,SAAU;AACnC,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,QAAQ,SAAS,EAAG,QAAO;AAAA,EACjC;AACA,SAAO;AACT;AAEA,SAAS,QAAQ,OAAgB,MAAM,KAAyB;AAC9D,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,MAAI,QAAQ,UAAU,IAAK,QAAO;AAClC,SAAO,GAAG,QAAQ,MAAM,GAAG,MAAM,CAAC,CAAC;AACrC;AAEA,SAAS,sBAAsB,WAAwB,QAAwD;AAC7G,QAAM,QAAQ,WAAW,OAAO,OAAO,KAAK,UAAU,kCAAkC,SAAS;AACjG,QAAM,OAAO,QAAQ,OAAO,IAAI;AAChC,QAAM,eAAe,WAAW,OAAO,eAAe,OAAO,YAAY;AACzE,QAAM,WAAW,CAAC,cAAc,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK,KAAK;AACrE,SAAO;AAAA,IACL,OAAO,OAAO,KAAK;AAAA,IACnB;AAAA,IACA,MAAM;AAAA,IACN,OAAO,UAAU,iCAAiC,SAAS;AAAA,EAC7D;AACF;AAEO,MAAM,eAAmC;AAAA,EAC9C,UAAU;AAAA,IACR;AAAA,MACE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,UAAU;AAAA,MACV,aAAa,OAAO,QAA+D;AACjF,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,cAAM,SAAS,IAAI;AACnB,cAAM,QAAkB,CAAC;AACzB,mBAAW,OAAO,WAAW,OAAO,OAAO;AAC3C,mBAAW,OAAO,QAAQ,OAAO,IAAI;AACrC,mBAAW,OAAO,aAAa,OAAO,iBAAiB,OAAO,YAAY;AAC1E,YAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,eAAO;AAAA,UACL,MAAM;AAAA,UACN,WAAW,sBAAsB,GAAG,MAAM;AAAA,UAC1C,gBAAgB;AAAA,YACd,QAAQ;AAAA,cACN,SAAS,OAAO;AAAA,cAChB,MAAM,OAAO;AAAA,cACb,eAAe,OAAO,iBAAiB,OAAO;AAAA,cAC9C,qBAAqB,OAAO,uBAAuB,OAAO;AAAA,YAC5D;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,cAAc,OAAO,QAAQ;AAC3B,cAAM,EAAE,EAAE,IAAI,MAAM,oBAAoB;AACxC,eAAO,sBAAsB,GAAG,IAAI,MAAM;AAAA,MAC5C;AAAA,MACA,YAAY,OAAO,QAAQ;AACzB,cAAM,KAAK,WAAW,IAAI,OAAO,EAAE;AACnC,eAAO,KAAK,qBAAqB,mBAAmB,EAAE,CAAC,KAAK;AAAA,MAC9D;AAAA,MACA,aAAa;AAAA,QACX,YAAY,CAAC,WAAW,QAAQ,eAAe;AAAA,QAC/C,UAAU,CAAC,gBAAgB;AAAA,QAC3B,UAAU,CAAC,eAAe,eAAe;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,iBAAQ;AACR,MAAM,SAAS;",
4
+ "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchIndexSource,\n SearchResultPresenter,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction buildMessagePresenter(translate: TranslateFn, record: Record<string, unknown>): SearchResultPresenter {\n const title = pickString(record.subject) ?? translate('messages.search.fallback.title', 'Message')\n const body = snippet(record.body)\n const externalName = pickString(record.external_name, record.externalName)\n const subtitle = [externalName, body].filter(Boolean).join(' \u00B7 ') || undefined\n return {\n title: String(title),\n subtitle,\n icon: 'mail',\n badge: translate('messages.search.badge.message', 'Message'),\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'messages:message',\n aclFeatures: ['messages.view'],\n enabled: false,\n priority: 5,\n buildSource: async (ctx: SearchBuildContext): Promise<SearchIndexSource | null> => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Subject', record.subject)\n appendLine(lines, 'Body', record.body)\n appendLine(lines, 'From name', record.external_name ?? record.externalName)\n if (!lines.length) return null\n return {\n text: lines,\n presenter: buildMessagePresenter(t, record),\n checksumSource: {\n record: {\n subject: record.subject,\n body: record.body,\n external_name: record.external_name ?? record.externalName,\n external_email_hash: record.external_email_hash ?? record.externalEmailHash,\n },\n },\n }\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildMessagePresenter(t, ctx.record)\n },\n resolveUrl: async (ctx) => {\n const id = pickString(ctx.record.id)\n return id ? `/backend/messages/${encodeURIComponent(id)}` : null\n },\n fieldPolicy: {\n searchable: ['subject', 'body', 'external_name'],\n hashOnly: ['external_email'],\n excluded: ['action_data', 'action_result'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -55,6 +55,7 @@ const searchConfig = {
55
55
  entities: [
56
56
  {
57
57
  entityId: "planner:planner_availability_rule_set",
58
+ aclFeatures: ["planner.view"],
58
59
  enabled: true,
59
60
  priority: 6,
60
61
  buildSource: async (ctx) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/planner/search.ts"],
4
- "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildRuleSetPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('planner.search.badge.availabilityRuleSet', 'Availability rule set')\n const description = snippet(record.description ?? customFields.description)\n const timezone = pickString(record.timezone, customFields.timezone)\n return {\n title: String(title),\n subtitle: formatSubtitle(description, timezone),\n icon: 'calendar-check',\n badge: t('planner.search.badge.availabilityRuleSet', 'Availability rule set'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'planner:planner_availability_rule_set',\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Timezone', record.timezone ?? ctx.customFields.timezone)\n return buildIndexSource(ctx, buildRuleSetPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildRuleSetPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/planner/availability-rulesets/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'timezone'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildRuleSetPresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('planner.search.badge.availabilityRuleSet', 'Availability rule set')\n const description = snippet(record.description ?? customFields.description)\n const timezone = pickString(record.timezone, customFields.timezone)\n return {\n title: String(title),\n subtitle: formatSubtitle(description, timezone),\n icon: 'calendar-check',\n badge: t('planner.search.badge.availabilityRuleSet', 'Availability rule set'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'planner:planner_availability_rule_set',\n aclFeatures: ['planner.view'],\n enabled: true,\n priority: 6,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Timezone', record.timezone ?? ctx.customFields.timezone)\n return buildIndexSource(ctx, buildRuleSetPresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildRuleSetPresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/planner/availability-rulesets/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'timezone'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -67,6 +67,7 @@ const searchConfig = {
67
67
  entities: [
68
68
  {
69
69
  entityId: "resources:resources_resource",
70
+ aclFeatures: ["resources.view"],
70
71
  enabled: true,
71
72
  priority: 8,
72
73
  buildSource: async (ctx) => {
@@ -92,6 +93,7 @@ const searchConfig = {
92
93
  },
93
94
  {
94
95
  entityId: "resources:resources_resource_type",
96
+ aclFeatures: ["resources.view"],
95
97
  enabled: true,
96
98
  priority: 7,
97
99
  buildSource: async (ctx) => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/resources/search.ts"],
4
- "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildResourcePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resource', 'Resource')\n const description = snippet(record.description ?? customFields.description)\n const capacity = record.capacity ?? record.capacity_value ?? record.capacityValue\n const capacityUnit = pickString(record.capacity_unit_name, record.capacityUnitName, record.capacity_unit_value, record.capacityUnitValue)\n const capacityLabel = capacity != null ? `${capacity}${capacityUnit ? ` ${capacityUnit}` : ''}` : null\n return {\n title: String(title),\n subtitle: formatSubtitle(description, capacityLabel),\n icon: 'box',\n badge: t('resources.search.badge.resource', 'Resource'),\n }\n}\n\nfunction buildResourceTypePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resourceType', 'Resource type')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shapes',\n badge: t('resources.search.badge.resourceType', 'Resource type'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'resources:resources_resource',\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Capacity', record.capacity ?? record.capacity_value ?? record.capacityValue)\n appendLine(lines, 'Capacity unit', record.capacity_unit_name ?? record.capacityUnitName ?? record.capacity_unit_value)\n appendLine(lines, 'Resource type', record.resource_type_id ?? record.resourceTypeId)\n appendLine(lines, 'Tags', record.tags)\n return buildIndexSource(ctx, buildResourcePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourcePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resources/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'capacity', 'capacity_unit_name', 'capacity_unit_value', 'tags'],\n },\n },\n {\n entityId: 'resources:resources_resource_type',\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildResourceTypePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourceTypePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resource-types/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n SearchModuleConfig,\n SearchBuildContext,\n SearchResultPresenter,\n SearchIndexSource,\n} from '@open-mercato/shared/modules/search'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\n\nfunction pickString(...candidates: Array<unknown>): string | null {\n for (const candidate of candidates) {\n if (typeof candidate !== 'string') continue\n const trimmed = candidate.trim()\n if (trimmed.length > 0) return trimmed\n }\n return null\n}\n\nfunction snippet(value: unknown, max = 140): string | undefined {\n if (typeof value !== 'string') return undefined\n const trimmed = value.trim()\n if (!trimmed.length) return undefined\n if (trimmed.length <= max) return trimmed\n return `${trimmed.slice(0, max - 3)}...`\n}\n\nfunction appendLine(lines: string[], label: string, value: unknown) {\n if (value === null || value === undefined) return\n const text = Array.isArray(value)\n ? value.map((item) => (item === null || item === undefined ? '' : String(item))).filter(Boolean).join(', ')\n : (typeof value === 'object' ? JSON.stringify(value) : String(value))\n if (!text.trim()) return\n lines.push(`${label}: ${text}`)\n}\n\nfunction appendCustomFieldLines(lines: string[], customFields: Record<string, unknown>) {\n for (const [key, value] of Object.entries(customFields)) {\n if (value === null || value === undefined) continue\n appendLine(lines, key.replace(/^cf:/, ''), value)\n }\n}\n\nfunction formatSubtitle(...parts: Array<unknown>): string | undefined {\n const text = parts\n .map((part) => (part === null || part === undefined ? '' : String(part)))\n .map((part) => part.trim())\n .filter(Boolean)\n if (text.length === 0) return undefined\n return text.join(' \u00B7 ')\n}\n\nfunction buildResourcePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resource', 'Resource')\n const description = snippet(record.description ?? customFields.description)\n const capacity = record.capacity ?? record.capacity_value ?? record.capacityValue\n const capacityUnit = pickString(record.capacity_unit_name, record.capacityUnitName, record.capacity_unit_value, record.capacityUnitValue)\n const capacityLabel = capacity != null ? `${capacity}${capacityUnit ? ` ${capacityUnit}` : ''}` : null\n return {\n title: String(title),\n subtitle: formatSubtitle(description, capacityLabel),\n icon: 'box',\n badge: t('resources.search.badge.resource', 'Resource'),\n }\n}\n\nfunction buildResourceTypePresenter(\n t: TranslateFn,\n record: Record<string, unknown>,\n customFields: Record<string, unknown>,\n): SearchResultPresenter {\n const title =\n pickString(record.name, record.display_name, record.displayName, customFields.name, customFields.display_name) ??\n (record.id as string | undefined) ??\n t('resources.search.badge.resourceType', 'Resource type')\n const description = snippet(record.description ?? customFields.description)\n return {\n title: String(title),\n subtitle: formatSubtitle(description),\n icon: 'shapes',\n badge: t('resources.search.badge.resourceType', 'Resource type'),\n }\n}\n\nfunction buildIndexSource(\n ctx: SearchBuildContext,\n presenter: SearchResultPresenter,\n lines: string[],\n): SearchIndexSource | null {\n appendCustomFieldLines(lines, ctx.customFields)\n if (!lines.length) return null\n return {\n text: lines,\n presenter,\n checksumSource: { record: ctx.record, customFields: ctx.customFields },\n }\n}\n\nexport const searchConfig: SearchModuleConfig = {\n entities: [\n {\n entityId: 'resources:resources_resource',\n aclFeatures: ['resources.view'],\n enabled: true,\n priority: 8,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Capacity', record.capacity ?? record.capacity_value ?? record.capacityValue)\n appendLine(lines, 'Capacity unit', record.capacity_unit_name ?? record.capacityUnitName ?? record.capacity_unit_value)\n appendLine(lines, 'Resource type', record.resource_type_id ?? record.resourceTypeId)\n appendLine(lines, 'Tags', record.tags)\n return buildIndexSource(ctx, buildResourcePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourcePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resources/${encodeURIComponent(String(ctx.record.id))}`,\n fieldPolicy: {\n searchable: ['name', 'description', 'capacity', 'capacity_unit_name', 'capacity_unit_value', 'tags'],\n },\n },\n {\n entityId: 'resources:resources_resource_type',\n aclFeatures: ['resources.view'],\n enabled: true,\n priority: 7,\n buildSource: async (ctx) => {\n const { t } = await resolveTranslations()\n const record = ctx.record\n const lines: string[] = []\n appendLine(lines, 'Name', record.name ?? record.display_name ?? ctx.customFields.name)\n appendLine(lines, 'Description', record.description ?? ctx.customFields.description)\n appendLine(lines, 'Icon', record.appearance_icon ?? record.appearanceIcon)\n appendLine(lines, 'Color', record.appearance_color ?? record.appearanceColor)\n return buildIndexSource(ctx, buildResourceTypePresenter(t, record, ctx.customFields), lines)\n },\n formatResult: async (ctx) => {\n const { t } = await resolveTranslations()\n return buildResourceTypePresenter(t, ctx.record, ctx.customFields)\n },\n resolveUrl: async (ctx) => `/backend/resources/resource-types/${encodeURIComponent(String(ctx.record.id))}/edit`,\n fieldPolicy: {\n searchable: ['name', 'description', 'appearance_icon', 'appearance_color'],\n },\n },\n ],\n}\n\nexport default searchConfig\nexport const config = searchConfig\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -330,6 +330,7 @@ const searchConfig = {
330
330
  entities: [
331
331
  {
332
332
  entityId: "sales:sales_channel",
333
+ aclFeatures: ["sales.channels.manage"],
333
334
  enabled: true,
334
335
  priority: 7,
335
336
  buildSource: async (ctx) => {
@@ -356,6 +357,7 @@ const searchConfig = {
356
357
  },
357
358
  {
358
359
  entityId: "sales:sales_order",
360
+ aclFeatures: ["sales.orders.view"],
359
361
  enabled: true,
360
362
  priority: 10,
361
363
  buildSource: async (ctx) => {
@@ -379,6 +381,7 @@ const searchConfig = {
379
381
  },
380
382
  {
381
383
  entityId: "sales:sales_quote",
384
+ aclFeatures: ["sales.quotes.view"],
382
385
  enabled: true,
383
386
  priority: 10,
384
387
  buildSource: async (ctx) => {
@@ -401,6 +404,7 @@ const searchConfig = {
401
404
  },
402
405
  {
403
406
  entityId: "sales:sales_order_line",
407
+ aclFeatures: ["sales.orders.view"],
404
408
  enabled: true,
405
409
  priority: 7,
406
410
  fieldPolicy: {
@@ -429,6 +433,7 @@ const searchConfig = {
429
433
  },
430
434
  {
431
435
  entityId: "sales:sales_quote_line",
436
+ aclFeatures: ["sales.quotes.view"],
432
437
  enabled: true,
433
438
  priority: 7,
434
439
  fieldPolicy: {
@@ -457,6 +462,7 @@ const searchConfig = {
457
462
  },
458
463
  {
459
464
  entityId: "sales:sales_order_adjustment",
465
+ aclFeatures: ["sales.orders.view"],
460
466
  enabled: true,
461
467
  priority: 6,
462
468
  buildSource: async (ctx) => {
@@ -477,6 +483,7 @@ const searchConfig = {
477
483
  },
478
484
  {
479
485
  entityId: "sales:sales_quote_adjustment",
486
+ aclFeatures: ["sales.quotes.view"],
480
487
  enabled: true,
481
488
  priority: 6,
482
489
  buildSource: async (ctx) => {
@@ -497,6 +504,7 @@ const searchConfig = {
497
504
  },
498
505
  {
499
506
  entityId: "sales:sales_shipment",
507
+ aclFeatures: ["sales.orders.view"],
500
508
  enabled: true,
501
509
  priority: 6,
502
510
  buildSource: async (ctx) => {
@@ -517,6 +525,7 @@ const searchConfig = {
517
525
  },
518
526
  {
519
527
  entityId: "sales:sales_shipment_item",
528
+ aclFeatures: ["sales.orders.view"],
520
529
  enabled: true,
521
530
  priority: 5,
522
531
  buildSource: async (ctx) => {
@@ -535,6 +544,7 @@ const searchConfig = {
535
544
  },
536
545
  {
537
546
  entityId: "sales:sales_invoice",
547
+ aclFeatures: ["sales.invoices.manage"],
538
548
  enabled: true,
539
549
  priority: 6,
540
550
  buildSource: async (ctx) => {
@@ -555,6 +565,7 @@ const searchConfig = {
555
565
  },
556
566
  {
557
567
  entityId: "sales:sales_invoice_line",
568
+ aclFeatures: ["sales.invoices.manage"],
558
569
  enabled: true,
559
570
  priority: 5,
560
571
  fieldPolicy: {
@@ -581,6 +592,7 @@ const searchConfig = {
581
592
  },
582
593
  {
583
594
  entityId: "sales:sales_credit_memo",
595
+ aclFeatures: ["sales.credit_memos.manage"],
584
596
  enabled: true,
585
597
  priority: 6,
586
598
  buildSource: async (ctx) => {
@@ -601,6 +613,7 @@ const searchConfig = {
601
613
  },
602
614
  {
603
615
  entityId: "sales:sales_credit_memo_line",
616
+ aclFeatures: ["sales.credit_memos.manage"],
604
617
  enabled: true,
605
618
  priority: 5,
606
619
  fieldPolicy: {
@@ -627,6 +640,7 @@ const searchConfig = {
627
640
  },
628
641
  {
629
642
  entityId: "sales:sales_payment",
643
+ aclFeatures: ["sales.orders.view"],
630
644
  enabled: true,
631
645
  priority: 8,
632
646
  buildSource: async (ctx) => {
@@ -647,6 +661,7 @@ const searchConfig = {
647
661
  },
648
662
  {
649
663
  entityId: "sales:sales_payment_allocation",
664
+ aclFeatures: ["sales.orders.view"],
650
665
  enabled: true,
651
666
  priority: 5,
652
667
  buildSource: async (ctx) => {
@@ -667,7 +682,8 @@ const searchConfig = {
667
682
  },
668
683
  {
669
684
  entityId: "sales:sales_note",
670
- enabled: true,
685
+ aclFeatures: ["sales.orders.view"],
686
+ enabled: false,
671
687
  priority: 7,
672
688
  buildSource: async (ctx) => {
673
689
  const { t: translate } = await resolveTranslations();
@@ -690,7 +706,8 @@ const searchConfig = {
690
706
  },
691
707
  {
692
708
  entityId: "sales:sales_document_address",
693
- enabled: true,
709
+ aclFeatures: ["sales.orders.view"],
710
+ enabled: false,
694
711
  priority: 7,
695
712
  buildSource: async (ctx) => {
696
713
  const { t: translate } = await resolveTranslations();
@@ -716,6 +733,7 @@ const searchConfig = {
716
733
  },
717
734
  {
718
735
  entityId: "sales:sales_shipping_method",
736
+ aclFeatures: ["sales.settings.manage"],
719
737
  enabled: true,
720
738
  priority: 4,
721
739
  buildSource: async (ctx) => {
@@ -736,6 +754,7 @@ const searchConfig = {
736
754
  },
737
755
  {
738
756
  entityId: "sales:sales_delivery_window",
757
+ aclFeatures: ["sales.settings.manage"],
739
758
  enabled: true,
740
759
  priority: 4,
741
760
  buildSource: async (ctx) => {
@@ -756,6 +775,7 @@ const searchConfig = {
756
775
  },
757
776
  {
758
777
  entityId: "sales:sales_payment_method",
778
+ aclFeatures: ["sales.settings.manage"],
759
779
  enabled: true,
760
780
  priority: 4,
761
781
  buildSource: async (ctx) => {
@@ -776,6 +796,7 @@ const searchConfig = {
776
796
  },
777
797
  {
778
798
  entityId: "sales:sales_tax_rate",
799
+ aclFeatures: ["sales.settings.manage"],
779
800
  enabled: true,
780
801
  priority: 4,
781
802
  buildSource: async (ctx) => {
@@ -796,6 +817,7 @@ const searchConfig = {
796
817
  },
797
818
  {
798
819
  entityId: "sales:sales_document_tag",
820
+ aclFeatures: ["sales.orders.view"],
799
821
  enabled: true,
800
822
  priority: 3,
801
823
  buildSource: async (ctx) => {