@infuro/cms-core 1.0.34 → 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.
Files changed (158) hide show
  1. package/README.md +13 -0
  2. package/dist/OrderTrackPage-W3J6WIG2.js +426 -0
  3. package/dist/OrderTrackPage-Z6FCJQYY.cjs +428 -0
  4. package/dist/admin.cjs +34329 -20923
  5. package/dist/admin.d.cts +186 -9
  6. package/dist/admin.d.ts +186 -9
  7. package/dist/admin.js +34140 -20829
  8. package/dist/api.cjs +120 -17515
  9. package/dist/api.d.cts +633 -3
  10. package/dist/api.d.ts +633 -3
  11. package/dist/api.js +14 -17528
  12. package/dist/auth.cjs +192 -1034
  13. package/dist/auth.d.cts +194 -51
  14. package/dist/auth.d.ts +194 -51
  15. package/dist/auth.js +4 -966
  16. package/dist/chunk-2XE4X74C.js +29602 -0
  17. package/dist/chunk-3DZRIZOD.cjs +52 -0
  18. package/dist/chunk-3KPNTQBV.cjs +620 -0
  19. package/dist/chunk-46GKADYE.cjs +84 -0
  20. package/dist/chunk-4TRPKBKO.js +589 -0
  21. package/dist/chunk-5ELSW2UP.js +150 -0
  22. package/dist/chunk-6KPQWRFW.js +171 -0
  23. package/dist/chunk-7NMT3GBR.cjs +29 -0
  24. package/dist/chunk-7YIBMQDR.cjs +86 -0
  25. package/dist/chunk-BGJAV67S.cjs +29710 -0
  26. package/dist/chunk-CNTSLED2.cjs +559 -0
  27. package/dist/chunk-CRFV5WJK.js +16 -0
  28. package/dist/chunk-D5FBNKQM.cjs +104 -0
  29. package/dist/chunk-EF2JBPDM.js +114 -0
  30. package/dist/chunk-EQPITOP6.js +543 -0
  31. package/dist/chunk-GO7PPYNU.js +76 -0
  32. package/dist/chunk-HF3L2GIT.cjs +194 -0
  33. package/dist/chunk-J7XHLOLO.js +830 -0
  34. package/dist/chunk-JBRR5UYL.js +87 -0
  35. package/dist/chunk-JC6DLWTE.js +21 -0
  36. package/dist/chunk-JHF4YYRC.cjs +188 -0
  37. package/dist/chunk-JXF23MPG.js +25 -0
  38. package/dist/chunk-MQBT33IV.js +48 -0
  39. package/dist/chunk-N44BJZ4C.cjs +123 -0
  40. package/dist/chunk-OOTLNH63.cjs +18 -0
  41. package/dist/chunk-PAMVINEX.cjs +577 -0
  42. package/dist/chunk-PNOKNSG2.cjs +222 -0
  43. package/dist/chunk-QM733NUK.js +186 -0
  44. package/dist/chunk-R73BKDRO.cjs +90 -0
  45. package/dist/chunk-SHUYVCID.js +4 -0
  46. package/dist/chunk-SYBOCAWB.js +97 -0
  47. package/dist/chunk-TDV6EJHV.js +192 -0
  48. package/dist/chunk-TFUOHI37.cjs +839 -0
  49. package/dist/chunk-TIAEXJLI.cjs +182 -0
  50. package/dist/chunk-UPLVMVRX.cjs +23 -0
  51. package/dist/chunk-USNT2KNT.cjs +6 -0
  52. package/dist/chunk-WEMDMVHQ.js +216 -0
  53. package/dist/chunk-XDSNZUW7.js +564 -0
  54. package/dist/chunk-XQ3QUHWR.cjs +83 -0
  55. package/dist/chunk-XW5ATPRW.cjs +155 -0
  56. package/dist/chunk-ZQ4X6OAU.js +82 -0
  57. package/dist/chunk-ZSVCP6N3.js +83 -0
  58. package/dist/cli.cjs +103 -84
  59. package/dist/cli.js +62 -27
  60. package/dist/email-FKR4FXFI.js +5 -0
  61. package/dist/email-KVKVPNCL.cjs +58 -0
  62. package/dist/email-queue-CGZBVVAS.js +2 -0
  63. package/dist/email-queue-TPZWLTIV.cjs +23 -0
  64. package/dist/erp-config-enabled-CUMQ6N2V.cjs +11 -0
  65. package/dist/erp-config-enabled-T37X7T34.js +2 -0
  66. package/dist/erp-order-invoice-3YISSOWW.js +3 -0
  67. package/dist/erp-order-invoice-ZR5F2KTA.cjs +12 -0
  68. package/dist/event-order-defaults-6E543227.js +2 -0
  69. package/dist/event-order-defaults-DUGDVGJI.cjs +39 -0
  70. package/dist/event-order-notifications-5GSAOYVS.cjs +27 -0
  71. package/dist/event-order-notifications-IIIF23D5.js +10 -0
  72. package/dist/hooks.cjs +259 -132
  73. package/dist/hooks.d.cts +42 -1
  74. package/dist/hooks.d.ts +42 -1
  75. package/dist/hooks.js +234 -91
  76. package/dist/index.cjs +3884 -22307
  77. package/dist/index.d.cts +2203 -772
  78. package/dist/index.d.ts +2203 -772
  79. package/dist/index.js +2871 -22064
  80. package/dist/interpolate-WAKPN56R.cjs +11 -0
  81. package/dist/interpolate-WDUWDF3I.js +2 -0
  82. package/dist/layout-36UFTHC5.cjs +11 -0
  83. package/dist/layout-AOBN26XG.js +2 -0
  84. package/dist/migrations/1779400000000-ConvertStatusToEnum.ts +142 -0
  85. package/dist/migrations/1779400000000-SeedDefaultCurrencies.ts +33 -0
  86. package/dist/migrations/1779500000000-VendorRolesAndPermissions.ts +102 -0
  87. package/dist/migrations/1779600000000-VendorRegistrationProfile.ts +52 -0
  88. package/dist/migrations/1779700000000-CollectionIsCatalog.ts +22 -0
  89. package/dist/migrations/1779710000000-CollectionPlatformCatalog.ts +60 -0
  90. package/dist/migrations/1779720000000-ProductCategoryPlatformCatalog.ts +157 -0
  91. package/dist/migrations/1779800000000-EventsAndEventProducts.ts +173 -0
  92. package/dist/migrations/1779810000000-BackfillVendorRoleEventsPermissions.ts +38 -0
  93. package/dist/migrations/1779820000000-FixProductsCategoryForeignKey.ts +70 -0
  94. package/dist/migrations/1779830000000-ProductTitleColumn.ts +32 -0
  95. package/dist/migrations/1779840000000-EventAboutAndVisibilityFields.ts +34 -0
  96. package/dist/migrations/1779850000000-EventCityCountrySplit.ts +43 -0
  97. package/dist/migrations/1779860000000-CreateCombos.ts +140 -0
  98. package/dist/migrations/1780100000000-OrderAttendeesEventId.ts +55 -0
  99. package/dist/migrations/1780110000000-EventContactFormId.ts +49 -0
  100. package/dist/migrations/1780130000000-ProductVariants.ts +54 -0
  101. package/dist/migrations/1780140000000-EventManagementEnhancements.ts +44 -0
  102. package/dist/migrations/1780160000000-EventRegistrationGstProductContactForm.ts +79 -0
  103. package/dist/migrations/1780170000000-ComboCurrencyPrices.ts +20 -0
  104. package/dist/migrations/1781110000000-VendorOwnerCombosPermission.ts +38 -0
  105. package/dist/migrations/1781120000000-RefundPoliciesAndRequests.ts +225 -0
  106. package/dist/migrations/1781130000000-CreateAttendees.ts +44 -0
  107. package/dist/migrations/1781140000000-EventOrderNotifications.ts +29 -0
  108. package/dist/migrations/1781150000000-EventNamedLists.ts +28 -0
  109. package/dist/migrations/1781160000000-RefundPolicyEventTiers.ts +27 -0
  110. package/dist/migrations/1781170000000-EventRefundPolicy.ts +42 -0
  111. package/dist/migrations/1781180000000-RemoveCartItemsUniqueConstraint.ts +15 -0
  112. package/dist/migrations/1781190000000-RenameProductTaxesToProductConfig.ts +84 -0
  113. package/dist/migrations/1781200000000-VendorOwnerProductConfigPermissions.ts +51 -0
  114. package/dist/migrations/1781210000000-VendorRoleProductConfigPermissions.ts +46 -0
  115. package/dist/migrations/helpers/vendor-role-seed.ts +243 -0
  116. package/dist/paid-order-erp-3USEG6WL.js +3 -0
  117. package/dist/paid-order-erp-FSQ3GSXE.cjs +12 -0
  118. package/dist/pg-boss-service-4XF2TQ2E.js +2 -0
  119. package/dist/pg-boss-service-L6MTF4EQ.cjs +15 -0
  120. package/dist/razorpay-KLO2KNCB.js +49 -0
  121. package/dist/razorpay-U23LGY72.cjs +56 -0
  122. package/dist/rbac-debug-db-D7ME7QUY.cjs +35 -0
  123. package/dist/rbac-debug-db-MTCTVNNM.js +33 -0
  124. package/dist/sms-defaults-2NL24H57.js +2 -0
  125. package/dist/sms-defaults-KCOPKQBA.cjs +19 -0
  126. package/dist/stripe-4FD27QVJ.js +51 -0
  127. package/dist/stripe-VU6OEG2D.cjs +57 -0
  128. package/dist/theme.cjs +31 -59
  129. package/dist/theme.d.cts +78 -3
  130. package/dist/theme.d.ts +78 -3
  131. package/dist/theme.js +23 -20
  132. package/dist/vendor-invite-status-77O7ZQ3U.cjs +19 -0
  133. package/dist/vendor-invite-status-PWJ3DE76.js +2 -0
  134. package/dist/whatsapp-queue-3DXA4MXU.js +2 -0
  135. package/dist/whatsapp-queue-KG65MXD5.cjs +15 -0
  136. package/package.json +147 -142
  137. package/dist/admin.cjs.map +0 -1
  138. package/dist/admin.js.map +0 -1
  139. package/dist/api.cjs.map +0 -1
  140. package/dist/api.js.map +0 -1
  141. package/dist/auth.cjs.map +0 -1
  142. package/dist/auth.js.map +0 -1
  143. package/dist/cli.cjs.map +0 -1
  144. package/dist/cli.js.map +0 -1
  145. package/dist/config-DJ5CmQvS.d.cts +0 -8
  146. package/dist/config-DJ5CmQvS.d.ts +0 -8
  147. package/dist/hooks.cjs.map +0 -1
  148. package/dist/hooks.js.map +0 -1
  149. package/dist/index-Bf5GO8fu.d.cts +0 -583
  150. package/dist/index-DOiJuMQA.d.ts +0 -583
  151. package/dist/index.cjs.map +0 -1
  152. package/dist/index.js.map +0 -1
  153. package/dist/theme.cjs.map +0 -1
  154. package/dist/theme.js.map +0 -1
  155. package/dist/types-DCVaXlPV.d.cts +0 -78
  156. package/dist/types-DCVaXlPV.d.ts +0 -78
  157. package/dist/vendor-scope-DTYhJk_I.d.cts +0 -129
  158. 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;