@infuro/cms-core 1.0.33 → 1.0.35
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/README.md +22 -6
- package/dist/OrderTrackPage-W3J6WIG2.js +426 -0
- package/dist/OrderTrackPage-Z6FCJQYY.cjs +428 -0
- package/dist/admin.cjs +34072 -20487
- package/dist/admin.d.cts +191 -9
- package/dist/admin.d.ts +191 -9
- package/dist/admin.js +33913 -20423
- package/dist/api.cjs +123 -16508
- package/dist/api.d.cts +633 -3
- package/dist/api.d.ts +633 -3
- package/dist/api.js +14 -16519
- package/dist/auth.cjs +196 -955
- package/dist/auth.d.cts +201 -42
- package/dist/auth.d.ts +201 -42
- package/dist/auth.js +4 -888
- package/dist/chunk-2XE4X74C.js +29602 -0
- package/dist/chunk-3DZRIZOD.cjs +52 -0
- package/dist/chunk-3KPNTQBV.cjs +620 -0
- package/dist/chunk-46GKADYE.cjs +84 -0
- package/dist/chunk-4TRPKBKO.js +589 -0
- package/dist/chunk-5ELSW2UP.js +150 -0
- package/dist/chunk-6KPQWRFW.js +171 -0
- package/dist/chunk-7NMT3GBR.cjs +29 -0
- package/dist/chunk-7YIBMQDR.cjs +86 -0
- package/dist/chunk-BGJAV67S.cjs +29710 -0
- package/dist/chunk-CNTSLED2.cjs +559 -0
- package/dist/chunk-CRFV5WJK.js +16 -0
- package/dist/chunk-D5FBNKQM.cjs +104 -0
- package/dist/chunk-EF2JBPDM.js +114 -0
- package/dist/chunk-EQPITOP6.js +543 -0
- package/dist/chunk-GO7PPYNU.js +76 -0
- package/dist/chunk-HF3L2GIT.cjs +194 -0
- package/dist/chunk-J7XHLOLO.js +830 -0
- package/dist/chunk-JBRR5UYL.js +87 -0
- package/dist/chunk-JC6DLWTE.js +21 -0
- package/dist/chunk-JHF4YYRC.cjs +188 -0
- package/dist/chunk-JXF23MPG.js +25 -0
- package/dist/chunk-MQBT33IV.js +48 -0
- package/dist/chunk-N44BJZ4C.cjs +123 -0
- package/dist/chunk-OOTLNH63.cjs +18 -0
- package/dist/chunk-PAMVINEX.cjs +577 -0
- package/dist/chunk-PNOKNSG2.cjs +222 -0
- package/dist/chunk-QM733NUK.js +186 -0
- package/dist/chunk-R73BKDRO.cjs +90 -0
- package/dist/chunk-SHUYVCID.js +4 -0
- package/dist/chunk-SYBOCAWB.js +97 -0
- package/dist/chunk-TDV6EJHV.js +192 -0
- package/dist/chunk-TFUOHI37.cjs +839 -0
- package/dist/chunk-TIAEXJLI.cjs +182 -0
- package/dist/chunk-UPLVMVRX.cjs +23 -0
- package/dist/chunk-USNT2KNT.cjs +6 -0
- package/dist/chunk-WEMDMVHQ.js +216 -0
- package/dist/chunk-XDSNZUW7.js +564 -0
- package/dist/chunk-XQ3QUHWR.cjs +83 -0
- package/dist/chunk-XW5ATPRW.cjs +155 -0
- package/dist/chunk-ZQ4X6OAU.js +82 -0
- package/dist/chunk-ZSVCP6N3.js +83 -0
- package/dist/cli.cjs +142 -84
- package/dist/cli.js +101 -27
- package/dist/email-FKR4FXFI.js +5 -0
- package/dist/email-KVKVPNCL.cjs +58 -0
- package/dist/email-queue-CGZBVVAS.js +2 -0
- package/dist/email-queue-TPZWLTIV.cjs +23 -0
- package/dist/erp-config-enabled-CUMQ6N2V.cjs +11 -0
- package/dist/erp-config-enabled-T37X7T34.js +2 -0
- package/dist/erp-order-invoice-3YISSOWW.js +3 -0
- package/dist/erp-order-invoice-ZR5F2KTA.cjs +12 -0
- package/dist/event-order-defaults-6E543227.js +2 -0
- package/dist/event-order-defaults-DUGDVGJI.cjs +39 -0
- package/dist/event-order-notifications-5GSAOYVS.cjs +27 -0
- package/dist/event-order-notifications-IIIF23D5.js +10 -0
- package/dist/hooks.cjs +259 -132
- package/dist/hooks.d.cts +42 -1
- package/dist/hooks.d.ts +42 -1
- package/dist/hooks.js +234 -91
- package/dist/index.cjs +3884 -21070
- package/dist/index.d.cts +2255 -749
- package/dist/index.d.ts +2255 -749
- package/dist/index.js +1925 -19891
- package/dist/interpolate-WAKPN56R.cjs +11 -0
- package/dist/interpolate-WDUWDF3I.js +2 -0
- package/dist/layout-36UFTHC5.cjs +11 -0
- package/dist/layout-AOBN26XG.js +2 -0
- package/dist/migrations/1778660000004-CreateCustomerAndCustomerContacts.ts +99 -0
- package/dist/migrations/1778660000005-AddCustomerIdToVendorCustomers.ts +39 -0
- package/dist/migrations/1778660000006-UpdateVendorCustomersContactNullable.ts +36 -0
- package/dist/migrations/1778660000007-VendorOwnerCustomerContactsPermission.ts +39 -0
- package/dist/migrations/1779300000000-VendorOwnerContactsPermission.ts +39 -0
- package/dist/migrations/1779400000000-AddCustomerContactIdToOrders.ts +33 -0
- package/dist/migrations/1779400000000-ConvertStatusToEnum.ts +142 -0
- package/dist/migrations/1779400000000-SeedDefaultCurrencies.ts +33 -0
- package/dist/migrations/1779500000000-VendorRolesAndPermissions.ts +102 -0
- package/dist/migrations/1779600000000-VendorRegistrationProfile.ts +52 -0
- package/dist/migrations/1779700000000-CollectionIsCatalog.ts +22 -0
- package/dist/migrations/1779710000000-CollectionPlatformCatalog.ts +60 -0
- package/dist/migrations/1779720000000-ProductCategoryPlatformCatalog.ts +157 -0
- package/dist/migrations/1779800000000-EventsAndEventProducts.ts +173 -0
- package/dist/migrations/1779810000000-BackfillVendorRoleEventsPermissions.ts +38 -0
- package/dist/migrations/1779820000000-FixProductsCategoryForeignKey.ts +70 -0
- package/dist/migrations/1779830000000-ProductTitleColumn.ts +32 -0
- package/dist/migrations/1779840000000-EventAboutAndVisibilityFields.ts +34 -0
- package/dist/migrations/1779850000000-EventCityCountrySplit.ts +43 -0
- package/dist/migrations/1779860000000-CreateCombos.ts +140 -0
- package/dist/migrations/1780100000000-OrderAttendeesEventId.ts +55 -0
- package/dist/migrations/1780110000000-EventContactFormId.ts +49 -0
- package/dist/migrations/1780130000000-ProductVariants.ts +54 -0
- package/dist/migrations/1780140000000-EventManagementEnhancements.ts +44 -0
- package/dist/migrations/1780160000000-EventRegistrationGstProductContactForm.ts +79 -0
- package/dist/migrations/1780170000000-ComboCurrencyPrices.ts +20 -0
- package/dist/migrations/1781110000000-VendorOwnerCombosPermission.ts +38 -0
- package/dist/migrations/1781120000000-RefundPoliciesAndRequests.ts +225 -0
- package/dist/migrations/1781130000000-CreateAttendees.ts +44 -0
- package/dist/migrations/1781140000000-EventOrderNotifications.ts +29 -0
- package/dist/migrations/1781150000000-EventNamedLists.ts +28 -0
- package/dist/migrations/1781160000000-RefundPolicyEventTiers.ts +27 -0
- package/dist/migrations/1781170000000-EventRefundPolicy.ts +42 -0
- package/dist/migrations/1781180000000-RemoveCartItemsUniqueConstraint.ts +15 -0
- package/dist/migrations/1781190000000-RenameProductTaxesToProductConfig.ts +84 -0
- package/dist/migrations/1781200000000-VendorOwnerProductConfigPermissions.ts +51 -0
- package/dist/migrations/1781210000000-VendorRoleProductConfigPermissions.ts +46 -0
- package/dist/migrations/helpers/vendor-role-seed.ts +243 -0
- package/dist/paid-order-erp-3USEG6WL.js +3 -0
- package/dist/paid-order-erp-FSQ3GSXE.cjs +12 -0
- package/dist/pg-boss-service-4XF2TQ2E.js +2 -0
- package/dist/pg-boss-service-L6MTF4EQ.cjs +15 -0
- package/dist/razorpay-KLO2KNCB.js +49 -0
- package/dist/razorpay-U23LGY72.cjs +56 -0
- package/dist/rbac-debug-db-D7ME7QUY.cjs +35 -0
- package/dist/rbac-debug-db-MTCTVNNM.js +33 -0
- package/dist/sms-defaults-2NL24H57.js +2 -0
- package/dist/sms-defaults-KCOPKQBA.cjs +19 -0
- package/dist/stripe-4FD27QVJ.js +51 -0
- package/dist/stripe-VU6OEG2D.cjs +57 -0
- package/dist/theme.cjs +31 -59
- package/dist/theme.d.cts +78 -3
- package/dist/theme.d.ts +78 -3
- package/dist/theme.js +23 -20
- package/dist/vendor-invite-status-77O7ZQ3U.cjs +19 -0
- package/dist/vendor-invite-status-PWJ3DE76.js +2 -0
- package/dist/whatsapp-queue-3DXA4MXU.js +2 -0
- package/dist/whatsapp-queue-KG65MXD5.cjs +15 -0
- package/package.json +147 -141
- package/dist/admin.cjs.map +0 -1
- package/dist/admin.js.map +0 -1
- package/dist/api.cjs.map +0 -1
- package/dist/api.js.map +0 -1
- package/dist/auth.cjs.map +0 -1
- package/dist/auth.js.map +0 -1
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/config-DJ5CmQvS.d.cts +0 -8
- package/dist/config-DJ5CmQvS.d.ts +0 -8
- package/dist/hooks.cjs.map +0 -1
- package/dist/hooks.js.map +0 -1
- package/dist/index-DWd5Gjc4.d.ts +0 -582
- package/dist/index-rZTnpK7y.d.cts +0 -582
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/theme.cjs.map +0 -1
- package/dist/theme.js.map +0 -1
- package/dist/types-DCVaXlPV.d.cts +0 -78
- package/dist/types-DCVaXlPV.d.ts +0 -78
- package/dist/vendor-scope-DTYhJk_I.d.cts +0 -129
- package/dist/vendor-scope-DTYhJk_I.d.ts +0 -129
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
import { queueEmail } from './chunk-5ELSW2UP.js';
|
|
2
|
+
import { __name } from './chunk-SHUYVCID.js';
|
|
3
|
+
|
|
4
|
+
// src/plugins/email/templates/types.ts
|
|
5
|
+
function normalizeSocialLinkItem(o) {
|
|
6
|
+
const url = String(o.url ?? "").trim();
|
|
7
|
+
if (!url) return null;
|
|
8
|
+
let iconUrl = String(o.iconUrl ?? o.icon_image ?? "").trim();
|
|
9
|
+
let icon = String(o.icon ?? "").trim();
|
|
10
|
+
if (!iconUrl && /^https?:\/\//i.test(icon)) {
|
|
11
|
+
iconUrl = icon;
|
|
12
|
+
icon = "";
|
|
13
|
+
}
|
|
14
|
+
const item = {
|
|
15
|
+
url
|
|
16
|
+
};
|
|
17
|
+
if (iconUrl) item.iconUrl = iconUrl;
|
|
18
|
+
if (icon) item.icon = icon;
|
|
19
|
+
return item;
|
|
20
|
+
}
|
|
21
|
+
__name(normalizeSocialLinkItem, "normalizeSocialLinkItem");
|
|
22
|
+
function parseSocialLinksJson(raw) {
|
|
23
|
+
if (raw == null || raw.trim() === "") return void 0;
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(raw);
|
|
26
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
27
|
+
const out = [];
|
|
28
|
+
for (const item of parsed) {
|
|
29
|
+
if (item && typeof item === "object" && "url" in item) {
|
|
30
|
+
const n = normalizeSocialLinkItem(item);
|
|
31
|
+
if (n) out.push(n);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return out.length ? out : void 0;
|
|
35
|
+
} catch {
|
|
36
|
+
return void 0;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
__name(parseSocialLinksJson, "parseSocialLinksJson");
|
|
40
|
+
function mergeEmailLayoutCompanyDetails(branding, emailSettings) {
|
|
41
|
+
const fromBranding = getCompanyDetailsFromSettings(branding);
|
|
42
|
+
const pick = /* @__PURE__ */ __name((emailVal, fallback) => {
|
|
43
|
+
const t = emailVal?.trim();
|
|
44
|
+
return t || fallback?.trim() || void 0;
|
|
45
|
+
}, "pick");
|
|
46
|
+
const logoUrl = pick(emailSettings.logoUrl ?? emailSettings.emailLogoUrl, fromBranding.logoUrl);
|
|
47
|
+
const companyName = pick(emailSettings.companyName ?? emailSettings.emailCompanyName, fromBranding.companyName);
|
|
48
|
+
const supportEmail = pick(emailSettings.supportEmail ?? emailSettings.emailSupportEmail, fromBranding.supportEmail);
|
|
49
|
+
const supportPhone = pick(emailSettings.supportPhone, void 0);
|
|
50
|
+
const footerDisclaimer = pick(emailSettings.footerDisclaimer, void 0);
|
|
51
|
+
const followUsTitle = pick(emailSettings.followUsTitle, "Follow Us") || "Follow Us";
|
|
52
|
+
const socialFromEmail = parseSocialLinksJson(emailSettings.socialLinks);
|
|
53
|
+
const socialLinks = socialFromEmail?.length ? socialFromEmail : fromBranding.socialLinks;
|
|
54
|
+
return {
|
|
55
|
+
logoUrl,
|
|
56
|
+
companyName,
|
|
57
|
+
supportEmail,
|
|
58
|
+
supportPhone,
|
|
59
|
+
socialLinks,
|
|
60
|
+
footerDisclaimer,
|
|
61
|
+
followUsTitle
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
__name(mergeEmailLayoutCompanyDetails, "mergeEmailLayoutCompanyDetails");
|
|
65
|
+
function getCompanyDetailsFromSettings(settingsGroup) {
|
|
66
|
+
const logoUrl = settingsGroup.logo ?? settingsGroup.logoUrl ?? "";
|
|
67
|
+
const companyName = settingsGroup.companyName ?? settingsGroup.company_name ?? "";
|
|
68
|
+
const supportEmail = settingsGroup.supportEmail ?? settingsGroup.support_email ?? "";
|
|
69
|
+
let socialLinks = [];
|
|
70
|
+
const raw = settingsGroup.socialLinks ?? settingsGroup.social_links;
|
|
71
|
+
if (typeof raw === "string") {
|
|
72
|
+
try {
|
|
73
|
+
const arr = JSON.parse(raw);
|
|
74
|
+
if (Array.isArray(arr)) {
|
|
75
|
+
for (const item of arr) {
|
|
76
|
+
if (item && typeof item === "object") {
|
|
77
|
+
const n = normalizeSocialLinkItem(item);
|
|
78
|
+
if (n) socialLinks.push(n);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
logoUrl: logoUrl || void 0,
|
|
87
|
+
companyName: companyName || void 0,
|
|
88
|
+
supportEmail: supportEmail || void 0,
|
|
89
|
+
socialLinks: socialLinks.length ? socialLinks : void 0
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
__name(getCompanyDetailsFromSettings, "getCompanyDetailsFromSettings");
|
|
93
|
+
|
|
94
|
+
// src/lib/email-recipients.ts
|
|
95
|
+
function parseEmailRecipientsFromConfig(raw) {
|
|
96
|
+
if (raw == null || raw === "") return [];
|
|
97
|
+
const trimmed = raw.trim();
|
|
98
|
+
if (trimmed.startsWith("[")) {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = JSON.parse(trimmed);
|
|
101
|
+
if (Array.isArray(parsed)) {
|
|
102
|
+
return parsed.map((e) => String(e).trim()).filter(Boolean);
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return trimmed.split(/[,;]+/).map((s) => s.trim()).filter(Boolean);
|
|
108
|
+
}
|
|
109
|
+
__name(parseEmailRecipientsFromConfig, "parseEmailRecipientsFromConfig");
|
|
110
|
+
function serializeEmailRecipients(emails) {
|
|
111
|
+
return JSON.stringify(emails);
|
|
112
|
+
}
|
|
113
|
+
__name(serializeEmailRecipients, "serializeEmailRecipients");
|
|
114
|
+
function joinRecipientsForSend(emails) {
|
|
115
|
+
if (!emails.length) return null;
|
|
116
|
+
return emails.join(", ");
|
|
117
|
+
}
|
|
118
|
+
__name(joinRecipientsForSend, "joinRecipientsForSend");
|
|
119
|
+
|
|
120
|
+
// src/plugins/llm/chat-email-intent.ts
|
|
121
|
+
var NONE_INTENT = "NONE";
|
|
122
|
+
var CHAT_EMAIL_LOG = "[chat-email-tool]";
|
|
123
|
+
function logChatEmail(step, data) {
|
|
124
|
+
if (data && Object.keys(data).length > 0) {
|
|
125
|
+
console.info(CHAT_EMAIL_LOG, step, data);
|
|
126
|
+
} else {
|
|
127
|
+
console.info(CHAT_EMAIL_LOG, step);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
__name(logChatEmail, "logChatEmail");
|
|
131
|
+
function normalizeIntentKey(raw) {
|
|
132
|
+
return raw.trim().toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
|
|
133
|
+
}
|
|
134
|
+
__name(normalizeIntentKey, "normalizeIntentKey");
|
|
135
|
+
function parseIntentsJson(raw) {
|
|
136
|
+
if (!raw?.trim()) return null;
|
|
137
|
+
try {
|
|
138
|
+
const parsed = JSON.parse(raw);
|
|
139
|
+
if (!Array.isArray(parsed)) return null;
|
|
140
|
+
const out = [];
|
|
141
|
+
for (const row of parsed) {
|
|
142
|
+
if (!row || typeof row !== "object") continue;
|
|
143
|
+
const o = row;
|
|
144
|
+
const intent = normalizeIntentKey(String(o.intent ?? o.id ?? ""));
|
|
145
|
+
const description = String(o.description ?? "").trim();
|
|
146
|
+
const emailTo = String(o.emailTo ?? o.email ?? "").trim();
|
|
147
|
+
if (!intent || !description || !emailTo) continue;
|
|
148
|
+
out.push({
|
|
149
|
+
intent,
|
|
150
|
+
description,
|
|
151
|
+
emailTo
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return out.length > 0 ? out : null;
|
|
155
|
+
} catch {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
__name(parseIntentsJson, "parseIntentsJson");
|
|
160
|
+
function dedupeIntents(intents) {
|
|
161
|
+
const seen = /* @__PURE__ */ new Set();
|
|
162
|
+
const out = [];
|
|
163
|
+
for (const row of intents) {
|
|
164
|
+
const key = normalizeIntentKey(row.intent);
|
|
165
|
+
if (!key || seen.has(key)) continue;
|
|
166
|
+
seen.add(key);
|
|
167
|
+
out.push({
|
|
168
|
+
intent: key,
|
|
169
|
+
description: row.description.trim(),
|
|
170
|
+
emailTo: row.emailTo.trim()
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
__name(dedupeIntents, "dedupeIntents");
|
|
176
|
+
function parseChatEmailToolSettings(map) {
|
|
177
|
+
const fromJson = parseIntentsJson(map.emailIntents);
|
|
178
|
+
const intents = dedupeIntents(fromJson ?? []);
|
|
179
|
+
const legacyPositive = map.emailIntentPrompt?.trim() ?? "";
|
|
180
|
+
const legacyNegative = map.emailNegativeIntentPrompt?.trim() ?? "";
|
|
181
|
+
let classifierInstructions = map.emailClassifierInstructions?.trim() ?? "";
|
|
182
|
+
if (!classifierInstructions && (legacyPositive || legacyNegative)) {
|
|
183
|
+
const parts = [];
|
|
184
|
+
if (legacyPositive) parts.push(`Legacy positive signals:
|
|
185
|
+
${legacyPositive}`);
|
|
186
|
+
if (legacyNegative) parts.push(`Do NOT assign an intent when:
|
|
187
|
+
${legacyNegative}`);
|
|
188
|
+
classifierInstructions = parts.join("\n\n");
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
enabled: map.emailToolEnabled === "true",
|
|
192
|
+
intents,
|
|
193
|
+
classifierInstructions,
|
|
194
|
+
toolPrompt: map.emailToolPrompt ?? ""
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
__name(parseChatEmailToolSettings, "parseChatEmailToolSettings");
|
|
198
|
+
var EMAIL_TOOL_VALIDATION_KEY = "emailTool";
|
|
199
|
+
function parseEmailToolObject(raw) {
|
|
200
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
201
|
+
const o = raw;
|
|
202
|
+
const intentsRaw = o.intents;
|
|
203
|
+
let intents;
|
|
204
|
+
if (Array.isArray(intentsRaw)) {
|
|
205
|
+
const parsed = parseIntentsJson(JSON.stringify(intentsRaw));
|
|
206
|
+
if (parsed?.length) intents = parsed;
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
enabled: o.enabled === true,
|
|
210
|
+
classifierInstructions: typeof o.classifierInstructions === "string" ? o.classifierInstructions.trim() : void 0,
|
|
211
|
+
toolPrompt: typeof o.toolPrompt === "string" ? o.toolPrompt.trim() : void 0,
|
|
212
|
+
intents
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
__name(parseEmailToolObject, "parseEmailToolObject");
|
|
216
|
+
function parseEmailToolFromAgentValidationRules(validationRulesText) {
|
|
217
|
+
const raw = validationRulesText?.trim();
|
|
218
|
+
if (!raw) return null;
|
|
219
|
+
try {
|
|
220
|
+
const parsed = JSON.parse(raw);
|
|
221
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
222
|
+
const emailTool = parsed[EMAIL_TOOL_VALIDATION_KEY];
|
|
223
|
+
return parseEmailToolObject(emailTool);
|
|
224
|
+
} catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
__name(parseEmailToolFromAgentValidationRules, "parseEmailToolFromAgentValidationRules");
|
|
229
|
+
function resolveChatEmailToolSettings(configMap, sources) {
|
|
230
|
+
const fromConfig = parseChatEmailToolSettings(configMap);
|
|
231
|
+
const resolved = typeof sources === "string" || sources == null ? {
|
|
232
|
+
chatbotValidationRules: typeof sources === "string" ? sources : null
|
|
233
|
+
} : sources;
|
|
234
|
+
const fromChatbot = parseEmailToolFromAgentValidationRules(resolved.chatbotValidationRules);
|
|
235
|
+
const fromNotify = resolved.notifyAgent ? parseEmailToolFromAgentValidationRules(resolved.notifyAgent.validationRules) : null;
|
|
236
|
+
const notifySystem = resolved.notifyAgent?.systemInstruction?.trim() ?? "";
|
|
237
|
+
const intents = fromNotify?.intents?.length ? fromNotify.intents : fromChatbot?.intents?.length ? fromChatbot.intents : fromConfig.intents;
|
|
238
|
+
const classifierParts = [
|
|
239
|
+
notifySystem,
|
|
240
|
+
fromNotify?.classifierInstructions?.trim(),
|
|
241
|
+
fromChatbot?.classifierInstructions?.trim(),
|
|
242
|
+
fromConfig.classifierInstructions.trim()
|
|
243
|
+
].filter(Boolean);
|
|
244
|
+
const toolPrompt = fromNotify?.toolPrompt?.trim() || fromChatbot?.toolPrompt?.trim() || fromConfig.toolPrompt?.trim() || "";
|
|
245
|
+
return {
|
|
246
|
+
enabled: fromConfig.enabled,
|
|
247
|
+
intents,
|
|
248
|
+
classifierInstructions: classifierParts.join("\n\n"),
|
|
249
|
+
toolPrompt
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
__name(resolveChatEmailToolSettings, "resolveChatEmailToolSettings");
|
|
253
|
+
function intentByKey(intents, key) {
|
|
254
|
+
if (!key) return null;
|
|
255
|
+
const norm = normalizeIntentKey(key);
|
|
256
|
+
return intents.find((i) => i.intent === norm) ?? null;
|
|
257
|
+
}
|
|
258
|
+
__name(intentByKey, "intentByKey");
|
|
259
|
+
function buildIntentTableForPrompt(intents) {
|
|
260
|
+
return intents.map((i) => `- ${i.intent}: ${i.description} \u2192 notify ${i.emailTo}`).join("\n");
|
|
261
|
+
}
|
|
262
|
+
__name(buildIntentTableForPrompt, "buildIntentTableForPrompt");
|
|
263
|
+
function buildIntentClassifierSystem(config, agentClassifierInstructions) {
|
|
264
|
+
const table = buildIntentTableForPrompt(config.intents);
|
|
265
|
+
const extra = [
|
|
266
|
+
agentClassifierInstructions?.trim(),
|
|
267
|
+
config.classifierInstructions.trim()
|
|
268
|
+
].filter(Boolean).join("\n\n");
|
|
269
|
+
const intentKeys = config.intents.map((i) => i.intent).join(", ");
|
|
270
|
+
return `You classify a chat visitor into exactly one lead intent for email routing.
|
|
271
|
+
|
|
272
|
+
Available intents (pick the best match):
|
|
273
|
+
${table}
|
|
274
|
+
|
|
275
|
+
If the visitor is not ready for a lead email (general FAQ, greetings only, spam, off-topic, no clear business need), use intent "${NONE_INTENT}".
|
|
276
|
+
|
|
277
|
+
Allowed intent values: ${intentKeys}, or ${NONE_INTENT}.
|
|
278
|
+
|
|
279
|
+
${extra ? `Additional instructions:
|
|
280
|
+
${extra}
|
|
281
|
+
` : ""}
|
|
282
|
+
Reply with ONLY valid JSON, no markdown:
|
|
283
|
+
{"intent":"INTENT_KEY","reason":"short explanation"}
|
|
284
|
+
Use "${NONE_INTENT}" when no intent applies.`;
|
|
285
|
+
}
|
|
286
|
+
__name(buildIntentClassifierSystem, "buildIntentClassifierSystem");
|
|
287
|
+
function buildChatEmailAgentContext(settings) {
|
|
288
|
+
if (!settings.enabled) return "";
|
|
289
|
+
const classifier = settings.classifierInstructions.trim();
|
|
290
|
+
const extra = settings.toolPrompt?.trim() ?? "";
|
|
291
|
+
const parts = [];
|
|
292
|
+
if (settings.intents.length > 0) {
|
|
293
|
+
parts.push("## Lead email routing", "When a visitor message clearly matches an intent below, the system sends one team notification email (per conversation). Continue the conversation normally in all cases.");
|
|
294
|
+
if (classifier) parts.push(`### Routing rules
|
|
295
|
+
${classifier}`);
|
|
296
|
+
parts.push(`### Intent catalog
|
|
297
|
+
${buildIntentTableForPrompt(settings.intents)}`);
|
|
298
|
+
} else if (classifier) {
|
|
299
|
+
parts.push(`## Lead email routing
|
|
300
|
+
${classifier}`);
|
|
301
|
+
}
|
|
302
|
+
if (extra) parts.push(`### Assistant behavior
|
|
303
|
+
${extra}`);
|
|
304
|
+
return parts.join("\n\n");
|
|
305
|
+
}
|
|
306
|
+
__name(buildChatEmailAgentContext, "buildChatEmailAgentContext");
|
|
307
|
+
function buildChatbotSystemPromptWithEmailTool(baseSystemInstruction, guardrailsForPrompt, emailSettings) {
|
|
308
|
+
let prompt = (baseSystemInstruction ?? "").trim();
|
|
309
|
+
const guard = guardrailsForPrompt?.trim();
|
|
310
|
+
if (guard) prompt = [
|
|
311
|
+
prompt,
|
|
312
|
+
guard
|
|
313
|
+
].filter(Boolean).join("\n\n");
|
|
314
|
+
if (emailSettings.enabled) {
|
|
315
|
+
const emailCtx = buildChatEmailAgentContext(emailSettings);
|
|
316
|
+
if (emailCtx) prompt = [
|
|
317
|
+
prompt,
|
|
318
|
+
emailCtx
|
|
319
|
+
].filter(Boolean).join("\n\n");
|
|
320
|
+
}
|
|
321
|
+
return prompt;
|
|
322
|
+
}
|
|
323
|
+
__name(buildChatbotSystemPromptWithEmailTool, "buildChatbotSystemPromptWithEmailTool");
|
|
324
|
+
function formatTranscript(history, latestMessage, maxChars = 4e3) {
|
|
325
|
+
const lines = [];
|
|
326
|
+
for (const m of history) {
|
|
327
|
+
const role = m.role === "assistant" ? "Assistant" : m.role === "user" ? "Visitor" : "System";
|
|
328
|
+
lines.push(`${role}: ${m.content}`);
|
|
329
|
+
}
|
|
330
|
+
const last = history[history.length - 1];
|
|
331
|
+
if (!last || last.role !== "user" || last.content !== latestMessage) {
|
|
332
|
+
lines.push(`Visitor: ${latestMessage}`);
|
|
333
|
+
}
|
|
334
|
+
let text = lines.join("\n");
|
|
335
|
+
if (text.length > maxChars) text = text.slice(-maxChars);
|
|
336
|
+
return text;
|
|
337
|
+
}
|
|
338
|
+
__name(formatTranscript, "formatTranscript");
|
|
339
|
+
function parseIntentJson(raw, intents) {
|
|
340
|
+
const trimmed = raw.trim();
|
|
341
|
+
const fence = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
342
|
+
const candidate = (fence?.[1] ?? trimmed).trim();
|
|
343
|
+
const tryParse = /* @__PURE__ */ __name((s) => {
|
|
344
|
+
const o = JSON.parse(s);
|
|
345
|
+
let intentRaw = null;
|
|
346
|
+
if (typeof o.intent === "string") intentRaw = o.intent;
|
|
347
|
+
else if (o.interested === false) intentRaw = NONE_INTENT;
|
|
348
|
+
else if (o.interested === true && intents[0]) intentRaw = intents[0].intent;
|
|
349
|
+
if (intentRaw == null) return null;
|
|
350
|
+
const reason = typeof o.reason === "string" && o.reason.trim() ? o.reason.trim() : "Classified from conversation";
|
|
351
|
+
return {
|
|
352
|
+
intent: normalizeIntentKey(intentRaw),
|
|
353
|
+
reason
|
|
354
|
+
};
|
|
355
|
+
}, "tryParse");
|
|
356
|
+
try {
|
|
357
|
+
return tryParse(candidate);
|
|
358
|
+
} catch {
|
|
359
|
+
const m = candidate.match(/\{[\s\S]*\}/);
|
|
360
|
+
if (!m) return null;
|
|
361
|
+
try {
|
|
362
|
+
return tryParse(m[0]);
|
|
363
|
+
} catch {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
__name(parseIntentJson, "parseIntentJson");
|
|
369
|
+
async function detectChatLeadIntent(llm, params) {
|
|
370
|
+
if (!params.settings.intents.length) {
|
|
371
|
+
logChatEmail("classify skipped", {
|
|
372
|
+
reason: "no_intents_configured"
|
|
373
|
+
});
|
|
374
|
+
return {
|
|
375
|
+
intent: null,
|
|
376
|
+
intentLabel: "NONE",
|
|
377
|
+
reason: "No lead intents configured",
|
|
378
|
+
emailTo: null
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
logChatEmail("classify start", {
|
|
382
|
+
intentCount: params.settings.intents.length,
|
|
383
|
+
intentKeys: params.settings.intents.map((i) => i.intent),
|
|
384
|
+
model: params.model?.trim() || "(gateway default)",
|
|
385
|
+
messageChars: params.message.length,
|
|
386
|
+
historyTurns: params.history.length,
|
|
387
|
+
hasClassifierInstructions: Boolean(params.agentClassifierInstructions?.trim() || params.settings.classifierInstructions.trim())
|
|
388
|
+
});
|
|
389
|
+
const transcript = formatTranscript(params.history, params.message);
|
|
390
|
+
const contactLines = [
|
|
391
|
+
params.contact.name?.trim() ? `Name: ${params.contact.name.trim()}` : null,
|
|
392
|
+
params.contact.email?.trim() ? `Email: ${params.contact.email.trim()}` : null,
|
|
393
|
+
params.contact.phone?.trim() ? `Phone: ${params.contact.phone.trim()}` : null
|
|
394
|
+
].filter(Boolean).join("\n");
|
|
395
|
+
const userPrompt = `Customer:
|
|
396
|
+
${contactLines || "(unknown)"}
|
|
397
|
+
|
|
398
|
+
Conversation:
|
|
399
|
+
${transcript}
|
|
400
|
+
|
|
401
|
+
Pick the single best intent for the visitor's latest message.`;
|
|
402
|
+
const res = await llm.chatAgent({
|
|
403
|
+
systemPrompt: buildIntentClassifierSystem(params.settings, params.agentClassifierInstructions),
|
|
404
|
+
userPrompt,
|
|
405
|
+
temperature: 0.1,
|
|
406
|
+
max_tokens: 256,
|
|
407
|
+
...params.model?.trim() ? {
|
|
408
|
+
model: params.model.trim()
|
|
409
|
+
} : {}
|
|
410
|
+
});
|
|
411
|
+
const rawContent = res.content ?? "";
|
|
412
|
+
logChatEmail("classify llm response", {
|
|
413
|
+
responseChars: rawContent.length,
|
|
414
|
+
responsePreview: rawContent.slice(0, 280) + (rawContent.length > 280 ? "\u2026" : "")
|
|
415
|
+
});
|
|
416
|
+
const parsed = parseIntentJson(rawContent, params.settings.intents);
|
|
417
|
+
if (!parsed) {
|
|
418
|
+
logChatEmail("classify result", {
|
|
419
|
+
matched: false,
|
|
420
|
+
outcome: "parse_failed",
|
|
421
|
+
emailWillSend: false
|
|
422
|
+
});
|
|
423
|
+
return {
|
|
424
|
+
intent: null,
|
|
425
|
+
intentLabel: "Unclassified",
|
|
426
|
+
reason: "Could not parse intent classifier response",
|
|
427
|
+
emailTo: null
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
if (parsed.intent === NONE_INTENT) {
|
|
431
|
+
logChatEmail("classify result", {
|
|
432
|
+
matched: false,
|
|
433
|
+
outcome: NONE_INTENT,
|
|
434
|
+
reason: parsed.reason,
|
|
435
|
+
emailWillSend: false
|
|
436
|
+
});
|
|
437
|
+
return {
|
|
438
|
+
intent: null,
|
|
439
|
+
intentLabel: NONE_INTENT,
|
|
440
|
+
reason: parsed.reason,
|
|
441
|
+
emailTo: null
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
const matched = intentByKey(params.settings.intents, parsed.intent);
|
|
445
|
+
if (!matched) {
|
|
446
|
+
logChatEmail("classify result", {
|
|
447
|
+
matched: false,
|
|
448
|
+
outcome: "unknown_intent",
|
|
449
|
+
parsedIntent: parsed.intent,
|
|
450
|
+
reason: parsed.reason,
|
|
451
|
+
emailWillSend: false
|
|
452
|
+
});
|
|
453
|
+
return {
|
|
454
|
+
intent: null,
|
|
455
|
+
intentLabel: parsed.intent,
|
|
456
|
+
reason: `Unknown intent "${parsed.intent}": ${parsed.reason}`,
|
|
457
|
+
emailTo: null
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
logChatEmail("classify result", {
|
|
461
|
+
matched: true,
|
|
462
|
+
outcome: "intent_found",
|
|
463
|
+
intent: matched.intent,
|
|
464
|
+
emailTo: matched.emailTo,
|
|
465
|
+
reason: parsed.reason,
|
|
466
|
+
emailWillSend: true
|
|
467
|
+
});
|
|
468
|
+
return {
|
|
469
|
+
intent: matched.intent,
|
|
470
|
+
intentLabel: `${matched.intent} \u2014 ${matched.description}`,
|
|
471
|
+
reason: parsed.reason,
|
|
472
|
+
emailTo: matched.emailTo
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
__name(detectChatLeadIntent, "detectChatLeadIntent");
|
|
476
|
+
function buildTranscriptForLeadEmail(history, latestMessage) {
|
|
477
|
+
return formatTranscript(history, latestMessage);
|
|
478
|
+
}
|
|
479
|
+
__name(buildTranscriptForLeadEmail, "buildTranscriptForLeadEmail");
|
|
480
|
+
function parseIntentRecipientEmails(emailTo) {
|
|
481
|
+
return emailTo.split(/[,;]+/).map((s) => s.trim()).filter((s) => s.length > 0 && s.includes("@"));
|
|
482
|
+
}
|
|
483
|
+
__name(parseIntentRecipientEmails, "parseIntentRecipientEmails");
|
|
484
|
+
|
|
485
|
+
// src/plugins/email/chat-lead-email.ts
|
|
486
|
+
function resolveLeadRecipients(emailPlugin, emailSettings) {
|
|
487
|
+
const fromCrm = parseEmailRecipientsFromConfig(emailSettings.crmEmails ?? emailSettings.crmEmail ?? "");
|
|
488
|
+
if (fromCrm.length > 0) return fromCrm;
|
|
489
|
+
const fallback = emailPlugin.getDefaultTo?.() ?? "";
|
|
490
|
+
if (fallback.trim()) return [
|
|
491
|
+
fallback.trim()
|
|
492
|
+
];
|
|
493
|
+
return [];
|
|
494
|
+
}
|
|
495
|
+
__name(resolveLeadRecipients, "resolveLeadRecipients");
|
|
496
|
+
async function sendChatLeadEmail(cms, emailSettings, brandingSettings, input) {
|
|
497
|
+
console.info(CHAT_EMAIL_LOG, "send start", {
|
|
498
|
+
conversationId: input.conversationId,
|
|
499
|
+
intentCode: input.intentCode ?? null,
|
|
500
|
+
contactEmail: input.contactEmail,
|
|
501
|
+
contactName: input.contactName,
|
|
502
|
+
explicitRecipients: input.recipients?.length ?? 0
|
|
503
|
+
});
|
|
504
|
+
const email = cms.getPlugin("email");
|
|
505
|
+
if (!email?.send || !email.renderTemplate) {
|
|
506
|
+
console.warn(CHAT_EMAIL_LOG, "send failed", {
|
|
507
|
+
conversationId: input.conversationId,
|
|
508
|
+
reason: "email_plugin_disabled"
|
|
509
|
+
});
|
|
510
|
+
return {
|
|
511
|
+
sent: false,
|
|
512
|
+
recipients: [],
|
|
513
|
+
error: "Email plugin is not enabled"
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
const recipients = input.recipients?.filter((r) => r.trim().includes("@")).map((r) => r.trim()) ?? resolveLeadRecipients(email, emailSettings);
|
|
517
|
+
if (recipients.length === 0) {
|
|
518
|
+
console.warn(CHAT_EMAIL_LOG, "send failed", {
|
|
519
|
+
conversationId: input.conversationId,
|
|
520
|
+
reason: "no_recipients"
|
|
521
|
+
});
|
|
522
|
+
return {
|
|
523
|
+
sent: false,
|
|
524
|
+
recipients: [],
|
|
525
|
+
error: "No lead email recipients (configure intent Email To, CRM emails, or SMTP default To)"
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
console.info(CHAT_EMAIL_LOG, "send recipients resolved", {
|
|
529
|
+
conversationId: input.conversationId,
|
|
530
|
+
recipients,
|
|
531
|
+
source: input.recipients?.length ? "intent_email_to" : "crm_or_smtp_fallback"
|
|
532
|
+
});
|
|
533
|
+
const companyDetails = mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
|
|
534
|
+
const ctx = {
|
|
535
|
+
...input,
|
|
536
|
+
companyDetails: input.companyDetails ?? companyDetails
|
|
537
|
+
};
|
|
538
|
+
let anySent = false;
|
|
539
|
+
for (const to of recipients) {
|
|
540
|
+
await queueEmail(cms, {
|
|
541
|
+
to,
|
|
542
|
+
templateName: "chatLead",
|
|
543
|
+
ctx
|
|
544
|
+
});
|
|
545
|
+
console.info(CHAT_EMAIL_LOG, "send queued", {
|
|
546
|
+
conversationId: input.conversationId,
|
|
547
|
+
to,
|
|
548
|
+
template: "chatLead"
|
|
549
|
+
});
|
|
550
|
+
anySent = true;
|
|
551
|
+
}
|
|
552
|
+
console.info(CHAT_EMAIL_LOG, "send complete", {
|
|
553
|
+
conversationId: input.conversationId,
|
|
554
|
+
sent: anySent,
|
|
555
|
+
recipientCount: recipients.length
|
|
556
|
+
});
|
|
557
|
+
return {
|
|
558
|
+
sent: anySent,
|
|
559
|
+
recipients
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
__name(sendChatLeadEmail, "sendChatLeadEmail");
|
|
563
|
+
|
|
564
|
+
export { CHAT_EMAIL_LOG, buildChatbotSystemPromptWithEmailTool, buildTranscriptForLeadEmail, detectChatLeadIntent, getCompanyDetailsFromSettings, joinRecipientsForSend, mergeEmailLayoutCompanyDetails, parseEmailRecipientsFromConfig, parseIntentRecipientEmails, resolveChatEmailToolSettings, sendChatLeadEmail, serializeEmailRecipients };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
|
|
4
|
+
var PgBoss = require('pg-boss');
|
|
5
|
+
|
|
6
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
|
|
8
|
+
var PgBoss__default = /*#__PURE__*/_interopDefault(PgBoss);
|
|
9
|
+
|
|
10
|
+
var JOB_RUNNER_QUEUE = "job-runner";
|
|
11
|
+
var PgBossService = class {
|
|
12
|
+
static {
|
|
13
|
+
chunkUSNT2KNT_cjs.__name(this, "PgBossService");
|
|
14
|
+
}
|
|
15
|
+
boss;
|
|
16
|
+
started = false;
|
|
17
|
+
workRegistered = /* @__PURE__ */ new Set();
|
|
18
|
+
constructor(connectionString, schema) {
|
|
19
|
+
this.boss = new PgBoss__default.default({
|
|
20
|
+
connectionString,
|
|
21
|
+
...schema?.trim() ? {
|
|
22
|
+
schema: schema.trim()
|
|
23
|
+
} : {},
|
|
24
|
+
schedule: true
|
|
25
|
+
});
|
|
26
|
+
this.boss.on("error", (err) => {
|
|
27
|
+
console.error("[pg-boss]", err);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async start() {
|
|
31
|
+
if (this.started) return;
|
|
32
|
+
await this.boss.start();
|
|
33
|
+
await this.ensureQueue(JOB_RUNNER_QUEUE);
|
|
34
|
+
this.started = true;
|
|
35
|
+
}
|
|
36
|
+
async stop() {
|
|
37
|
+
if (!this.started) return;
|
|
38
|
+
await this.boss.stop({
|
|
39
|
+
graceful: true,
|
|
40
|
+
timeout: 1e4
|
|
41
|
+
});
|
|
42
|
+
this.started = false;
|
|
43
|
+
this.workRegistered.clear();
|
|
44
|
+
}
|
|
45
|
+
get raw() {
|
|
46
|
+
return this.boss;
|
|
47
|
+
}
|
|
48
|
+
async ensureQueue(name) {
|
|
49
|
+
const existing = await this.boss.getQueue(name);
|
|
50
|
+
if (!existing) {
|
|
51
|
+
await this.boss.createQueue(name);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async send(queue, data) {
|
|
55
|
+
await this.ensureQueue(queue);
|
|
56
|
+
return this.boss.send(queue, data, {
|
|
57
|
+
retryLimit: 2
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async schedule(name, cron, data, options) {
|
|
61
|
+
await this.ensureQueue(name);
|
|
62
|
+
await this.boss.schedule(name, cron, data, options);
|
|
63
|
+
}
|
|
64
|
+
async unschedule(name) {
|
|
65
|
+
try {
|
|
66
|
+
await this.boss.unschedule(name);
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async registerWork(queue, handler) {
|
|
71
|
+
if (this.workRegistered.has(queue)) return;
|
|
72
|
+
await this.ensureQueue(queue);
|
|
73
|
+
await this.boss.work(queue, async (jobs) => {
|
|
74
|
+
for (const job of jobs) {
|
|
75
|
+
await handler(job.data);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this.workRegistered.add(queue);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
exports.JOB_RUNNER_QUEUE = JOB_RUNNER_QUEUE;
|
|
83
|
+
exports.PgBossService = PgBossService;
|