@infuro/cms-core 1.0.61 → 1.0.63

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 (50) hide show
  1. package/dist/admin.cjs +3624 -2642
  2. package/dist/admin.js +2415 -1433
  3. package/dist/api.cjs +41 -37
  4. package/dist/api.js +9 -5
  5. package/dist/chunk-3VZAAQUV.js +106 -0
  6. package/dist/{chunk-UHT4INVW.js → chunk-77YWLP4X.js} +625 -252
  7. package/dist/{chunk-BXYZDMTZ.cjs → chunk-7L556RGL.cjs} +3 -94
  8. package/dist/{chunk-T3HPSF7K.js → chunk-AYWDQFJZ.js} +3 -0
  9. package/dist/{chunk-URN7GS23.js → chunk-BWOITUNI.js} +203 -1062
  10. package/dist/{chunk-CNAHVRRU.cjs → chunk-CJEOH6QC.cjs} +676 -312
  11. package/dist/{chunk-O2642WVS.js → chunk-DTUL3Q5L.js} +17 -3
  12. package/dist/{chunk-YSYX4GUD.cjs → chunk-EWXG4E74.cjs} +213 -1082
  13. package/dist/chunk-GWDI752Q.js +83 -0
  14. package/dist/chunk-H3IVLIPR.cjs +86 -0
  15. package/dist/chunk-JLDHK2QE.cjs +109 -0
  16. package/dist/chunk-KAOHOHCA.js +901 -0
  17. package/dist/{chunk-2KUCQVAQ.js → chunk-MWEK7N3F.js} +2 -91
  18. package/dist/{chunk-V25RDUOU.cjs → chunk-MXABMVF7.cjs} +38 -4
  19. package/dist/chunk-OVTOP42W.js +199 -0
  20. package/dist/{chunk-73WVHINE.cjs → chunk-RHYVNRYG.cjs} +18 -4
  21. package/dist/{chunk-L3525VXI.js → chunk-RXTUSF3R.js} +36 -2
  22. package/dist/{chunk-77I3KS7V.cjs → chunk-UEE4PTTB.cjs} +3 -0
  23. package/dist/chunk-WFMVD567.cjs +209 -0
  24. package/dist/chunk-YVP4NQII.cjs +914 -0
  25. package/dist/{email-queue-6NJY6HNM.cjs → email-queue-VTYL2KFA.cjs} +7 -6
  26. package/dist/{email-queue-OI2HSCGE.js → email-queue-YPRSVG56.js} +3 -2
  27. package/dist/email-service-ATCPJFWG.cjs +28 -0
  28. package/dist/email-service-DPKVQOKP.js +3 -0
  29. package/dist/{emit-order-notification-trigger-TNEZOYEE.cjs → emit-order-notification-trigger-WI4HGMKH.cjs} +4 -4
  30. package/dist/{emit-order-notification-trigger-CZU3V2WE.js → emit-order-notification-trigger-XVG2B5ZF.js} +2 -2
  31. package/dist/{erp-order-invoice-3GXDE443.js → erp-order-invoice-3UGWLICU.js} +2 -1
  32. package/dist/{erp-order-invoice-EYYNR526.cjs → erp-order-invoice-KJYJNWMG.cjs} +6 -5
  33. package/dist/index.cjs +366 -316
  34. package/dist/index.d.cts +61 -21
  35. package/dist/index.d.ts +61 -21
  36. package/dist/index.js +79 -29
  37. package/dist/migrations/1783000000000-AddOrderPendingProcessingCompletedTriggers.ts +56 -0
  38. package/dist/migrations/1783100000000-AddSmsToOrderNotificationBindingsChannelEnum.ts +17 -0
  39. package/dist/migrations/1783200000000-AddOrderAssigneeColumns.ts +30 -0
  40. package/dist/order-assignees-handlers-LKMAGLG6.js +150 -0
  41. package/dist/order-assignees-handlers-NPKD64P6.cjs +152 -0
  42. package/dist/order-completion-otp-handlers-IMMQGHDR.cjs +363 -0
  43. package/dist/order-completion-otp-handlers-WGM7HWG4.js +361 -0
  44. package/dist/order-notification-dispatcher-5TUFCDU7.cjs +35 -0
  45. package/dist/order-notification-dispatcher-JKFQJYGG.js +10 -0
  46. package/dist/sms-notification-templates-handlers-SJLO7JGZ.js +47 -0
  47. package/dist/sms-notification-templates-handlers-YSB3L2PK.cjs +49 -0
  48. package/package.json +1 -1
  49. package/dist/order-notification-dispatcher-KJVGLK5E.cjs +0 -24
  50. package/dist/order-notification-dispatcher-ZSFKEYMP.js +0 -7
@@ -1,4 +1,5 @@
1
1
  import { isErpIntegrationEnabled } from './chunk-JC6DLWTE.js';
2
+ import { mergeEmailLayoutCompanyDetails, getCompanyDetailsFromSettings } from './chunk-3VZAAQUV.js';
2
3
  import { __name } from './chunk-SHUYVCID.js';
3
4
  import { rgb, PDFDocument, StandardFonts } from 'pdf-lib';
4
5
 
@@ -583,96 +584,6 @@ function resolveInvoiceAssetUrl(raw) {
583
584
  }
584
585
  __name(resolveInvoiceAssetUrl, "resolveInvoiceAssetUrl");
585
586
 
586
- // src/plugins/email/templates/types.ts
587
- function normalizeSocialLinkItem(o) {
588
- const url = String(o.url ?? "").trim();
589
- if (!url) return null;
590
- let iconUrl = String(o.iconUrl ?? o.icon_image ?? "").trim();
591
- let icon = String(o.icon ?? "").trim();
592
- if (!iconUrl && /^https?:\/\//i.test(icon)) {
593
- iconUrl = icon;
594
- icon = "";
595
- }
596
- const item = {
597
- url
598
- };
599
- if (iconUrl) item.iconUrl = iconUrl;
600
- if (icon) item.icon = icon;
601
- return item;
602
- }
603
- __name(normalizeSocialLinkItem, "normalizeSocialLinkItem");
604
- function parseSocialLinksJson(raw) {
605
- if (raw == null || raw.trim() === "") return void 0;
606
- try {
607
- const parsed = JSON.parse(raw);
608
- if (!Array.isArray(parsed)) return void 0;
609
- const out = [];
610
- for (const item of parsed) {
611
- if (item && typeof item === "object" && "url" in item) {
612
- const n = normalizeSocialLinkItem(item);
613
- if (n) out.push(n);
614
- }
615
- }
616
- return out.length ? out : void 0;
617
- } catch {
618
- return void 0;
619
- }
620
- }
621
- __name(parseSocialLinksJson, "parseSocialLinksJson");
622
- function mergeEmailLayoutCompanyDetails(branding, emailSettings) {
623
- const fromBranding = getCompanyDetailsFromSettings(branding);
624
- const pick = /* @__PURE__ */ __name((emailVal, fallback) => {
625
- const t = emailVal?.trim();
626
- return t || fallback?.trim() || void 0;
627
- }, "pick");
628
- const logoUrl = pick(emailSettings.logoUrl ?? emailSettings.emailLogoUrl, fromBranding.logoUrl);
629
- const companyName = pick(emailSettings.companyName ?? emailSettings.emailCompanyName, fromBranding.companyName);
630
- const supportEmail = pick(emailSettings.supportEmail ?? emailSettings.emailSupportEmail, fromBranding.supportEmail);
631
- const supportPhone = pick(emailSettings.supportPhone, void 0);
632
- const footerDisclaimer = pick(emailSettings.footerDisclaimer, void 0);
633
- const followUsTitle = pick(emailSettings.followUsTitle, "Follow Us") || "Follow Us";
634
- const socialFromEmail = parseSocialLinksJson(emailSettings.socialLinks);
635
- const socialLinks = socialFromEmail?.length ? socialFromEmail : fromBranding.socialLinks;
636
- return {
637
- logoUrl,
638
- companyName,
639
- supportEmail,
640
- supportPhone,
641
- socialLinks,
642
- footerDisclaimer,
643
- followUsTitle
644
- };
645
- }
646
- __name(mergeEmailLayoutCompanyDetails, "mergeEmailLayoutCompanyDetails");
647
- function getCompanyDetailsFromSettings(settingsGroup) {
648
- const logoUrl = settingsGroup.logo ?? settingsGroup.logoUrl ?? "";
649
- const companyName = settingsGroup.companyName ?? settingsGroup.company_name ?? "";
650
- const supportEmail = settingsGroup.supportEmail ?? settingsGroup.support_email ?? "";
651
- let socialLinks = [];
652
- const raw = settingsGroup.socialLinks ?? settingsGroup.social_links;
653
- if (typeof raw === "string") {
654
- try {
655
- const arr = JSON.parse(raw);
656
- if (Array.isArray(arr)) {
657
- for (const item of arr) {
658
- if (item && typeof item === "object") {
659
- const n = normalizeSocialLinkItem(item);
660
- if (n) socialLinks.push(n);
661
- }
662
- }
663
- }
664
- } catch {
665
- }
666
- }
667
- return {
668
- logoUrl: logoUrl || void 0,
669
- companyName: companyName || void 0,
670
- supportEmail: supportEmail || void 0,
671
- socialLinks: socialLinks.length ? socialLinks : void 0
672
- };
673
- }
674
- __name(getCompanyDetailsFromSettings, "getCompanyDetailsFromSettings");
675
-
676
587
  // src/lib/invoice/build-local-invoice-for-order.ts
677
588
  async function loadSettingsGroup(ds, entityMap, group) {
678
589
  if (!entityMap.configs) return {};
@@ -933,4 +844,4 @@ async function streamOrderInvoicePdf(cms, dataSource, entityMap, orderId, option
933
844
  }
934
845
  __name(streamOrderInvoicePdf, "streamOrderInvoicePdf");
935
846
 
936
- export { INVOICE_TEMPLATE_IDS, INVOICE_TEMPLATE_OPTIONS, ORDER_INVOICE_EMAIL_ELIGIBLE_STATUSES, buildLocalInvoicePdfForOrder, extractChildOrderRefsFromSalePayload, generateLocalInvoicePdf, getCompanyDetailsFromSettings, isOrderEligibleForInvoiceEmail, mapErpPayloadToFulfillment, mapErpPayloadToInvoiceNumber, mergeEmailLayoutCompanyDetails, normalizeInvoiceTemplateId, resolveInvoiceAssetUrl, resolveOrderInvoicePdfBytes, streamOrderInvoicePdf, unwrapErpReadData };
847
+ export { INVOICE_TEMPLATE_IDS, INVOICE_TEMPLATE_OPTIONS, ORDER_INVOICE_EMAIL_ELIGIBLE_STATUSES, buildLocalInvoicePdfForOrder, extractChildOrderRefsFromSalePayload, generateLocalInvoicePdf, isOrderEligibleForInvoiceEmail, mapErpPayloadToFulfillment, mapErpPayloadToInvoiceNumber, normalizeInvoiceTemplateId, resolveInvoiceAssetUrl, resolveOrderInvoicePdfBytes, streamOrderInvoicePdf, unwrapErpReadData };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkBXYZDMTZ_cjs = require('./chunk-BXYZDMTZ.cjs');
3
+ var chunk7L556RGL_cjs = require('./chunk-7L556RGL.cjs');
4
4
  var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
5
5
 
6
6
  // src/plugins/email/email-queue.ts
@@ -50,13 +50,13 @@ async function resolveInvoiceAttachmentForJob(cms, payload, options) {
50
50
  invoiceAttached: false
51
51
  };
52
52
  const o = order;
53
- if (!chunkBXYZDMTZ_cjs.isOrderEligibleForInvoiceEmail(o.status, o.orderKind)) {
53
+ if (!chunk7L556RGL_cjs.isOrderEligibleForInvoiceEmail(o.status, o.orderKind)) {
54
54
  return {
55
55
  attachments: payload.attachments,
56
56
  invoiceAttached: false
57
57
  };
58
58
  }
59
- const resolved = await chunkBXYZDMTZ_cjs.resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, payload.orderId);
59
+ const resolved = await chunk7L556RGL_cjs.resolveOrderInvoicePdfBytes(cms, dataSource, entityMap, payload.orderId);
60
60
  if ("error" in resolved) {
61
61
  console.warn("[email] order invoice attach failed", {
62
62
  orderId: payload.orderId,
@@ -130,7 +130,41 @@ async function queueEmail(cms, payload) {
130
130
  await queue.add(EMAIL_QUEUE_NAME, payload);
131
131
  return;
132
132
  }
133
- const email = cms.getPlugin("email");
133
+ let email = cms && typeof cms.getPlugin === "function" ? cms.getPlugin("email") : void 0;
134
+ if (!email) {
135
+ try {
136
+ const { EmailService } = await import('./email-service-ATCPJFWG.cjs');
137
+ const env = typeof process !== "undefined" && process.env ? process.env : {};
138
+ const type = String(env.SMTP_TYPE || "SMTP").toUpperCase();
139
+ const port = env.SMTP_PORT ? parseInt(env.SMTP_PORT, 10) : void 0;
140
+ const fallbackService = new EmailService({
141
+ type: type === "AWS" || type === "GMAIL" || type === "SENDGRID" ? type : "SMTP",
142
+ from: env.SMTP_FROM || "no-reply@example.com",
143
+ to: env.SMTP_TO || "info@example.com",
144
+ user: env.SMTP_USER,
145
+ password: env.SMTP_PASSWORD || env.SMTP_PASS,
146
+ host: env.SMTP_HOST,
147
+ port,
148
+ secure: env.SMTP_SECURE === "true",
149
+ region: env.AWS_SES_REGION || env.AWS_REGION,
150
+ accessKeyId: env.AWS_ACCESS_KEY_ID,
151
+ secretAccessKey: env.AWS_SECRET_ACCESS_KEY
152
+ });
153
+ if (payload.subject != null && payload.html != null) {
154
+ await fallbackService.send({
155
+ to: payload.to,
156
+ subject: payload.subject,
157
+ html: payload.html,
158
+ text: payload.text,
159
+ attachments: payload.attachments
160
+ });
161
+ return;
162
+ }
163
+ } catch (e) {
164
+ console.error("[email-queue] fallback email send error", e);
165
+ return;
166
+ }
167
+ }
134
168
  if (!email) return;
135
169
  const attachmentsResult = await resolveInvoiceAttachmentForJob(cms, payload, registeredInvoiceOptions);
136
170
  if (payload.templateName && payload.ctx) {
@@ -0,0 +1,199 @@
1
+ import { __name } from './chunk-SHUYVCID.js';
2
+ import { createHmac, timingSafeEqual, randomInt } from 'crypto';
3
+ import { MoreThan, IsNull } from 'typeorm';
4
+
5
+ // src/plugins/sms/sms-queue.ts
6
+ var SMS_QUEUE_NAME = "sms";
7
+ function registerSmsQueueProcessor(cms) {
8
+ const queue = cms.getPlugin("queue");
9
+ const sms = cms.getPlugin("sms");
10
+ if (!queue || !sms || typeof sms.send !== "function") return;
11
+ queue.registerProcessor(SMS_QUEUE_NAME, async (data) => {
12
+ const payload = data;
13
+ if (!payload.to) return;
14
+ if (payload.templateKey?.trim()) {
15
+ await sms.send({
16
+ to: payload.to,
17
+ templateKey: payload.templateKey.trim(),
18
+ variables: payload.variables,
19
+ otpCode: payload.otpCode
20
+ });
21
+ return;
22
+ }
23
+ if (!payload.body?.trim()) return;
24
+ await sms.send({
25
+ to: payload.to,
26
+ body: payload.body,
27
+ otpCode: payload.otpCode,
28
+ variables: payload.variables
29
+ });
30
+ });
31
+ }
32
+ __name(registerSmsQueueProcessor, "registerSmsQueueProcessor");
33
+ async function queueSms(cms, payload) {
34
+ const queue = cms.getPlugin("queue");
35
+ const sms = cms.getPlugin("sms");
36
+ if (queue) {
37
+ await queue.add(SMS_QUEUE_NAME, payload);
38
+ return;
39
+ }
40
+ if (sms && typeof sms.send === "function") {
41
+ if (payload.templateKey?.trim()) {
42
+ await sms.send({
43
+ to: payload.to,
44
+ templateKey: payload.templateKey.trim(),
45
+ variables: payload.variables,
46
+ otpCode: payload.otpCode
47
+ });
48
+ return;
49
+ }
50
+ if (payload.body?.trim()) {
51
+ await sms.send({
52
+ to: payload.to,
53
+ body: payload.body,
54
+ otpCode: payload.otpCode,
55
+ variables: payload.variables
56
+ });
57
+ }
58
+ }
59
+ }
60
+ __name(queueSms, "queueSms");
61
+ var OTP_TTL_MS = 10 * 60 * 1e3;
62
+ var MAX_SENDS_PER_HOUR = 5;
63
+ var MAX_VERIFY_ATTEMPTS = 8;
64
+ function getPepper(explicit) {
65
+ return (explicit || process.env.OTP_PEPPER || process.env.NEXTAUTH_SECRET || "dev-otp-pepper").trim();
66
+ }
67
+ __name(getPepper, "getPepper");
68
+ function hashOtpCode(code, purpose, identifier, pepper) {
69
+ return createHmac("sha256", getPepper(pepper)).update(`${purpose}|${identifier}|${code}`).digest("hex");
70
+ }
71
+ __name(hashOtpCode, "hashOtpCode");
72
+ function verifyOtpCodeHash(code, storedHash, purpose, identifier, pepper) {
73
+ const h = hashOtpCode(code, purpose, identifier, pepper);
74
+ try {
75
+ return timingSafeEqual(Buffer.from(h, "utf8"), Buffer.from(storedHash, "utf8"));
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ __name(verifyOtpCodeHash, "verifyOtpCodeHash");
81
+ function generateNumericOtp(length = 6) {
82
+ const max = 10 ** length;
83
+ return randomInt(0, max).toString().padStart(length, "0");
84
+ }
85
+ __name(generateNumericOtp, "generateNumericOtp");
86
+ function normalizePhoneE164(raw, defaultCountryCode) {
87
+ const t = raw.trim();
88
+ const digitsOnly = t.replace(/\D/g, "");
89
+ if (digitsOnly.length < 10) return null;
90
+ if (t.startsWith("+")) return `+${digitsOnly}`;
91
+ const cc = (defaultCountryCode || process.env.DEFAULT_PHONE_COUNTRY_CODE || "91").replace(/\D/g, "");
92
+ if (digitsOnly.length > 10) return `+${digitsOnly}`;
93
+ return `+${cc}${digitsOnly}`;
94
+ }
95
+ __name(normalizePhoneE164, "normalizePhoneE164");
96
+ async function countRecentOtpSends(dataSource, entityMap, purpose, identifier, since) {
97
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
98
+ return repo.count({
99
+ where: {
100
+ purpose,
101
+ identifier,
102
+ createdAt: MoreThan(since)
103
+ }
104
+ });
105
+ }
106
+ __name(countRecentOtpSends, "countRecentOtpSends");
107
+ async function createOtpChallenge(dataSource, entityMap, input) {
108
+ const { purpose, channel, identifier, code, pepper } = input;
109
+ const since = new Date(Date.now() - 60 * 60 * 1e3);
110
+ const recent = await countRecentOtpSends(dataSource, entityMap, purpose, identifier, since);
111
+ if (recent >= MAX_SENDS_PER_HOUR) {
112
+ return {
113
+ ok: false,
114
+ error: "Too many codes sent. Try again later.",
115
+ status: 429
116
+ };
117
+ }
118
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
119
+ await repo.delete({
120
+ purpose,
121
+ identifier,
122
+ consumedAt: IsNull()
123
+ });
124
+ const expiresAt = new Date(Date.now() + OTP_TTL_MS);
125
+ const codeHash = hashOtpCode(code, purpose, identifier, pepper);
126
+ await repo.save(repo.create({
127
+ purpose,
128
+ channel,
129
+ identifier,
130
+ codeHash,
131
+ expiresAt,
132
+ attempts: 0,
133
+ consumedAt: null
134
+ }));
135
+ return {
136
+ ok: true
137
+ };
138
+ }
139
+ __name(createOtpChallenge, "createOtpChallenge");
140
+ async function verifyAndConsumeOtpChallenge(dataSource, entityMap, input) {
141
+ const { purpose, identifier, code, pepper } = input;
142
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
143
+ const row = await repo.findOne({
144
+ where: {
145
+ purpose,
146
+ identifier,
147
+ consumedAt: IsNull()
148
+ },
149
+ order: {
150
+ id: "DESC"
151
+ }
152
+ });
153
+ if (!row) {
154
+ return {
155
+ ok: false,
156
+ error: "Invalid or expired code",
157
+ status: 400
158
+ };
159
+ }
160
+ const r = row;
161
+ if (new Date(r.expiresAt) < /* @__PURE__ */ new Date()) {
162
+ await repo.delete(row.id);
163
+ return {
164
+ ok: false,
165
+ error: "Invalid or expired code",
166
+ status: 400
167
+ };
168
+ }
169
+ const attempts = r.attempts || 0;
170
+ if (attempts >= MAX_VERIFY_ATTEMPTS) {
171
+ await repo.delete(row.id);
172
+ return {
173
+ ok: false,
174
+ error: "Too many attempts",
175
+ status: 400
176
+ };
177
+ }
178
+ const valid = verifyOtpCodeHash(code, r.codeHash, purpose, identifier, pepper);
179
+ if (!valid) {
180
+ await repo.update(row.id, {
181
+ attempts: attempts + 1
182
+ });
183
+ return {
184
+ ok: false,
185
+ error: "Invalid or expired code",
186
+ status: 400
187
+ };
188
+ }
189
+ await repo.update(row.id, {
190
+ consumedAt: /* @__PURE__ */ new Date(),
191
+ attempts: attempts + 1
192
+ });
193
+ return {
194
+ ok: true
195
+ };
196
+ }
197
+ __name(verifyAndConsumeOtpChallenge, "verifyAndConsumeOtpChallenge");
198
+
199
+ export { countRecentOtpSends, createOtpChallenge, generateNumericOtp, hashOtpCode, normalizePhoneE164, queueSms, registerSmsQueueProcessor, verifyAndConsumeOtpChallenge, verifyOtpCodeHash };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk77I3KS7V_cjs = require('./chunk-77I3KS7V.cjs');
3
+ var chunkUEE4PTTB_cjs = require('./chunk-UEE4PTTB.cjs');
4
4
  var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
5
5
 
6
6
  // src/lib/emit-order-notification-trigger.ts
@@ -18,7 +18,7 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
18
18
  });
19
19
  return;
20
20
  }
21
- const listenerCount = chunk77I3KS7V_cjs.notificationTriggerEmitter.listenerCount("__any__");
21
+ const listenerCount = chunkUEE4PTTB_cjs.notificationTriggerEmitter.listenerCount("__any__");
22
22
  if (listenerCount === 0) {
23
23
  console.warn("[notification-triggers] no WhatsApp dispatcher listener \u2014 ensure createCmsApiHandler passes getCms (initWhatsappTriggerDispatcher)");
24
24
  }
@@ -79,7 +79,7 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
79
79
  }
80
80
  }
81
81
  }
82
- chunk77I3KS7V_cjs.notificationTriggerEmitter.emitTrigger(triggerKey, {
82
+ const triggerPayload = {
83
83
  orderId,
84
84
  orderNumber: String(fo.orderNumber ?? ""),
85
85
  customerName: fo.contact?.name ?? "",
@@ -89,7 +89,21 @@ async function emitOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
89
89
  vendorId: fo.vendorId ?? null,
90
90
  extraVariables: extra?.extraVariables,
91
91
  refundAmount: resolvedRefundAmount
92
- });
92
+ };
93
+ if (listenerCount === 0) {
94
+ try {
95
+ const { dispatchOrderNotificationDirectly } = await import('./order-notification-dispatcher-5TUFCDU7.cjs');
96
+ await dispatchOrderNotificationDirectly(triggerKey, triggerPayload, deps.dataSource, deps.entityMap);
97
+ } catch (err) {
98
+ console.error("[notification-triggers] direct dispatch failed", {
99
+ triggerKey,
100
+ orderId,
101
+ err
102
+ });
103
+ }
104
+ } else {
105
+ chunkUEE4PTTB_cjs.notificationTriggerEmitter.emitTrigger(triggerKey, triggerPayload);
106
+ }
93
107
  }
94
108
  chunkUSNT2KNT_cjs.__name(emitOrderNotificationTrigger, "emitOrderNotificationTrigger");
95
109
  function fireOrderNotificationTrigger(triggerKey, orderId, deps, extra) {
@@ -1,4 +1,4 @@
1
- import { isOrderEligibleForInvoiceEmail, resolveOrderInvoicePdfBytes } from './chunk-2KUCQVAQ.js';
1
+ import { isOrderEligibleForInvoiceEmail, resolveOrderInvoicePdfBytes } from './chunk-MWEK7N3F.js';
2
2
  import { __name } from './chunk-SHUYVCID.js';
3
3
 
4
4
  // src/plugins/email/email-queue.ts
@@ -128,7 +128,41 @@ async function queueEmail(cms, payload) {
128
128
  await queue.add(EMAIL_QUEUE_NAME, payload);
129
129
  return;
130
130
  }
131
- const email = cms.getPlugin("email");
131
+ let email = cms && typeof cms.getPlugin === "function" ? cms.getPlugin("email") : void 0;
132
+ if (!email) {
133
+ try {
134
+ const { EmailService } = await import('./email-service-DPKVQOKP.js');
135
+ const env = typeof process !== "undefined" && process.env ? process.env : {};
136
+ const type = String(env.SMTP_TYPE || "SMTP").toUpperCase();
137
+ const port = env.SMTP_PORT ? parseInt(env.SMTP_PORT, 10) : void 0;
138
+ const fallbackService = new EmailService({
139
+ type: type === "AWS" || type === "GMAIL" || type === "SENDGRID" ? type : "SMTP",
140
+ from: env.SMTP_FROM || "no-reply@example.com",
141
+ to: env.SMTP_TO || "info@example.com",
142
+ user: env.SMTP_USER,
143
+ password: env.SMTP_PASSWORD || env.SMTP_PASS,
144
+ host: env.SMTP_HOST,
145
+ port,
146
+ secure: env.SMTP_SECURE === "true",
147
+ region: env.AWS_SES_REGION || env.AWS_REGION,
148
+ accessKeyId: env.AWS_ACCESS_KEY_ID,
149
+ secretAccessKey: env.AWS_SECRET_ACCESS_KEY
150
+ });
151
+ if (payload.subject != null && payload.html != null) {
152
+ await fallbackService.send({
153
+ to: payload.to,
154
+ subject: payload.subject,
155
+ html: payload.html,
156
+ text: payload.text,
157
+ attachments: payload.attachments
158
+ });
159
+ return;
160
+ }
161
+ } catch (e) {
162
+ console.error("[email-queue] fallback email send error", e);
163
+ return;
164
+ }
165
+ }
132
166
  if (!email) return;
133
167
  const attachmentsResult = await resolveInvoiceAttachmentForJob(cms, payload, registeredInvoiceOptions);
134
168
  if (payload.templateName && payload.ctx) {
@@ -4,6 +4,9 @@ var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
4
4
  var events = require('events');
5
5
 
6
6
  var KNOWN_NOTIFICATION_TRIGGERS = {
7
+ ORDER_PENDING: "order_pending",
8
+ ORDER_PROCESSING: "order_processing",
9
+ ORDER_COMPLETED: "order_completed",
7
10
  ORDER_PLACED: "order_placed",
8
11
  ORDER_CANCELLED: "order_cancelled",
9
12
  PAYMENT_SUCCESS: "payment_success",
@@ -0,0 +1,209 @@
1
+ 'use strict';
2
+
3
+ var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
4
+ var crypto = require('crypto');
5
+ var typeorm = require('typeorm');
6
+
7
+ // src/plugins/sms/sms-queue.ts
8
+ var SMS_QUEUE_NAME = "sms";
9
+ function registerSmsQueueProcessor(cms) {
10
+ const queue = cms.getPlugin("queue");
11
+ const sms = cms.getPlugin("sms");
12
+ if (!queue || !sms || typeof sms.send !== "function") return;
13
+ queue.registerProcessor(SMS_QUEUE_NAME, async (data) => {
14
+ const payload = data;
15
+ if (!payload.to) return;
16
+ if (payload.templateKey?.trim()) {
17
+ await sms.send({
18
+ to: payload.to,
19
+ templateKey: payload.templateKey.trim(),
20
+ variables: payload.variables,
21
+ otpCode: payload.otpCode
22
+ });
23
+ return;
24
+ }
25
+ if (!payload.body?.trim()) return;
26
+ await sms.send({
27
+ to: payload.to,
28
+ body: payload.body,
29
+ otpCode: payload.otpCode,
30
+ variables: payload.variables
31
+ });
32
+ });
33
+ }
34
+ chunkUSNT2KNT_cjs.__name(registerSmsQueueProcessor, "registerSmsQueueProcessor");
35
+ async function queueSms(cms, payload) {
36
+ const queue = cms.getPlugin("queue");
37
+ const sms = cms.getPlugin("sms");
38
+ if (queue) {
39
+ await queue.add(SMS_QUEUE_NAME, payload);
40
+ return;
41
+ }
42
+ if (sms && typeof sms.send === "function") {
43
+ if (payload.templateKey?.trim()) {
44
+ await sms.send({
45
+ to: payload.to,
46
+ templateKey: payload.templateKey.trim(),
47
+ variables: payload.variables,
48
+ otpCode: payload.otpCode
49
+ });
50
+ return;
51
+ }
52
+ if (payload.body?.trim()) {
53
+ await sms.send({
54
+ to: payload.to,
55
+ body: payload.body,
56
+ otpCode: payload.otpCode,
57
+ variables: payload.variables
58
+ });
59
+ }
60
+ }
61
+ }
62
+ chunkUSNT2KNT_cjs.__name(queueSms, "queueSms");
63
+ var OTP_TTL_MS = 10 * 60 * 1e3;
64
+ var MAX_SENDS_PER_HOUR = 5;
65
+ var MAX_VERIFY_ATTEMPTS = 8;
66
+ function getPepper(explicit) {
67
+ return (explicit || process.env.OTP_PEPPER || process.env.NEXTAUTH_SECRET || "dev-otp-pepper").trim();
68
+ }
69
+ chunkUSNT2KNT_cjs.__name(getPepper, "getPepper");
70
+ function hashOtpCode(code, purpose, identifier, pepper) {
71
+ return crypto.createHmac("sha256", getPepper(pepper)).update(`${purpose}|${identifier}|${code}`).digest("hex");
72
+ }
73
+ chunkUSNT2KNT_cjs.__name(hashOtpCode, "hashOtpCode");
74
+ function verifyOtpCodeHash(code, storedHash, purpose, identifier, pepper) {
75
+ const h = hashOtpCode(code, purpose, identifier, pepper);
76
+ try {
77
+ return crypto.timingSafeEqual(Buffer.from(h, "utf8"), Buffer.from(storedHash, "utf8"));
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+ chunkUSNT2KNT_cjs.__name(verifyOtpCodeHash, "verifyOtpCodeHash");
83
+ function generateNumericOtp(length = 6) {
84
+ const max = 10 ** length;
85
+ return crypto.randomInt(0, max).toString().padStart(length, "0");
86
+ }
87
+ chunkUSNT2KNT_cjs.__name(generateNumericOtp, "generateNumericOtp");
88
+ function normalizePhoneE164(raw, defaultCountryCode) {
89
+ const t = raw.trim();
90
+ const digitsOnly = t.replace(/\D/g, "");
91
+ if (digitsOnly.length < 10) return null;
92
+ if (t.startsWith("+")) return `+${digitsOnly}`;
93
+ const cc = (defaultCountryCode || process.env.DEFAULT_PHONE_COUNTRY_CODE || "91").replace(/\D/g, "");
94
+ if (digitsOnly.length > 10) return `+${digitsOnly}`;
95
+ return `+${cc}${digitsOnly}`;
96
+ }
97
+ chunkUSNT2KNT_cjs.__name(normalizePhoneE164, "normalizePhoneE164");
98
+ async function countRecentOtpSends(dataSource, entityMap, purpose, identifier, since) {
99
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
100
+ return repo.count({
101
+ where: {
102
+ purpose,
103
+ identifier,
104
+ createdAt: typeorm.MoreThan(since)
105
+ }
106
+ });
107
+ }
108
+ chunkUSNT2KNT_cjs.__name(countRecentOtpSends, "countRecentOtpSends");
109
+ async function createOtpChallenge(dataSource, entityMap, input) {
110
+ const { purpose, channel, identifier, code, pepper } = input;
111
+ const since = new Date(Date.now() - 60 * 60 * 1e3);
112
+ const recent = await countRecentOtpSends(dataSource, entityMap, purpose, identifier, since);
113
+ if (recent >= MAX_SENDS_PER_HOUR) {
114
+ return {
115
+ ok: false,
116
+ error: "Too many codes sent. Try again later.",
117
+ status: 429
118
+ };
119
+ }
120
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
121
+ await repo.delete({
122
+ purpose,
123
+ identifier,
124
+ consumedAt: typeorm.IsNull()
125
+ });
126
+ const expiresAt = new Date(Date.now() + OTP_TTL_MS);
127
+ const codeHash = hashOtpCode(code, purpose, identifier, pepper);
128
+ await repo.save(repo.create({
129
+ purpose,
130
+ channel,
131
+ identifier,
132
+ codeHash,
133
+ expiresAt,
134
+ attempts: 0,
135
+ consumedAt: null
136
+ }));
137
+ return {
138
+ ok: true
139
+ };
140
+ }
141
+ chunkUSNT2KNT_cjs.__name(createOtpChallenge, "createOtpChallenge");
142
+ async function verifyAndConsumeOtpChallenge(dataSource, entityMap, input) {
143
+ const { purpose, identifier, code, pepper } = input;
144
+ const repo = dataSource.getRepository(entityMap.otp_challenges);
145
+ const row = await repo.findOne({
146
+ where: {
147
+ purpose,
148
+ identifier,
149
+ consumedAt: typeorm.IsNull()
150
+ },
151
+ order: {
152
+ id: "DESC"
153
+ }
154
+ });
155
+ if (!row) {
156
+ return {
157
+ ok: false,
158
+ error: "Invalid or expired code",
159
+ status: 400
160
+ };
161
+ }
162
+ const r = row;
163
+ if (new Date(r.expiresAt) < /* @__PURE__ */ new Date()) {
164
+ await repo.delete(row.id);
165
+ return {
166
+ ok: false,
167
+ error: "Invalid or expired code",
168
+ status: 400
169
+ };
170
+ }
171
+ const attempts = r.attempts || 0;
172
+ if (attempts >= MAX_VERIFY_ATTEMPTS) {
173
+ await repo.delete(row.id);
174
+ return {
175
+ ok: false,
176
+ error: "Too many attempts",
177
+ status: 400
178
+ };
179
+ }
180
+ const valid = verifyOtpCodeHash(code, r.codeHash, purpose, identifier, pepper);
181
+ if (!valid) {
182
+ await repo.update(row.id, {
183
+ attempts: attempts + 1
184
+ });
185
+ return {
186
+ ok: false,
187
+ error: "Invalid or expired code",
188
+ status: 400
189
+ };
190
+ }
191
+ await repo.update(row.id, {
192
+ consumedAt: /* @__PURE__ */ new Date(),
193
+ attempts: attempts + 1
194
+ });
195
+ return {
196
+ ok: true
197
+ };
198
+ }
199
+ chunkUSNT2KNT_cjs.__name(verifyAndConsumeOtpChallenge, "verifyAndConsumeOtpChallenge");
200
+
201
+ exports.countRecentOtpSends = countRecentOtpSends;
202
+ exports.createOtpChallenge = createOtpChallenge;
203
+ exports.generateNumericOtp = generateNumericOtp;
204
+ exports.hashOtpCode = hashOtpCode;
205
+ exports.normalizePhoneE164 = normalizePhoneE164;
206
+ exports.queueSms = queueSms;
207
+ exports.registerSmsQueueProcessor = registerSmsQueueProcessor;
208
+ exports.verifyAndConsumeOtpChallenge = verifyAndConsumeOtpChallenge;
209
+ exports.verifyOtpCodeHash = verifyOtpCodeHash;