@infuro/cms-core 1.0.36 → 1.0.39

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 (29) hide show
  1. package/dist/admin.cjs +459 -496
  2. package/dist/admin.js +459 -496
  3. package/dist/api.cjs +36 -36
  4. package/dist/api.js +4 -4
  5. package/dist/auth.cjs +51 -51
  6. package/dist/auth.js +3 -3
  7. package/dist/{chunk-COBORIJH.cjs → chunk-22FFHLTO.cjs} +39 -56
  8. package/dist/{chunk-X6H5VBQ2.cjs → chunk-E6WVP7BK.cjs} +6 -6
  9. package/dist/{chunk-2AEVFOQP.cjs → chunk-ERJK5QXN.cjs} +418 -139
  10. package/dist/{chunk-VMY2S32H.js → chunk-NNQBWDCI.js} +39 -56
  11. package/dist/{chunk-WO2DW4AU.cjs → chunk-OIGCAGH7.cjs} +7 -7
  12. package/dist/{chunk-UF3BYUXY.js → chunk-P7QCLE5W.js} +4 -3
  13. package/dist/{chunk-FG6I64HP.js → chunk-SBRBR3VO.js} +1 -1
  14. package/dist/{chunk-JS2W7XZ4.js → chunk-SFDZMGHD.js} +351 -72
  15. package/dist/{chunk-LI2IXVAY.js → chunk-UXMDSNIG.js} +1 -1
  16. package/dist/{chunk-KPKFNLQQ.cjs → chunk-WMXPKKXU.cjs} +4 -3
  17. package/dist/index.cjs +260 -260
  18. package/dist/index.d.cts +12 -5
  19. package/dist/index.d.ts +12 -5
  20. package/dist/index.js +8 -8
  21. package/dist/migrations/1775500000000-RssFeedsAndArticles.ts +0 -1
  22. package/dist/migrations/1775700000000-JobSchedules.ts +0 -1
  23. package/dist/migrations/1781260000000-RenameWhatsappTriggerBindingsToOrderNotificationBindings.ts +92 -0
  24. package/dist/migrations/1781270000000-ComboVendorId.ts +58 -0
  25. package/dist/{whatsapp-trigger-dispatcher-ONHXI7UY.cjs → order-notification-dispatcher-RU7BTGGX.cjs} +3 -4
  26. package/dist/{whatsapp-trigger-dispatcher-PWFI4FKP.js → order-notification-dispatcher-XWIJYDGA.js} +1 -2
  27. package/dist/{rbac-debug-db-HWP65A4O.cjs → rbac-debug-db-KHG4FJC3.cjs} +2 -2
  28. package/dist/{rbac-debug-db-QJH3AD34.js → rbac-debug-db-QWHOENBR.js} +1 -1
  29. package/package.json +147 -147
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
- var chunkCOBORIJH_cjs = require('./chunk-COBORIJH.cjs');
3
+ var chunk22FFHLTO_cjs = require('./chunk-22FFHLTO.cjs');
4
4
  var chunk7NMT3GBR_cjs = require('./chunk-7NMT3GBR.cjs');
5
5
  var chunkPNOKNSG2_cjs = require('./chunk-PNOKNSG2.cjs');
6
6
  var chunkXW5ATPRW_cjs = require('./chunk-XW5ATPRW.cjs');
7
7
  var chunk3DZRIZOD_cjs = require('./chunk-3DZRIZOD.cjs');
8
8
  var chunkSPQFNIYJ_cjs = require('./chunk-SPQFNIYJ.cjs');
9
9
  var chunkXQ3QUHWR_cjs = require('./chunk-XQ3QUHWR.cjs');
10
- var chunkWO2DW4AU_cjs = require('./chunk-WO2DW4AU.cjs');
11
- var chunkKPKFNLQQ_cjs = require('./chunk-KPKFNLQQ.cjs');
10
+ var chunkOIGCAGH7_cjs = require('./chunk-OIGCAGH7.cjs');
11
+ var chunkWMXPKKXU_cjs = require('./chunk-WMXPKKXU.cjs');
12
12
  var chunkD5FBNKQM_cjs = require('./chunk-D5FBNKQM.cjs');
13
13
  var chunkUPLVMVRX_cjs = require('./chunk-UPLVMVRX.cjs');
14
14
  var chunkUSNT2KNT_cjs = require('./chunk-USNT2KNT.cjs');
@@ -87,7 +87,7 @@ async function loadUserVendorContext(dataSource, userId, preferredVendorId) {
87
87
  `, [
88
88
  primary.vendorRoleId
89
89
  ]);
90
- vendorEntityPerms = chunkKPKFNLQQ_cjs.permissionRowsToRecord(permRows);
90
+ vendorEntityPerms = chunkWMXPKKXU_cjs.permissionRowsToRecord(permRows);
91
91
  } catch (err) {
92
92
  if (!isMissingVendorRoleSchemaError(err)) throw err;
93
93
  }
@@ -120,7 +120,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
120
120
  ]);
121
121
  const resolvedId = Number(byEmailRows[0]?.id);
122
122
  if (!Number.isFinite(resolvedId)) {
123
- chunkKPKFNLQQ_cjs.logRbac("hydrateVendorSessionUser: unable to resolve numeric user id", {
123
+ chunkWMXPKKXU_cjs.logRbac("hydrateVendorSessionUser: unable to resolve numeric user id", {
124
124
  email: user.email,
125
125
  rawSessionId: user.id ?? null
126
126
  });
@@ -140,7 +140,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
140
140
  const groupName = rows[0]?.groupName ?? user.groupName ?? null;
141
141
  const groupId = rows[0]?.groupId ?? user.groupId ?? void 0;
142
142
  const adminAccess = rows[0]?.adminAccess ?? user.adminAccess;
143
- const isRBACAdmin = user.isRBACAdmin ?? chunkKPKFNLQQ_cjs.isSuperAdmin({
143
+ const isRBACAdmin = user.isRBACAdmin ?? chunkWMXPKKXU_cjs.isSuperAdmin({
144
144
  groupId,
145
145
  groupName,
146
146
  isRBACAdmin: user.isRBACAdmin
@@ -153,7 +153,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
153
153
  };
154
154
  if (multiVendorEnabled) {
155
155
  ctx = await loadUserVendorContext(dataSource, id, user.activeVendorId);
156
- flags = chunkKPKFNLQQ_cjs.vendorPortalFlagsFromUser({
156
+ flags = chunkWMXPKKXU_cjs.vendorPortalFlagsFromUser({
157
157
  email: user.email,
158
158
  isRBACAdmin,
159
159
  groupName,
@@ -188,7 +188,7 @@ async function hydrateVendorSessionUser(dataSource, user) {
188
188
  isVendorPortal: flags.isVendorPortal,
189
189
  isVendorOwner: flags.isVendorOwner
190
190
  };
191
- chunkKPKFNLQQ_cjs.logRbac("hydrateVendorSessionUser", {
191
+ chunkWMXPKKXU_cjs.logRbac("hydrateVendorSessionUser", {
192
192
  email: user.email,
193
193
  userId: id,
194
194
  groupName,
@@ -332,7 +332,7 @@ function repoHasVendorIdColumn(repo) {
332
332
  }
333
333
  chunkUSNT2KNT_cjs.__name(repoHasVendorIdColumn, "repoHasVendorIdColumn");
334
334
  function resourceUsesVendorScope(resource) {
335
- return resource === "vendors" || chunkKPKFNLQQ_cjs.VENDOR_SCOPED_STORE_ENTITIES.has(resource);
335
+ return resource === "vendors" || chunkWMXPKKXU_cjs.VENDOR_SCOPED_STORE_ENTITIES.has(resource);
336
336
  }
337
337
  chunkUSNT2KNT_cjs.__name(resourceUsesVendorScope, "resourceUsesVendorScope");
338
338
  function mergeVendorScopeIntoWhere(where, scope, resource) {
@@ -2617,10 +2617,11 @@ async function calculateOrderTotalsFromLines(dataSource, entityMap, lineInputs,
2617
2617
  }
2618
2618
  });
2619
2619
  if (combo) {
2620
- const comboRows = await dataSource.query(`SELECT p."vendorId", ci."productId" as "firstProductId"
2620
+ const comboVendorId = Number(combo.vendorId);
2621
+ const comboRows = await dataSource.query(`SELECT ci."productId" as "firstProductId"
2621
2622
  FROM combo_items ci
2622
2623
  JOIN products p ON p.id = ci."productId"
2623
- WHERE ci."comboId" = $1 AND p.deleted = false AND p."vendorId" IS NOT NULL
2624
+ WHERE ci."comboId" = $1 AND p.deleted = false
2624
2625
  LIMIT 1`, [
2625
2626
  productId
2626
2627
  ]);
@@ -2637,7 +2638,8 @@ async function calculateOrderTotalsFromLines(dataSource, entityMap, lineInputs,
2637
2638
  ...childProduct,
2638
2639
  id: productId,
2639
2640
  price: combo.price,
2640
- name: combo.name
2641
+ name: combo.name,
2642
+ vendorId: Number.isFinite(comboVendorId) && comboVendorId > 0 ? comboVendorId : childProduct.vendorId
2641
2643
  };
2642
2644
  }
2643
2645
  }
@@ -5193,6 +5195,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
5193
5195
  });
5194
5196
  }
5195
5197
  if (resource === "combos") {
5198
+ const scope2 = await resolveScopeById();
5196
5199
  const combo = await repo.findOne({
5197
5200
  where: {
5198
5201
  id: Number(id),
@@ -5203,6 +5206,8 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
5203
5206
  "items.product"
5204
5207
  ]
5205
5208
  });
5209
+ const comboDenied = vendorScopeAccessJson(combo, scope2, resource);
5210
+ if (comboDenied) return comboDenied;
5206
5211
  return combo ? json(combo) : json({
5207
5212
  message: "Not found"
5208
5213
  }, {
@@ -7408,7 +7413,7 @@ function createVendorDashboardHandler(config) {
7408
7413
  if (pe) return pe;
7409
7414
  }
7410
7415
  const user = await getSessionUser();
7411
- if (!user || !chunkKPKFNLQQ_cjs.isVendorPortalUser(user)) {
7416
+ if (!user || !chunkWMXPKKXU_cjs.isVendorPortalUser(user)) {
7412
7417
  return json({
7413
7418
  error: "Forbidden"
7414
7419
  }, {
@@ -9632,7 +9637,7 @@ function createChatHandlers(config) {
9632
9637
  const notifyEmailAgent = await findLlmAgentByScope(dataSource, entityMap, LLM_AGENT_SCOPE_EMAIL_INTENT_CHATBOT, {
9633
9638
  enabledOnly: false
9634
9639
  });
9635
- const emailTool = chunkCOBORIJH_cjs.resolveChatEmailToolSettings(llmSettings, {
9640
+ const emailTool = chunk22FFHLTO_cjs.resolveChatEmailToolSettings(llmSettings, {
9636
9641
  chatbotValidationRules: agentRow?.validationRules ?? null,
9637
9642
  notifyAgent: notifyEmailAgent ? {
9638
9643
  systemInstruction: notifyEmailAgent.systemInstruction,
@@ -9642,7 +9647,7 @@ function createChatHandlers(config) {
9642
9647
  const emailPlugin2 = cms.getPlugin("email");
9643
9648
  const convLeadSent = conv.leadEmailSentAt;
9644
9649
  const chatAgentFn = llm.chatAgent?.bind(llm);
9645
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline check", {
9650
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline check", {
9646
9651
  conversationId,
9647
9652
  enabled: emailTool.enabled,
9648
9653
  intentCount: emailTool.intents.length,
@@ -9656,27 +9661,27 @@ function createChatHandlers(config) {
9656
9661
  mergedPromptIncludesNotify: Boolean(notifyEmailAgent?.systemInstruction?.trim())
9657
9662
  });
9658
9663
  if (!emailTool.enabled) {
9659
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9664
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9660
9665
  conversationId,
9661
9666
  reason: "email_tool_disabled"
9662
9667
  });
9663
9668
  } else if (emailTool.intents.length === 0) {
9664
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9669
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9665
9670
  conversationId,
9666
9671
  reason: "no_intents_configured"
9667
9672
  });
9668
9673
  } else if (!emailPlugin2) {
9669
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9674
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9670
9675
  conversationId,
9671
9676
  reason: "email_plugin_missing"
9672
9677
  });
9673
9678
  } else if (!chatAgentFn) {
9674
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9679
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9675
9680
  conversationId,
9676
9681
  reason: "llm_chat_agent_unavailable"
9677
9682
  });
9678
9683
  } else if (convLeadSent) {
9679
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9684
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9680
9685
  conversationId,
9681
9686
  reason: "lead_email_already_sent",
9682
9687
  leadEmailSentAt: convLeadSent
@@ -9689,7 +9694,7 @@ function createChatHandlers(config) {
9689
9694
  }
9690
9695
  });
9691
9696
  if (!contactRow) {
9692
- console.warn(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9697
+ console.warn(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline skipped", {
9693
9698
  conversationId,
9694
9699
  reason: "contact_not_found",
9695
9700
  contactId
@@ -9697,7 +9702,7 @@ function createChatHandlers(config) {
9697
9702
  } else {
9698
9703
  const c = contactRow;
9699
9704
  try {
9700
- const intent = await chunkCOBORIJH_cjs.detectChatLeadIntent({
9705
+ const intent = await chunk22FFHLTO_cjs.detectChatLeadIntent({
9701
9706
  chatAgent: chatAgentFn
9702
9707
  }, {
9703
9708
  settings: emailTool,
@@ -9711,15 +9716,15 @@ function createChatHandlers(config) {
9711
9716
  model: agentRow?.model?.trim() || notifyEmailAgent?.model?.trim() || void 0
9712
9717
  });
9713
9718
  if (!intent.intent || !intent.emailTo) {
9714
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "no email sent", {
9719
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "no email sent", {
9715
9720
  conversationId,
9716
9721
  reason: intent.intent ? "missing_email_to" : "no_intent_match",
9717
9722
  intentLabel: intent.intentLabel,
9718
9723
  classifierReason: intent.reason
9719
9724
  });
9720
9725
  } else {
9721
- const intentRecipients = chunkCOBORIJH_cjs.parseIntentRecipientEmails(intent.emailTo);
9722
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "intent matched \u2014 sending", {
9726
+ const intentRecipients = chunk22FFHLTO_cjs.parseIntentRecipientEmails(intent.emailTo);
9727
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "intent matched \u2014 sending", {
9723
9728
  conversationId,
9724
9729
  intent: intent.intent,
9725
9730
  emailTo: intent.emailTo,
@@ -9728,8 +9733,8 @@ function createChatHandlers(config) {
9728
9733
  });
9729
9734
  const emailSettings = await loadSettingsGroupMap(dataSource, entityMap, "email");
9730
9735
  const brandingSettings = await loadSettingsGroupMap(dataSource, entityMap, "branding");
9731
- const companyDetails = chunkCOBORIJH_cjs.mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
9732
- const leadResult = await chunkCOBORIJH_cjs.sendChatLeadEmail(cms, emailSettings, brandingSettings, {
9736
+ const companyDetails = chunk22FFHLTO_cjs.mergeEmailLayoutCompanyDetails(brandingSettings, emailSettings);
9737
+ const leadResult = await chunk22FFHLTO_cjs.sendChatLeadEmail(cms, emailSettings, brandingSettings, {
9733
9738
  contactName: String(c.name ?? "").trim() || "Visitor",
9734
9739
  contactEmail: String(c.email ?? "").trim(),
9735
9740
  contactPhone: c.phone ?? null,
@@ -9737,7 +9742,7 @@ function createChatHandlers(config) {
9737
9742
  latestMessage: message,
9738
9743
  intentCode: intent.intent,
9739
9744
  intentReason: intent.intentLabel || intent.reason,
9740
- transcript: chunkCOBORIJH_cjs.buildTranscriptForLeadEmail(history, message),
9745
+ transcript: chunk22FFHLTO_cjs.buildTranscriptForLeadEmail(history, message),
9741
9746
  companyDetails,
9742
9747
  recipients: intentRecipients.length > 0 ? intentRecipients : void 0
9743
9748
  });
@@ -9745,13 +9750,13 @@ function createChatHandlers(config) {
9745
9750
  await convRepo().update(conversationId, {
9746
9751
  leadEmailSentAt: /* @__PURE__ */ new Date()
9747
9752
  });
9748
- console.info(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "lead email recorded", {
9753
+ console.info(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "lead email recorded", {
9749
9754
  conversationId,
9750
9755
  sent: true,
9751
9756
  recipients: leadResult.recipients
9752
9757
  });
9753
9758
  } else {
9754
- console.warn(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "lead email not sent", {
9759
+ console.warn(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "lead email not sent", {
9755
9760
  conversationId,
9756
9761
  sent: false,
9757
9762
  error: leadResult.error ?? "unknown",
@@ -9760,7 +9765,7 @@ function createChatHandlers(config) {
9760
9765
  }
9761
9766
  }
9762
9767
  } catch (intentErr) {
9763
- console.warn(chunkCOBORIJH_cjs.CHAT_EMAIL_LOG, "pipeline error", {
9768
+ console.warn(chunk22FFHLTO_cjs.CHAT_EMAIL_LOG, "pipeline error", {
9764
9769
  conversationId,
9765
9770
  error: intentErr instanceof Error ? intentErr.message : String(intentErr)
9766
9771
  });
@@ -9777,7 +9782,7 @@ function createChatHandlers(config) {
9777
9782
  });
9778
9783
  if (agentRow && llm.chatAgent) {
9779
9784
  const fromAgent = llmAgentToChatAgentOptions(agentRow);
9780
- const systemPrompt = chunkCOBORIJH_cjs.buildChatbotSystemPromptWithEmailTool(fromAgent.systemPrompt, parsedValidation.guardrailsForPrompt, emailTool);
9785
+ const systemPrompt = chunk22FFHLTO_cjs.buildChatbotSystemPromptWithEmailTool(fromAgent.systemPrompt, parsedValidation.guardrailsForPrompt, emailTool);
9781
9786
  const res = await llm.chatAgent({
9782
9787
  ...fromAgent,
9783
9788
  systemPrompt: systemPrompt || void 0,
@@ -9798,7 +9803,7 @@ ${contextParts.join("\n\n")}` : "";
9798
9803
  agentRow.systemInstruction?.trim(),
9799
9804
  ragSystem
9800
9805
  ].filter(Boolean).join("\n\n");
9801
- systemContent = chunkCOBORIJH_cjs.buildChatbotSystemPromptWithEmailTool(mergedBase || defaultSystem, parsedValidation.guardrailsForPrompt, emailTool) || defaultSystem;
9806
+ systemContent = chunk22FFHLTO_cjs.buildChatbotSystemPromptWithEmailTool(mergedBase || defaultSystem, parsedValidation.guardrailsForPrompt, emailTool) || defaultSystem;
9802
9807
  } else {
9803
9808
  systemContent = ragSystem || defaultSystem;
9804
9809
  }
@@ -11209,7 +11214,7 @@ chunkUSNT2KNT_cjs.__name(findActiveRefundPolicyForVendor, "findActiveRefundPolic
11209
11214
  // src/api/admin-roles-handlers.ts
11210
11215
  function createAdminRolesHandlers(config) {
11211
11216
  const { dataSource, entityMap, json, getSessionUser } = config;
11212
- const baseEntities = chunkKPKFNLQQ_cjs.getPermissionableEntityKeys(entityMap);
11217
+ const baseEntities = chunkWMXPKKXU_cjs.getPermissionableEntityKeys(entityMap);
11213
11218
  const allowEntities = /* @__PURE__ */ new Set([
11214
11219
  ...baseEntities,
11215
11220
  "users"
@@ -11224,7 +11229,7 @@ function createAdminRolesHandlers(config) {
11224
11229
  }, {
11225
11230
  status: 401
11226
11231
  });
11227
- if (!chunkWO2DW4AU_cjs.canManageRoles(u) && !chunkKPKFNLQQ_cjs.canManageVendorRoles(u)) {
11232
+ if (!chunkOIGCAGH7_cjs.canManageRoles(u) && !chunkWMXPKKXU_cjs.canManageVendorRoles(u)) {
11228
11233
  return json({
11229
11234
  error: "Forbidden"
11230
11235
  }, {
@@ -11235,11 +11240,11 @@ function createAdminRolesHandlers(config) {
11235
11240
  }
11236
11241
  chunkUSNT2KNT_cjs.__name(gate, "gate");
11237
11242
  function isVendorRolesOnly(u) {
11238
- return chunkKPKFNLQQ_cjs.canManageVendorRoles(u) && !chunkWO2DW4AU_cjs.canManageRoles(u);
11243
+ return chunkWMXPKKXU_cjs.canManageVendorRoles(u) && !chunkOIGCAGH7_cjs.canManageRoles(u);
11239
11244
  }
11240
11245
  chunkUSNT2KNT_cjs.__name(isVendorRolesOnly, "isVendorRolesOnly");
11241
11246
  const vendorRoleEntities = [
11242
- ...chunkKPKFNLQQ_cjs.VENDOR_STORE_RBAC_ENTITIES,
11247
+ ...chunkWMXPKKXU_cjs.VENDOR_STORE_RBAC_ENTITIES,
11243
11248
  "dashboard",
11244
11249
  "settings"
11245
11250
  ].sort();
@@ -11396,7 +11401,7 @@ function createAdminRolesHandlers(config) {
11396
11401
  }, {
11397
11402
  status: 404
11398
11403
  });
11399
- if (chunkKPKFNLQQ_cjs.isSuperAdminGroupName(g.name) && !chunkKPKFNLQQ_cjs.isSuperAdminGroupName(name)) {
11404
+ if (chunkWMXPKKXU_cjs.isSuperAdminGroupName(g.name) && !chunkWMXPKKXU_cjs.isSuperAdminGroupName(name)) {
11400
11405
  return json({
11401
11406
  error: "Cannot rename the administrator group"
11402
11407
  }, {
@@ -11453,7 +11458,7 @@ function createAdminRolesHandlers(config) {
11453
11458
  }, {
11454
11459
  status: 404
11455
11460
  });
11456
- if (chunkKPKFNLQQ_cjs.isSuperAdminGroupName(g.name)) return json({
11461
+ if (chunkWMXPKKXU_cjs.isSuperAdminGroupName(g.name)) return json({
11457
11462
  error: "Cannot delete the administrator group"
11458
11463
  }, {
11459
11464
  status: 400
@@ -11592,8 +11597,8 @@ async function sendVendorOnboardEmails(input, deps) {
11592
11597
  getSettingsGroup(deps, "branding"),
11593
11598
  getSettingsGroup(deps, "email")
11594
11599
  ]);
11595
- const companyDetails = chunkCOBORIJH_cjs.mergeEmailLayoutCompanyDetails(branding, emailSettings);
11596
- const notifyEmails = chunkCOBORIJH_cjs.parseEmailRecipientsFromConfig(emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail);
11600
+ const companyDetails = chunk22FFHLTO_cjs.mergeEmailLayoutCompanyDetails(branding, emailSettings);
11601
+ const notifyEmails = chunk22FFHLTO_cjs.parseEmailRecipientsFromConfig(emailSettings.salesTeamEmails ?? emailSettings.salesTeamEmail);
11597
11602
  const sendToOwner = input.sendToOwner !== false;
11598
11603
  const ownerEmail = input.ownerEmail?.trim() || "";
11599
11604
  const cms = await deps.getCms();
@@ -11621,7 +11626,7 @@ chunkUSNT2KNT_cjs.__name(sendVendorOnboardEmails, "sendVendorOnboardEmails");
11621
11626
 
11622
11627
  // src/lib/seed-vendor-roles.ts
11623
11628
  async function insertRolePermissions(exec, vendorRoleId, permissions) {
11624
- for (const entity of chunkKPKFNLQQ_cjs.VENDOR_RBAC_ENTITIES) {
11629
+ for (const entity of chunkWMXPKKXU_cjs.VENDOR_RBAC_ENTITIES) {
11625
11630
  const flags = permissions[entity];
11626
11631
  if (!flags) continue;
11627
11632
  await exec.query(`
@@ -11652,7 +11657,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
11652
11657
  for (const r of existing) {
11653
11658
  roleIdsByName2[r.name] = Number(r.id);
11654
11659
  if (r.isOwnerRole) ownerRoleId2 = Number(r.id);
11655
- if (r.name === chunkKPKFNLQQ_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId2 = Number(r.id);
11660
+ if (r.name === chunkWMXPKKXU_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId2 = Number(r.id);
11656
11661
  }
11657
11662
  return {
11658
11663
  roleIdsByName: roleIdsByName2,
@@ -11663,7 +11668,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
11663
11668
  const roleIdsByName = {};
11664
11669
  let ownerRoleId = 0;
11665
11670
  let viewerRoleId = 0;
11666
- for (const def of chunkKPKFNLQQ_cjs.DEFAULT_VENDOR_ROLE_DEFS) {
11671
+ for (const def of chunkWMXPKKXU_cjs.DEFAULT_VENDOR_ROLE_DEFS) {
11667
11672
  const inserted = await exec.query(`
11668
11673
  INSERT INTO "vendor_roles"
11669
11674
  ("vendorId", "name", "description", "isSystem", "isOwnerRole")
@@ -11680,7 +11685,7 @@ async function seedVendorDefaultRoles(em, vendorId) {
11680
11685
  if (!roleId) continue;
11681
11686
  roleIdsByName[def.name] = roleId;
11682
11687
  if (def.isOwnerRole) ownerRoleId = roleId;
11683
- if (def.name === chunkKPKFNLQQ_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId = roleId;
11688
+ if (def.name === chunkWMXPKKXU_cjs.VENDOR_VIEWER_ROLE_NAME) viewerRoleId = roleId;
11684
11689
  await insertRolePermissions(exec, roleId, def.permissions);
11685
11690
  }
11686
11691
  return {
@@ -11701,7 +11706,7 @@ async function backfillVendorUserRoleIds(em, vendorId, seeded) {
11701
11706
  vendorId
11702
11707
  ]);
11703
11708
  }
11704
- const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[chunkKPKFNLQQ_cjs.VENDOR_VIEWER_ROLE_NAME];
11709
+ const viewerId = seeded.viewerRoleId || seeded.roleIdsByName[chunkWMXPKKXU_cjs.VENDOR_VIEWER_ROLE_NAME];
11705
11710
  if (viewerId) {
11706
11711
  await em.query(`
11707
11712
  UPDATE "vendor_users"
@@ -11727,7 +11732,7 @@ async function getDefaultStaffRoleIdForVendor(em, vendorId) {
11727
11732
  LIMIT 1
11728
11733
  `, [
11729
11734
  vendorId,
11730
- chunkKPKFNLQQ_cjs.VENDOR_VIEWER_ROLE_NAME
11735
+ chunkWMXPKKXU_cjs.VENDOR_VIEWER_ROLE_NAME
11731
11736
  ]);
11732
11737
  const id = rows[0]?.id;
11733
11738
  return id != null ? Number(id) : null;
@@ -11816,6 +11821,84 @@ function slugify(input) {
11816
11821
  return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
11817
11822
  }
11818
11823
  chunkUSNT2KNT_cjs.__name(slugify, "slugify");
11824
+ function vendorOnboardErrorResponse(json, err) {
11825
+ const msg = err instanceof Error ? err.message : String(err);
11826
+ console.error("[vendor-onboard]", err);
11827
+ if (msg === "VENDOR_SLUG_EXISTS") {
11828
+ return json({
11829
+ error: "Vendor slug already exists"
11830
+ }, {
11831
+ status: 400
11832
+ });
11833
+ }
11834
+ if (msg === "USER_EMAIL_EXISTS") {
11835
+ return json({
11836
+ error: "User with this email already exists"
11837
+ }, {
11838
+ status: 400
11839
+ });
11840
+ }
11841
+ if (msg === "VENDOR_OWNER_GROUP_MISSING") {
11842
+ return json({
11843
+ error: "Vendor Owner group not found. Run migrations (VendorOwnerRbacSeed)."
11844
+ }, {
11845
+ status: 500
11846
+ });
11847
+ }
11848
+ if (msg === "VENDOR_ROLES_SEED_FAILED") {
11849
+ return json({
11850
+ error: "Failed to seed store roles for vendor. Run migrations."
11851
+ }, {
11852
+ status: 500
11853
+ });
11854
+ }
11855
+ if (/vendor_roles|vendor_role_permissions/i.test(msg)) {
11856
+ return json({
11857
+ error: "Vendor roles tables missing. Run migrations."
11858
+ }, {
11859
+ status: 500
11860
+ });
11861
+ }
11862
+ if (/relation .* does not exist|column .* does not exist/i.test(msg)) {
11863
+ return json({
11864
+ error: "Database schema is outdated on this environment. Run migrations.",
11865
+ detail: msg
11866
+ }, {
11867
+ status: 500
11868
+ });
11869
+ }
11870
+ if (/duplicate key|unique constraint/i.test(msg)) {
11871
+ if (/email/i.test(msg)) {
11872
+ return json({
11873
+ error: "A user or record with this email already exists",
11874
+ detail: msg
11875
+ }, {
11876
+ status: 409
11877
+ });
11878
+ }
11879
+ if (/slug/i.test(msg)) {
11880
+ return json({
11881
+ error: "Vendor slug already exists",
11882
+ detail: msg
11883
+ }, {
11884
+ status: 409
11885
+ });
11886
+ }
11887
+ return json({
11888
+ error: "Duplicate value conflicts with an existing record",
11889
+ detail: msg
11890
+ }, {
11891
+ status: 409
11892
+ });
11893
+ }
11894
+ return json({
11895
+ error: "Server error",
11896
+ detail: msg
11897
+ }, {
11898
+ status: 500
11899
+ });
11900
+ }
11901
+ chunkUSNT2KNT_cjs.__name(vendorOnboardErrorResponse, "vendorOnboardErrorResponse");
11819
11902
  function createVendorOnboardHandlers(config) {
11820
11903
  const { dataSource, entityMap, json, getSessionUser, baseUrl, getCms, hashPassword, minPasswordLength = 6 } = config;
11821
11904
  async function gateAdmin() {
@@ -11825,7 +11908,7 @@ function createVendorOnboardHandlers(config) {
11825
11908
  }, {
11826
11909
  status: 401
11827
11910
  });
11828
- if (!chunkKPKFNLQQ_cjs.isPlatformAdministrator(u)) return json({
11911
+ if (!chunkWMXPKKXU_cjs.isPlatformAdministrator(u)) return json({
11829
11912
  error: "Forbidden",
11830
11913
  reason: "admin_only"
11831
11914
  }, {
@@ -11835,7 +11918,7 @@ function createVendorOnboardHandlers(config) {
11835
11918
  }
11836
11919
  chunkUSNT2KNT_cjs.__name(gateAdmin, "gateAdmin");
11837
11920
  async function resolveActiveVendorId(u) {
11838
- const scope = chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u);
11921
+ const scope = chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u);
11839
11922
  if (scope.type === "vendor") return scope.vendorId;
11840
11923
  if (scope.type === "all") {
11841
11924
  const id = u.activeVendorId ?? u.vendorIds?.[0];
@@ -11851,7 +11934,7 @@ function createVendorOnboardHandlers(config) {
11851
11934
  }, {
11852
11935
  status: 401
11853
11936
  });
11854
- if (!chunkKPKFNLQQ_cjs.canManageVendorTeam(u)) return json({
11937
+ if (!chunkWMXPKKXU_cjs.canManageVendorTeam(u)) return json({
11855
11938
  error: "Forbidden"
11856
11939
  }, {
11857
11940
  status: 403
@@ -11984,12 +12067,28 @@ function createVendorOnboardHandlers(config) {
11984
12067
  }
11985
12068
  });
11986
12069
  if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
11987
- const ownerGroup = await groupRepo.findOne({
12070
+ let ownerGroup = await groupRepo.findOne({
11988
12071
  where: {
11989
- name: chunkKPKFNLQQ_cjs.VENDOR_OWNER_GROUP_NAME,
12072
+ name: chunkWMXPKKXU_cjs.VENDOR_OWNER_GROUP_NAME,
11990
12073
  deleted: false
11991
12074
  }
11992
12075
  });
12076
+ if (!ownerGroup) {
12077
+ try {
12078
+ await groupRepo.save(groupRepo.create({
12079
+ name: chunkWMXPKKXU_cjs.VENDOR_OWNER_GROUP_NAME,
12080
+ deleted: false
12081
+ }));
12082
+ ownerGroup = await groupRepo.findOne({
12083
+ where: {
12084
+ name: chunkWMXPKKXU_cjs.VENDOR_OWNER_GROUP_NAME,
12085
+ deleted: false
12086
+ }
12087
+ });
12088
+ } catch (seedErr) {
12089
+ console.error("[vendor-onboard] failed to seed Vendor Owner group", seedErr);
12090
+ }
12091
+ }
11993
12092
  if (!ownerGroup) throw new Error("VENDOR_OWNER_GROUP_MISSING");
11994
12093
  const existingUser = await userRepo.findOne({
11995
12094
  where: {
@@ -12078,14 +12177,18 @@ function createVendorOnboardHandlers(config) {
12078
12177
  });
12079
12178
  }
12080
12179
  if (entityMap.customer) {
12081
- await ensureCustomerForUser(em, entityMap.customer, {
12082
- id: newUser.id,
12083
- name: userName,
12084
- email: userEmail,
12085
- phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12086
- }, {
12087
- phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12088
- });
12180
+ try {
12181
+ await ensureCustomerForUser(em, entityMap.customer, {
12182
+ id: newUser.id,
12183
+ name: userName,
12184
+ email: userEmail,
12185
+ phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12186
+ }, {
12187
+ phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12188
+ });
12189
+ } catch (customerErr) {
12190
+ console.error("[vendor-onboard] ensureCustomerForUser skipped", customerErr);
12191
+ }
12089
12192
  }
12090
12193
  return {
12091
12194
  vendor,
@@ -12135,46 +12238,7 @@ function createVendorOnboardHandlers(config) {
12135
12238
  status: 201
12136
12239
  });
12137
12240
  } catch (e) {
12138
- const msg = e instanceof Error ? e.message : String(e);
12139
- if (process.env.NODE_ENV === "development") {
12140
- console.error("[vendor-onboard]", e);
12141
- }
12142
- if (msg === "VENDOR_SLUG_EXISTS") return json({
12143
- error: "Vendor slug already exists"
12144
- }, {
12145
- status: 400
12146
- });
12147
- if (msg === "USER_EMAIL_EXISTS") return json({
12148
- error: "User with this email already exists"
12149
- }, {
12150
- status: 400
12151
- });
12152
- if (msg === "VENDOR_OWNER_GROUP_MISSING") {
12153
- return json({
12154
- error: "Vendor Owner group not found. Run migrations."
12155
- }, {
12156
- status: 500
12157
- });
12158
- }
12159
- if (msg === "VENDOR_ROLES_SEED_FAILED") {
12160
- return json({
12161
- error: "Failed to seed store roles for vendor. Run migrations."
12162
- }, {
12163
- status: 500
12164
- });
12165
- }
12166
- if (/vendor_roles|vendor_role_permissions/i.test(msg)) {
12167
- return json({
12168
- error: "Vendor roles tables missing. Run migrations."
12169
- }, {
12170
- status: 500
12171
- });
12172
- }
12173
- return json({
12174
- error: "Server error"
12175
- }, {
12176
- status: 500
12177
- });
12241
+ return vendorOnboardErrorResponse(json, e);
12178
12242
  }
12179
12243
  },
12180
12244
  /** POST /api/admin/vendor/switch — set active vendor in session (JWT update via client) */
@@ -12368,7 +12432,7 @@ function createVendorOnboardHandlers(config) {
12368
12432
  if (!groupId) {
12369
12433
  const g = await groupRepo.findOne({
12370
12434
  where: {
12371
- name: chunkKPKFNLQQ_cjs.VENDOR_OWNER_GROUP_NAME,
12435
+ name: chunkWMXPKKXU_cjs.VENDOR_OWNER_GROUP_NAME,
12372
12436
  deleted: false
12373
12437
  }
12374
12438
  });
@@ -12678,10 +12742,10 @@ chunkUSNT2KNT_cjs.__name(createVendorOnboardHandlers, "createVendorOnboardHandle
12678
12742
  function createVendorRolesHandlers(config) {
12679
12743
  const { dataSource, entityMap, json, getSessionUser } = config;
12680
12744
  const vendorRoleEntities = [
12681
- ...chunkKPKFNLQQ_cjs.VENDOR_RBAC_ENTITIES
12745
+ ...chunkWMXPKKXU_cjs.VENDOR_RBAC_ENTITIES
12682
12746
  ].sort();
12683
12747
  async function resolveActiveVendorId(u) {
12684
- const scope = chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u);
12748
+ const scope = chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u);
12685
12749
  if (scope.type === "vendor") return scope.vendorId;
12686
12750
  if (scope.type === "all") {
12687
12751
  const id = u.activeVendorId ?? u.vendorIds?.[0];
@@ -12697,7 +12761,7 @@ function createVendorRolesHandlers(config) {
12697
12761
  }, {
12698
12762
  status: 401
12699
12763
  });
12700
- if (!chunkKPKFNLQQ_cjs.canManageVendorRoles(u)) return json({
12764
+ if (!chunkWMXPKKXU_cjs.canManageVendorRoles(u)) return json({
12701
12765
  error: "Forbidden"
12702
12766
  }, {
12703
12767
  status: 403
@@ -20855,6 +20919,8 @@ exports.Combo = class Combo {
20855
20919
  chunkUSNT2KNT_cjs.__name(this, "Combo");
20856
20920
  }
20857
20921
  id;
20922
+ vendorId;
20923
+ vendor;
20858
20924
  name;
20859
20925
  desc;
20860
20926
  eventId;
@@ -20880,6 +20946,19 @@ _ts_decorate63([
20880
20946
  typeorm.PrimaryGeneratedColumn(),
20881
20947
  _ts_metadata63("design:type", Number)
20882
20948
  ], exports.Combo.prototype, "id", void 0);
20949
+ _ts_decorate63([
20950
+ typeorm.Column("int"),
20951
+ _ts_metadata63("design:type", Number)
20952
+ ], exports.Combo.prototype, "vendorId", void 0);
20953
+ _ts_decorate63([
20954
+ typeorm.ManyToOne(() => exports.Vendor, {
20955
+ onDelete: "RESTRICT"
20956
+ }),
20957
+ typeorm.JoinColumn({
20958
+ name: "vendorId"
20959
+ }),
20960
+ _ts_metadata63("design:type", typeof exports.Vendor === "undefined" ? Object : exports.Vendor)
20961
+ ], exports.Combo.prototype, "vendor", void 0);
20883
20962
  _ts_decorate63([
20884
20963
  typeorm.Column({
20885
20964
  type: "varchar"
@@ -21224,12 +21303,18 @@ function _ts_metadata66(k, v) {
21224
21303
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
21225
21304
  }
21226
21305
  chunkUSNT2KNT_cjs.__name(_ts_metadata66, "_ts_metadata");
21227
- exports.WhatsappTriggerBinding = class WhatsappTriggerBinding {
21306
+ var NotificationChannel = /* @__PURE__ */ (function(NotificationChannel2) {
21307
+ NotificationChannel2["WHATSAPP"] = "whatsapp";
21308
+ NotificationChannel2["EMAIL"] = "email";
21309
+ return NotificationChannel2;
21310
+ })({});
21311
+ exports.OrderNotificationBinding = class OrderNotificationBinding {
21228
21312
  static {
21229
- chunkUSNT2KNT_cjs.__name(this, "WhatsappTriggerBinding");
21313
+ chunkUSNT2KNT_cjs.__name(this, "OrderNotificationBinding");
21230
21314
  }
21231
21315
  id;
21232
21316
  triggerKey;
21317
+ channel;
21233
21318
  messageTemplateId;
21234
21319
  enabled;
21235
21320
  createdAt;
@@ -21238,39 +21323,52 @@ exports.WhatsappTriggerBinding = class WhatsappTriggerBinding {
21238
21323
  _ts_decorate66([
21239
21324
  typeorm.PrimaryGeneratedColumn(),
21240
21325
  _ts_metadata66("design:type", Number)
21241
- ], exports.WhatsappTriggerBinding.prototype, "id", void 0);
21326
+ ], exports.OrderNotificationBinding.prototype, "id", void 0);
21242
21327
  _ts_decorate66([
21243
21328
  typeorm.Column({
21244
- type: "varchar",
21245
- unique: true
21329
+ type: "varchar"
21246
21330
  }),
21247
21331
  _ts_metadata66("design:type", String)
21248
- ], exports.WhatsappTriggerBinding.prototype, "triggerKey", void 0);
21332
+ ], exports.OrderNotificationBinding.prototype, "triggerKey", void 0);
21333
+ _ts_decorate66([
21334
+ typeorm.Column({
21335
+ type: "enum",
21336
+ enum: NotificationChannel,
21337
+ default: "whatsapp"
21338
+ }),
21339
+ _ts_metadata66("design:type", String)
21340
+ ], exports.OrderNotificationBinding.prototype, "channel", void 0);
21249
21341
  _ts_decorate66([
21250
21342
  typeorm.Column({
21251
21343
  type: "int",
21252
21344
  nullable: true
21253
21345
  }),
21254
21346
  _ts_metadata66("design:type", Object)
21255
- ], exports.WhatsappTriggerBinding.prototype, "messageTemplateId", void 0);
21347
+ ], exports.OrderNotificationBinding.prototype, "messageTemplateId", void 0);
21256
21348
  _ts_decorate66([
21257
21349
  typeorm.Column({
21258
21350
  type: "boolean",
21259
21351
  default: true
21260
21352
  }),
21261
21353
  _ts_metadata66("design:type", Boolean)
21262
- ], exports.WhatsappTriggerBinding.prototype, "enabled", void 0);
21354
+ ], exports.OrderNotificationBinding.prototype, "enabled", void 0);
21263
21355
  _ts_decorate66([
21264
21356
  typeorm.CreateDateColumn(),
21265
21357
  _ts_metadata66("design:type", typeof Date === "undefined" ? Object : Date)
21266
- ], exports.WhatsappTriggerBinding.prototype, "createdAt", void 0);
21358
+ ], exports.OrderNotificationBinding.prototype, "createdAt", void 0);
21267
21359
  _ts_decorate66([
21268
21360
  typeorm.UpdateDateColumn(),
21269
21361
  _ts_metadata66("design:type", typeof Date === "undefined" ? Object : Date)
21270
- ], exports.WhatsappTriggerBinding.prototype, "updatedAt", void 0);
21271
- exports.WhatsappTriggerBinding = _ts_decorate66([
21272
- typeorm.Entity("whatsapp_trigger_bindings")
21273
- ], exports.WhatsappTriggerBinding);
21362
+ ], exports.OrderNotificationBinding.prototype, "updatedAt", void 0);
21363
+ exports.OrderNotificationBinding = _ts_decorate66([
21364
+ typeorm.Entity("order_notification_bindings"),
21365
+ typeorm.Index([
21366
+ "triggerKey",
21367
+ "channel"
21368
+ ], {
21369
+ unique: true
21370
+ })
21371
+ ], exports.OrderNotificationBinding);
21274
21372
  function _ts_decorate67(decorators, target, key, desc) {
21275
21373
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
21276
21374
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -21420,7 +21518,7 @@ var CMS_ENTITY_MAP = {
21420
21518
  refund_policies: exports.RefundPolicy,
21421
21519
  refund_requests: exports.RefundRequest,
21422
21520
  attendees: exports.Attendee,
21423
- whatsapp_trigger_bindings: exports.WhatsappTriggerBinding,
21521
+ order_notification_bindings: exports.OrderNotificationBinding,
21424
21522
  order_notification_triggers: exports.OrderNotificationTrigger
21425
21523
  };
21426
21524
 
@@ -24523,6 +24621,173 @@ function createWhatsappMessageTemplatesHandlers(config) {
24523
24621
  };
24524
24622
  }
24525
24623
  chunkUSNT2KNT_cjs.__name(createWhatsappMessageTemplatesHandlers, "createWhatsappMessageTemplatesHandlers");
24624
+
24625
+ // src/api/email-message-templates-handlers.ts
24626
+ function slugify2(input) {
24627
+ return input.toLowerCase().trim().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) || "template";
24628
+ }
24629
+ chunkUSNT2KNT_cjs.__name(slugify2, "slugify");
24630
+ function createEmailMessageTemplatesHandlers(config) {
24631
+ const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;
24632
+ const templateRepo = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(() => dataSource.getRepository(entityMap.message_templates), "templateRepo");
24633
+ async function requireRead(req, entity) {
24634
+ const a = await requireAuth(req);
24635
+ if (a) return a;
24636
+ if (requireEntityPermission) {
24637
+ const pe = await requireEntityPermission(req, entity, "read");
24638
+ if (pe) return pe;
24639
+ }
24640
+ return null;
24641
+ }
24642
+ chunkUSNT2KNT_cjs.__name(requireRead, "requireRead");
24643
+ async function requireUpdate(req, entity) {
24644
+ const a = await requireAuth(req);
24645
+ if (a) return a;
24646
+ if (requireEntityPermission) {
24647
+ const pe = await requireEntityPermission(req, entity, "update");
24648
+ if (pe) return pe;
24649
+ }
24650
+ return null;
24651
+ }
24652
+ chunkUSNT2KNT_cjs.__name(requireUpdate, "requireUpdate");
24653
+ return {
24654
+ async listCached(req) {
24655
+ const err = await requireRead(req, "settings");
24656
+ if (err) return err;
24657
+ try {
24658
+ const rows = await templateRepo().find({
24659
+ where: {
24660
+ channel: "email",
24661
+ deleted: false
24662
+ },
24663
+ order: {
24664
+ name: "ASC"
24665
+ }
24666
+ });
24667
+ return json({
24668
+ items: rows
24669
+ });
24670
+ } catch {
24671
+ return json({
24672
+ error: "Failed to load templates"
24673
+ }, {
24674
+ status: 500
24675
+ });
24676
+ }
24677
+ },
24678
+ async create(req) {
24679
+ const err = await requireUpdate(req, "settings");
24680
+ if (err) return err;
24681
+ let body;
24682
+ try {
24683
+ body = await req.json();
24684
+ } catch {
24685
+ return json({
24686
+ error: "Invalid JSON body"
24687
+ }, {
24688
+ status: 400
24689
+ });
24690
+ }
24691
+ const name = typeof body.name === "string" ? body.name.trim() : "";
24692
+ const subject = typeof body.subject === "string" ? body.subject : "";
24693
+ const bodyText = typeof body.body === "string" ? body.body : "";
24694
+ if (!name) return json({
24695
+ error: "name is required"
24696
+ }, {
24697
+ status: 400
24698
+ });
24699
+ if (!bodyText.trim()) return json({
24700
+ error: "body is required"
24701
+ }, {
24702
+ status: 400
24703
+ });
24704
+ const baseKey = slugify2(name);
24705
+ let templateKey = baseKey;
24706
+ let suffix = 1;
24707
+ while (await templateRepo().findOne({
24708
+ where: {
24709
+ channel: "email",
24710
+ templateKey,
24711
+ deleted: false
24712
+ }
24713
+ })) {
24714
+ suffix += 1;
24715
+ templateKey = `${baseKey}_${suffix}`;
24716
+ }
24717
+ const row = await templateRepo().save(templateRepo().create({
24718
+ channel: "email",
24719
+ templateKey,
24720
+ name,
24721
+ subject,
24722
+ body: bodyText,
24723
+ externalTemplateRef: null,
24724
+ providerMeta: null,
24725
+ enabled: true,
24726
+ deleted: false
24727
+ }));
24728
+ return json({
24729
+ item: row
24730
+ }, {
24731
+ status: 201
24732
+ });
24733
+ },
24734
+ async update(req, id) {
24735
+ const err = await requireUpdate(req, "settings");
24736
+ if (err) return err;
24737
+ const numId = Number(id);
24738
+ if (!Number.isFinite(numId)) return json({
24739
+ error: "Invalid id"
24740
+ }, {
24741
+ status: 400
24742
+ });
24743
+ let body;
24744
+ try {
24745
+ body = await req.json();
24746
+ } catch {
24747
+ return json({
24748
+ error: "Invalid JSON body"
24749
+ }, {
24750
+ status: 400
24751
+ });
24752
+ }
24753
+ const existing = await templateRepo().findOne({
24754
+ where: {
24755
+ id: numId,
24756
+ channel: "email",
24757
+ deleted: false
24758
+ }
24759
+ });
24760
+ if (!existing) return json({
24761
+ error: "Template not found"
24762
+ }, {
24763
+ status: 404
24764
+ });
24765
+ const patch = {
24766
+ updatedAt: /* @__PURE__ */ new Date()
24767
+ };
24768
+ if (typeof body.name === "string" && body.name.trim()) patch.name = body.name.trim();
24769
+ if (typeof body.subject === "string") patch.subject = body.subject;
24770
+ if (typeof body.body === "string") {
24771
+ if (!body.body.trim()) return json({
24772
+ error: "body cannot be empty"
24773
+ }, {
24774
+ status: 400
24775
+ });
24776
+ patch.body = body.body;
24777
+ }
24778
+ await templateRepo().update(numId, patch);
24779
+ const updated = await templateRepo().findOne({
24780
+ where: {
24781
+ id: numId
24782
+ }
24783
+ });
24784
+ return json({
24785
+ item: updated
24786
+ });
24787
+ }
24788
+ };
24789
+ }
24790
+ chunkUSNT2KNT_cjs.__name(createEmailMessageTemplatesHandlers, "createEmailMessageTemplatesHandlers");
24526
24791
  function connectionFromUrl(redisUrl) {
24527
24792
  const u = new URL(redisUrl);
24528
24793
  return {
@@ -24680,16 +24945,16 @@ function whatsappPlugin(config = {}) {
24680
24945
  db = await getWhatsAppSettings?.() ?? {};
24681
24946
  } catch {
24682
24947
  }
24683
- if (!chunkCOBORIJH_cjs.isWhatsAppPluginEnabled(db)) {
24948
+ if (!chunk22FFHLTO_cjs.isWhatsAppPluginEnabled(db)) {
24684
24949
  context.logger.warn("WhatsApp plugin skipped: disabled in Plugins \u2192 WhatsApp");
24685
24950
  return null;
24686
24951
  }
24687
- const merged = chunkCOBORIJH_cjs.mergeWhatsAppConfigLayers(env, db, staticRest);
24688
- if (!getWhatsAppSettings && !chunkCOBORIJH_cjs.whatsAppConfigured(merged)) {
24952
+ const merged = chunk22FFHLTO_cjs.mergeWhatsAppConfigLayers(env, db, staticRest);
24953
+ if (!getWhatsAppSettings && !chunk22FFHLTO_cjs.whatsAppConfigured(merged)) {
24689
24954
  context.logger.warn("WhatsApp plugin skipped: set WHATSAPP_ACCESS_TOKEN and WHATSAPP_PHONE_NUMBER_ID, or pass getWhatsAppSettings");
24690
24955
  return null;
24691
24956
  }
24692
- const svc = new chunkCOBORIJH_cjs.WhatsAppService(env, staticRest, getWhatsAppSettings, getMessageTemplateRow);
24957
+ const svc = new chunk22FFHLTO_cjs.WhatsAppService(env, staticRest, getWhatsAppSettings, getMessageTemplateRow);
24693
24958
  return {
24694
24959
  send: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name((opts) => svc.send(opts), "send")
24695
24960
  };
@@ -24763,7 +25028,7 @@ function createMessageTemplateRowLoader(dataSource, entityMap) {
24763
25028
  chunkUSNT2KNT_cjs.__name(createMessageTemplateRowLoader, "createMessageTemplateRowLoader");
24764
25029
  function registerMessagingQueueProcessors(cms) {
24765
25030
  chunkXW5ATPRW_cjs.registerEmailQueueProcessor(cms);
24766
- chunkCOBORIJH_cjs.registerWhatsAppQueueProcessor(cms);
25031
+ chunk22FFHLTO_cjs.registerWhatsAppQueueProcessor(cms);
24767
25032
  }
24768
25033
  chunkUSNT2KNT_cjs.__name(registerMessagingQueueProcessors, "registerMessagingQueueProcessors");
24769
25034
  async function ensureMessagingPluginsOnCms(base, options) {
@@ -24792,7 +25057,7 @@ async function ensureMessagingPluginsOnCms(base, options) {
24792
25057
  }
24793
25058
  if (!cms.getPlugin("email")) {
24794
25059
  try {
24795
- const instance = await chunkCOBORIJH_cjs.emailPlugin({
25060
+ const instance = await chunk22FFHLTO_cjs.emailPlugin({
24796
25061
  type: "SMTP",
24797
25062
  from: config.SMTP_FROM ?? "no-reply@localhost",
24798
25063
  to: config.SMTP_TO ?? ""
@@ -24833,7 +25098,7 @@ function messagingPlugins(options) {
24833
25098
  const config = options.config ?? (typeof process !== "undefined" ? process.env : {});
24834
25099
  return [
24835
25100
  queuePlugin(),
24836
- chunkCOBORIJH_cjs.emailPlugin({
25101
+ chunk22FFHLTO_cjs.emailPlugin({
24837
25102
  type: "SMTP",
24838
25103
  from: config.SMTP_FROM ?? "no-reply@localhost",
24839
25104
  to: config.SMTP_TO ?? ""
@@ -24880,7 +25145,7 @@ function withLlmKnowledgeEntityFallbacks(base) {
24880
25145
  "rss_feeds",
24881
25146
  "rss_articles",
24882
25147
  "order_notification_triggers",
24883
- "whatsapp_trigger_bindings",
25148
+ "order_notification_bindings",
24884
25149
  "message_templates"
24885
25150
  ];
24886
25151
  const patch = {};
@@ -24967,7 +25232,7 @@ function createCmsApiHandler(config) {
24967
25232
  } : void 0;
24968
25233
  const entityMap = withLlmKnowledgeEntityFallbacks(rawEntityMap);
24969
25234
  if (getCms) {
24970
- chunkCOBORIJH_cjs.initWhatsappTriggerDispatcher({
25235
+ chunk22FFHLTO_cjs.initWhatsappTriggerDispatcher({
24971
25236
  dataSource,
24972
25237
  entityMap,
24973
25238
  getCms
@@ -24980,7 +25245,7 @@ function createCmsApiHandler(config) {
24980
25245
  ] : baseCrudResources;
24981
25246
  const requireEntityPermissionEffective = /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async (_req, entity, action) => {
24982
25247
  if (!resolveSessionUser) {
24983
- chunkKPKFNLQQ_cjs.logRbac("requireEntityPermission: getSessionUser not passed \u2014 vendor store APIs may 403", {
25248
+ chunkWMXPKKXU_cjs.logRbac("requireEntityPermission: getSessionUser not passed \u2014 vendor store APIs may 403", {
24984
25249
  entity,
24985
25250
  action,
24986
25251
  hint: "Pass getSessionUser: auth.getAuthenticatedUser from createCmsAuthBundle()"
@@ -24990,7 +25255,7 @@ function createCmsApiHandler(config) {
24990
25255
  const raw = await resolveSessionUser();
24991
25256
  const u = await hydrateVendorSessionUser(dataSource, raw);
24992
25257
  if (!u?.email) {
24993
- chunkKPKFNLQQ_cjs.logRbac("requireEntityPermission: no session user", {
25258
+ chunkWMXPKKXU_cjs.logRbac("requireEntityPermission: no session user", {
24994
25259
  entity,
24995
25260
  action
24996
25261
  });
@@ -25000,13 +25265,13 @@ function createCmsApiHandler(config) {
25000
25265
  status: 401
25001
25266
  });
25002
25267
  }
25003
- const allowed = chunkWO2DW4AU_cjs.sessionHasEntityAccess(u, entity, action);
25004
- await chunkKPKFNLQQ_cjs.logEntityAccessDecision(dataSource, "cmsApi.requireEntityPermission", u, entity, action, {
25268
+ const allowed = chunkOIGCAGH7_cjs.sessionHasEntityAccess(u, entity, action);
25269
+ await chunkWMXPKKXU_cjs.logEntityAccessDecision(dataSource, "cmsApi.requireEntityPermission", u, entity, action, {
25005
25270
  allowed,
25006
25271
  resolvePath: "hydrated_session"
25007
25272
  });
25008
25273
  if (allowed) return null;
25009
- const { reason } = chunkKPKFNLQQ_cjs.explainSessionEntityAccess(u, entity, action);
25274
+ const { reason } = chunkWMXPKKXU_cjs.explainSessionEntityAccess(u, entity, action);
25010
25275
  return config.json({
25011
25276
  error: "Forbidden",
25012
25277
  entity,
@@ -25017,7 +25282,7 @@ function createCmsApiHandler(config) {
25017
25282
  });
25018
25283
  }
25019
25284
  if (userRequireEntityPermission) {
25020
- chunkKPKFNLQQ_cjs.logRbac("requireEntityPermission: using app callback only (no getSessionUser)", {
25285
+ chunkWMXPKKXU_cjs.logRbac("requireEntityPermission: using app callback only (no getSessionUser)", {
25021
25286
  entity,
25022
25287
  action
25023
25288
  });
@@ -25104,10 +25369,10 @@ function createCmsApiHandler(config) {
25104
25369
  getVendorScope: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
25105
25370
  const multiVendorEnabled = await checkMultiVendorEnabled(dataSource);
25106
25371
  if (!multiVendorEnabled) {
25107
- return chunkKPKFNLQQ_cjs.resolveDisabledMultiVendorScope(dataSource);
25372
+ return chunkWMXPKKXU_cjs.resolveDisabledMultiVendorScope(dataSource);
25108
25373
  }
25109
25374
  const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
25110
- return chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u ?? null);
25375
+ return chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u ?? null);
25111
25376
  }, "getVendorScope"),
25112
25377
  getHydratedSessionUser: /* @__PURE__ */ chunkUSNT2KNT_cjs.__name(async () => {
25113
25378
  const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
@@ -25238,6 +25503,13 @@ function createCmsApiHandler(config) {
25238
25503
  requireEntityPermission: requireEntityPermissionEffective,
25239
25504
  settingsEncryptionKey: settingsConfig?.encryptionKey
25240
25505
  });
25506
+ const emailMessageTemplatesHandlers = createEmailMessageTemplatesHandlers({
25507
+ dataSource,
25508
+ entityMap,
25509
+ json: config.json,
25510
+ requireAuth: config.requireAuth,
25511
+ requireEntityPermission: requireEntityPermissionEffective
25512
+ });
25241
25513
  const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;
25242
25514
  const llmAgentKnowledgeMerged = llmAgentKnowledgeConfig ?? (chatConfig ? {
25243
25515
  dataSource: chatConfig.dataSource,
@@ -26210,6 +26482,13 @@ function createCmsApiHandler(config) {
26210
26482
  if (path2[0] === "message-templates" && path2[1] === "whatsapp" && path2.length === 3 && path2[2] !== "sync") {
26211
26483
  if (m === "PATCH") return whatsappMessageTemplatesHandlers.setParamOrder(req, path2[2]);
26212
26484
  }
26485
+ if (path2[0] === "message-templates" && path2[1] === "email" && path2.length === 2) {
26486
+ if (m === "GET") return emailMessageTemplatesHandlers.listCached(req);
26487
+ if (m === "POST") return emailMessageTemplatesHandlers.create(req);
26488
+ }
26489
+ if (path2[0] === "message-templates" && path2[1] === "email" && path2.length === 3) {
26490
+ if (m === "PATCH") return emailMessageTemplatesHandlers.update(req, path2[2]);
26491
+ }
26213
26492
  if (path2[0] === "llm_agents") {
26214
26493
  if (!entityMap.llm_agents) {
26215
26494
  console.error(CMS_API_LOG, "llm_agents route: entity missing after merge", {
@@ -26338,7 +26617,7 @@ function createCmsApiHandler(config) {
26338
26617
  let vendorId = null;
26339
26618
  if (resolveSessionUser) {
26340
26619
  const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
26341
- const scope = chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u ?? null);
26620
+ const scope = chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u ?? null);
26342
26621
  if (scope.type === "vendor") vendorId = scope.vendorId;
26343
26622
  }
26344
26623
  const result = await validateCoupon(dataSource, entityMap, couponCode, orderLinesNorm, currency, contactId, isAutomatic, discountId ?? void 0, vendorId);
@@ -26418,7 +26697,7 @@ function createCmsApiHandler(config) {
26418
26697
  let vendorId = null;
26419
26698
  if (resolveSessionUser) {
26420
26699
  const u = await hydrateVendorSessionUser(dataSource, await resolveSessionUser());
26421
- const scope = chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u ?? null);
26700
+ const scope = chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u ?? null);
26422
26701
  if (scope.type === "vendor") vendorId = scope.vendorId;
26423
26702
  }
26424
26703
  const orderLinesNorm = normalizeOrderLinesInput(body?.orderLines);
@@ -26624,7 +26903,7 @@ function createCmsApiHandler(config) {
26624
26903
  status: 400
26625
26904
  });
26626
26905
  }
26627
- const { resendOrderNotification } = await import('./whatsapp-trigger-dispatcher-ONHXI7UY.cjs');
26906
+ const { resendOrderNotification } = await import('./order-notification-dispatcher-RU7BTGGX.cjs');
26628
26907
  const result = await resendOrderNotification(triggerKey, orderId, {
26629
26908
  dataSource,
26630
26909
  entityMap,
@@ -27032,7 +27311,7 @@ function createCmsApiHandler(config) {
27032
27311
  if (resolveSessionUser) {
27033
27312
  const raw = await resolveSessionUser();
27034
27313
  const u = await hydrateVendorSessionUser(dataSource, raw);
27035
- const scope = chunkKPKFNLQQ_cjs.resolveVendorScopeFromSessionUser(u ?? null);
27314
+ const scope = chunkWMXPKKXU_cjs.resolveVendorScopeFromSessionUser(u ?? null);
27036
27315
  if (scope.type === "vendor") {
27037
27316
  scopedVendorIds = scope.vendorIds;
27038
27317
  }