@open-mercato/core 0.7.1-develop.7175.1.d49ab48ee2 → 0.7.1-develop.7176.1.d229567a50
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.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/phone_call/index.js +53 -0
- package/dist/generated/entities/phone_call/index.js.map +7 -0
- package/dist/generated/entities/phone_call_participant/index.js +27 -0
- package/dist/generated/entities/phone_call_participant/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +5 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +41 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js +20 -0
- package/dist/modules/configs/lib/upgrade-actions.js.map +2 -2
- package/dist/modules/entities/migrations/Migration20260822120000.js +44 -0
- package/dist/modules/entities/migrations/Migration20260822120000.js.map +7 -0
- package/dist/modules/phone_calls/acl.js +15 -0
- package/dist/modules/phone_calls/acl.js.map +7 -0
- package/dist/modules/phone_calls/api/calls/route.js +132 -0
- package/dist/modules/phone_calls/api/calls/route.js.map +7 -0
- package/dist/modules/phone_calls/api/openapi.js +23 -0
- package/dist/modules/phone_calls/api/openapi.js.map +7 -0
- package/dist/modules/phone_calls/backend/page.js +261 -0
- package/dist/modules/phone_calls/backend/page.js.map +7 -0
- package/dist/modules/phone_calls/backend/page.meta.js +16 -0
- package/dist/modules/phone_calls/backend/page.meta.js.map +7 -0
- package/dist/modules/phone_calls/commands/calls.js +125 -0
- package/dist/modules/phone_calls/commands/calls.js.map +7 -0
- package/dist/modules/phone_calls/commands/index.js +2 -0
- package/dist/modules/phone_calls/commands/index.js.map +7 -0
- package/dist/modules/phone_calls/data/entities.js +162 -0
- package/dist/modules/phone_calls/data/entities.js.map +7 -0
- package/dist/modules/phone_calls/data/validators.js +68 -0
- package/dist/modules/phone_calls/data/validators.js.map +7 -0
- package/dist/modules/phone_calls/di.js +12 -0
- package/dist/modules/phone_calls/di.js.map +7 -0
- package/dist/modules/phone_calls/encryption.js +28 -0
- package/dist/modules/phone_calls/encryption.js.map +7 -0
- package/dist/modules/phone_calls/events.js +18 -0
- package/dist/modules/phone_calls/events.js.map +7 -0
- package/dist/modules/phone_calls/index.js +15 -0
- package/dist/modules/phone_calls/index.js.map +7 -0
- package/dist/modules/phone_calls/migrations/Migration20260706124120_phone_calls.js +22 -0
- package/dist/modules/phone_calls/migrations/Migration20260706124120_phone_calls.js.map +7 -0
- package/dist/modules/phone_calls/migrations/Migration20260814124333_phone_calls.js +13 -0
- package/dist/modules/phone_calls/migrations/Migration20260814124333_phone_calls.js.map +7 -0
- package/dist/modules/phone_calls/setup.js +16 -0
- package/dist/modules/phone_calls/setup.js.map +7 -0
- package/generated/entities/phone_call/index.ts +25 -0
- package/generated/entities/phone_call_participant/index.ts +12 -0
- package/generated/entities.ids.generated.ts +5 -0
- package/generated/entity-fields-registry.ts +41 -0
- package/package.json +7 -7
- package/src/modules/auth/i18n/de.json +3 -0
- package/src/modules/auth/i18n/en.json +3 -0
- package/src/modules/auth/i18n/es.json +3 -0
- package/src/modules/auth/i18n/ko.json +3 -0
- package/src/modules/auth/i18n/pl.json +3 -0
- package/src/modules/configs/lib/upgrade-actions.ts +20 -0
- package/src/modules/entities/migrations/Migration20260822120000.ts +56 -0
- package/src/modules/phone_calls/acl.ts +11 -0
- package/src/modules/phone_calls/api/calls/route.ts +150 -0
- package/src/modules/phone_calls/api/openapi.ts +25 -0
- package/src/modules/phone_calls/backend/page.meta.ts +12 -0
- package/src/modules/phone_calls/backend/page.tsx +303 -0
- package/src/modules/phone_calls/commands/calls.ts +156 -0
- package/src/modules/phone_calls/commands/index.ts +1 -0
- package/src/modules/phone_calls/data/entities.ts +144 -0
- package/src/modules/phone_calls/data/validators.ts +69 -0
- package/src/modules/phone_calls/di.ts +10 -0
- package/src/modules/phone_calls/encryption.ts +26 -0
- package/src/modules/phone_calls/events.ts +25 -0
- package/src/modules/phone_calls/i18n/de.json +42 -0
- package/src/modules/phone_calls/i18n/en.json +42 -0
- package/src/modules/phone_calls/i18n/es.json +42 -0
- package/src/modules/phone_calls/i18n/ko.json +42 -0
- package/src/modules/phone_calls/i18n/pl.json +42 -0
- package/src/modules/phone_calls/index.ts +13 -0
- package/src/modules/phone_calls/migrations/.snapshot-open-mercato.json +772 -0
- package/src/modules/phone_calls/migrations/Migration20260706124120_phone_calls.ts +23 -0
- package/src/modules/phone_calls/migrations/Migration20260814124333_phone_calls.ts +13 -0
- package/src/modules/phone_calls/setup.ts +14 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/phone_calls/backend/page.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { SortingState } from '@tanstack/react-table'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { StatusBadge, type StatusMap } from '@open-mercato/ui/primitives/status-badge'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { useProgressPoll } from '@open-mercato/ui/backend/progress/useProgressPoll'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { PHONE_CALL_RESOURCE_KIND } from '@open-mercato/shared/modules/phone_calls/types'\n\ntype PhoneCallRow = {\n id: string\n provider_key: string | null\n external_call_id: string | null\n direction: string | null\n status: string | null\n started_at: string | null\n duration_seconds: number | null\n ingest_status: string | null\n}\n\ntype PhoneCallListResponse = {\n items?: PhoneCallRow[]\n total?: number\n page?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\nconst DIRECTION_VALUES = ['inbound', 'outbound', 'internal', 'unknown'] as const\nconst STATUS_VALUES = ['new', 'ringing', 'answered', 'missed', 'failed', 'completed', 'unknown'] as const\n\ntype PhoneCallStatusValue = typeof STATUS_VALUES[number]\n\nfunction isPhoneCallStatus(value: string): value is PhoneCallStatusValue {\n return (STATUS_VALUES as readonly string[]).includes(value)\n}\n\n// Column id (snake_case accessorKey) -> API sortField key (camelCase, matches\n// the route's sortFieldMap). Columns absent from this map are not sortable.\nconst SORT_FIELDS: Record<string, string> = {\n external_call_id: 'externalCallId',\n direction: 'direction',\n status: 'status',\n provider_key: 'providerKey',\n started_at: 'startedAt',\n duration_seconds: 'durationSeconds',\n ingest_status: 'ingestStatus',\n}\n\nconst STATUS_TONE: StatusMap<PhoneCallStatusValue> = {\n completed: 'success',\n answered: 'success',\n ringing: 'warning',\n new: 'neutral',\n missed: 'error',\n failed: 'error',\n unknown: 'neutral',\n}\n\nfunction formatDuration(seconds: number | null): string {\n if (seconds == null || Number.isNaN(seconds)) return '\u2014'\n const total = Math.max(0, Math.floor(seconds))\n const mins = Math.floor(total / 60)\n const secs = total % 60\n return `${mins}:${String(secs).padStart(2, '0')}`\n}\n\nexport default function PhoneCallsPage() {\n const t = useT()\n const [rows, setRows] = React.useState<PhoneCallRow[]>([])\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [page, setPage] = React.useState(1)\n const [pageSize, setPageSize] = React.useState(50)\n const [search, setSearch] = React.useState('')\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'started_at', desc: true }])\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n\n const handleSortingChange = React.useCallback((next: SortingState) => {\n setSorting(next)\n setPage(1)\n }, [])\n const [isLoading, setIsLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [reloadToken, setReloadToken] = React.useState(0)\n\n // Ingest runs in a provider worker, so the rows land after the page did. Any job that\n // declares this resource kind wrote calls, whichever provider queued it.\n useAppEvent('progress.job.completed', (event) => {\n const meta = (event.payload as { meta?: Record<string, unknown> | null } | undefined)?.meta\n if (meta?.resourceKind !== PHONE_CALL_RESOURCE_KIND) return\n setReloadToken((token) => token + 1)\n }, [])\n\n // The event above is a live subscription with no replay: one emitted while the stream is\n // reconnecting is gone, and the grid keeps showing a range the ingest already filled. Polling\n // asks for state instead of waiting to be told, keyed by job id so nothing reloads twice.\n const { recentlyCompleted } = useProgressPoll()\n const seenJobIds = React.useRef<Set<string> | null>(null)\n React.useEffect(() => {\n const ingestJobs = recentlyCompleted.filter(\n (job) => (job.meta as { resourceKind?: string } | null | undefined)?.resourceKind === PHONE_CALL_RESOURCE_KIND,\n )\n // Jobs that finished before this page mounted are recorded without a reload; the initial\n // load already covers them.\n if (seenJobIds.current === null) {\n seenJobIds.current = new Set(ingestJobs.map((job) => job.id))\n return\n }\n const unseen = ingestJobs.filter((job) => !seenJobIds.current!.has(job.id))\n if (!unseen.length) return\n for (const job of unseen) seenJobIds.current.add(job.id)\n setReloadToken((token) => token + 1)\n }, [recentlyCompleted])\n\n const queryString = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(pageSize))\n if (search.trim()) params.set('q', search.trim())\n if (typeof filterValues.direction === 'string' && filterValues.direction) params.set('direction', filterValues.direction)\n if (typeof filterValues.status === 'string' && filterValues.status) params.set('status', filterValues.status)\n if (typeof filterValues.providerKey === 'string' && filterValues.providerKey.trim()) params.set('providerKey', filterValues.providerKey.trim())\n const started = filterValues.started as { from?: string; to?: string } | undefined\n if (started?.from) params.set('startedFrom', started.from)\n if (started?.to) params.set('startedTo', started.to)\n const activeSort = sorting[0]\n if (activeSort) {\n const sortField = SORT_FIELDS[activeSort.id]\n if (sortField) {\n params.set('sortField', sortField)\n params.set('sortDir', activeSort.desc ? 'desc' : 'asc')\n }\n }\n return params.toString()\n }, [page, pageSize, search, filterValues, sorting])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setIsLoading(true)\n setError(null)\n const response = await apiCall<PhoneCallListResponse>(`/api/phone_calls/calls?${queryString}`).catch((err: unknown) => ({\n ok: false as const,\n result: { error: err instanceof Error ? err.message : undefined },\n }))\n if (cancelled) return\n if (!response.ok) {\n const errBody = response.result as { error?: string } | undefined\n setError(errBody?.error ?? t('phone_calls.calls.list.error', 'Failed to load phone calls'))\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setTotalIsCapped(false)\n } else {\n const data = (response.result ?? {}) as PhoneCallListResponse\n setRows(Array.isArray(data.items) ? data.items : [])\n setTotal(typeof data.total === 'number' ? data.total : 0)\n setTotalPages(typeof data.totalPages === 'number' ? data.totalPages : 1)\n setTotalIsCapped(data.totalIsCapped === true)\n }\n setIsLoading(false)\n }\n void load()\n return () => { cancelled = true }\n }, [queryString, reloadToken, t])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'direction',\n label: t('phone_calls.calls.filters.direction', 'Direction'),\n type: 'select',\n options: DIRECTION_VALUES.map((value) => ({\n value,\n label: t(`phone_calls.calls.direction.${value}`, value),\n })),\n },\n {\n id: 'status',\n label: t('phone_calls.calls.filters.status', 'Status'),\n type: 'select',\n options: STATUS_VALUES.map((value) => ({\n value,\n label: t(`phone_calls.calls.status.${value}`, value),\n })),\n },\n {\n id: 'providerKey',\n label: t('phone_calls.calls.filters.provider', 'Provider'),\n type: 'text',\n placeholder: t('phone_calls.calls.filters.providerPlaceholder', 'Provider key'),\n },\n {\n id: 'started',\n label: t('phone_calls.calls.filters.started', 'Started'),\n type: 'dateRange',\n },\n ], [t])\n\n const columns = React.useMemo<ColumnDef<PhoneCallRow>[]>(() => [\n {\n accessorKey: 'external_call_id',\n header: t('phone_calls.calls.columns.callId', 'Call ID'),\n meta: { truncate: true, maxWidth: '240px' },\n cell: ({ row }) => (\n <span className=\"text-sm font-medium\">{row.original.external_call_id || '\u2014'}</span>\n ),\n },\n {\n accessorKey: 'direction',\n header: t('phone_calls.calls.columns.direction', 'Direction'),\n cell: ({ row }) => {\n const value = row.original.direction\n return <span className=\"text-sm\">{value ? t(`phone_calls.calls.direction.${value}`, value) : '\u2014'}</span>\n },\n },\n {\n accessorKey: 'status',\n header: t('phone_calls.calls.columns.status', 'Status'),\n cell: ({ row }) => {\n const value = row.original.status\n if (!value) return <span className=\"text-sm text-muted-foreground\">\u2014</span>\n return (\n <StatusBadge variant={STATUS_TONE[isPhoneCallStatus(value) ? value : 'unknown']} dot>\n {t(`phone_calls.calls.status.${value}`, value)}\n </StatusBadge>\n )\n },\n },\n {\n accessorKey: 'provider_key',\n header: t('phone_calls.calls.columns.provider', 'Provider'),\n cell: ({ row }) => <span className=\"text-sm\">{row.original.provider_key || '\u2014'}</span>,\n },\n {\n accessorKey: 'started_at',\n header: t('phone_calls.calls.columns.started', 'Started'),\n cell: ({ row }) => <span className=\"text-sm text-muted-foreground\">{formatDateTime(row.original.started_at) ?? '\u2014'}</span>,\n },\n {\n accessorKey: 'duration_seconds',\n header: t('phone_calls.calls.columns.duration', 'Duration'),\n cell: ({ row }) => <span className=\"text-sm tabular-nums\">{formatDuration(row.original.duration_seconds)}</span>,\n },\n {\n accessorKey: 'ingest_status',\n header: t('phone_calls.calls.columns.ingestStatus', 'Ingest'),\n cell: ({ row }) => {\n const value = row.original.ingest_status\n return (\n <span className=\"text-sm text-muted-foreground\">\n {value ? t(`phone_calls.calls.ingestStatus.${value}`, value) : '\u2014'}\n </span>\n )\n },\n },\n ], [t])\n\n return (\n <Page>\n <PageBody>\n <DataTable<PhoneCallRow>\n title={t('phone_calls.calls.list.title', 'Phone Calls')}\n extensionTableId=\"phone_calls.calls\"\n columns={columns}\n data={rows}\n isLoading={isLoading}\n error={error}\n sortable\n manualSorting\n sorting={sorting}\n onSortingChange={handleSortingChange}\n searchValue={search}\n onSearchChange={(value) => { setSearch(value); setPage(1) }}\n searchPlaceholder={t('phone_calls.calls.list.searchPlaceholder', 'Search by call, conversation or provider')}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={(values) => { setFilterValues(values); setPage(1) }}\n onFiltersClear={() => { setFilterValues({}); setPage(1) }}\n emptyState={t('phone_calls.calls.list.empty', 'No phone calls yet. Calls appear here once they are ingested from a provider.')}\n pagination={{\n page,\n pageSize,\n total,\n totalPages,\n totalIsCapped,\n onPageChange: setPage,\n pageSizeOptions: [10, 25, 50, 100],\n onPageSizeChange: (size) => { setPageSize(size); setPage(1) },\n }}\n />\n </PageBody>\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const metadata = {
|
|
2
|
+
requireAuth: true,
|
|
3
|
+
requireFeatures: ["phone_calls.view"],
|
|
4
|
+
pageTitle: "Phone Calls",
|
|
5
|
+
pageTitleKey: "phone_calls.nav.calls",
|
|
6
|
+
pageGroup: "Communication",
|
|
7
|
+
pageGroupKey: "phone_calls.nav.group",
|
|
8
|
+
pagePriority: 10,
|
|
9
|
+
pageOrder: 100,
|
|
10
|
+
icon: "phone-call",
|
|
11
|
+
breadcrumb: [{ label: "Phone Calls", labelKey: "phone_calls.nav.calls" }]
|
|
12
|
+
};
|
|
13
|
+
export {
|
|
14
|
+
metadata
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=page.meta.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/phone_calls/backend/page.meta.ts"],
|
|
4
|
+
"sourcesContent": ["export const metadata = {\n requireAuth: true,\n requireFeatures: ['phone_calls.view'],\n pageTitle: 'Phone Calls',\n pageTitleKey: 'phone_calls.nav.calls',\n pageGroup: 'Communication',\n pageGroupKey: 'phone_calls.nav.group',\n pagePriority: 10,\n pageOrder: 100,\n icon: 'phone-call',\n breadcrumb: [{ label: 'Phone Calls', labelKey: 'phone_calls.nav.calls' }],\n}\n"],
|
|
5
|
+
"mappings": "AAAO,MAAM,WAAW;AAAA,EACtB,aAAa;AAAA,EACb,iBAAiB,CAAC,kBAAkB;AAAA,EACpC,WAAW;AAAA,EACX,cAAc;AAAA,EACd,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAAA,EACd,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY,CAAC,EAAE,OAAO,eAAe,UAAU,wBAAwB,CAAC;AAC1E;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
2
|
+
import { emitCrudSideEffects } from "@open-mercato/shared/lib/commands/helpers";
|
|
3
|
+
import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
|
|
4
|
+
import { ensureOrganizationScope, ensureTenantScope } from "@open-mercato/shared/lib/commands/scope";
|
|
5
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
6
|
+
import { PHONE_CALL_RESOURCE_KIND } from "@open-mercato/shared/modules/phone_calls/types";
|
|
7
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
8
|
+
import { E } from "../../../generated/entities.ids.generated.js";
|
|
9
|
+
import { PhoneCall, PhoneCallParticipant } from "../data/entities.js";
|
|
10
|
+
import {
|
|
11
|
+
ingestPhoneCallSchema
|
|
12
|
+
} from "../data/validators.js";
|
|
13
|
+
import { emitPhoneCallsEvent } from "../events.js";
|
|
14
|
+
const PHONE_CALLS_CALL_INGEST_COMMAND_ID = "phone_calls.call.ingest";
|
|
15
|
+
const phoneCallCrudIndexer = {
|
|
16
|
+
entityType: E.phone_calls.phone_call
|
|
17
|
+
};
|
|
18
|
+
const PHONE_CALL_CACHE_ALIASES = [PhoneCall.name];
|
|
19
|
+
function applyScalarFields(call, input, ingestedAt) {
|
|
20
|
+
call.integrationId = input.integrationId ?? null;
|
|
21
|
+
call.externalConversationId = input.externalConversationId ?? null;
|
|
22
|
+
call.direction = input.direction;
|
|
23
|
+
call.status = input.status;
|
|
24
|
+
call.startedAt = input.startedAt ?? null;
|
|
25
|
+
call.answeredAt = input.answeredAt ?? null;
|
|
26
|
+
call.endedAt = input.endedAt ?? null;
|
|
27
|
+
call.durationSeconds = input.durationSeconds ?? null;
|
|
28
|
+
call.recordingUrl = input.recording?.url ?? null;
|
|
29
|
+
call.providerFacts = input.providerFacts ?? null;
|
|
30
|
+
call.rawSnapshot = input.rawPayload;
|
|
31
|
+
call.ingestStatus = "complete";
|
|
32
|
+
call.lastIngestedAt = ingestedAt;
|
|
33
|
+
}
|
|
34
|
+
async function syncParticipants(em, call, input) {
|
|
35
|
+
await em.nativeDelete(PhoneCallParticipant, { phoneCallId: call.id });
|
|
36
|
+
for (const participant of input.participants) {
|
|
37
|
+
em.persist(em.create(PhoneCallParticipant, {
|
|
38
|
+
organizationId: call.organizationId,
|
|
39
|
+
tenantId: call.tenantId,
|
|
40
|
+
phoneCallId: call.id,
|
|
41
|
+
providerParticipantId: participant.providerParticipantId ?? null,
|
|
42
|
+
role: participant.role,
|
|
43
|
+
phoneNumber: participant.phoneNumber ?? null,
|
|
44
|
+
displayName: participant.displayName ?? null,
|
|
45
|
+
email: participant.email ?? null,
|
|
46
|
+
metadata: participant.metadata ?? null
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const ingestPhoneCallCommand = {
|
|
51
|
+
id: PHONE_CALLS_CALL_INGEST_COMMAND_ID,
|
|
52
|
+
async execute(rawInput, ctx) {
|
|
53
|
+
const input = ingestPhoneCallSchema.parse(rawInput);
|
|
54
|
+
ensureTenantScope(ctx, input.tenantId);
|
|
55
|
+
ensureOrganizationScope(ctx, input.organizationId);
|
|
56
|
+
const em = ctx.container.resolve("em").fork();
|
|
57
|
+
const existing = await findOneWithDecryption(
|
|
58
|
+
em,
|
|
59
|
+
PhoneCall,
|
|
60
|
+
{
|
|
61
|
+
providerKey: input.providerKey,
|
|
62
|
+
externalCallId: input.externalCallId,
|
|
63
|
+
tenantId: input.tenantId,
|
|
64
|
+
organizationId: input.organizationId
|
|
65
|
+
},
|
|
66
|
+
void 0,
|
|
67
|
+
{ tenantId: input.tenantId, organizationId: input.organizationId }
|
|
68
|
+
);
|
|
69
|
+
const created = !existing;
|
|
70
|
+
const call = existing ?? em.create(PhoneCall, {
|
|
71
|
+
organizationId: input.organizationId,
|
|
72
|
+
tenantId: input.tenantId,
|
|
73
|
+
providerKey: input.providerKey,
|
|
74
|
+
externalCallId: input.externalCallId,
|
|
75
|
+
direction: input.direction,
|
|
76
|
+
status: input.status
|
|
77
|
+
});
|
|
78
|
+
if (created) em.persist(call);
|
|
79
|
+
const ingestedAt = /* @__PURE__ */ new Date();
|
|
80
|
+
await withAtomicFlush(
|
|
81
|
+
em,
|
|
82
|
+
[
|
|
83
|
+
() => applyScalarFields(call, input, ingestedAt),
|
|
84
|
+
() => syncParticipants(em, call, input)
|
|
85
|
+
],
|
|
86
|
+
{ transaction: true, label: PHONE_CALLS_CALL_INGEST_COMMAND_ID }
|
|
87
|
+
);
|
|
88
|
+
await emitCrudSideEffects({
|
|
89
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
90
|
+
action: created ? "created" : "updated",
|
|
91
|
+
entity: call,
|
|
92
|
+
identifiers: {
|
|
93
|
+
id: call.id,
|
|
94
|
+
organizationId: call.organizationId,
|
|
95
|
+
tenantId: call.tenantId
|
|
96
|
+
},
|
|
97
|
+
indexer: phoneCallCrudIndexer
|
|
98
|
+
});
|
|
99
|
+
await emitPhoneCallsEvent(
|
|
100
|
+
created ? "phone_calls.call.ingested" : "phone_calls.call.updated",
|
|
101
|
+
{ id: call.id, organizationId: call.organizationId, tenantId: call.tenantId }
|
|
102
|
+
).catch(() => void 0);
|
|
103
|
+
return { phoneCallId: call.id, created };
|
|
104
|
+
},
|
|
105
|
+
// Calls carry PII (numbers, names, recordings), so the audit entry stays at identifiers
|
|
106
|
+
// and the ingest outcome. No snapshot, and the command is not undoable.
|
|
107
|
+
buildLog: async ({ input, result }) => {
|
|
108
|
+
const { translate } = await resolveTranslations();
|
|
109
|
+
return {
|
|
110
|
+
actionLabel: result.created ? translate("phone_calls.audit.calls.ingested", "Ingest phone call") : translate("phone_calls.audit.calls.updated", "Update ingested phone call"),
|
|
111
|
+
resourceKind: PHONE_CALL_RESOURCE_KIND,
|
|
112
|
+
resourceId: result.phoneCallId,
|
|
113
|
+
tenantId: input.tenantId,
|
|
114
|
+
organizationId: input.organizationId,
|
|
115
|
+
context: { cacheAliases: PHONE_CALL_CACHE_ALIASES }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
registerCommand(ingestPhoneCallCommand);
|
|
120
|
+
export {
|
|
121
|
+
PHONE_CALLS_CALL_INGEST_COMMAND_ID,
|
|
122
|
+
PHONE_CALL_RESOURCE_KIND,
|
|
123
|
+
ingestPhoneCallCommand
|
|
124
|
+
};
|
|
125
|
+
//# sourceMappingURL=calls.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/phone_calls/commands/calls.ts"],
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { ensureOrganizationScope, ensureTenantScope } from '@open-mercato/shared/lib/commands/scope'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { PHONE_CALL_RESOURCE_KIND } from '@open-mercato/shared/modules/phone_calls/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { E } from '#generated/entities.ids.generated'\nimport { PhoneCall, PhoneCallParticipant } from '../data/entities'\nimport {\n ingestPhoneCallSchema,\n type IngestPhoneCallInput,\n} from '../data/validators'\nimport { emitPhoneCallsEvent } from '../events'\n\nexport const PHONE_CALLS_CALL_INGEST_COMMAND_ID = 'phone_calls.call.ingest'\nexport { PHONE_CALL_RESOURCE_KIND }\n\nconst phoneCallCrudIndexer: CrudIndexerConfig<PhoneCall> = {\n entityType: E.phone_calls.phone_call,\n}\n\n// The list route derives its cache tag from the entity class name, and the tag the bus\n// derives from this command id is a different one, so without the alias the cached list\n// pages survive an ingest.\nconst PHONE_CALL_CACHE_ALIASES = [PhoneCall.name]\n\nexport type IngestPhoneCallResult = { phoneCallId: string; created: boolean }\n\nfunction applyScalarFields(call: PhoneCall, input: IngestPhoneCallInput, ingestedAt: Date): void {\n call.integrationId = input.integrationId ?? null\n call.externalConversationId = input.externalConversationId ?? null\n call.direction = input.direction\n call.status = input.status\n call.startedAt = input.startedAt ?? null\n call.answeredAt = input.answeredAt ?? null\n call.endedAt = input.endedAt ?? null\n call.durationSeconds = input.durationSeconds ?? null\n call.recordingUrl = input.recording?.url ?? null\n call.providerFacts = input.providerFacts ?? null\n call.rawSnapshot = input.rawPayload\n call.ingestStatus = 'complete'\n call.lastIngestedAt = ingestedAt\n}\n\nasync function syncParticipants(\n em: EntityManager,\n call: PhoneCall,\n input: IngestPhoneCallInput,\n): Promise<void> {\n // Replace the whole participant set on every ingest: participants have no reliable\n // natural key (providerParticipantId/phoneNumber are often null), so a diff/upsert would\n // be guesswork. Delete-all + insert stays deterministic and idempotent. Revisit this if\n // anything starts referencing participant.id externally (re-pull rotates these ids).\n await em.nativeDelete(PhoneCallParticipant, { phoneCallId: call.id })\n for (const participant of input.participants) {\n em.persist(em.create(PhoneCallParticipant, {\n organizationId: call.organizationId,\n tenantId: call.tenantId,\n phoneCallId: call.id,\n providerParticipantId: participant.providerParticipantId ?? null,\n role: participant.role,\n phoneNumber: participant.phoneNumber ?? null,\n displayName: participant.displayName ?? null,\n email: participant.email ?? null,\n metadata: participant.metadata ?? null,\n }))\n }\n}\n\nconst ingestPhoneCallCommand: CommandHandler<IngestPhoneCallInput, IngestPhoneCallResult> = {\n id: PHONE_CALLS_CALL_INGEST_COMMAND_ID,\n async execute(rawInput, ctx) {\n const input = ingestPhoneCallSchema.parse(rawInput)\n ensureTenantScope(ctx, input.tenantId)\n ensureOrganizationScope(ctx, input.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const existing = await findOneWithDecryption(\n em,\n PhoneCall,\n {\n providerKey: input.providerKey,\n externalCallId: input.externalCallId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n undefined,\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n const created = !existing\n const call = existing ?? em.create(PhoneCall, {\n organizationId: input.organizationId,\n tenantId: input.tenantId,\n providerKey: input.providerKey,\n externalCallId: input.externalCallId,\n direction: input.direction,\n status: input.status,\n })\n if (created) em.persist(call)\n const ingestedAt = new Date()\n\n await withAtomicFlush(\n em,\n [\n () => applyScalarFields(call, input, ingestedAt),\n () => syncParticipants(em, call, input),\n ],\n { transaction: true, label: PHONE_CALLS_CALL_INGEST_COMMAND_ID },\n )\n\n // The module emits its own declared events, so only the indexer is handed to the\n // shared side effects: the query index and the read caches have to see the write.\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action: created ? 'created' : 'updated',\n entity: call,\n identifiers: {\n id: call.id,\n organizationId: call.organizationId,\n tenantId: call.tenantId,\n },\n indexer: phoneCallCrudIndexer,\n })\n\n await emitPhoneCallsEvent(\n created ? 'phone_calls.call.ingested' : 'phone_calls.call.updated',\n { id: call.id, organizationId: call.organizationId, tenantId: call.tenantId },\n ).catch(() => undefined)\n\n return { phoneCallId: call.id, created }\n },\n // Calls carry PII (numbers, names, recordings), so the audit entry stays at identifiers\n // and the ingest outcome. No snapshot, and the command is not undoable.\n buildLog: async ({ input, result }) => {\n const { translate } = await resolveTranslations()\n return {\n actionLabel: result.created\n ? translate('phone_calls.audit.calls.ingested', 'Ingest phone call')\n : translate('phone_calls.audit.calls.updated', 'Update ingested phone call'),\n resourceKind: PHONE_CALL_RESOURCE_KIND,\n resourceId: result.phoneCallId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n context: { cacheAliases: PHONE_CALL_CACHE_ALIASES },\n }\n },\n}\n\nregisterCommand(ingestPhoneCallCommand)\n\nexport { ingestPhoneCallCommand }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
import { OptionalProps } from "@mikro-orm/core";
|
|
12
|
+
import { Entity, Index, ManyToOne, PrimaryKey, Property, Unique } from "@mikro-orm/decorators/legacy";
|
|
13
|
+
OptionalProps;
|
|
14
|
+
let PhoneCall = class {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.ingestStatus = "pending";
|
|
17
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
18
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
__decorateClass([
|
|
22
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
23
|
+
], PhoneCall.prototype, "id", 2);
|
|
24
|
+
__decorateClass([
|
|
25
|
+
Property({ name: "organization_id", type: "uuid" })
|
|
26
|
+
], PhoneCall.prototype, "organizationId", 2);
|
|
27
|
+
__decorateClass([
|
|
28
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
29
|
+
], PhoneCall.prototype, "tenantId", 2);
|
|
30
|
+
__decorateClass([
|
|
31
|
+
Property({ name: "provider_key", type: "text" })
|
|
32
|
+
], PhoneCall.prototype, "providerKey", 2);
|
|
33
|
+
__decorateClass([
|
|
34
|
+
Property({ name: "integration_id", type: "text", nullable: true })
|
|
35
|
+
], PhoneCall.prototype, "integrationId", 2);
|
|
36
|
+
__decorateClass([
|
|
37
|
+
Property({ name: "external_call_id", type: "text" })
|
|
38
|
+
], PhoneCall.prototype, "externalCallId", 2);
|
|
39
|
+
__decorateClass([
|
|
40
|
+
Property({ name: "external_conversation_id", type: "text", nullable: true })
|
|
41
|
+
], PhoneCall.prototype, "externalConversationId", 2);
|
|
42
|
+
__decorateClass([
|
|
43
|
+
Property({ name: "direction", type: "text" })
|
|
44
|
+
], PhoneCall.prototype, "direction", 2);
|
|
45
|
+
__decorateClass([
|
|
46
|
+
Property({ name: "status", type: "text" })
|
|
47
|
+
], PhoneCall.prototype, "status", 2);
|
|
48
|
+
__decorateClass([
|
|
49
|
+
Property({ name: "started_at", type: Date, nullable: true })
|
|
50
|
+
], PhoneCall.prototype, "startedAt", 2);
|
|
51
|
+
__decorateClass([
|
|
52
|
+
Property({ name: "answered_at", type: Date, nullable: true })
|
|
53
|
+
], PhoneCall.prototype, "answeredAt", 2);
|
|
54
|
+
__decorateClass([
|
|
55
|
+
Property({ name: "ended_at", type: Date, nullable: true })
|
|
56
|
+
], PhoneCall.prototype, "endedAt", 2);
|
|
57
|
+
__decorateClass([
|
|
58
|
+
Property({ name: "duration_seconds", type: "integer", nullable: true })
|
|
59
|
+
], PhoneCall.prototype, "durationSeconds", 2);
|
|
60
|
+
__decorateClass([
|
|
61
|
+
Property({ name: "recording_url", type: "text", nullable: true })
|
|
62
|
+
], PhoneCall.prototype, "recordingUrl", 2);
|
|
63
|
+
__decorateClass([
|
|
64
|
+
Property({ name: "recording_attachment_id", type: "uuid", nullable: true })
|
|
65
|
+
], PhoneCall.prototype, "recordingAttachmentId", 2);
|
|
66
|
+
__decorateClass([
|
|
67
|
+
Property({ name: "active_transcript_version_id", type: "uuid", nullable: true })
|
|
68
|
+
], PhoneCall.prototype, "activeTranscriptVersionId", 2);
|
|
69
|
+
__decorateClass([
|
|
70
|
+
Property({ name: "active_summary_version_id", type: "uuid", nullable: true })
|
|
71
|
+
], PhoneCall.prototype, "activeSummaryVersionId", 2);
|
|
72
|
+
__decorateClass([
|
|
73
|
+
Property({ name: "communication_projection_id", type: "uuid", nullable: true })
|
|
74
|
+
], PhoneCall.prototype, "communicationProjectionId", 2);
|
|
75
|
+
__decorateClass([
|
|
76
|
+
Property({ name: "provider_facts", type: "jsonb", nullable: true })
|
|
77
|
+
], PhoneCall.prototype, "providerFacts", 2);
|
|
78
|
+
__decorateClass([
|
|
79
|
+
Property({ name: "raw_snapshot", type: "jsonb", nullable: true })
|
|
80
|
+
], PhoneCall.prototype, "rawSnapshot", 2);
|
|
81
|
+
__decorateClass([
|
|
82
|
+
Property({ name: "ingest_status", type: "text", default: "pending" })
|
|
83
|
+
], PhoneCall.prototype, "ingestStatus", 2);
|
|
84
|
+
__decorateClass([
|
|
85
|
+
Property({ name: "last_ingested_at", type: Date, nullable: true })
|
|
86
|
+
], PhoneCall.prototype, "lastIngestedAt", 2);
|
|
87
|
+
__decorateClass([
|
|
88
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
89
|
+
], PhoneCall.prototype, "createdAt", 2);
|
|
90
|
+
__decorateClass([
|
|
91
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
92
|
+
], PhoneCall.prototype, "updatedAt", 2);
|
|
93
|
+
__decorateClass([
|
|
94
|
+
Property({ name: "deleted_at", type: Date, nullable: true })
|
|
95
|
+
], PhoneCall.prototype, "deletedAt", 2);
|
|
96
|
+
PhoneCall = __decorateClass([
|
|
97
|
+
Entity({ tableName: "phone_calls" }),
|
|
98
|
+
Index({ name: "phone_calls_org_tenant_idx", properties: ["organizationId", "tenantId"] }),
|
|
99
|
+
Unique({
|
|
100
|
+
name: "phone_calls_provider_external_scope_uq",
|
|
101
|
+
properties: ["providerKey", "externalCallId", "tenantId", "organizationId"]
|
|
102
|
+
}),
|
|
103
|
+
Index({ name: "phone_calls_org_started_at_idx", properties: ["organizationId", "startedAt"] }),
|
|
104
|
+
Index({ name: "phone_calls_org_status_idx", properties: ["organizationId", "status"] }),
|
|
105
|
+
Index({
|
|
106
|
+
name: "phone_calls_communication_projection_id_idx",
|
|
107
|
+
expression: 'create index "phone_calls_communication_projection_id_idx" on "phone_calls" ("communication_projection_id") where "communication_projection_id" is not null'
|
|
108
|
+
})
|
|
109
|
+
], PhoneCall);
|
|
110
|
+
OptionalProps;
|
|
111
|
+
let PhoneCallParticipant = class {
|
|
112
|
+
constructor() {
|
|
113
|
+
this.createdAt = /* @__PURE__ */ new Date();
|
|
114
|
+
this.updatedAt = /* @__PURE__ */ new Date();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
__decorateClass([
|
|
118
|
+
PrimaryKey({ type: "uuid", defaultRaw: "gen_random_uuid()" })
|
|
119
|
+
], PhoneCallParticipant.prototype, "id", 2);
|
|
120
|
+
__decorateClass([
|
|
121
|
+
Property({ name: "organization_id", type: "uuid" })
|
|
122
|
+
], PhoneCallParticipant.prototype, "organizationId", 2);
|
|
123
|
+
__decorateClass([
|
|
124
|
+
Property({ name: "tenant_id", type: "uuid" })
|
|
125
|
+
], PhoneCallParticipant.prototype, "tenantId", 2);
|
|
126
|
+
__decorateClass([
|
|
127
|
+
ManyToOne(() => PhoneCall, { fieldName: "phone_call_id", deleteRule: "cascade", mapToPk: true })
|
|
128
|
+
], PhoneCallParticipant.prototype, "phoneCallId", 2);
|
|
129
|
+
__decorateClass([
|
|
130
|
+
Property({ name: "provider_participant_id", type: "text", nullable: true })
|
|
131
|
+
], PhoneCallParticipant.prototype, "providerParticipantId", 2);
|
|
132
|
+
__decorateClass([
|
|
133
|
+
Property({ name: "role", type: "text" })
|
|
134
|
+
], PhoneCallParticipant.prototype, "role", 2);
|
|
135
|
+
__decorateClass([
|
|
136
|
+
Property({ name: "phone_number", type: "text", nullable: true })
|
|
137
|
+
], PhoneCallParticipant.prototype, "phoneNumber", 2);
|
|
138
|
+
__decorateClass([
|
|
139
|
+
Property({ name: "display_name", type: "text", nullable: true })
|
|
140
|
+
], PhoneCallParticipant.prototype, "displayName", 2);
|
|
141
|
+
__decorateClass([
|
|
142
|
+
Property({ name: "email", type: "text", nullable: true })
|
|
143
|
+
], PhoneCallParticipant.prototype, "email", 2);
|
|
144
|
+
__decorateClass([
|
|
145
|
+
Property({ name: "metadata", type: "jsonb", nullable: true })
|
|
146
|
+
], PhoneCallParticipant.prototype, "metadata", 2);
|
|
147
|
+
__decorateClass([
|
|
148
|
+
Property({ name: "created_at", type: Date, onCreate: () => /* @__PURE__ */ new Date() })
|
|
149
|
+
], PhoneCallParticipant.prototype, "createdAt", 2);
|
|
150
|
+
__decorateClass([
|
|
151
|
+
Property({ name: "updated_at", type: Date, onUpdate: () => /* @__PURE__ */ new Date() })
|
|
152
|
+
], PhoneCallParticipant.prototype, "updatedAt", 2);
|
|
153
|
+
PhoneCallParticipant = __decorateClass([
|
|
154
|
+
Entity({ tableName: "phone_call_participants" }),
|
|
155
|
+
Index({ name: "phone_call_participants_call_idx", properties: ["phoneCallId"] }),
|
|
156
|
+
Index({ name: "phone_call_participants_org_tenant_idx", properties: ["organizationId", "tenantId"] })
|
|
157
|
+
], PhoneCallParticipant);
|
|
158
|
+
export {
|
|
159
|
+
PhoneCall,
|
|
160
|
+
PhoneCallParticipant
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=entities.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/phone_calls/data/entities.ts"],
|
|
4
|
+
"sourcesContent": ["import { OptionalProps } from '@mikro-orm/core'\nimport { Entity, Index, ManyToOne, PrimaryKey, Property, Unique } from '@mikro-orm/decorators/legacy'\nimport type {\n PhoneCallDirection,\n PhoneCallStatus,\n PhoneCallParticipantRole,\n} from '@open-mercato/shared/modules/phone_calls/types'\n\nexport type PhoneCallIngestStatus = 'pending' | 'complete' | 'failed'\n\n@Entity({ tableName: 'phone_calls' })\n@Index({ name: 'phone_calls_org_tenant_idx', properties: ['organizationId', 'tenantId'] })\n@Unique({\n name: 'phone_calls_provider_external_scope_uq',\n properties: ['providerKey', 'externalCallId', 'tenantId', 'organizationId'],\n})\n@Index({ name: 'phone_calls_org_started_at_idx', properties: ['organizationId', 'startedAt'] })\n@Index({ name: 'phone_calls_org_status_idx', properties: ['organizationId', 'status'] })\n@Index({\n name: 'phone_calls_communication_projection_id_idx',\n expression:\n 'create index \"phone_calls_communication_projection_id_idx\" on \"phone_calls\" (\"communication_projection_id\") where \"communication_projection_id\" is not null',\n})\nexport class PhoneCall {\n [OptionalProps]?: 'ingestStatus' | 'createdAt' | 'updatedAt' | 'deletedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'organization_id', type: 'uuid' })\n organizationId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @Property({ name: 'provider_key', type: 'text' })\n providerKey!: string\n\n @Property({ name: 'integration_id', type: 'text', nullable: true })\n integrationId?: string | null\n\n @Property({ name: 'external_call_id', type: 'text' })\n externalCallId!: string\n\n @Property({ name: 'external_conversation_id', type: 'text', nullable: true })\n externalConversationId?: string | null\n\n @Property({ name: 'direction', type: 'text' })\n direction!: PhoneCallDirection\n\n @Property({ name: 'status', type: 'text' })\n status!: PhoneCallStatus\n\n @Property({ name: 'started_at', type: Date, nullable: true })\n startedAt?: Date | null\n\n @Property({ name: 'answered_at', type: Date, nullable: true })\n answeredAt?: Date | null\n\n @Property({ name: 'ended_at', type: Date, nullable: true })\n endedAt?: Date | null\n\n @Property({ name: 'duration_seconds', type: 'integer', nullable: true })\n durationSeconds?: number | null\n\n @Property({ name: 'recording_url', type: 'text', nullable: true })\n recordingUrl?: string | null\n\n @Property({ name: 'recording_attachment_id', type: 'uuid', nullable: true })\n recordingAttachmentId?: string | null\n\n @Property({ name: 'active_transcript_version_id', type: 'uuid', nullable: true })\n activeTranscriptVersionId?: string | null\n\n @Property({ name: 'active_summary_version_id', type: 'uuid', nullable: true })\n activeSummaryVersionId?: string | null\n\n @Property({ name: 'communication_projection_id', type: 'uuid', nullable: true })\n communicationProjectionId?: string | null\n\n @Property({ name: 'provider_facts', type: 'jsonb', nullable: true })\n providerFacts?: Record<string, unknown> | null\n\n @Property({ name: 'raw_snapshot', type: 'jsonb', nullable: true })\n rawSnapshot?: Record<string, unknown> | null\n\n @Property({ name: 'ingest_status', type: 'text', default: 'pending' })\n ingestStatus: PhoneCallIngestStatus = 'pending'\n\n @Property({ name: 'last_ingested_at', type: Date, nullable: true })\n lastIngestedAt?: Date | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n\n @Property({ name: 'deleted_at', type: Date, nullable: true })\n deletedAt?: Date | null\n}\n\n@Entity({ tableName: 'phone_call_participants' })\n@Index({ name: 'phone_call_participants_call_idx', properties: ['phoneCallId'] })\n@Index({ name: 'phone_call_participants_org_tenant_idx', properties: ['organizationId', 'tenantId'] })\nexport class PhoneCallParticipant {\n [OptionalProps]?: 'createdAt' | 'updatedAt'\n\n @PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })\n id!: string\n\n @Property({ name: 'organization_id', type: 'uuid' })\n organizationId!: string\n\n @Property({ name: 'tenant_id', type: 'uuid' })\n tenantId!: string\n\n @ManyToOne(() => PhoneCall, { fieldName: 'phone_call_id', deleteRule: 'cascade', mapToPk: true })\n phoneCallId!: string\n\n @Property({ name: 'provider_participant_id', type: 'text', nullable: true })\n providerParticipantId?: string | null\n\n @Property({ name: 'role', type: 'text' })\n role!: PhoneCallParticipantRole\n\n @Property({ name: 'phone_number', type: 'text', nullable: true })\n phoneNumber?: string | null\n\n @Property({ name: 'display_name', type: 'text', nullable: true })\n displayName?: string | null\n\n @Property({ name: 'email', type: 'text', nullable: true })\n email?: string | null\n\n @Property({ name: 'metadata', type: 'jsonb', nullable: true })\n metadata?: Record<string, unknown> | null\n\n @Property({ name: 'created_at', type: Date, onCreate: () => new Date() })\n createdAt: Date = new Date()\n\n @Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })\n updatedAt: Date = new Date()\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const uuid = () => z.string().uuid();
|
|
3
|
+
const scopedSchema = z.object({
|
|
4
|
+
organizationId: uuid(),
|
|
5
|
+
tenantId: uuid()
|
|
6
|
+
});
|
|
7
|
+
const phoneCallDirectionSchema = z.enum([
|
|
8
|
+
"inbound",
|
|
9
|
+
"outbound",
|
|
10
|
+
"internal",
|
|
11
|
+
"unknown"
|
|
12
|
+
]);
|
|
13
|
+
const phoneCallStatusSchema = z.enum([
|
|
14
|
+
"new",
|
|
15
|
+
"ringing",
|
|
16
|
+
"answered",
|
|
17
|
+
"missed",
|
|
18
|
+
"failed",
|
|
19
|
+
"completed",
|
|
20
|
+
"unknown"
|
|
21
|
+
]);
|
|
22
|
+
const phoneCallParticipantRoleSchema = z.enum([
|
|
23
|
+
"caller",
|
|
24
|
+
"callee",
|
|
25
|
+
"agent",
|
|
26
|
+
"unknown"
|
|
27
|
+
]);
|
|
28
|
+
const ingestParticipantSchema = z.object({
|
|
29
|
+
role: phoneCallParticipantRoleSchema,
|
|
30
|
+
providerParticipantId: z.string().nullish(),
|
|
31
|
+
phoneNumber: z.string().nullish(),
|
|
32
|
+
displayName: z.string().nullish(),
|
|
33
|
+
email: z.string().nullish(),
|
|
34
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
35
|
+
});
|
|
36
|
+
const ingestRecordingSchema = z.object({
|
|
37
|
+
url: z.string().nullish(),
|
|
38
|
+
providerRecordingId: z.string().nullish(),
|
|
39
|
+
mimeType: z.string().nullish(),
|
|
40
|
+
durationSeconds: z.number().int().nullish(),
|
|
41
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
42
|
+
});
|
|
43
|
+
const ingestPhoneCallSchema = scopedSchema.extend({
|
|
44
|
+
providerKey: z.string().min(1),
|
|
45
|
+
integrationId: z.string().nullish(),
|
|
46
|
+
externalCallId: z.string().min(1),
|
|
47
|
+
externalConversationId: z.string().nullish(),
|
|
48
|
+
direction: phoneCallDirectionSchema,
|
|
49
|
+
status: phoneCallStatusSchema,
|
|
50
|
+
participants: z.array(ingestParticipantSchema).default([]),
|
|
51
|
+
recording: ingestRecordingSchema.nullish(),
|
|
52
|
+
startedAt: z.coerce.date().nullish(),
|
|
53
|
+
answeredAt: z.coerce.date().nullish(),
|
|
54
|
+
endedAt: z.coerce.date().nullish(),
|
|
55
|
+
durationSeconds: z.number().int().nullish(),
|
|
56
|
+
providerFacts: z.record(z.string(), z.unknown()).optional(),
|
|
57
|
+
rawPayload: z.record(z.string(), z.unknown())
|
|
58
|
+
});
|
|
59
|
+
export {
|
|
60
|
+
ingestParticipantSchema,
|
|
61
|
+
ingestPhoneCallSchema,
|
|
62
|
+
ingestRecordingSchema,
|
|
63
|
+
phoneCallDirectionSchema,
|
|
64
|
+
phoneCallParticipantRoleSchema,
|
|
65
|
+
phoneCallStatusSchema,
|
|
66
|
+
scopedSchema
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/phone_calls/data/validators.ts"],
|
|
4
|
+
"sourcesContent": ["import { z } from 'zod'\n\nconst uuid = () => z.string().uuid()\n\nexport const scopedSchema = z.object({\n organizationId: uuid(),\n tenantId: uuid(),\n})\n\nexport const phoneCallDirectionSchema = z.enum([\n 'inbound',\n 'outbound',\n 'internal',\n 'unknown',\n])\n\nexport const phoneCallStatusSchema = z.enum([\n 'new',\n 'ringing',\n 'answered',\n 'missed',\n 'failed',\n 'completed',\n 'unknown',\n])\n\nexport const phoneCallParticipantRoleSchema = z.enum([\n 'caller',\n 'callee',\n 'agent',\n 'unknown',\n])\n\nexport const ingestParticipantSchema = z.object({\n role: phoneCallParticipantRoleSchema,\n providerParticipantId: z.string().nullish(),\n phoneNumber: z.string().nullish(),\n displayName: z.string().nullish(),\n email: z.string().nullish(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const ingestRecordingSchema = z.object({\n url: z.string().nullish(),\n providerRecordingId: z.string().nullish(),\n mimeType: z.string().nullish(),\n durationSeconds: z.number().int().nullish(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n})\n\nexport const ingestPhoneCallSchema = scopedSchema.extend({\n providerKey: z.string().min(1),\n integrationId: z.string().nullish(),\n externalCallId: z.string().min(1),\n externalConversationId: z.string().nullish(),\n direction: phoneCallDirectionSchema,\n status: phoneCallStatusSchema,\n participants: z.array(ingestParticipantSchema).default([]),\n recording: ingestRecordingSchema.nullish(),\n startedAt: z.coerce.date().nullish(),\n answeredAt: z.coerce.date().nullish(),\n endedAt: z.coerce.date().nullish(),\n durationSeconds: z.number().int().nullish(),\n providerFacts: z.record(z.string(), z.unknown()).optional(),\n rawPayload: z.record(z.string(), z.unknown()),\n})\n\nexport type IngestPhoneCallInput = z.infer<typeof ingestPhoneCallSchema>\nexport type IngestParticipantInput = z.infer<typeof ingestParticipantSchema>\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS;AAElB,MAAM,OAAO,MAAM,EAAE,OAAO,EAAE,KAAK;AAE5B,MAAM,eAAe,EAAE,OAAO;AAAA,EACnC,gBAAgB,KAAK;AAAA,EACrB,UAAU,KAAK;AACjB,CAAC;AAEM,MAAM,2BAA2B,EAAE,KAAK;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,wBAAwB,EAAE,KAAK;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,iCAAiC,EAAE,KAAK;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,MAAM,0BAA0B,EAAE,OAAO;AAAA,EAC9C,MAAM;AAAA,EACN,uBAAuB,EAAE,OAAO,EAAE,QAAQ;AAAA,EAC1C,aAAa,EAAE,OAAO,EAAE,QAAQ;AAAA,EAChC,aAAa,EAAE,OAAO,EAAE,QAAQ;AAAA,EAChC,OAAO,EAAE,OAAO,EAAE,QAAQ;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;AAEM,MAAM,wBAAwB,EAAE,OAAO;AAAA,EAC5C,KAAK,EAAE,OAAO,EAAE,QAAQ;AAAA,EACxB,qBAAqB,EAAE,OAAO,EAAE,QAAQ;AAAA,EACxC,UAAU,EAAE,OAAO,EAAE,QAAQ;AAAA,EAC7B,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ;AAAA,EAC1C,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AACvD,CAAC;AAEM,MAAM,wBAAwB,aAAa,OAAO;AAAA,EACvD,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,eAAe,EAAE,OAAO,EAAE,QAAQ;AAAA,EAClC,gBAAgB,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAChC,wBAAwB,EAAE,OAAO,EAAE,QAAQ;AAAA,EAC3C,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,cAAc,EAAE,MAAM,uBAAuB,EAAE,QAAQ,CAAC,CAAC;AAAA,EACzD,WAAW,sBAAsB,QAAQ;AAAA,EACzC,WAAW,EAAE,OAAO,KAAK,EAAE,QAAQ;AAAA,EACnC,YAAY,EAAE,OAAO,KAAK,EAAE,QAAQ;AAAA,EACpC,SAAS,EAAE,OAAO,KAAK,EAAE,QAAQ;AAAA,EACjC,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ;AAAA,EAC1C,eAAe,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS;AAAA,EAC1D,YAAY,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC;AAC9C,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { asValue } from "awilix";
|
|
2
|
+
import { PhoneCall, PhoneCallParticipant } from "./data/entities.js";
|
|
3
|
+
function register(container) {
|
|
4
|
+
container.register({
|
|
5
|
+
PhoneCall: asValue(PhoneCall),
|
|
6
|
+
PhoneCallParticipant: asValue(PhoneCallParticipant)
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
register
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=di.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/phone_calls/di.ts"],
|
|
4
|
+
"sourcesContent": ["import { asValue } from 'awilix'\nimport type { AppContainer } from '@open-mercato/shared/lib/di/container'\nimport { PhoneCall, PhoneCallParticipant } from './data/entities'\n\nexport function register(container: AppContainer) {\n container.register({\n PhoneCall: asValue(PhoneCall),\n PhoneCallParticipant: asValue(PhoneCallParticipant),\n })\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,eAAe;AAExB,SAAS,WAAW,4BAA4B;AAEzC,SAAS,SAAS,WAAyB;AAChD,YAAU,SAAS;AAAA,IACjB,WAAW,QAAQ,SAAS;AAAA,IAC5B,sBAAsB,QAAQ,oBAAoB;AAAA,EACpD,CAAC;AACH;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const defaultEncryptionMaps = [
|
|
2
|
+
{
|
|
3
|
+
entityId: "phone_calls:phone_call",
|
|
4
|
+
fields: [
|
|
5
|
+
// raw_snapshot and provider_facts hold the untouched Tillio payload, which
|
|
6
|
+
// carries caller/destination numbers (PII) that we already encrypt on the
|
|
7
|
+
// participant. recording_url points at the call recording. QueryEngine
|
|
8
|
+
// decrypts these transparently on read.
|
|
9
|
+
{ field: "raw_snapshot" },
|
|
10
|
+
{ field: "provider_facts" },
|
|
11
|
+
{ field: "recording_url" }
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
entityId: "phone_calls:phone_call_participant",
|
|
16
|
+
fields: [
|
|
17
|
+
{ field: "phone_number" },
|
|
18
|
+
{ field: "display_name" },
|
|
19
|
+
{ field: "email" }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
];
|
|
23
|
+
var encryption_default = defaultEncryptionMaps;
|
|
24
|
+
export {
|
|
25
|
+
encryption_default as default,
|
|
26
|
+
defaultEncryptionMaps
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=encryption.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/phone_calls/encryption.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleEncryptionMap } from '@open-mercato/shared/modules/encryption'\n\nexport const defaultEncryptionMaps: ModuleEncryptionMap[] = [\n {\n entityId: 'phone_calls:phone_call',\n fields: [\n // raw_snapshot and provider_facts hold the untouched Tillio payload, which\n // carries caller/destination numbers (PII) that we already encrypt on the\n // participant. recording_url points at the call recording. QueryEngine\n // decrypts these transparently on read.\n { field: 'raw_snapshot' },\n { field: 'provider_facts' },\n { field: 'recording_url' },\n ],\n },\n {\n entityId: 'phone_calls:phone_call_participant',\n fields: [\n { field: 'phone_number' },\n { field: 'display_name' },\n { field: 'email' },\n ],\n },\n]\n\nexport default defaultEncryptionMaps\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,wBAA+C;AAAA,EAC1D;AAAA,IACE,UAAU;AAAA,IACV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,MAKN,EAAE,OAAO,eAAe;AAAA,MACxB,EAAE,OAAO,iBAAiB;AAAA,MAC1B,EAAE,OAAO,gBAAgB;AAAA,IAC3B;AAAA,EACF;AAAA,EACA;AAAA,IACE,UAAU;AAAA,IACV,QAAQ;AAAA,MACN,EAAE,OAAO,eAAe;AAAA,MACxB,EAAE,OAAO,eAAe;AAAA,MACxB,EAAE,OAAO,QAAQ;AAAA,IACnB;AAAA,EACF;AACF;AAEA,IAAO,qBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createModuleEvents } from "@open-mercato/shared/modules/events";
|
|
2
|
+
const events = [
|
|
3
|
+
{ id: "phone_calls.call.ingested", label: "Phone Call Ingested", entity: "call", category: "crud" },
|
|
4
|
+
{ id: "phone_calls.call.updated", label: "Phone Call Updated", entity: "call", category: "crud" },
|
|
5
|
+
{ id: "phone_calls.call.ingest_failed", label: "Phone Call Ingest Failed", entity: "call", category: "crud" }
|
|
6
|
+
];
|
|
7
|
+
const eventsConfig = createModuleEvents({
|
|
8
|
+
moduleId: "phone_calls",
|
|
9
|
+
events
|
|
10
|
+
});
|
|
11
|
+
const emitPhoneCallsEvent = eventsConfig.emit;
|
|
12
|
+
var events_default = eventsConfig;
|
|
13
|
+
export {
|
|
14
|
+
events_default as default,
|
|
15
|
+
emitPhoneCallsEvent,
|
|
16
|
+
eventsConfig
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/phone_calls/events.ts"],
|
|
4
|
+
"sourcesContent": ["import { createModuleEvents } from '@open-mercato/shared/modules/events'\n\n/**\n * Phone Calls Module Events\n *\n * Declares all events that can be emitted by the phone_calls module.\n */\nconst events = [\n { id: 'phone_calls.call.ingested', label: 'Phone Call Ingested', entity: 'call', category: 'crud' },\n { id: 'phone_calls.call.updated', label: 'Phone Call Updated', entity: 'call', category: 'crud' },\n { id: 'phone_calls.call.ingest_failed', label: 'Phone Call Ingest Failed', entity: 'call', category: 'crud' },\n] as const\n\nexport const eventsConfig = createModuleEvents({\n moduleId: 'phone_calls',\n events,\n})\n\n/** Type-safe event emitter for phone_calls module */\nexport const emitPhoneCallsEvent = eventsConfig.emit\n\n/** Event IDs that can be emitted by the phone_calls module */\nexport type PhoneCallsEventId = typeof events[number]['id']\n\nexport default eventsConfig\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAOnC,MAAM,SAAS;AAAA,EACb,EAAE,IAAI,6BAA6B,OAAO,uBAAuB,QAAQ,QAAQ,UAAU,OAAO;AAAA,EAClG,EAAE,IAAI,4BAA4B,OAAO,sBAAsB,QAAQ,QAAQ,UAAU,OAAO;AAAA,EAChG,EAAE,IAAI,kCAAkC,OAAO,4BAA4B,QAAQ,QAAQ,UAAU,OAAO;AAC9G;AAEO,MAAM,eAAe,mBAAmB;AAAA,EAC7C,UAAU;AAAA,EACV;AACF,CAAC;AAGM,MAAM,sBAAsB,aAAa;AAKhD,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const metadata = {
|
|
2
|
+
name: "phone_calls",
|
|
3
|
+
title: "Phone Calls",
|
|
4
|
+
version: "0.1.0",
|
|
5
|
+
description: "Provider-neutral core hub for ingesting and browsing phone calls.",
|
|
6
|
+
author: "Open Mercato Team",
|
|
7
|
+
license: "MIT",
|
|
8
|
+
ejectable: true
|
|
9
|
+
};
|
|
10
|
+
import { features } from "./acl.js";
|
|
11
|
+
export {
|
|
12
|
+
features,
|
|
13
|
+
metadata
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/phone_calls/index.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleInfo } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: ModuleInfo = {\n name: 'phone_calls',\n title: 'Phone Calls',\n version: '0.1.0',\n description: 'Provider-neutral core hub for ingesting and browsing phone calls.',\n author: 'Open Mercato Team',\n license: 'MIT',\n ejectable: true,\n}\n\nexport { features } from './acl'\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,WAAuB;AAAA,EAClC,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,WAAW;AACb;AAEA,SAAS,gBAAgB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|