@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,12 +1,12 @@
1
- import { resolveChatEmailToolSettings, CHAT_EMAIL_LOG, detectChatLeadIntent, parseIntentRecipientEmails, mergeEmailLayoutCompanyDetails, sendChatLeadEmail, buildTranscriptForLeadEmail, buildChatbotSystemPromptWithEmailTool, parseEmailRecipientsFromConfig, isWhatsAppPluginEnabled, mergeWhatsAppConfigLayers, whatsAppConfigured, WhatsAppService, registerWhatsAppQueueProcessor, emailPlugin, initWhatsappTriggerDispatcher } from './chunk-VMY2S32H.js';
1
+ import { resolveChatEmailToolSettings, CHAT_EMAIL_LOG, detectChatLeadIntent, parseIntentRecipientEmails, mergeEmailLayoutCompanyDetails, sendChatLeadEmail, buildTranscriptForLeadEmail, buildChatbotSystemPromptWithEmailTool, parseEmailRecipientsFromConfig, isWhatsAppPluginEnabled, mergeWhatsAppConfigLayers, whatsAppConfigured, WhatsAppService, registerWhatsAppQueueProcessor, emailPlugin, initWhatsappTriggerDispatcher } from './chunk-NNQBWDCI.js';
2
2
  import { inviteStatusForActivation } from './chunk-JXF23MPG.js';
3
3
  import { unwrapErpReadData, mapErpPayloadToFulfillment, extractChildOrderRefsFromSalePayload, mapErpPayloadToInvoiceNumber, streamOrderInvoicePdf } from './chunk-WEMDMVHQ.js';
4
4
  import { queueEmail, queueVendorOnboardEmails, registerEmailQueueProcessor } from './chunk-5ELSW2UP.js';
5
5
  import { getSmsTemplateDefault, SMS_MESSAGE_TEMPLATE_DEFAULTS } from './chunk-MQBT33IV.js';
6
6
  import { EVENT_ORDER_MESSAGE_TEMPLATE_DEFAULTS, EVENT_ORDER_TEMPLATE_KEY, EVENT_ORDER_TEMPLATE_VARIABLES } from './chunk-KFFB6EMZ.js';
7
7
  import { JOB_RUNNER_QUEUE } from './chunk-GO7PPYNU.js';
8
- import { canManageRoles, sessionHasEntityAccess } from './chunk-LI2IXVAY.js';
9
- import { permissionRowsToRecord, logRbac, isSuperAdmin, vendorPortalFlagsFromUser, VENDOR_SCOPED_STORE_ENTITIES, isVendorPortalUser, getPermissionableEntityKeys, VENDOR_STORE_RBAC_ENTITIES, isSuperAdminGroupName, VENDOR_RBAC_ENTITIES, VENDOR_VIEWER_ROLE_NAME, DEFAULT_VENDOR_ROLE_DEFS, VENDOR_OWNER_GROUP_NAME, resolveVendorScopeFromSessionUser, canManageVendorRoles, isPlatformAdministrator, canManageVendorTeam, resolveDisabledMultiVendorScope, logEntityAccessDecision, explainSessionEntityAccess } from './chunk-UF3BYUXY.js';
8
+ import { canManageRoles, sessionHasEntityAccess } from './chunk-UXMDSNIG.js';
9
+ import { permissionRowsToRecord, logRbac, isSuperAdmin, vendorPortalFlagsFromUser, VENDOR_SCOPED_STORE_ENTITIES, isVendorPortalUser, getPermissionableEntityKeys, VENDOR_STORE_RBAC_ENTITIES, isSuperAdminGroupName, VENDOR_RBAC_ENTITIES, VENDOR_VIEWER_ROLE_NAME, DEFAULT_VENDOR_ROLE_DEFS, VENDOR_OWNER_GROUP_NAME, resolveVendorScopeFromSessionUser, canManageVendorRoles, isPlatformAdministrator, canManageVendorTeam, resolveDisabledMultiVendorScope, logEntityAccessDecision, explainSessionEntityAccess } from './chunk-P7QCLE5W.js';
10
10
  import { queueErp } from './chunk-SYBOCAWB.js';
11
11
  import { isErpIntegrationEnabled } from './chunk-JC6DLWTE.js';
12
12
  import { __name } from './chunk-SHUYVCID.js';
@@ -2607,10 +2607,11 @@ async function calculateOrderTotalsFromLines(dataSource, entityMap, lineInputs,
2607
2607
  }
2608
2608
  });
2609
2609
  if (combo) {
2610
- const comboRows = await dataSource.query(`SELECT p."vendorId", ci."productId" as "firstProductId"
2610
+ const comboVendorId = Number(combo.vendorId);
2611
+ const comboRows = await dataSource.query(`SELECT ci."productId" as "firstProductId"
2611
2612
  FROM combo_items ci
2612
2613
  JOIN products p ON p.id = ci."productId"
2613
- WHERE ci."comboId" = $1 AND p.deleted = false AND p."vendorId" IS NOT NULL
2614
+ WHERE ci."comboId" = $1 AND p.deleted = false
2614
2615
  LIMIT 1`, [
2615
2616
  productId
2616
2617
  ]);
@@ -2627,7 +2628,8 @@ async function calculateOrderTotalsFromLines(dataSource, entityMap, lineInputs,
2627
2628
  ...childProduct,
2628
2629
  id: productId,
2629
2630
  price: combo.price,
2630
- name: combo.name
2631
+ name: combo.name,
2632
+ vendorId: Number.isFinite(comboVendorId) && comboVendorId > 0 ? comboVendorId : childProduct.vendorId
2631
2633
  };
2632
2634
  }
2633
2635
  }
@@ -5183,6 +5185,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
5183
5185
  });
5184
5186
  }
5185
5187
  if (resource === "combos") {
5188
+ const scope2 = await resolveScopeById();
5186
5189
  const combo = await repo.findOne({
5187
5190
  where: {
5188
5191
  id: Number(id),
@@ -5193,6 +5196,8 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
5193
5196
  "items.product"
5194
5197
  ]
5195
5198
  });
5199
+ const comboDenied = vendorScopeAccessJson(combo, scope2, resource);
5200
+ if (comboDenied) return comboDenied;
5196
5201
  return combo ? json(combo) : json({
5197
5202
  message: "Not found"
5198
5203
  }, {
@@ -11806,6 +11811,84 @@ function slugify(input) {
11806
11811
  return input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
11807
11812
  }
11808
11813
  __name(slugify, "slugify");
11814
+ function vendorOnboardErrorResponse(json, err) {
11815
+ const msg = err instanceof Error ? err.message : String(err);
11816
+ console.error("[vendor-onboard]", err);
11817
+ if (msg === "VENDOR_SLUG_EXISTS") {
11818
+ return json({
11819
+ error: "Vendor slug already exists"
11820
+ }, {
11821
+ status: 400
11822
+ });
11823
+ }
11824
+ if (msg === "USER_EMAIL_EXISTS") {
11825
+ return json({
11826
+ error: "User with this email already exists"
11827
+ }, {
11828
+ status: 400
11829
+ });
11830
+ }
11831
+ if (msg === "VENDOR_OWNER_GROUP_MISSING") {
11832
+ return json({
11833
+ error: "Vendor Owner group not found. Run migrations (VendorOwnerRbacSeed)."
11834
+ }, {
11835
+ status: 500
11836
+ });
11837
+ }
11838
+ if (msg === "VENDOR_ROLES_SEED_FAILED") {
11839
+ return json({
11840
+ error: "Failed to seed store roles for vendor. Run migrations."
11841
+ }, {
11842
+ status: 500
11843
+ });
11844
+ }
11845
+ if (/vendor_roles|vendor_role_permissions/i.test(msg)) {
11846
+ return json({
11847
+ error: "Vendor roles tables missing. Run migrations."
11848
+ }, {
11849
+ status: 500
11850
+ });
11851
+ }
11852
+ if (/relation .* does not exist|column .* does not exist/i.test(msg)) {
11853
+ return json({
11854
+ error: "Database schema is outdated on this environment. Run migrations.",
11855
+ detail: msg
11856
+ }, {
11857
+ status: 500
11858
+ });
11859
+ }
11860
+ if (/duplicate key|unique constraint/i.test(msg)) {
11861
+ if (/email/i.test(msg)) {
11862
+ return json({
11863
+ error: "A user or record with this email already exists",
11864
+ detail: msg
11865
+ }, {
11866
+ status: 409
11867
+ });
11868
+ }
11869
+ if (/slug/i.test(msg)) {
11870
+ return json({
11871
+ error: "Vendor slug already exists",
11872
+ detail: msg
11873
+ }, {
11874
+ status: 409
11875
+ });
11876
+ }
11877
+ return json({
11878
+ error: "Duplicate value conflicts with an existing record",
11879
+ detail: msg
11880
+ }, {
11881
+ status: 409
11882
+ });
11883
+ }
11884
+ return json({
11885
+ error: "Server error",
11886
+ detail: msg
11887
+ }, {
11888
+ status: 500
11889
+ });
11890
+ }
11891
+ __name(vendorOnboardErrorResponse, "vendorOnboardErrorResponse");
11809
11892
  function createVendorOnboardHandlers(config) {
11810
11893
  const { dataSource, entityMap, json, getSessionUser, baseUrl, getCms, hashPassword, minPasswordLength = 6 } = config;
11811
11894
  async function gateAdmin() {
@@ -11974,12 +12057,28 @@ function createVendorOnboardHandlers(config) {
11974
12057
  }
11975
12058
  });
11976
12059
  if (dupVendor) throw new Error("VENDOR_SLUG_EXISTS");
11977
- const ownerGroup = await groupRepo.findOne({
12060
+ let ownerGroup = await groupRepo.findOne({
11978
12061
  where: {
11979
12062
  name: VENDOR_OWNER_GROUP_NAME,
11980
12063
  deleted: false
11981
12064
  }
11982
12065
  });
12066
+ if (!ownerGroup) {
12067
+ try {
12068
+ await groupRepo.save(groupRepo.create({
12069
+ name: VENDOR_OWNER_GROUP_NAME,
12070
+ deleted: false
12071
+ }));
12072
+ ownerGroup = await groupRepo.findOne({
12073
+ where: {
12074
+ name: VENDOR_OWNER_GROUP_NAME,
12075
+ deleted: false
12076
+ }
12077
+ });
12078
+ } catch (seedErr) {
12079
+ console.error("[vendor-onboard] failed to seed Vendor Owner group", seedErr);
12080
+ }
12081
+ }
11983
12082
  if (!ownerGroup) throw new Error("VENDOR_OWNER_GROUP_MISSING");
11984
12083
  const existingUser = await userRepo.findOne({
11985
12084
  where: {
@@ -12068,14 +12167,18 @@ function createVendorOnboardHandlers(config) {
12068
12167
  });
12069
12168
  }
12070
12169
  if (entityMap.customer) {
12071
- await ensureCustomerForUser(em, entityMap.customer, {
12072
- id: newUser.id,
12073
- name: userName,
12074
- email: userEmail,
12075
- phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12076
- }, {
12077
- phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12078
- });
12170
+ try {
12171
+ await ensureCustomerForUser(em, entityMap.customer, {
12172
+ id: newUser.id,
12173
+ name: userName,
12174
+ email: userEmail,
12175
+ phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12176
+ }, {
12177
+ phone: trimOrNull(body.vendor?.phone) ?? ownerPhone
12178
+ });
12179
+ } catch (customerErr) {
12180
+ console.error("[vendor-onboard] ensureCustomerForUser skipped", customerErr);
12181
+ }
12079
12182
  }
12080
12183
  return {
12081
12184
  vendor,
@@ -12125,46 +12228,7 @@ function createVendorOnboardHandlers(config) {
12125
12228
  status: 201
12126
12229
  });
12127
12230
  } catch (e) {
12128
- const msg = e instanceof Error ? e.message : String(e);
12129
- if (process.env.NODE_ENV === "development") {
12130
- console.error("[vendor-onboard]", e);
12131
- }
12132
- if (msg === "VENDOR_SLUG_EXISTS") return json({
12133
- error: "Vendor slug already exists"
12134
- }, {
12135
- status: 400
12136
- });
12137
- if (msg === "USER_EMAIL_EXISTS") return json({
12138
- error: "User with this email already exists"
12139
- }, {
12140
- status: 400
12141
- });
12142
- if (msg === "VENDOR_OWNER_GROUP_MISSING") {
12143
- return json({
12144
- error: "Vendor Owner group not found. Run migrations."
12145
- }, {
12146
- status: 500
12147
- });
12148
- }
12149
- if (msg === "VENDOR_ROLES_SEED_FAILED") {
12150
- return json({
12151
- error: "Failed to seed store roles for vendor. Run migrations."
12152
- }, {
12153
- status: 500
12154
- });
12155
- }
12156
- if (/vendor_roles|vendor_role_permissions/i.test(msg)) {
12157
- return json({
12158
- error: "Vendor roles tables missing. Run migrations."
12159
- }, {
12160
- status: 500
12161
- });
12162
- }
12163
- return json({
12164
- error: "Server error"
12165
- }, {
12166
- status: 500
12167
- });
12231
+ return vendorOnboardErrorResponse(json, e);
12168
12232
  }
12169
12233
  },
12170
12234
  /** POST /api/admin/vendor/switch — set active vendor in session (JWT update via client) */
@@ -20845,6 +20909,8 @@ var Combo = class {
20845
20909
  __name(this, "Combo");
20846
20910
  }
20847
20911
  id;
20912
+ vendorId;
20913
+ vendor;
20848
20914
  name;
20849
20915
  desc;
20850
20916
  eventId;
@@ -20870,6 +20936,19 @@ _ts_decorate63([
20870
20936
  PrimaryGeneratedColumn(),
20871
20937
  _ts_metadata63("design:type", Number)
20872
20938
  ], Combo.prototype, "id", void 0);
20939
+ _ts_decorate63([
20940
+ Column("int"),
20941
+ _ts_metadata63("design:type", Number)
20942
+ ], Combo.prototype, "vendorId", void 0);
20943
+ _ts_decorate63([
20944
+ ManyToOne(() => Vendor, {
20945
+ onDelete: "RESTRICT"
20946
+ }),
20947
+ JoinColumn({
20948
+ name: "vendorId"
20949
+ }),
20950
+ _ts_metadata63("design:type", typeof Vendor === "undefined" ? Object : Vendor)
20951
+ ], Combo.prototype, "vendor", void 0);
20873
20952
  _ts_decorate63([
20874
20953
  Column({
20875
20954
  type: "varchar"
@@ -21214,12 +21293,18 @@ function _ts_metadata66(k, v) {
21214
21293
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
21215
21294
  }
21216
21295
  __name(_ts_metadata66, "_ts_metadata");
21217
- var WhatsappTriggerBinding = class {
21296
+ var NotificationChannel = /* @__PURE__ */ (function(NotificationChannel2) {
21297
+ NotificationChannel2["WHATSAPP"] = "whatsapp";
21298
+ NotificationChannel2["EMAIL"] = "email";
21299
+ return NotificationChannel2;
21300
+ })({});
21301
+ var OrderNotificationBinding = class {
21218
21302
  static {
21219
- __name(this, "WhatsappTriggerBinding");
21303
+ __name(this, "OrderNotificationBinding");
21220
21304
  }
21221
21305
  id;
21222
21306
  triggerKey;
21307
+ channel;
21223
21308
  messageTemplateId;
21224
21309
  enabled;
21225
21310
  createdAt;
@@ -21228,39 +21313,52 @@ var WhatsappTriggerBinding = class {
21228
21313
  _ts_decorate66([
21229
21314
  PrimaryGeneratedColumn(),
21230
21315
  _ts_metadata66("design:type", Number)
21231
- ], WhatsappTriggerBinding.prototype, "id", void 0);
21316
+ ], OrderNotificationBinding.prototype, "id", void 0);
21232
21317
  _ts_decorate66([
21233
21318
  Column({
21234
- type: "varchar",
21235
- unique: true
21319
+ type: "varchar"
21236
21320
  }),
21237
21321
  _ts_metadata66("design:type", String)
21238
- ], WhatsappTriggerBinding.prototype, "triggerKey", void 0);
21322
+ ], OrderNotificationBinding.prototype, "triggerKey", void 0);
21323
+ _ts_decorate66([
21324
+ Column({
21325
+ type: "enum",
21326
+ enum: NotificationChannel,
21327
+ default: "whatsapp"
21328
+ }),
21329
+ _ts_metadata66("design:type", String)
21330
+ ], OrderNotificationBinding.prototype, "channel", void 0);
21239
21331
  _ts_decorate66([
21240
21332
  Column({
21241
21333
  type: "int",
21242
21334
  nullable: true
21243
21335
  }),
21244
21336
  _ts_metadata66("design:type", Object)
21245
- ], WhatsappTriggerBinding.prototype, "messageTemplateId", void 0);
21337
+ ], OrderNotificationBinding.prototype, "messageTemplateId", void 0);
21246
21338
  _ts_decorate66([
21247
21339
  Column({
21248
21340
  type: "boolean",
21249
21341
  default: true
21250
21342
  }),
21251
21343
  _ts_metadata66("design:type", Boolean)
21252
- ], WhatsappTriggerBinding.prototype, "enabled", void 0);
21344
+ ], OrderNotificationBinding.prototype, "enabled", void 0);
21253
21345
  _ts_decorate66([
21254
21346
  CreateDateColumn(),
21255
21347
  _ts_metadata66("design:type", typeof Date === "undefined" ? Object : Date)
21256
- ], WhatsappTriggerBinding.prototype, "createdAt", void 0);
21348
+ ], OrderNotificationBinding.prototype, "createdAt", void 0);
21257
21349
  _ts_decorate66([
21258
21350
  UpdateDateColumn(),
21259
21351
  _ts_metadata66("design:type", typeof Date === "undefined" ? Object : Date)
21260
- ], WhatsappTriggerBinding.prototype, "updatedAt", void 0);
21261
- WhatsappTriggerBinding = _ts_decorate66([
21262
- Entity("whatsapp_trigger_bindings")
21263
- ], WhatsappTriggerBinding);
21352
+ ], OrderNotificationBinding.prototype, "updatedAt", void 0);
21353
+ OrderNotificationBinding = _ts_decorate66([
21354
+ Entity("order_notification_bindings"),
21355
+ Index([
21356
+ "triggerKey",
21357
+ "channel"
21358
+ ], {
21359
+ unique: true
21360
+ })
21361
+ ], OrderNotificationBinding);
21264
21362
  function _ts_decorate67(decorators, target, key, desc) {
21265
21363
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
21266
21364
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -21410,7 +21508,7 @@ var CMS_ENTITY_MAP = {
21410
21508
  refund_policies: RefundPolicy,
21411
21509
  refund_requests: RefundRequest,
21412
21510
  attendees: Attendee,
21413
- whatsapp_trigger_bindings: WhatsappTriggerBinding,
21511
+ order_notification_bindings: OrderNotificationBinding,
21414
21512
  order_notification_triggers: OrderNotificationTrigger
21415
21513
  };
21416
21514
 
@@ -24513,6 +24611,173 @@ function createWhatsappMessageTemplatesHandlers(config) {
24513
24611
  };
24514
24612
  }
24515
24613
  __name(createWhatsappMessageTemplatesHandlers, "createWhatsappMessageTemplatesHandlers");
24614
+
24615
+ // src/api/email-message-templates-handlers.ts
24616
+ function slugify2(input) {
24617
+ return input.toLowerCase().trim().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 64) || "template";
24618
+ }
24619
+ __name(slugify2, "slugify");
24620
+ function createEmailMessageTemplatesHandlers(config) {
24621
+ const { dataSource, entityMap, json, requireAuth, requireEntityPermission } = config;
24622
+ const templateRepo = /* @__PURE__ */ __name(() => dataSource.getRepository(entityMap.message_templates), "templateRepo");
24623
+ async function requireRead(req, entity) {
24624
+ const a = await requireAuth(req);
24625
+ if (a) return a;
24626
+ if (requireEntityPermission) {
24627
+ const pe = await requireEntityPermission(req, entity, "read");
24628
+ if (pe) return pe;
24629
+ }
24630
+ return null;
24631
+ }
24632
+ __name(requireRead, "requireRead");
24633
+ async function requireUpdate(req, entity) {
24634
+ const a = await requireAuth(req);
24635
+ if (a) return a;
24636
+ if (requireEntityPermission) {
24637
+ const pe = await requireEntityPermission(req, entity, "update");
24638
+ if (pe) return pe;
24639
+ }
24640
+ return null;
24641
+ }
24642
+ __name(requireUpdate, "requireUpdate");
24643
+ return {
24644
+ async listCached(req) {
24645
+ const err = await requireRead(req, "settings");
24646
+ if (err) return err;
24647
+ try {
24648
+ const rows = await templateRepo().find({
24649
+ where: {
24650
+ channel: "email",
24651
+ deleted: false
24652
+ },
24653
+ order: {
24654
+ name: "ASC"
24655
+ }
24656
+ });
24657
+ return json({
24658
+ items: rows
24659
+ });
24660
+ } catch {
24661
+ return json({
24662
+ error: "Failed to load templates"
24663
+ }, {
24664
+ status: 500
24665
+ });
24666
+ }
24667
+ },
24668
+ async create(req) {
24669
+ const err = await requireUpdate(req, "settings");
24670
+ if (err) return err;
24671
+ let body;
24672
+ try {
24673
+ body = await req.json();
24674
+ } catch {
24675
+ return json({
24676
+ error: "Invalid JSON body"
24677
+ }, {
24678
+ status: 400
24679
+ });
24680
+ }
24681
+ const name = typeof body.name === "string" ? body.name.trim() : "";
24682
+ const subject = typeof body.subject === "string" ? body.subject : "";
24683
+ const bodyText = typeof body.body === "string" ? body.body : "";
24684
+ if (!name) return json({
24685
+ error: "name is required"
24686
+ }, {
24687
+ status: 400
24688
+ });
24689
+ if (!bodyText.trim()) return json({
24690
+ error: "body is required"
24691
+ }, {
24692
+ status: 400
24693
+ });
24694
+ const baseKey = slugify2(name);
24695
+ let templateKey = baseKey;
24696
+ let suffix = 1;
24697
+ while (await templateRepo().findOne({
24698
+ where: {
24699
+ channel: "email",
24700
+ templateKey,
24701
+ deleted: false
24702
+ }
24703
+ })) {
24704
+ suffix += 1;
24705
+ templateKey = `${baseKey}_${suffix}`;
24706
+ }
24707
+ const row = await templateRepo().save(templateRepo().create({
24708
+ channel: "email",
24709
+ templateKey,
24710
+ name,
24711
+ subject,
24712
+ body: bodyText,
24713
+ externalTemplateRef: null,
24714
+ providerMeta: null,
24715
+ enabled: true,
24716
+ deleted: false
24717
+ }));
24718
+ return json({
24719
+ item: row
24720
+ }, {
24721
+ status: 201
24722
+ });
24723
+ },
24724
+ async update(req, id) {
24725
+ const err = await requireUpdate(req, "settings");
24726
+ if (err) return err;
24727
+ const numId = Number(id);
24728
+ if (!Number.isFinite(numId)) return json({
24729
+ error: "Invalid id"
24730
+ }, {
24731
+ status: 400
24732
+ });
24733
+ let body;
24734
+ try {
24735
+ body = await req.json();
24736
+ } catch {
24737
+ return json({
24738
+ error: "Invalid JSON body"
24739
+ }, {
24740
+ status: 400
24741
+ });
24742
+ }
24743
+ const existing = await templateRepo().findOne({
24744
+ where: {
24745
+ id: numId,
24746
+ channel: "email",
24747
+ deleted: false
24748
+ }
24749
+ });
24750
+ if (!existing) return json({
24751
+ error: "Template not found"
24752
+ }, {
24753
+ status: 404
24754
+ });
24755
+ const patch = {
24756
+ updatedAt: /* @__PURE__ */ new Date()
24757
+ };
24758
+ if (typeof body.name === "string" && body.name.trim()) patch.name = body.name.trim();
24759
+ if (typeof body.subject === "string") patch.subject = body.subject;
24760
+ if (typeof body.body === "string") {
24761
+ if (!body.body.trim()) return json({
24762
+ error: "body cannot be empty"
24763
+ }, {
24764
+ status: 400
24765
+ });
24766
+ patch.body = body.body;
24767
+ }
24768
+ await templateRepo().update(numId, patch);
24769
+ const updated = await templateRepo().findOne({
24770
+ where: {
24771
+ id: numId
24772
+ }
24773
+ });
24774
+ return json({
24775
+ item: updated
24776
+ });
24777
+ }
24778
+ };
24779
+ }
24780
+ __name(createEmailMessageTemplatesHandlers, "createEmailMessageTemplatesHandlers");
24516
24781
  function connectionFromUrl(redisUrl) {
24517
24782
  const u = new URL(redisUrl);
24518
24783
  return {
@@ -24870,7 +25135,7 @@ function withLlmKnowledgeEntityFallbacks(base) {
24870
25135
  "rss_feeds",
24871
25136
  "rss_articles",
24872
25137
  "order_notification_triggers",
24873
- "whatsapp_trigger_bindings",
25138
+ "order_notification_bindings",
24874
25139
  "message_templates"
24875
25140
  ];
24876
25141
  const patch = {};
@@ -25228,6 +25493,13 @@ function createCmsApiHandler(config) {
25228
25493
  requireEntityPermission: requireEntityPermissionEffective,
25229
25494
  settingsEncryptionKey: settingsConfig?.encryptionKey
25230
25495
  });
25496
+ const emailMessageTemplatesHandlers = createEmailMessageTemplatesHandlers({
25497
+ dataSource,
25498
+ entityMap,
25499
+ json: config.json,
25500
+ requireAuth: config.requireAuth,
25501
+ requireEntityPermission: requireEntityPermissionEffective
25502
+ });
25231
25503
  const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;
25232
25504
  const llmAgentKnowledgeMerged = llmAgentKnowledgeConfig ?? (chatConfig ? {
25233
25505
  dataSource: chatConfig.dataSource,
@@ -26200,6 +26472,13 @@ function createCmsApiHandler(config) {
26200
26472
  if (path2[0] === "message-templates" && path2[1] === "whatsapp" && path2.length === 3 && path2[2] !== "sync") {
26201
26473
  if (m === "PATCH") return whatsappMessageTemplatesHandlers.setParamOrder(req, path2[2]);
26202
26474
  }
26475
+ if (path2[0] === "message-templates" && path2[1] === "email" && path2.length === 2) {
26476
+ if (m === "GET") return emailMessageTemplatesHandlers.listCached(req);
26477
+ if (m === "POST") return emailMessageTemplatesHandlers.create(req);
26478
+ }
26479
+ if (path2[0] === "message-templates" && path2[1] === "email" && path2.length === 3) {
26480
+ if (m === "PATCH") return emailMessageTemplatesHandlers.update(req, path2[2]);
26481
+ }
26203
26482
  if (path2[0] === "llm_agents") {
26204
26483
  if (!entityMap.llm_agents) {
26205
26484
  console.error(CMS_API_LOG, "llm_agents route: entity missing after merge", {
@@ -26614,7 +26893,7 @@ function createCmsApiHandler(config) {
26614
26893
  status: 400
26615
26894
  });
26616
26895
  }
26617
- const { resendOrderNotification } = await import('./whatsapp-trigger-dispatcher-PWFI4FKP.js');
26896
+ const { resendOrderNotification } = await import('./order-notification-dispatcher-XWIJYDGA.js');
26618
26897
  const result = await resendOrderNotification(triggerKey, orderId, {
26619
26898
  dataSource,
26620
26899
  entityMap,
@@ -30309,4 +30588,4 @@ function createStorefrontApiHandler(config) {
30309
30588
  }
30310
30589
  __name(createStorefrontApiHandler, "createStorefrontApiHandler");
30311
30590
 
30312
- export { Address, Attendee, Attribute, BLOG_GENERATOR_AGENT_NAME, BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION, BLOG_GENERATOR_DEFAULT_VALIDATION_RULES, BLOG_GENERATOR_LLM_AGENT_SLUG, BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR, BLOG_METADATA_ENRICHER_AGENT_NAME, BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION, BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES, BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG, Blog, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationTrigger, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, WhatsappTriggerBinding, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, calculateOrderRefundPreview, calculateRefundFromPolicy, checkEventsEnabled, checkMultiVendorEnabled, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging };
30591
+ export { Address, Attendee, Attribute, BLOG_GENERATOR_AGENT_NAME, BLOG_GENERATOR_DEFAULT_SYSTEM_INSTRUCTION, BLOG_GENERATOR_DEFAULT_VALIDATION_RULES, BLOG_GENERATOR_LLM_AGENT_SLUG, BLOG_GENERATOR_MARKDOWN_ARTICLE_SEPARATOR, BLOG_METADATA_ENRICHER_AGENT_NAME, BLOG_METADATA_ENRICHER_DEFAULT_SYSTEM_INSTRUCTION, BLOG_METADATA_ENRICHER_DEFAULT_VALIDATION_RULES, BLOG_METADATA_ENRICHER_LLM_AGENT_SLUG, Blog, BlogGeneratorService, Brand, CMS_ENTITY_MAP, Cart, CartItem, Category, ChatConversation, ChatMessage, Collection, Combo, ComboItem, Comment, Config, Contact, Currency, CurrencyExchange, Customer, Customer_Contacts, Discount, DiscountRules, Event, EventProduct, Form, FormField, FormSubmission, JobSchedule, JobScheduleRun, KnowledgeBaseChunk, KnowledgeBaseDocument, LlmAgent, Media, MessageTemplate, Order, OrderAddresses, OrderDiscounts, OrderItem, OrderNotificationBinding, OrderNotificationTrigger, OtpChallenge, Page, PasswordResetToken, Payment, Permission, Product, ProductAttribute, ProductCategory, ProductConfig, ProductVariant, RefundPolicy, RefundRequest, RssArticle, RssFeed, Seo, Tag, Tax, User, UserGroup, Vendor, VendorCustomer, VendorRole, VendorRolePermission, VendorUser, Wishlist, WishlistItem, ZIP_MIME_TYPES, applyVendorCustomersContactFilter, assertCaptchaOk, assertContactAllowedForVendorOrder, buildBlogMetadataUserPrompt, buildCronFromSchedule, buildRssUserPromptFromFeeds, calculateOrderRefundPreview, calculateRefundFromPolicy, checkEventsEnabled, checkMultiVendorEnabled, contactIsVendorCustomer, countRecentOtpSends, createAnalyticsHandlers, createBlogBySlugHandler, createChangePasswordHandler, createCmsApiHandler, createCmsApp, createCmsAppWithMessaging, createCrudByIdHandler, createCrudHandler, createDashboardStatsHandler, createEcommerceAnalyticsHandler, createEventOrderMessageTemplateHandlers, createForgotPasswordHandler, createFormBySlugHandler, createInviteAcceptHandler, createJobScheduleHandlers, createLlmAgentKnowledgeHandlers, createMediaZipExtractHandler, createMessageTemplateRowLoader, createOtpChallenge, createSetPasswordHandler, createSettingsApiHandlers, createSocialMediaHandlers, createStorefrontApiHandler, createUploadHandler, createUserAuthApiRouter, createUserAvatarHandler, createUserProfileHandler, createUsersApiHandlers, createVendorDashboardHandler, createVendorOnboardHandlers, customerPhoneForUser, daysBeforeEventStart, describeEventTierPolicy, ensureCustomerForUser, ensureMessagingPluginsOnCms, ensureScheduleQueueWorker, ensureVendorCustomerForOrderContact, findActiveRefundPolicyForVendor, formatTierRange, generateNumericOtp, getPublicSettingsGroup, getRssArticleSummaryFromItem, hashOtpCode, hydrateVendorSessionUser, invalidateEventsCache, invalidateMultiVendorCache, isCustomerTypeContact, isZipMedia, linkUnclaimedContactToUser, llmAgentToChatAgentOptions, loadSettingsGroupFromDb, loadUserVendorContext, mergeGuardrailsIntoSystemPrompt, messagingPlugins, metaFetchUserManagedPages, metaPostPageFeed, metaPostPagePhoto, metaResolvePageAccessToken, normalizePhoneE164, normalizeRefundTiers, overlayCmsPlugins, parseBlogGeneratorAgentContent, parseBlogGeneratorModelOutput, parseBlogMetadataEnrichmentJson, parseLlmAgentValidationRules, pgBossScheduleNameForId, queueErpCreateContactIfEnabled, queueJobScheduleNow, queuePlugin, queueSms, registerJobRunnerWorker, registerMessagingQueueProcessors, registerSmsQueueProcessor, relativePathFromMediaParentId, resolveBlogCategoryIdByName, resolveSettingsEncryptionKey, resolveVendorIdForContactCheck, sanitizeMediaFolderPath, sanitizeStorageSegment, sendVendorOnboardEmails, simpleDecrypt, simpleEncrypt, syncJobScheduleToPgBoss, validateRefundTiers, validateScheduleInput, validateUserMessageAgainstAgentRules, validateUserMessageAgainstStructuredRules, verifyAndConsumeOtpChallenge, verifyOtpCodeHash, whatsappPlugin, wrapGetCmsWithMessaging };
@@ -1,4 +1,4 @@
1
- import { explainSessionEntityAccess, isVendorPortalUser, logRbac } from './chunk-UF3BYUXY.js';
1
+ import { explainSessionEntityAccess, isVendorPortalUser, logRbac } from './chunk-P7QCLE5W.js';
2
2
  import { __name } from './chunk-SHUYVCID.js';
3
3
 
4
4
  // src/auth/helpers.ts
@@ -18,7 +18,7 @@ var PERMISSION_ENTITY_INTERNAL_EXCLUDE = /* @__PURE__ */ new Set([
18
18
  "wishlist_items",
19
19
  "message_templates",
20
20
  "order_notification_triggers",
21
- "whatsapp_trigger_bindings",
21
+ "order_notification_bindings",
22
22
  "vendor_users",
23
23
  "vendor_roles",
24
24
  "vendor_role_permissions"
@@ -129,7 +129,8 @@ var VENDOR_SCOPED_STORE_ENTITIES = /* @__PURE__ */ new Set([
129
129
  "vendor_customers",
130
130
  "discounts",
131
131
  "events",
132
- "refund_policies"
132
+ "refund_policies",
133
+ "combos"
133
134
  ]);
134
135
  var VENDOR_STORE_RBAC_ENTITIES = /* @__PURE__ */ new Set([
135
136
  ...VENDOR_SCOPED_STORE_ENTITIES,
@@ -594,7 +595,7 @@ async function logEntityAccessDecision(dataSource, context, user, entity, action
594
595
  const id = Number(user.id);
595
596
  if (Number.isFinite(id)) {
596
597
  try {
597
- const { loadDbPermissionsForUser } = await import('./rbac-debug-db-HWP65A4O.cjs');
598
+ const { loadDbPermissionsForUser } = await import('./rbac-debug-db-KHG4FJC3.cjs');
598
599
  dbPermissions = await loadDbPermissionsForUser(dataSource, id);
599
600
  } catch (e) {
600
601
  dbPermissions = {