@infuro/cms-core 1.0.16 → 1.0.18

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 (46) hide show
  1. package/README.md +739 -724
  2. package/dist/admin.cjs +1 -1
  3. package/dist/admin.cjs.map +1 -1
  4. package/dist/admin.js +1 -1
  5. package/dist/admin.js.map +1 -1
  6. package/dist/api.cjs +132 -57
  7. package/dist/api.cjs.map +1 -1
  8. package/dist/api.d.cts +1 -1
  9. package/dist/api.d.ts +1 -1
  10. package/dist/api.js +132 -57
  11. package/dist/api.js.map +1 -1
  12. package/dist/auth.cjs.map +1 -1
  13. package/dist/auth.js.map +1 -1
  14. package/dist/cli.cjs +21 -6
  15. package/dist/cli.cjs.map +1 -1
  16. package/dist/cli.js +21 -6
  17. package/dist/cli.js.map +1 -1
  18. package/dist/hooks.cjs.map +1 -1
  19. package/dist/hooks.js.map +1 -1
  20. package/dist/{index-h42MoUNq.d.cts → index-D2C1O9b4.d.cts} +8 -1
  21. package/dist/{index-C85X7cc7.d.ts → index-GMn7-9PX.d.ts} +8 -1
  22. package/dist/index.cjs +135 -57
  23. package/dist/index.cjs.map +1 -1
  24. package/dist/index.d.cts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.js +135 -57
  27. package/dist/index.js.map +1 -1
  28. package/dist/migrations/1772178563554-InitialSchema.ts +304 -304
  29. package/dist/migrations/1772178563555-ChatAndKnowledgeBase.ts +55 -55
  30. package/dist/migrations/1772178563556-KnowledgeBaseVector.ts +16 -16
  31. package/dist/migrations/1774300000000-RbacSeedGroupsAndPermissionUnique.ts +24 -24
  32. package/dist/migrations/1774300000001-SeedAdministratorUsersPermission.ts +35 -35
  33. package/dist/migrations/1774400000000-CustomerAdminAccessContactUser.ts +37 -37
  34. package/dist/migrations/1774400000001-StorefrontCartWishlist.ts +100 -100
  35. package/dist/migrations/1774400000002-WishlistGuestId.ts +29 -29
  36. package/dist/migrations/1774500000000-ProductCollectionHsn.ts +15 -15
  37. package/dist/migrations/1774600000000-OrderKindParentOrderNumber.ts +36 -36
  38. package/dist/migrations/1774800000000-OtpChallengesUserPhone.ts +41 -41
  39. package/dist/migrations/1774900000000-MessageTemplates.ts +39 -39
  40. package/dist/migrations/1775000000000-ProductUomTypeOrderItemSnapshots.ts +29 -29
  41. package/dist/migrations/1775200000000-MediaDriveFolders.ts +38 -38
  42. package/dist/migrations/README.md +3 -3
  43. package/dist/theme.cjs.map +1 -1
  44. package/dist/theme.js.map +1 -1
  45. package/package.json +13 -6
  46. package/src/admin/admin.css +72 -72
package/dist/api.cjs CHANGED
@@ -569,6 +569,28 @@ function buildSearchWhereClause(repo, search) {
569
569
  if (ors.length === 0) return {};
570
570
  return ors.length === 1 ? ors[0] : ors;
571
571
  }
572
+ function entityHasSoftDelete(repo) {
573
+ return repo.metadata.columns.some((c) => c.propertyName === "deleted");
574
+ }
575
+ function mergeDeletedFalseWhere(repo, where) {
576
+ if (!entityHasSoftDelete(repo)) return where;
577
+ const d = { deleted: false };
578
+ if (Array.isArray(where)) {
579
+ if (where.length === 0) return [d];
580
+ return where.map((w) => ({ ...w, ...d }));
581
+ }
582
+ return Object.keys(where).length > 0 ? { ...where, ...d } : d;
583
+ }
584
+ function buildSoftDeletePayload(meta, deletedBy) {
585
+ const payload = { deleted: true };
586
+ if (meta.columns.some((c) => c.propertyName === "deletedAt")) {
587
+ payload.deletedAt = /* @__PURE__ */ new Date();
588
+ }
589
+ if (deletedBy != null && meta.columns.some((c) => c.propertyName === "deletedBy")) {
590
+ payload.deletedBy = deletedBy;
591
+ }
592
+ return payload;
593
+ }
572
594
  function makeContactErpSync(dataSource, entityMap, getCms) {
573
595
  return async function syncContactRowToErp(row) {
574
596
  if (!getCms) return;
@@ -593,10 +615,11 @@ function createCrudHandler(dataSource, entityMap, options) {
593
615
  async function authz(req, resource, action) {
594
616
  const authError = await requireAuth(req);
595
617
  if (authError) return authError;
596
- if (reqPerm) {
597
- const pe = await reqPerm(req, resource, action);
598
- if (pe) return pe;
618
+ if (!reqPerm) {
619
+ return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
599
620
  }
621
+ const pe = await reqPerm(req, resource, action);
622
+ if (pe) return pe;
600
623
  return null;
601
624
  }
602
625
  return {
@@ -632,7 +655,7 @@ function createCrudHandler(dataSource, entityMap, options) {
632
655
  return json({ total: 0, page, limit, totalPages: 0, data: [] });
633
656
  }
634
657
  }
635
- const qb = repo2.createQueryBuilder("order").leftJoinAndSelect("order.contact", "contact").leftJoinAndSelect("order.items", "items").leftJoinAndSelect("items.product", "product").leftJoinAndSelect("product.collection", "collection").orderBy(`order.${sortField2}`, sortOrderOrders).skip(skip).take(limit);
658
+ const qb = repo2.createQueryBuilder("order").leftJoinAndSelect("order.contact", "contact").leftJoinAndSelect("order.items", "items").leftJoinAndSelect("items.product", "product").leftJoinAndSelect("product.collection", "collection").andWhere("order.deleted = :orderDel", { orderDel: false }).orderBy(`order.${sortField2}`, sortOrderOrders).skip(skip).take(limit);
636
659
  if (search && typeof search === "string" && search.trim()) {
637
660
  const term = `%${search.trim()}%`;
638
661
  qb.andWhere(
@@ -670,7 +693,7 @@ function createCrudHandler(dataSource, entityMap, options) {
670
693
  const dateTo = searchParams.get("dateTo")?.trim();
671
694
  const methodFilter = searchParams.get("method")?.trim();
672
695
  const orderNumberParam = searchParams.get("orderNumber")?.trim();
673
- const qb = repo2.createQueryBuilder("payment").leftJoinAndSelect("payment.order", "ord").leftJoinAndSelect("ord.contact", "orderContact").leftJoinAndSelect("payment.contact", "contact").orderBy(`payment.${sortField2}`, sortOrderPayments).skip(skip).take(limit);
696
+ const qb = repo2.createQueryBuilder("payment").leftJoinAndSelect("payment.order", "ord").leftJoinAndSelect("ord.contact", "orderContact").leftJoinAndSelect("payment.contact", "contact").andWhere("payment.deleted = :payDel", { payDel: false }).orderBy(`payment.${sortField2}`, sortOrderPayments).skip(skip).take(limit);
674
697
  if (search && typeof search === "string" && search.trim()) {
675
698
  const term = `%${search.trim()}%`;
676
699
  qb.andWhere(
@@ -701,7 +724,7 @@ function createCrudHandler(dataSource, entityMap, options) {
701
724
  const repo2 = dataSource.getRepository(entity);
702
725
  const statusFilter = searchParams.get("status")?.trim();
703
726
  const inventory = searchParams.get("inventory")?.trim();
704
- const productWhere = {};
727
+ const productWhere = { deleted: false };
705
728
  if (statusFilter) productWhere.status = statusFilter;
706
729
  if (inventory === "in_stock") productWhere.quantity = (0, import_typeorm.MoreThan)(0);
707
730
  if (inventory === "out_of_stock") productWhere.quantity = 0;
@@ -724,7 +747,7 @@ function createCrudHandler(dataSource, entityMap, options) {
724
747
  const typeFilter2 = searchParams.get("type")?.trim();
725
748
  const orderIdParam = searchParams.get("orderId")?.trim();
726
749
  const includeSummary = searchParams.get("includeSummary") === "1";
727
- const qb = repo2.createQueryBuilder("contact").orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
750
+ const qb = repo2.createQueryBuilder("contact").andWhere("contact.deleted = :contactDel", { contactDel: false }).orderBy(`contact.${sortField2}`, sortOrderContacts).skip(skip).take(limit);
728
751
  if (search && typeof search === "string" && search.trim()) {
729
752
  const term = `%${search.trim()}%`;
730
753
  qb.andWhere("(contact.name ILIKE :term OR contact.email ILIKE :term OR contact.phone ILIKE :term)", { term });
@@ -765,9 +788,9 @@ function createCrudHandler(dataSource, entityMap, options) {
765
788
  if (parentIdParam != null && parentIdParam !== "") {
766
789
  const n = Number(parentIdParam);
767
790
  if (!Number.isFinite(n)) return json({ error: "Invalid parentId" }, { status: 400 });
768
- qb.where("m.parentId = :pid", { pid: n });
791
+ qb.where("m.deleted = :mediaDel AND m.parentId = :pid", { mediaDel: false, pid: n });
769
792
  } else {
770
- qb.where("m.parentId IS NULL");
793
+ qb.where("m.deleted = :mediaDel AND m.parentId IS NULL", { mediaDel: false });
771
794
  }
772
795
  if (search && typeof search === "string" && search.trim()) {
773
796
  qb.andWhere("m.filename ILIKE :search", { search: `%${search.trim()}%` });
@@ -811,6 +834,7 @@ function createCrudHandler(dataSource, entityMap, options) {
811
834
  where = extraWhere;
812
835
  }
813
836
  }
837
+ where = mergeDeletedFalseWhere(repo, where);
814
838
  const [data, total] = await repo.findAndCount({
815
839
  skip,
816
840
  take: limit,
@@ -978,15 +1002,16 @@ function createCrudHandler(dataSource, entityMap, options) {
978
1002
  };
979
1003
  }
980
1004
  function createCrudByIdHandler(dataSource, entityMap, options) {
981
- const { requireAuth, json, requireEntityPermission: reqPerm, getCms } = options;
1005
+ const { requireAuth, json, requireEntityPermission: reqPerm, getCms, getDeletedByUserId } = options;
982
1006
  const syncContactRowToErp = makeContactErpSync(dataSource, entityMap, getCms);
983
1007
  async function authz(req, resource, action) {
984
1008
  const authError = await requireAuth(req);
985
1009
  if (authError) return authError;
986
- if (reqPerm) {
987
- const pe = await reqPerm(req, resource, action);
988
- if (pe) return pe;
1010
+ if (!reqPerm) {
1011
+ return json({ error: "Forbidden", reason: "entity_rbac_required", entity: resource, action }, { status: 403 });
989
1012
  }
1013
+ const pe = await reqPerm(req, resource, action);
1014
+ if (pe) return pe;
990
1015
  return null;
991
1016
  }
992
1017
  return {
@@ -998,7 +1023,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
998
1023
  const repo = dataSource.getRepository(entity);
999
1024
  if (resource === "orders") {
1000
1025
  const order = await repo.findOne({
1001
- where: { id: Number(id) },
1026
+ where: { id: Number(id), deleted: false },
1002
1027
  relations: ["contact", "billingAddress", "shippingAddress", "items", "items.product", "items.product.collection", "payments"]
1003
1028
  });
1004
1029
  if (!order) return json({ message: "Not found" }, { status: 404 });
@@ -1010,7 +1035,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1010
1035
  }
1011
1036
  if (resource === "contacts") {
1012
1037
  const contact = await repo.findOne({
1013
- where: { id: Number(id) },
1038
+ where: { id: Number(id), deleted: false },
1014
1039
  relations: ["form_submissions", "form_submissions.form", "orders", "payments", "addresses"]
1015
1040
  });
1016
1041
  if (!contact) return json({ message: "Not found" }, { status: 404 });
@@ -1032,7 +1057,7 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1032
1057
  }
1033
1058
  if (resource === "payments") {
1034
1059
  const payment = await repo.findOne({
1035
- where: { id: Number(id) },
1060
+ where: { id: Number(id), deleted: false },
1036
1061
  relations: ["order", "order.contact", "contact"]
1037
1062
  });
1038
1063
  if (!payment) return json({ message: "Not found" }, { status: 404 });
@@ -1040,12 +1065,13 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1040
1065
  }
1041
1066
  if (resource === "blogs") {
1042
1067
  const blog = await repo.findOne({
1043
- where: { id: Number(id) },
1068
+ where: { id: Number(id), deleted: false },
1044
1069
  relations: ["category", "seo", "tags"]
1045
1070
  });
1046
1071
  return blog ? json(blog) : json({ message: "Not found" }, { status: 404 });
1047
1072
  }
1048
- const item = await repo.findOne({ where: { id: Number(id) } });
1073
+ const idWhere = entityHasSoftDelete(repo) ? { id: Number(id), deleted: false } : { id: Number(id) };
1074
+ const item = await repo.findOne({ where: idWhere });
1049
1075
  return item ? json(item) : json({ message: "Not found" }, { status: 404 });
1050
1076
  },
1051
1077
  async PUT(req, resource, id) {
@@ -1057,7 +1083,9 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1057
1083
  const repo = dataSource.getRepository(entity);
1058
1084
  const numericId = Number(id);
1059
1085
  if (resource === "blogs" && rawBody && typeof rawBody === "object" && entityMap.categories && entityMap.seos && entityMap.tags) {
1060
- const existing = await repo.findOne({ where: { id: numericId } });
1086
+ const existing = await repo.findOne({
1087
+ where: { id: numericId, deleted: false }
1088
+ });
1061
1089
  if (!existing) return json({ message: "Not found" }, { status: 404 });
1062
1090
  const updatePayload2 = pickColumnUpdates(repo, rawBody);
1063
1091
  if ("category" in rawBody) {
@@ -1133,6 +1161,12 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1133
1161
  });
1134
1162
  return updated2 ? json(updated2) : json({ message: "Not found" }, { status: 404 });
1135
1163
  }
1164
+ if (entityHasSoftDelete(repo)) {
1165
+ const cur = await repo.findOne({
1166
+ where: { id: numericId, deleted: false }
1167
+ });
1168
+ if (!cur) return json({ message: "Not found" }, { status: 404 });
1169
+ }
1136
1170
  const updatePayload = rawBody && typeof rawBody === "object" ? pickColumnUpdates(repo, rawBody) : {};
1137
1171
  if (resource === "media") {
1138
1172
  const u = updatePayload;
@@ -1159,7 +1193,24 @@ function createCrudByIdHandler(dataSource, entityMap, options) {
1159
1193
  const entity = entityMap[resource];
1160
1194
  if (!entity) return json({ error: "Invalid resource" }, { status: 400 });
1161
1195
  const repo = dataSource.getRepository(entity);
1162
- const result = await repo.delete(Number(id));
1196
+ const numericId = Number(id);
1197
+ if (entityHasSoftDelete(repo)) {
1198
+ const existing = await repo.findOne({
1199
+ where: { id: numericId, deleted: false }
1200
+ });
1201
+ if (!existing) return json({ message: "Not found" }, { status: 404 });
1202
+ let deletedBy = null;
1203
+ if (getDeletedByUserId) {
1204
+ try {
1205
+ deletedBy = await getDeletedByUserId(req);
1206
+ } catch {
1207
+ deletedBy = null;
1208
+ }
1209
+ }
1210
+ await repo.update(numericId, buildSoftDeletePayload(repo.metadata, deletedBy));
1211
+ return json({ message: "Deleted successfully" }, { status: 200 });
1212
+ }
1213
+ const result = await repo.delete(numericId);
1163
1214
  if (result.affected === 0) return json({ message: "Not found" }, { status: 404 });
1164
1215
  return json({ message: "Deleted successfully" }, { status: 200 });
1165
1216
  }
@@ -2267,7 +2318,7 @@ function createFormSubmissionHandler(config) {
2267
2318
  };
2268
2319
  }
2269
2320
  function createUsersApiHandlers(config) {
2270
- const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails } = config;
2321
+ const { dataSource, entityMap, json, requireAuth, requireEntityPermission, baseUrl, getCms, getCompanyDetails, getSessionUser } = config;
2271
2322
  async function trySendInviteEmail(toEmail, inviteLink, inviteeName) {
2272
2323
  if (!getCms) return;
2273
2324
  try {
@@ -2303,7 +2354,10 @@ function createUsersApiHandlers(config) {
2303
2354
  const sortField = url.searchParams.get("sortField") || "createdAt";
2304
2355
  const sortOrder = url.searchParams.get("sortOrder") === "desc" ? "DESC" : "ASC";
2305
2356
  const search = url.searchParams.get("search");
2306
- const where = search ? [{ name: (0, import_typeorm4.ILike)(`%${search}%`) }, { email: (0, import_typeorm4.ILike)(`%${search}%`) }] : {};
2357
+ const where = search ? [
2358
+ { name: (0, import_typeorm4.ILike)(`%${search}%`), deleted: false },
2359
+ { email: (0, import_typeorm4.ILike)(`%${search}%`), deleted: false }
2360
+ ] : { deleted: false };
2307
2361
  const [data, total] = await userRepo().findAndCount({
2308
2362
  skip,
2309
2363
  take: limit,
@@ -2368,7 +2422,7 @@ function createUsersApiHandlers(config) {
2368
2422
  }
2369
2423
  try {
2370
2424
  const user = await userRepo().findOne({
2371
- where: { id: parseInt(id, 10) },
2425
+ where: { id: parseInt(id, 10), deleted: false },
2372
2426
  relations: ["group"],
2373
2427
  select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
2374
2428
  });
@@ -2386,11 +2440,14 @@ function createUsersApiHandlers(config) {
2386
2440
  if (pe) return pe;
2387
2441
  }
2388
2442
  try {
2443
+ const uid = parseInt(id, 10);
2444
+ const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
2445
+ if (!existing) return json({ error: "Not found" }, { status: 404 });
2389
2446
  const body = await req.json();
2390
2447
  const { password: _p, ...safe } = body;
2391
- await userRepo().update(parseInt(id, 10), safe);
2448
+ await userRepo().update(uid, safe);
2392
2449
  const updated = await userRepo().findOne({
2393
- where: { id: parseInt(id, 10) },
2450
+ where: { id: uid, deleted: false },
2394
2451
  relations: ["group"],
2395
2452
  select: ["id", "name", "email", "blocked", "createdAt", "updatedAt", "groupId"]
2396
2453
  });
@@ -2407,8 +2464,23 @@ function createUsersApiHandlers(config) {
2407
2464
  if (pe) return pe;
2408
2465
  }
2409
2466
  try {
2410
- const r = await userRepo().delete(parseInt(id, 10));
2411
- if (r.affected === 0) return json({ error: "User not found" }, { status: 404 });
2467
+ const uid = parseInt(id, 10);
2468
+ const existing = await userRepo().findOne({ where: { id: uid, deleted: false } });
2469
+ if (!existing) return json({ error: "User not found" }, { status: 404 });
2470
+ let deletedBy = null;
2471
+ if (getSessionUser) {
2472
+ try {
2473
+ const u = await getSessionUser();
2474
+ if (u?.id) {
2475
+ const n = Number(u.id);
2476
+ if (Number.isFinite(n)) deletedBy = n;
2477
+ }
2478
+ } catch {
2479
+ }
2480
+ }
2481
+ const payload = { deleted: true, deletedAt: /* @__PURE__ */ new Date() };
2482
+ if (deletedBy != null) payload.deletedBy = deletedBy;
2483
+ await userRepo().update(uid, payload);
2412
2484
  return json({ message: "User deleted successfully" });
2413
2485
  } catch {
2414
2486
  return json({ error: "Server Error" }, { status: 500 });
@@ -2422,7 +2494,10 @@ function createUsersApiHandlers(config) {
2422
2494
  if (pe) return pe;
2423
2495
  }
2424
2496
  try {
2425
- const user = await userRepo().findOne({ where: { id: parseInt(id, 10) }, select: ["email", "name"] });
2497
+ const user = await userRepo().findOne({
2498
+ where: { id: parseInt(id, 10), deleted: false },
2499
+ select: ["email", "name"]
2500
+ });
2426
2501
  if (!user) return json({ error: "User not found" }, { status: 404 });
2427
2502
  const emailToken = Buffer.from(user.email).toString("base64");
2428
2503
  const inviteLink = `${baseUrl}/admin/invite?token=${emailToken}`;
@@ -3045,9 +3120,10 @@ function createCmsApiHandler(config) {
3045
3120
  userProfile,
3046
3121
  settings: settingsConfig,
3047
3122
  chat: chatConfig,
3048
- requireEntityPermission: reqEntityPerm,
3123
+ requireEntityPermission: userRequireEntityPermission,
3049
3124
  getSessionUser
3050
3125
  } = config;
3126
+ const requireEntityPermissionEffective = userRequireEntityPermission ?? (async (_req, entity, action) => config.json({ error: "Forbidden", reason: "entity_rbac_required", entity, action }, { status: 403 }));
3051
3127
  const analytics = analyticsConfig ?? (getCms ? {
3052
3128
  json: config.json,
3053
3129
  requireAuth: async () => null,
@@ -3085,12 +3161,20 @@ function createCmsApiHandler(config) {
3085
3161
  const crudOpts = {
3086
3162
  requireAuth: config.requireAuth,
3087
3163
  json: config.json,
3088
- requireEntityPermission: reqEntityPerm,
3089
- getCms
3164
+ requireEntityPermission: requireEntityPermissionEffective,
3165
+ getCms,
3166
+ ...getSessionUser ? {
3167
+ getDeletedByUserId: async () => {
3168
+ const u = await getSessionUser();
3169
+ if (!u?.id) return null;
3170
+ const n = Number(u.id);
3171
+ return Number.isFinite(n) ? n : null;
3172
+ }
3173
+ } : {}
3090
3174
  };
3091
3175
  const crud = createCrudHandler(dataSource, entityMap, crudOpts);
3092
3176
  const crudById = createCrudByIdHandler(dataSource, entityMap, crudOpts);
3093
- const mergePerm = (c) => !c ? void 0 : reqEntityPerm ? { ...c, requireEntityPermission: reqEntityPerm } : c;
3177
+ const mergePerm = (c) => !c ? void 0 : { ...c, requireEntityPermission: requireEntityPermissionEffective };
3094
3178
  const adminRoles = getSessionUser && createAdminRolesHandlers({
3095
3179
  dataSource,
3096
3180
  entityMap,
@@ -3106,12 +3190,7 @@ function createCmsApiHandler(config) {
3106
3190
  json: config.json,
3107
3191
  requireAuth: config.requireAuth
3108
3192
  }
3109
- ) ?? {
3110
- dataSource,
3111
- entityMap,
3112
- json: config.json,
3113
- requireAuth: config.requireAuth
3114
- };
3193
+ );
3115
3194
  const ecommerceAnalyticsGet = createEcommerceAnalyticsHandler(ecommerceAnalyticsResolved);
3116
3195
  const analyticsHandlers = analytics ? createAnalyticsHandlers(analytics) : null;
3117
3196
  const uploadMerged = upload ? {
@@ -3130,7 +3209,11 @@ function createCmsApiHandler(config) {
3130
3209
  const usersApiMerged = usersApi && getCms ? {
3131
3210
  ...usersApi,
3132
3211
  getCms: usersApi.getCms ?? getCms,
3133
- getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails
3212
+ getCompanyDetails: usersApi.getCompanyDetails ?? config.getCompanyDetails,
3213
+ ...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
3214
+ } : usersApi ? {
3215
+ ...usersApi,
3216
+ ...getSessionUser ? { getSessionUser: usersApi.getSessionUser ?? getSessionUser } : {}
3134
3217
  } : usersApi;
3135
3218
  const usersHandlers = usersApiMerged ? createUsersApiHandlers(mergePerm(usersApiMerged) ?? usersApiMerged) : null;
3136
3219
  const avatarPost = userAvatar ? createUserAvatarHandler(userAvatar) : null;
@@ -3141,7 +3224,7 @@ function createCmsApiHandler(config) {
3141
3224
  entityMap,
3142
3225
  json: config.json,
3143
3226
  requireAuth: config.requireAuth,
3144
- requireEntityPermission: reqEntityPerm
3227
+ requireEntityPermission: requireEntityPermissionEffective
3145
3228
  });
3146
3229
  const chatHandlers = chatConfig ? createChatHandlers(chatConfig) : null;
3147
3230
  function resolveResource(segment) {
@@ -3150,12 +3233,10 @@ function createCmsApiHandler(config) {
3150
3233
  }
3151
3234
  return {
3152
3235
  async handle(method, path, req) {
3153
- const perm = reqEntityPerm;
3154
3236
  async function analyticsGate() {
3155
3237
  const a = await config.requireAuth(req);
3156
3238
  if (a) return a;
3157
- if (perm) return perm(req, "analytics", "read");
3158
- return null;
3239
+ return requireEntityPermissionEffective(req, "analytics", "read");
3159
3240
  }
3160
3241
  if (path[0] === "admin" && path[1] === "roles") {
3161
3242
  if (!adminRoles) return config.json({ error: "Not found" }, { status: 404 });
@@ -3239,19 +3320,17 @@ function createCmsApiHandler(config) {
3239
3320
  const group = path[1];
3240
3321
  const isPublic = settingsConfig?.publicGetGroups?.includes(group);
3241
3322
  if (method === "GET") {
3242
- if (!isPublic && perm) {
3323
+ if (!isPublic) {
3243
3324
  const a = await config.requireAuth(req);
3244
3325
  if (a) return a;
3245
- const pe = await perm(req, "settings", "read");
3326
+ const pe = await requireEntityPermissionEffective(req, "settings", "read");
3246
3327
  if (pe) return pe;
3247
3328
  }
3248
3329
  return settingsHandlers.GET(req, group);
3249
3330
  }
3250
3331
  if (method === "PUT") {
3251
- if (perm) {
3252
- const pe = await perm(req, "settings", "update");
3253
- if (pe) return pe;
3254
- }
3332
+ const pe = await requireEntityPermissionEffective(req, "settings", "update");
3333
+ if (pe) return pe;
3255
3334
  return settingsHandlers.PUT(req, group);
3256
3335
  }
3257
3336
  }
@@ -3267,10 +3346,8 @@ function createCmsApiHandler(config) {
3267
3346
  if (path[0] === "orders" && path.length === 3 && path[2] === "invoice" && method === "GET" && getCms) {
3268
3347
  const a = await config.requireAuth(req);
3269
3348
  if (a) return a;
3270
- if (perm) {
3271
- const pe = await perm(req, "orders", "read");
3272
- if (pe) return pe;
3273
- }
3349
+ const pe = await requireEntityPermissionEffective(req, "orders", "read");
3350
+ if (pe) return pe;
3274
3351
  const cms = await getCms();
3275
3352
  const { streamOrderInvoicePdf: streamOrderInvoicePdf2 } = await Promise.resolve().then(() => (init_erp_order_invoice(), erp_order_invoice_exports));
3276
3353
  const oid = Number(path[1]);
@@ -3280,10 +3357,8 @@ function createCmsApiHandler(config) {
3280
3357
  if (path[0] === "orders" && path.length === 3 && path[2] === "repost-erp" && getCms) {
3281
3358
  const a = await config.requireAuth(req);
3282
3359
  if (a) return a;
3283
- if (perm) {
3284
- const pe = await perm(req, "orders", method === "GET" ? "read" : "update");
3285
- if (pe) return pe;
3286
- }
3360
+ const pe = await requireEntityPermissionEffective(req, "orders", method === "GET" ? "read" : "update");
3361
+ if (pe) return pe;
3287
3362
  const oid = Number(path[1]);
3288
3363
  if (!Number.isFinite(oid)) return config.json({ error: "Invalid id" }, { status: 400 });
3289
3364
  const cms = await getCms();