@open-mercato/core 0.10.1-develop.7954.1.48da4a7d13 → 0.10.1-develop.7972.1.03f813eaaf

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 (88) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/auth/api/logout.js +3 -3
  3. package/dist/modules/auth/api/logout.js.map +2 -2
  4. package/dist/modules/auth/commands/roles.js +42 -31
  5. package/dist/modules/auth/commands/roles.js.map +2 -2
  6. package/dist/modules/communication_channels/setup.js +49 -45
  7. package/dist/modules/communication_channels/setup.js.map +2 -2
  8. package/dist/modules/customer_accounts/services/domainMappingService.js +55 -29
  9. package/dist/modules/customer_accounts/services/domainMappingService.js.map +2 -2
  10. package/dist/modules/customers/components/detail/ActivitiesSection.js +8 -3
  11. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
  12. package/dist/modules/customers/components/detail/ActivityCard.js +3 -3
  13. package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
  14. package/dist/modules/customers/components/detail/ActivityHistorySection.js +19 -7
  15. package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +2 -2
  16. package/dist/modules/customers/components/detail/ActivityTimeline.js +5 -5
  17. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  18. package/dist/modules/directory/subscribers/seedOrganizationDefaults.js +67 -0
  19. package/dist/modules/directory/subscribers/seedOrganizationDefaults.js.map +7 -0
  20. package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js +1 -1
  21. package/dist/modules/ecommerce/api/storefront/categories/[slug]/route.js.map +2 -2
  22. package/dist/modules/ecommerce/api/storefront/categories/route.js +1 -1
  23. package/dist/modules/ecommerce/api/storefront/categories/route.js.map +2 -2
  24. package/dist/modules/ecommerce/api/storefront/context/route.js +1 -1
  25. package/dist/modules/ecommerce/api/storefront/context/route.js.map +2 -2
  26. package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js +1 -1
  27. package/dist/modules/ecommerce/api/storefront/products/[idOrHandle]/route.js.map +2 -2
  28. package/dist/modules/ecommerce/api/storefront/products/route.js +1 -1
  29. package/dist/modules/ecommerce/api/storefront/products/route.js.map +2 -2
  30. package/dist/modules/ecommerce/api/storefront/search/suggest/route.js +1 -1
  31. package/dist/modules/ecommerce/api/storefront/search/suggest/route.js.map +2 -2
  32. package/dist/modules/ecommerce/lib/cacheInvalidation.js +3 -0
  33. package/dist/modules/ecommerce/lib/cacheInvalidation.js.map +2 -2
  34. package/dist/modules/ecommerce/lib/cacheKeys.js +4 -0
  35. package/dist/modules/ecommerce/lib/cacheKeys.js.map +2 -2
  36. package/dist/modules/ecommerce/lib/storeContext.js +36 -12
  37. package/dist/modules/ecommerce/lib/storeContext.js.map +2 -2
  38. package/dist/modules/ecommerce/subscribers/sales-channel-cache-invalidation.js +14 -0
  39. package/dist/modules/ecommerce/subscribers/sales-channel-cache-invalidation.js.map +7 -0
  40. package/dist/modules/integrations/setup.js +34 -24
  41. package/dist/modules/integrations/setup.js.map +2 -2
  42. package/dist/modules/messages/components/MessagesInboxPageClient.js +1 -1
  43. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  44. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +3 -3
  45. package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +2 -2
  46. package/dist/modules/messages/components/message-detail/panels/body-panel.js +2 -2
  47. package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +2 -2
  48. package/dist/modules/payment_gateways/setup.js +3 -0
  49. package/dist/modules/payment_gateways/setup.js.map +2 -2
  50. package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js +30 -11
  51. package/dist/modules/warranty_claims/backend/warranty_claims/[id]/page.js.map +3 -3
  52. package/dist/modules/warranty_claims/setup.js +34 -30
  53. package/dist/modules/warranty_claims/setup.js.map +2 -2
  54. package/dist/modules/workflows/setup.js +7 -0
  55. package/dist/modules/workflows/setup.js.map +2 -2
  56. package/package.json +7 -7
  57. package/src/modules/auth/api/logout.ts +3 -3
  58. package/src/modules/auth/commands/roles.ts +43 -32
  59. package/src/modules/communication_channels/setup.ts +59 -53
  60. package/src/modules/customer_accounts/services/domainMappingService.ts +57 -29
  61. package/src/modules/customers/components/detail/ActivitiesSection.tsx +8 -3
  62. package/src/modules/customers/components/detail/ActivityCard.tsx +3 -3
  63. package/src/modules/customers/components/detail/ActivityHistorySection.tsx +20 -8
  64. package/src/modules/customers/components/detail/ActivityTimeline.tsx +7 -7
  65. package/src/modules/customers/i18n/de.json +1 -0
  66. package/src/modules/customers/i18n/en.json +1 -0
  67. package/src/modules/customers/i18n/es.json +1 -0
  68. package/src/modules/customers/i18n/ko.json +1 -0
  69. package/src/modules/customers/i18n/pl.json +1 -0
  70. package/src/modules/directory/subscribers/seedOrganizationDefaults.ts +84 -0
  71. package/src/modules/ecommerce/api/storefront/categories/[slug]/route.ts +1 -1
  72. package/src/modules/ecommerce/api/storefront/categories/route.ts +1 -1
  73. package/src/modules/ecommerce/api/storefront/context/route.ts +1 -1
  74. package/src/modules/ecommerce/api/storefront/products/[idOrHandle]/route.ts +1 -1
  75. package/src/modules/ecommerce/api/storefront/products/route.ts +1 -1
  76. package/src/modules/ecommerce/api/storefront/search/suggest/route.ts +1 -1
  77. package/src/modules/ecommerce/lib/cacheInvalidation.ts +4 -0
  78. package/src/modules/ecommerce/lib/cacheKeys.ts +4 -0
  79. package/src/modules/ecommerce/lib/storeContext.ts +56 -10
  80. package/src/modules/ecommerce/subscribers/sales-channel-cache-invalidation.ts +12 -0
  81. package/src/modules/integrations/setup.ts +41 -24
  82. package/src/modules/messages/components/MessagesInboxPageClient.tsx +1 -1
  83. package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +3 -3
  84. package/src/modules/messages/components/message-detail/panels/body-panel.tsx +2 -2
  85. package/src/modules/payment_gateways/setup.ts +4 -0
  86. package/src/modules/warranty_claims/backend/warranty_claims/[id]/page.tsx +55 -28
  87. package/src/modules/warranty_claims/setup.ts +40 -30
  88. package/src/modules/workflows/setup.ts +8 -0
@@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation'
6
6
  import type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'
7
7
  import { Copy, Hash, Info, MessageSquare, Pencil, RefreshCw, Trash2, UserRound } from 'lucide-react'
8
8
  import { hasFeature } from '@open-mercato/shared/security/features'
9
+ import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
9
10
  import { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'
10
11
  import type { TranslateFn, TranslateParams } from '@open-mercato/shared/lib/i18n/context'
11
12
  import { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'
@@ -783,6 +784,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
783
784
  const [lineDialog, setLineDialog] = React.useState<{ mode: 'create' } | { mode: 'edit'; line: ClaimLine } | null>(null)
784
785
  const [defaultWarrantyMonths, setDefaultWarrantyMonths] = React.useState<number | null>(null)
785
786
  const [featureAccess, setFeatureAccess] = React.useState({
787
+ attachmentsView: false,
786
788
  claimManage: false,
787
789
  claimDelete: false,
788
790
  receivingManage: false,
@@ -814,6 +816,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
814
816
  headers: { 'content-type': 'application/json' },
815
817
  body: JSON.stringify({
816
818
  features: [
819
+ 'attachments.view',
817
820
  'warranty_claims.claim.manage',
818
821
  'warranty_claims.claim.delete',
819
822
  'warranty_claims.receiving.manage',
@@ -830,6 +833,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
830
833
  const granted = Array.isArray(call.result?.granted) ? call.result.granted : []
831
834
  const allGranted = call.result?.ok === true
832
835
  setFeatureAccess({
836
+ attachmentsView: allGranted || hasFeature(granted, 'attachments.view'),
833
837
  claimManage: allGranted || hasFeature(granted, 'warranty_claims.claim.manage'),
834
838
  claimDelete: allGranted || hasFeature(granted, 'warranty_claims.claim.delete'),
835
839
  receivingManage: allGranted || hasFeature(granted, 'warranty_claims.receiving.manage'),
@@ -841,6 +845,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
841
845
  .catch(() => {
842
846
  if (!cancelled) {
843
847
  setFeatureAccess({
848
+ attachmentsView: false,
844
849
  claimManage: false,
845
850
  claimDelete: false,
846
851
  receivingManage: false,
@@ -925,7 +930,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
925
930
  setError(null)
926
931
  setNotFound(false)
927
932
  try {
928
- const [claimPayload, linesPayload, eventsPayload, riskPayload, statsPayload, attachmentsPayload] = await Promise.all([
933
+ const [claimPayload, linesPayload, eventsPayload, riskPayload, statsPayload] = await Promise.all([
929
934
  readApiResultOrThrow<{ items?: unknown[] }>(
930
935
  `/api/warranty_claims?ids=${encodeURIComponent(id)}&page=1&pageSize=1`,
931
936
  undefined,
@@ -950,11 +955,6 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
950
955
  undefined,
951
956
  { fallback: { ok: true, result: {} } },
952
957
  ),
953
- readApiResultOrThrow<{ items?: unknown[] }>(
954
- `/api/attachments?entityId=${encodeURIComponent('warranty_claims:warranty_claim')}&recordId=${encodeURIComponent(id)}`,
955
- undefined,
956
- { fallback: { items: [] } },
957
- ),
958
958
  ])
959
959
  const nextClaim = (claimPayload.items ?? []).map(normalizeClaim).find((item): item is ClaimRecord => item !== null) ?? null
960
960
  if (!nextClaim) {
@@ -969,7 +969,6 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
969
969
  setClaim(nextClaim)
970
970
  setLines((linesPayload.items ?? []).map(normalizeLine).filter((item): item is ClaimLine => item !== null))
971
971
  setEvents((eventsPayload.items ?? []).map(normalizeEvent).filter((item): item is ClaimEvent => item !== null))
972
- setAttachmentCount(Array.isArray(attachmentsPayload.items) ? attachmentsPayload.items.length : 0)
973
972
  setRiskAssessment(normalizeRiskResponse(riskPayload))
974
973
  const nextThreshold = statsPayload?.result?.slaAtRiskThresholdPct
975
974
  setSlaAtRiskThresholdPct(typeof nextThreshold === 'number' ? nextThreshold : undefined)
@@ -984,6 +983,30 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
984
983
  void loadData()
985
984
  }, [loadData])
986
985
 
986
+ React.useEffect(() => {
987
+ let cancelled = false
988
+ setAttachmentCount(0)
989
+ if (!claim || claim.id !== id || !featureAccess.attachmentsView) return
990
+ void apiCall<{ items?: unknown[] }>(
991
+ `/api/attachments?entityId=${encodeURIComponent('warranty_claims:warranty_claim')}&recordId=${encodeURIComponent(claim.id)}`,
992
+ { headers: { 'x-om-forbidden-redirect': '0' } },
993
+ { fallback: { items: [] } },
994
+ )
995
+ .then((call) => {
996
+ if (cancelled || !call.ok) return
997
+ setAttachmentCount(Array.isArray(call.result?.items) ? call.result.items.length : 0)
998
+ })
999
+ .catch((error) => {
1000
+ getTelemetryRuntime()?.reportError(error, {
1001
+ module: 'warranty_claims',
1002
+ code: 'warranty_claims.attachment_count_failed',
1003
+ })
1004
+ })
1005
+ return () => {
1006
+ cancelled = true
1007
+ }
1008
+ }, [claim, featureAccess.attachmentsView, id, scopeVersion])
1009
+
987
1010
  useAppEvent('warranty_claims.claim.*', (event) => {
988
1011
  const eventClaimId = toStringOrNull(event.payload.claimId)
989
1012
  if (eventClaimId === id) void loadData()
@@ -1908,7 +1931,9 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
1908
1931
  const tabs: Array<{ id: TabId; label: string; count?: number }> = [
1909
1932
  { id: 'lines', label: t('warranty_claims.detail.tabs.lines'), count: lines.length },
1910
1933
  { id: 'timeline', label: t('warranty_claims.detail.tabs.timeline'), count: events.length },
1911
- { id: 'attachments', label: t('warranty_claims.detail.tabs.attachments'), count: attachmentCount },
1934
+ ...(featureAccess.attachmentsView
1935
+ ? [{ id: 'attachments' as const, label: t('warranty_claims.detail.tabs.attachments'), count: attachmentCount }]
1936
+ : []),
1912
1937
  { id: 'ai', label: t('warranty_claims.detail.tabs.ai') },
1913
1938
  ]
1914
1939
  const approvedLineCount = lines.filter((line) => line.lineStatus === 'approved').length
@@ -2046,7 +2071,7 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
2046
2071
  </div>
2047
2072
  <ClaimStageProgress status={claim.status} />
2048
2073
  <Tabs
2049
- value={activeTab}
2074
+ value={activeTab === 'attachments' && !featureAccess.attachmentsView ? 'lines' : activeTab}
2050
2075
  onValueChange={(value) => setActiveTab(value as TabId)}
2051
2076
  variant="underline"
2052
2077
  >
@@ -2249,25 +2274,27 @@ export default function WarrantyClaimDetailPage({ params }: { params?: { id?: st
2249
2274
  </div>
2250
2275
  </TabsContent>
2251
2276
 
2252
- <TabsContent value="attachments" className="mt-0">
2253
- <div className="px-8 pb-8 pt-6">
2254
- <AttachmentInput
2255
- entityId="warranty_claims:warranty_claim"
2256
- recordId={claim.id}
2257
- allowDelete={featureAccess.claimManage}
2258
- allowReplace={featureAccess.claimManage}
2259
- disabled={!featureAccess.claimManage}
2260
- onCountChange={setAttachmentCount}
2261
- renderItemMeta={(item) => (
2262
- isCustomerVisibleAttachment(item.tags) ? (
2263
- <StatusBadge variant="info">
2264
- {t('warranty_claims.detail.attachments.customerVisible', 'Visible to customer')}
2265
- </StatusBadge>
2266
- ) : null
2267
- )}
2268
- />
2269
- </div>
2270
- </TabsContent>
2277
+ {featureAccess.attachmentsView ? (
2278
+ <TabsContent value="attachments" className="mt-0">
2279
+ <div className="px-8 pb-8 pt-6">
2280
+ <AttachmentInput
2281
+ entityId="warranty_claims:warranty_claim"
2282
+ recordId={claim.id}
2283
+ allowDelete={featureAccess.claimManage}
2284
+ allowReplace={featureAccess.claimManage}
2285
+ disabled={!featureAccess.claimManage}
2286
+ onCountChange={setAttachmentCount}
2287
+ renderItemMeta={(item) => (
2288
+ isCustomerVisibleAttachment(item.tags) ? (
2289
+ <StatusBadge variant="info">
2290
+ {t('warranty_claims.detail.attachments.customerVisible', 'Visible to customer')}
2291
+ </StatusBadge>
2292
+ ) : null
2293
+ )}
2294
+ />
2295
+ </div>
2296
+ </TabsContent>
2297
+ ) : null}
2271
2298
 
2272
2299
  <TabsContent value="ai" className="mt-0">
2273
2300
  <div className="grid gap-4 px-8 pb-8 pt-6 xl:grid-cols-2">
@@ -76,6 +76,42 @@ function stableSlaSweepScheduleId(organizationId: string): string {
76
76
  return stableScheduleUuid(`warranty_claims:sla-sweep:${organizationId}`)
77
77
  }
78
78
 
79
+ async function ensureSlaSweepSchedule(ctx: {
80
+ container: import('awilix').AwilixContainer
81
+ tenantId: string
82
+ organizationId: string
83
+ }): Promise<void> {
84
+ const cradle = ctx.container as { hasRegistration?: (name: string) => boolean }
85
+ if (typeof cradle.hasRegistration !== 'function' || !cradle.hasRegistration('schedulerService')) return
86
+
87
+ const schedulerService = ctx.container.resolve('schedulerService') as SchedulerServiceLike
88
+ try {
89
+ await schedulerService.register({
90
+ id: stableSlaSweepScheduleId(ctx.organizationId),
91
+ name: 'Warranty claims SLA sweep',
92
+ description: 'Enqueues tenant-scoped warranty claim SLA escalation sweeps every 900 seconds.',
93
+ scopeType: 'organization',
94
+ organizationId: ctx.organizationId,
95
+ tenantId: ctx.tenantId,
96
+ scheduleType: 'interval',
97
+ scheduleValue: '900s',
98
+ timezone: 'UTC',
99
+ targetType: 'queue',
100
+ targetQueue: 'warranty_claims.sla_sweep',
101
+ targetPayload: {
102
+ scope: { tenantId: ctx.tenantId, organizationId: ctx.organizationId },
103
+ },
104
+ sourceType: 'module',
105
+ sourceModule: 'warranty_claims',
106
+ isEnabled: true,
107
+ })
108
+ } catch (error) {
109
+ logger.warn('[warranty_claims] Failed to register SLA sweep schedule', {
110
+ error: error instanceof Error ? error.message : error,
111
+ })
112
+ }
113
+ }
114
+
79
115
  export const setup: ModuleSetupConfig = {
80
116
  defaultRoleFeatures: {
81
117
  admin: adminFeatures,
@@ -117,37 +153,11 @@ export const setup: ModuleSetupConfig = {
117
153
 
118
154
  async seedDefaults({ em, tenantId, organizationId, container }) {
119
155
  await seedWarrantyClaimDictionaries(em, { tenantId, organizationId })
120
- const cradle = container as { hasRegistration?: (name: string) => boolean }
121
- if (typeof cradle.hasRegistration !== 'function' || !cradle.hasRegistration('schedulerService')) {
122
- return
123
- }
156
+ await ensureSlaSweepSchedule({ container, tenantId, organizationId })
157
+ },
124
158
 
125
- const schedulerService = container.resolve('schedulerService') as SchedulerServiceLike
126
- try {
127
- await schedulerService.register({
128
- id: stableSlaSweepScheduleId(organizationId),
129
- name: 'Warranty claims SLA sweep',
130
- description: 'Enqueues tenant-scoped warranty claim SLA escalation sweeps every 900 seconds.',
131
- scopeType: 'organization',
132
- organizationId,
133
- tenantId,
134
- scheduleType: 'interval',
135
- scheduleValue: '900s',
136
- timezone: 'UTC',
137
- targetType: 'queue',
138
- targetQueue: 'warranty_claims.sla_sweep',
139
- targetPayload: {
140
- scope: { tenantId, organizationId },
141
- },
142
- sourceType: 'module',
143
- sourceModule: 'warranty_claims',
144
- isEnabled: true,
145
- })
146
- } catch (error) {
147
- logger.warn('[warranty_claims] Failed to register SLA sweep schedule', {
148
- error: error instanceof Error ? error.message : error,
149
- })
150
- }
159
+ async onOrganizationCreated({ container, tenantId, organizationId }) {
160
+ await ensureSlaSweepSchedule({ container, tenantId, organizationId })
151
161
  },
152
162
  }
153
163
 
@@ -95,6 +95,14 @@ export const setup: ModuleSetupConfig = {
95
95
  })
96
96
  },
97
97
 
98
+ onOrganizationCreated: async (ctx) => {
99
+ await ensureMetricRollupSchedule({
100
+ container: ctx.container as never,
101
+ tenantId: ctx.tenantId,
102
+ organizationId: ctx.organizationId,
103
+ })
104
+ },
105
+
98
106
  /**
99
107
  * Portal grants for the §6.4 portal task surface.
100
108
  *