@qcobro/common 1.11.3
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/CHANGELOG.md +115 -0
- package/package.json +25 -0
- package/src/config.test.ts +19 -0
- package/src/config.ts +358 -0
- package/src/errors/ValidationError.test.ts +38 -0
- package/src/errors/ValidationError.ts +68 -0
- package/src/errors/index.ts +1 -0
- package/src/index.ts +21 -0
- package/src/schemas/agentTemplates.ts +100 -0
- package/src/schemas/apiKeys.test.ts +38 -0
- package/src/schemas/apiKeys.ts +28 -0
- package/src/schemas/auth.ts +76 -0
- package/src/schemas/campaigns.ts +88 -0
- package/src/schemas/contactLog.ts +96 -0
- package/src/schemas/dispatch.ts +115 -0
- package/src/schemas/email.ts +37 -0
- package/src/schemas/index.ts +15 -0
- package/src/schemas/insight.ts +20 -0
- package/src/schemas/portfolios.ts +49 -0
- package/src/schemas/userSettings.ts +18 -0
- package/src/schemas/users.ts +7 -0
- package/src/schemas/voiceEvent.ts +45 -0
- package/src/schemas/whatsApp.ts +101 -0
- package/src/schemas/workspaceSettings.ts +20 -0
- package/src/schemas/workspaces.ts +53 -0
- package/src/types/agentTemplates.ts +104 -0
- package/src/types/campaigns.ts +210 -0
- package/src/types/dispatch.ts +160 -0
- package/src/types/email.ts +66 -0
- package/src/types/engine.ts +73 -0
- package/src/types/index.ts +11 -0
- package/src/types/insight.ts +20 -0
- package/src/types/portfolios.ts +128 -0
- package/src/types/userSettings.ts +21 -0
- package/src/types/voiceApplication.ts +29 -0
- package/src/types/whatsApp.ts +82 -0
- package/src/types/workspaceSettings.ts +22 -0
- package/src/utils/index.ts +14 -0
- package/src/utils/outreach.test.ts +83 -0
- package/src/utils/outreach.ts +57 -0
- package/src/utils/time.ts +66 -0
- package/src/utils/withErrorHandlingAndValidation.test.ts +33 -0
- package/src/utils/withErrorHandlingAndValidation.ts +32 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/** Supported console languages. Keep in sync with the webapp message catalogs. */
|
|
4
|
+
export const languageSchema = z.enum(["en", "es"]);
|
|
5
|
+
export type Language = z.infer<typeof languageSchema>;
|
|
6
|
+
|
|
7
|
+
/** The per-user settings record (stored in the app DB, keyed by the Identity userRef). */
|
|
8
|
+
export const userSettingsSchema = z.object({
|
|
9
|
+
userRef: z.string().min(1),
|
|
10
|
+
language: languageSchema
|
|
11
|
+
});
|
|
12
|
+
export type UserSettings = z.infer<typeof userSettingsSchema>;
|
|
13
|
+
|
|
14
|
+
/** Operator-editable user settings. */
|
|
15
|
+
export const updateUserLanguageSchema = z.object({
|
|
16
|
+
language: languageSchema
|
|
17
|
+
});
|
|
18
|
+
export type UpdateUserLanguageInput = z.infer<typeof updateUserLanguageSchema>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Events emitted by the Fonoster autopilot events-hook for a Voz IA call.
|
|
5
|
+
* `conversation.started` lets us capture partial data even if the call never ends
|
|
6
|
+
* cleanly; `conversation.ended` carries the transcript and recording.
|
|
7
|
+
*/
|
|
8
|
+
export const voiceEventTypeSchema = z.enum(["conversation.started", "conversation.ended"]);
|
|
9
|
+
export type VoiceEventType = z.infer<typeof voiceEventTypeSchema>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A raw chat-history entry from the autopilot: `{ ai: text }` (our agent) or
|
|
13
|
+
* `{ human: text }` (the customer). Kept permissive — only the ai/human keys are read.
|
|
14
|
+
*/
|
|
15
|
+
export const voiceChatMessageSchema = z.record(z.string(), z.unknown());
|
|
16
|
+
|
|
17
|
+
export const voiceConversationEventSchema = z.object({
|
|
18
|
+
eventType: voiceEventTypeSchema,
|
|
19
|
+
appRef: z.string().min(1),
|
|
20
|
+
callRef: z.string().min(1),
|
|
21
|
+
phone: z.string().min(1),
|
|
22
|
+
chatHistory: z.array(voiceChatMessageSchema).optional(),
|
|
23
|
+
recordingUrl: z.string().optional(),
|
|
24
|
+
durationSeconds: z.number().int().nonnegative().optional()
|
|
25
|
+
});
|
|
26
|
+
export type VoiceConversationEvent = z.infer<typeof voiceConversationEventSchema>;
|
|
27
|
+
|
|
28
|
+
/** A normalized transcript line stored in `channelData.transcript` for the console. */
|
|
29
|
+
export interface TranscriptLine {
|
|
30
|
+
role: "agent" | "customer";
|
|
31
|
+
text: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Normalize autopilot chatHistory into ordered console transcript lines. */
|
|
35
|
+
export function normalizeChatHistory(
|
|
36
|
+
chatHistory: ReadonlyArray<Record<string, unknown>> | undefined
|
|
37
|
+
): TranscriptLine[] {
|
|
38
|
+
if (!chatHistory) return [];
|
|
39
|
+
const lines: TranscriptLine[] = [];
|
|
40
|
+
for (const entry of chatHistory) {
|
|
41
|
+
if (typeof entry.ai === "string") lines.push({ role: "agent", text: entry.ai });
|
|
42
|
+
else if (typeof entry.human === "string") lines.push({ role: "customer", text: entry.human });
|
|
43
|
+
}
|
|
44
|
+
return lines;
|
|
45
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WhatsApp integration contracts: the per-workspace WABA credentials and its sender
|
|
5
|
+
* numbers, plus the inbound Meta webhook body. This is QCobro's first tenant-provided
|
|
6
|
+
* secret — the `accessToken` is encrypted at rest (cloak) and never returned to clients.
|
|
7
|
+
*
|
|
8
|
+
* The webhook schema is a focused port of `../mikro/mods/common/src/schemas/whatsapp.ts`,
|
|
9
|
+
* trimmed to what QCobro ingests (customer messages, delivery/opt-out statuses) and
|
|
10
|
+
* extended with `metadata.phone_number_id` so events resolve to a workspace/sender.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** What a sender number can do. `messaging` now; `calling` reserved for WhatsApp Voice (future). */
|
|
14
|
+
export const whatsAppCapabilitiesSchema = z.object({
|
|
15
|
+
messaging: z.boolean(),
|
|
16
|
+
calling: z.boolean()
|
|
17
|
+
});
|
|
18
|
+
export type WhatsAppCapabilities = z.infer<typeof whatsAppCapabilitiesSchema>;
|
|
19
|
+
|
|
20
|
+
/** Connect (or update) the workspace's WABA. The token is the tenant secret. */
|
|
21
|
+
export const upsertWhatsAppIntegrationSchema = z.object({
|
|
22
|
+
wabaId: z.string().min(1),
|
|
23
|
+
accessToken: z.string().min(1),
|
|
24
|
+
/** Token echoed back during Meta's webhook verify-token handshake. */
|
|
25
|
+
verifyToken: z.string().min(1),
|
|
26
|
+
/** Meta template-send language for this workspace (e.g. `es_DO`); the single source for
|
|
27
|
+
* the WhatsApp send language. Kept with the WhatsApp config rather than in WorkspaceSettings. */
|
|
28
|
+
defaultLanguage: z.string().min(1)
|
|
29
|
+
});
|
|
30
|
+
export type UpsertWhatsAppIntegrationInput = z.infer<typeof upsertWhatsAppIntegrationSchema>;
|
|
31
|
+
|
|
32
|
+
/** Add a sender number to the workspace's integration. */
|
|
33
|
+
export const addWhatsAppSenderNumberSchema = z.object({
|
|
34
|
+
/** Meta per-number messaging endpoint id. Globally unique across the deployment. */
|
|
35
|
+
phoneNumberId: z.string().min(1),
|
|
36
|
+
/** E.164 display number for the UI. */
|
|
37
|
+
displayNumber: z.string().min(1),
|
|
38
|
+
/** Operator label, e.g. "Cobranza Suave". */
|
|
39
|
+
label: z.string().min(1)
|
|
40
|
+
});
|
|
41
|
+
export type AddWhatsAppSenderNumberInput = z.infer<typeof addWhatsAppSenderNumberSchema>;
|
|
42
|
+
|
|
43
|
+
export const removeWhatsAppSenderNumberSchema = z.object({
|
|
44
|
+
phoneNumberId: z.string().min(1)
|
|
45
|
+
});
|
|
46
|
+
export type RemoveWhatsAppSenderNumberInput = z.infer<typeof removeWhatsAppSenderNumberSchema>;
|
|
47
|
+
|
|
48
|
+
// ── Inbound webhook body (Meta Cloud API) ─────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
const whatsAppInboundMessageSchema = z.object({
|
|
51
|
+
from: z.string(),
|
|
52
|
+
id: z.string(),
|
|
53
|
+
timestamp: z.string(),
|
|
54
|
+
type: z.string(),
|
|
55
|
+
text: z.object({ body: z.string() }).optional()
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/** Delivery/read/opt-out status callbacks. `errors` carries opt-out/block signals (code 131050 etc.). */
|
|
59
|
+
const whatsAppStatusSchema = z.object({
|
|
60
|
+
id: z.string(),
|
|
61
|
+
status: z.string(),
|
|
62
|
+
recipient_id: z.string().optional(),
|
|
63
|
+
timestamp: z.string().optional(),
|
|
64
|
+
errors: z
|
|
65
|
+
.array(z.object({ code: z.number().optional(), title: z.string().optional() }))
|
|
66
|
+
.optional()
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const whatsAppChangeValueSchema = z.object({
|
|
70
|
+
messaging_product: z.string().optional(),
|
|
71
|
+
metadata: z
|
|
72
|
+
.object({
|
|
73
|
+
display_phone_number: z.string().optional(),
|
|
74
|
+
/** Resolves the event to a `WhatsAppSenderNumber` (and thus a workspace). */
|
|
75
|
+
phone_number_id: z.string()
|
|
76
|
+
})
|
|
77
|
+
.optional(),
|
|
78
|
+
messages: z.array(whatsAppInboundMessageSchema).optional(),
|
|
79
|
+
statuses: z.array(whatsAppStatusSchema).optional(),
|
|
80
|
+
// Quality-rating callbacks: phone_number_id is at the value root, not under metadata.
|
|
81
|
+
phone_number_id: z.string().optional(),
|
|
82
|
+
event: z.string().optional(),
|
|
83
|
+
new_quality_rating: z.string().optional()
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const whatsAppChangeSchema = z.object({
|
|
87
|
+
field: z.string().optional(),
|
|
88
|
+
value: whatsAppChangeValueSchema.optional()
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const whatsAppEntrySchema = z.object({
|
|
92
|
+
id: z.string().optional(),
|
|
93
|
+
changes: z.array(whatsAppChangeSchema).optional()
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/** The full inbound webhook body. Lenient on unknown fields Meta may add. */
|
|
97
|
+
export const whatsAppWebhookSchema = z.object({
|
|
98
|
+
object: z.string().optional(),
|
|
99
|
+
entry: z.array(whatsAppEntrySchema).optional()
|
|
100
|
+
});
|
|
101
|
+
export type WhatsAppWebhookBody = z.infer<typeof whatsAppWebhookSchema>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/** Supported display/billing currencies. A workspace has exactly one. */
|
|
4
|
+
export const currencySchema = z.enum(["USD", "DOP"]);
|
|
5
|
+
export type Currency = z.infer<typeof currencySchema>;
|
|
6
|
+
|
|
7
|
+
/** The per-workspace settings record (stored in the app DB, keyed by workspaceRef). */
|
|
8
|
+
export const workspaceSettingsSchema = z.object({
|
|
9
|
+
workspaceRef: z.string().min(1),
|
|
10
|
+
currency: currencySchema,
|
|
11
|
+
timezone: z.string().min(1)
|
|
12
|
+
});
|
|
13
|
+
export type WorkspaceSettings = z.infer<typeof workspaceSettingsSchema>;
|
|
14
|
+
|
|
15
|
+
/** Operator-editable settings for the active workspace. */
|
|
16
|
+
export const updateWorkspaceSettingsSchema = z.object({
|
|
17
|
+
currency: currencySchema,
|
|
18
|
+
timezone: z.string().min(1)
|
|
19
|
+
});
|
|
20
|
+
export type UpdateWorkspaceSettingsInput = z.infer<typeof updateWorkspaceSettingsSchema>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { currencySchema } from "./workspaceSettings.js";
|
|
3
|
+
|
|
4
|
+
export const createWorkspaceSchema = z.object({
|
|
5
|
+
name: z.string().min(1).max(60),
|
|
6
|
+
currency: currencySchema,
|
|
7
|
+
timezone: z.string().min(1)
|
|
8
|
+
});
|
|
9
|
+
export type CreateWorkspaceInput = z.infer<typeof createWorkspaceSchema>;
|
|
10
|
+
|
|
11
|
+
export const getWorkspaceSchema = z.object({
|
|
12
|
+
ref: z.string().min(1)
|
|
13
|
+
});
|
|
14
|
+
export type GetWorkspaceInput = z.infer<typeof getWorkspaceSchema>;
|
|
15
|
+
|
|
16
|
+
export const updateWorkspaceSchema = z.object({
|
|
17
|
+
ref: z.string().min(1),
|
|
18
|
+
name: z.string().min(1).max(60)
|
|
19
|
+
});
|
|
20
|
+
export type UpdateWorkspaceInput = z.infer<typeof updateWorkspaceSchema>;
|
|
21
|
+
|
|
22
|
+
export const deleteWorkspaceSchema = z.object({
|
|
23
|
+
ref: z.string().min(1)
|
|
24
|
+
});
|
|
25
|
+
export type DeleteWorkspaceInput = z.infer<typeof deleteWorkspaceSchema>;
|
|
26
|
+
|
|
27
|
+
export const workspaceRoleEnum = z.enum(["WORKSPACE_ADMIN", "WORKSPACE_MEMBER"]);
|
|
28
|
+
export type WorkspaceRole = z.infer<typeof workspaceRoleEnum>;
|
|
29
|
+
|
|
30
|
+
export const inviteMemberSchema = z.object({
|
|
31
|
+
email: z.email(),
|
|
32
|
+
role: workspaceRoleEnum.default("WORKSPACE_MEMBER"),
|
|
33
|
+
// Identity's inviteUserToWorkspace requires a name; keep the apiserver
|
|
34
|
+
// contract in sync so a missing name fails validation with a clear message
|
|
35
|
+
// instead of an opaque gRPC error.
|
|
36
|
+
name: z.string().min(1).max(60)
|
|
37
|
+
});
|
|
38
|
+
export type InviteMemberInput = z.infer<typeof inviteMemberSchema>;
|
|
39
|
+
|
|
40
|
+
export const removeMemberSchema = z.object({
|
|
41
|
+
userRef: z.string().min(1)
|
|
42
|
+
});
|
|
43
|
+
export type RemoveMemberInput = z.infer<typeof removeMemberSchema>;
|
|
44
|
+
|
|
45
|
+
export const resendInvitationSchema = z.object({
|
|
46
|
+
userRef: z.string().min(1)
|
|
47
|
+
});
|
|
48
|
+
export type ResendInvitationInput = z.infer<typeof resendInvitationSchema>;
|
|
49
|
+
|
|
50
|
+
export const acceptInvitationSchema = z.object({
|
|
51
|
+
token: z.string().min(1)
|
|
52
|
+
});
|
|
53
|
+
export type AcceptInvitationInput = z.infer<typeof acceptInvitationSchema>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentType,
|
|
3
|
+
CreateAgentTemplateInput,
|
|
4
|
+
UpdateAgentTemplateInput,
|
|
5
|
+
DeleteAgentTemplateInput
|
|
6
|
+
} from "../schemas/agentTemplates.js";
|
|
7
|
+
|
|
8
|
+
export interface AgentTemplateRecord {
|
|
9
|
+
id: string;
|
|
10
|
+
workspaceRef: string;
|
|
11
|
+
name: string;
|
|
12
|
+
type: AgentType;
|
|
13
|
+
archivedAt: Date | null;
|
|
14
|
+
createdAt: Date;
|
|
15
|
+
updatedAt: Date;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface VoiceAiConfigRecord {
|
|
19
|
+
templateId: string;
|
|
20
|
+
fonosterAppName: string;
|
|
21
|
+
fonosterAppRef: string | null;
|
|
22
|
+
voice: string;
|
|
23
|
+
systemPrompt: string;
|
|
24
|
+
firstMessage: string | null;
|
|
25
|
+
language: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface VoicePrerecordedConfigRecord {
|
|
29
|
+
templateId: string;
|
|
30
|
+
fonosterAppName: string;
|
|
31
|
+
fonosterAppRef: string | null;
|
|
32
|
+
voice: string;
|
|
33
|
+
script: string;
|
|
34
|
+
language: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SmsConfigRecord {
|
|
38
|
+
templateId: string;
|
|
39
|
+
messageBody: string;
|
|
40
|
+
senderId: string | null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface EmailConfigRecord {
|
|
44
|
+
templateId: string;
|
|
45
|
+
subject: string;
|
|
46
|
+
messageBody: string;
|
|
47
|
+
fromName: string;
|
|
48
|
+
fromEmail: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface WhatsAppConfigRecord {
|
|
52
|
+
templateId: string;
|
|
53
|
+
templateName: string;
|
|
54
|
+
messageBody: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A child-config delegate exposing the create/read/update calls the functions use. */
|
|
58
|
+
interface ChildConfigDelegate<R> {
|
|
59
|
+
create(args: { data: Record<string, unknown> }): Promise<R>;
|
|
60
|
+
update(args: { where: { templateId: string }; data: Record<string, unknown> }): Promise<R>;
|
|
61
|
+
findUnique(args: { where: { templateId: string } }): Promise<R | null>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface AgentTemplateClient {
|
|
65
|
+
agentTemplate: {
|
|
66
|
+
findMany(args: {
|
|
67
|
+
where: { workspaceRef: string; type?: AgentType; archivedAt?: Date | null };
|
|
68
|
+
orderBy?: { createdAt: "asc" | "desc" };
|
|
69
|
+
}): Promise<AgentTemplateRecord[]>;
|
|
70
|
+
|
|
71
|
+
findFirst(args: {
|
|
72
|
+
where: { id: string; workspaceRef: string };
|
|
73
|
+
}): Promise<AgentTemplateRecord | null>;
|
|
74
|
+
|
|
75
|
+
findFirstOrThrow(args: {
|
|
76
|
+
where: { id: string; workspaceRef: string };
|
|
77
|
+
}): Promise<AgentTemplateRecord>;
|
|
78
|
+
|
|
79
|
+
create(args: { data: Record<string, unknown> }): Promise<AgentTemplateRecord>;
|
|
80
|
+
|
|
81
|
+
update(args: {
|
|
82
|
+
where: { id: string };
|
|
83
|
+
data: Record<string, unknown>;
|
|
84
|
+
}): Promise<AgentTemplateRecord>;
|
|
85
|
+
|
|
86
|
+
delete(args: { where: { id: string } }): Promise<AgentTemplateRecord>;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
voiceAiConfig: ChildConfigDelegate<VoiceAiConfigRecord>;
|
|
90
|
+
voicePrerecordedConfig: ChildConfigDelegate<VoicePrerecordedConfigRecord>;
|
|
91
|
+
smsConfig: ChildConfigDelegate<SmsConfigRecord>;
|
|
92
|
+
emailConfig: ChildConfigDelegate<EmailConfigRecord>;
|
|
93
|
+
whatsAppConfig: ChildConfigDelegate<WhatsAppConfigRecord>;
|
|
94
|
+
|
|
95
|
+
campaign: {
|
|
96
|
+
count(args: {
|
|
97
|
+
where: { agentTemplateId: string; status?: { not: "ARCHIVED" } };
|
|
98
|
+
}): Promise<number>;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
$transaction<T>(fn: (tx: AgentTemplateClient) => Promise<T>): Promise<T>;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type { CreateAgentTemplateInput, UpdateAgentTemplateInput, DeleteAgentTemplateInput };
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { AgentType } from "../schemas/agentTemplates.js";
|
|
2
|
+
import type {
|
|
3
|
+
CampaignStatus,
|
|
4
|
+
CreateCampaignInput,
|
|
5
|
+
UpdateCampaignInput,
|
|
6
|
+
UpdateCampaignStatusInput,
|
|
7
|
+
DeleteCampaignInput
|
|
8
|
+
} from "../schemas/campaigns.js";
|
|
9
|
+
import type {
|
|
10
|
+
ContactOutcome,
|
|
11
|
+
PaymentPromiseStatus,
|
|
12
|
+
CreateContactLogInput,
|
|
13
|
+
UpdatePaymentPromiseInput,
|
|
14
|
+
FollowUpPaymentPromiseInput
|
|
15
|
+
} from "../schemas/contactLog.js";
|
|
16
|
+
|
|
17
|
+
export interface CampaignRecord {
|
|
18
|
+
id: string;
|
|
19
|
+
workspaceRef: string;
|
|
20
|
+
name: string;
|
|
21
|
+
agentTemplateId: string;
|
|
22
|
+
status: CampaignStatus;
|
|
23
|
+
startDate: Date;
|
|
24
|
+
endDate: Date | null;
|
|
25
|
+
daysOfWeek: number[];
|
|
26
|
+
startTime: string;
|
|
27
|
+
endTime: string;
|
|
28
|
+
maxAttemptsPerAccount: number;
|
|
29
|
+
maxAttemptsPerDay: number;
|
|
30
|
+
createdAt: Date;
|
|
31
|
+
updatedAt: Date;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface CampaignTriggerRecord {
|
|
35
|
+
id: string;
|
|
36
|
+
campaignId: string;
|
|
37
|
+
type:
|
|
38
|
+
| "MAX_ATTEMPTS_PER_DAY"
|
|
39
|
+
| "DNC_CHECK"
|
|
40
|
+
| "WRONG_NUMBER"
|
|
41
|
+
| "OPT_OUT"
|
|
42
|
+
| "PAYMENT_PROMISE"
|
|
43
|
+
| "INTENT_MET"
|
|
44
|
+
| "CALLBACK_REQUESTED";
|
|
45
|
+
config: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface CampaignAccountStateRecord {
|
|
49
|
+
campaignId: string;
|
|
50
|
+
portfolioAccountId: string;
|
|
51
|
+
attemptCount: number;
|
|
52
|
+
attemptsToday: number;
|
|
53
|
+
lastAttemptAt: Date | null;
|
|
54
|
+
suppressUntil: Date | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface AccountContactLogRecord {
|
|
58
|
+
id: string;
|
|
59
|
+
portfolioAccountId: string;
|
|
60
|
+
campaignId: string | null;
|
|
61
|
+
agentType: AgentType;
|
|
62
|
+
contactedAt: Date;
|
|
63
|
+
durationSeconds: number | null;
|
|
64
|
+
outcome: ContactOutcome;
|
|
65
|
+
notes: string | null;
|
|
66
|
+
debtAmountSnapshot: number | null;
|
|
67
|
+
aiSummary: string | null;
|
|
68
|
+
aiSentiment: string | null;
|
|
69
|
+
aiDebtReason: string | null;
|
|
70
|
+
aiResult: string | null;
|
|
71
|
+
aiNextStep: string | null;
|
|
72
|
+
intentMetadata: Record<string, unknown> | null;
|
|
73
|
+
channelData: Record<string, unknown> | null;
|
|
74
|
+
correctedEntryId: string | null;
|
|
75
|
+
agentTemplateId: string | null;
|
|
76
|
+
paymentPromiseId: string | null;
|
|
77
|
+
providerRef: string | null;
|
|
78
|
+
createdAt: Date;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface PaymentPromiseRecord {
|
|
82
|
+
id: string;
|
|
83
|
+
contactLogId: string;
|
|
84
|
+
portfolioAccountId: string;
|
|
85
|
+
amount: number | null;
|
|
86
|
+
dueDate: Date;
|
|
87
|
+
status: PaymentPromiseStatus;
|
|
88
|
+
notes: string | null;
|
|
89
|
+
createdAt: Date;
|
|
90
|
+
updatedAt: Date;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface CampaignClient {
|
|
94
|
+
agentTemplate: {
|
|
95
|
+
findFirst(args: {
|
|
96
|
+
where: { id: string; workspaceRef: string };
|
|
97
|
+
}): Promise<{ id: string; workspaceRef: string; type: AgentType } | null>;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
whatsAppSenderNumber: {
|
|
101
|
+
findUnique(args: {
|
|
102
|
+
where: { id: string };
|
|
103
|
+
}): Promise<{ id: string; workspaceRef: string } | null>;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
campaign: {
|
|
107
|
+
findMany(args: {
|
|
108
|
+
where: { workspaceRef: string; status?: CampaignStatus | { notIn: CampaignStatus[] } };
|
|
109
|
+
orderBy?: { createdAt: "asc" | "desc" };
|
|
110
|
+
}): Promise<CampaignRecord[]>;
|
|
111
|
+
|
|
112
|
+
findFirst(args: {
|
|
113
|
+
where: { id: string; workspaceRef?: string };
|
|
114
|
+
}): Promise<CampaignRecord | null>;
|
|
115
|
+
|
|
116
|
+
findFirstOrThrow(args: {
|
|
117
|
+
where: { id: string; workspaceRef: string };
|
|
118
|
+
}): Promise<CampaignRecord>;
|
|
119
|
+
|
|
120
|
+
create(args: { data: Record<string, unknown> }): Promise<CampaignRecord>;
|
|
121
|
+
|
|
122
|
+
update(args: { where: { id: string }; data: Record<string, unknown> }): Promise<CampaignRecord>;
|
|
123
|
+
|
|
124
|
+
delete(args: { where: { id: string } }): Promise<CampaignRecord>;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
campaignPortfolio: {
|
|
128
|
+
createMany(args: {
|
|
129
|
+
data: Array<{ campaignId: string; portfolioId: string }>;
|
|
130
|
+
}): Promise<{ count: number }>;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
campaignTrigger: {
|
|
134
|
+
findMany(args: { where: { campaignId: string } }): Promise<CampaignTriggerRecord[]>;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
campaignAccountState: {
|
|
138
|
+
findUnique(args: {
|
|
139
|
+
where: {
|
|
140
|
+
campaignId_portfolioAccountId: { campaignId: string; portfolioAccountId: string };
|
|
141
|
+
};
|
|
142
|
+
}): Promise<CampaignAccountStateRecord | null>;
|
|
143
|
+
|
|
144
|
+
upsert(args: {
|
|
145
|
+
where: {
|
|
146
|
+
campaignId_portfolioAccountId: { campaignId: string; portfolioAccountId: string };
|
|
147
|
+
};
|
|
148
|
+
create: Record<string, unknown>;
|
|
149
|
+
update: Record<string, unknown>;
|
|
150
|
+
}): Promise<CampaignAccountStateRecord>;
|
|
151
|
+
|
|
152
|
+
count(args: { where: { campaignId: string; attemptCount?: { gt: number } } }): Promise<number>;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
accountContactLog: {
|
|
156
|
+
create(args: { data: Record<string, unknown> }): Promise<AccountContactLogRecord>;
|
|
157
|
+
findFirst(args: { where: Record<string, unknown> }): Promise<AccountContactLogRecord | null>;
|
|
158
|
+
update(args: {
|
|
159
|
+
where: { id: string };
|
|
160
|
+
data: Record<string, unknown>;
|
|
161
|
+
}): Promise<AccountContactLogRecord>;
|
|
162
|
+
findMany(args: {
|
|
163
|
+
where: Record<string, unknown>;
|
|
164
|
+
orderBy?: { createdAt: "asc" | "desc" };
|
|
165
|
+
take?: number;
|
|
166
|
+
skip?: number;
|
|
167
|
+
}): Promise<AccountContactLogRecord[]>;
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
paymentPromise: {
|
|
171
|
+
create(args: { data: Record<string, unknown> }): Promise<PaymentPromiseRecord>;
|
|
172
|
+
findFirst(args: { where: Record<string, unknown> }): Promise<PaymentPromiseRecord | null>;
|
|
173
|
+
update(args: {
|
|
174
|
+
where: { id: string };
|
|
175
|
+
data: Record<string, unknown>;
|
|
176
|
+
}): Promise<PaymentPromiseRecord>;
|
|
177
|
+
updateMany(args: {
|
|
178
|
+
where: Record<string, unknown>;
|
|
179
|
+
data: { status: PaymentPromiseStatus };
|
|
180
|
+
}): Promise<{ count: number }>;
|
|
181
|
+
findMany(args: {
|
|
182
|
+
where: Record<string, unknown>;
|
|
183
|
+
orderBy?: { dueDate: "asc" | "desc" };
|
|
184
|
+
}): Promise<PaymentPromiseRecord[]>;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
portfolioAccount: {
|
|
188
|
+
findFirst(args: {
|
|
189
|
+
where: { id: string };
|
|
190
|
+
}): Promise<{ id: string; portfolioId: string; outstandingBalance: number } | null>;
|
|
191
|
+
|
|
192
|
+
update(args: { where: { id: string }; data: Record<string, unknown> }): Promise<{ id: string }>;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
portfolio: {
|
|
196
|
+
update(args: { where: { id: string }; data: Record<string, unknown> }): Promise<{ id: string }>;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
$transaction<T>(fn: (tx: CampaignClient) => Promise<T>): Promise<T>;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export type {
|
|
203
|
+
CreateCampaignInput,
|
|
204
|
+
UpdateCampaignInput,
|
|
205
|
+
UpdateCampaignStatusInput,
|
|
206
|
+
DeleteCampaignInput,
|
|
207
|
+
CreateContactLogInput,
|
|
208
|
+
UpdatePaymentPromiseInput,
|
|
209
|
+
FollowUpPaymentPromiseInput
|
|
210
|
+
};
|