@open-mercato/core 0.7.1-develop.7131.1.20abf9e885 → 0.7.1-develop.7136.1.0f76137a1d

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 (73) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
  3. package/dist/modules/communication_channels/api/post/test-seed/route.js +40 -2
  4. package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
  5. package/dist/modules/communication_channels/lib/access-control.js +6 -1
  6. package/dist/modules/communication_channels/lib/access-control.js.map +2 -2
  7. package/dist/modules/communication_channels/lib/system-user.js +8 -3
  8. package/dist/modules/communication_channels/lib/system-user.js.map +2 -2
  9. package/dist/modules/warranty_claims/api/ai/assess/route.js +20 -18
  10. package/dist/modules/warranty_claims/api/ai/assess/route.js.map +2 -2
  11. package/dist/modules/warranty_claims/api/credit-memo/route.js +11 -12
  12. package/dist/modules/warranty_claims/api/credit-memo/route.js.map +2 -2
  13. package/dist/modules/warranty_claims/api/events/route.js +1 -1
  14. package/dist/modules/warranty_claims/api/events/route.js.map +2 -2
  15. package/dist/modules/warranty_claims/api/portal/attachments/route.js +24 -27
  16. package/dist/modules/warranty_claims/api/portal/attachments/route.js.map +2 -2
  17. package/dist/modules/warranty_claims/api/portal/claims/[id]/route.js +8 -10
  18. package/dist/modules/warranty_claims/api/portal/claims/[id]/route.js.map +2 -2
  19. package/dist/modules/warranty_claims/api/portal/claims/[id]/shared.js +4 -9
  20. package/dist/modules/warranty_claims/api/portal/claims/[id]/shared.js.map +2 -2
  21. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js +3 -3
  22. package/dist/modules/warranty_claims/api/portal/claims/[id]/submit/route.js.map +2 -2
  23. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js +3 -3
  24. package/dist/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.js.map +2 -2
  25. package/dist/modules/warranty_claims/api/portal/claims/route.js +4 -9
  26. package/dist/modules/warranty_claims/api/portal/claims/route.js.map +2 -2
  27. package/dist/modules/warranty_claims/api/portal/events/route.js +12 -13
  28. package/dist/modules/warranty_claims/api/portal/events/route.js.map +2 -2
  29. package/dist/modules/warranty_claims/api/receiving/route.js +14 -15
  30. package/dist/modules/warranty_claims/api/receiving/route.js.map +2 -2
  31. package/dist/modules/warranty_claims/api/registrations/route.js +9 -4
  32. package/dist/modules/warranty_claims/api/registrations/route.js.map +2 -2
  33. package/dist/modules/warranty_claims/api/replacement-order/route.js +11 -12
  34. package/dist/modules/warranty_claims/api/replacement-order/route.js.map +2 -2
  35. package/dist/modules/warranty_claims/api/return-label/route.js +20 -19
  36. package/dist/modules/warranty_claims/api/return-label/route.js.map +2 -2
  37. package/dist/modules/warranty_claims/api/risk/route.js +2 -1
  38. package/dist/modules/warranty_claims/api/risk/route.js.map +2 -2
  39. package/dist/modules/warranty_claims/api/sales-return/route.js +11 -12
  40. package/dist/modules/warranty_claims/api/sales-return/route.js.map +2 -2
  41. package/dist/modules/warranty_claims/api/troubleshooting-guides/route.js +22 -1
  42. package/dist/modules/warranty_claims/api/troubleshooting-guides/route.js.map +2 -2
  43. package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js +2 -1
  44. package/dist/modules/warranty_claims/api/vendor-recovery-suggestions/route.js.map +2 -2
  45. package/dist/modules/warranty_claims/commands/shared.js +2 -2
  46. package/dist/modules/warranty_claims/commands/shared.js.map +2 -2
  47. package/dist/modules/warranty_claims/lib/portalAuthGuard.js +31 -0
  48. package/dist/modules/warranty_claims/lib/portalAuthGuard.js.map +7 -0
  49. package/package.json +7 -7
  50. package/src/helpers/integration/communicationChannelsFixtures.ts +13 -0
  51. package/src/modules/communication_channels/api/post/test-seed/route.ts +47 -2
  52. package/src/modules/communication_channels/lib/access-control.ts +28 -0
  53. package/src/modules/communication_channels/lib/system-user.ts +40 -22
  54. package/src/modules/warranty_claims/api/ai/assess/route.ts +23 -17
  55. package/src/modules/warranty_claims/api/credit-memo/route.ts +14 -13
  56. package/src/modules/warranty_claims/api/events/route.ts +1 -1
  57. package/src/modules/warranty_claims/api/portal/attachments/route.ts +29 -27
  58. package/src/modules/warranty_claims/api/portal/claims/[id]/route.ts +9 -10
  59. package/src/modules/warranty_claims/api/portal/claims/[id]/shared.ts +5 -9
  60. package/src/modules/warranty_claims/api/portal/claims/[id]/submit/route.ts +3 -3
  61. package/src/modules/warranty_claims/api/portal/claims/[id]/withdraw/route.ts +3 -3
  62. package/src/modules/warranty_claims/api/portal/claims/route.ts +5 -9
  63. package/src/modules/warranty_claims/api/portal/events/route.ts +13 -13
  64. package/src/modules/warranty_claims/api/receiving/route.ts +17 -15
  65. package/src/modules/warranty_claims/api/registrations/route.ts +9 -3
  66. package/src/modules/warranty_claims/api/replacement-order/route.ts +14 -13
  67. package/src/modules/warranty_claims/api/return-label/route.ts +21 -17
  68. package/src/modules/warranty_claims/api/risk/route.ts +3 -1
  69. package/src/modules/warranty_claims/api/sales-return/route.ts +14 -13
  70. package/src/modules/warranty_claims/api/troubleshooting-guides/route.ts +23 -1
  71. package/src/modules/warranty_claims/api/vendor-recovery-suggestions/route.ts +3 -1
  72. package/src/modules/warranty_claims/commands/shared.ts +7 -1
  73. package/src/modules/warranty_claims/lib/portalAuthGuard.ts +30 -0
@@ -2,6 +2,7 @@ import { z } from 'zod'
2
2
  import type { CrudCtx } from '@open-mercato/shared/lib/crud/factory'
3
3
  import { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'
4
4
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
5
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
5
6
  import { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'
6
7
  import { buildIlikeTerm } from '@open-mercato/shared/lib/db/buildIlikeTerm'
7
8
  import { applyIdsFilter } from '../../lib/apiIdsFilter'
@@ -122,11 +123,24 @@ function toEntitySteps(value: unknown): Record<string, unknown> | null {
122
123
  if (value === undefined || value === null) return null
123
124
  const parsed = parseGuideSteps(value)
124
125
  if (!parsed) {
125
- throw new CrudHttpError(400, { error: 'warranty_claims.errors.invalidTroubleshootingSteps' })
126
+ throw new CrudHttpError(400, { error: '[internal] troubleshooting steps reached the entity mapper unvalidated' })
126
127
  }
127
128
  return { prompt: parsed.prompt, options: parsed.options }
128
129
  }
129
130
 
131
+ async function assertParsableGuideSteps(input: object): Promise<void> {
132
+ if (!hasOwn(input, 'steps')) return
133
+ const value = (input as { steps?: unknown }).steps
134
+ if (value === undefined || value === null || parseGuideSteps(value)) return
135
+ const { translate } = await resolveTranslations()
136
+ throw new CrudHttpError(400, {
137
+ error: translate(
138
+ 'warranty_claims.errors.invalidTroubleshootingSteps',
139
+ 'Troubleshooting steps must include a prompt and valid option branches.',
140
+ ),
141
+ })
142
+ }
143
+
130
144
  function toTroubleshootingGuideEntityData(input: TroubleshootingGuideCreateInput): Record<string, unknown> {
131
145
  return {
132
146
  claimType: input.claimType ?? null,
@@ -238,6 +252,14 @@ const crud = makeCrudRoute<RawTroubleshootingGuideInput, RawTroubleshootingGuide
238
252
  schema: rawBodySchema,
239
253
  mapToEntity: (input, ctx) => toTroubleshootingGuideEntityData(parseCreateInput(input, ctx)),
240
254
  },
255
+ hooks: {
256
+ beforeCreate: async (input) => {
257
+ await assertParsableGuideSteps(input)
258
+ },
259
+ beforeUpdate: async (input) => {
260
+ await assertParsableGuideSteps(input)
261
+ },
262
+ },
241
263
  update: {
242
264
  schema: rawBodySchema,
243
265
  getId: (input) => {
@@ -43,6 +43,7 @@ type SuggestionsRouteContext = {
43
43
  tenantId: string
44
44
  organizationId: string
45
45
  scope: WarrantyClaimScope
46
+ translate: (key: string, fallback?: string) => string
46
47
  em: EntityManager
47
48
  }
48
49
 
@@ -79,6 +80,7 @@ async function resolveSuggestionsContext(req: Request): Promise<SuggestionsRoute
79
80
  tenantId: auth.tenantId,
80
81
  organizationId,
81
82
  scope: { tenantId: auth.tenantId, organizationId },
83
+ translate,
82
84
  em,
83
85
  }
84
86
  }
@@ -88,7 +90,7 @@ export async function GET(req: Request) {
88
90
  const context = await resolveSuggestionsContext(req)
89
91
  const url = new URL(req.url)
90
92
  const query = querySchema.parse(Object.fromEntries(url.searchParams))
91
- const claim = await requireScopedClaim(context.em, query.claimId, context.scope)
93
+ const claim = await requireScopedClaim(context.em, query.claimId, context.scope, {}, context.translate('warranty_claims.errors.notFound', 'Claim not found.'))
92
94
  if (claim.claimType !== 'warranty' || (claim.status !== 'resolved' && claim.status !== 'closed')) {
93
95
  return NextResponse.json({ ok: true, result: { claimId: claim.id, suggestions: [] } })
94
96
  }
@@ -80,14 +80,20 @@ export async function loadScopedClaim(
80
80
  )
81
81
  }
82
82
 
83
+ /**
84
+ * `notFoundMessage` is passed to `assertFound` verbatim, so request-scoped callers
85
+ * must hand in an already-translated sentence; the key default only suits the
86
+ * command surface, which runs without a request locale.
87
+ */
83
88
  export async function requireScopedClaim(
84
89
  em: EntityManager,
85
90
  id: string,
86
91
  scope: WarrantyClaimScope,
87
92
  options: FindOneOptions<WarrantyClaim> = {},
93
+ notFoundMessage = 'warranty_claims.errors.notFound',
88
94
  ): Promise<WarrantyClaim> {
89
95
  const claim = await loadScopedClaim(em, id, scope, options)
90
- return assertFound(claim, 'warranty_claims.errors.notFound')
96
+ return assertFound(claim, notFoundMessage)
91
97
  }
92
98
 
93
99
  export function appendClaimEvent(
@@ -0,0 +1,30 @@
1
+ import { NextResponse } from 'next/server'
2
+ import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
3
+ import { getCustomerAuthFromRequest, type CustomerAuthContext } from '@open-mercato/core/modules/customer_accounts/lib/customerAuth'
4
+
5
+ export type LinkedCustomerAuthContext = CustomerAuthContext & { customerEntityId: string }
6
+
7
+ export async function resolveLinkedCustomerAuth(req: Request): Promise<LinkedCustomerAuthContext | Response> {
8
+ const auth = await getCustomerAuthFromRequest(req)
9
+ if (!auth) {
10
+ const { translate } = await resolveTranslations()
11
+ return NextResponse.json(
12
+ { ok: false, error: translate('warranty_claims.errors.unauthorized', 'Unauthorized') },
13
+ { status: 401 },
14
+ )
15
+ }
16
+ if (!auth.customerEntityId) {
17
+ const { translate } = await resolveTranslations()
18
+ return NextResponse.json(
19
+ {
20
+ ok: false,
21
+ error: translate(
22
+ 'warranty_claims.errors.customerAccountNotLinked',
23
+ 'Customer account is not linked to a customer record',
24
+ ),
25
+ },
26
+ { status: 403 },
27
+ )
28
+ }
29
+ return auth as LinkedCustomerAuthContext
30
+ }