@open-mercato/core 0.6.6-develop.6367.1.2321ccacd4 → 0.6.6-develop.6370.1.efeac59f8b

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.
@@ -1,4 +1,4 @@
1
- [build:core] found 3429 entry points
1
+ [build:core] found 3430 entry points
2
2
  [build:core] built successfully
3
3
  [build:core:generated] found 186 entry points
4
4
  [build:core:generated] built successfully
@@ -43,12 +43,58 @@ import {
43
43
  } from "../../../lib/personCompanyLinkTable.js";
44
44
  import { normalizeCustomerDetailCustomFields } from "../../detailCustomFields.js";
45
45
  import { isOrganizationReadAccessAllowed } from "@open-mercato/core/modules/directory/utils/organizationScopeGuard";
46
+ import { runWithCacheTenant } from "@open-mercato/cache";
47
+ import {
48
+ buildCollectionTags,
49
+ canonicalizeResourceTag,
50
+ isCrudCacheEnabled,
51
+ resolveCrudCache
52
+ } from "@open-mercato/shared/lib/crud/cache";
46
53
  const metadata = {
47
54
  GET: { requireAuth: true, requireFeatures: ["customers.companies.view"] }
48
55
  };
49
56
  const paramsSchema = z.object({
50
57
  id: z.string().uuid()
51
58
  });
59
+ const COMPANY_DETAIL_CACHE_TTL_MS = 6e4;
60
+ const COMPANY_DETAIL_CACHE_RESOURCE_KINDS = [
61
+ "customers.company",
62
+ "customers.address",
63
+ "customers.tagAssignment",
64
+ "customers.labelAssignment",
65
+ "customers.personCompanyLink",
66
+ "customers.interaction",
67
+ "customers.activity"
68
+ ];
69
+ function buildCompanyDetailCacheTags(tenantId, organizationId) {
70
+ const tags = /* @__PURE__ */ new Set();
71
+ for (const resourceKind of COMPANY_DETAIL_CACHE_RESOURCE_KINDS) {
72
+ const resource = canonicalizeResourceTag(resourceKind) ?? resourceKind;
73
+ for (const tag of buildCollectionTags(resource, tenantId, [organizationId])) {
74
+ tags.add(tag);
75
+ }
76
+ }
77
+ return Array.from(tags);
78
+ }
79
+ function buildCompanyDetailCacheKey(parts) {
80
+ const sortKeys = (values) => [...values].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
81
+ const filterIds = parts.filterIds ? sortKeys(parts.filterIds).join(",") : "all";
82
+ const allowedIds = parts.allowedIds ? sortKeys(parts.allowedIds).join(",") : "all";
83
+ const includeTokens = sortKeys(parts.includeTokens).join(",");
84
+ return [
85
+ "customers:companies:detail",
86
+ `tenant:${parts.tenantId ?? "null"}`,
87
+ `org:${parts.organizationId ?? "null"}`,
88
+ `company:${parts.companyId}`,
89
+ `selected:${parts.selectedOrganizationId ?? "null"}`,
90
+ `filter:${filterIds}`,
91
+ `allowed:${allowedIds}`,
92
+ `super:${parts.isSuperAdmin ? "1" : "0"}`,
93
+ `viewer:${parts.viewerUserId ?? "null"}`,
94
+ `mode:${parts.interactionMode}`,
95
+ `include:${includeTokens}`
96
+ ].join("|");
97
+ }
52
98
  function parseIncludeParams(request) {
53
99
  const url = new URL(request.url);
54
100
  const raw = url.searchParams.getAll("include");
@@ -335,6 +381,24 @@ async function GET(_req, ctx) {
335
381
  currentUserId: viewerUserId,
336
382
  userFeatures: void 0
337
383
  });
384
+ const cacheTenantId = companyScope.tenantId;
385
+ const cache = isCrudCacheEnabled() ? resolveCrudCache(container) : null;
386
+ const cacheKey = cache ? buildCompanyDetailCacheKey({
387
+ tenantId: cacheTenantId,
388
+ organizationId: companyScope.organizationId,
389
+ companyId: company.id,
390
+ selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,
391
+ filterIds: scope?.filterIds ?? null,
392
+ allowedIds: scope?.allowedIds ?? null,
393
+ isSuperAdmin: auth.isSuperAdmin === true,
394
+ viewerUserId,
395
+ interactionMode,
396
+ includeTokens: Array.from(includeTokens)
397
+ }) : null;
398
+ if (cache && cacheKey) {
399
+ const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey));
400
+ if (cached) return NextResponse.json(cached);
401
+ }
338
402
  const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos;
339
403
  const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([
340
404
  company.companyProfile ? findOneWithDecryption(
@@ -776,7 +840,7 @@ async function GET(_req, ctx) {
776
840
  people: peopleCount,
777
841
  addresses: addressesCount
778
842
  };
779
- return NextResponse.json({
843
+ const payload = {
780
844
  interactionMode,
781
845
  company: {
782
846
  id: company.id,
@@ -949,7 +1013,21 @@ async function GET(_req, ctx) {
949
1013
  name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,
950
1014
  email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null
951
1015
  }
952
- });
1016
+ };
1017
+ if (cache && cacheKey) {
1018
+ try {
1019
+ await runWithCacheTenant(
1020
+ cacheTenantId,
1021
+ () => cache.set(cacheKey, payload, {
1022
+ ttl: COMPANY_DETAIL_CACHE_TTL_MS,
1023
+ tags: buildCompanyDetailCacheTags(cacheTenantId, companyScope.organizationId)
1024
+ })
1025
+ );
1026
+ } catch (err) {
1027
+ console.warn("[customers:companies] Failed to set company detail cache", err);
1028
+ }
1029
+ }
1030
+ return NextResponse.json(payload);
953
1031
  }
954
1032
  const companyDetailQuerySchema = z.object({
955
1033
  include: z.string().optional().describe("Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people).")
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/api/companies/%5Bid%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\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 type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerTagAssignment,\n CustomerTag,\n CustomerLabelAssignment,\n CustomerLabel,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerTodoLink,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n CustomerInteraction,\n} from '../../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n resolveCompanyCustomFieldRouting,\n mergeCompanyCustomFieldValues,\n} from '../../../lib/customFieldRouting'\nimport {\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n EXAMPLE_TODO_SOURCE,\n CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n mapInteractionRecordToActivitySummary,\n mapInteractionRecordToTodoSummary,\n} from '../../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../lib/interactionFeatureFlags'\nimport { hydrateCanonicalInteractions } from '../../../lib/interactionReadModel'\nimport { buildEmailVisibilityMikroFilter } from '../../../lib/visibilityFilter'\nimport { resolveCustomerDetailTenantScope } from '../../../lib/detailTenantScope'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../lib/personCompanyLinkTable'\nimport { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nfunction parseIncludeParams(request: Request): Set<string> {\n const url = new URL(request.url)\n const raw = url.searchParams.getAll('include')\n const tokens = new Set<string>()\n raw.forEach((entry) => {\n if (!entry) return\n entry\n .split(',')\n .map((part) => part.trim().toLowerCase())\n .filter((part) => part.length > 0)\n .forEach((part) => tokens.add(part))\n })\n return tokens\n}\n\nfunction forbidden(message: string) {\n return NextResponse.json({ error: message }, { status: 403 })\n}\n\nfunction notFound(message: string) {\n return NextResponse.json({ error: message }, { status: 404 })\n}\n\nfunction serializeTags(assignments: CustomerTagAssignment[]): Array<{ id: string; label: string; color: string | null }> {\n return assignments\n .map((assignment) => {\n const tag = assignment.tag as CustomerTag | string | null\n if (!tag || typeof tag === 'string') return null\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n })\n .filter((tag): tag is { id: string; label: string; color: string | null } => tag !== null)\n}\n\ntype TodoDetail = {\n title: string | null\n isDone: boolean | null\n priority: number | null\n severity: string | null\n description: string | null\n dueAt: string | null\n organizationId: string | null\n customValues: Record<string, unknown> | null\n}\n\nfunction extractTodoTitle(record: Record<string, unknown>): string | null {\n const candidates = ['title', 'subject', 'name', 'summary', 'text', 'description']\n for (const key of candidates) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length > 0) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction parseNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = Number(trimmed)\n if (!Number.isNaN(parsed)) return parsed\n }\n return null\n}\n\nfunction parseDateValue(value: unknown): string | null {\n if (value instanceof Date) {\n const ts = value.getTime()\n return Number.isNaN(ts) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const candidate = new Date(trimmed)\n if (!Number.isNaN(candidate.getTime())) return candidate.toISOString()\n }\n return null\n}\n\nfunction readCustomField(record: Record<string, unknown>, key: string): unknown {\n const custom = record.custom ?? record.customFields ?? record.cf\n if (custom && typeof custom === 'object') {\n const bucket = custom as Record<string, unknown>\n if (key in bucket) return bucket[key]\n }\n return undefined\n}\n\ntype CompanyDetailKpiSummary = {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: { value: number; direction: 'up' | 'down' | 'unchanged' } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n}\n\nfunction parseDealAmount(value: string | number | null | undefined): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction computeActivityTrend(\n timestamps: string[],\n): { value: number; direction: 'up' | 'down' | 'unchanged' } | null {\n if (!timestamps.length) return null\n const now = Date.now()\n const weekMs = 7 * 86_400_000\n let thisWeek = 0\n let lastWeek = 0\n timestamps.forEach((value) => {\n const time = new Date(value).getTime()\n if (Number.isNaN(time)) return\n const diff = now - time\n if (diff < 0 || diff >= weekMs * 2) return\n if (diff < weekMs) {\n thisWeek += 1\n return\n }\n lastWeek += 1\n })\n if (lastWeek === 0 && thisWeek === 0) return null\n if (lastWeek === 0) return { value: 100, direction: 'up' }\n const pct = ((thisWeek - lastWeek) / lastWeek) * 100\n if (Math.abs(pct) < 0.5) return { value: 0, direction: 'unchanged' }\n return { value: Math.round(Math.abs(pct) * 100) / 100, direction: pct > 0 ? 'up' : 'down' }\n}\n\nasync function resolveTodoDetails(\n queryEngine: QueryEngine,\n links: CustomerTodoLink[],\n tenantId: string | null,\n organizationIds: Array<string | null>,\n): Promise<Map<string, TodoDetail>> {\n const details = new Map<string, TodoDetail>()\n if (!links.length || !tenantId) return details\n\n const scopedOrgIds = organizationIds\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n\n const idsBySource = new Map<string, Set<string>>()\n for (const link of links) {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const id = typeof link.todoId === 'string' && link.todoId.trim().length > 0 ? link.todoId : String(link.todoId ?? '')\n if (!id) continue\n if (!idsBySource.has(source)) idsBySource.set(source, new Set<string>())\n idsBySource.get(source)!.add(id)\n }\n\n for (const [source, idSet] of idsBySource.entries()) {\n const ids = Array.from(idSet)\n if (!ids.length) continue\n try {\n const result = await queryEngine.query<Record<string, unknown>>(source as EntityId, {\n tenantId,\n organizationIds: scopedOrgIds.length > 0 ? scopedOrgIds : undefined,\n filters: { id: { $in: ids } },\n includeCustomFields: ['priority', 'due_at', 'severity', 'description'],\n page: { page: 1, pageSize: Math.max(ids.length, 1) },\n })\n for (const item of result.items ?? []) {\n if (!item || typeof item !== 'object') continue\n const record = item as Record<string, unknown>\n const rawId = typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : String(record.id ?? '')\n if (!rawId) continue\n const title = extractTodoTitle(record)\n const isDone = (() => {\n const direct = parseBooleanFromUnknown(record.is_done)\n if (direct !== null) return direct\n const custom = parseBooleanFromUnknown(readCustomField(record, 'is_done'))\n if (custom !== null) return custom\n const generic = parseBooleanFromUnknown(record.isDone)\n if (generic !== null) return generic\n return parseBooleanFromUnknown(readCustomField(record, 'isDone'))\n })()\n const priority = (() => {\n const candidates = [\n record['cf:priority'],\n record['cf_priority'],\n record.priority,\n readCustomField(record, 'priority'),\n ]\n for (const candidate of candidates) {\n const parsed = parseNumber(candidate)\n if (parsed !== null) return parsed\n }\n return null\n })()\n const severity = (() => {\n const candidates = [\n record['cf:severity'],\n record['cf_severity'],\n record.severity,\n readCustomField(record, 'severity'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const dueAt = (() => {\n const candidates = [\n record['cf:due_at'],\n record['cf_due_at'],\n record.due_at,\n readCustomField(record, 'due_at'),\n record.dueAt,\n readCustomField(record, 'dueAt'),\n ]\n for (const candidate of candidates) {\n const parsed = parseDateValue(candidate)\n if (parsed) return parsed\n }\n return null\n })()\n const organizationId = (() => {\n const candidates = [\n record.organization_id,\n record['cf:organization_id'],\n record['cf_organization_id'],\n record.organizationId,\n readCustomField(record, 'organization_id'),\n readCustomField(record, 'organizationId'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const descriptionValue = (() => {\n const direct = typeof record.description === 'string' ? record.description : null\n if (direct) return direct\n const customDescription = readCustomField(record, 'description')\n if (typeof customDescription === 'string' && customDescription.trim().length > 0) {\n return customDescription.trim()\n }\n return null\n })()\n\n const customValues: Record<string, unknown> = {}\n const assignCustomValue = (key: string, value: unknown) => {\n const trimmedKey = key.trim()\n if (!trimmedKey.length) return\n customValues[trimmedKey] = value === undefined ? null : value\n }\n for (const [rawKey, rawValue] of Object.entries(record)) {\n if (rawKey.startsWith('cf:')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n } else if (rawKey.startsWith('cf_')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n }\n }\n const nestedCustom = record.custom ?? record.customFields ?? record.cf\n if (nestedCustom && typeof nestedCustom === 'object') {\n for (const [nestedKey, nestedValue] of Object.entries(nestedCustom as Record<string, unknown>)) {\n assignCustomValue(nestedKey, nestedValue)\n }\n }\n\n details.set(`${source}:${rawId}`, {\n title,\n isDone,\n priority,\n severity,\n description: descriptionValue,\n dueAt,\n organizationId,\n customValues: Object.keys(customValues).length ? customValues : null,\n })\n }\n } catch (err) {\n console.warn(`customers.companies.detail: failed to resolve todos for source ${source}`, err)\n }\n }\n\n return details\n}\n\nexport async function GET(_req: Request, ctx: { params?: { id?: string } }) {\n const auth = await getAuthFromRequest(_req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const parse = paramsSchema.safeParse({ id: ctx.params?.id })\n if (!parse.success) return NextResponse.json({ error: 'Invalid company id' }, { status: 400 })\n\n const includeTokens = parseIncludeParams(_req)\n const includeActivities = includeTokens.has('activities')\n const includeAddresses = includeTokens.has('addresses')\n const includeComments = includeTokens.has('comments') || includeTokens.has('notes')\n const includeDeals = includeTokens.has('deals')\n const includeInteractions = includeTokens.has('interactions')\n const includeTodos = includeTokens.has('todos') || includeTokens.has('tasks')\n const includePeople = includeTokens.has('people')\n const plannedPreviewLimit = 5\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: _req })\n const em = (container.resolve('em') as EntityManager)\n const interactionFlags = await resolveCustomerInteractionFeatureFlags(container, scope?.tenantId ?? auth.tenantId)\n const interactionMode = interactionFlags.unified ? 'canonical' : 'legacy'\n\n const tenantScope = resolveCustomerDetailTenantScope(parse.data.id, 'company', auth)\n if (!tenantScope.allowed) return notFound('Company not found')\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n tenantScope.where,\n { populate: ['companyProfile'] },\n {\n tenantId: auth.tenantId ?? null,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n },\n )\n if (!company) return notFound('Company not found')\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: company.organizationId })) {\n return forbidden('Access denied')\n }\n\n const companyScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n\n // Per-user email privacy (CRM email integration): exclude private email\n // interactions owned by other users from every read path that returns\n // customer_interactions. Non-email rows, shared emails, and legacy\n // null-visibility rows pass through. v1 is strict owner-only: there is NO\n // admin bypass \u2014 the filter ignores caller features, and\n // `customers.email.view_private` is reserved (inert) for v2 oversight.\n // Mirrors the people detail route. API-key callers resolve to null\n // (no author match \u2014 shared/non-email rows only).\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n const emailVisibilityFilter = buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures: undefined,\n })\n\n const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos\n\n // These reads only depend on the resolved company + scope + email visibility\n // filter, so dispatch them together to avoid a server-side request waterfall\n // before the detail surface can render (issue #3203).\n const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([\n company.companyProfile\n ? findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n id: company.companyProfile.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n )\n : findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n entity: company,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n ),\n includeAddresses\n ? findWithDecryption(\n em,\n CustomerAddress,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },\n companyScope,\n )\n : Promise.resolve<CustomerAddress[]>([]),\n findWithDecryption(\n em,\n CustomerTagAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['tag'] },\n companyScope,\n ),\n findWithDecryption(\n em,\n CustomerLabelAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['label'] },\n companyScope,\n ),\n includeComments\n ? findWithDecryption(\n em,\n CustomerComment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : Promise.resolve<CustomerComment[]>([]),\n shouldLoadCanonicalInteractions\n ? findWithDecryption(\n em,\n CustomerInteraction,\n interactionFlags.unified\n ? {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }\n : {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },\n companyScope,\n )\n : Promise.resolve<CustomerInteraction[]>([]),\n ])\n const canonicalActiveInteractions = canonicalInteractionRows.filter((interaction) => !interaction.deletedAt)\n const canonicalInteractions = shouldLoadCanonicalInteractions\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: canonicalActiveInteractions,\n enrich: includeInteractions,\n })\n : []\n\n const plannedPreviewRows =\n canonicalActiveInteractions.length > 0\n ? canonicalActiveInteractions\n .filter((interaction) => interaction.status === 'planned' && interaction.interactionType !== 'task')\n .sort((left, right) => {\n const leftTime = new Date(left.scheduledAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.scheduledAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return left.id.localeCompare(right.id)\n return leftTime - rightTime\n })\n .slice(0, plannedPreviewLimit)\n : await findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n status: 'planned',\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'ASC', createdAt: 'ASC' }, limit: plannedPreviewLimit },\n companyScope,\n )\n const plannedActivitiesPreview = plannedPreviewRows.length\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: plannedPreviewRows,\n enrich: true,\n })\n : []\n\n const activities = includeActivities && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerActivity,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n const todoLinks = includeTodos && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerTodoLink,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n\n let todoDetails = new Map<string, TodoDetail>()\n if (includeTodos && !interactionFlags.unified && todoLinks.length) {\n const queryEngine = (container.resolve('queryEngine') as QueryEngine)\n try {\n todoDetails = await resolveTodoDetails(\n queryEngine,\n todoLinks,\n company.tenantId ?? auth.tenantId ?? null,\n [company.organizationId ?? null, ...(scope?.filterIds ?? [])],\n )\n } catch (err) {\n console.warn('customers.companies.detail: failed to enrich todo links', err)\n }\n }\n\n const canonicalActivityBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n const canonicalTodoBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n\n const canonicalActivityItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType !== 'task')\n .map((interaction) => mapInteractionRecordToActivitySummary(interaction))\n const canonicalTodoItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType === 'task')\n .map((interaction) => mapInteractionRecordToTodoSummary(interaction))\n\n const authorIds = new Set<string>()\n if (includeActivities) {\n for (const activity of activities) {\n if (activity.authorUserId) authorIds.add(activity.authorUserId)\n }\n }\n if (includeComments) {\n for (const comment of comments) {\n if (comment.authorUserId) authorIds.add(comment.authorUserId)\n }\n }\n if (viewerUserId) authorIds.add(viewerUserId)\n\n let userMap = new Map<string, { name: string | null; email: string | null }>()\n if (authorIds.size) {\n const authorIdList = Array.from(authorIds)\n const users = await findWithDecryption(\n em,\n User,\n {\n id: { $in: authorIdList },\n tenantId: company.tenantId,\n },\n {},\n companyScope,\n )\n 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 }\n\n let deals: CustomerDeal[] = []\n if (includeDeals) {\n const dealLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n deals = dealLinks\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n }\n\n const dealLinksForMetrics = includeDeals\n ? deals\n : (\n await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n )\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n\n let relatedPeople: Array<{\n entity: CustomerEntity\n profile: CustomerPersonProfile | null\n linkedAt: string | null\n }> = []\n if (includePeople) {\n const peopleDecryptionScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n const relatedPeopleById = new Map<\n string,\n { entity: CustomerEntity; profile: CustomerPersonProfile | null; linkedAt: string | null }\n >()\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyLinkWhere,\n {\n populate: ['person', 'person.personProfile'],\n orderBy: { isPrimary: 'desc', createdAt: 'asc' },\n },\n peopleDecryptionScope,\n ),\n )\n companyLinks.forEach((link) => {\n const entity = typeof link.person === 'string' ? null : link.person\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n const personProfile =\n entity.personProfile && typeof entity.personProfile !== 'string'\n ? entity.personProfile\n : null\n relatedPeopleById.set(entity.id, {\n entity,\n profile: personProfile,\n linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null,\n })\n })\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { deletedAt: null },\n },\n { populate: ['entity'] },\n peopleDecryptionScope,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | null\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n if (!relatedPeopleById.has(entity.id)) {\n relatedPeopleById.set(entity.id, {\n entity,\n profile: entry ?? null,\n linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null,\n })\n }\n })\n relatedPeople = Array.from(relatedPeopleById.values())\n }\n\n // Entity custom fields, profile custom fields, and the routing lookup do not\n // depend on each other (profileId is already resolved above), so load them in\n // parallel instead of three sequential awaits (issue #3203).\n const profileId = profile?.id ?? null\n const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([\n loadCustomFieldValues({\n em,\n entityId: E.customers.customer_entity,\n recordIds: [company.id],\n tenantIdByRecord: { [company.id]: company.tenantId ?? null },\n organizationIdByRecord: { [company.id]: company.organizationId ?? null },\n tenantFallbacks: [\n company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n }),\n profileId\n ? loadCustomFieldValues({\n em,\n entityId: E.customers.customer_company_profile,\n recordIds: [profileId],\n tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },\n organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },\n tenantFallbacks: [\n profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null),\n ])\n const customFields = normalizeCustomerDetailCustomFields(\n mergeCompanyCustomFieldValues(\n routing,\n entityCustomFieldValues?.[company.id] ?? {},\n profileId ? profileCustomFieldValues?.[profileId] ?? {} : {},\n ),\n )\n\n // The count queries, related-people fallback, and KPI interaction fallback are\n // all independent of each other; dispatch them together rather than awaiting\n // each inline so the response counts/KPIs are assembled in one parallel round\n // instead of a waterfall (issue #3203).\n const peopleCountQuery = includePeople\n ? Promise.resolve(relatedPeople.length)\n : (async () => {\n const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n peopleLinkWhere,\n {},\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ).length\n })()\n const [\n activityCount,\n interactionCount,\n todoCount,\n commentsCount,\n addressesCount,\n peopleCount,\n kpiInteractionRows,\n ] = await Promise.all([\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n }),\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }),\n interactionFlags.unified\n ? em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: 'task',\n })\n : em.count(CustomerTodoLink, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeComments\n ? Promise.resolve(comments.length)\n : em.count(CustomerComment, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeAddresses\n ? Promise.resolve(addresses.length)\n : em.count(CustomerAddress, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n peopleCountQuery,\n canonicalActiveInteractions.length\n ? Promise.resolve(canonicalActiveInteractions)\n : findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n },\n {\n fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],\n orderBy: { createdAt: 'DESC' },\n },\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ])\n const activityTrend = computeActivityTrend(\n kpiInteractionRows\n .map((interaction) => interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt)\n .map((value) => (value instanceof Date ? value.toISOString() : typeof value === 'string' ? value : ''))\n .filter((value) => value.length > 0),\n )\n const activeDeals = dealLinksForMetrics.filter(\n (deal) => deal.status !== 'won' && deal.status !== 'lost' && deal.status !== 'closed',\n )\n const wonDeals = dealLinksForMetrics.filter((deal) => deal.status === 'won')\n const activeDealsValue = activeDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n const ltvValue = wonDeals.length\n ? wonDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n : null\n const earliestInteractionTime = kpiInteractionRows.reduce<number | null>((earliest, interaction) => {\n const candidate = interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt\n const time = candidate instanceof Date ? candidate.getTime() : new Date(candidate).getTime()\n if (Number.isNaN(time)) return earliest\n if (earliest === null) return time\n return Math.min(earliest, time)\n }, null)\n const companyKpis: CompanyDetailKpiSummary = {\n activeDealsCount: activeDeals.length,\n activeDealsValue: activeDeals.length ? activeDealsValue : null,\n dealCurrency:\n activeDeals[0]?.valueCurrency ??\n dealLinksForMetrics[0]?.valueCurrency ??\n null,\n activityCount,\n activityTrend,\n ltvValue,\n completedDealsCount: wonDeals.length,\n clientTenureYears:\n earliestInteractionTime === null\n ? null\n : Math.floor((Date.now() - earliestInteractionTime) / (365.25 * 86_400_000)),\n }\n const counts = {\n tags: tagAssignments.length + labelAssignments.length,\n comments: commentsCount,\n activities: activityCount,\n interactions: interactionCount,\n todos: todoCount,\n deals: includeDeals ? deals.length : dealLinksForMetrics.length,\n people: peopleCount,\n addresses: addressesCount,\n }\n\n return NextResponse.json({\n interactionMode,\n company: {\n id: company.id,\n displayName: company.displayName,\n description: company.description,\n ownerUserId: company.ownerUserId,\n primaryEmail: company.primaryEmail,\n primaryPhone: company.primaryPhone,\n status: company.status,\n lifecycleStage: company.lifecycleStage,\n source: company.source,\n nextInteractionAt: company.nextInteractionAt ? company.nextInteractionAt.toISOString() : null,\n nextInteractionName: company.nextInteractionName,\n nextInteractionRefId: company.nextInteractionRefId,\n nextInteractionIcon: company.nextInteractionIcon,\n nextInteractionColor: company.nextInteractionColor,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n isActive: company.isActive,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n createdAt: company.createdAt.toISOString(),\n updatedAt: company.updatedAt.toISOString(),\n },\n profile: profile\n ? {\n id: profile.id,\n legalName: profile.legalName,\n brandName: profile.brandName,\n domain: profile.domain,\n websiteUrl: profile.websiteUrl,\n industry: profile.industry,\n sizeBucket: profile.sizeBucket,\n annualRevenue: profile.annualRevenue,\n }\n : null,\n customFields,\n tags: [\n ...serializeTags(tagAssignments),\n ...labelAssignments\n .map((assignment) => {\n const label = assignment.label as CustomerLabel | string | null\n if (!label || typeof label === 'string') return null\n return { id: label.id, label: label.label, color: null }\n })\n .filter((tag): tag is { id: string; label: string; color: null } => tag !== null),\n ],\n addresses: includeAddresses\n ? addresses.map((address) => ({\n id: address.id,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\n buildingNumber: address.buildingNumber,\n flatNumber: address.flatNumber,\n city: address.city,\n region: address.region,\n postalCode: address.postalCode,\n country: address.country,\n latitude: address.latitude,\n longitude: address.longitude,\n isPrimary: address.isPrimary,\n createdAt: address.createdAt.toISOString(),\n }))\n : [],\n comments: includeComments\n ? comments.map((comment) => {\n const authorInfo = comment.authorUserId ? userMap.get(comment.authorUserId) : null\n return {\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId,\n authorName: comment.authorUserId ? authorInfo?.name ?? null : null,\n authorEmail: comment.authorUserId ? authorInfo?.email ?? null : null,\n dealId: comment.deal ? (typeof comment.deal === 'string' ? comment.deal : comment.deal.id) : null,\n createdAt: comment.createdAt.toISOString(),\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n }\n })\n : [],\n activities: includeActivities\n ? (\n interactionFlags.unified\n ? canonicalActivityItems\n : [\n ...activities\n .filter((activity) => !canonicalActivityBridgeIds.has(activity.id))\n .map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n authorUserId: activity.authorUserId,\n authorName: activity.authorUserId ? userMap.get(activity.authorUserId)?.name ?? null : null,\n authorEmail: activity.authorUserId ? userMap.get(activity.authorUserId)?.email ?? null : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n })),\n ...canonicalActivityItems.filter(\n (activity) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === activity.id &&\n interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.occurredAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.occurredAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n interactions: includeInteractions\n ? canonicalInteractions\n : [],\n deals: includeDeals\n ? deals.map((deal) => ({\n id: deal.id,\n title: deal.title,\n status: deal.status,\n pipelineStage: deal.pipelineStage,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount,\n valueCurrency: deal.valueCurrency,\n probability: deal.probability,\n expectedCloseAt: deal.expectedCloseAt ? deal.expectedCloseAt.toISOString() : null,\n ownerUserId: deal.ownerUserId,\n source: deal.source,\n createdAt: deal.createdAt.toISOString(),\n updatedAt: deal.updatedAt.toISOString(),\n }))\n : [],\n todos: includeTodos\n ? (\n interactionFlags.unified\n ? canonicalTodoItems\n : [\n ...todoLinks\n .filter((link) => !canonicalTodoBridgeIds.has(link.todoId))\n .map((link) => {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const key = `${source}:${link.todoId}`\n const detail = todoDetails.get(key)\n return {\n id: link.id,\n todoId: link.todoId,\n todoSource: source,\n createdAt: link.createdAt.toISOString(),\n createdByUserId: link.createdByUserId,\n title: detail?.title ?? null,\n isDone: detail?.isDone ?? null,\n priority: detail?.priority ?? null,\n severity: detail?.severity ?? null,\n description: detail?.description ?? null,\n dueAt: detail?.dueAt ?? null,\n todoOrganizationId: detail?.organizationId ?? null,\n customValues: detail?.customValues ?? null,\n }\n }),\n ...canonicalTodoItems.filter(\n (todo) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === todo.todoId &&\n interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.createdAt).getTime()\n const rightTime = new Date(right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n people: includePeople\n ? relatedPeople.map(({ entity, profile: personProfile, linkedAt }) => ({\n id: entity.id,\n displayName: entity.displayName,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n jobTitle: personProfile?.jobTitle ?? null,\n department: personProfile?.department ?? null,\n createdAt: entity.createdAt.toISOString(),\n organizationId: entity.organizationId,\n source: entity.source ?? null,\n temperature: entity.temperature ?? null,\n linkedAt,\n }))\n : [],\n plannedActivitiesPreview,\n counts,\n kpis: companyKpis,\n viewer: {\n userId: viewerUserId,\n name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,\n email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null,\n },\n })\n}\n\nconst companyDetailQuerySchema = z.object({\n include: z\n .string()\n .optional()\n .describe('Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people).'),\n}).passthrough()\n\nconst companyDetailResponseSchema = z.object({\n interactionMode: z.enum(['canonical', 'legacy']),\n company: z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n nextInteractionAt: z.string().nullable().optional(),\n nextInteractionName: z.string().nullable().optional(),\n nextInteractionRefId: z.string().nullable().optional(),\n nextInteractionIcon: z.string().nullable().optional(),\n nextInteractionColor: z.string().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n isActive: z.boolean().optional(),\n temperature: z.string().nullable().optional(),\n renewalQuarter: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n profile: z\n .object({\n id: z.string().uuid(),\n legalName: z.string().nullable().optional(),\n brandName: z.string().nullable().optional(),\n domain: z.string().nullable().optional(),\n websiteUrl: z.string().nullable().optional(),\n industry: z.string().nullable().optional(),\n sizeBucket: z.string().nullable().optional(),\n annualRevenue: z.number().nullable().optional(),\n })\n .nullable(),\n customFields: z.record(z.string(), z.unknown()),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable().optional(),\n }),\n ),\n addresses: z.array(\n z.object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n purpose: z.string().nullable().optional(),\n addressLine1: z.string().nullable().optional(),\n addressLine2: z.string().nullable().optional(),\n buildingNumber: z.string().nullable().optional(),\n flatNumber: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n region: z.string().nullable().optional(),\n postalCode: z.string().nullable().optional(),\n country: z.string().nullable().optional(),\n latitude: z.number().nullable().optional(),\n longitude: z.number().nullable().optional(),\n isPrimary: z.boolean().nullable().optional(),\n createdAt: z.string(),\n }),\n ),\n comments: z.array(\n z.object({\n id: z.string().uuid(),\n body: z.string().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 createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n activities: z.array(\n z.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 dealId: 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 createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n interactions: z.array(\n z.object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable().optional(),\n interactionType: z.string(),\n title: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n status: z.string(),\n scheduledAt: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n priority: z.number().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n deals: z.array(\n z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n pipelineStage: z.string().nullable().optional(),\n valueAmount: z.number().nullable().optional(),\n valueCurrency: z.string().nullable().optional(),\n probability: z.number().nullable().optional(),\n expectedCloseAt: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n todos: z.array(\n z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n createdAt: z.string(),\n createdByUserId: z.string().uuid().nullable().optional(),\n title: z.string().nullable().optional(),\n isDone: z.boolean().nullable().optional(),\n priority: z.number().nullable().optional(),\n severity: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n dueAt: z.string().nullable().optional(),\n todoOrganizationId: z.string().uuid().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n }),\n ),\n people: z.array(\n z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n jobTitle: z.string().nullable().optional(),\n department: z.string().nullable().optional(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n temperature: z.string().nullable().optional(),\n linkedAt: z.string().nullable().optional(),\n }),\n ),\n viewer: z.object({\n userId: z.string().uuid().nullable(),\n name: z.string().nullable(),\n email: z.string().nullable(),\n }),\n})\n\nconst companyDetailErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Fetch company detail',\n methods: {\n GET: {\n summary: 'Fetch company with related data',\n description: 'Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.',\n query: companyDetailQuerySchema,\n responses: [\n { status: 200, description: 'Company detail payload', schema: companyDetailResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: companyDetailErrorSchema },\n { status: 401, description: 'Unauthorized', schema: companyDetailErrorSchema },\n { status: 403, description: 'Forbidden for tenant/organization scope', schema: companyDetailErrorSchema },\n { status: 404, description: 'Company not found', schema: companyDetailErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\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 type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerEntity,\n CustomerCompanyProfile,\n CustomerAddress,\n CustomerComment,\n CustomerActivity,\n CustomerTagAssignment,\n CustomerTag,\n CustomerLabelAssignment,\n CustomerLabel,\n CustomerDealCompanyLink,\n CustomerDeal,\n CustomerTodoLink,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n CustomerInteraction,\n} from '../../../data/entities'\nimport { User } from '@open-mercato/core/modules/auth/data/entities'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n resolveCompanyCustomFieldRouting,\n mergeCompanyCustomFieldValues,\n} from '../../../lib/customFieldRouting'\nimport {\n CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n EXAMPLE_TODO_SOURCE,\n CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n mapInteractionRecordToActivitySummary,\n mapInteractionRecordToTodoSummary,\n} from '../../../lib/interactionCompatibility'\nimport { resolveCustomerInteractionFeatureFlags } from '../../../lib/interactionFeatureFlags'\nimport { hydrateCanonicalInteractions } from '../../../lib/interactionReadModel'\nimport { buildEmailVisibilityMikroFilter } from '../../../lib/visibilityFilter'\nimport { resolveCustomerDetailTenantScope } from '../../../lib/detailTenantScope'\nimport type { QueryEngine } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanFromUnknown } from '@open-mercato/shared/lib/boolean'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../../lib/personCompanyLinkTable'\nimport { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'\nimport { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'\nimport { runWithCacheTenant } from '@open-mercato/cache'\nimport {\n buildCollectionTags,\n canonicalizeResourceTag,\n isCrudCacheEnabled,\n resolveCrudCache,\n} from '@open-mercato/shared/lib/crud/cache'\n\nexport const metadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },\n}\n\nconst paramsSchema = z.object({\n id: z.string().uuid(),\n})\n\nconst COMPANY_DETAIL_CACHE_TTL_MS = 60_000\n\n// The customers write commands already invalidate these resource collections via\n// invalidateCrudCache using these exact resourceKind strings. Reusing them as\n// cache tags means the cached detail is flushed by those existing commands with\n// no new wiring (#3664, mirroring #3143). Canonicalize each kind the same way\n// invalidateCrudCache does (camelCase split + lowercase) so the tag shapes match.\nconst COMPANY_DETAIL_CACHE_RESOURCE_KINDS = [\n 'customers.company',\n 'customers.address',\n 'customers.tagAssignment',\n 'customers.labelAssignment',\n 'customers.personCompanyLink',\n 'customers.interaction',\n 'customers.activity',\n] as const\n\nfunction buildCompanyDetailCacheTags(tenantId: string | null, organizationId: string | null): string[] {\n const tags = new Set<string>()\n for (const resourceKind of COMPANY_DETAIL_CACHE_RESOURCE_KINDS) {\n const resource = canonicalizeResourceTag(resourceKind) ?? resourceKind\n for (const tag of buildCollectionTags(resource, tenantId, [organizationId])) {\n tags.add(tag)\n }\n }\n return Array.from(tags)\n}\n\nfunction buildCompanyDetailCacheKey(parts: {\n tenantId: string | null\n organizationId: string | null\n companyId: string\n selectedOrganizationId: string | null\n filterIds: string[] | null\n allowedIds: string[] | null\n isSuperAdmin: boolean\n viewerUserId: string | null\n interactionMode: string\n includeTokens: string[]\n}): string {\n const sortKeys = (values: string[]): string[] =>\n [...values].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))\n const filterIds = parts.filterIds ? sortKeys(parts.filterIds).join(',') : 'all'\n const allowedIds = parts.allowedIds ? sortKeys(parts.allowedIds).join(',') : 'all'\n const includeTokens = sortKeys(parts.includeTokens).join(',')\n return [\n 'customers:companies:detail',\n `tenant:${parts.tenantId ?? 'null'}`,\n `org:${parts.organizationId ?? 'null'}`,\n `company:${parts.companyId}`,\n `selected:${parts.selectedOrganizationId ?? 'null'}`,\n `filter:${filterIds}`,\n `allowed:${allowedIds}`,\n `super:${parts.isSuperAdmin ? '1' : '0'}`,\n `viewer:${parts.viewerUserId ?? 'null'}`,\n `mode:${parts.interactionMode}`,\n `include:${includeTokens}`,\n ].join('|')\n}\n\nfunction parseIncludeParams(request: Request): Set<string> {\n const url = new URL(request.url)\n const raw = url.searchParams.getAll('include')\n const tokens = new Set<string>()\n raw.forEach((entry) => {\n if (!entry) return\n entry\n .split(',')\n .map((part) => part.trim().toLowerCase())\n .filter((part) => part.length > 0)\n .forEach((part) => tokens.add(part))\n })\n return tokens\n}\n\nfunction forbidden(message: string) {\n return NextResponse.json({ error: message }, { status: 403 })\n}\n\nfunction notFound(message: string) {\n return NextResponse.json({ error: message }, { status: 404 })\n}\n\nfunction serializeTags(assignments: CustomerTagAssignment[]): Array<{ id: string; label: string; color: string | null }> {\n return assignments\n .map((assignment) => {\n const tag = assignment.tag as CustomerTag | string | null\n if (!tag || typeof tag === 'string') return null\n return {\n id: tag.id,\n label: tag.label,\n color: tag.color ?? null,\n }\n })\n .filter((tag): tag is { id: string; label: string; color: string | null } => tag !== null)\n}\n\ntype TodoDetail = {\n title: string | null\n isDone: boolean | null\n priority: number | null\n severity: string | null\n description: string | null\n dueAt: string | null\n organizationId: string | null\n customValues: Record<string, unknown> | null\n}\n\nfunction extractTodoTitle(record: Record<string, unknown>): string | null {\n const candidates = ['title', 'subject', 'name', 'summary', 'text', 'description']\n for (const key of candidates) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length > 0) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction parseNumber(value: unknown): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const parsed = Number(trimmed)\n if (!Number.isNaN(parsed)) return parsed\n }\n return null\n}\n\nfunction parseDateValue(value: unknown): string | null {\n if (value instanceof Date) {\n const ts = value.getTime()\n return Number.isNaN(ts) ? null : value.toISOString()\n }\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed) return null\n const candidate = new Date(trimmed)\n if (!Number.isNaN(candidate.getTime())) return candidate.toISOString()\n }\n return null\n}\n\nfunction readCustomField(record: Record<string, unknown>, key: string): unknown {\n const custom = record.custom ?? record.customFields ?? record.cf\n if (custom && typeof custom === 'object') {\n const bucket = custom as Record<string, unknown>\n if (key in bucket) return bucket[key]\n }\n return undefined\n}\n\ntype CompanyDetailKpiSummary = {\n activeDealsCount: number\n activeDealsValue: number | null\n dealCurrency: string | null\n activityCount: number\n activityTrend: { value: number; direction: 'up' | 'down' | 'unchanged' } | null\n ltvValue: number | null\n completedDealsCount: number\n clientTenureYears: number | null\n}\n\nfunction parseDealAmount(value: string | number | null | undefined): number | null {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (!trimmed.length) return null\n const parsed = Number(trimmed)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction computeActivityTrend(\n timestamps: string[],\n): { value: number; direction: 'up' | 'down' | 'unchanged' } | null {\n if (!timestamps.length) return null\n const now = Date.now()\n const weekMs = 7 * 86_400_000\n let thisWeek = 0\n let lastWeek = 0\n timestamps.forEach((value) => {\n const time = new Date(value).getTime()\n if (Number.isNaN(time)) return\n const diff = now - time\n if (diff < 0 || diff >= weekMs * 2) return\n if (diff < weekMs) {\n thisWeek += 1\n return\n }\n lastWeek += 1\n })\n if (lastWeek === 0 && thisWeek === 0) return null\n if (lastWeek === 0) return { value: 100, direction: 'up' }\n const pct = ((thisWeek - lastWeek) / lastWeek) * 100\n if (Math.abs(pct) < 0.5) return { value: 0, direction: 'unchanged' }\n return { value: Math.round(Math.abs(pct) * 100) / 100, direction: pct > 0 ? 'up' : 'down' }\n}\n\nasync function resolveTodoDetails(\n queryEngine: QueryEngine,\n links: CustomerTodoLink[],\n tenantId: string | null,\n organizationIds: Array<string | null>,\n): Promise<Map<string, TodoDetail>> {\n const details = new Map<string, TodoDetail>()\n if (!links.length || !tenantId) return details\n\n const scopedOrgIds = organizationIds\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n\n const idsBySource = new Map<string, Set<string>>()\n for (const link of links) {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const id = typeof link.todoId === 'string' && link.todoId.trim().length > 0 ? link.todoId : String(link.todoId ?? '')\n if (!id) continue\n if (!idsBySource.has(source)) idsBySource.set(source, new Set<string>())\n idsBySource.get(source)!.add(id)\n }\n\n for (const [source, idSet] of idsBySource.entries()) {\n const ids = Array.from(idSet)\n if (!ids.length) continue\n try {\n const result = await queryEngine.query<Record<string, unknown>>(source as EntityId, {\n tenantId,\n organizationIds: scopedOrgIds.length > 0 ? scopedOrgIds : undefined,\n filters: { id: { $in: ids } },\n includeCustomFields: ['priority', 'due_at', 'severity', 'description'],\n page: { page: 1, pageSize: Math.max(ids.length, 1) },\n })\n for (const item of result.items ?? []) {\n if (!item || typeof item !== 'object') continue\n const record = item as Record<string, unknown>\n const rawId = typeof record.id === 'string' && record.id.trim().length > 0 ? record.id : String(record.id ?? '')\n if (!rawId) continue\n const title = extractTodoTitle(record)\n const isDone = (() => {\n const direct = parseBooleanFromUnknown(record.is_done)\n if (direct !== null) return direct\n const custom = parseBooleanFromUnknown(readCustomField(record, 'is_done'))\n if (custom !== null) return custom\n const generic = parseBooleanFromUnknown(record.isDone)\n if (generic !== null) return generic\n return parseBooleanFromUnknown(readCustomField(record, 'isDone'))\n })()\n const priority = (() => {\n const candidates = [\n record['cf:priority'],\n record['cf_priority'],\n record.priority,\n readCustomField(record, 'priority'),\n ]\n for (const candidate of candidates) {\n const parsed = parseNumber(candidate)\n if (parsed !== null) return parsed\n }\n return null\n })()\n const severity = (() => {\n const candidates = [\n record['cf:severity'],\n record['cf_severity'],\n record.severity,\n readCustomField(record, 'severity'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const dueAt = (() => {\n const candidates = [\n record['cf:due_at'],\n record['cf_due_at'],\n record.due_at,\n readCustomField(record, 'due_at'),\n record.dueAt,\n readCustomField(record, 'dueAt'),\n ]\n for (const candidate of candidates) {\n const parsed = parseDateValue(candidate)\n if (parsed) return parsed\n }\n return null\n })()\n const organizationId = (() => {\n const candidates = [\n record.organization_id,\n record['cf:organization_id'],\n record['cf_organization_id'],\n record.organizationId,\n readCustomField(record, 'organization_id'),\n readCustomField(record, 'organizationId'),\n ]\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim()\n }\n }\n return null\n })()\n const descriptionValue = (() => {\n const direct = typeof record.description === 'string' ? record.description : null\n if (direct) return direct\n const customDescription = readCustomField(record, 'description')\n if (typeof customDescription === 'string' && customDescription.trim().length > 0) {\n return customDescription.trim()\n }\n return null\n })()\n\n const customValues: Record<string, unknown> = {}\n const assignCustomValue = (key: string, value: unknown) => {\n const trimmedKey = key.trim()\n if (!trimmedKey.length) return\n customValues[trimmedKey] = value === undefined ? null : value\n }\n for (const [rawKey, rawValue] of Object.entries(record)) {\n if (rawKey.startsWith('cf:')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n } else if (rawKey.startsWith('cf_')) {\n assignCustomValue(rawKey.slice(3), rawValue)\n }\n }\n const nestedCustom = record.custom ?? record.customFields ?? record.cf\n if (nestedCustom && typeof nestedCustom === 'object') {\n for (const [nestedKey, nestedValue] of Object.entries(nestedCustom as Record<string, unknown>)) {\n assignCustomValue(nestedKey, nestedValue)\n }\n }\n\n details.set(`${source}:${rawId}`, {\n title,\n isDone,\n priority,\n severity,\n description: descriptionValue,\n dueAt,\n organizationId,\n customValues: Object.keys(customValues).length ? customValues : null,\n })\n }\n } catch (err) {\n console.warn(`customers.companies.detail: failed to resolve todos for source ${source}`, err)\n }\n }\n\n return details\n}\n\nexport async function GET(_req: Request, ctx: { params?: { id?: string } }) {\n const auth = await getAuthFromRequest(_req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const parse = paramsSchema.safeParse({ id: ctx.params?.id })\n if (!parse.success) return NextResponse.json({ error: 'Invalid company id' }, { status: 400 })\n\n const includeTokens = parseIncludeParams(_req)\n const includeActivities = includeTokens.has('activities')\n const includeAddresses = includeTokens.has('addresses')\n const includeComments = includeTokens.has('comments') || includeTokens.has('notes')\n const includeDeals = includeTokens.has('deals')\n const includeInteractions = includeTokens.has('interactions')\n const includeTodos = includeTokens.has('todos') || includeTokens.has('tasks')\n const includePeople = includeTokens.has('people')\n const plannedPreviewLimit = 5\n\n const container = await createRequestContainer()\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request: _req })\n const em = (container.resolve('em') as EntityManager)\n const interactionFlags = await resolveCustomerInteractionFeatureFlags(container, scope?.tenantId ?? auth.tenantId)\n const interactionMode = interactionFlags.unified ? 'canonical' : 'legacy'\n\n const tenantScope = resolveCustomerDetailTenantScope(parse.data.id, 'company', auth)\n if (!tenantScope.allowed) return notFound('Company not found')\n\n const company = await findOneWithDecryption(\n em,\n CustomerEntity,\n tenantScope.where,\n { populate: ['companyProfile'] },\n {\n tenantId: auth.tenantId ?? null,\n organizationId: scope?.selectedId ?? auth.orgId ?? null,\n },\n )\n if (!company) return notFound('Company not found')\n\n if (!isOrganizationReadAccessAllowed({ scope, auth, organizationId: company.organizationId })) {\n return forbidden('Access denied')\n }\n\n const companyScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n\n // Per-user email privacy (CRM email integration): exclude private email\n // interactions owned by other users from every read path that returns\n // customer_interactions. Non-email rows, shared emails, and legacy\n // null-visibility rows pass through. v1 is strict owner-only: there is NO\n // admin bypass \u2014 the filter ignores caller features, and\n // `customers.email.view_private` is reserved (inert) for v2 oversight.\n // Mirrors the people detail route. API-key callers resolve to null\n // (no author match \u2014 shared/non-email rows only).\n const viewerUserId = auth.isApiKey ? null : (auth.sub ?? null)\n const emailVisibilityFilter = buildEmailVisibilityMikroFilter({\n currentUserId: viewerUserId,\n userFeatures: undefined,\n })\n\n // Opt-in cache (#3664): the company existence + org read-access checks above\n // always run, so authorization is never served from cache. Only the expensive\n // detail sweeps below are cached. Key on tenant/org/company + the RBAC scope,\n // viewer (email privacy), interaction mode, and the requested include set.\n const cacheTenantId = companyScope.tenantId\n const cache = isCrudCacheEnabled() ? resolveCrudCache(container) : null\n const cacheKey = cache\n ? buildCompanyDetailCacheKey({\n tenantId: cacheTenantId,\n organizationId: companyScope.organizationId,\n companyId: company.id,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n filterIds: scope?.filterIds ?? null,\n allowedIds: scope?.allowedIds ?? null,\n isSuperAdmin: auth.isSuperAdmin === true,\n viewerUserId,\n interactionMode,\n includeTokens: Array.from(includeTokens),\n })\n : null\n if (cache && cacheKey) {\n const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey))\n if (cached) return NextResponse.json(cached)\n }\n\n const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos\n\n // These reads only depend on the resolved company + scope + email visibility\n // filter, so dispatch them together to avoid a server-side request waterfall\n // before the detail surface can render (issue #3203).\n const [profile, addresses, tagAssignments, labelAssignments, comments, canonicalInteractionRows] = await Promise.all([\n company.companyProfile\n ? findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n id: company.companyProfile.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n )\n : findOneWithDecryption(\n em,\n CustomerCompanyProfile,\n {\n entity: company,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n {},\n companyScope,\n ),\n includeAddresses\n ? findWithDecryption(\n em,\n CustomerAddress,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { isPrimary: 'desc', createdAt: 'desc' } },\n companyScope,\n )\n : Promise.resolve<CustomerAddress[]>([]),\n findWithDecryption(\n em,\n CustomerTagAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['tag'] },\n companyScope,\n ),\n findWithDecryption(\n em,\n CustomerLabelAssignment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { populate: ['label'] },\n companyScope,\n ),\n includeComments\n ? findWithDecryption(\n em,\n CustomerComment,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : Promise.resolve<CustomerComment[]>([]),\n shouldLoadCanonicalInteractions\n ? findWithDecryption(\n em,\n CustomerInteraction,\n interactionFlags.unified\n ? {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }\n : {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'asc', createdAt: 'desc' }, limit: 100 },\n companyScope,\n )\n : Promise.resolve<CustomerInteraction[]>([]),\n ])\n const canonicalActiveInteractions = canonicalInteractionRows.filter((interaction) => !interaction.deletedAt)\n const canonicalInteractions = shouldLoadCanonicalInteractions\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: canonicalActiveInteractions,\n enrich: includeInteractions,\n })\n : []\n\n const plannedPreviewRows =\n canonicalActiveInteractions.length > 0\n ? canonicalActiveInteractions\n .filter((interaction) => interaction.status === 'planned' && interaction.interactionType !== 'task')\n .sort((left, right) => {\n const leftTime = new Date(left.scheduledAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.scheduledAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return left.id.localeCompare(right.id)\n return leftTime - rightTime\n })\n .slice(0, plannedPreviewLimit)\n : await findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n status: 'planned',\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n },\n { orderBy: { scheduledAt: 'ASC', createdAt: 'ASC' }, limit: plannedPreviewLimit },\n companyScope,\n )\n const plannedActivitiesPreview = plannedPreviewRows.length\n ? await hydrateCanonicalInteractions({\n em,\n container,\n auth,\n selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,\n interactions: plannedPreviewRows,\n enrich: true,\n })\n : []\n\n const activities = includeActivities && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerActivity,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { occurredAt: 'desc', createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n const todoLinks = includeTodos && !interactionFlags.unified\n ? await findWithDecryption(\n em,\n CustomerTodoLink,\n {\n entity: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n },\n { orderBy: { createdAt: 'desc' }, limit: 50 },\n companyScope,\n )\n : []\n\n let todoDetails = new Map<string, TodoDetail>()\n if (includeTodos && !interactionFlags.unified && todoLinks.length) {\n const queryEngine = (container.resolve('queryEngine') as QueryEngine)\n try {\n todoDetails = await resolveTodoDetails(\n queryEngine,\n todoLinks,\n company.tenantId ?? auth.tenantId ?? null,\n [company.organizationId ?? null, ...(scope?.filterIds ?? [])],\n )\n } catch (err) {\n console.warn('customers.companies.detail: failed to enrich todo links', err)\n }\n }\n\n const canonicalActivityBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n const canonicalTodoBridgeIds = new Set(\n canonicalInteractionRows\n .filter((interaction) => interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE)\n .map((interaction) => interaction.id),\n )\n\n const canonicalActivityItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType !== 'task')\n .map((interaction) => mapInteractionRecordToActivitySummary(interaction))\n const canonicalTodoItems = canonicalInteractions\n .filter((interaction) => interaction.interactionType === 'task')\n .map((interaction) => mapInteractionRecordToTodoSummary(interaction))\n\n const authorIds = new Set<string>()\n if (includeActivities) {\n for (const activity of activities) {\n if (activity.authorUserId) authorIds.add(activity.authorUserId)\n }\n }\n if (includeComments) {\n for (const comment of comments) {\n if (comment.authorUserId) authorIds.add(comment.authorUserId)\n }\n }\n if (viewerUserId) authorIds.add(viewerUserId)\n\n let userMap = new Map<string, { name: string | null; email: string | null }>()\n if (authorIds.size) {\n const authorIdList = Array.from(authorIds)\n const users = await findWithDecryption(\n em,\n User,\n {\n id: { $in: authorIdList },\n tenantId: company.tenantId,\n },\n {},\n companyScope,\n )\n 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 }\n\n let deals: CustomerDeal[] = []\n if (includeDeals) {\n const dealLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n deals = dealLinks\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n }\n\n const dealLinksForMetrics = includeDeals\n ? deals\n : (\n await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n {\n company: company.id,\n },\n { populate: ['deal'] },\n companyScope,\n )\n )\n .map((link) => (link.deal as CustomerDeal | string | null) ?? null)\n .filter(\n (deal): deal is CustomerDeal =>\n !!deal &&\n typeof deal !== 'string' &&\n deal.tenantId === company.tenantId &&\n deal.organizationId === company.organizationId,\n )\n\n let relatedPeople: Array<{\n entity: CustomerEntity\n profile: CustomerPersonProfile | null\n linkedAt: string | null\n }> = []\n if (includePeople) {\n const peopleDecryptionScope = {\n tenantId: company.tenantId ?? auth.tenantId ?? null,\n organizationId: company.organizationId ?? scope?.selectedId ?? auth.orgId ?? null,\n }\n const relatedPeopleById = new Map<\n string,\n { entity: CustomerEntity; profile: CustomerPersonProfile | null; linkedAt: string | null }\n >()\n const companyLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n const companyLinks = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n companyLinkWhere,\n {\n populate: ['person', 'person.personProfile'],\n orderBy: { isPrimary: 'desc', createdAt: 'asc' },\n },\n peopleDecryptionScope,\n ),\n )\n companyLinks.forEach((link) => {\n const entity = typeof link.person === 'string' ? null : link.person\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n const personProfile =\n entity.personProfile && typeof entity.personProfile !== 'string'\n ? entity.personProfile\n : null\n relatedPeopleById.set(entity.id, {\n entity,\n profile: personProfile,\n linkedAt: link.createdAt instanceof Date ? link.createdAt.toISOString() : null,\n })\n })\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n {\n company: company.id,\n tenantId: company.tenantId,\n organizationId: company.organizationId,\n entity: { deletedAt: null },\n },\n { populate: ['entity'] },\n peopleDecryptionScope,\n )\n profiles.forEach((entry) => {\n const entity = entry.entity as CustomerEntity | null\n if (!entity || entity.kind !== 'person' || entity.deletedAt) return\n if (!relatedPeopleById.has(entity.id)) {\n relatedPeopleById.set(entity.id, {\n entity,\n profile: entry ?? null,\n linkedAt: entry.createdAt instanceof Date ? entry.createdAt.toISOString() : null,\n })\n }\n })\n relatedPeople = Array.from(relatedPeopleById.values())\n }\n\n // Entity custom fields, profile custom fields, and the routing lookup do not\n // depend on each other (profileId is already resolved above), so load them in\n // parallel instead of three sequential awaits (issue #3203).\n const profileId = profile?.id ?? null\n const [entityCustomFieldValues, profileCustomFieldValues, routing] = await Promise.all([\n loadCustomFieldValues({\n em,\n entityId: E.customers.customer_entity,\n recordIds: [company.id],\n tenantIdByRecord: { [company.id]: company.tenantId ?? null },\n organizationIdByRecord: { [company.id]: company.organizationId ?? null },\n tenantFallbacks: [\n company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n }),\n profileId\n ? loadCustomFieldValues({\n em,\n entityId: E.customers.customer_company_profile,\n recordIds: [profileId],\n tenantIdByRecord: { [profileId]: profile?.tenantId ?? null },\n organizationIdByRecord: { [profileId]: profile?.organizationId ?? null },\n tenantFallbacks: [\n profile?.tenantId ?? company.tenantId ?? auth.tenantId ?? null,\n ].filter((v): v is string => !!v),\n })\n : Promise.resolve<Record<string, Record<string, unknown>>>({}),\n resolveCompanyCustomFieldRouting(em, company.tenantId ?? null, company.organizationId ?? null),\n ])\n const customFields = normalizeCustomerDetailCustomFields(\n mergeCompanyCustomFieldValues(\n routing,\n entityCustomFieldValues?.[company.id] ?? {},\n profileId ? profileCustomFieldValues?.[profileId] ?? {} : {},\n ),\n )\n\n // The count queries, related-people fallback, and KPI interaction fallback are\n // all independent of each other; dispatch them together rather than awaiting\n // each inline so the response counts/KPIs are assembled in one parallel round\n // instead of a waterfall (issue #3203).\n const peopleCountQuery = includePeople\n ? Promise.resolve(relatedPeople.length)\n : (async () => {\n const peopleLinkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n {\n company: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n },\n 'customers.companies.GET',\n )\n return filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n peopleLinkWhere,\n {},\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ).length\n })()\n const [\n activityCount,\n interactionCount,\n todoCount,\n commentsCount,\n addressesCount,\n peopleCount,\n kpiInteractionRows,\n ] = await Promise.all([\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: { $ne: 'task' },\n ...emailVisibilityFilter,\n }),\n em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n }),\n interactionFlags.unified\n ? em.count(CustomerInteraction, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n interactionType: 'task',\n })\n : em.count(CustomerTodoLink, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeComments\n ? Promise.resolve(comments.length)\n : em.count(CustomerComment, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n includeAddresses\n ? Promise.resolve(addresses.length)\n : em.count(CustomerAddress, {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n }),\n peopleCountQuery,\n canonicalActiveInteractions.length\n ? Promise.resolve(canonicalActiveInteractions)\n : findWithDecryption(\n em,\n CustomerInteraction,\n {\n entity: company.id,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n deletedAt: null,\n ...emailVisibilityFilter,\n },\n {\n fields: ['id', 'occurredAt', 'scheduledAt', 'createdAt'],\n orderBy: { createdAt: 'DESC' },\n },\n { tenantId: company.tenantId, organizationId: company.organizationId },\n ),\n ])\n const activityTrend = computeActivityTrend(\n kpiInteractionRows\n .map((interaction) => interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt)\n .map((value) => (value instanceof Date ? value.toISOString() : typeof value === 'string' ? value : ''))\n .filter((value) => value.length > 0),\n )\n const activeDeals = dealLinksForMetrics.filter(\n (deal) => deal.status !== 'won' && deal.status !== 'lost' && deal.status !== 'closed',\n )\n const wonDeals = dealLinksForMetrics.filter((deal) => deal.status === 'won')\n const activeDealsValue = activeDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n const ltvValue = wonDeals.length\n ? wonDeals.reduce((sum, deal) => sum + (parseDealAmount(deal.valueAmount) ?? 0), 0)\n : null\n const earliestInteractionTime = kpiInteractionRows.reduce<number | null>((earliest, interaction) => {\n const candidate = interaction.occurredAt ?? interaction.scheduledAt ?? interaction.createdAt\n const time = candidate instanceof Date ? candidate.getTime() : new Date(candidate).getTime()\n if (Number.isNaN(time)) return earliest\n if (earliest === null) return time\n return Math.min(earliest, time)\n }, null)\n const companyKpis: CompanyDetailKpiSummary = {\n activeDealsCount: activeDeals.length,\n activeDealsValue: activeDeals.length ? activeDealsValue : null,\n dealCurrency:\n activeDeals[0]?.valueCurrency ??\n dealLinksForMetrics[0]?.valueCurrency ??\n null,\n activityCount,\n activityTrend,\n ltvValue,\n completedDealsCount: wonDeals.length,\n clientTenureYears:\n earliestInteractionTime === null\n ? null\n : Math.floor((Date.now() - earliestInteractionTime) / (365.25 * 86_400_000)),\n }\n const counts = {\n tags: tagAssignments.length + labelAssignments.length,\n comments: commentsCount,\n activities: activityCount,\n interactions: interactionCount,\n todos: todoCount,\n deals: includeDeals ? deals.length : dealLinksForMetrics.length,\n people: peopleCount,\n addresses: addressesCount,\n }\n\n const payload = {\n interactionMode,\n company: {\n id: company.id,\n displayName: company.displayName,\n description: company.description,\n ownerUserId: company.ownerUserId,\n primaryEmail: company.primaryEmail,\n primaryPhone: company.primaryPhone,\n status: company.status,\n lifecycleStage: company.lifecycleStage,\n source: company.source,\n nextInteractionAt: company.nextInteractionAt ? company.nextInteractionAt.toISOString() : null,\n nextInteractionName: company.nextInteractionName,\n nextInteractionRefId: company.nextInteractionRefId,\n nextInteractionIcon: company.nextInteractionIcon,\n nextInteractionColor: company.nextInteractionColor,\n organizationId: company.organizationId,\n tenantId: company.tenantId,\n isActive: company.isActive,\n temperature: company.temperature ?? null,\n renewalQuarter: company.renewalQuarter ?? null,\n createdAt: company.createdAt.toISOString(),\n updatedAt: company.updatedAt.toISOString(),\n },\n profile: profile\n ? {\n id: profile.id,\n legalName: profile.legalName,\n brandName: profile.brandName,\n domain: profile.domain,\n websiteUrl: profile.websiteUrl,\n industry: profile.industry,\n sizeBucket: profile.sizeBucket,\n annualRevenue: profile.annualRevenue,\n }\n : null,\n customFields,\n tags: [\n ...serializeTags(tagAssignments),\n ...labelAssignments\n .map((assignment) => {\n const label = assignment.label as CustomerLabel | string | null\n if (!label || typeof label === 'string') return null\n return { id: label.id, label: label.label, color: null }\n })\n .filter((tag): tag is { id: string; label: string; color: null } => tag !== null),\n ],\n addresses: includeAddresses\n ? addresses.map((address) => ({\n id: address.id,\n name: address.name,\n purpose: address.purpose,\n addressLine1: address.addressLine1,\n addressLine2: address.addressLine2,\n buildingNumber: address.buildingNumber,\n flatNumber: address.flatNumber,\n city: address.city,\n region: address.region,\n postalCode: address.postalCode,\n country: address.country,\n latitude: address.latitude,\n longitude: address.longitude,\n isPrimary: address.isPrimary,\n createdAt: address.createdAt.toISOString(),\n }))\n : [],\n comments: includeComments\n ? comments.map((comment) => {\n const authorInfo = comment.authorUserId ? userMap.get(comment.authorUserId) : null\n return {\n id: comment.id,\n body: comment.body,\n authorUserId: comment.authorUserId,\n authorName: comment.authorUserId ? authorInfo?.name ?? null : null,\n authorEmail: comment.authorUserId ? authorInfo?.email ?? null : null,\n dealId: comment.deal ? (typeof comment.deal === 'string' ? comment.deal : comment.deal.id) : null,\n createdAt: comment.createdAt.toISOString(),\n appearanceIcon: comment.appearanceIcon ?? null,\n appearanceColor: comment.appearanceColor ?? null,\n }\n })\n : [],\n activities: includeActivities\n ? (\n interactionFlags.unified\n ? canonicalActivityItems\n : [\n ...activities\n .filter((activity) => !canonicalActivityBridgeIds.has(activity.id))\n .map((activity) => ({\n id: activity.id,\n activityType: activity.activityType,\n subject: activity.subject,\n body: activity.body,\n occurredAt: activity.occurredAt ? activity.occurredAt.toISOString() : null,\n dealId: activity.deal ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id) : null,\n authorUserId: activity.authorUserId,\n authorName: activity.authorUserId ? userMap.get(activity.authorUserId)?.name ?? null : null,\n authorEmail: activity.authorUserId ? userMap.get(activity.authorUserId)?.email ?? null : null,\n createdAt: activity.createdAt.toISOString(),\n appearanceIcon: activity.appearanceIcon ?? null,\n appearanceColor: activity.appearanceColor ?? null,\n })),\n ...canonicalActivityItems.filter(\n (activity) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === activity.id &&\n interaction.source === CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.occurredAt ?? left.createdAt).getTime()\n const rightTime = new Date(right.occurredAt ?? right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n interactions: includeInteractions\n ? canonicalInteractions\n : [],\n deals: includeDeals\n ? deals.map((deal) => ({\n id: deal.id,\n title: deal.title,\n status: deal.status,\n pipelineStage: deal.pipelineStage,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount,\n valueCurrency: deal.valueCurrency,\n probability: deal.probability,\n expectedCloseAt: deal.expectedCloseAt ? deal.expectedCloseAt.toISOString() : null,\n ownerUserId: deal.ownerUserId,\n source: deal.source,\n createdAt: deal.createdAt.toISOString(),\n updatedAt: deal.updatedAt.toISOString(),\n }))\n : [],\n todos: includeTodos\n ? (\n interactionFlags.unified\n ? canonicalTodoItems\n : [\n ...todoLinks\n .filter((link) => !canonicalTodoBridgeIds.has(link.todoId))\n .map((link) => {\n const source = typeof link.todoSource === 'string' && link.todoSource.trim().length > 0 ? link.todoSource : EXAMPLE_TODO_SOURCE\n const key = `${source}:${link.todoId}`\n const detail = todoDetails.get(key)\n return {\n id: link.id,\n todoId: link.todoId,\n todoSource: source,\n createdAt: link.createdAt.toISOString(),\n createdByUserId: link.createdByUserId,\n title: detail?.title ?? null,\n isDone: detail?.isDone ?? null,\n priority: detail?.priority ?? null,\n severity: detail?.severity ?? null,\n description: detail?.description ?? null,\n dueAt: detail?.dueAt ?? null,\n todoOrganizationId: detail?.organizationId ?? null,\n customValues: detail?.customValues ?? null,\n }\n }),\n ...canonicalTodoItems.filter(\n (todo) =>\n canonicalInteractions.some(\n (interaction) =>\n interaction.id === todo.todoId &&\n interaction.source === CUSTOMER_INTERACTION_TODO_ADAPTER_SOURCE,\n ),\n ),\n ].sort((left, right) => {\n const leftTime = new Date(left.createdAt).getTime()\n const rightTime = new Date(right.createdAt).getTime()\n if (leftTime === rightTime) return right.id.localeCompare(left.id)\n return rightTime - leftTime\n }).slice(0, 50)\n )\n : [],\n people: includePeople\n ? relatedPeople.map(({ entity, profile: personProfile, linkedAt }) => ({\n id: entity.id,\n displayName: entity.displayName,\n primaryEmail: entity.primaryEmail ?? null,\n primaryPhone: entity.primaryPhone ?? null,\n status: entity.status ?? null,\n lifecycleStage: entity.lifecycleStage ?? null,\n jobTitle: personProfile?.jobTitle ?? null,\n department: personProfile?.department ?? null,\n createdAt: entity.createdAt.toISOString(),\n organizationId: entity.organizationId,\n source: entity.source ?? null,\n temperature: entity.temperature ?? null,\n linkedAt,\n }))\n : [],\n plannedActivitiesPreview,\n counts,\n kpis: companyKpis,\n viewer: {\n userId: viewerUserId,\n name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,\n email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null,\n },\n }\n\n if (cache && cacheKey) {\n try {\n await runWithCacheTenant(cacheTenantId, () =>\n cache.set(cacheKey, payload, {\n ttl: COMPANY_DETAIL_CACHE_TTL_MS,\n tags: buildCompanyDetailCacheTags(cacheTenantId, companyScope.organizationId),\n }),\n )\n } catch (err) {\n console.warn('[customers:companies] Failed to set company detail cache', err)\n }\n }\n\n return NextResponse.json(payload)\n}\n\nconst companyDetailQuerySchema = z.object({\n include: z\n .string()\n .optional()\n .describe('Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people).'),\n}).passthrough()\n\nconst companyDetailResponseSchema = z.object({\n interactionMode: z.enum(['canonical', 'legacy']),\n company: z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n nextInteractionAt: z.string().nullable().optional(),\n nextInteractionName: z.string().nullable().optional(),\n nextInteractionRefId: z.string().nullable().optional(),\n nextInteractionIcon: z.string().nullable().optional(),\n nextInteractionColor: z.string().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n isActive: z.boolean().optional(),\n temperature: z.string().nullable().optional(),\n renewalQuarter: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n profile: z\n .object({\n id: z.string().uuid(),\n legalName: z.string().nullable().optional(),\n brandName: z.string().nullable().optional(),\n domain: z.string().nullable().optional(),\n websiteUrl: z.string().nullable().optional(),\n industry: z.string().nullable().optional(),\n sizeBucket: z.string().nullable().optional(),\n annualRevenue: z.number().nullable().optional(),\n })\n .nullable(),\n customFields: z.record(z.string(), z.unknown()),\n tags: z.array(\n z.object({\n id: z.string().uuid(),\n label: z.string(),\n color: z.string().nullable().optional(),\n }),\n ),\n addresses: z.array(\n z.object({\n id: z.string().uuid(),\n name: z.string().nullable().optional(),\n purpose: z.string().nullable().optional(),\n addressLine1: z.string().nullable().optional(),\n addressLine2: z.string().nullable().optional(),\n buildingNumber: z.string().nullable().optional(),\n flatNumber: z.string().nullable().optional(),\n city: z.string().nullable().optional(),\n region: z.string().nullable().optional(),\n postalCode: z.string().nullable().optional(),\n country: z.string().nullable().optional(),\n latitude: z.number().nullable().optional(),\n longitude: z.number().nullable().optional(),\n isPrimary: z.boolean().nullable().optional(),\n createdAt: z.string(),\n }),\n ),\n comments: z.array(\n z.object({\n id: z.string().uuid(),\n body: z.string().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 createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n activities: z.array(\n z.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 dealId: 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 createdAt: z.string(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n }),\n ),\n interactions: z.array(\n z.object({\n id: z.string().uuid(),\n entityId: z.string().uuid().nullable().optional(),\n interactionType: z.string(),\n title: z.string().nullable().optional(),\n body: z.string().nullable().optional(),\n status: z.string(),\n scheduledAt: z.string().nullable().optional(),\n occurredAt: z.string().nullable().optional(),\n priority: z.number().nullable().optional(),\n authorUserId: z.string().uuid().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n dealId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n authorName: z.string().nullable().optional(),\n authorEmail: z.string().nullable().optional(),\n dealTitle: z.string().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n appearanceIcon: z.string().nullable().optional(),\n appearanceColor: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n _integrations: z.record(z.string(), z.unknown()).optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n deals: z.array(\n z.object({\n id: z.string().uuid(),\n title: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n pipelineStage: z.string().nullable().optional(),\n valueAmount: z.number().nullable().optional(),\n valueCurrency: z.string().nullable().optional(),\n probability: z.number().nullable().optional(),\n expectedCloseAt: z.string().nullable().optional(),\n ownerUserId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n }),\n ),\n todos: z.array(\n z.object({\n id: z.string().uuid(),\n todoId: z.string().uuid(),\n todoSource: z.string(),\n createdAt: z.string(),\n createdByUserId: z.string().uuid().nullable().optional(),\n title: z.string().nullable().optional(),\n isDone: z.boolean().nullable().optional(),\n priority: z.number().nullable().optional(),\n severity: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n dueAt: z.string().nullable().optional(),\n todoOrganizationId: z.string().uuid().nullable().optional(),\n customValues: z.record(z.string(), z.unknown()).nullable().optional(),\n }),\n ),\n people: z.array(\n z.object({\n id: z.string().uuid(),\n displayName: z.string().nullable().optional(),\n primaryEmail: z.string().nullable().optional(),\n primaryPhone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycleStage: z.string().nullable().optional(),\n jobTitle: z.string().nullable().optional(),\n department: z.string().nullable().optional(),\n createdAt: z.string(),\n organizationId: z.string().uuid().nullable().optional(),\n source: z.string().nullable().optional(),\n temperature: z.string().nullable().optional(),\n linkedAt: z.string().nullable().optional(),\n }),\n ),\n viewer: z.object({\n userId: z.string().uuid().nullable(),\n name: z.string().nullable(),\n email: z.string().nullable(),\n }),\n})\n\nconst companyDetailErrorSchema = z.object({\n error: z.string(),\n})\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Customers',\n summary: 'Fetch company detail',\n methods: {\n GET: {\n summary: 'Fetch company with related data',\n description: 'Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.',\n query: companyDetailQuerySchema,\n responses: [\n { status: 200, description: 'Company detail payload', schema: companyDetailResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Invalid identifier', schema: companyDetailErrorSchema },\n { status: 401, description: 'Unauthorized', schema: companyDetailErrorSchema },\n { status: 403, description: 'Forbidden for tenant/organization scope', schema: companyDetailErrorSchema },\n { status: 404, description: 'Company not found', schema: companyDetailErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,0CAA0C;AAEnD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY;AACrB,SAAS,6BAA6B;AACtC,SAAS,SAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,8CAA8C;AACvD,SAAS,oCAAoC;AAC7C,SAAS,uCAAuC;AAChD,SAAS,wCAAwC;AAIjD,SAAS,uBAAuB,0BAA0B;AAC1D,SAAS,+BAA+B;AACxC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,2CAA2C;AACpD,SAAS,uCAAuC;AAChD,SAAS,0BAA0B;AACnC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEA,MAAM,WAAW;AAAA,EACtB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,0BAA0B,EAAE;AAC1E;AAEA,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO,EAAE,KAAK;AACtB,CAAC;AAED,MAAM,8BAA8B;AAOpC,MAAM,sCAAsC;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,4BAA4B,UAAyB,gBAAyC;AACrG,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,gBAAgB,qCAAqC;AAC9D,UAAM,WAAW,wBAAwB,YAAY,KAAK;AAC1D,eAAW,OAAO,oBAAoB,UAAU,UAAU,CAAC,cAAc,CAAC,GAAG;AAC3E,WAAK,IAAI,GAAG;AAAA,IACd;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAEA,SAAS,2BAA2B,OAWzB;AACT,QAAM,WAAW,CAAC,WAChB,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE;AACzD,QAAM,YAAY,MAAM,YAAY,SAAS,MAAM,SAAS,EAAE,KAAK,GAAG,IAAI;AAC1E,QAAM,aAAa,MAAM,aAAa,SAAS,MAAM,UAAU,EAAE,KAAK,GAAG,IAAI;AAC7E,QAAM,gBAAgB,SAAS,MAAM,aAAa,EAAE,KAAK,GAAG;AAC5D,SAAO;AAAA,IACL;AAAA,IACA,UAAU,MAAM,YAAY,MAAM;AAAA,IAClC,OAAO,MAAM,kBAAkB,MAAM;AAAA,IACrC,WAAW,MAAM,SAAS;AAAA,IAC1B,YAAY,MAAM,0BAA0B,MAAM;AAAA,IAClD,UAAU,SAAS;AAAA,IACnB,WAAW,UAAU;AAAA,IACrB,SAAS,MAAM,eAAe,MAAM,GAAG;AAAA,IACvC,UAAU,MAAM,gBAAgB,MAAM;AAAA,IACtC,QAAQ,MAAM,eAAe;AAAA,IAC7B,WAAW,aAAa;AAAA,EAC1B,EAAE,KAAK,GAAG;AACZ;AAEA,SAAS,mBAAmB,SAA+B;AACzD,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,MAAM,IAAI,aAAa,OAAO,SAAS;AAC7C,QAAM,SAAS,oBAAI,IAAY;AAC/B,MAAI,QAAQ,CAAC,UAAU;AACrB,QAAI,CAAC,MAAO;AACZ,UACG,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC,EACvC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,EAChC,QAAQ,CAAC,SAAS,OAAO,IAAI,IAAI,CAAC;AAAA,EACvC,CAAC;AACD,SAAO;AACT;AAEA,SAAS,UAAU,SAAiB;AAClC,SAAO,aAAa,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC9D;AAEA,SAAS,SAAS,SAAiB;AACjC,SAAO,aAAa,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC9D;AAEA,SAAS,cAAc,aAAkG;AACvH,SAAO,YACJ,IAAI,CAAC,eAAe;AACnB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,OAAO,IAAI;AAAA,MACX,OAAO,IAAI,SAAS;AAAA,IACtB;AAAA,EACF,CAAC,EACA,OAAO,CAAC,QAAoE,QAAQ,IAAI;AAC7F;AAaA,SAAS,iBAAiB,QAAgD;AACxE,QAAM,aAAa,CAAC,SAAS,WAAW,QAAQ,WAAW,QAAQ,aAAa;AAChF,aAAW,OAAO,YAAY;AAC5B,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,GAAG;AACxD,aAAO,MAAM,KAAK;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAA+B;AAClD,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,SAAS,OAAO,OAAO;AAC7B,QAAI,CAAC,OAAO,MAAM,MAAM,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAEA,SAAS,eAAe,OAA+B;AACrD,MAAI,iBAAiB,MAAM;AACzB,UAAM,KAAK,MAAM,QAAQ;AACzB,WAAO,OAAO,MAAM,EAAE,IAAI,OAAO,MAAM,YAAY;AAAA,EACrD;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,QAAS,QAAO;AACrB,UAAM,YAAY,IAAI,KAAK,OAAO;AAClC,QAAI,CAAC,OAAO,MAAM,UAAU,QAAQ,CAAC,EAAG,QAAO,UAAU,YAAY;AAAA,EACvE;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAiC,KAAsB;AAC9E,QAAM,SAAS,OAAO,UAAU,OAAO,gBAAgB,OAAO;AAC9D,MAAI,UAAU,OAAO,WAAW,UAAU;AACxC,UAAM,SAAS;AACf,QAAI,OAAO,OAAQ,QAAO,OAAO,GAAG;AAAA,EACtC;AACA,SAAO;AACT;AAaA,SAAS,gBAAgB,OAA0D;AACjF,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,UAAU,MAAM,KAAK;AAC3B,QAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,UAAM,SAAS,OAAO,OAAO;AAC7B,WAAO,OAAO,MAAM,MAAM,IAAI,OAAO;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,qBACP,YACkE;AAClE,MAAI,CAAC,WAAW,OAAQ,QAAO;AAC/B,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,SAAS,IAAI;AACnB,MAAI,WAAW;AACf,MAAI,WAAW;AACf,aAAW,QAAQ,CAAC,UAAU;AAC5B,UAAM,OAAO,IAAI,KAAK,KAAK,EAAE,QAAQ;AACrC,QAAI,OAAO,MAAM,IAAI,EAAG;AACxB,UAAM,OAAO,MAAM;AACnB,QAAI,OAAO,KAAK,QAAQ,SAAS,EAAG;AACpC,QAAI,OAAO,QAAQ;AACjB,kBAAY;AACZ;AAAA,IACF;AACA,gBAAY;AAAA,EACd,CAAC;AACD,MAAI,aAAa,KAAK,aAAa,EAAG,QAAO;AAC7C,MAAI,aAAa,EAAG,QAAO,EAAE,OAAO,KAAK,WAAW,KAAK;AACzD,QAAM,OAAQ,WAAW,YAAY,WAAY;AACjD,MAAI,KAAK,IAAI,GAAG,IAAI,IAAK,QAAO,EAAE,OAAO,GAAG,WAAW,YAAY;AACnE,SAAO,EAAE,OAAO,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,KAAK,WAAW,MAAM,IAAI,OAAO,OAAO;AAC5F;AAEA,eAAe,mBACb,aACA,OACA,UACA,iBACkC;AAClC,QAAM,UAAU,oBAAI,IAAwB;AAC5C,MAAI,CAAC,MAAM,UAAU,CAAC,SAAU,QAAO;AAEvC,QAAM,eAAe,gBAClB,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC;AAE1F,QAAM,cAAc,oBAAI,IAAyB;AACjD,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,OAAO,KAAK,eAAe,YAAY,KAAK,WAAW,KAAK,EAAE,SAAS,IAAI,KAAK,aAAa;AAC5G,UAAM,KAAK,OAAO,KAAK,WAAW,YAAY,KAAK,OAAO,KAAK,EAAE,SAAS,IAAI,KAAK,SAAS,OAAO,KAAK,UAAU,EAAE;AACpH,QAAI,CAAC,GAAI;AACT,QAAI,CAAC,YAAY,IAAI,MAAM,EAAG,aAAY,IAAI,QAAQ,oBAAI,IAAY,CAAC;AACvE,gBAAY,IAAI,MAAM,EAAG,IAAI,EAAE;AAAA,EACjC;AAEA,aAAW,CAAC,QAAQ,KAAK,KAAK,YAAY,QAAQ,GAAG;AACnD,UAAM,MAAM,MAAM,KAAK,KAAK;AAC5B,QAAI,CAAC,IAAI,OAAQ;AACjB,QAAI;AACF,YAAM,SAAS,MAAM,YAAY,MAA+B,QAAoB;AAAA,QAClF;AAAA,QACA,iBAAiB,aAAa,SAAS,IAAI,eAAe;AAAA,QAC1D,SAAS,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;AAAA,QAC5B,qBAAqB,CAAC,YAAY,UAAU,YAAY,aAAa;AAAA,QACrE,MAAM,EAAE,MAAM,GAAG,UAAU,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAE;AAAA,MACrD,CAAC;AACD,iBAAW,QAAQ,OAAO,SAAS,CAAC,GAAG;AACrC,YAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,cAAM,SAAS;AACf,cAAM,QAAQ,OAAO,OAAO,OAAO,YAAY,OAAO,GAAG,KAAK,EAAE,SAAS,IAAI,OAAO,KAAK,OAAO,OAAO,MAAM,EAAE;AAC/G,YAAI,CAAC,MAAO;AACZ,cAAM,QAAQ,iBAAiB,MAAM;AACrC,cAAM,UAAU,MAAM;AACpB,gBAAM,SAAS,wBAAwB,OAAO,OAAO;AACrD,cAAI,WAAW,KAAM,QAAO;AAC5B,gBAAM,SAAS,wBAAwB,gBAAgB,QAAQ,SAAS,CAAC;AACzE,cAAI,WAAW,KAAM,QAAO;AAC5B,gBAAM,UAAU,wBAAwB,OAAO,MAAM;AACrD,cAAI,YAAY,KAAM,QAAO;AAC7B,iBAAO,wBAAwB,gBAAgB,QAAQ,QAAQ,CAAC;AAAA,QAClE,GAAG;AACH,cAAM,YAAY,MAAM;AACtB,gBAAM,aAAa;AAAA,YACjB,OAAO,aAAa;AAAA,YACpB,OAAO,aAAa;AAAA,YACpB,OAAO;AAAA,YACP,gBAAgB,QAAQ,UAAU;AAAA,UACpC;AACA,qBAAW,aAAa,YAAY;AAClC,kBAAM,SAAS,YAAY,SAAS;AACpC,gBAAI,WAAW,KAAM,QAAO;AAAA,UAC9B;AACA,iBAAO;AAAA,QACT,GAAG;AACH,cAAM,YAAY,MAAM;AACtB,gBAAM,aAAa;AAAA,YACjB,OAAO,aAAa;AAAA,YACpB,OAAO,aAAa;AAAA,YACpB,OAAO;AAAA,YACP,gBAAgB,QAAQ,UAAU;AAAA,UACpC;AACA,qBAAW,aAAa,YAAY;AAClC,gBAAI,OAAO,cAAc,YAAY,UAAU,KAAK,EAAE,SAAS,GAAG;AAChE,qBAAO,UAAU,KAAK;AAAA,YACxB;AAAA,UACF;AACA,iBAAO;AAAA,QACT,GAAG;AACH,cAAM,SAAS,MAAM;AACnB,gBAAM,aAAa;AAAA,YACjB,OAAO,WAAW;AAAA,YAClB,OAAO,WAAW;AAAA,YAClB,OAAO;AAAA,YACP,gBAAgB,QAAQ,QAAQ;AAAA,YAChC,OAAO;AAAA,YACP,gBAAgB,QAAQ,OAAO;AAAA,UACjC;AACA,qBAAW,aAAa,YAAY;AAClC,kBAAM,SAAS,eAAe,SAAS;AACvC,gBAAI,OAAQ,QAAO;AAAA,UACrB;AACA,iBAAO;AAAA,QACT,GAAG;AACH,cAAM,kBAAkB,MAAM;AAC5B,gBAAM,aAAa;AAAA,YACjB,OAAO;AAAA,YACP,OAAO,oBAAoB;AAAA,YAC3B,OAAO,oBAAoB;AAAA,YAC3B,OAAO;AAAA,YACP,gBAAgB,QAAQ,iBAAiB;AAAA,YACzC,gBAAgB,QAAQ,gBAAgB;AAAA,UAC1C;AACA,qBAAW,aAAa,YAAY;AAClC,gBAAI,OAAO,cAAc,YAAY,UAAU,KAAK,EAAE,SAAS,GAAG;AAChE,qBAAO,UAAU,KAAK;AAAA,YACxB;AAAA,UACF;AACA,iBAAO;AAAA,QACT,GAAG;AACH,cAAM,oBAAoB,MAAM;AAC9B,gBAAM,SAAS,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc;AAC7E,cAAI,OAAQ,QAAO;AACnB,gBAAM,oBAAoB,gBAAgB,QAAQ,aAAa;AAC/D,cAAI,OAAO,sBAAsB,YAAY,kBAAkB,KAAK,EAAE,SAAS,GAAG;AAChF,mBAAO,kBAAkB,KAAK;AAAA,UAChC;AACA,iBAAO;AAAA,QACT,GAAG;AAEH,cAAM,eAAwC,CAAC;AAC/C,cAAM,oBAAoB,CAAC,KAAa,UAAmB;AACzD,gBAAM,aAAa,IAAI,KAAK;AAC5B,cAAI,CAAC,WAAW,OAAQ;AACxB,uBAAa,UAAU,IAAI,UAAU,SAAY,OAAO;AAAA,QAC1D;AACA,mBAAW,CAAC,QAAQ,QAAQ,KAAK,OAAO,QAAQ,MAAM,GAAG;AACvD,cAAI,OAAO,WAAW,KAAK,GAAG;AAC5B,8BAAkB,OAAO,MAAM,CAAC,GAAG,QAAQ;AAAA,UAC7C,WAAW,OAAO,WAAW,KAAK,GAAG;AACnC,8BAAkB,OAAO,MAAM,CAAC,GAAG,QAAQ;AAAA,UAC7C;AAAA,QACF;AACA,cAAM,eAAe,OAAO,UAAU,OAAO,gBAAgB,OAAO;AACpE,YAAI,gBAAgB,OAAO,iBAAiB,UAAU;AACpD,qBAAW,CAAC,WAAW,WAAW,KAAK,OAAO,QAAQ,YAAuC,GAAG;AAC9F,8BAAkB,WAAW,WAAW;AAAA,UAC1C;AAAA,QACF;AAEA,gBAAQ,IAAI,GAAG,MAAM,IAAI,KAAK,IAAI;AAAA,UAChC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,aAAa;AAAA,UACb;AAAA,UACA;AAAA,UACA,cAAc,OAAO,KAAK,YAAY,EAAE,SAAS,eAAe;AAAA,QAClE,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,kEAAkE,MAAM,IAAI,GAAG;AAAA,IAC9F;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,IAAI,MAAe,KAAmC;AAC1E,QAAM,OAAO,MAAM,mBAAmB,IAAI;AAC1C,MAAI,CAAC,KAAM,QAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC9E,QAAM,QAAQ,aAAa,UAAU,EAAE,IAAI,IAAI,QAAQ,GAAG,CAAC;AAC3D,MAAI,CAAC,MAAM,QAAS,QAAO,aAAa,KAAK,EAAE,OAAO,qBAAqB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAE7F,QAAM,gBAAgB,mBAAmB,IAAI;AAC7C,QAAM,oBAAoB,cAAc,IAAI,YAAY;AACxD,QAAM,mBAAmB,cAAc,IAAI,WAAW;AACtD,QAAM,kBAAkB,cAAc,IAAI,UAAU,KAAK,cAAc,IAAI,OAAO;AAClF,QAAM,eAAe,cAAc,IAAI,OAAO;AAC9C,QAAM,sBAAsB,cAAc,IAAI,cAAc;AAC5D,QAAM,eAAe,cAAc,IAAI,OAAO,KAAK,cAAc,IAAI,OAAO;AAC5E,QAAM,gBAAgB,cAAc,IAAI,QAAQ;AAChD,QAAM,sBAAsB;AAE5B,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AACzF,QAAM,KAAM,UAAU,QAAQ,IAAI;AAClC,QAAM,mBAAmB,MAAM,uCAAuC,WAAW,OAAO,YAAY,KAAK,QAAQ;AACjH,QAAM,kBAAkB,iBAAiB,UAAU,cAAc;AAEjE,QAAM,cAAc,iCAAiC,MAAM,KAAK,IAAI,WAAW,IAAI;AACnF,MAAI,CAAC,YAAY,QAAS,QAAO,SAAS,mBAAmB;AAE7D,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,EAAE,UAAU,CAAC,gBAAgB,EAAE;AAAA,IAC/B;AAAA,MACE,UAAU,KAAK,YAAY;AAAA,MAC3B,gBAAgB,OAAO,cAAc,KAAK,SAAS;AAAA,IACrD;AAAA,EACF;AACA,MAAI,CAAC,QAAS,QAAO,SAAS,mBAAmB;AAEjD,MAAI,CAAC,gCAAgC,EAAE,OAAO,MAAM,gBAAgB,QAAQ,eAAe,CAAC,GAAG;AAC7F,WAAO,UAAU,eAAe;AAAA,EAClC;AAEA,QAAM,eAAe;AAAA,IACnB,UAAU,QAAQ,YAAY,KAAK,YAAY;AAAA,IAC/C,gBAAgB,QAAQ,kBAAkB,OAAO,cAAc,KAAK,SAAS;AAAA,EAC/E;AAUA,QAAM,eAAe,KAAK,WAAW,OAAQ,KAAK,OAAO;AACzD,QAAM,wBAAwB,gCAAgC;AAAA,IAC5D,eAAe;AAAA,IACf,cAAc;AAAA,EAChB,CAAC;AAMD,QAAM,gBAAgB,aAAa;AACnC,QAAM,QAAQ,mBAAmB,IAAI,iBAAiB,SAAS,IAAI;AACnE,QAAM,WAAW,QACb,2BAA2B;AAAA,IACzB,UAAU;AAAA,IACV,gBAAgB,aAAa;AAAA,IAC7B,WAAW,QAAQ;AAAA,IACnB,wBAAwB,OAAO,cAAc,KAAK,SAAS;AAAA,IAC3D,WAAW,OAAO,aAAa;AAAA,IAC/B,YAAY,OAAO,cAAc;AAAA,IACjC,cAAc,KAAK,iBAAiB;AAAA,IACpC;AAAA,IACA;AAAA,IACA,eAAe,MAAM,KAAK,aAAa;AAAA,EACzC,CAAC,IACD;AACJ,MAAI,SAAS,UAAU;AACrB,UAAM,SAAS,MAAM,mBAAmB,eAAe,MAAM,MAAM,IAAI,QAAQ,CAAC;AAChF,QAAI,OAAQ,QAAO,aAAa,KAAK,MAAM;AAAA,EAC7C;AAEA,QAAM,kCAAkC,uBAAuB,qBAAqB;AAKpF,QAAM,CAAC,SAAS,WAAW,gBAAgB,kBAAkB,UAAU,wBAAwB,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnH,QAAQ,iBACJ;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,IAAI,QAAQ,eAAe;AAAA,QAC3B,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,CAAC;AAAA,MACD;AAAA,IACF,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IACJ,mBACI;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,EAAE,SAAS,EAAE,WAAW,QAAQ,WAAW,OAAO,EAAE;AAAA,MACpD;AAAA,IACF,IACA,QAAQ,QAA2B,CAAC,CAAC;AAAA,IACzC;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,EAAE,UAAU,CAAC,KAAK,EAAE;AAAA,MACpB;AAAA,IACF;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,EAAE,UAAU,CAAC,OAAO,EAAE;AAAA,MACtB;AAAA,IACF;AAAA,IACA,kBACI;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,MAC1B;AAAA,MACA,EAAE,SAAS,EAAE,WAAW,OAAO,GAAG,OAAO,GAAG;AAAA,MAC5C;AAAA,IACF,IACA,QAAQ,QAA2B,CAAC,CAAC;AAAA,IACzC,kCACI;AAAA,MACE;AAAA,MACA;AAAA,MACA,iBAAiB,UACb;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,QACxB,WAAW;AAAA,QACX,GAAG;AAAA,MACL,IACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,QACxB,GAAG;AAAA,MACL;AAAA,MACJ,EAAE,SAAS,EAAE,aAAa,OAAO,WAAW,OAAO,GAAG,OAAO,IAAI;AAAA,MACjE;AAAA,IACF,IACA,QAAQ,QAA+B,CAAC,CAAC;AAAA,EAC/C,CAAC;AACD,QAAM,8BAA8B,yBAAyB,OAAO,CAAC,gBAAgB,CAAC,YAAY,SAAS;AAC3G,QAAM,wBAAwB,kCAC1B,MAAM,6BAA6B;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,wBAAwB,OAAO,cAAc,KAAK,SAAS;AAAA,IAC3D,cAAc;AAAA,IACd,QAAQ;AAAA,EACV,CAAC,IACD,CAAC;AAEL,QAAM,qBACJ,4BAA4B,SAAS,IACjC,4BACG,OAAO,CAAC,gBAAgB,YAAY,WAAW,aAAa,YAAY,oBAAoB,MAAM,EAClG,KAAK,CAAC,MAAM,UAAU;AACrB,UAAM,WAAW,IAAI,KAAK,KAAK,eAAe,KAAK,SAAS,EAAE,QAAQ;AACtE,UAAM,YAAY,IAAI,KAAK,MAAM,eAAe,MAAM,SAAS,EAAE,QAAQ;AACzE,QAAI,aAAa,UAAW,QAAO,KAAK,GAAG,cAAc,MAAM,EAAE;AACjE,WAAO,WAAW;AAAA,EACpB,CAAC,EACA,MAAM,GAAG,mBAAmB,IAC/B,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,iBAAiB,EAAE,KAAK,OAAO;AAAA,MAC/B,GAAG;AAAA,IACL;AAAA,IACA,EAAE,SAAS,EAAE,aAAa,OAAO,WAAW,MAAM,GAAG,OAAO,oBAAoB;AAAA,IAChF;AAAA,EACF;AACN,QAAM,2BAA2B,mBAAmB,SAChD,MAAM,6BAA6B;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,wBAAwB,OAAO,cAAc,KAAK,SAAS;AAAA,IAC3D,cAAc;AAAA,IACd,QAAQ;AAAA,EACV,CAAC,IACD,CAAC;AAEL,QAAM,aAAa,qBAAqB,CAAC,iBAAiB,UACtD,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA,EAAE,SAAS,EAAE,YAAY,QAAQ,WAAW,OAAO,GAAG,OAAO,GAAG;AAAA,IAChE;AAAA,EACF,IACA,CAAC;AACL,QAAM,YAAY,gBAAgB,CAAC,iBAAiB,UAChD,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,MACE,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,gBAAgB,QAAQ;AAAA,IAC1B;AAAA,IACA,EAAE,SAAS,EAAE,WAAW,OAAO,GAAG,OAAO,GAAG;AAAA,IAC5C;AAAA,EACF,IACA,CAAC;AAEL,MAAI,cAAc,oBAAI,IAAwB;AAC9C,MAAI,gBAAgB,CAAC,iBAAiB,WAAW,UAAU,QAAQ;AACjE,UAAM,cAAe,UAAU,QAAQ,aAAa;AACpD,QAAI;AACF,oBAAc,MAAM;AAAA,QAClB;AAAA,QACA;AAAA,QACA,QAAQ,YAAY,KAAK,YAAY;AAAA,QACrC,CAAC,QAAQ,kBAAkB,MAAM,GAAI,OAAO,aAAa,CAAC,CAAE;AAAA,MAC9D;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,2DAA2D,GAAG;AAAA,IAC7E;AAAA,EACF;AAEA,QAAM,6BAA6B,IAAI;AAAA,IACrC,yBACG,OAAO,CAAC,gBAAgB,YAAY,WAAW,4CAA4C,EAC3F,IAAI,CAAC,gBAAgB,YAAY,EAAE;AAAA,EACxC;AACA,QAAM,yBAAyB,IAAI;AAAA,IACjC,yBACG,OAAO,CAAC,gBAAgB,YAAY,WAAW,wCAAwC,EACvF,IAAI,CAAC,gBAAgB,YAAY,EAAE;AAAA,EACxC;AAEA,QAAM,yBAAyB,sBAC5B,OAAO,CAAC,gBAAgB,YAAY,oBAAoB,MAAM,EAC9D,IAAI,CAAC,gBAAgB,sCAAsC,WAAW,CAAC;AAC1E,QAAM,qBAAqB,sBACxB,OAAO,CAAC,gBAAgB,YAAY,oBAAoB,MAAM,EAC9D,IAAI,CAAC,gBAAgB,kCAAkC,WAAW,CAAC;AAEtE,QAAM,YAAY,oBAAI,IAAY;AAClC,MAAI,mBAAmB;AACrB,eAAW,YAAY,YAAY;AACjC,UAAI,SAAS,aAAc,WAAU,IAAI,SAAS,YAAY;AAAA,IAChE;AAAA,EACF;AACA,MAAI,iBAAiB;AACnB,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,aAAc,WAAU,IAAI,QAAQ,YAAY;AAAA,IAC9D;AAAA,EACF;AACA,MAAI,aAAc,WAAU,IAAI,YAAY;AAE5C,MAAI,UAAU,oBAAI,IAA2D;AAC7E,MAAI,UAAU,MAAM;AAClB,UAAM,eAAe,MAAM,KAAK,SAAS;AACzC,UAAM,QAAQ,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,QACE,IAAI,EAAE,KAAK,aAAa;AAAA,QACxB,UAAU,QAAQ;AAAA,MACpB;AAAA,MACA,CAAC;AAAA,MACD;AAAA,IACF;AACA,cAAU,IAAI;AAAA,MACZ,MAAM,IAAI,CAAC,SAAS;AAAA,QAClB,KAAK;AAAA,QACL;AAAA,UACE,MAAM,KAAK,QAAQ;AAAA,UACnB,OAAO,KAAK,SAAS;AAAA,QACvB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,MAAI,QAAwB,CAAC;AAC7B,MAAI,cAAc;AAChB,UAAM,YAAY,MAAM;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS,QAAQ;AAAA,MACnB;AAAA,MACA,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,MACrB;AAAA,IACF;AACA,YAAQ,UACL,IAAI,CAAC,SAAU,KAAK,QAAyC,IAAI,EACjE;AAAA,MACC,CAAC,SACC,CAAC,CAAC,QACF,OAAO,SAAS,YAChB,KAAK,aAAa,QAAQ,YAC1B,KAAK,mBAAmB,QAAQ;AAAA,IACpC;AAAA,EACJ;AAEA,QAAM,sBAAsB,eACxB,SAEE,MAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,MACE,SAAS,QAAQ;AAAA,IACnB;AAAA,IACA,EAAE,UAAU,CAAC,MAAM,EAAE;AAAA,IACrB;AAAA,EACF,GAEC,IAAI,CAAC,SAAU,KAAK,QAAyC,IAAI,EACjE;AAAA,IACC,CAAC,SACC,CAAC,CAAC,QACF,OAAO,SAAS,YAChB,KAAK,aAAa,QAAQ,YAC1B,KAAK,mBAAmB,QAAQ;AAAA,EACpC;AAEN,MAAI,gBAIC,CAAC;AACN,MAAI,eAAe;AACjB,UAAM,wBAAwB;AAAA,MAC5B,UAAU,QAAQ,YAAY,KAAK,YAAY;AAAA,MAC/C,gBAAgB,QAAQ,kBAAkB,OAAO,cAAc,KAAK,SAAS;AAAA,IAC/E;AACA,UAAM,oBAAoB,oBAAI,IAG5B;AACF,UAAM,mBAAmB,MAAM;AAAA,MAC7B;AAAA,MACA;AAAA,QACE,SAAS,QAAQ;AAAA,QACjB,gBAAgB,QAAQ;AAAA,QACxB,UAAU,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AACA,UAAM,eAAe;AAAA,MACnB,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,UACE,UAAU,CAAC,UAAU,sBAAsB;AAAA,UAC3C,SAAS,EAAE,WAAW,QAAQ,WAAW,MAAM;AAAA,QACjD;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,iBAAa,QAAQ,CAAC,SAAS;AAC7B,YAAM,SAAS,OAAO,KAAK,WAAW,WAAW,OAAO,KAAK;AAC7D,UAAI,CAAC,UAAU,OAAO,SAAS,YAAY,OAAO,UAAW;AAC7D,YAAM,gBACJ,OAAO,iBAAiB,OAAO,OAAO,kBAAkB,WACpD,OAAO,gBACP;AACN,wBAAkB,IAAI,OAAO,IAAI;AAAA,QAC/B;AAAA,QACA,SAAS;AAAA,QACT,UAAU,KAAK,qBAAqB,OAAO,KAAK,UAAU,YAAY,IAAI;AAAA,MAC5E,CAAC;AAAA,IACH,CAAC;AAED,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,QACE,SAAS,QAAQ;AAAA,QACjB,UAAU,QAAQ;AAAA,QAClB,gBAAgB,QAAQ;AAAA,QACxB,QAAQ,EAAE,WAAW,KAAK;AAAA,MAC5B;AAAA,MACA,EAAE,UAAU,CAAC,QAAQ,EAAE;AAAA,MACvB;AAAA,IACF;AACA,aAAS,QAAQ,CAAC,UAAU;AAC1B,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,UAAU,OAAO,SAAS,YAAY,OAAO,UAAW;AAC7D,UAAI,CAAC,kBAAkB,IAAI,OAAO,EAAE,GAAG;AACrC,0BAAkB,IAAI,OAAO,IAAI;AAAA,UAC/B;AAAA,UACA,SAAS,SAAS;AAAA,UAClB,UAAU,MAAM,qBAAqB,OAAO,MAAM,UAAU,YAAY,IAAI;AAAA,QAC9E,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,oBAAgB,MAAM,KAAK,kBAAkB,OAAO,CAAC;AAAA,EACvD;AAKA,QAAM,YAAY,SAAS,MAAM;AACjC,QAAM,CAAC,yBAAyB,0BAA0B,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,IACrF,sBAAsB;AAAA,MACpB;AAAA,MACA,UAAU,EAAE,UAAU;AAAA,MACtB,WAAW,CAAC,QAAQ,EAAE;AAAA,MACtB,kBAAkB,EAAE,CAAC,QAAQ,EAAE,GAAG,QAAQ,YAAY,KAAK;AAAA,MAC3D,wBAAwB,EAAE,CAAC,QAAQ,EAAE,GAAG,QAAQ,kBAAkB,KAAK;AAAA,MACvE,iBAAiB;AAAA,QACf,QAAQ,YAAY,KAAK,YAAY;AAAA,MACvC,EAAE,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AAAA,IAClC,CAAC;AAAA,IACD,YACI,sBAAsB;AAAA,MACpB;AAAA,MACA,UAAU,EAAE,UAAU;AAAA,MACtB,WAAW,CAAC,SAAS;AAAA,MACrB,kBAAkB,EAAE,CAAC,SAAS,GAAG,SAAS,YAAY,KAAK;AAAA,MAC3D,wBAAwB,EAAE,CAAC,SAAS,GAAG,SAAS,kBAAkB,KAAK;AAAA,MACvE,iBAAiB;AAAA,QACf,SAAS,YAAY,QAAQ,YAAY,KAAK,YAAY;AAAA,MAC5D,EAAE,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AAAA,IAClC,CAAC,IACD,QAAQ,QAAiD,CAAC,CAAC;AAAA,IAC/D,iCAAiC,IAAI,QAAQ,YAAY,MAAM,QAAQ,kBAAkB,IAAI;AAAA,EAC/F,CAAC;AACD,QAAM,eAAe;AAAA,IACnB;AAAA,MACE;AAAA,MACA,0BAA0B,QAAQ,EAAE,KAAK,CAAC;AAAA,MAC1C,YAAY,2BAA2B,SAAS,KAAK,CAAC,IAAI,CAAC;AAAA,IAC7D;AAAA,EACF;AAMA,QAAM,mBAAmB,gBACrB,QAAQ,QAAQ,cAAc,MAAM,KACnC,YAAY;AACX,UAAM,kBAAkB,MAAM;AAAA,MAC5B;AAAA,MACA;AAAA,QACE,SAAS,QAAQ;AAAA,QACjB,gBAAgB,QAAQ;AAAA,QACxB,UAAU,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM;AAAA,QACJ;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC;AAAA,QACD,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AAAA,MACvE;AAAA,IACF,EAAE;AAAA,EACJ,GAAG;AACP,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpB,GAAG,MAAM,qBAAqB;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,WAAW;AAAA,MACX,iBAAiB,EAAE,KAAK,OAAO;AAAA,MAC/B,GAAG;AAAA,IACL,CAAC;AAAA,IACD,GAAG,MAAM,qBAAqB;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,WAAW;AAAA,MACX,GAAG;AAAA,IACL,CAAC;AAAA,IACD,iBAAiB,UACb,GAAG,MAAM,qBAAqB;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,WAAW;AAAA,MACX,iBAAiB;AAAA,IACnB,CAAC,IACD,GAAG,MAAM,kBAAkB;AAAA,MACzB,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,IACpB,CAAC;AAAA,IACL,kBACI,QAAQ,QAAQ,SAAS,MAAM,IAC/B,GAAG,MAAM,iBAAiB;AAAA,MACxB,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,IACpB,CAAC;AAAA,IACL,mBACI,QAAQ,QAAQ,UAAU,MAAM,IAChC,GAAG,MAAM,iBAAiB;AAAA,MACxB,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,IACpB,CAAC;AAAA,IACL;AAAA,IACA,4BAA4B,SACxB,QAAQ,QAAQ,2BAA2B,IAC3C;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,gBAAgB,QAAQ;AAAA,QACxB,UAAU,QAAQ;AAAA,QAClB,WAAW;AAAA,QACX,GAAG;AAAA,MACL;AAAA,MACA;AAAA,QACE,QAAQ,CAAC,MAAM,cAAc,eAAe,WAAW;AAAA,QACvD,SAAS,EAAE,WAAW,OAAO;AAAA,MAC/B;AAAA,MACA,EAAE,UAAU,QAAQ,UAAU,gBAAgB,QAAQ,eAAe;AAAA,IACvE;AAAA,EACN,CAAC;AACD,QAAM,gBAAgB;AAAA,IACpB,mBACG,IAAI,CAAC,gBAAgB,YAAY,cAAc,YAAY,eAAe,YAAY,SAAS,EAC/F,IAAI,CAAC,UAAW,iBAAiB,OAAO,MAAM,YAAY,IAAI,OAAO,UAAU,WAAW,QAAQ,EAAG,EACrG,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AAAA,EACvC;AACA,QAAM,cAAc,oBAAoB;AAAA,IACtC,CAAC,SAAS,KAAK,WAAW,SAAS,KAAK,WAAW,UAAU,KAAK,WAAW;AAAA,EAC/E;AACA,QAAM,WAAW,oBAAoB,OAAO,CAAC,SAAS,KAAK,WAAW,KAAK;AAC3E,QAAM,mBAAmB,YAAY,OAAO,CAAC,KAAK,SAAS,OAAO,gBAAgB,KAAK,WAAW,KAAK,IAAI,CAAC;AAC5G,QAAM,WAAW,SAAS,SACtB,SAAS,OAAO,CAAC,KAAK,SAAS,OAAO,gBAAgB,KAAK,WAAW,KAAK,IAAI,CAAC,IAChF;AACJ,QAAM,0BAA0B,mBAAmB,OAAsB,CAAC,UAAU,gBAAgB;AAClG,UAAM,YAAY,YAAY,cAAc,YAAY,eAAe,YAAY;AACnF,UAAM,OAAO,qBAAqB,OAAO,UAAU,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,QAAQ;AAC3F,QAAI,OAAO,MAAM,IAAI,EAAG,QAAO;AAC/B,QAAI,aAAa,KAAM,QAAO;AAC9B,WAAO,KAAK,IAAI,UAAU,IAAI;AAAA,EAChC,GAAG,IAAI;AACP,QAAM,cAAuC;AAAA,IAC3C,kBAAkB,YAAY;AAAA,IAC9B,kBAAkB,YAAY,SAAS,mBAAmB;AAAA,IAC1D,cACE,YAAY,CAAC,GAAG,iBAChB,oBAAoB,CAAC,GAAG,iBACxB;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAqB,SAAS;AAAA,IAC9B,mBACE,4BAA4B,OACxB,OACA,KAAK,OAAO,KAAK,IAAI,IAAI,4BAA4B,SAAS,MAAW;AAAA,EACjF;AACA,QAAM,SAAS;AAAA,IACb,MAAM,eAAe,SAAS,iBAAiB;AAAA,IAC/C,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,OAAO;AAAA,IACP,OAAO,eAAe,MAAM,SAAS,oBAAoB;AAAA,IACzD,QAAQ;AAAA,IACR,WAAW;AAAA,EACb;AAEA,QAAM,UAAU;AAAA,IACd;AAAA,IACA,SAAS;AAAA,MACP,IAAI,QAAQ;AAAA,MACZ,aAAa,QAAQ;AAAA,MACrB,aAAa,QAAQ;AAAA,MACrB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ;AAAA,MACtB,cAAc,QAAQ;AAAA,MACtB,QAAQ,QAAQ;AAAA,MAChB,gBAAgB,QAAQ;AAAA,MACxB,QAAQ,QAAQ;AAAA,MAChB,mBAAmB,QAAQ,oBAAoB,QAAQ,kBAAkB,YAAY,IAAI;AAAA,MACzF,qBAAqB,QAAQ;AAAA,MAC7B,sBAAsB,QAAQ;AAAA,MAC9B,qBAAqB,QAAQ;AAAA,MAC7B,sBAAsB,QAAQ;AAAA,MAC9B,gBAAgB,QAAQ;AAAA,MACxB,UAAU,QAAQ;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,aAAa,QAAQ,eAAe;AAAA,MACpC,gBAAgB,QAAQ,kBAAkB;AAAA,MAC1C,WAAW,QAAQ,UAAU,YAAY;AAAA,MACzC,WAAW,QAAQ,UAAU,YAAY;AAAA,IAC3C;AAAA,IACA,SAAS,UACL;AAAA,MACE,IAAI,QAAQ;AAAA,MACZ,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,MACpB,UAAU,QAAQ;AAAA,MAClB,YAAY,QAAQ;AAAA,MACpB,eAAe,QAAQ;AAAA,IACzB,IACA;AAAA,IACJ;AAAA,IACA,MAAM;AAAA,MACJ,GAAG,cAAc,cAAc;AAAA,MAC/B,GAAG,iBACA,IAAI,CAAC,eAAe;AACnB,cAAM,QAAQ,WAAW;AACzB,YAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,eAAO,EAAE,IAAI,MAAM,IAAI,OAAO,MAAM,OAAO,OAAO,KAAK;AAAA,MACzD,CAAC,EACA,OAAO,CAAC,QAA2D,QAAQ,IAAI;AAAA,IACpF;AAAA,IACA,WAAW,mBACP,UAAU,IAAI,CAAC,aAAa;AAAA,MAC1B,IAAI,QAAQ;AAAA,MACZ,MAAM,QAAQ;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB,cAAc,QAAQ;AAAA,MACtB,cAAc,QAAQ;AAAA,MACtB,gBAAgB,QAAQ;AAAA,MACxB,YAAY,QAAQ;AAAA,MACpB,MAAM,QAAQ;AAAA,MACd,QAAQ,QAAQ;AAAA,MAChB,YAAY,QAAQ;AAAA,MACpB,SAAS,QAAQ;AAAA,MACjB,UAAU,QAAQ;AAAA,MAClB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ;AAAA,MACnB,WAAW,QAAQ,UAAU,YAAY;AAAA,IAC3C,EAAE,IACF,CAAC;AAAA,IACL,UAAU,kBACN,SAAS,IAAI,CAAC,YAAY;AACxB,YAAM,aAAa,QAAQ,eAAe,QAAQ,IAAI,QAAQ,YAAY,IAAI;AAC9E,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,MAAM,QAAQ;AAAA,QACd,cAAc,QAAQ;AAAA,QACtB,YAAY,QAAQ,eAAe,YAAY,QAAQ,OAAO;AAAA,QAC9D,aAAa,QAAQ,eAAe,YAAY,SAAS,OAAO;AAAA,QAChE,QAAQ,QAAQ,OAAQ,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO,QAAQ,KAAK,KAAM;AAAA,QAC7F,WAAW,QAAQ,UAAU,YAAY;AAAA,QACzC,gBAAgB,QAAQ,kBAAkB;AAAA,QAC1C,iBAAiB,QAAQ,mBAAmB;AAAA,MAC9C;AAAA,IACF,CAAC,IACD,CAAC;AAAA,IACL,YAAY,oBAEN,iBAAiB,UACb,yBACA;AAAA,MACE,GAAG,WACA,OAAO,CAAC,aAAa,CAAC,2BAA2B,IAAI,SAAS,EAAE,CAAC,EACjE,IAAI,CAAC,cAAc;AAAA,QAClB,IAAI,SAAS;AAAA,QACb,cAAc,SAAS;AAAA,QACvB,SAAS,SAAS;AAAA,QAClB,MAAM,SAAS;AAAA,QACf,YAAY,SAAS,aAAa,SAAS,WAAW,YAAY,IAAI;AAAA,QACtE,QAAQ,SAAS,OAAQ,OAAO,SAAS,SAAS,WAAW,SAAS,OAAO,SAAS,KAAK,KAAM;AAAA,QACjG,cAAc,SAAS;AAAA,QACvB,YAAY,SAAS,eAAe,QAAQ,IAAI,SAAS,YAAY,GAAG,QAAQ,OAAO;AAAA,QACvF,aAAa,SAAS,eAAe,QAAQ,IAAI,SAAS,YAAY,GAAG,SAAS,OAAO;AAAA,QACzF,WAAW,SAAS,UAAU,YAAY;AAAA,QAC1C,gBAAgB,SAAS,kBAAkB;AAAA,QAC3C,iBAAiB,SAAS,mBAAmB;AAAA,MAC/C,EAAE;AAAA,MACJ,GAAG,uBAAuB;AAAA,QACxB,CAAC,aACC,sBAAsB;AAAA,UACpB,CAAC,gBACC,YAAY,OAAO,SAAS,MAC5B,YAAY,WAAW;AAAA,QAC3B;AAAA,MACJ;AAAA,IACF,EAAE,KAAK,CAAC,MAAM,UAAU;AACtB,YAAM,WAAW,IAAI,KAAK,KAAK,cAAc,KAAK,SAAS,EAAE,QAAQ;AACrE,YAAM,YAAY,IAAI,KAAK,MAAM,cAAc,MAAM,SAAS,EAAE,QAAQ;AACxE,UAAI,aAAa,UAAW,QAAO,MAAM,GAAG,cAAc,KAAK,EAAE;AACjE,aAAO,YAAY;AAAA,IACrB,CAAC,EAAE,MAAM,GAAG,EAAE,IAEpB,CAAC;AAAA,IACL,cAAc,sBACV,wBACA,CAAC;AAAA,IACH,OAAO,eACH,MAAM,IAAI,CAAC,UAAU;AAAA,MACnB,IAAI,KAAK;AAAA,MACT,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK;AAAA,MACpB,YAAY,KAAK,cAAc;AAAA,MAC/B,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,aAAa,KAAK;AAAA,MAClB,eAAe,KAAK;AAAA,MACpB,aAAa,KAAK;AAAA,MACpB,iBAAiB,KAAK,kBAAkB,KAAK,gBAAgB,YAAY,IAAI;AAAA,MAC7E,aAAa,KAAK;AAAA,MAClB,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK,UAAU,YAAY;AAAA,MACtC,WAAW,KAAK,UAAU,YAAY;AAAA,IACxC,EAAE,IACF,CAAC;AAAA,IACL,OAAO,eAED,iBAAiB,UACb,qBACA;AAAA,MACI,GAAG,UACA,OAAO,CAAC,SAAS,CAAC,uBAAuB,IAAI,KAAK,MAAM,CAAC,EACzD,IAAI,CAAC,SAAS;AACb,cAAM,SAAS,OAAO,KAAK,eAAe,YAAY,KAAK,WAAW,KAAK,EAAE,SAAS,IAAI,KAAK,aAAa;AAC9G,cAAM,MAAM,GAAG,MAAM,IAAI,KAAK,MAAM;AACpC,cAAM,SAAS,YAAY,IAAI,GAAG;AAClC,eAAO;AAAA,UACL,IAAI,KAAK;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,YAAY;AAAA,UACZ,WAAW,KAAK,UAAU,YAAY;AAAA,UACtC,iBAAiB,KAAK;AAAA,UACtB,OAAO,QAAQ,SAAS;AAAA,UACxB,QAAQ,QAAQ,UAAU;AAAA,UAC1B,UAAU,QAAQ,YAAY;AAAA,UAC9B,UAAU,QAAQ,YAAY;AAAA,UAC9B,aAAa,QAAQ,eAAe;AAAA,UACpC,OAAO,QAAQ,SAAS;AAAA,UACxB,oBAAoB,QAAQ,kBAAkB;AAAA,UAC9C,cAAc,QAAQ,gBAAgB;AAAA,QACxC;AAAA,MACF,CAAC;AAAA,MACH,GAAG,mBAAmB;AAAA,QACpB,CAAC,SACC,sBAAsB;AAAA,UACpB,CAAC,gBACC,YAAY,OAAO,KAAK,UACxB,YAAY,WAAW;AAAA,QAC3B;AAAA,MACJ;AAAA,IACF,EAAE,KAAK,CAAC,MAAM,UAAU;AACtB,YAAM,WAAW,IAAI,KAAK,KAAK,SAAS,EAAE,QAAQ;AAClD,YAAM,YAAY,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ;AACpD,UAAI,aAAa,UAAW,QAAO,MAAM,GAAG,cAAc,KAAK,EAAE;AACjE,aAAO,YAAY;AAAA,IACrB,CAAC,EAAE,MAAM,GAAG,EAAE,IAEpB,CAAC;AAAA,IACL,QAAQ,gBACJ,cAAc,IAAI,CAAC,EAAE,QAAQ,SAAS,eAAe,SAAS,OAAO;AAAA,MACnE,IAAI,OAAO;AAAA,MACX,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO,gBAAgB;AAAA,MACrC,cAAc,OAAO,gBAAgB;AAAA,MACrC,QAAQ,OAAO,UAAU;AAAA,MACzB,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,UAAU,eAAe,YAAY;AAAA,MACrC,YAAY,eAAe,cAAc;AAAA,MACzC,WAAW,OAAO,UAAU,YAAY;AAAA,MACxC,gBAAgB,OAAO;AAAA,MACvB,QAAQ,OAAO,UAAU;AAAA,MACzB,aAAa,OAAO,eAAe;AAAA,MACnC;AAAA,IACF,EAAE,IACF,CAAC;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,QAAQ;AAAA,MACN,QAAQ;AAAA,MACR,MAAM,eAAe,QAAQ,IAAI,YAAY,GAAG,QAAQ,OAAO;AAAA,MAC/D,OAAO,eAAe,QAAQ,IAAI,YAAY,GAAG,SAAS,KAAK,SAAS,OAAO,KAAK,SAAS;AAAA,IAC/F;AAAA,EACF;AAEA,MAAI,SAAS,UAAU;AACrB,QAAI;AACF,YAAM;AAAA,QAAmB;AAAA,QAAe,MACtC,MAAM,IAAI,UAAU,SAAS;AAAA,UAC3B,KAAK;AAAA,UACL,MAAM,4BAA4B,eAAe,aAAa,cAAc;AAAA,QAC9E,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,cAAQ,KAAK,4DAA4D,GAAG;AAAA,IAC9E;AAAA,EACF;AAEA,SAAO,aAAa,KAAK,OAAO;AAClC;AAEA,MAAM,2BAA2B,EAAE,OAAO;AAAA,EACxC,SAAS,EACN,OAAO,EACP,SAAS,EACT,SAAS,qHAAqH;AACnI,CAAC,EAAE,YAAY;AAEf,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAC3C,iBAAiB,EAAE,KAAK,CAAC,aAAa,QAAQ,CAAC;AAAA,EAC/C,SAAS,EAAE,OAAO;AAAA,IAChB,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,IACpB,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC5C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC5C,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,IACnD,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC7C,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC7C,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACvC,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC/C,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACvC,mBAAmB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAClD,qBAAqB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACpD,sBAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACrD,qBAAqB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACpD,sBAAsB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACrD,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,IACtD,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,IAChD,UAAU,EAAE,QAAQ,EAAE,SAAS;AAAA,IAC/B,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC5C,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC/C,WAAW,EAAE,OAAO;AAAA,IACpB,WAAW,EAAE,OAAO;AAAA,EACtB,CAAC;AAAA,EACD,SAAS,EACN,OAAO;AAAA,IACN,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,IACpB,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC1C,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC1C,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACvC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC3C,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACzC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC3C,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAChD,CAAC,EACA,SAAS;AAAA,EACZ,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAAA,EAC9C,MAAM,EAAE;AAAA,IACN,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,OAAO,EAAE,OAAO;AAAA,MAChB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IACxC,CAAC;AAAA,EACH;AAAA,EACA,WAAW,EAAE;AAAA,IACX,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACrC,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACxC,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC7C,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC7C,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC/C,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACrC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACxC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACzC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC1C,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,WAAW,EAAE,OAAO;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EACA,UAAU,EAAE;AAAA,IACV,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACrC,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACpD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAC9C,WAAW,EAAE,OAAO;AAAA,MACpB,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC/C,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAClD,CAAC;AAAA,EACH;AAAA,EACA,YAAY,EAAE;AAAA,IACZ,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,cAAc,EAAE,OAAO;AAAA,MACvB,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACxC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACrC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAC9C,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACpD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,WAAW,EAAE,OAAO;AAAA,MACpB,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC/C,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAClD,CAAC;AAAA,EACH;AAAA,EACA,cAAc,EAAE;AAAA,IACd,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAChD,iBAAiB,EAAE,OAAO;AAAA,MAC1B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACtC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACrC,QAAQ,EAAE,OAAO;AAAA,MACjB,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACzC,cAAc,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACpD,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACnD,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAC9C,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACtD,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAChD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC1C,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,MACpE,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC/C,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAChD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,MAC1D,WAAW,EAAE,OAAO;AAAA,MACpB,WAAW,EAAE,OAAO;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EACA,OAAO,EAAE;AAAA,IACP,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACtC,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC9C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC9C,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAChD,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACnD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,WAAW,EAAE,OAAO;AAAA,MACpB,WAAW,EAAE,OAAO;AAAA,IACtB,CAAC;AAAA,EACH;AAAA,EACA,OAAO,EAAE;AAAA,IACP,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,MACxB,YAAY,EAAE,OAAO;AAAA,MACrB,WAAW,EAAE,OAAO;AAAA,MACpB,iBAAiB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACvD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACtC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS;AAAA,MACxC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACzC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACzC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACtC,oBAAoB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MAC1D,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS;AAAA,IACtE,CAAC;AAAA,EACH;AAAA,EACA,QAAQ,EAAE;AAAA,IACR,EAAE,OAAO;AAAA,MACP,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,MACpB,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC7C,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC7C,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC/C,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACzC,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC3C,WAAW,EAAE,OAAO;AAAA,MACpB,gBAAgB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,MACtD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MACvC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,MAC5C,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA,EACA,QAAQ,EAAE,OAAO;AAAA,IACf,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,IACnC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,CAAC;AACH,CAAC;AAED,MAAM,2BAA2B,EAAE,OAAO;AAAA,EACxC,OAAO,EAAE,OAAO;AAClB,CAAC;AAEM,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,aAAa;AAAA,MACb,OAAO;AAAA,MACP,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,0BAA0B,QAAQ,4BAA4B;AAAA,MAC5F;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,sBAAsB,QAAQ,yBAAyB;AAAA,QACnF,EAAE,QAAQ,KAAK,aAAa,gBAAgB,QAAQ,yBAAyB;AAAA,QAC7E,EAAE,QAAQ,KAAK,aAAa,2CAA2C,QAAQ,yBAAyB;AAAA,QACxG,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,yBAAyB;AAAA,MACpF;AAAA,IACF;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.6-develop.6367.1.2321ccacd4",
3
+ "version": "0.6.6-develop.6370.1.efeac59f8b",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -246,16 +246,16 @@
246
246
  "zod": "^4.4.3"
247
247
  },
248
248
  "peerDependencies": {
249
- "@open-mercato/ai-assistant": "0.6.6-develop.6367.1.2321ccacd4",
250
- "@open-mercato/shared": "0.6.6-develop.6367.1.2321ccacd4",
251
- "@open-mercato/ui": "0.6.6-develop.6367.1.2321ccacd4",
249
+ "@open-mercato/ai-assistant": "0.6.6-develop.6370.1.efeac59f8b",
250
+ "@open-mercato/shared": "0.6.6-develop.6370.1.efeac59f8b",
251
+ "@open-mercato/ui": "0.6.6-develop.6370.1.efeac59f8b",
252
252
  "react": "^19.0.0",
253
253
  "react-dom": "^19.0.0"
254
254
  },
255
255
  "devDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.6-develop.6367.1.2321ccacd4",
257
- "@open-mercato/shared": "0.6.6-develop.6367.1.2321ccacd4",
258
- "@open-mercato/ui": "0.6.6-develop.6367.1.2321ccacd4",
256
+ "@open-mercato/ai-assistant": "0.6.6-develop.6370.1.efeac59f8b",
257
+ "@open-mercato/shared": "0.6.6-develop.6370.1.efeac59f8b",
258
+ "@open-mercato/ui": "0.6.6-develop.6370.1.efeac59f8b",
259
259
  "@testing-library/dom": "^10.4.1",
260
260
  "@testing-library/jest-dom": "^6.9.1",
261
261
  "@testing-library/react": "^16.3.1",
@@ -103,88 +103,88 @@
103
103
  "customer_accounts.admin.flash.deactivated": "User deactivated",
104
104
  "customer_accounts.admin.flash.deleted": "User deleted",
105
105
  "customer_accounts.admin.inactive": "Inactive",
106
- "customer_accounts.admin.portalFeatures.addresses.manage": "Manage addresses",
107
- "customer_accounts.admin.portalFeatures.addresses.view": "View addresses",
108
- "customer_accounts.admin.portalFeatures.groups.addresses": "Addresses",
109
- "customer_accounts.admin.portalFeatures.groups.invoices": "Invoices",
110
- "customer_accounts.admin.portalFeatures.groups.orders": "Orders",
111
- "customer_accounts.admin.portalFeatures.groups.profile": "Profile",
112
- "customer_accounts.admin.portalFeatures.groups.quotes": "Quotes",
113
- "customer_accounts.admin.portalFeatures.groups.users": "Users",
114
- "customer_accounts.admin.portalFeatures.invoices.view": "View invoices",
115
- "customer_accounts.admin.portalFeatures.orders.create": "Create orders",
116
- "customer_accounts.admin.portalFeatures.orders.view": "View orders",
117
- "customer_accounts.admin.portalFeatures.profile.edit": "Edit profile",
118
- "customer_accounts.admin.portalFeatures.profile.view": "View profile",
119
- "customer_accounts.admin.portalFeatures.quotes.request": "Request quotes",
120
- "customer_accounts.admin.portalFeatures.quotes.view": "View quotes",
121
- "customer_accounts.admin.portalFeatures.users.invite": "Invite team members",
122
- "customer_accounts.admin.portalFeatures.users.manage": "Manage team members",
123
- "customer_accounts.admin.portalFeatures.users.view": "View team members",
106
+ "customer_accounts.admin.portalFeatures.addresses.manage": "Adressen verwalten",
107
+ "customer_accounts.admin.portalFeatures.addresses.view": "Adressen anzeigen",
108
+ "customer_accounts.admin.portalFeatures.groups.addresses": "Adressen",
109
+ "customer_accounts.admin.portalFeatures.groups.invoices": "Rechnungen",
110
+ "customer_accounts.admin.portalFeatures.groups.orders": "Bestellungen",
111
+ "customer_accounts.admin.portalFeatures.groups.profile": "Profil",
112
+ "customer_accounts.admin.portalFeatures.groups.quotes": "Angebote",
113
+ "customer_accounts.admin.portalFeatures.groups.users": "Benutzer",
114
+ "customer_accounts.admin.portalFeatures.invoices.view": "Rechnungen anzeigen",
115
+ "customer_accounts.admin.portalFeatures.orders.create": "Bestellungen erstellen",
116
+ "customer_accounts.admin.portalFeatures.orders.view": "Bestellungen anzeigen",
117
+ "customer_accounts.admin.portalFeatures.profile.edit": "Profil bearbeiten",
118
+ "customer_accounts.admin.portalFeatures.profile.view": "Profil anzeigen",
119
+ "customer_accounts.admin.portalFeatures.quotes.request": "Angebote anfordern",
120
+ "customer_accounts.admin.portalFeatures.quotes.view": "Angebote anzeigen",
121
+ "customer_accounts.admin.portalFeatures.users.invite": "Teammitglieder einladen",
122
+ "customer_accounts.admin.portalFeatures.users.manage": "Teammitglieder verwalten",
123
+ "customer_accounts.admin.portalFeatures.users.view": "Teammitglieder anzeigen",
124
124
  "customer_accounts.admin.portalInfo.credentials": "Demo credentials: alice.johnson@example.com / Password123!",
125
125
  "customer_accounts.admin.portalInfo.description": "Manage customer portal accounts. Customers can self-register, log in, and access orders, quotes, and invoices through the portal.",
126
126
  "customer_accounts.admin.portalInfo.open": "Open Portal",
127
127
  "customer_accounts.admin.portalInfo.openConfiguration": "Open Configuration",
128
128
  "customer_accounts.admin.portalInfo.title": "Customer Portal",
129
129
  "customer_accounts.admin.portalInfo.url": "Portal URL: {url}",
130
- "customer_accounts.admin.roleCreate.actions.cancel": "Cancel",
131
- "customer_accounts.admin.roleCreate.actions.create": "Create Role",
132
- "customer_accounts.admin.roleCreate.actions.saving": "Creating...",
133
- "customer_accounts.admin.roleCreate.error.nameRequired": "Name is required",
134
- "customer_accounts.admin.roleCreate.error.required": "Name and slug are required",
135
- "customer_accounts.admin.roleCreate.error.save": "Failed to create role",
136
- "customer_accounts.admin.roleCreate.error.slugFormat": "Slug must contain only lowercase letters, numbers, hyphens, and underscores",
137
- "customer_accounts.admin.roleCreate.error.slugRequired": "Slug is required",
138
- "customer_accounts.admin.roleCreate.fields.customerAssignable": "Customers can self-assign",
139
- "customer_accounts.admin.roleCreate.fields.description": "Description",
140
- "customer_accounts.admin.roleCreate.fields.isDefault": "Default role (auto-assigned to new users)",
130
+ "customer_accounts.admin.roleCreate.actions.cancel": "Abbrechen",
131
+ "customer_accounts.admin.roleCreate.actions.create": "Rolle erstellen",
132
+ "customer_accounts.admin.roleCreate.actions.saving": "Erstellen...",
133
+ "customer_accounts.admin.roleCreate.error.nameRequired": "Name ist erforderlich",
134
+ "customer_accounts.admin.roleCreate.error.required": "Name und Slug sind erforderlich",
135
+ "customer_accounts.admin.roleCreate.error.save": "Rolle konnte nicht erstellt werden",
136
+ "customer_accounts.admin.roleCreate.error.slugFormat": "Slug darf nur Kleinbuchstaben, Zahlen, Bindestriche und Unterstriche enthalten",
137
+ "customer_accounts.admin.roleCreate.error.slugRequired": "Slug ist erforderlich",
138
+ "customer_accounts.admin.roleCreate.fields.customerAssignable": "Kunden können sich selbst zuweisen",
139
+ "customer_accounts.admin.roleCreate.fields.description": "Beschreibung",
140
+ "customer_accounts.admin.roleCreate.fields.isDefault": "Standardrolle (wird neuen Benutzern automatisch zugewiesen)",
141
141
  "customer_accounts.admin.roleCreate.fields.name": "Name",
142
- "customer_accounts.admin.roleCreate.fields.namePlaceholder": "e.g. Buyer",
142
+ "customer_accounts.admin.roleCreate.fields.namePlaceholder": "z. B. Käufer",
143
143
  "customer_accounts.admin.roleCreate.fields.slug": "Slug",
144
- "customer_accounts.admin.roleCreate.fields.slugHint": "Lowercase letters, numbers, hyphens, and underscores only.",
145
- "customer_accounts.admin.roleCreate.fields.slugPlaceholder": "e.g. buyer",
146
- "customer_accounts.admin.roleCreate.flash.created": "Role created",
147
- "customer_accounts.admin.roleCreate.sections.details": "Role Details",
148
- "customer_accounts.admin.roleCreate.sections.options": "Options",
149
- "customer_accounts.admin.roleCreate.title": "Create Customer Role",
150
- "customer_accounts.admin.roleDetail.actions.backToList": "Back to roles",
151
- "customer_accounts.admin.roleDetail.actions.cancel": "Cancel",
152
- "customer_accounts.admin.roleDetail.actions.delete": "Delete",
153
- "customer_accounts.admin.roleDetail.actions.save": "Save Changes",
154
- "customer_accounts.admin.roleDetail.actions.saving": "Saving...",
155
- "customer_accounts.admin.roleDetail.error.load": "Failed to load role",
156
- "customer_accounts.admin.roleDetail.error.notFound": "Role not found",
157
- "customer_accounts.admin.roleDetail.error.save": "Failed to save role",
158
- "customer_accounts.admin.roleDetail.error.saveAcl": "Failed to save permissions",
159
- "customer_accounts.admin.roleDetail.fields.customerAssignable": "Customers can self-assign",
160
- "customer_accounts.admin.roleDetail.fields.description": "Description",
161
- "customer_accounts.admin.roleDetail.fields.isDefault": "Default role (auto-assigned to new users)",
144
+ "customer_accounts.admin.roleCreate.fields.slugHint": "Nur Kleinbuchstaben, Zahlen, Bindestriche und Unterstriche.",
145
+ "customer_accounts.admin.roleCreate.fields.slugPlaceholder": "z. B. kaeufer",
146
+ "customer_accounts.admin.roleCreate.flash.created": "Rolle erstellt",
147
+ "customer_accounts.admin.roleCreate.sections.details": "Rollendetails",
148
+ "customer_accounts.admin.roleCreate.sections.options": "Optionen",
149
+ "customer_accounts.admin.roleCreate.title": "Kundenrolle erstellen",
150
+ "customer_accounts.admin.roleDetail.actions.backToList": "Zurück zu Rollen",
151
+ "customer_accounts.admin.roleDetail.actions.cancel": "Abbrechen",
152
+ "customer_accounts.admin.roleDetail.actions.delete": "Löschen",
153
+ "customer_accounts.admin.roleDetail.actions.save": "Änderungen speichern",
154
+ "customer_accounts.admin.roleDetail.actions.saving": "Speichern...",
155
+ "customer_accounts.admin.roleDetail.error.load": "Rolle konnte nicht geladen werden",
156
+ "customer_accounts.admin.roleDetail.error.notFound": "Rolle nicht gefunden",
157
+ "customer_accounts.admin.roleDetail.error.save": "Rolle konnte nicht gespeichert werden",
158
+ "customer_accounts.admin.roleDetail.error.saveAcl": "Berechtigungen konnten nicht gespeichert werden",
159
+ "customer_accounts.admin.roleDetail.fields.customerAssignable": "Kunden können sich selbst zuweisen",
160
+ "customer_accounts.admin.roleDetail.fields.description": "Beschreibung",
161
+ "customer_accounts.admin.roleDetail.fields.isDefault": "Standardrolle (wird neuen Benutzern automatisch zugewiesen)",
162
162
  "customer_accounts.admin.roleDetail.fields.name": "Name",
163
- "customer_accounts.admin.roleDetail.flash.saved": "Role updated",
164
- "customer_accounts.admin.roleDetail.loading": "Loading role...",
165
- "customer_accounts.admin.roleDetail.sections.details": "Role Details",
166
- "customer_accounts.admin.roleDetail.sections.options": "Options",
167
- "customer_accounts.admin.roleDetail.sections.permissions": "Portal Permissions",
168
- "customer_accounts.admin.roleDetail.selectAll": "Select all",
169
- "customer_accounts.admin.roles": "Roles",
170
- "customer_accounts.admin.roles.actions.create": "Create Role",
171
- "customer_accounts.admin.roles.actions.delete": "Delete",
172
- "customer_accounts.admin.roles.actions.edit": "Edit",
173
- "customer_accounts.admin.roles.assignable": "Yes",
174
- "customer_accounts.admin.roles.columns.customerAssignable": "Self-assignable",
175
- "customer_accounts.admin.roles.columns.description": "Description",
176
- "customer_accounts.admin.roles.columns.isDefault": "Default",
163
+ "customer_accounts.admin.roleDetail.flash.saved": "Rolle aktualisiert",
164
+ "customer_accounts.admin.roleDetail.loading": "Rolle wird geladen...",
165
+ "customer_accounts.admin.roleDetail.sections.details": "Rollendetails",
166
+ "customer_accounts.admin.roleDetail.sections.options": "Optionen",
167
+ "customer_accounts.admin.roleDetail.sections.permissions": "Portal-Berechtigungen",
168
+ "customer_accounts.admin.roleDetail.selectAll": "Alle auswählen",
169
+ "customer_accounts.admin.roles": "Rollen",
170
+ "customer_accounts.admin.roles.actions.create": "Rolle erstellen",
171
+ "customer_accounts.admin.roles.actions.delete": "Löschen",
172
+ "customer_accounts.admin.roles.actions.edit": "Bearbeiten",
173
+ "customer_accounts.admin.roles.assignable": "Ja",
174
+ "customer_accounts.admin.roles.columns.customerAssignable": "Selbst zuweisbar",
175
+ "customer_accounts.admin.roles.columns.description": "Beschreibung",
176
+ "customer_accounts.admin.roles.columns.isDefault": "Standard",
177
177
  "customer_accounts.admin.roles.columns.isSystem": "System",
178
178
  "customer_accounts.admin.roles.columns.name": "Name",
179
179
  "customer_accounts.admin.roles.columns.slug": "Slug",
180
- "customer_accounts.admin.roles.confirm.delete": "Delete role \"{{name}}\"?",
181
- "customer_accounts.admin.roles.default": "Default",
182
- "customer_accounts.admin.roles.error.delete": "Failed to delete role",
183
- "customer_accounts.admin.roles.error.deleteSystem": "System roles cannot be deleted",
184
- "customer_accounts.admin.roles.error.load": "Failed to load roles",
185
- "customer_accounts.admin.roles.flash.deleted": "Role deleted",
186
- "customer_accounts.admin.roles.notAssignable": "No",
187
- "customer_accounts.admin.roles.searchPlaceholder": "Search roles...",
180
+ "customer_accounts.admin.roles.confirm.delete": "Rolle \"{{name}}\" löschen?",
181
+ "customer_accounts.admin.roles.default": "Standard",
182
+ "customer_accounts.admin.roles.error.delete": "Rolle konnte nicht gelöscht werden",
183
+ "customer_accounts.admin.roles.error.deleteSystem": "Systemrollen können nicht gelöscht werden",
184
+ "customer_accounts.admin.roles.error.load": "Rollen konnten nicht geladen werden",
185
+ "customer_accounts.admin.roles.flash.deleted": "Rolle gelöscht",
186
+ "customer_accounts.admin.roles.notAssignable": "Nein",
187
+ "customer_accounts.admin.roles.searchPlaceholder": "Rollen suchen...",
188
188
  "customer_accounts.admin.roles.system": "System",
189
189
  "customer_accounts.admin.roles.title": "Rollen",
190
190
  "customer_accounts.admin.searchPlaceholder": "Search by name or email...",
@@ -263,8 +263,8 @@
263
263
  "customer_accounts.domainMapping.tls.retryButton": "Retry SSL",
264
264
  "customer_accounts.domainMapping.verifyNow": "Check Now",
265
265
  "customer_accounts.nav.group": "Customers",
266
- "customer_accounts.nav.role_create": "Create Role",
267
- "customer_accounts.nav.role_detail": "Role Detail",
266
+ "customer_accounts.nav.role_create": "Rolle erstellen",
267
+ "customer_accounts.nav.role_detail": "Rollendetails",
268
268
  "customer_accounts.nav.roles": "Kundenrollen",
269
269
  "customer_accounts.nav.user_detail": "User Detail",
270
270
  "customer_accounts.nav.users": "Kundenbenutzer",
@@ -50,6 +50,13 @@ import {
50
50
  } from '../../../lib/personCompanyLinkTable'
51
51
  import { normalizeCustomerDetailCustomFields } from '../../detailCustomFields'
52
52
  import { isOrganizationReadAccessAllowed } from '@open-mercato/core/modules/directory/utils/organizationScopeGuard'
53
+ import { runWithCacheTenant } from '@open-mercato/cache'
54
+ import {
55
+ buildCollectionTags,
56
+ canonicalizeResourceTag,
57
+ isCrudCacheEnabled,
58
+ resolveCrudCache,
59
+ } from '@open-mercato/shared/lib/crud/cache'
53
60
 
54
61
  export const metadata = {
55
62
  GET: { requireAuth: true, requireFeatures: ['customers.companies.view'] },
@@ -59,6 +66,66 @@ const paramsSchema = z.object({
59
66
  id: z.string().uuid(),
60
67
  })
61
68
 
69
+ const COMPANY_DETAIL_CACHE_TTL_MS = 60_000
70
+
71
+ // The customers write commands already invalidate these resource collections via
72
+ // invalidateCrudCache using these exact resourceKind strings. Reusing them as
73
+ // cache tags means the cached detail is flushed by those existing commands with
74
+ // no new wiring (#3664, mirroring #3143). Canonicalize each kind the same way
75
+ // invalidateCrudCache does (camelCase split + lowercase) so the tag shapes match.
76
+ const COMPANY_DETAIL_CACHE_RESOURCE_KINDS = [
77
+ 'customers.company',
78
+ 'customers.address',
79
+ 'customers.tagAssignment',
80
+ 'customers.labelAssignment',
81
+ 'customers.personCompanyLink',
82
+ 'customers.interaction',
83
+ 'customers.activity',
84
+ ] as const
85
+
86
+ function buildCompanyDetailCacheTags(tenantId: string | null, organizationId: string | null): string[] {
87
+ const tags = new Set<string>()
88
+ for (const resourceKind of COMPANY_DETAIL_CACHE_RESOURCE_KINDS) {
89
+ const resource = canonicalizeResourceTag(resourceKind) ?? resourceKind
90
+ for (const tag of buildCollectionTags(resource, tenantId, [organizationId])) {
91
+ tags.add(tag)
92
+ }
93
+ }
94
+ return Array.from(tags)
95
+ }
96
+
97
+ function buildCompanyDetailCacheKey(parts: {
98
+ tenantId: string | null
99
+ organizationId: string | null
100
+ companyId: string
101
+ selectedOrganizationId: string | null
102
+ filterIds: string[] | null
103
+ allowedIds: string[] | null
104
+ isSuperAdmin: boolean
105
+ viewerUserId: string | null
106
+ interactionMode: string
107
+ includeTokens: string[]
108
+ }): string {
109
+ const sortKeys = (values: string[]): string[] =>
110
+ [...values].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
111
+ const filterIds = parts.filterIds ? sortKeys(parts.filterIds).join(',') : 'all'
112
+ const allowedIds = parts.allowedIds ? sortKeys(parts.allowedIds).join(',') : 'all'
113
+ const includeTokens = sortKeys(parts.includeTokens).join(',')
114
+ return [
115
+ 'customers:companies:detail',
116
+ `tenant:${parts.tenantId ?? 'null'}`,
117
+ `org:${parts.organizationId ?? 'null'}`,
118
+ `company:${parts.companyId}`,
119
+ `selected:${parts.selectedOrganizationId ?? 'null'}`,
120
+ `filter:${filterIds}`,
121
+ `allowed:${allowedIds}`,
122
+ `super:${parts.isSuperAdmin ? '1' : '0'}`,
123
+ `viewer:${parts.viewerUserId ?? 'null'}`,
124
+ `mode:${parts.interactionMode}`,
125
+ `include:${includeTokens}`,
126
+ ].join('|')
127
+ }
128
+
62
129
  function parseIncludeParams(request: Request): Set<string> {
63
130
  const url = new URL(request.url)
64
131
  const raw = url.searchParams.getAll('include')
@@ -414,6 +481,31 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
414
481
  userFeatures: undefined,
415
482
  })
416
483
 
484
+ // Opt-in cache (#3664): the company existence + org read-access checks above
485
+ // always run, so authorization is never served from cache. Only the expensive
486
+ // detail sweeps below are cached. Key on tenant/org/company + the RBAC scope,
487
+ // viewer (email privacy), interaction mode, and the requested include set.
488
+ const cacheTenantId = companyScope.tenantId
489
+ const cache = isCrudCacheEnabled() ? resolveCrudCache(container) : null
490
+ const cacheKey = cache
491
+ ? buildCompanyDetailCacheKey({
492
+ tenantId: cacheTenantId,
493
+ organizationId: companyScope.organizationId,
494
+ companyId: company.id,
495
+ selectedOrganizationId: scope?.selectedId ?? auth.orgId ?? null,
496
+ filterIds: scope?.filterIds ?? null,
497
+ allowedIds: scope?.allowedIds ?? null,
498
+ isSuperAdmin: auth.isSuperAdmin === true,
499
+ viewerUserId,
500
+ interactionMode,
501
+ includeTokens: Array.from(includeTokens),
502
+ })
503
+ : null
504
+ if (cache && cacheKey) {
505
+ const cached = await runWithCacheTenant(cacheTenantId, () => cache.get(cacheKey))
506
+ if (cached) return NextResponse.json(cached)
507
+ }
508
+
417
509
  const shouldLoadCanonicalInteractions = includeInteractions || includeActivities || includeTodos
418
510
 
419
511
  // These reads only depend on the resolved company + scope + email visibility
@@ -961,7 +1053,7 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
961
1053
  addresses: addressesCount,
962
1054
  }
963
1055
 
964
- return NextResponse.json({
1056
+ const payload = {
965
1057
  interactionMode,
966
1058
  company: {
967
1059
  id: company.id,
@@ -1170,7 +1262,22 @@ export async function GET(_req: Request, ctx: { params?: { id?: string } }) {
1170
1262
  name: viewerUserId ? userMap.get(viewerUserId)?.name ?? null : null,
1171
1263
  email: viewerUserId ? userMap.get(viewerUserId)?.email ?? auth.email ?? null : auth.email ?? null,
1172
1264
  },
1173
- })
1265
+ }
1266
+
1267
+ if (cache && cacheKey) {
1268
+ try {
1269
+ await runWithCacheTenant(cacheTenantId, () =>
1270
+ cache.set(cacheKey, payload, {
1271
+ ttl: COMPANY_DETAIL_CACHE_TTL_MS,
1272
+ tags: buildCompanyDetailCacheTags(cacheTenantId, companyScope.organizationId),
1273
+ }),
1274
+ )
1275
+ } catch (err) {
1276
+ console.warn('[customers:companies] Failed to set company detail cache', err)
1277
+ }
1278
+ }
1279
+
1280
+ return NextResponse.json(payload)
1174
1281
  }
1175
1282
 
1176
1283
  const companyDetailQuerySchema = z.object({