@open-mercato/core 0.6.1-develop.3139.9fc38487c8 → 0.6.1-develop.3144.b39fb4dfa6

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 (190) hide show
  1. package/dist/modules/catalog/api/dictionaries/[key]/route.js +2 -2
  2. package/dist/modules/catalog/api/dictionaries/[key]/route.js.map +2 -2
  3. package/dist/modules/customers/api/activities/route.js +5 -5
  4. package/dist/modules/customers/api/activities/route.js.map +2 -2
  5. package/dist/modules/customers/api/assignable-staff/route.js +2 -2
  6. package/dist/modules/customers/api/assignable-staff/route.js.map +2 -2
  7. package/dist/modules/customers/api/companies/[id]/people/route.js +2 -2
  8. package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
  9. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +2 -2
  10. package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
  11. package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js +2 -2
  12. package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js.map +2 -2
  13. package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js +2 -2
  14. package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js.map +2 -2
  15. package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js +2 -2
  16. package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js.map +2 -2
  17. package/dist/modules/customers/api/deals/[id]/companies/route.js +2 -2
  18. package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
  19. package/dist/modules/customers/api/deals/[id]/people/route.js +2 -2
  20. package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
  21. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +6 -6
  22. package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
  23. package/dist/modules/customers/api/dictionaries/[kind]/route.js +3 -3
  24. package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
  25. package/dist/modules/customers/api/dictionaries/currency/route.js +2 -2
  26. package/dist/modules/customers/api/dictionaries/currency/route.js.map +2 -2
  27. package/dist/modules/customers/api/dictionaries/kind-settings/route.js +3 -3
  28. package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
  29. package/dist/modules/customers/api/entity-roles-factory.js +5 -5
  30. package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
  31. package/dist/modules/customers/api/interactions/cancel/route.js +2 -2
  32. package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
  33. package/dist/modules/customers/api/interactions/complete/route.js +2 -2
  34. package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
  35. package/dist/modules/customers/api/interactions/conflicts/route.js +2 -2
  36. package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
  37. package/dist/modules/customers/api/interactions/counts/route.js +2 -2
  38. package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
  39. package/dist/modules/customers/api/interactions/route.js +2 -2
  40. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  41. package/dist/modules/customers/api/interactions/tasks/route.js +2 -2
  42. package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
  43. package/dist/modules/customers/api/labels/assign/route.js +2 -2
  44. package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
  45. package/dist/modules/customers/api/labels/route.js +3 -3
  46. package/dist/modules/customers/api/labels/route.js.map +2 -2
  47. package/dist/modules/customers/api/labels/unassign/route.js +2 -2
  48. package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
  49. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +3 -3
  50. package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +2 -2
  51. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +2 -2
  52. package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
  53. package/dist/modules/customers/api/people/[id]/companies/route.js +3 -3
  54. package/dist/modules/customers/api/people/[id]/companies/route.js.map +2 -2
  55. package/dist/modules/customers/api/pipeline-stages/reorder/route.js +2 -2
  56. package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
  57. package/dist/modules/customers/api/pipeline-stages/route.js +5 -5
  58. package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
  59. package/dist/modules/customers/api/pipelines/route.js +5 -5
  60. package/dist/modules/customers/api/pipelines/route.js.map +2 -2
  61. package/dist/modules/customers/api/settings/address-format/route.js +3 -3
  62. package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
  63. package/dist/modules/customers/api/tags/assign/route.js +2 -2
  64. package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
  65. package/dist/modules/customers/api/tags/unassign/route.js +2 -2
  66. package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
  67. package/dist/modules/customers/api/todos/route.js +5 -5
  68. package/dist/modules/customers/api/todos/route.js.map +2 -2
  69. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
  70. package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
  71. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +2 -2
  72. package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
  73. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +3 -3
  74. package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
  75. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +2 -2
  76. package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
  77. package/dist/modules/dictionaries/api/[dictionaryId]/route.js +4 -4
  78. package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
  79. package/dist/modules/dictionaries/api/route.js +3 -3
  80. package/dist/modules/dictionaries/api/route.js.map +2 -2
  81. package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
  82. package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
  83. package/dist/modules/planner/api/availability-date-specific.js +2 -2
  84. package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
  85. package/dist/modules/planner/api/availability-weekly.js +2 -2
  86. package/dist/modules/planner/api/availability-weekly.js.map +2 -2
  87. package/dist/modules/resources/api/resources/tags/assign/route.js +2 -2
  88. package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
  89. package/dist/modules/resources/api/resources/tags/unassign/route.js +2 -2
  90. package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
  91. package/dist/modules/sales/api/document-history/route.js +2 -2
  92. package/dist/modules/sales/api/document-history/route.js.map +2 -2
  93. package/dist/modules/sales/api/document-numbers/route.js +2 -2
  94. package/dist/modules/sales/api/document-numbers/route.js.map +2 -2
  95. package/dist/modules/sales/api/quotes/accept/route.js +2 -2
  96. package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
  97. package/dist/modules/sales/api/quotes/convert/route.js +2 -2
  98. package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
  99. package/dist/modules/sales/api/quotes/public/[token]/route.js +2 -2
  100. package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
  101. package/dist/modules/sales/api/quotes/send/route.js +2 -2
  102. package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
  103. package/dist/modules/sales/api/returns/[id]/route.js +2 -2
  104. package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
  105. package/dist/modules/sales/api/settings/document-numbers/route.js +3 -3
  106. package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
  107. package/dist/modules/sales/api/settings/order-editing/route.js +3 -3
  108. package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
  109. package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js +2 -2
  110. package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js.map +2 -2
  111. package/dist/modules/staff/api/leave-requests/accept/route.js +2 -2
  112. package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
  113. package/dist/modules/staff/api/leave-requests/reject/route.js +2 -2
  114. package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
  115. package/dist/modules/staff/api/team-members/self/route.js +3 -3
  116. package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
  117. package/dist/modules/staff/api/team-members/tags/assign/route.js +2 -2
  118. package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
  119. package/dist/modules/staff/api/team-members/tags/unassign/route.js +2 -2
  120. package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
  121. package/dist/modules/translations/api/[entityType]/[entityId]/route.js +4 -4
  122. package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
  123. package/dist/modules/translations/api/get/locales.js +2 -2
  124. package/dist/modules/translations/api/get/locales.js.map +2 -2
  125. package/dist/modules/translations/api/put/locales.js +2 -2
  126. package/dist/modules/translations/api/put/locales.js.map +2 -2
  127. package/package.json +5 -5
  128. package/src/modules/catalog/api/dictionaries/[key]/route.ts +2 -2
  129. package/src/modules/customers/api/activities/route.ts +5 -5
  130. package/src/modules/customers/api/assignable-staff/route.ts +2 -2
  131. package/src/modules/customers/api/companies/[id]/people/route.ts +2 -2
  132. package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +2 -2
  133. package/src/modules/customers/api/dashboard/widgets/new-customers/route.ts +2 -2
  134. package/src/modules/customers/api/dashboard/widgets/new-deals/route.ts +2 -2
  135. package/src/modules/customers/api/dashboard/widgets/next-interactions/route.ts +2 -2
  136. package/src/modules/customers/api/deals/[id]/companies/route.ts +2 -2
  137. package/src/modules/customers/api/deals/[id]/people/route.ts +2 -2
  138. package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +6 -6
  139. package/src/modules/customers/api/dictionaries/[kind]/route.ts +3 -3
  140. package/src/modules/customers/api/dictionaries/currency/route.ts +2 -2
  141. package/src/modules/customers/api/dictionaries/kind-settings/route.ts +3 -3
  142. package/src/modules/customers/api/entity-roles-factory.ts +5 -5
  143. package/src/modules/customers/api/interactions/cancel/route.ts +2 -2
  144. package/src/modules/customers/api/interactions/complete/route.ts +2 -2
  145. package/src/modules/customers/api/interactions/conflicts/route.ts +2 -2
  146. package/src/modules/customers/api/interactions/counts/route.ts +2 -2
  147. package/src/modules/customers/api/interactions/route.ts +2 -2
  148. package/src/modules/customers/api/interactions/tasks/route.ts +2 -2
  149. package/src/modules/customers/api/labels/assign/route.ts +2 -2
  150. package/src/modules/customers/api/labels/route.ts +3 -3
  151. package/src/modules/customers/api/labels/unassign/route.ts +2 -2
  152. package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +3 -3
  153. package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +2 -2
  154. package/src/modules/customers/api/people/[id]/companies/route.ts +3 -3
  155. package/src/modules/customers/api/pipeline-stages/reorder/route.ts +2 -2
  156. package/src/modules/customers/api/pipeline-stages/route.ts +5 -5
  157. package/src/modules/customers/api/pipelines/route.ts +5 -5
  158. package/src/modules/customers/api/settings/address-format/route.ts +3 -3
  159. package/src/modules/customers/api/tags/assign/route.ts +2 -2
  160. package/src/modules/customers/api/tags/unassign/route.ts +2 -2
  161. package/src/modules/customers/api/todos/route.ts +5 -5
  162. package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
  163. package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +2 -2
  164. package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +3 -3
  165. package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +2 -2
  166. package/src/modules/dictionaries/api/[dictionaryId]/route.ts +4 -4
  167. package/src/modules/dictionaries/api/route.ts +3 -3
  168. package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
  169. package/src/modules/planner/api/availability-date-specific.ts +2 -2
  170. package/src/modules/planner/api/availability-weekly.ts +2 -2
  171. package/src/modules/resources/api/resources/tags/assign/route.ts +2 -2
  172. package/src/modules/resources/api/resources/tags/unassign/route.ts +2 -2
  173. package/src/modules/sales/api/document-history/route.ts +2 -2
  174. package/src/modules/sales/api/document-numbers/route.ts +2 -2
  175. package/src/modules/sales/api/quotes/accept/route.ts +2 -2
  176. package/src/modules/sales/api/quotes/convert/route.ts +2 -2
  177. package/src/modules/sales/api/quotes/public/[token]/route.ts +2 -2
  178. package/src/modules/sales/api/quotes/send/route.ts +2 -2
  179. package/src/modules/sales/api/returns/[id]/route.ts +2 -2
  180. package/src/modules/sales/api/settings/document-numbers/route.ts +3 -3
  181. package/src/modules/sales/api/settings/order-editing/route.ts +3 -3
  182. package/src/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.ts +2 -2
  183. package/src/modules/staff/api/leave-requests/accept/route.ts +2 -2
  184. package/src/modules/staff/api/leave-requests/reject/route.ts +2 -2
  185. package/src/modules/staff/api/team-members/self/route.ts +3 -3
  186. package/src/modules/staff/api/team-members/tags/assign/route.ts +2 -2
  187. package/src/modules/staff/api/team-members/tags/unassign/route.ts +2 -2
  188. package/src/modules/translations/api/[entityType]/[entityId]/route.ts +4 -4
  189. package/src/modules/translations/api/get/locales.ts +2 -2
  190. package/src/modules/translations/api/put/locales.ts +2 -2
@@ -2,7 +2,7 @@ import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
3
  import { Dictionary, DictionaryEntry } from "@open-mercato/core/modules/dictionaries/data/entities";
4
4
  import { resolveDictionariesRouteContext } from "@open-mercato/core/modules/dictionaries/api/context";
5
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
5
+ import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
6
6
  const KEY_ALIASES = {
7
7
  currency: ["currency", "currencies"],
8
8
  unit: ["unit", "units", "measurement_units"]
@@ -52,7 +52,7 @@ async function GET(req, ctx) {
52
52
  }))
53
53
  });
54
54
  } catch (err) {
55
- if (err instanceof CrudHttpError) {
55
+ if (isCrudHttpError(err)) {
56
56
  return NextResponse.json(err.body, { status: err.status });
57
57
  }
58
58
  console.error("[catalog.dictionaries.GET] Unexpected error", err);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/catalog/api/dictionaries/%5Bkey%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { Dictionary, DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { resolveDictionariesRouteContext } from '@open-mercato/core/modules/dictionaries/api/context'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nconst KEY_ALIASES: Record<string, string[]> = {\n currency: ['currency', 'currencies'],\n unit: ['unit', 'units', 'measurement_units'],\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.manage'] },\n}\n\nexport async function GET(\n req: Request,\n ctx: { params?: { key?: string } },\n): Promise<Response> {\n try {\n const context = await resolveDictionariesRouteContext(req)\n const keyParam = (ctx.params?.key ?? '').toLowerCase().trim()\n if (!keyParam) {\n throw new CrudHttpError(400, { error: 'Dictionary key is required.' })\n }\n const keys = KEY_ALIASES[keyParam] ?? [keyParam]\n const dictionaries = await context.em.find(\n Dictionary,\n {\n tenantId: context.tenantId,\n key: { $in: keys },\n deletedAt: null,\n isActive: true,\n },\n { orderBy: { organizationId: 'asc', createdAt: 'asc' } },\n )\n const dictionary =\n dictionaries.find((entry) => entry.organizationId === context.organizationId) ??\n dictionaries[0] ??\n null\n if (!dictionary) {\n return NextResponse.json({ error: 'Dictionary not found.' }, { status: 404 })\n }\n const entries = await context.em.find(\n DictionaryEntry,\n {\n dictionary,\n organizationId: dictionary.organizationId,\n tenantId: dictionary.tenantId,\n },\n { orderBy: { label: 'asc' } },\n )\n return NextResponse.json({\n id: dictionary.id,\n entries: entries.map((entry) => ({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n })),\n })\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('[catalog.dictionaries.GET] Unexpected error', err)\n return NextResponse.json({ error: 'Failed to load dictionary.' }, { status: 500 })\n }\n}\n\nconst dictionaryEntrySchema = z.object({\n id: z.string().uuid(),\n value: z.string(),\n label: z.string(),\n color: z.string().nullable(),\n icon: z.string().nullable(),\n})\n\nconst dictionaryResponseSchema = z.object({\n id: z.string().uuid(),\n entries: z.array(dictionaryEntrySchema),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Catalog',\n summary: 'Catalog Dictionary lookup',\n methods: {\n GET: {\n summary: 'Get dictionary entries by key',\n description: 'Returns dictionary entries for a specific key (e.g., currency, unit).',\n responses: [\n {\n status: 200,\n description: 'Dictionary entries',\n schema: dictionaryResponseSchema,\n },\n ],\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,YAAY,uBAAuB;AAC5C,SAAS,uCAAuC;AAChD,SAAS,qBAAqB;AAG9B,MAAM,cAAwC;AAAA,EAC5C,UAAU,CAAC,YAAY,YAAY;AAAA,EACnC,MAAM,CAAC,QAAQ,SAAS,mBAAmB;AAC7C;AAEO,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AACzE;AAEA,eAAsB,IACpB,KACA,KACmB;AACnB,MAAI;AACF,UAAM,UAAU,MAAM,gCAAgC,GAAG;AACzD,UAAM,YAAY,IAAI,QAAQ,OAAO,IAAI,YAAY,EAAE,KAAK;AAC5D,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,8BAA8B,CAAC;AAAA,IACvE;AACA,UAAM,OAAO,YAAY,QAAQ,KAAK,CAAC,QAAQ;AAC/C,UAAM,eAAe,MAAM,QAAQ,GAAG;AAAA,MACpC;AAAA,MACA;AAAA,QACE,UAAU,QAAQ;AAAA,QAClB,KAAK,EAAE,KAAK,KAAK;AAAA,QACjB,WAAW;AAAA,QACX,UAAU;AAAA,MACZ;AAAA,MACA,EAAE,SAAS,EAAE,gBAAgB,OAAO,WAAW,MAAM,EAAE;AAAA,IACzD;AACA,UAAM,aACJ,aAAa,KAAK,CAAC,UAAU,MAAM,mBAAmB,QAAQ,cAAc,KAC5E,aAAa,CAAC,KACd;AACF,QAAI,CAAC,YAAY;AACf,aAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC9E;AACA,UAAM,UAAU,MAAM,QAAQ,GAAG;AAAA,MAC/B;AAAA,MACA;AAAA,QACE;AAAA,QACA,gBAAgB,WAAW;AAAA,QAC3B,UAAU,WAAW;AAAA,MACvB;AAAA,MACA,EAAE,SAAS,EAAE,OAAO,MAAM,EAAE;AAAA,IAC9B;AACA,WAAO,aAAa,KAAK;AAAA,MACvB,IAAI,WAAW;AAAA,MACf,SAAS,QAAQ,IAAI,CAAC,WAAW;AAAA,QAC/B,IAAI,MAAM;AAAA,QACV,OAAO,MAAM;AAAA,QACb,OAAO,MAAM;AAAA,QACb,OAAO,MAAM,SAAS;AAAA,QACtB,MAAM,MAAM,QAAQ;AAAA,MACtB,EAAE;AAAA,IACJ,CAAC;AAAA,EACH,SAAS,KAAK;AACZ,QAAI,eAAe,eAAe;AAChC,aAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC3D;AACA,YAAQ,MAAM,+CAA+C,GAAG;AAChE,WAAO,aAAa,KAAK,EAAE,OAAO,6BAA6B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACnF;AACF;AAEA,MAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,MAAM,2BAA2B,EAAE,OAAO;AAAA,EACxC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,SAAS,EAAE,MAAM,qBAAqB;AACxC,CAAC;AAEM,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { Dictionary, DictionaryEntry } from '@open-mercato/core/modules/dictionaries/data/entities'\nimport { resolveDictionariesRouteContext } from '@open-mercato/core/modules/dictionaries/api/context'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\n\nconst KEY_ALIASES: Record<string, string[]> = {\n currency: ['currency', 'currencies'],\n unit: ['unit', 'units', 'measurement_units'],\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.manage'] },\n}\n\nexport async function GET(\n req: Request,\n ctx: { params?: { key?: string } },\n): Promise<Response> {\n try {\n const context = await resolveDictionariesRouteContext(req)\n const keyParam = (ctx.params?.key ?? '').toLowerCase().trim()\n if (!keyParam) {\n throw new CrudHttpError(400, { error: 'Dictionary key is required.' })\n }\n const keys = KEY_ALIASES[keyParam] ?? [keyParam]\n const dictionaries = await context.em.find(\n Dictionary,\n {\n tenantId: context.tenantId,\n key: { $in: keys },\n deletedAt: null,\n isActive: true,\n },\n { orderBy: { organizationId: 'asc', createdAt: 'asc' } },\n )\n const dictionary =\n dictionaries.find((entry) => entry.organizationId === context.organizationId) ??\n dictionaries[0] ??\n null\n if (!dictionary) {\n return NextResponse.json({ error: 'Dictionary not found.' }, { status: 404 })\n }\n const entries = await context.em.find(\n DictionaryEntry,\n {\n dictionary,\n organizationId: dictionary.organizationId,\n tenantId: dictionary.tenantId,\n },\n { orderBy: { label: 'asc' } },\n )\n return NextResponse.json({\n id: dictionary.id,\n entries: entries.map((entry) => ({\n id: entry.id,\n value: entry.value,\n label: entry.label,\n color: entry.color ?? null,\n icon: entry.icon ?? null,\n })),\n })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('[catalog.dictionaries.GET] Unexpected error', err)\n return NextResponse.json({ error: 'Failed to load dictionary.' }, { status: 500 })\n }\n}\n\nconst dictionaryEntrySchema = z.object({\n id: z.string().uuid(),\n value: z.string(),\n label: z.string(),\n color: z.string().nullable(),\n icon: z.string().nullable(),\n})\n\nconst dictionaryResponseSchema = z.object({\n id: z.string().uuid(),\n entries: z.array(dictionaryEntrySchema),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Catalog',\n summary: 'Catalog Dictionary lookup',\n methods: {\n GET: {\n summary: 'Get dictionary entries by key',\n description: 'Returns dictionary entries for a specific key (e.g., currency, unit).',\n responses: [\n {\n status: 200,\n description: 'Dictionary entries',\n schema: dictionaryResponseSchema,\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
3
+ import { isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
4
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
5
5
  import {
6
6
  runCrudMutationGuardAfterSuccess,
@@ -314,7 +314,7 @@ async function GET(request) {
314
314
  })
315
315
  );
316
316
  } catch (err) {
317
- if (err instanceof CrudHttpError) {
317
+ if (isCrudHttpError(err)) {
318
318
  return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }));
319
319
  }
320
320
  if (err instanceof z.ZodError) {
@@ -395,7 +395,7 @@ async function POST(request) {
395
395
  )
396
396
  );
397
397
  } catch (err) {
398
- if (err instanceof CrudHttpError) {
398
+ if (isCrudHttpError(err)) {
399
399
  return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }));
400
400
  }
401
401
  if (err instanceof z.ZodError) {
@@ -467,7 +467,7 @@ async function PUT(request) {
467
467
  }
468
468
  return withAdapterHeaders(NextResponse.json({ ok: true }));
469
469
  } catch (err) {
470
- if (err instanceof CrudHttpError) {
470
+ if (isCrudHttpError(err)) {
471
471
  return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }));
472
472
  }
473
473
  if (err instanceof z.ZodError) {
@@ -526,7 +526,7 @@ async function DELETE(request) {
526
526
  }
527
527
  return withAdapterHeaders(NextResponse.json({ ok: true }));
528
528
  } catch (err) {
529
- if (err instanceof CrudHttpError) {
529
+ if (isCrudHttpError(err)) {
530
530
  return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }));
531
531
  }
532
532
  if (err instanceof z.ZodError) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/api/activities/route.ts"],
4
- "sourcesContent": ["/**\n * @deprecated Use /api/customers/interactions instead. This route is maintained\n * as a compatibility bridge per SPEC-046b and delegates writes to canonical\n * interaction commands.\n */\nimport { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerActivity, CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { activityCreateSchema, activityUpdateSchema } from '../../data/validators'\nimport { createCustomersCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../openapi'\nimport {\n mapInteractionRecordToActivitySummary,\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n} from '../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../lib/interactionFeatureFlags'\nimport { resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\nimport { hydrateCanonicalInteractions } from '../../lib/interactionReadModel'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\n\nconst listSchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n activityType: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.activities.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst activityCreateBodySchema = activityCreateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityUpdateBodySchema = activityUpdateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityDeleteBodySchema = z.object({\n id: z.string().uuid(),\n})\n\nconst ADAPTER_HEADERS = {\n Deprecation: 'true',\n Sunset: 'Tue, 30 Jun 2026 00:00:00 GMT',\n Link: '</api/customers/interactions>; rel=\"successor-version\"',\n}\n\n// Caps the per-source fetch window used by the deprecated merged (legacy +\n// canonical bridge) read path. Keeps memory bounded on tenants with large\n// activity history; deep-pagination beyond this window is not supported here \u2014\n// use /api/customers/interactions instead.\nconst MERGED_ACTIVITY_FETCH_CAP = 2000\n\ntype ActivityItem = {\n id: string\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n createdAt: string\n appearanceIcon?: string | null\n appearanceColor?: string | null\n entityId?: string | null\n authorUserId?: string | null\n authorName?: string | null\n authorEmail?: string | null\n dealId?: string | null\n dealTitle?: string | null\n customValues?: Record<string, unknown> | null\n activityTypeLabel?: string | null\n}\n\ntype CanonicalActivityListResult = {\n items: ActivityItem[]\n total: number\n bridgeIds: Set<string>\n}\n\nfunction resolveGuardUserId(auth: {\n sub?: string | null\n userId?: string | null\n keyId?: string | null\n}): string {\n if (typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nfunction withAdapterHeaders(response: Response): Response {\n const headers = new Headers(response.headers)\n Object.entries(ADAPTER_HEADERS).forEach(([key, value]) => headers.set(key, value))\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n\nasync function legacyAdaptersDisabledResponse(): Promise<Response> {\n const { translate } = await resolveTranslations()\n return withAdapterHeaders(NextResponse.json(\n {\n error: translate(\n 'customers.interactions.legacyAdapters.disabled',\n 'This legacy adapter has been disabled. Use /api/customers/interactions instead.',\n ),\n },\n { status: 410 },\n ))\n}\n\nfunction buildLegacyOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction buildCanonicalOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction resolveActivitySortValue(item: ActivityItem, sortField: string | undefined): number {\n const raw =\n sortField === 'createdAt'\n ? item.createdAt\n : item.occurredAt ?? item.createdAt\n const timestamp = raw ? new Date(raw).getTime() : Number.NaN\n return Number.isNaN(timestamp) ? 0 : timestamp\n}\n\nfunction sortActivityItems(\n items: ActivityItem[],\n sortField: string | undefined,\n sortDir: 'asc' | 'desc',\n): ActivityItem[] {\n return [...items].sort((left, right) => {\n const leftValue = resolveActivitySortValue(left, sortField)\n const rightValue = resolveActivitySortValue(right, sortField)\n if (leftValue === rightValue) {\n return sortDir === 'asc'\n ? left.id.localeCompare(right.id)\n : right.id.localeCompare(left.id)\n }\n return sortDir === 'asc' ? leftValue - rightValue : rightValue - leftValue\n })\n}\n\nfunction paginateActivityItems(\n items: ActivityItem[],\n page: number,\n pageSize: number,\n): { items: ActivityItem[]; total: number } {\n const start = (page - 1) * pageSize\n return {\n items: items.slice(start, start + pageSize),\n total: items.length,\n }\n}\n\nasync function decorateActivityItems(\n em: EntityManager,\n items: ActivityItem[],\n decryptionScope?: { tenantId: string; organizationId: string },\n): Promise<ActivityItem[]> {\n if (items.length === 0) return items\n\n const authorIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.authorUserId === 'string' ? item.authorUserId : null))\n .filter((value): value is string => !!value),\n ),\n )\n const dealIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.dealId === 'string' ? item.dealId : null))\n .filter((value): value is string => !!value),\n ),\n )\n\n const [users, deals] = await Promise.all([\n authorIds.length > 0 ? em.find(User, { id: { $in: authorIds } }) : Promise.resolve([]),\n dealIds.length > 0\n ? decryptionScope\n ? findWithDecryption(em, CustomerDeal, { id: { $in: dealIds } }, undefined, decryptionScope)\n : em.find(CustomerDeal, { id: { $in: dealIds } })\n : Promise.resolve([]),\n ])\n\n const userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ]),\n )\n const dealMap = new Map(deals.map((deal) => [deal.id, deal.title]))\n\n return items.map((item) => ({\n ...item,\n activityTypeLabel: item.activityType,\n authorName: item.authorUserId ? userMap.get(item.authorUserId)?.name ?? null : null,\n authorEmail: item.authorUserId ? userMap.get(item.authorUserId)?.email ?? null : null,\n dealTitle: item.dealId ? dealMap.get(item.dealId) ?? null : null,\n }))\n}\n\nfunction mapLegacyActivity(activity: CustomerActivity): ActivityItem {\n return {\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n entityId: typeof activity.entity === 'string' ? activity.entity : activity.entity.id,\n authorUserId: activity.authorUserId ?? null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n customValues: null,\n }\n}\n\nasync function listCanonicalActivities(\n em: EntityManager,\n container: { resolve: (name: string) => unknown },\n auth: { tenantId: string | null; orgId: string | null; sub?: string | null; userId?: string | null; keyId?: string | null },\n selectedOrganizationId: string | null,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { includeDeleted?: boolean; source?: string | string[] | null; paginate?: boolean },\n): Promise<CanonicalActivityListResult> {\n const where: Record<string, unknown> = {\n tenantId,\n interactionType: { $ne: 'task' },\n }\n if (!options?.includeDeleted) {\n where.deletedAt = null\n }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.dealId = query.dealId\n if (query.activityType) where.interactionType = query.activityType\n if (options?.source) {\n where.source = Array.isArray(options.source) ? { $in: options.source } : options.source\n }\n\n const findOptions = {\n orderBy: buildCanonicalOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerInteraction, where, findOptions)\n : (await em.findAndCount(CustomerInteraction, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.filter((row) => !row.deletedAt).length\n : await em.count(CustomerInteraction, where)\n\n const activeRows = rows.filter((row) => !row.deletedAt)\n const hydrated = await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId,\n interactions: activeRows,\n })\n const items = hydrated.map((row) => ({\n ...mapInteractionRecordToActivitySummary(row),\n customValues: row.customValues ?? null,\n activityTypeLabel: row.interactionType,\n }))\n\n return {\n items,\n total,\n bridgeIds: new Set(rows.map((row) => row.id)),\n }\n}\n\nasync function listLegacyActivities(\n em: EntityManager,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { paginate?: boolean },\n selectedOrganizationId?: string | null,\n): Promise<{ items: ActivityItem[]; total: number }> {\n const where: Record<string, unknown> = { tenantId }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.deal = query.dealId\n if (query.activityType) where.activityType = query.activityType\n\n const findOptions = {\n populate: ['entity', 'deal'] as const,\n orderBy: buildLegacyOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerActivity, where, findOptions)\n : (await em.findAndCount(CustomerActivity, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.length\n : await em.count(CustomerActivity, where)\n\n return {\n items: await decorateActivityItems(\n em,\n rows.map(mapLegacyActivity),\n selectedOrganizationId ? { tenantId, organizationId: selectedOrganizationId } : undefined,\n ),\n total,\n }\n}\n\nexport async function GET(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url)\n const query = listSchema.parse(Object.fromEntries(url.searchParams))\n const {\n auth,\n em,\n organizationIds,\n container,\n selectedOrganizationId,\n } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n\n const sortDir = query.sortDir ?? 'desc'\n\n const result = flags.unified\n ? await listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n query,\n )\n : await (async () => {\n const windowSize = Math.min(\n MERGED_ACTIVITY_FETCH_CAP,\n Math.max(query.pageSize, query.page * query.pageSize + query.pageSize),\n )\n const windowedQuery = { ...query, page: 1, pageSize: windowSize }\n const [legacy, canonical] = await Promise.all([\n listLegacyActivities(\n em,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n { paginate: true },\n selectedOrganizationId,\n ),\n listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n {\n includeDeleted: true,\n paginate: true,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n },\n ),\n ])\n const merged = sortActivityItems(\n [\n ...legacy.items.filter((item) => !canonical.bridgeIds.has(item.id)),\n ...canonical.items,\n ],\n query.sortField,\n sortDir,\n )\n const paged = paginateActivityItems(merged, query.page, query.pageSize)\n return {\n items: paged.items,\n total: paged.total,\n }\n })()\n\n return withAdapterHeaders(\n NextResponse.json({\n items: result.items,\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n totalPages: Math.max(1, Math.ceil(result.total / query.pageSize)),\n }),\n )\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.get failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function POST(request: Request): Promise<Response> {\n try {\n const { commandContext, container, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityCreateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute('customers.interactions.create', {\n input: {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId ?? auth.orgId,\n entityId: parsed.entityId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? null,\n body: parsed.body ?? null,\n occurredAt: parsed.occurredAt ?? null,\n status: parsed.occurredAt ? 'done' : 'planned',\n dealId: parsed.dealId ?? null,\n authorUserId: parsed.authorUserId ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(\n NextResponse.json(\n {\n id:\n result &&\n typeof result === 'object' &&\n 'interactionId' in result &&\n typeof result.interactionId === 'string'\n ? result.interactionId\n : result &&\n typeof result === 'object' &&\n 'id' in result &&\n typeof result.id === 'string'\n ? result.id\n : null,\n },\n { status: 201 },\n ),\n )\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.post failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function PUT(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityUpdateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n\n await commandBus.execute('customers.interactions.update', {\n input: {\n id: interactionId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? undefined,\n body: parsed.body ?? undefined,\n occurredAt: parsed.occurredAt ?? undefined,\n status: parsed.occurredAt ? 'done' : undefined,\n dealId: parsed.dealId ?? undefined,\n authorUserId: parsed.authorUserId ?? undefined,\n appearanceIcon: parsed.appearanceIcon ?? undefined,\n appearanceColor: parsed.appearanceColor ?? undefined,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(NextResponse.json({ ok: true }))\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.put failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function DELETE(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityDeleteBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n await commandBus.execute('customers.interactions.delete', {\n input: { id: interactionId },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withAdapterHeaders(NextResponse.json({ ok: true }))\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.delete failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nconst activityListItemSchema = z\n .object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n entityId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n activityTypeLabel: z.string().nullable().optional(),\n })\n .passthrough()\n\nconst activityCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = createCustomersCrudOpenApi({\n resourceName: 'Activity',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(activityListItemSchema),\n create: {\n schema: activityCreateBodySchema,\n responseSchema: activityCreateResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.',\n },\n update: {\n schema: activityUpdateBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.',\n },\n del: {\n schema: activityDeleteBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @deprecated Use /api/customers/interactions instead. This route is maintained\n * as a compatibility bridge per SPEC-046b and delegates writes to canonical\n * interaction commands.\n */\nimport { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { CommandBus } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n runCrudMutationGuardAfterSuccess,\n validateCrudMutationGuard,\n} from '@open-mercato/shared/lib/crud/mutation-guard'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerActivity, CustomerDeal, CustomerInteraction } from '../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { activityCreateSchema, activityUpdateSchema } from '../../data/validators'\nimport { createCustomersCrudOpenApi, createPagedListResponseSchema, defaultOkResponseSchema } from '../openapi'\nimport {\n mapInteractionRecordToActivitySummary,\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n} from '../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../lib/interactionFeatureFlags'\nimport { resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\nimport { hydrateCanonicalInteractions } from '../../lib/interactionReadModel'\nimport { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'\n\nconst listSchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n entityId: z.string().uuid().optional(),\n dealId: z.string().uuid().optional(),\n activityType: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n}).passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.activities.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.activities.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst activityCreateBodySchema = activityCreateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityUpdateBodySchema = activityUpdateSchema.omit({\n organizationId: true,\n tenantId: true,\n}).passthrough()\n\nconst activityDeleteBodySchema = z.object({\n id: z.string().uuid(),\n})\n\nconst ADAPTER_HEADERS = {\n Deprecation: 'true',\n Sunset: 'Tue, 30 Jun 2026 00:00:00 GMT',\n Link: '</api/customers/interactions>; rel=\"successor-version\"',\n}\n\n// Caps the per-source fetch window used by the deprecated merged (legacy +\n// canonical bridge) read path. Keeps memory bounded on tenants with large\n// activity history; deep-pagination beyond this window is not supported here \u2014\n// use /api/customers/interactions instead.\nconst MERGED_ACTIVITY_FETCH_CAP = 2000\n\ntype ActivityItem = {\n id: string\n activityType: string\n subject?: string | null\n body?: string | null\n occurredAt?: string | null\n createdAt: string\n appearanceIcon?: string | null\n appearanceColor?: string | null\n entityId?: string | null\n authorUserId?: string | null\n authorName?: string | null\n authorEmail?: string | null\n dealId?: string | null\n dealTitle?: string | null\n customValues?: Record<string, unknown> | null\n activityTypeLabel?: string | null\n}\n\ntype CanonicalActivityListResult = {\n items: ActivityItem[]\n total: number\n bridgeIds: Set<string>\n}\n\nfunction resolveGuardUserId(auth: {\n sub?: string | null\n userId?: string | null\n keyId?: string | null\n}): string {\n if (typeof auth.sub === 'string' && auth.sub.trim().length > 0) return auth.sub\n if (typeof auth.userId === 'string' && auth.userId.trim().length > 0) return auth.userId\n if (typeof auth.keyId === 'string' && auth.keyId.trim().length > 0) return auth.keyId\n return 'system'\n}\n\nfunction withAdapterHeaders(response: Response): Response {\n const headers = new Headers(response.headers)\n Object.entries(ADAPTER_HEADERS).forEach(([key, value]) => headers.set(key, value))\n return new Response(response.body, {\n status: response.status,\n statusText: response.statusText,\n headers,\n })\n}\n\nasync function legacyAdaptersDisabledResponse(): Promise<Response> {\n const { translate } = await resolveTranslations()\n return withAdapterHeaders(NextResponse.json(\n {\n error: translate(\n 'customers.interactions.legacyAdapters.disabled',\n 'This legacy adapter has been disabled. Use /api/customers/interactions instead.',\n ),\n },\n { status: 410 },\n ))\n}\n\nfunction buildLegacyOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction buildCanonicalOrderBy(sortField: string | undefined, sortDir: 'asc' | 'desc') {\n if (sortField === 'createdAt') {\n return { createdAt: sortDir }\n }\n return { occurredAt: sortDir, createdAt: sortDir } as const\n}\n\nfunction resolveActivitySortValue(item: ActivityItem, sortField: string | undefined): number {\n const raw =\n sortField === 'createdAt'\n ? item.createdAt\n : item.occurredAt ?? item.createdAt\n const timestamp = raw ? new Date(raw).getTime() : Number.NaN\n return Number.isNaN(timestamp) ? 0 : timestamp\n}\n\nfunction sortActivityItems(\n items: ActivityItem[],\n sortField: string | undefined,\n sortDir: 'asc' | 'desc',\n): ActivityItem[] {\n return [...items].sort((left, right) => {\n const leftValue = resolveActivitySortValue(left, sortField)\n const rightValue = resolveActivitySortValue(right, sortField)\n if (leftValue === rightValue) {\n return sortDir === 'asc'\n ? left.id.localeCompare(right.id)\n : right.id.localeCompare(left.id)\n }\n return sortDir === 'asc' ? leftValue - rightValue : rightValue - leftValue\n })\n}\n\nfunction paginateActivityItems(\n items: ActivityItem[],\n page: number,\n pageSize: number,\n): { items: ActivityItem[]; total: number } {\n const start = (page - 1) * pageSize\n return {\n items: items.slice(start, start + pageSize),\n total: items.length,\n }\n}\n\nasync function decorateActivityItems(\n em: EntityManager,\n items: ActivityItem[],\n decryptionScope?: { tenantId: string; organizationId: string },\n): Promise<ActivityItem[]> {\n if (items.length === 0) return items\n\n const authorIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.authorUserId === 'string' ? item.authorUserId : null))\n .filter((value): value is string => !!value),\n ),\n )\n const dealIds = Array.from(\n new Set(\n items\n .map((item) => (typeof item.dealId === 'string' ? item.dealId : null))\n .filter((value): value is string => !!value),\n ),\n )\n\n const [users, deals] = await Promise.all([\n authorIds.length > 0 ? em.find(User, { id: { $in: authorIds } }) : Promise.resolve([]),\n dealIds.length > 0\n ? decryptionScope\n ? findWithDecryption(em, CustomerDeal, { id: { $in: dealIds } }, undefined, decryptionScope)\n : em.find(CustomerDeal, { id: { $in: dealIds } })\n : Promise.resolve([]),\n ])\n\n const userMap = new Map(\n users.map((user) => [\n user.id,\n {\n name: user.name ?? null,\n email: user.email ?? null,\n },\n ]),\n )\n const dealMap = new Map(deals.map((deal) => [deal.id, deal.title]))\n\n return items.map((item) => ({\n ...item,\n activityTypeLabel: item.activityType,\n authorName: item.authorUserId ? userMap.get(item.authorUserId)?.name ?? null : null,\n authorEmail: item.authorUserId ? userMap.get(item.authorUserId)?.email ?? null : null,\n dealTitle: item.dealId ? dealMap.get(item.dealId) ?? null : null,\n }))\n}\n\nfunction mapLegacyActivity(activity: CustomerActivity): ActivityItem {\n return {\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject ?? null,\n body: activity.body ?? null,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n entityId: typeof activity.entity === 'string' ? activity.entity : activity.entity.id,\n authorUserId: activity.authorUserId ?? null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n customValues: null,\n }\n}\n\nasync function listCanonicalActivities(\n em: EntityManager,\n container: { resolve: (name: string) => unknown },\n auth: { tenantId: string | null; orgId: string | null; sub?: string | null; userId?: string | null; keyId?: string | null },\n selectedOrganizationId: string | null,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { includeDeleted?: boolean; source?: string | string[] | null; paginate?: boolean },\n): Promise<CanonicalActivityListResult> {\n const where: Record<string, unknown> = {\n tenantId,\n interactionType: { $ne: 'task' },\n }\n if (!options?.includeDeleted) {\n where.deletedAt = null\n }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.dealId = query.dealId\n if (query.activityType) where.interactionType = query.activityType\n if (options?.source) {\n where.source = Array.isArray(options.source) ? { $in: options.source } : options.source\n }\n\n const findOptions = {\n orderBy: buildCanonicalOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerInteraction, where, findOptions)\n : (await em.findAndCount(CustomerInteraction, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.filter((row) => !row.deletedAt).length\n : await em.count(CustomerInteraction, where)\n\n const activeRows = rows.filter((row) => !row.deletedAt)\n const hydrated = await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId,\n interactions: activeRows,\n })\n const items = hydrated.map((row) => ({\n ...mapInteractionRecordToActivitySummary(row),\n customValues: row.customValues ?? null,\n activityTypeLabel: row.interactionType,\n }))\n\n return {\n items,\n total,\n bridgeIds: new Set(rows.map((row) => row.id)),\n }\n}\n\nasync function listLegacyActivities(\n em: EntityManager,\n tenantId: string,\n organizationIds: string[] | null,\n query: z.infer<typeof listSchema>,\n options?: { paginate?: boolean },\n selectedOrganizationId?: string | null,\n): Promise<{ items: ActivityItem[]; total: number }> {\n const where: Record<string, unknown> = { tenantId }\n if (organizationIds && organizationIds.length > 0) {\n where.organizationId = { $in: organizationIds }\n }\n if (query.entityId) where.entity = query.entityId\n if (query.dealId) where.deal = query.dealId\n if (query.activityType) where.activityType = query.activityType\n\n const findOptions = {\n populate: ['entity', 'deal'] as const,\n orderBy: buildLegacyOrderBy(query.sortField, query.sortDir ?? 'desc'),\n ...(options?.paginate === false\n ? {}\n : {\n offset: (query.page - 1) * query.pageSize,\n limit: query.pageSize,\n }),\n }\n\n const rows =\n options?.paginate === false\n ? await em.find(CustomerActivity, where, findOptions)\n : (await em.findAndCount(CustomerActivity, where, findOptions))[0]\n const total =\n options?.paginate === false\n ? rows.length\n : await em.count(CustomerActivity, where)\n\n return {\n items: await decorateActivityItems(\n em,\n rows.map(mapLegacyActivity),\n selectedOrganizationId ? { tenantId, organizationId: selectedOrganizationId } : undefined,\n ),\n total,\n }\n}\n\nexport async function GET(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url)\n const query = listSchema.parse(Object.fromEntries(url.searchParams))\n const {\n auth,\n em,\n organizationIds,\n container,\n selectedOrganizationId,\n } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n\n const sortDir = query.sortDir ?? 'desc'\n\n const result = flags.unified\n ? await listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n query,\n )\n : await (async () => {\n const windowSize = Math.min(\n MERGED_ACTIVITY_FETCH_CAP,\n Math.max(query.pageSize, query.page * query.pageSize + query.pageSize),\n )\n const windowedQuery = { ...query, page: 1, pageSize: windowSize }\n const [legacy, canonical] = await Promise.all([\n listLegacyActivities(\n em,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n { paginate: true },\n selectedOrganizationId,\n ),\n listCanonicalActivities(\n em,\n container,\n auth,\n selectedOrganizationId,\n auth.tenantId,\n organizationIds,\n windowedQuery,\n {\n includeDeleted: true,\n paginate: true,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n },\n ),\n ])\n const merged = sortActivityItems(\n [\n ...legacy.items.filter((item) => !canonical.bridgeIds.has(item.id)),\n ...canonical.items,\n ],\n query.sortField,\n sortDir,\n )\n const paged = paginateActivityItems(merged, query.page, query.pageSize)\n return {\n items: paged.items,\n total: paged.total,\n }\n })()\n\n return withAdapterHeaders(\n NextResponse.json({\n items: result.items,\n total: result.total,\n page: query.page,\n pageSize: query.pageSize,\n totalPages: Math.max(1, Math.ceil(result.total / query.pageSize)),\n }),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.get failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function POST(request: Request): Promise<Response> {\n try {\n const { commandContext, container, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityCreateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const { result } = await commandBus.execute('customers.interactions.create', {\n input: {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId ?? auth.orgId,\n entityId: parsed.entityId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? null,\n body: parsed.body ?? null,\n occurredAt: parsed.occurredAt ?? null,\n status: parsed.occurredAt ? 'done' : 'planned',\n dealId: parsed.dealId ?? null,\n authorUserId: parsed.authorUserId ?? null,\n appearanceIcon: parsed.appearanceIcon ?? null,\n appearanceColor: parsed.appearanceColor ?? null,\n source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.entityId,\n operation: 'create',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(\n NextResponse.json(\n {\n id:\n result &&\n typeof result === 'object' &&\n 'interactionId' in result &&\n typeof result.interactionId === 'string'\n ? result.interactionId\n : result &&\n typeof result === 'object' &&\n 'id' in result &&\n typeof result.id === 'string'\n ? result.id\n : null,\n },\n { status: 201 },\n ),\n )\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.post failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function PUT(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityUpdateBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n\n await commandBus.execute('customers.interactions.update', {\n input: {\n id: interactionId,\n interactionType: parsed.activityType,\n title: parsed.subject ?? undefined,\n body: parsed.body ?? undefined,\n occurredAt: parsed.occurredAt ?? undefined,\n status: parsed.occurredAt ? 'done' : undefined,\n dealId: parsed.dealId ?? undefined,\n authorUserId: parsed.authorUserId ?? undefined,\n appearanceIcon: parsed.appearanceIcon ?? undefined,\n appearanceColor: parsed.appearanceColor ?? undefined,\n customFields: (parsed as Record<string, unknown>).customFields,\n customValues: (parsed as Record<string, unknown>).customValues,\n },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'update',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n\n return withAdapterHeaders(NextResponse.json({ ok: true }))\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.put failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nexport async function DELETE(request: Request): Promise<Response> {\n try {\n const { commandContext, container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n const flags = await resolveCustomerInteractionFeatureFlags(container, auth.tenantId)\n if (!flags.legacyAdapters) {\n return await legacyAdaptersDisabledResponse()\n }\n const body = await readJsonSafe<Record<string, unknown>>(request, {})\n const parsed = activityDeleteBodySchema.parse(body)\n const guardUserId = resolveGuardUserId(auth)\n const guardResult = await validateCrudMutationGuard(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n mutationPayload: parsed,\n })\n if (guardResult && !guardResult.ok) {\n return withAdapterHeaders(NextResponse.json(guardResult.body, { status: guardResult.status }))\n }\n const commandBus = container.resolve('commandBus') as CommandBus\n const interactionId = flags.unified\n ? parsed.id\n : await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, auth.tenantId)\n await commandBus.execute('customers.interactions.delete', {\n input: { id: interactionId },\n ctx: commandContext,\n })\n if (guardResult?.ok && guardResult.shouldRunAfterSuccess) {\n await runCrudMutationGuardAfterSuccess(container, {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n userId: guardUserId,\n resourceKind: 'customers.activity',\n resourceId: parsed.id,\n operation: 'delete',\n requestMethod: request.method,\n requestHeaders: request.headers,\n metadata: guardResult.metadata ?? null,\n })\n }\n return withAdapterHeaders(NextResponse.json({ ok: true }))\n } catch (err) {\n if (isCrudHttpError(err)) {\n return withAdapterHeaders(NextResponse.json(err.body, { status: err.status }))\n }\n if (err instanceof z.ZodError) {\n return withAdapterHeaders(\n NextResponse.json({ error: 'Validation failed', details: err.issues }, { status: 400 }),\n )\n }\n console.error('customers.activities.delete failed', err)\n return withAdapterHeaders(\n NextResponse.json({ error: 'Internal server error' }, { status: 500 }),\n )\n }\n}\n\nconst activityListItemSchema = z\n .object({\n id: z.string().uuid(),\n activityType: z.string(),\n subject: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n entityId: z.string().uuid().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n activityTypeLabel: z.string().nullable().optional(),\n })\n .passthrough()\n\nconst activityCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = createCustomersCrudOpenApi({\n resourceName: 'Activity',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(activityListItemSchema),\n create: {\n schema: activityCreateBodySchema,\n responseSchema: activityCreateResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.',\n },\n update: {\n schema: activityUpdateBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.',\n },\n del: {\n schema: activityDeleteBodySchema,\n responseSchema: defaultOkResponseSchema,\n description: 'DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
3
+ import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
4
  import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
5
5
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
6
6
  import { User } from "@open-mercato/core/modules/auth/data/entities";
@@ -167,7 +167,7 @@ async function GET(request) {
167
167
  pageSize: query.pageSize
168
168
  });
169
169
  } catch (error) {
170
- if (error instanceof CrudHttpError) {
170
+ if (isCrudHttpError(error)) {
171
171
  return NextResponse.json(error.body, { status: error.status });
172
172
  }
173
173
  if (error instanceof z.ZodError) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/api/assignable-staff/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { StaffTeam, StaffTeamMember } from '@open-mercato/core/modules/staff/data/entities'\nimport { createPagedListResponseSchema } from '../openapi'\nimport { resolveAuthActorId, resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\n\nconst querySchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(24),\n search: z.string().optional(),\n })\n .passthrough()\n\nconst itemSchema = z.object({\n id: z.string().uuid(),\n teamMemberId: z.string().uuid(),\n userId: z.string().uuid(),\n displayName: z.string(),\n email: z.string().nullable().optional(),\n teamName: z.string().nullable().optional(),\n user: z\n .object({\n id: z.string().uuid(),\n email: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n team: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n})\n\nconst errorSchema = z.object({ error: z.string() })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.roles.view'] },\n}\n\nasync function canAccessAssignableStaff(\n rbac: RbacService | undefined,\n userId: string,\n scope: { tenantId: string; organizationId: string },\n): Promise<boolean> {\n if (!rbac) return false\n if (\n await rbac.userHasAllFeatures(userId, ['customers.roles.manage'], scope)\n ) {\n return true\n }\n return rbac.userHasAllFeatures(userId, ['customers.activities.manage'], scope)\n}\n\nexport async function GET(request: Request) {\n const { translate } = await resolveTranslations()\n try {\n const query = querySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n\n if (!selectedOrganizationId) {\n throw new CrudHttpError(\n 400,\n { error: translate('customers.errors.organization_required', 'Organization context is required') },\n )\n }\n\n const actorId = resolveAuthActorId(auth)\n const rbacService = container.resolve('rbacService') as RbacService | undefined\n const scope = { tenantId: auth.tenantId, organizationId: selectedOrganizationId }\n const hasAccess = await canAccessAssignableStaff(rbacService, actorId, scope)\n if (!hasAccess) {\n throw new CrudHttpError(\n 403,\n {\n error: translate(\n 'customers.assignableStaff.forbidden',\n 'Insufficient permissions to load assignable staff.',\n ),\n },\n )\n }\n\n const normalizedSearch = query.search?.trim().toLowerCase() ?? ''\n\n const members = await findWithDecryption(\n em,\n StaffTeamMember,\n {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n deletedAt: null,\n isActive: true,\n },\n { orderBy: { displayName: 'asc' } },\n scope,\n )\n\n const userIds = Array.from(\n new Set(\n members\n .map((member) => (typeof member.userId === 'string' && member.userId.trim().length > 0 ? member.userId : null))\n .filter((value): value is string => typeof value === 'string'),\n ),\n )\n const teamIds = Array.from(\n new Set(\n members\n .map((member) => (typeof member.teamId === 'string' && member.teamId.trim().length > 0 ? member.teamId : null))\n .filter((value): value is string => typeof value === 'string'),\n ),\n )\n\n const [users, teams] = await Promise.all([\n userIds.length > 0\n ? findWithDecryption(\n em,\n User,\n {\n id: { $in: userIds },\n deletedAt: null,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n },\n undefined,\n scope,\n )\n : Promise.resolve([]),\n teamIds.length > 0\n ? findWithDecryption(\n em,\n StaffTeam,\n {\n id: { $in: teamIds },\n deletedAt: null,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n },\n undefined,\n scope,\n )\n : Promise.resolve([]),\n ])\n\n const userById = new Map(\n users.map((user) => [\n user.id,\n {\n id: user.id,\n email: user.email ?? null,\n },\n ]),\n )\n const teamById = new Map(\n teams.map((team) => [\n team.id,\n {\n id: team.id,\n name: team.name ?? null,\n },\n ]),\n )\n\n const items = members\n .filter((member) => typeof member.userId === 'string' && member.userId.trim().length > 0)\n .map((member) => {\n const userId = member.userId as string\n const user = userById.get(userId) ?? { id: userId, email: null }\n const team = member.teamId ? teamById.get(member.teamId) ?? null : null\n return {\n id: member.id,\n teamMemberId: member.id,\n userId,\n displayName: member.displayName?.trim() || user.email || userId,\n email: user.email,\n teamName: team?.name ?? null,\n user,\n team,\n }\n })\n .filter((item) => {\n if (!normalizedSearch) return true\n const haystack = [item.displayName, item.email, item.teamName]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .join(' ')\n .toLowerCase()\n return haystack.includes(normalizedSearch)\n })\n\n const deduped = Array.from(\n items.reduce((acc, item) => {\n if (!acc.has(item.userId)) {\n acc.set(item.userId, item)\n }\n return acc\n }, new Map<string, (typeof items)[number]>()),\n ).map(([, item]) => item)\n\n const start = (query.page - 1) * query.pageSize\n return NextResponse.json({\n items: deduped.slice(start, start + query.pageSize),\n total: deduped.length,\n page: query.page,\n pageSize: query.pageSize,\n })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: translate('customers.errors.validationFailed', 'Validation failed') }, { status: 400 })\n }\n console.error('customers.assignable-staff.get failed', error)\n return NextResponse.json({ error: translate('customers.errors.assignable_staff_load_failed', 'Failed to load assignable staff') }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Assignable staff candidates',\n methods: {\n GET: {\n summary: 'List staff members that can be assigned from customer flows',\n query: querySchema,\n description:\n 'Returns active staff members linked to auth users. Access requires either customers.roles.manage or customers.activities.manage.',\n responses: [\n {\n status: 200,\n description: 'Assignable staff members',\n schema: createPagedListResponseSchema(itemSchema),\n },\n ],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 403, description: 'Forbidden', schema: errorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { StaffTeam, StaffTeamMember } from '@open-mercato/core/modules/staff/data/entities'\nimport { createPagedListResponseSchema } from '../openapi'\nimport { resolveAuthActorId, resolveCustomersRequestContext } from '../../lib/interactionRequestContext'\n\nconst querySchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(24),\n search: z.string().optional(),\n })\n .passthrough()\n\nconst itemSchema = z.object({\n id: z.string().uuid(),\n teamMemberId: z.string().uuid(),\n userId: z.string().uuid(),\n displayName: z.string(),\n email: z.string().nullable().optional(),\n teamName: z.string().nullable().optional(),\n user: z\n .object({\n id: z.string().uuid(),\n email: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n team: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n})\n\nconst errorSchema = z.object({ error: z.string() })\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.roles.view'] },\n}\n\nasync function canAccessAssignableStaff(\n rbac: RbacService | undefined,\n userId: string,\n scope: { tenantId: string; organizationId: string },\n): Promise<boolean> {\n if (!rbac) return false\n if (\n await rbac.userHasAllFeatures(userId, ['customers.roles.manage'], scope)\n ) {\n return true\n }\n return rbac.userHasAllFeatures(userId, ['customers.activities.manage'], scope)\n}\n\nexport async function GET(request: Request) {\n const { translate } = await resolveTranslations()\n try {\n const query = querySchema.parse(Object.fromEntries(new URL(request.url).searchParams))\n const { container, em, auth, selectedOrganizationId } = await resolveCustomersRequestContext(request)\n\n if (!selectedOrganizationId) {\n throw new CrudHttpError(\n 400,\n { error: translate('customers.errors.organization_required', 'Organization context is required') },\n )\n }\n\n const actorId = resolveAuthActorId(auth)\n const rbacService = container.resolve('rbacService') as RbacService | undefined\n const scope = { tenantId: auth.tenantId, organizationId: selectedOrganizationId }\n const hasAccess = await canAccessAssignableStaff(rbacService, actorId, scope)\n if (!hasAccess) {\n throw new CrudHttpError(\n 403,\n {\n error: translate(\n 'customers.assignableStaff.forbidden',\n 'Insufficient permissions to load assignable staff.',\n ),\n },\n )\n }\n\n const normalizedSearch = query.search?.trim().toLowerCase() ?? ''\n\n const members = await findWithDecryption(\n em,\n StaffTeamMember,\n {\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n deletedAt: null,\n isActive: true,\n },\n { orderBy: { displayName: 'asc' } },\n scope,\n )\n\n const userIds = Array.from(\n new Set(\n members\n .map((member) => (typeof member.userId === 'string' && member.userId.trim().length > 0 ? member.userId : null))\n .filter((value): value is string => typeof value === 'string'),\n ),\n )\n const teamIds = Array.from(\n new Set(\n members\n .map((member) => (typeof member.teamId === 'string' && member.teamId.trim().length > 0 ? member.teamId : null))\n .filter((value): value is string => typeof value === 'string'),\n ),\n )\n\n const [users, teams] = await Promise.all([\n userIds.length > 0\n ? findWithDecryption(\n em,\n User,\n {\n id: { $in: userIds },\n deletedAt: null,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n },\n undefined,\n scope,\n )\n : Promise.resolve([]),\n teamIds.length > 0\n ? findWithDecryption(\n em,\n StaffTeam,\n {\n id: { $in: teamIds },\n deletedAt: null,\n tenantId: auth.tenantId,\n organizationId: selectedOrganizationId,\n },\n undefined,\n scope,\n )\n : Promise.resolve([]),\n ])\n\n const userById = new Map(\n users.map((user) => [\n user.id,\n {\n id: user.id,\n email: user.email ?? null,\n },\n ]),\n )\n const teamById = new Map(\n teams.map((team) => [\n team.id,\n {\n id: team.id,\n name: team.name ?? null,\n },\n ]),\n )\n\n const items = members\n .filter((member) => typeof member.userId === 'string' && member.userId.trim().length > 0)\n .map((member) => {\n const userId = member.userId as string\n const user = userById.get(userId) ?? { id: userId, email: null }\n const team = member.teamId ? teamById.get(member.teamId) ?? null : null\n return {\n id: member.id,\n teamMemberId: member.id,\n userId,\n displayName: member.displayName?.trim() || user.email || userId,\n email: user.email,\n teamName: team?.name ?? null,\n user,\n team,\n }\n })\n .filter((item) => {\n if (!normalizedSearch) return true\n const haystack = [item.displayName, item.email, item.teamName]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .join(' ')\n .toLowerCase()\n return haystack.includes(normalizedSearch)\n })\n\n const deduped = Array.from(\n items.reduce((acc, item) => {\n if (!acc.has(item.userId)) {\n acc.set(item.userId, item)\n }\n return acc\n }, new Map<string, (typeof items)[number]>()),\n ).map(([, item]) => item)\n\n const start = (query.page - 1) * query.pageSize\n return NextResponse.json({\n items: deduped.slice(start, start + query.pageSize),\n total: deduped.length,\n page: query.page,\n pageSize: query.pageSize,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n if (error instanceof z.ZodError) {\n return NextResponse.json({ error: translate('customers.errors.validationFailed', 'Validation failed') }, { status: 400 })\n }\n console.error('customers.assignable-staff.get failed', error)\n return NextResponse.json({ error: translate('customers.errors.assignable_staff_load_failed', 'Failed to load assignable staff') }, { status: 500 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Assignable staff candidates',\n methods: {\n GET: {\n summary: 'List staff members that can be assigned from customer flows',\n query: querySchema,\n description:\n 'Returns active staff members linked to auth users. Access requires either customers.roles.manage or customers.activities.manage.',\n responses: [\n {\n status: 200,\n description: 'Assignable staff members',\n schema: createPagedListResponseSchema(itemSchema),\n },\n ],\n errors: [\n { status: 400, description: 'Invalid request', schema: errorSchema },\n { status: 401, description: 'Unauthorized', schema: errorSchema },\n { status: 403, description: 'Forbidden', schema: errorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
3
+ import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
4
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
5
5
  import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
6
6
  import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
@@ -158,7 +158,7 @@ async function GET(req, ctx) {
158
158
  totalPages
159
159
  });
160
160
  } catch (error) {
161
- if (error instanceof CrudHttpError) {
161
+ if (isCrudHttpError(error)) {
162
162
  return NextResponse.json(error.body, { status: error.status });
163
163
  }
164
164
  console.error("[customers.companies.people.GET]", error);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/api/companies/%5Bid%5D/people/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../../../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../../lib/personCompanyLinkTable'\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst querySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(20),\n search: z.string().optional(),\n sort: z.enum(['name-asc', 'name-desc', 'recent']).default('name-asc'),\n})\n\ntype CompanyPersonItem = {\n id: string\n displayName: string\n primaryEmail: string | null\n primaryPhone: string | null\n status: string | null\n lifecycleStage: string | null\n jobTitle: string | null\n department: string | null\n createdAt: string\n organizationId: string\n temperature: string | null\n source: string | null\n linkedAt: string | null\n}\n\nfunction matchesSearch(item: CompanyPersonItem, query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized.length) return true\n return [\n item.displayName,\n item.primaryEmail,\n item.primaryPhone,\n item.jobTitle,\n item.department,\n item.status,\n item.lifecycleStage,\n item.source,\n ]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .some((value) => value.toLowerCase().includes(normalized))\n}\n\nfunction sortItems(items: CompanyPersonItem[], sort: 'name-asc' | 'name-desc' | 'recent'): CompanyPersonItem[] {\n if (sort === 'recent') {\n return [...items].sort((left, right) => {\n const leftTimestamp = left.linkedAt ? new Date(left.linkedAt).getTime() : new Date(left.createdAt).getTime()\n const rightTimestamp = right.linkedAt ? new Date(right.linkedAt).getTime() : new Date(right.createdAt).getTime()\n if (leftTimestamp === rightTimestamp) return left.displayName.localeCompare(right.displayName)\n return rightTimestamp - leftTimestamp\n })\n }\n\n return [...items].sort((left, right) => {\n const compare = left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n return sort === 'name-asc' ? compare : -compare\n })\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nexport async function GET(req: Request, ctx: { params?: { id?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id } = paramsSchema.parse({ id: ctx.params?.id })\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) throw new CrudHttpError(401, { error: 'Unauthorized' })\n\n const query = querySchema.parse({\n page: new URL(req.url).searchParams.get('page') ?? undefined,\n pageSize: new URL(req.url).searchParams.get('pageSize') ?? undefined,\n search: new URL(req.url).searchParams.get('search') ?? undefined,\n sort: new URL(req.url).searchParams.get('sort') ?? undefined,\n })\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n const decryptionScope = {\n tenantId: auth.tenantId,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n }\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id, kind: 'company', tenantId: auth.tenantId, deletedAt: null },\n {},\n decryptionScope,\n )\n if (!company) {\n throw new CrudHttpError(404, { error: translate('customers.errors.company_not_found', 'Company not found') })\n }\n\n const allowedOrgIds = new Set<string>()\n if (scope?.filterIds?.length) scope.filterIds.forEach((entry) => allowedOrgIds.add(entry))\n else if (auth.orgId) allowedOrgIds.add(auth.orgId)\n if (allowedOrgIds.size > 0 && company.organizationId && !allowedOrgIds.has(company.organizationId)) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n\n const entityScope = { tenantId: auth.tenantId, organizationId: company.organizationId }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n 'customers.companies.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n entityScope,\n ),\n )\n\n const personIds = links\n .map((link) => link.person?.id)\n .filter((personId): personId is string => typeof personId === 'string' && personId.length > 0)\n\n const profiles = personIds.length > 0\n ? await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n entity: { $in: personIds },\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n entityScope,\n )\n : []\n const profileByPersonId = new Map(\n profiles.map((profile) => [(profile.entity as { id: string }).id, profile]),\n )\n\n const items = links\n .map((link) => {\n const person = link.person\n if (!person?.id) return null\n const profile = profileByPersonId.get(person.id) ?? null\n return {\n id: person.id,\n displayName: person.displayName ?? person.primaryEmail ?? person.id,\n primaryEmail: person.primaryEmail ?? null,\n primaryPhone: person.primaryPhone ?? null,\n status: person.status ?? null,\n lifecycleStage: person.lifecycleStage ?? null,\n jobTitle: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n createdAt: person.createdAt.toISOString(),\n organizationId: person.organizationId,\n temperature: person.temperature ?? null,\n source: person.source ?? null,\n linkedAt: link.createdAt ? link.createdAt.toISOString() : null,\n } satisfies CompanyPersonItem\n })\n .filter((item): item is CompanyPersonItem => item !== null)\n\n const filtered = query.search?.trim().length ? items.filter((item) => matchesSearch(item, query.search ?? '')) : items\n const sorted = sortItems(filtered, query.sort)\n const total = sorted.length\n const totalPages = Math.max(1, Math.ceil(total / query.pageSize))\n const page = Math.min(query.page, totalPages)\n const start = (page - 1) * query.pageSize\n\n return NextResponse.json({\n items: sorted.slice(start, start + query.pageSize),\n total,\n page,\n pageSize: query.pageSize,\n totalPages,\n })\n } catch (error) {\n if (error instanceof CrudHttpError) {\n return NextResponse.json(error.body, { status: error.status })\n }\n console.error('[customers.companies.people.GET]', error)\n return NextResponse.json({ error: translate('customers.errors.company_people_load_failed', 'Failed to load linked people') }, { status: 500 })\n }\n}\n\nconst companyPeopleItemSchema = z.object({\n id: z.string().uuid(),\n displayName: z.string(),\n primaryEmail: z.string().nullable(),\n primaryPhone: z.string().nullable(),\n status: z.string().nullable(),\n lifecycleStage: z.string().nullable(),\n jobTitle: z.string().nullable(),\n department: z.string().nullable(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable(),\n temperature: z.string().nullable(),\n source: z.string().nullable(),\n linkedAt: z.string().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n GET: {\n summary: 'List linked people for a company',\n query: querySchema,\n responses: [\n {\n status: 200,\n description: 'Paginated linked people',\n schema: z.object({\n items: z.array(companyPeopleItemSchema),\n total: z.number().int().nonnegative(),\n page: z.number().int().min(1),\n pageSize: z.number().int().min(1),\n totalPages: z.number().int().min(1),\n }),\n },\n ],\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAElB,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AACnD,SAAS,2BAA2B;AAEpC,SAAS,uBAAuB,0BAA0B;AAC1D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO,EAAE,KAAK;AACtB,CAAC;AAED,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,MAAM,EAAE,KAAK,CAAC,YAAY,aAAa,QAAQ,CAAC,EAAE,QAAQ,UAAU;AACtE,CAAC;AAkBD,SAAS,cAAc,MAAyB,OAAwB;AACtE,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,MAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,SAAO;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EACP,EACG,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,EAChF,KAAK,CAAC,UAAU,MAAM,YAAY,EAAE,SAAS,UAAU,CAAC;AAC7D;AAEA,SAAS,UAAU,OAA4B,MAAgE;AAC7G,MAAI,SAAS,UAAU;AACrB,WAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU;AACtC,YAAM,gBAAgB,KAAK,WAAW,IAAI,KAAK,KAAK,QAAQ,EAAE,QAAQ,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,QAAQ;AAC3G,YAAM,iBAAiB,MAAM,WAAW,IAAI,KAAK,MAAM,QAAQ,EAAE,QAAQ,IAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ;AAC/G,UAAI,kBAAkB,eAAgB,QAAO,KAAK,YAAY,cAAc,MAAM,WAAW;AAC7F,aAAO,iBAAiB;AAAA,IAC1B,CAAC;AAAA,EACH;AAEA,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU;AACtC,UAAM,UAAU,KAAK,YAAY,cAAc,MAAM,aAAa,QAAW,EAAE,aAAa,OAAO,CAAC;AACpG,WAAO,SAAS,aAAa,UAAU,CAAC;AAAA,EAC1C,CAAC;AACH;AAEO,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,0BAA0B,EAAE;AAC1E;AAEA,eAAsB,IAAI,KAAc,KAAmC;AACzE,QAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,MAAI;AACF,UAAM,EAAE,GAAG,IAAI,aAAa,MAAM,EAAE,IAAI,IAAI,QAAQ,GAAG,CAAC;AACxD,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,QAAI,CAAC,MAAM,SAAU,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,eAAe,CAAC;AAE3E,UAAM,QAAQ,YAAY,MAAM;AAAA,MAC9B,MAAM,IAAI,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,MAAM,KAAK;AAAA,MACnD,UAAU,IAAI,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,UAAU,KAAK;AAAA,MAC3D,QAAQ,IAAI,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,QAAQ,KAAK;AAAA,MACvD,MAAM,IAAI,IAAI,IAAI,GAAG,EAAE,aAAa,IAAI,MAAM,KAAK;AAAA,IACrD,CAAC;AAED,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,SAAS,IAAI,CAAC;AACxF,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC3D,UAAM,kBAAkB;AAAA,MACtB,UAAU,KAAK;AAAA,MACf,gBAAgB,OAAO,cAAc,KAAK,SAAS;AAAA,IACrD;AAEA,UAAM,UAAU,MAAM;AAAA,MACpB;AAAA,MACA;AAAA,MACA,EAAE,IAAI,MAAM,WAAW,UAAU,KAAK,UAAU,WAAW,KAAK;AAAA,MAChE,CAAC;AAAA,MACD;AAAA,IACF;AACA,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,sCAAsC,mBAAmB,EAAE,CAAC;AAAA,IAC9G;AAEA,UAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAI,OAAO,WAAW,OAAQ,OAAM,UAAU,QAAQ,CAAC,UAAU,cAAc,IAAI,KAAK,CAAC;AAAA,aAChF,KAAK,MAAO,eAAc,IAAI,KAAK,KAAK;AACjD,QAAI,cAAc,OAAO,KAAK,QAAQ,kBAAkB,CAAC,cAAc,IAAI,QAAQ,cAAc,GAAG;AAClG,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,kCAAkC,eAAe,EAAE,CAAC;AAAA,IACtG;AAEA,UAAM,cAAc,EAAE,UAAU,KAAK,UAAU,gBAAgB,QAAQ,eAAe;AACtF,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,QACE,SAAS,QAAQ;AAAA,QACjB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,MACZ,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,EAAE,UAAU,CAAC,QAAQ,EAAE;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,YAAY,MACf,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,EAC7B,OAAO,CAAC,aAAiC,OAAO,aAAa,YAAY,SAAS,SAAS,CAAC;AAE/F,UAAM,WAAW,UAAU,SAAS,IAChC,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,EAAE,KAAK,UAAU;AAAA,QACzB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,CAAC;AAAA,MACD;AAAA,IACF,IACA,CAAC;AACL,UAAM,oBAAoB,IAAI;AAAA,MAC5B,SAAS,IAAI,CAAC,YAAY,CAAE,QAAQ,OAA0B,IAAI,OAAO,CAAC;AAAA,IAC5E;AAEA,UAAM,QAAQ,MACX,IAAI,CAAC,SAAS;AACb,YAAM,SAAS,KAAK;AACpB,UAAI,CAAC,QAAQ,GAAI,QAAO;AACxB,YAAM,UAAU,kBAAkB,IAAI,OAAO,EAAE,KAAK;AACpD,aAAO;AAAA,QACL,IAAI,OAAO;AAAA,QACX,aAAa,OAAO,eAAe,OAAO,gBAAgB,OAAO;AAAA,QACjE,cAAc,OAAO,gBAAgB;AAAA,QACrC,cAAc,OAAO,gBAAgB;AAAA,QACrC,QAAQ,OAAO,UAAU;AAAA,QACzB,gBAAgB,OAAO,kBAAkB;AAAA,QACzC,UAAU,SAAS,YAAY;AAAA,QAC/B,YAAY,SAAS,cAAc;AAAA,QACnC,WAAW,OAAO,UAAU,YAAY;AAAA,QACxC,gBAAgB,OAAO;AAAA,QACvB,aAAa,OAAO,eAAe;AAAA,QACnC,QAAQ,OAAO,UAAU;AAAA,QACzB,UAAU,KAAK,YAAY,KAAK,UAAU,YAAY,IAAI;AAAA,MAC5D;AAAA,IACF,CAAC,EACA,OAAO,CAAC,SAAoC,SAAS,IAAI;AAE5D,UAAM,WAAW,MAAM,QAAQ,KAAK,EAAE,SAAS,MAAM,OAAO,CAAC,SAAS,cAAc,MAAM,MAAM,UAAU,EAAE,CAAC,IAAI;AACjH,UAAM,SAAS,UAAU,UAAU,MAAM,IAAI;AAC7C,UAAM,QAAQ,OAAO;AACrB,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,MAAM,QAAQ,CAAC;AAChE,UAAM,OAAO,KAAK,IAAI,MAAM,MAAM,UAAU;AAC5C,UAAM,SAAS,OAAO,KAAK,MAAM;AAEjC,WAAO,aAAa,KAAK;AAAA,MACvB,OAAO,OAAO,MAAM,OAAO,QAAQ,MAAM,QAAQ;AAAA,MACjD;AAAA,MACA;AAAA,MACA,UAAU,MAAM;AAAA,MAChB;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,QAAI,iBAAiB,eAAe;AAClC,aAAO,aAAa,KAAK,MAAM,MAAM,EAAE,QAAQ,MAAM,OAAO,CAAC;AAAA,IAC/D;AACA,YAAQ,MAAM,oCAAoC,KAAK;AACvD,WAAO,aAAa,KAAK,EAAE,OAAO,UAAU,+CAA+C,8BAA8B,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/I;AACF;AAEA,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,aAAa,EAAE,OAAO;AAAA,EACtB,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,WAAW,EAAE,OAAO;AAAA,EACpB,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC3C,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAEM,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,OAAO;AAAA,MACP,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO;AAAA,YACf,OAAO,EAAE,MAAM,uBAAuB;AAAA,YACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY;AAAA,YACpC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,YAC5B,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,YAChC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC;AAAA,UACpC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport {\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../../../data/entities'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../../lib/personCompanyLinkTable'\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst querySchema = z.object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(20),\n search: z.string().optional(),\n sort: z.enum(['name-asc', 'name-desc', 'recent']).default('name-asc'),\n})\n\ntype CompanyPersonItem = {\n id: string\n displayName: string\n primaryEmail: string | null\n primaryPhone: string | null\n status: string | null\n lifecycleStage: string | null\n jobTitle: string | null\n department: string | null\n createdAt: string\n organizationId: string\n temperature: string | null\n source: string | null\n linkedAt: string | null\n}\n\nfunction matchesSearch(item: CompanyPersonItem, query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized.length) return true\n return [\n item.displayName,\n item.primaryEmail,\n item.primaryPhone,\n item.jobTitle,\n item.department,\n item.status,\n item.lifecycleStage,\n item.source,\n ]\n .filter((value): value is string => typeof value === 'string' && value.length > 0)\n .some((value) => value.toLowerCase().includes(normalized))\n}\n\nfunction sortItems(items: CompanyPersonItem[], sort: 'name-asc' | 'name-desc' | 'recent'): CompanyPersonItem[] {\n if (sort === 'recent') {\n return [...items].sort((left, right) => {\n const leftTimestamp = left.linkedAt ? new Date(left.linkedAt).getTime() : new Date(left.createdAt).getTime()\n const rightTimestamp = right.linkedAt ? new Date(right.linkedAt).getTime() : new Date(right.createdAt).getTime()\n if (leftTimestamp === rightTimestamp) return left.displayName.localeCompare(right.displayName)\n return rightTimestamp - leftTimestamp\n })\n }\n\n return [...items].sort((left, right) => {\n const compare = left.displayName.localeCompare(right.displayName, undefined, { sensitivity: 'base' })\n return sort === 'name-asc' ? compare : -compare\n })\n}\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nexport async function GET(req: Request, ctx: { params?: { id?: string } }) {\n const { translate } = await resolveTranslations()\n try {\n const { id } = paramsSchema.parse({ id: ctx.params?.id })\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId) throw new CrudHttpError(401, { error: 'Unauthorized' })\n\n const query = querySchema.parse({\n page: new URL(req.url).searchParams.get('page') ?? undefined,\n pageSize: new URL(req.url).searchParams.get('pageSize') ?? undefined,\n search: new URL(req.url).searchParams.get('search') ?? undefined,\n sort: new URL(req.url).searchParams.get('sort') ?? undefined,\n })\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req })\n const em = (container.resolve('em') as EntityManager).fork()\n const decryptionScope = {\n tenantId: auth.tenantId,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n }\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n { id, kind: 'company', tenantId: auth.tenantId, deletedAt: null },\n {},\n decryptionScope,\n )\n if (!company) {\n throw new CrudHttpError(404, { error: translate('customers.errors.company_not_found', 'Company not found') })\n }\n\n const allowedOrgIds = new Set<string>()\n if (scope?.filterIds?.length) scope.filterIds.forEach((entry) => allowedOrgIds.add(entry))\n else if (auth.orgId) allowedOrgIds.add(auth.orgId)\n if (allowedOrgIds.size > 0 && company.organizationId && !allowedOrgIds.has(company.organizationId)) {\n throw new CrudHttpError(403, { error: translate('customers.errors.access_denied', 'Access denied') })\n }\n\n const entityScope = { tenantId: auth.tenantId, organizationId: company.organizationId }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n 'customers.companies.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n entityScope,\n ),\n )\n\n const personIds = links\n .map((link) => link.person?.id)\n .filter((personId): personId is string => typeof personId === 'string' && personId.length > 0)\n\n const profiles = personIds.length > 0\n ? await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n entity: { $in: personIds },\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n entityScope,\n )\n : []\n const profileByPersonId = new Map(\n profiles.map((profile) => [(profile.entity as { id: string }).id, profile]),\n )\n\n const items = links\n .map((link) => {\n const person = link.person\n if (!person?.id) return null\n const profile = profileByPersonId.get(person.id) ?? null\n return {\n id: person.id,\n displayName: person.displayName ?? person.primaryEmail ?? person.id,\n primaryEmail: person.primaryEmail ?? null,\n primaryPhone: person.primaryPhone ?? null,\n status: person.status ?? null,\n lifecycleStage: person.lifecycleStage ?? null,\n jobTitle: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n createdAt: person.createdAt.toISOString(),\n organizationId: person.organizationId,\n temperature: person.temperature ?? null,\n source: person.source ?? null,\n linkedAt: link.createdAt ? link.createdAt.toISOString() : null,\n } satisfies CompanyPersonItem\n })\n .filter((item): item is CompanyPersonItem => item !== null)\n\n const filtered = query.search?.trim().length ? items.filter((item) => matchesSearch(item, query.search ?? '')) : items\n const sorted = sortItems(filtered, query.sort)\n const total = sorted.length\n const totalPages = Math.max(1, Math.ceil(total / query.pageSize))\n const page = Math.min(query.page, totalPages)\n const start = (page - 1) * query.pageSize\n\n return NextResponse.json({\n items: sorted.slice(start, start + query.pageSize),\n total,\n page,\n pageSize: query.pageSize,\n totalPages,\n })\n } catch (error) {\n if (isCrudHttpError(error)) {\n return NextResponse.json(error.body, { status: error.status })\n }\n console.error('[customers.companies.people.GET]', error)\n return NextResponse.json({ error: translate('customers.errors.company_people_load_failed', 'Failed to load linked people') }, { status: 500 })\n }\n}\n\nconst companyPeopleItemSchema = z.object({\n id: z.string().uuid(),\n displayName: z.string(),\n primaryEmail: z.string().nullable(),\n primaryPhone: z.string().nullable(),\n status: z.string().nullable(),\n lifecycleStage: z.string().nullable(),\n jobTitle: z.string().nullable(),\n department: z.string().nullable(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable(),\n temperature: z.string().nullable(),\n source: z.string().nullable(),\n linkedAt: z.string().nullable(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n methods: {\n GET: {\n summary: 'List linked people for a company',\n query: querySchema,\n responses: [\n {\n status: 200,\n description: 'Paginated linked people',\n schema: z.object({\n items: z.array(companyPeopleItemSchema),\n total: z.number().int().nonnegative(),\n page: z.number().int().min(1),\n pageSize: z.number().int().min(1),\n totalPages: z.number().int().min(1),\n }),\n },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
3
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
4
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
+ import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
5
5
  import { resolveWidgetScope } from "../utils.js";
6
6
  import { resolveCustomerInteractionFeatureFlags } from "../../../../lib/interactionFeatureFlags.js";
7
7
  import { CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE } from "../../../../lib/interactionCompatibility.js";
@@ -110,7 +110,7 @@ async function GET(req) {
110
110
  });
111
111
  return NextResponse.json({ items });
112
112
  } catch (err) {
113
- if (err instanceof CrudHttpError) {
113
+ if (isCrudHttpError(err)) {
114
114
  return NextResponse.json(err.body, { status: err.status });
115
115
  }
116
116
  console.error("customers.widgets.todos failed", err);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/customers/api/dashboard/widgets/customer-todos/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveWidgetScope, type WidgetScopeContext } from '../utils'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../../lib/interactionFeatureFlags'\nimport { CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE } from '../../../../lib/interactionCompatibility'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n listLegacyTodoRows,\n listCanonicalTodoRows,\n sortTodoRows,\n type CustomerTodoRow,\n} from '../../../../lib/todoCompatibility'\n\nconst querySchema = z.object({\n limit: z.coerce.number().min(1).max(20).default(5),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['dashboards.view', 'customers.widgets.todos'] },\n}\n\ntype WidgetContext = WidgetScopeContext & { limit: number }\n\nasync function resolveContext(req: Request, translate: (key: string, fallback?: string) => string): Promise<WidgetContext> {\n const url = new URL(req.url)\n const rawQuery: Record<string, string> = {}\n for (const [key, value] of url.searchParams.entries()) {\n rawQuery[key] = value\n }\n const parsed = querySchema.safeParse(rawQuery)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: translate('customers.errors.invalid_query', 'Invalid query parameters') })\n }\n\n const { container, em, tenantId, organizationIds } = await resolveWidgetScope(req, translate, {\n tenantId: parsed.data.tenantId ?? null,\n organizationId: parsed.data.organizationId ?? null,\n })\n\n return {\n container,\n em,\n tenantId,\n organizationIds,\n limit: parsed.data.limit,\n }\n}\n\nexport async function GET(req: Request) {\n const { translate } = await resolveTranslations()\n try {\n const { container, em, tenantId, organizationIds, limit } = await resolveContext(req, translate)\n const auth = {\n tenantId,\n orgId: organizationIds?.[0] ?? null,\n sub: 'customers.dashboard.todos',\n }\n const flags = await resolveCustomerInteractionFeatureFlags(container, tenantId)\n const mergedWindow = Math.min(limit * 4, 50)\n const rows = flags.unified\n ? (await listCanonicalTodoRows(\n em,\n container,\n auth,\n organizationIds?.[0] ?? null,\n organizationIds ?? null,\n { pagination: { page: 1, pageSize: limit } },\n )).items\n : await Promise.all([\n listLegacyTodoRows(\n em,\n container.resolve('queryEngine') as QueryEngine,\n tenantId,\n organizationIds ?? null,\n undefined,\n { limit: mergedWindow },\n ),\n listCanonicalTodoRows(\n em,\n container,\n auth,\n organizationIds?.[0] ?? null,\n organizationIds ?? null,\n {\n includeDeleted: true,\n source: CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n limit: mergedWindow,\n },\n ),\n ]).then(([legacyRows, canonicalRows]) =>\n sortTodoRows([\n ...legacyRows.filter((row) => !canonicalRows.bridgeIds.has(row.todoId)),\n ...canonicalRows.items,\n ]),\n )\n\n const items = rows.slice(0, limit).map((row: CustomerTodoRow) => {\n const entity = row.customer ?? null\n return {\n id: row.id,\n todoId: row.todoId,\n todoSource: row.todoSource,\n todoTitle: row.todoTitle ?? null,\n createdAt: row.createdAt,\n organizationId: row.organizationId ?? null,\n _integrations: row._integrations ?? undefined,\n entity: entity?.id\n ? {\n id: entity.id,\n displayName: entity.displayName ?? null,\n kind: entity.kind ?? null,\n ownerUserId: null,\n }\n : {\n id: null,\n displayName: null,\n kind: null,\n ownerUserId: null,\n },\n }\n })\n\n return NextResponse.json({ items })\n } catch (err) {\n if (err instanceof CrudHttpError) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('customers.widgets.todos failed', err)\n return NextResponse.json(\n { error: translate('customers.widgets.todos.error', 'Failed to load customer tasks') },\n { status: 500 }\n )\n }\n}\n\nconst customerTodoWidgetItemSchema = z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n todoTitle: z.string().nullable().optional(),\n createdAt: z.string(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n organizationId: z.string().uuid().nullable().optional(),\n entity: z\n .object({\n id: z.string().uuid().nullable(),\n displayName: z.string().nullable(),\n kind: z.string().nullable(),\n ownerUserId: z.string().uuid().nullable().optional(),\n })\n .passthrough(),\n})\n\nconst customerTodoWidgetResponseSchema = z.object({\n items: z.array(customerTodoWidgetItemSchema),\n})\n\nconst widgetErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Customer todos widget',\n methods: {\n GET: {\n summary: 'Fetch recent customer tasks',\n description: 'Returns the most recent customer tasks for display on dashboards, including legacy compatibility rows when needed.',\n query: querySchema,\n responses: [\n { status: 200, description: 'Widget payload', schema: customerTodoWidgetResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid query parameters', schema: widgetErrorSchema },\n { status: 401, description: 'Unauthorized', schema: widgetErrorSchema },\n { status: 500, description: 'Widget failed to load', schema: widgetErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveWidgetScope, type WidgetScopeContext } from '../utils'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../../lib/interactionFeatureFlags'\nimport { CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE } from '../../../../lib/interactionCompatibility'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport {\n listLegacyTodoRows,\n listCanonicalTodoRows,\n sortTodoRows,\n type CustomerTodoRow,\n} from '../../../../lib/todoCompatibility'\n\nconst querySchema = z.object({\n limit: z.coerce.number().min(1).max(20).default(5),\n tenantId: z.string().uuid().optional(),\n organizationId: z.string().uuid().optional(),\n})\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['dashboards.view', 'customers.widgets.todos'] },\n}\n\ntype WidgetContext = WidgetScopeContext & { limit: number }\n\nasync function resolveContext(req: Request, translate: (key: string, fallback?: string) => string): Promise<WidgetContext> {\n const url = new URL(req.url)\n const rawQuery: Record<string, string> = {}\n for (const [key, value] of url.searchParams.entries()) {\n rawQuery[key] = value\n }\n const parsed = querySchema.safeParse(rawQuery)\n if (!parsed.success) {\n throw new CrudHttpError(400, { error: translate('customers.errors.invalid_query', 'Invalid query parameters') })\n }\n\n const { container, em, tenantId, organizationIds } = await resolveWidgetScope(req, translate, {\n tenantId: parsed.data.tenantId ?? null,\n organizationId: parsed.data.organizationId ?? null,\n })\n\n return {\n container,\n em,\n tenantId,\n organizationIds,\n limit: parsed.data.limit,\n }\n}\n\nexport async function GET(req: Request) {\n const { translate } = await resolveTranslations()\n try {\n const { container, em, tenantId, organizationIds, limit } = await resolveContext(req, translate)\n const auth = {\n tenantId,\n orgId: organizationIds?.[0] ?? null,\n sub: 'customers.dashboard.todos',\n }\n const flags = await resolveCustomerInteractionFeatureFlags(container, tenantId)\n const mergedWindow = Math.min(limit * 4, 50)\n const rows = flags.unified\n ? (await listCanonicalTodoRows(\n em,\n container,\n auth,\n organizationIds?.[0] ?? null,\n organizationIds ?? null,\n { pagination: { page: 1, pageSize: limit } },\n )).items\n : await Promise.all([\n listLegacyTodoRows(\n em,\n container.resolve('queryEngine') as QueryEngine,\n tenantId,\n organizationIds ?? null,\n undefined,\n { limit: mergedWindow },\n ),\n listCanonicalTodoRows(\n em,\n container,\n auth,\n organizationIds?.[0] ?? null,\n organizationIds ?? null,\n {\n includeDeleted: true,\n source: CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n limit: mergedWindow,\n },\n ),\n ]).then(([legacyRows, canonicalRows]) =>\n sortTodoRows([\n ...legacyRows.filter((row) => !canonicalRows.bridgeIds.has(row.todoId)),\n ...canonicalRows.items,\n ]),\n )\n\n const items = rows.slice(0, limit).map((row: CustomerTodoRow) => {\n const entity = row.customer ?? null\n return {\n id: row.id,\n todoId: row.todoId,\n todoSource: row.todoSource,\n todoTitle: row.todoTitle ?? null,\n createdAt: row.createdAt,\n organizationId: row.organizationId ?? null,\n _integrations: row._integrations ?? undefined,\n entity: entity?.id\n ? {\n id: entity.id,\n displayName: entity.displayName ?? null,\n kind: entity.kind ?? null,\n ownerUserId: null,\n }\n : {\n id: null,\n displayName: null,\n kind: null,\n ownerUserId: null,\n },\n }\n })\n\n return NextResponse.json({ items })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n console.error('customers.widgets.todos failed', err)\n return NextResponse.json(\n { error: translate('customers.widgets.todos.error', 'Failed to load customer tasks') },\n { status: 500 }\n )\n }\n}\n\nconst customerTodoWidgetItemSchema = z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n todoTitle: z.string().nullable().optional(),\n createdAt: z.string(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n organizationId: z.string().uuid().nullable().optional(),\n entity: z\n .object({\n id: z.string().uuid().nullable(),\n displayName: z.string().nullable(),\n kind: z.string().nullable(),\n ownerUserId: z.string().uuid().nullable().optional(),\n })\n .passthrough(),\n})\n\nconst customerTodoWidgetResponseSchema = z.object({\n items: z.array(customerTodoWidgetItemSchema),\n})\n\nconst widgetErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Customer todos widget',\n methods: {\n GET: {\n summary: 'Fetch recent customer tasks',\n description: 'Returns the most recent customer tasks for display on dashboards, including legacy compatibility rows when needed.',\n query: querySchema,\n responses: [\n { status: 200, description: 'Widget payload', schema: customerTodoWidgetResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid query parameters', schema: widgetErrorSchema },\n { status: 401, description: 'Unauthorized', schema: widgetErrorSchema },\n { status: 500, description: 'Widget failed to load', schema: widgetErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { z } from "zod";
3
3
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
4
- import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
4
+ import { CrudHttpError, isCrudHttpError } from "@open-mercato/shared/lib/crud/errors";
5
5
  import { CustomerEntity } from "../../../../data/entities.js";
6
6
  import { resolveWidgetScope } from "../utils.js";
7
7
  const querySchema = z.object({
@@ -62,7 +62,7 @@ async function GET(req) {
62
62
  }));
63
63
  return NextResponse.json({ items });
64
64
  } catch (err) {
65
- if (err instanceof CrudHttpError) {
65
+ if (isCrudHttpError(err)) {
66
66
  return NextResponse.json(err.body, { status: err.status });
67
67
  }
68
68
  console.error("customers.widgets.newCustomers failed", err);