@7365admin1/core 3.63.0 → 3.64.1

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.
package/dist/index.mjs CHANGED
@@ -10513,7 +10513,7 @@ import {
10513
10513
  BadRequestError as BadRequestError31,
10514
10514
  NotFoundError as NotFoundError11,
10515
10515
  InternalServerError as InternalServerError15,
10516
- UnauthorizedError as UnauthorizedError3,
10516
+ UnauthorizedError as UnauthorizedError4,
10517
10517
  useAtlas as useAtlas21
10518
10518
  } from "@7365admin1/node-server-utils";
10519
10519
 
@@ -10948,9 +10948,9 @@ var SUBSCRIPTION_AUTO_SUSPEND_ENABLED = process.env.SUBSCRIPTION_AUTO_SUSPEND_EN
10948
10948
  // src/repositories/organization.repo.ts
10949
10949
  import {
10950
10950
  AppError as AppError3,
10951
- BadRequestError as BadRequestError19,
10951
+ BadRequestError as BadRequestError20,
10952
10952
  InternalServerError as InternalServerError9,
10953
- logger as logger9,
10953
+ logger as logger10,
10954
10954
  makeCacheKey as makeCacheKey7,
10955
10955
  NotFoundError as NotFoundError7,
10956
10956
  paginate as paginate7,
@@ -10959,9 +10959,9 @@ import {
10959
10959
  } from "@7365admin1/node-server-utils";
10960
10960
 
10961
10961
  // src/models/organization.model.ts
10962
- import { BadRequestError as BadRequestError18 } from "@7365admin1/node-server-utils";
10963
- import Joi9 from "joi";
10964
- import { ObjectId as ObjectId18 } from "mongodb";
10962
+ import { BadRequestError as BadRequestError19 } from "@7365admin1/node-server-utils";
10963
+ import Joi10 from "joi";
10964
+ import { ObjectId as ObjectId19 } from "mongodb";
10965
10965
 
10966
10966
  // src/utils/org-modules.util.ts
10967
10967
  import Joi8 from "joi";
@@ -10981,6 +10981,285 @@ function normaliseModules(modules) {
10981
10981
  }
10982
10982
  return out;
10983
10983
  }
10984
+ function orgAllowsModule(modules, resource) {
10985
+ if (!Array.isArray(modules) || modules.length === 0)
10986
+ return true;
10987
+ const key = typeof resource === "string" ? resource.trim() : "";
10988
+ if (!key)
10989
+ return true;
10990
+ return modules.includes(key);
10991
+ }
10992
+
10993
+ // src/models/site.model.ts
10994
+ import {
10995
+ BadRequestError as BadRequestError18,
10996
+ logger as logger9
10997
+ } from "@7365admin1/node-server-utils";
10998
+ import Joi9 from "joi";
10999
+
11000
+ // src/utils/site-modules.util.ts
11001
+ import { UnauthorizedError } from "@7365admin1/node-server-utils";
11002
+ var siteModulesSchema = modulesSchema;
11003
+ function narrows(modules) {
11004
+ return Array.isArray(modules) && modules.length > 0;
11005
+ }
11006
+ function effectiveSiteModules(orgModules, siteModules) {
11007
+ const org = narrows(orgModules) ? normaliseModules(orgModules) : [];
11008
+ const site = narrows(siteModules) ? normaliseModules(siteModules) : [];
11009
+ if (!org.length)
11010
+ return site;
11011
+ if (!site.length)
11012
+ return org;
11013
+ const allowed = site.filter((key) => org.includes(key));
11014
+ return allowed.length ? allowed : org;
11015
+ }
11016
+ function rejectedSiteModules(orgModules, requested) {
11017
+ if (!narrows(orgModules))
11018
+ return [];
11019
+ const org = normaliseModules(orgModules);
11020
+ return normaliseModules(requested).filter((key) => !org.includes(key));
11021
+ }
11022
+ function rejectedSiteModulesMessage(rejected) {
11023
+ return `This organisation has not been given ${rejected.join(", ")}, so a site cannot offer it. Ask Seven365 to add it to the organisation first.`;
11024
+ }
11025
+ function permissionsOutsideModules(effective, next, previous) {
11026
+ if (!narrows(effective))
11027
+ return [];
11028
+ if (!Array.isArray(next) || !next.length || next.includes("*"))
11029
+ return [];
11030
+ const held = new Set(Array.isArray(previous) ? previous : []);
11031
+ const allowed = normaliseModules(effective);
11032
+ const refused = [];
11033
+ for (const permission of next) {
11034
+ if (typeof permission !== "string")
11035
+ continue;
11036
+ if (held.has(permission))
11037
+ continue;
11038
+ const resource = permission.split(":")[0]?.trim();
11039
+ if (!resource)
11040
+ continue;
11041
+ if (!orgAllowsModule(allowed, resource))
11042
+ refused.push(permission);
11043
+ }
11044
+ return refused;
11045
+ }
11046
+ function requireWithinModules(effective, next, previous) {
11047
+ const refused = permissionsOutsideModules(effective, next, previous);
11048
+ if (!refused.length)
11049
+ return;
11050
+ throw new UnauthorizedError(
11051
+ "This site has not been given " + refused.join(", ") + ". Ask Seven365 to add the module to the organisation first."
11052
+ );
11053
+ }
11054
+
11055
+ // src/models/site.model.ts
11056
+ import { ObjectId as ObjectId18 } from "mongodb";
11057
+
11058
+ // src/utils/site-timezone.util.ts
11059
+ import moment from "moment-timezone";
11060
+ var DEFAULT_SITE_TIMEZONE = "Asia/Singapore";
11061
+ function isValidTimezone(tz) {
11062
+ return typeof tz === "string" && tz.length > 0 && !!moment.tz.zone(tz);
11063
+ }
11064
+ function resolveSiteTimezone(site) {
11065
+ const tz = site?.timezone;
11066
+ return isValidTimezone(tz) ? tz : DEFAULT_SITE_TIMEZONE;
11067
+ }
11068
+ function siteDayBounds(value, timezone) {
11069
+ if (!value)
11070
+ return null;
11071
+ const tz = isValidTimezone(timezone) ? timezone : DEFAULT_SITE_TIMEZONE;
11072
+ const isDateOnly = typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value);
11073
+ const m = isDateOnly ? moment.tz(value, "YYYY-MM-DD", tz) : typeof value === "string" ? moment.tz(value, moment.ISO_8601, tz) : moment.tz(value, tz);
11074
+ if (!m.isValid())
11075
+ return null;
11076
+ return {
11077
+ start: m.clone().startOf("day").toDate(),
11078
+ end: m.clone().endOf("day").toDate(),
11079
+ date: m.format("YYYY-MM-DD")
11080
+ };
11081
+ }
11082
+
11083
+ // src/models/site.model.ts
11084
+ function siteTimezoneValidator(value, helpers) {
11085
+ return isValidTimezone(value) ? value : helpers.error("any.invalid");
11086
+ }
11087
+ var addressSchema = Joi9.object({
11088
+ line1: Joi9.string().min(3).required(),
11089
+ line2: Joi9.string().allow("", null),
11090
+ city: Joi9.string().min(2).required(),
11091
+ state: Joi9.string().allow("", null),
11092
+ postalCode: Joi9.string().min(3).required(),
11093
+ country: Joi9.string().min(2).required()
11094
+ });
11095
+ var hidQrCodePassSchema = Joi9.object({
11096
+ enabled: Joi9.boolean().required(),
11097
+ onlineMode: Joi9.boolean().optional(),
11098
+ readerId: Joi9.string().hex().length(24).allow("").required(),
11099
+ qrGatePermissions: Joi9.object({
11100
+ resident: Joi9.array().items(Joi9.string().hex().length(24)).unique().default([]),
11101
+ propertyManagement: Joi9.array().items(Joi9.string().hex().length(24)).unique().default([])
11102
+ }).optional(),
11103
+ qrFormat: Joi9.string().valid("0", "1", "2").required(),
11104
+ identificationMethods: Joi9.object({
11105
+ facial: Joi9.boolean().required(),
11106
+ card: Joi9.boolean().required(),
11107
+ qrCode: Joi9.boolean().required(),
11108
+ idPassword: Joi9.boolean().required(),
11109
+ pin: Joi9.boolean().required(),
11110
+ bluetooth: Joi9.boolean().required()
11111
+ }).optional(),
11112
+ printer: Joi9.object({
11113
+ vendorId: Joi9.string().allow("").required(),
11114
+ productId: Joi9.string().allow("").required()
11115
+ }).required(),
11116
+ template: Joi9.object({
11117
+ header: Joi9.string().allow("").required(),
11118
+ subtext: Joi9.string().allow("").required()
11119
+ }).required(),
11120
+ validityMinutes: Joi9.number().integer().min(1).allow(null).required(),
11121
+ updatedAt: Joi9.string().isoDate().required()
11122
+ });
11123
+ var residentAppModulesSchema = Joi9.object({
11124
+ feedback: Joi9.boolean(),
11125
+ bulletin: Joi9.boolean(),
11126
+ bulletinVideos: Joi9.boolean(),
11127
+ inviteVisitors: Joi9.boolean(),
11128
+ myVisitors: Joi9.boolean(),
11129
+ billingAndSoa: Joi9.boolean(),
11130
+ access: Joi9.boolean(),
11131
+ facilityBooking: Joi9.boolean(),
11132
+ onlineForm: Joi9.boolean(),
11133
+ emergencyContact: Joi9.boolean()
11134
+ });
11135
+ var metadataSchema3 = Joi9.object({
11136
+ /**
11137
+ * The catalogue modules THIS SITE offers — tier two of the cascade.
11138
+ *
11139
+ * Owner requirement R1: whatever Seven365 gives an organisation is the only
11140
+ * set that organisation may then give to each site it creates. The
11141
+ * organisation's own list is `organizations.modules`; this narrows it per
11142
+ * site, and `site-modules.util.ts` holds both the read (fails open) and the
11143
+ * write rule (refuses a key the organisation was never given).
11144
+ *
11145
+ * ABSENT AND EMPTY BOTH MEAN "everything the organisation has" — never
11146
+ * "nothing". No site has this field today.
11147
+ *
11148
+ * It lives in `metadata` because `MSite` is a whitelist: a new top-level
11149
+ * field is silently dropped, while `metadata` is passed through wholesale.
11150
+ * `residentAppModules` below is the same pattern for the same reason.
11151
+ */
11152
+ modules: siteModulesSchema.optional(),
11153
+ block: Joi9.number().optional(),
11154
+ guardPosts: Joi9.number().optional(),
11155
+ gracePeriod: Joi9.number().optional(),
11156
+ incidentCounter: Joi9.number().optional(),
11157
+ incidentLogo: Joi9.string().optional().allow("", null),
11158
+ services: Joi9.array().items(Joi9.object().unknown(true)).optional(),
11159
+ residentAppModules: residentAppModulesSchema.optional(),
11160
+ hidQrCodePass: hidQrCodePassSchema.optional()
11161
+ });
11162
+ var residentAppModuleKeys = [
11163
+ "feedback",
11164
+ "bulletin",
11165
+ "bulletinVideos",
11166
+ "inviteVisitors",
11167
+ "myVisitors",
11168
+ "billingAndSoa",
11169
+ "access",
11170
+ "facilityBooking",
11171
+ "onlineForm",
11172
+ "emergencyContact"
11173
+ ];
11174
+ var updateAddressSchema = Joi9.object({
11175
+ line1: Joi9.string().min(3).allow("", null),
11176
+ line2: Joi9.string().allow("", null),
11177
+ city: Joi9.string().min(2).allow("", null),
11178
+ state: Joi9.string().allow("", null),
11179
+ postalCode: Joi9.string().min(3).allow("", null),
11180
+ country: Joi9.string().min(2).allow("", null)
11181
+ });
11182
+ var SiteStatus = /* @__PURE__ */ ((SiteStatus2) => {
11183
+ SiteStatus2["ACTIVE"] = "active";
11184
+ SiteStatus2["PENDING"] = "pending";
11185
+ return SiteStatus2;
11186
+ })(SiteStatus || {});
11187
+ var SiteCategories = /* @__PURE__ */ ((SiteCategories2) => {
11188
+ SiteCategories2["RESIDENTIAL"] = "residential";
11189
+ SiteCategories2["COMMERCIAL"] = "commercial";
11190
+ SiteCategories2["INDUSTRIAL"] = "industrial";
11191
+ SiteCategories2["MIXED_DEVELOPMENT"] = "mixed_development";
11192
+ SiteCategories2["INSTITUTIONAL"] = "institutional";
11193
+ SiteCategories2["INFRASTRUCTURE"] = "infrastructure";
11194
+ SiteCategories2["HOSPITALITY"] = "hospitality";
11195
+ return SiteCategories2;
11196
+ })(SiteCategories || {});
11197
+ var allowedFieldsSite = [
11198
+ "metadata.block",
11199
+ "metadata.guardPosts",
11200
+ "metadata.gracePeriod",
11201
+ "metadata.incidentCounter",
11202
+ "metadata.incidentLogo",
11203
+ "metadata.services",
11204
+ "metadata.hidQrCodePass"
11205
+ ];
11206
+ var siteSchema = Joi9.object({
11207
+ name: Joi9.string().required(),
11208
+ description: Joi9.string().optional().allow("", null),
11209
+ orgId: Joi9.string().hex().required(),
11210
+ customerId: Joi9.string().hex().optional().allow("", null),
11211
+ address: addressSchema.optional(),
11212
+ timezone: Joi9.string().custom(siteTimezoneValidator, "IANA timezone").optional().default(DEFAULT_SITE_TIMEZONE),
11213
+ category: Joi9.string().valid(...Object.values(SiteCategories)).default("commercial" /* COMMERCIAL */),
11214
+ deliveryCompanyList: Joi9.array().items(Joi9.string()).optional().allow(null),
11215
+ isOpenGate: Joi9.boolean().optional().default(false),
11216
+ dahuaTimeExpiration: Joi9.number().optional().allow(null),
11217
+ siteDocs: Joi9.array().items(Joi9.string().hex().length(24).allow(null, "")),
11218
+ unitDocs: Joi9.array().items(Joi9.string().hex().length(24).allow(null, ""))
11219
+ });
11220
+ var updateSiteSchema = Joi9.object({
11221
+ _id: Joi9.string().hex().length(24).required(),
11222
+ address: updateAddressSchema.optional(),
11223
+ timezone: Joi9.string().custom(siteTimezoneValidator, "IANA timezone").optional(),
11224
+ metadata: metadataSchema3.optional(),
11225
+ deliveryCompanyList: Joi9.array().items(Joi9.string().trim()).optional().allow(null),
11226
+ isOpenGate: Joi9.boolean().optional().allow(null),
11227
+ dahuaTimeExpiration: Joi9.number().optional().allow(null),
11228
+ siteDocs: Joi9.array().items(Joi9.string().hex().length(24).allow(null, "")),
11229
+ unitDocs: Joi9.array().items(Joi9.string().hex().length(24).allow(null, ""))
11230
+ });
11231
+ function MSite(value) {
11232
+ const { error } = siteSchema.validate(value);
11233
+ if (error) {
11234
+ logger9.log({ level: "error", message: error.message });
11235
+ throw new BadRequestError18(error.message);
11236
+ }
11237
+ if (value.orgId) {
11238
+ try {
11239
+ value.orgId = new ObjectId18(value.orgId);
11240
+ } catch (error2) {
11241
+ throw new BadRequestError18("Invalid org ID format.");
11242
+ }
11243
+ }
11244
+ return {
11245
+ name: value.name ?? "",
11246
+ description: value.description ?? "",
11247
+ orgId: value.orgId ?? "",
11248
+ metadata: value.metadata ?? {},
11249
+ status: "active",
11250
+ createdAt: /* @__PURE__ */ new Date(),
11251
+ address: value.address,
11252
+ timezone: value.timezone ?? DEFAULT_SITE_TIMEZONE,
11253
+ category: value.category,
11254
+ deliveryCompanyList: value.deliveryCompanyList ?? [],
11255
+ isOpenGate: value.isOpenGate,
11256
+ dahuaTimeExpiration: value.dahuaTimeExpiration,
11257
+ siteDocs: value.siteDocs ?? [],
11258
+ unitDocs: value.unitDocs ?? [],
11259
+ updatedAt: value.updatedAt ?? "",
11260
+ deletedAt: value.deletedAt ?? ""
11261
+ };
11262
+ }
10984
11263
 
10985
11264
  // src/models/organization.model.ts
10986
11265
  var allowedNatures = [
@@ -10993,38 +11272,39 @@ var allowedNatures = [
10993
11272
  "pest_control_services",
10994
11273
  "pool_maintenance_services"
10995
11274
  ];
10996
- var orgSchema = Joi9.object({
10997
- _id: Joi9.string().hex().optional().allow("", null),
10998
- name: Joi9.string().required(),
10999
- description: Joi9.string().optional().allow("", null),
11000
- type: Joi9.string().required(),
11001
- nature: Joi9.string().valid(...allowedNatures).required(),
11275
+ var orgSchema = Joi10.object({
11276
+ _id: Joi10.string().hex().optional().allow("", null),
11277
+ name: Joi10.string().required(),
11278
+ description: Joi10.string().optional().allow("", null),
11279
+ type: Joi10.string().required(),
11280
+ nature: Joi10.string().valid(...allowedNatures).required(),
11002
11281
  modules: modulesSchema.optional(),
11003
- email: Joi9.string().email().required(),
11004
- contact: Joi9.string().optional().allow("", null),
11005
- country: Joi9.string().optional().allow("", null),
11006
- busInst: Joi9.string().optional().allow("", null),
11007
- status: Joi9.string().optional().allow("", null),
11008
- defaultSite: Joi9.string().hex().optional().allow("", null),
11009
- createdBy: Joi9.string().hex().optional().allow("", null),
11010
- invitedFrom: Joi9.string().hex().optional().allow("", null),
11011
- invitedRole: Joi9.string().hex().optional().allow("", null),
11012
- terms: Joi9.string().optional().allow("", null),
11013
- policies: Joi9.string().optional().allow("", null),
11014
- createdAt: Joi9.string().optional().allow("", null),
11015
- updatedAt: Joi9.string().optional().allow("", null),
11016
- deletedAt: Joi9.string().optional().allow("", null)
11282
+ residentAppModules: residentAppModulesSchema.optional(),
11283
+ email: Joi10.string().email().required(),
11284
+ contact: Joi10.string().optional().allow("", null),
11285
+ country: Joi10.string().optional().allow("", null),
11286
+ busInst: Joi10.string().optional().allow("", null),
11287
+ status: Joi10.string().optional().allow("", null),
11288
+ defaultSite: Joi10.string().hex().optional().allow("", null),
11289
+ createdBy: Joi10.string().hex().optional().allow("", null),
11290
+ invitedFrom: Joi10.string().hex().optional().allow("", null),
11291
+ invitedRole: Joi10.string().hex().optional().allow("", null),
11292
+ terms: Joi10.string().optional().allow("", null),
11293
+ policies: Joi10.string().optional().allow("", null),
11294
+ createdAt: Joi10.string().optional().allow("", null),
11295
+ updatedAt: Joi10.string().optional().allow("", null),
11296
+ deletedAt: Joi10.string().optional().allow("", null)
11017
11297
  });
11018
11298
  function MOrg(value) {
11019
11299
  const { error } = orgSchema.validate(value);
11020
11300
  if (error) {
11021
- throw new BadRequestError18(error.message);
11301
+ throw new BadRequestError19(error.message);
11022
11302
  }
11023
11303
  if (value._id) {
11024
11304
  try {
11025
- value._id = new ObjectId18(value._id);
11305
+ value._id = new ObjectId19(value._id);
11026
11306
  } catch (error2) {
11027
- throw new BadRequestError18("Invalid organization ID format.");
11307
+ throw new BadRequestError19("Invalid organization ID format.");
11028
11308
  }
11029
11309
  }
11030
11310
  return {
@@ -11037,15 +11317,20 @@ function MOrg(value) {
11037
11317
  // deliberate empty list to any later reader, and would put the field on all
11038
11318
  // 168 live organisations for no reason.
11039
11319
  ...value.modules === void 0 ? {} : { modules: normaliseModules(value.modules) },
11320
+ // Same rule for the resident app's own tier (R4). Absent stays ABSENT, and
11321
+ // MOrg is a WHITELIST — a new top-level field that is not named here is
11322
+ // silently dropped on the way to Mongo, which is how this one has to be
11323
+ // added at all.
11324
+ ...value.residentAppModules === void 0 ? {} : { residentAppModules: value.residentAppModules },
11040
11325
  email: value.email,
11041
11326
  contact: value.contact,
11042
11327
  country: value.country ?? "",
11043
11328
  busInst: value.busInst,
11044
11329
  status: value.status || "active",
11045
11330
  defaultSite: value.defaultSite,
11046
- createdBy: value.createdBy && ObjectId18.isValid(value.createdBy.toString()) ? new ObjectId18(value.createdBy.toString()) : void 0,
11047
- invitedFrom: value.invitedFrom && ObjectId18.isValid(value.invitedFrom.toString()) ? new ObjectId18(value.invitedFrom.toString()) : null,
11048
- invitedRole: value.invitedRole && ObjectId18.isValid(value.invitedRole.toString()) ? new ObjectId18(value.invitedRole.toString()) : null,
11331
+ createdBy: value.createdBy && ObjectId19.isValid(value.createdBy.toString()) ? new ObjectId19(value.createdBy.toString()) : void 0,
11332
+ invitedFrom: value.invitedFrom && ObjectId19.isValid(value.invitedFrom.toString()) ? new ObjectId19(value.invitedFrom.toString()) : null,
11333
+ invitedRole: value.invitedRole && ObjectId19.isValid(value.invitedRole.toString()) ? new ObjectId19(value.invitedRole.toString()) : null,
11049
11334
  terms: value.terms ?? "",
11050
11335
  policies: value.policies ?? "",
11051
11336
  createdAt: value.createdAt || /* @__PURE__ */ new Date(),
@@ -11055,7 +11340,7 @@ function MOrg(value) {
11055
11340
  }
11056
11341
 
11057
11342
  // src/repositories/organization.repo.ts
11058
- import { ObjectId as ObjectId19 } from "mongodb";
11343
+ import { ObjectId as ObjectId20 } from "mongodb";
11059
11344
  var DUPLICATE_FIELD_LABEL = {
11060
11345
  name: "name",
11061
11346
  email: "email address"
@@ -11114,12 +11399,12 @@ function useOrgRepo() {
11114
11399
  return null;
11115
11400
  try {
11116
11401
  return await collection.findOne({
11117
- createdBy: new ObjectId19(createdBy.toString()),
11402
+ createdBy: new ObjectId20(createdBy.toString()),
11118
11403
  nature,
11119
11404
  status: { $ne: "deleted" }
11120
11405
  });
11121
11406
  } catch (error) {
11122
- logger9.log({
11407
+ logger10.log({
11123
11408
  level: "error",
11124
11409
  message: `Failed to look up an existing ${nature} organisation for ${createdBy}`
11125
11410
  });
@@ -11131,22 +11416,22 @@ function useOrgRepo() {
11131
11416
  value = MOrg(value);
11132
11417
  const res = await collection.insertOne(value, { session });
11133
11418
  delNamespace().then(() => {
11134
- logger9.info(`Cache cleared for namespace: ${namespace_collection2}`);
11419
+ logger10.info(`Cache cleared for namespace: ${namespace_collection2}`);
11135
11420
  }).catch((err) => {
11136
- logger9.error(
11421
+ logger10.error(
11137
11422
  `Failed to clear cache for namespace: ${namespace_collection2}`,
11138
11423
  err
11139
11424
  );
11140
11425
  });
11141
11426
  return res.insertedId;
11142
11427
  } catch (error) {
11143
- logger9.log({ level: "error", message: error.message });
11428
+ logger10.log({ level: "error", message: error.message });
11144
11429
  if (error instanceof AppError3) {
11145
11430
  throw error;
11146
11431
  } else {
11147
11432
  const isDuplicated = error.message.includes("duplicate");
11148
11433
  if (isDuplicated) {
11149
- throw new BadRequestError19("Organization already exist.");
11434
+ throw new BadRequestError20("Organization already exist.");
11150
11435
  }
11151
11436
  throw new InternalServerError9("Failed to create organization.");
11152
11437
  }
@@ -11155,7 +11440,7 @@ function useOrgRepo() {
11155
11440
  async function update(id, value, session) {
11156
11441
  try {
11157
11442
  await collection.updateOne(
11158
- { _id: new ObjectId19(id) },
11443
+ { _id: new ObjectId20(id) },
11159
11444
  {
11160
11445
  $set: {
11161
11446
  ...value,
@@ -11167,7 +11452,7 @@ function useOrgRepo() {
11167
11452
  await delNamespace();
11168
11453
  return id;
11169
11454
  } catch (error) {
11170
- logger9.log({
11455
+ logger10.log({
11171
11456
  level: "error",
11172
11457
  message: `Organization update failed for ${id}: ${error?.name ?? "Error"}${error?.code !== void 0 ? ` code=${error.code}` : ""}${duplicatedField(error) ? ` key=${duplicatedField(error)}` : ""} fields=[${Object.keys(value ?? {}).join(",")}] ${error?.message ?? ""}`
11173
11458
  });
@@ -11175,7 +11460,7 @@ function useOrgRepo() {
11175
11460
  throw error;
11176
11461
  const field = duplicatedField(error);
11177
11462
  if (field) {
11178
- throw new BadRequestError19(
11463
+ throw new BadRequestError20(
11179
11464
  `Another organization already uses this ${DUPLICATE_FIELD_LABEL[field] ?? field}. Please use a different one.`
11180
11465
  );
11181
11466
  }
@@ -11203,12 +11488,12 @@ function useOrgRepo() {
11203
11488
  };
11204
11489
  if (scope) {
11205
11490
  const ids2 = Array.from(
11206
- new Set((scope.orgIds ?? []).filter((id) => ObjectId19.isValid(id)))
11491
+ new Set((scope.orgIds ?? []).filter((id) => ObjectId20.isValid(id)))
11207
11492
  ).sort();
11208
11493
  const email = (scope.email ?? "").trim();
11209
11494
  const reach = [];
11210
11495
  if (ids2.length)
11211
- reach.push({ _id: { $in: ids2.map((id) => new ObjectId19(id)) } });
11496
+ reach.push({ _id: { $in: ids2.map((id) => new ObjectId20(id)) } });
11212
11497
  if (email)
11213
11498
  reach.push({ email });
11214
11499
  if (!reach.length) {
@@ -11228,7 +11513,7 @@ function useOrgRepo() {
11228
11513
  const cacheKey = makeCacheKey7(namespace_collection2, cacheOptions);
11229
11514
  const cachedData = await getCache(cacheKey);
11230
11515
  if (cachedData) {
11231
- logger9.info(`Cache hit for key: ${cacheKey}`);
11516
+ logger10.info(`Cache hit for key: ${cacheKey}`);
11232
11517
  return cachedData;
11233
11518
  }
11234
11519
  const normalizedPage = page > 0 ? page - 1 : 0;
@@ -11253,21 +11538,21 @@ function useOrgRepo() {
11253
11538
  const length = await collection.countDocuments(query2);
11254
11539
  const data = paginate7(items, normalizedPage, limit, length);
11255
11540
  setCache(cacheKey, data, 15 * 60).then(() => {
11256
- logger9.info(`Cache set for key: ${cacheKey}`);
11541
+ logger10.info(`Cache set for key: ${cacheKey}`);
11257
11542
  }).catch((err) => {
11258
- logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
11543
+ logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
11259
11544
  });
11260
11545
  return data;
11261
11546
  } catch (error) {
11262
- logger9.log({ level: "error", message: `${error}` });
11547
+ logger10.log({ level: "error", message: `${error}` });
11263
11548
  throw error;
11264
11549
  }
11265
11550
  }
11266
11551
  async function getNameById(_id) {
11267
11552
  try {
11268
- _id = new ObjectId19(_id);
11553
+ _id = new ObjectId20(_id);
11269
11554
  } catch (error) {
11270
- throw new BadRequestError19("Invalid organization ID format.");
11555
+ throw new BadRequestError20("Invalid organization ID format.");
11271
11556
  }
11272
11557
  const data = await collection.findOne(
11273
11558
  { _id },
@@ -11280,16 +11565,16 @@ function useOrgRepo() {
11280
11565
  }
11281
11566
  async function getById(_id) {
11282
11567
  try {
11283
- _id = new ObjectId19(_id);
11568
+ _id = new ObjectId20(_id);
11284
11569
  } catch (error) {
11285
- throw new BadRequestError19("Invalid organization ID format.");
11570
+ throw new BadRequestError20("Invalid organization ID format.");
11286
11571
  }
11287
11572
  const cacheKey = makeCacheKey7(namespace_collection2, {
11288
11573
  _id: _id.toString()
11289
11574
  });
11290
11575
  const cachedData = await getCache(cacheKey);
11291
11576
  if (cachedData) {
11292
- logger9.info(`Cache hit for key: ${cacheKey}`);
11577
+ logger10.info(`Cache hit for key: ${cacheKey}`);
11293
11578
  return cachedData;
11294
11579
  }
11295
11580
  try {
@@ -11298,9 +11583,9 @@ function useOrgRepo() {
11298
11583
  throw new NotFoundError7("Organization not found.");
11299
11584
  }
11300
11585
  setCache(cacheKey, data, 15 * 60).then(() => {
11301
- logger9.info(`Cache set for key: ${cacheKey}`);
11586
+ logger10.info(`Cache set for key: ${cacheKey}`);
11302
11587
  }).catch((err) => {
11303
- logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
11588
+ logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
11304
11589
  });
11305
11590
  return data;
11306
11591
  } catch (error) {
@@ -11320,13 +11605,13 @@ function useOrgRepo() {
11320
11605
  const cacheKey = makeCacheKey7(namespace_collection2, { name });
11321
11606
  const cachedData = await getCache(cacheKey);
11322
11607
  if (cachedData) {
11323
- logger9.info(`Cache hit for key: ${cacheKey}`);
11608
+ logger10.info(`Cache hit for key: ${cacheKey}`);
11324
11609
  return cachedData;
11325
11610
  }
11326
11611
  setCache(cacheKey, data, 15 * 60).then(() => {
11327
- logger9.info(`Cache set for key: ${cacheKey}`);
11612
+ logger10.info(`Cache set for key: ${cacheKey}`);
11328
11613
  }).catch((err) => {
11329
- logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
11614
+ logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
11330
11615
  });
11331
11616
  return data;
11332
11617
  } catch (error) {
@@ -11341,15 +11626,15 @@ function useOrgRepo() {
11341
11626
  const cacheKey = makeCacheKey7(namespace_collection2, { email });
11342
11627
  const cachedData = await getCache(cacheKey);
11343
11628
  if (cachedData) {
11344
- logger9.info(`Cache hit for key: ${cacheKey}`);
11629
+ logger10.info(`Cache hit for key: ${cacheKey}`);
11345
11630
  return cachedData;
11346
11631
  }
11347
11632
  try {
11348
11633
  const data = await collection.findOne({ email });
11349
11634
  setCache(cacheKey, data, 15 * 60).then(() => {
11350
- logger9.info(`Cache set for key: ${cacheKey}`);
11635
+ logger10.info(`Cache set for key: ${cacheKey}`);
11351
11636
  }).catch((err) => {
11352
- logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
11637
+ logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
11353
11638
  });
11354
11639
  return data;
11355
11640
  } catch (error) {
@@ -11362,7 +11647,7 @@ function useOrgRepo() {
11362
11647
  });
11363
11648
  const cachedData = await getCache(cacheKey);
11364
11649
  if (cachedData) {
11365
- logger9.info(`Cache hit for key: ${cacheKey}`);
11650
+ logger10.info(`Cache hit for key: ${cacheKey}`);
11366
11651
  return cachedData;
11367
11652
  }
11368
11653
  try {
@@ -11370,9 +11655,9 @@ function useOrgRepo() {
11370
11655
  email
11371
11656
  }).toArray();
11372
11657
  setCache(cacheKey, data, 15 * 60).then(() => {
11373
- logger9.info(`Cache set for key: ${cacheKey}`);
11658
+ logger10.info(`Cache set for key: ${cacheKey}`);
11374
11659
  }).catch((err) => {
11375
- logger9.error(`Failed to set cache for key: ${cacheKey}`, err);
11660
+ logger10.error(`Failed to set cache for key: ${cacheKey}`, err);
11376
11661
  });
11377
11662
  return data;
11378
11663
  } catch (error) {
@@ -11386,14 +11671,14 @@ function useOrgRepo() {
11386
11671
  }, session) {
11387
11672
  const allowedFields = ["name", "description", "defaultSite"];
11388
11673
  if (!allowedFields.includes(field)) {
11389
- throw new BadRequestError19(
11674
+ throw new BadRequestError20(
11390
11675
  `Field "${field}" is not allowed to be updated.`
11391
11676
  );
11392
11677
  }
11393
11678
  try {
11394
- _id = new ObjectId19(_id);
11679
+ _id = new ObjectId20(_id);
11395
11680
  } catch (error) {
11396
- throw new BadRequestError19("Invalid organization ID format.");
11681
+ throw new BadRequestError20("Invalid organization ID format.");
11397
11682
  }
11398
11683
  try {
11399
11684
  await collection.updateOne(
@@ -11403,9 +11688,9 @@ function useOrgRepo() {
11403
11688
  { session }
11404
11689
  );
11405
11690
  delNamespace().then(() => {
11406
- logger9.info(`Cache cleared for namespace: ${namespace_collection2}`);
11691
+ logger10.info(`Cache cleared for namespace: ${namespace_collection2}`);
11407
11692
  }).catch((err) => {
11408
- logger9.error(
11693
+ logger10.error(
11409
11694
  `Failed to clear cache for namespace: ${namespace_collection2}`,
11410
11695
  err
11411
11696
  );
@@ -11417,9 +11702,9 @@ function useOrgRepo() {
11417
11702
  }
11418
11703
  async function deleteById(_id) {
11419
11704
  try {
11420
- _id = new ObjectId19(_id);
11705
+ _id = new ObjectId20(_id);
11421
11706
  } catch (error) {
11422
- throw new BadRequestError19("Invalid organization ID format.");
11707
+ throw new BadRequestError20("Invalid organization ID format.");
11423
11708
  }
11424
11709
  try {
11425
11710
  await collection.updateOne(
@@ -11427,9 +11712,9 @@ function useOrgRepo() {
11427
11712
  { $set: { status: "deleted", deletedAt: (/* @__PURE__ */ new Date()).toISOString() } }
11428
11713
  );
11429
11714
  delNamespace().then(() => {
11430
- logger9.info(`Cache cleared for namespace: ${namespace_collection2}`);
11715
+ logger10.info(`Cache cleared for namespace: ${namespace_collection2}`);
11431
11716
  }).catch((err) => {
11432
- logger9.error(
11717
+ logger10.error(
11433
11718
  `Failed to clear cache for namespace: ${namespace_collection2}`,
11434
11719
  err
11435
11720
  );
@@ -11441,9 +11726,9 @@ function useOrgRepo() {
11441
11726
  }
11442
11727
  async function updateStatusById(_id, status) {
11443
11728
  try {
11444
- _id = new ObjectId19(_id);
11729
+ _id = new ObjectId20(_id);
11445
11730
  } catch (error) {
11446
- throw new BadRequestError19("Invalid organization ID format.");
11731
+ throw new BadRequestError20("Invalid organization ID format.");
11447
11732
  }
11448
11733
  try {
11449
11734
  const result = await collection.updateOne(
@@ -11454,9 +11739,9 @@ function useOrgRepo() {
11454
11739
  throw new NotFoundError7("Organization not found.");
11455
11740
  }
11456
11741
  delNamespace().then(() => {
11457
- logger9.info(`Cache cleared for namespace: ${namespace_collection2}`);
11742
+ logger10.info(`Cache cleared for namespace: ${namespace_collection2}`);
11458
11743
  }).catch((err) => {
11459
- logger9.error(
11744
+ logger10.error(
11460
11745
  `Failed to clear cache for namespace: ${namespace_collection2}`,
11461
11746
  err
11462
11747
  );
@@ -11611,7 +11896,7 @@ function useOrgRepo() {
11611
11896
  totalItems
11612
11897
  );
11613
11898
  } catch (error) {
11614
- logger9.log({
11899
+ logger10.log({
11615
11900
  level: "error",
11616
11901
  message: `${error}`
11617
11902
  });
@@ -11624,7 +11909,7 @@ function useOrgRepo() {
11624
11909
  throw new NotFoundError7("Admin role not found.");
11625
11910
  let orgId;
11626
11911
  try {
11627
- orgId = new ObjectId19(role.org);
11912
+ orgId = new ObjectId20(role.org);
11628
11913
  } catch {
11629
11914
  throw new InternalServerError9(
11630
11915
  "Invalid organization reference in admin role."
@@ -11640,9 +11925,9 @@ function useOrgRepo() {
11640
11925
  }
11641
11926
  async function completeOnboardingById(_id, session) {
11642
11927
  try {
11643
- _id = new ObjectId19(_id);
11928
+ _id = new ObjectId20(_id);
11644
11929
  } catch (error) {
11645
- throw new BadRequestError19("Invalid organization ID format.");
11930
+ throw new BadRequestError20("Invalid organization ID format.");
11646
11931
  }
11647
11932
  try {
11648
11933
  const result = await collection.updateOne(
@@ -11694,238 +11979,6 @@ function useOrgRepo() {
11694
11979
 
11695
11980
  // src/repositories/site.repo.ts
11696
11981
  import { ObjectId as ObjectId21 } from "mongodb";
11697
-
11698
- // src/models/site.model.ts
11699
- import {
11700
- BadRequestError as BadRequestError20,
11701
- logger as logger10
11702
- } from "@7365admin1/node-server-utils";
11703
- import Joi10 from "joi";
11704
-
11705
- // src/utils/site-modules.util.ts
11706
- var siteModulesSchema = modulesSchema;
11707
- function narrows(modules) {
11708
- return Array.isArray(modules) && modules.length > 0;
11709
- }
11710
- function rejectedSiteModules(orgModules, requested) {
11711
- if (!narrows(orgModules))
11712
- return [];
11713
- const org = normaliseModules(orgModules);
11714
- return normaliseModules(requested).filter((key) => !org.includes(key));
11715
- }
11716
- function rejectedSiteModulesMessage(rejected) {
11717
- return `This organisation has not been given ${rejected.join(", ")}, so a site cannot offer it. Ask Seven365 to add it to the organisation first.`;
11718
- }
11719
-
11720
- // src/models/site.model.ts
11721
- import { ObjectId as ObjectId20 } from "mongodb";
11722
-
11723
- // src/utils/site-timezone.util.ts
11724
- import moment from "moment-timezone";
11725
- var DEFAULT_SITE_TIMEZONE = "Asia/Singapore";
11726
- function isValidTimezone(tz) {
11727
- return typeof tz === "string" && tz.length > 0 && !!moment.tz.zone(tz);
11728
- }
11729
- function resolveSiteTimezone(site) {
11730
- const tz = site?.timezone;
11731
- return isValidTimezone(tz) ? tz : DEFAULT_SITE_TIMEZONE;
11732
- }
11733
- function siteDayBounds(value, timezone) {
11734
- if (!value)
11735
- return null;
11736
- const tz = isValidTimezone(timezone) ? timezone : DEFAULT_SITE_TIMEZONE;
11737
- const isDateOnly = typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value);
11738
- const m = isDateOnly ? moment.tz(value, "YYYY-MM-DD", tz) : typeof value === "string" ? moment.tz(value, moment.ISO_8601, tz) : moment.tz(value, tz);
11739
- if (!m.isValid())
11740
- return null;
11741
- return {
11742
- start: m.clone().startOf("day").toDate(),
11743
- end: m.clone().endOf("day").toDate(),
11744
- date: m.format("YYYY-MM-DD")
11745
- };
11746
- }
11747
-
11748
- // src/models/site.model.ts
11749
- function siteTimezoneValidator(value, helpers) {
11750
- return isValidTimezone(value) ? value : helpers.error("any.invalid");
11751
- }
11752
- var addressSchema = Joi10.object({
11753
- line1: Joi10.string().min(3).required(),
11754
- line2: Joi10.string().allow("", null),
11755
- city: Joi10.string().min(2).required(),
11756
- state: Joi10.string().allow("", null),
11757
- postalCode: Joi10.string().min(3).required(),
11758
- country: Joi10.string().min(2).required()
11759
- });
11760
- var hidQrCodePassSchema = Joi10.object({
11761
- enabled: Joi10.boolean().required(),
11762
- onlineMode: Joi10.boolean().optional(),
11763
- readerId: Joi10.string().hex().length(24).allow("").required(),
11764
- qrGatePermissions: Joi10.object({
11765
- resident: Joi10.array().items(Joi10.string().hex().length(24)).unique().default([]),
11766
- propertyManagement: Joi10.array().items(Joi10.string().hex().length(24)).unique().default([])
11767
- }).optional(),
11768
- qrFormat: Joi10.string().valid("0", "1", "2").required(),
11769
- identificationMethods: Joi10.object({
11770
- facial: Joi10.boolean().required(),
11771
- card: Joi10.boolean().required(),
11772
- qrCode: Joi10.boolean().required(),
11773
- idPassword: Joi10.boolean().required(),
11774
- pin: Joi10.boolean().required(),
11775
- bluetooth: Joi10.boolean().required()
11776
- }).optional(),
11777
- printer: Joi10.object({
11778
- vendorId: Joi10.string().allow("").required(),
11779
- productId: Joi10.string().allow("").required()
11780
- }).required(),
11781
- template: Joi10.object({
11782
- header: Joi10.string().allow("").required(),
11783
- subtext: Joi10.string().allow("").required()
11784
- }).required(),
11785
- validityMinutes: Joi10.number().integer().min(1).allow(null).required(),
11786
- updatedAt: Joi10.string().isoDate().required()
11787
- });
11788
- var metadataSchema3 = Joi10.object({
11789
- /**
11790
- * The catalogue modules THIS SITE offers — tier two of the cascade.
11791
- *
11792
- * Owner requirement R1: whatever Seven365 gives an organisation is the only
11793
- * set that organisation may then give to each site it creates. The
11794
- * organisation's own list is `organizations.modules`; this narrows it per
11795
- * site, and `site-modules.util.ts` holds both the read (fails open) and the
11796
- * write rule (refuses a key the organisation was never given).
11797
- *
11798
- * ABSENT AND EMPTY BOTH MEAN "everything the organisation has" — never
11799
- * "nothing". No site has this field today.
11800
- *
11801
- * It lives in `metadata` because `MSite` is a whitelist: a new top-level
11802
- * field is silently dropped, while `metadata` is passed through wholesale.
11803
- * `residentAppModules` below is the same pattern for the same reason.
11804
- */
11805
- modules: siteModulesSchema.optional(),
11806
- block: Joi10.number().optional(),
11807
- guardPosts: Joi10.number().optional(),
11808
- gracePeriod: Joi10.number().optional(),
11809
- incidentCounter: Joi10.number().optional(),
11810
- incidentLogo: Joi10.string().optional().allow("", null),
11811
- services: Joi10.array().items(Joi10.object().unknown(true)).optional(),
11812
- residentAppModules: Joi10.object({
11813
- feedback: Joi10.boolean(),
11814
- bulletin: Joi10.boolean(),
11815
- bulletinVideos: Joi10.boolean(),
11816
- inviteVisitors: Joi10.boolean(),
11817
- myVisitors: Joi10.boolean(),
11818
- billingAndSoa: Joi10.boolean(),
11819
- access: Joi10.boolean(),
11820
- facilityBooking: Joi10.boolean(),
11821
- onlineForm: Joi10.boolean(),
11822
- emergencyContact: Joi10.boolean()
11823
- }).optional(),
11824
- hidQrCodePass: hidQrCodePassSchema.optional()
11825
- });
11826
- var residentAppModuleKeys = [
11827
- "feedback",
11828
- "bulletin",
11829
- "bulletinVideos",
11830
- "inviteVisitors",
11831
- "myVisitors",
11832
- "billingAndSoa",
11833
- "access",
11834
- "facilityBooking",
11835
- "onlineForm",
11836
- "emergencyContact"
11837
- ];
11838
- var updateAddressSchema = Joi10.object({
11839
- line1: Joi10.string().min(3).allow("", null),
11840
- line2: Joi10.string().allow("", null),
11841
- city: Joi10.string().min(2).allow("", null),
11842
- state: Joi10.string().allow("", null),
11843
- postalCode: Joi10.string().min(3).allow("", null),
11844
- country: Joi10.string().min(2).allow("", null)
11845
- });
11846
- var SiteStatus = /* @__PURE__ */ ((SiteStatus2) => {
11847
- SiteStatus2["ACTIVE"] = "active";
11848
- SiteStatus2["PENDING"] = "pending";
11849
- return SiteStatus2;
11850
- })(SiteStatus || {});
11851
- var SiteCategories = /* @__PURE__ */ ((SiteCategories2) => {
11852
- SiteCategories2["RESIDENTIAL"] = "residential";
11853
- SiteCategories2["COMMERCIAL"] = "commercial";
11854
- SiteCategories2["INDUSTRIAL"] = "industrial";
11855
- SiteCategories2["MIXED_DEVELOPMENT"] = "mixed_development";
11856
- SiteCategories2["INSTITUTIONAL"] = "institutional";
11857
- SiteCategories2["INFRASTRUCTURE"] = "infrastructure";
11858
- SiteCategories2["HOSPITALITY"] = "hospitality";
11859
- return SiteCategories2;
11860
- })(SiteCategories || {});
11861
- var allowedFieldsSite = [
11862
- "metadata.block",
11863
- "metadata.guardPosts",
11864
- "metadata.gracePeriod",
11865
- "metadata.incidentCounter",
11866
- "metadata.incidentLogo",
11867
- "metadata.services",
11868
- "metadata.hidQrCodePass"
11869
- ];
11870
- var siteSchema = Joi10.object({
11871
- name: Joi10.string().required(),
11872
- description: Joi10.string().optional().allow("", null),
11873
- orgId: Joi10.string().hex().required(),
11874
- customerId: Joi10.string().hex().optional().allow("", null),
11875
- address: addressSchema.optional(),
11876
- timezone: Joi10.string().custom(siteTimezoneValidator, "IANA timezone").optional().default(DEFAULT_SITE_TIMEZONE),
11877
- category: Joi10.string().valid(...Object.values(SiteCategories)).default("commercial" /* COMMERCIAL */),
11878
- deliveryCompanyList: Joi10.array().items(Joi10.string()).optional().allow(null),
11879
- isOpenGate: Joi10.boolean().optional().default(false),
11880
- dahuaTimeExpiration: Joi10.number().optional().allow(null),
11881
- siteDocs: Joi10.array().items(Joi10.string().hex().length(24).allow(null, "")),
11882
- unitDocs: Joi10.array().items(Joi10.string().hex().length(24).allow(null, ""))
11883
- });
11884
- var updateSiteSchema = Joi10.object({
11885
- _id: Joi10.string().hex().length(24).required(),
11886
- address: updateAddressSchema.optional(),
11887
- timezone: Joi10.string().custom(siteTimezoneValidator, "IANA timezone").optional(),
11888
- metadata: metadataSchema3.optional(),
11889
- deliveryCompanyList: Joi10.array().items(Joi10.string().trim()).optional().allow(null),
11890
- isOpenGate: Joi10.boolean().optional().allow(null),
11891
- dahuaTimeExpiration: Joi10.number().optional().allow(null),
11892
- siteDocs: Joi10.array().items(Joi10.string().hex().length(24).allow(null, "")),
11893
- unitDocs: Joi10.array().items(Joi10.string().hex().length(24).allow(null, ""))
11894
- });
11895
- function MSite(value) {
11896
- const { error } = siteSchema.validate(value);
11897
- if (error) {
11898
- logger10.log({ level: "error", message: error.message });
11899
- throw new BadRequestError20(error.message);
11900
- }
11901
- if (value.orgId) {
11902
- try {
11903
- value.orgId = new ObjectId20(value.orgId);
11904
- } catch (error2) {
11905
- throw new BadRequestError20("Invalid org ID format.");
11906
- }
11907
- }
11908
- return {
11909
- name: value.name ?? "",
11910
- description: value.description ?? "",
11911
- orgId: value.orgId ?? "",
11912
- metadata: value.metadata ?? {},
11913
- status: "active",
11914
- createdAt: /* @__PURE__ */ new Date(),
11915
- address: value.address,
11916
- timezone: value.timezone ?? DEFAULT_SITE_TIMEZONE,
11917
- category: value.category,
11918
- deliveryCompanyList: value.deliveryCompanyList ?? [],
11919
- isOpenGate: value.isOpenGate,
11920
- dahuaTimeExpiration: value.dahuaTimeExpiration,
11921
- siteDocs: value.siteDocs ?? [],
11922
- unitDocs: value.unitDocs ?? [],
11923
- updatedAt: value.updatedAt ?? "",
11924
- deletedAt: value.deletedAt ?? ""
11925
- };
11926
- }
11927
-
11928
- // src/repositories/site.repo.ts
11929
11982
  import {
11930
11983
  useAtlas as useAtlas13,
11931
11984
  InternalServerError as InternalServerError10,
@@ -13875,7 +13928,7 @@ async function holdsRole(userId, roleId) {
13875
13928
  // src/services/service-provider-invite.service.ts
13876
13929
  import {
13877
13930
  BadRequestError as BadRequestError30,
13878
- UnauthorizedError as UnauthorizedError2,
13931
+ UnauthorizedError as UnauthorizedError3,
13879
13932
  NotFoundError as NotFoundError10,
13880
13933
  compileHandlebar,
13881
13934
  getDirectory,
@@ -15130,7 +15183,7 @@ var NotificationService = class {
15130
15183
  // src/utils/console-authz.util.ts
15131
15184
  import {
15132
15185
  BadRequestError as BadRequestError29,
15133
- UnauthorizedError,
15186
+ UnauthorizedError as UnauthorizedError2,
15134
15187
  useAtlas as useAtlas20
15135
15188
  } from "@7365admin1/node-server-utils";
15136
15189
  import { ObjectId as ObjectId31 } from "mongodb";
@@ -15307,10 +15360,10 @@ async function requirePlatformStaff(req, grant) {
15307
15360
  const id = callerId(req);
15308
15361
  const role = id ? await resolveStaffRole(id) : null;
15309
15362
  if (!role) {
15310
- throw new UnauthorizedError("Not authorized.");
15363
+ throw new UnauthorizedError2("Not authorized.");
15311
15364
  }
15312
15365
  if (grant && !consoleRoleAllows(role.permissions, grant.resource, grant.action)) {
15313
- throw new UnauthorizedError("Not authorized.");
15366
+ throw new UnauthorizedError2("Not authorized.");
15314
15367
  }
15315
15368
  return id;
15316
15369
  }
@@ -15330,7 +15383,7 @@ async function requireOrgAccess(req, orgId) {
15330
15383
  async function requirePlatformOwner(req, grant) {
15331
15384
  const id = callerId(req);
15332
15385
  if (!id || !await isPlatformOwner(id)) {
15333
- throw new UnauthorizedError("Not authorized.");
15386
+ throw new UnauthorizedError2("Not authorized.");
15334
15387
  }
15335
15388
  if (grant)
15336
15389
  await requirePlatformStaff(req, grant);
@@ -15339,7 +15392,7 @@ async function requirePlatformOwner(req, grant) {
15339
15392
  async function requireOrgReach(req, orgId) {
15340
15393
  const id = callerId(req);
15341
15394
  if (!id)
15342
- throw new UnauthorizedError("Not authorized.");
15395
+ throw new UnauthorizedError2("Not authorized.");
15343
15396
  const org = orgId?.toString() ?? "";
15344
15397
  const actor = await resolveInviteActor(id);
15345
15398
  if (staffMayBypass(actor))
@@ -15350,7 +15403,7 @@ async function requireOrgReach(req, orgId) {
15350
15403
  return id;
15351
15404
  if (org && await hasOrgOwnership(id, org))
15352
15405
  return id;
15353
- throw new UnauthorizedError("Not authorized.");
15406
+ throw new UnauthorizedError2("Not authorized.");
15354
15407
  }
15355
15408
  async function requireRoleInvitable(role, org, apps) {
15356
15409
  const roleId = role?.toString() ?? "";
@@ -15490,13 +15543,13 @@ function useServiceProviderInviteService() {
15490
15543
  const org = inviteOrgId(invite);
15491
15544
  if (org && actor.orgIds.includes(org))
15492
15545
  return;
15493
- throw new UnauthorizedError2(
15546
+ throw new UnauthorizedError3(
15494
15547
  "This invitation belongs to another organisation."
15495
15548
  );
15496
15549
  }
15497
15550
  function assertSuperAdmin(actor) {
15498
15551
  if (!staffMayBypass(actor)) {
15499
- throw new UnauthorizedError2(
15552
+ throw new UnauthorizedError3(
15500
15553
  "Only a Seven365 administrator can approve or reject invitations."
15501
15554
  );
15502
15555
  }
@@ -15509,7 +15562,7 @@ function useServiceProviderInviteService() {
15509
15562
  async function actorFor(userId) {
15510
15563
  const actor = await resolveInviteActor(userId);
15511
15564
  if (!actor.id)
15512
- throw new UnauthorizedError2("Sign in to continue.");
15565
+ throw new UnauthorizedError3("Sign in to continue.");
15513
15566
  return actor;
15514
15567
  }
15515
15568
  async function listApprovals({
@@ -15546,7 +15599,7 @@ function useServiceProviderInviteService() {
15546
15599
  let scope = actor.orgIds;
15547
15600
  if (orgId) {
15548
15601
  if (!staffMayBypass(actor) && !actor.orgIds.includes(orgId)) {
15549
- throw new UnauthorizedError2(
15602
+ throw new UnauthorizedError3(
15550
15603
  "You are not a member of that organisation."
15551
15604
  );
15552
15605
  }
@@ -15705,7 +15758,7 @@ function useServiceProviderInviteService() {
15705
15758
  );
15706
15759
  const invitedUserId = user?._id?.toString();
15707
15760
  if (!invitedUserId || invitedUserId !== userId) {
15708
- throw new UnauthorizedError2("This invitation was sent to someone else.");
15761
+ throw new UnauthorizedError3("This invitation was sent to someone else.");
15709
15762
  }
15710
15763
  }
15711
15764
  async function decline({ id, userId }) {
@@ -16006,10 +16059,10 @@ function useVerificationService() {
16006
16059
  const org = await getOrgById(orgId);
16007
16060
  const actor = await resolveInviteActor(invitedBy);
16008
16061
  if (!actor.id) {
16009
- throw new UnauthorizedError3("Sign in to continue.");
16062
+ throw new UnauthorizedError4("Sign in to continue.");
16010
16063
  }
16011
16064
  if (!staffMayBypass(actor) && !actor.orgIds.includes(orgId)) {
16012
- throw new UnauthorizedError3(
16065
+ throw new UnauthorizedError4(
16013
16066
  "You can only invite service providers to your own organisation's sites."
16014
16067
  );
16015
16068
  }
@@ -19080,7 +19133,7 @@ function useRoleService() {
19080
19133
  }
19081
19134
 
19082
19135
  // src/utils/role-scope.util.ts
19083
- import { UnauthorizedError as UnauthorizedError4 } from "@7365admin1/node-server-utils";
19136
+ import { UnauthorizedError as UnauthorizedError5 } from "@7365admin1/node-server-utils";
19084
19137
  function roleScope(role) {
19085
19138
  if ((role?.type ?? "") === PLATFORM_STAFF_ROLE_TYPE)
19086
19139
  return "platform";
@@ -19114,7 +19167,7 @@ function requireNoPlatformGrant(role, next) {
19114
19167
  const added = platformPermissionsAdded(next, role?.permissions);
19115
19168
  if (added.length === 0)
19116
19169
  return;
19117
- throw new UnauthorizedError4(
19170
+ throw new UnauthorizedError5(
19118
19171
  "These are Seven365 console permissions and cannot be granted on a client role: " + added.join(", ")
19119
19172
  );
19120
19173
  }
@@ -19128,14 +19181,14 @@ function refuseSharedClientTemplate(role, next) {
19128
19181
  return true;
19129
19182
  if (Array.isArray(next) && restorableFromHistory(role, next))
19130
19183
  return true;
19131
- throw new UnauthorizedError4(
19184
+ throw new UnauthorizedError5(
19132
19185
  "This role is shared by every client that was invited with it and cannot be changed here."
19133
19186
  );
19134
19187
  }
19135
19188
  function refuseNewSharedClientTemplate(role) {
19136
19189
  if (roleScope(role) !== "client-template")
19137
19190
  return;
19138
- throw new UnauthorizedError4(
19191
+ throw new UnauthorizedError5(
19139
19192
  "A role with no organisation would be shared by every client and cannot be created. Choose the organisation this role belongs to."
19140
19193
  );
19141
19194
  }
@@ -19270,6 +19323,28 @@ async function healOrgDefaultRoles(deps, org) {
19270
19323
  }
19271
19324
  }
19272
19325
 
19326
+ // src/utils/module-ceiling.util.ts
19327
+ async function moduleCeiling(org, site) {
19328
+ const orgId = org?.toString() ?? "";
19329
+ const siteId = site?.toString() ?? "";
19330
+ if (!orgId && !siteId)
19331
+ return [];
19332
+ try {
19333
+ const { getById: getOrgById } = useOrgRepo();
19334
+ const { getSiteById } = useSiteRepo();
19335
+ const [orgDoc, siteDoc] = await Promise.all([
19336
+ orgId ? getOrgById(orgId).catch(() => null) : null,
19337
+ siteId ? getSiteById(siteId).catch(() => null) : null
19338
+ ]);
19339
+ return effectiveSiteModules(
19340
+ orgDoc?.modules,
19341
+ siteDoc?.metadata?.modules
19342
+ );
19343
+ } catch {
19344
+ return [];
19345
+ }
19346
+ }
19347
+
19273
19348
  // src/controllers/role.controller.ts
19274
19349
  async function requireRoleOrg(req, org) {
19275
19350
  const orgId = org?.toString() ?? "";
@@ -19371,6 +19446,10 @@ function useRoleController() {
19371
19446
  { type: payload.type, org: payload.org, permissions: [] },
19372
19447
  payload.permissions
19373
19448
  );
19449
+ requireWithinModules(
19450
+ await moduleCeiling(payload.org, payload.site),
19451
+ payload.permissions
19452
+ );
19374
19453
  const role = await _createRole(payload);
19375
19454
  res.status(201).json({ message: "Successfully created role.", data: { role } });
19376
19455
  return;
@@ -19488,6 +19567,11 @@ function useRoleController() {
19488
19567
  throw new NotFoundError14("Role not found.");
19489
19568
  const isRestore = await requireRoleWrite(req, existing, permissions);
19490
19569
  requireNoPlatformGrant(existing, permissions);
19570
+ requireWithinModules(
19571
+ await moduleCeiling(existing?.org, existing?.site),
19572
+ permissions,
19573
+ existing?.permissions
19574
+ );
19491
19575
  if (isRestore)
19492
19576
  await recordPriorPermissions(
19493
19577
  _appendPermissionHistory,
@@ -19526,6 +19610,11 @@ function useRoleController() {
19526
19610
  throw new NotFoundError14("Role not found.");
19527
19611
  const isRestore = await requireRoleWrite(req, existing, permissions);
19528
19612
  requireNoPlatformGrant(existing, permissions);
19613
+ requireWithinModules(
19614
+ await moduleCeiling(existing?.org, existing?.site),
19615
+ permissions,
19616
+ existing?.permissions
19617
+ );
19529
19618
  if (isRestore)
19530
19619
  await recordPriorPermissions(
19531
19620
  _appendPermissionHistory,
@@ -19646,12 +19735,12 @@ import { BadRequestError as BadRequestError49, logger as logger34 } from "@7365a
19646
19735
  // src/services/member.service.ts
19647
19736
  import {
19648
19737
  BadRequestError as BadRequestError41,
19649
- UnauthorizedError as UnauthorizedError5,
19738
+ UnauthorizedError as UnauthorizedError6,
19650
19739
  useAtlas as useAtlas28
19651
19740
  } from "@7365admin1/node-server-utils";
19652
19741
  async function requireStaffCaller(callerId5, what) {
19653
19742
  if (!await isSuperAdmin(callerId5)) {
19654
- throw new UnauthorizedError5(
19743
+ throw new UnauthorizedError6(
19655
19744
  `Only Seven365 staff can ${what}.`
19656
19745
  );
19657
19746
  }
@@ -19868,14 +19957,14 @@ function useMemberService() {
19868
19957
  }
19869
19958
 
19870
19959
  // src/utils/site-reach.util.ts
19871
- import { useAtlas as useAtlas35, UnauthorizedError as UnauthorizedError7 } from "@7365admin1/node-server-utils";
19960
+ import { useAtlas as useAtlas35, UnauthorizedError as UnauthorizedError8 } from "@7365admin1/node-server-utils";
19872
19961
  import { ObjectId as ObjectId48 } from "mongodb";
19873
19962
 
19874
19963
  // src/services/camera-view.service.ts
19875
19964
  import {
19876
19965
  BadRequestError as BadRequestError48,
19877
19966
  NotFoundError as NotFoundError16,
19878
- UnauthorizedError as UnauthorizedError6,
19967
+ UnauthorizedError as UnauthorizedError7,
19879
19968
  logger as logger33,
19880
19969
  useAtlas as useAtlas34,
19881
19970
  useCache as useCache19
@@ -26322,7 +26411,7 @@ function useCameraViewService() {
26322
26411
  }
26323
26412
  async function authorizeCamera(params) {
26324
26413
  if (!params.userId || !ObjectId47.isValid(params.userId)) {
26325
- throw new UnauthorizedError6("Not signed in.");
26414
+ throw new UnauthorizedError7("Not signed in.");
26326
26415
  }
26327
26416
  if (!ObjectId47.isValid(params.cameraId)) {
26328
26417
  throw new BadRequestError48("Invalid camera id.");
@@ -26351,7 +26440,7 @@ function useCameraViewService() {
26351
26440
  memberships
26352
26441
  );
26353
26442
  if (!hasAnyPermission(permissions, params.permissions)) {
26354
- throw new UnauthorizedError6(
26443
+ throw new UnauthorizedError7(
26355
26444
  "You do not have permission to use this camera."
26356
26445
  );
26357
26446
  }
@@ -26459,7 +26548,7 @@ function useCameraViewService() {
26459
26548
  }
26460
26549
  async function entitleSite(params) {
26461
26550
  if (!params.userId || !ObjectId47.isValid(params.userId)) {
26462
- throw new UnauthorizedError6("Not signed in.");
26551
+ throw new UnauthorizedError7("Not signed in.");
26463
26552
  }
26464
26553
  if (!ObjectId47.isValid(params.siteId)) {
26465
26554
  throw new BadRequestError48("Invalid site id.");
@@ -26491,7 +26580,7 @@ function useCameraViewService() {
26491
26580
  );
26492
26581
  const required = params.permissions ?? CAMERA_VIEW_PERMISSIONS;
26493
26582
  if (!hasAnyPermission(permissions, required)) {
26494
- throw new UnauthorizedError6(
26583
+ throw new UnauthorizedError7(
26495
26584
  params.message ?? (required === CAMERA_VIEW_PERMISSIONS ? "You do not have permission to view these cameras." : "You do not have permission to set up cameras on this site.")
26496
26585
  );
26497
26586
  }
@@ -26900,7 +26989,7 @@ function idText(value) {
26900
26989
  async function requireSiteReach(req, site, permission) {
26901
26990
  const siteId = site?.toString?.() ?? "";
26902
26991
  if (!siteId)
26903
- throw new UnauthorizedError7("Not authorized.");
26992
+ throw new UnauthorizedError8("Not authorized.");
26904
26993
  const actor = await resolveInviteActor(callerId(req));
26905
26994
  if (staffMayBypass(actor))
26906
26995
  return;
@@ -27886,7 +27975,7 @@ function useVerificationController() {
27886
27975
  // src/controllers/file.controller.ts
27887
27976
  import {
27888
27977
  BadRequestError as BadRequestError51,
27889
- UnauthorizedError as UnauthorizedError8,
27978
+ UnauthorizedError as UnauthorizedError9,
27890
27979
  logger as logger36
27891
27980
  } from "@7365admin1/node-server-utils";
27892
27981
  import Joi28 from "joi";
@@ -27915,7 +28004,7 @@ async function requireFileDelete(req, file) {
27915
28004
  return;
27916
28005
  const caller = callerId(req);
27917
28006
  if (!caller)
27918
- throw new UnauthorizedError8("Not authorized.");
28007
+ throw new UnauthorizedError9("Not authorized.");
27919
28008
  if (caller === ownerId)
27920
28009
  return;
27921
28010
  const [me, owner] = await Promise.all([
@@ -27931,7 +28020,7 @@ async function requireFileDelete(req, file) {
27931
28020
  })) {
27932
28021
  return;
27933
28022
  }
27934
- throw new UnauthorizedError8("Not authorized.");
28023
+ throw new UnauthorizedError9("Not authorized.");
27935
28024
  }
27936
28025
  function useFileController() {
27937
28026
  const { createFile, deleteFile: _deleteFile } = useFileService();
@@ -28004,7 +28093,7 @@ import {
28004
28093
  BadRequestError as BadRequestError55,
28005
28094
  logger as logger39,
28006
28095
  NotFoundError as NotFoundError17,
28007
- UnauthorizedError as UnauthorizedError9
28096
+ UnauthorizedError as UnauthorizedError10
28008
28097
  } from "@7365admin1/node-server-utils";
28009
28098
  import Joi32 from "joi";
28010
28099
 
@@ -29291,7 +29380,7 @@ function useOrgController() {
29291
29380
  try {
29292
29381
  const createdBy = callerId(req);
29293
29382
  if (!createdBy)
29294
- throw new UnauthorizedError9("Not authorized.");
29383
+ throw new UnauthorizedError10("Not authorized.");
29295
29384
  const { inviteId, ...body } = req.body ?? {};
29296
29385
  let invitedFrom = null;
29297
29386
  let invitedRole = null;
@@ -29543,7 +29632,8 @@ function useOrgController() {
29543
29632
  }
29544
29633
  async function updateModules(req, res, next) {
29545
29634
  const validation = Joi32.object({
29546
- modules: modulesSchema.required()
29635
+ modules: modulesSchema.required(),
29636
+ residentAppModules: residentAppModulesSchema.optional()
29547
29637
  });
29548
29638
  const { error } = validation.validate(req.body);
29549
29639
  if (error) {
@@ -29554,7 +29644,14 @@ function useOrgController() {
29554
29644
  try {
29555
29645
  const staffId = await requireConsolePermission(req, "organizations");
29556
29646
  const modules = normaliseModules(req.body.modules);
29557
- await _update(orgId, { modules });
29647
+ const residentAppModules = req.body.residentAppModules;
29648
+ await _update(orgId, {
29649
+ modules,
29650
+ // Absent stays ABSENT. Writing `{}` would put the field on an
29651
+ // organisation nobody has configured, and `{}` is not distinguishable
29652
+ // later from a deliberate "all ten on".
29653
+ ...residentAppModules === void 0 ? {} : { residentAppModules }
29654
+ });
29558
29655
  const data = await _getById(orgId);
29559
29656
  await recordConsoleAction({
29560
29657
  action: "client.modules-changed" /* CLIENT_MODULES_CHANGED */,
@@ -29564,7 +29661,14 @@ function useOrgController() {
29564
29661
  targetType: "organization" /* ORGANIZATION */,
29565
29662
  after: pickAuditFields("client.modules-changed" /* CLIENT_MODULES_CHANGED */, {
29566
29663
  modules: modules.join(", "),
29567
- moduleCount: modules.length
29664
+ moduleCount: modules.length,
29665
+ // Joined for the same reason as `modules`: `auditValue` drops an
29666
+ // object, which would leave a row saying something changed without
29667
+ // saying what to. Only the switches turned OFF are worth recording -
29668
+ // absent means on, so the off list IS the decision.
29669
+ ...residentAppModules === void 0 ? {} : {
29670
+ residentAppModulesOff: Object.keys(residentAppModules).filter((key) => residentAppModules[key] === false).join(", ")
29671
+ }
29568
29672
  })
29569
29673
  });
29570
29674
  res.json({
@@ -31887,7 +31991,7 @@ function useSubscriptionService() {
31887
31991
  import Joi37 from "joi";
31888
31992
  import {
31889
31993
  BadRequestError as BadRequestError71,
31890
- UnauthorizedError as UnauthorizedError10,
31994
+ UnauthorizedError as UnauthorizedError11,
31891
31995
  logger as logger49
31892
31996
  } from "@7365admin1/node-server-utils";
31893
31997
 
@@ -32308,7 +32412,7 @@ function useSubscriptionController() {
32308
32412
  try {
32309
32413
  const subscription = await _getSubscriptionById(subscriptionId);
32310
32414
  if (!subscription) {
32311
- throw new UnauthorizedError10("Not authorized.");
32415
+ throw new UnauthorizedError11("Not authorized.");
32312
32416
  }
32313
32417
  await requireOrgAccess(req, subscription.org?.toString());
32314
32418
  const _res = await _updateSubscriptionSeats({
@@ -37771,6 +37875,32 @@ function useSiteService() {
37771
37875
 
37772
37876
  // src/controllers/site.controller.ts
37773
37877
  import { BadRequestError as BadRequestError92, logger as logger66 } from "@7365admin1/node-server-utils";
37878
+
37879
+ // src/utils/resident-app-modules.util.ts
37880
+ function effectiveResidentAppModules(orgModules, siteModules) {
37881
+ const org = asModules(orgModules);
37882
+ const site = asModules(siteModules);
37883
+ const effective = {};
37884
+ for (const key of residentAppModuleKeys) {
37885
+ effective[key] = org[key] !== false && site[key] !== false;
37886
+ }
37887
+ return effective;
37888
+ }
37889
+ function residentAppModulesAboveCeiling(orgModules, requested) {
37890
+ const org = asModules(orgModules);
37891
+ const wanted = asModules(requested);
37892
+ return residentAppModuleKeys.filter(
37893
+ (key) => org[key] === false && wanted[key] === true
37894
+ );
37895
+ }
37896
+ function residentAppModulesAboveCeilingMessage(rejected) {
37897
+ return `This client has not been given ${rejected.join(", ")} in the resident app, so a site cannot switch it on. Ask Seven365 to add it to the organisation first.`;
37898
+ }
37899
+ function asModules(value) {
37900
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
37901
+ }
37902
+
37903
+ // src/controllers/site.controller.ts
37774
37904
  import Joi51 from "joi";
37775
37905
  async function requireSiteWrite(req, siteId) {
37776
37906
  const actor = await resolveInviteActor(callerId(req));
@@ -37868,6 +37998,25 @@ function useSiteController() {
37868
37998
  return;
37869
37999
  }
37870
38000
  }
38001
+ async function withResidentAppCeiling(site) {
38002
+ if (!site || typeof site !== "object")
38003
+ return site;
38004
+ try {
38005
+ const org = site.orgId ? await _getOrgById(site.orgId.toString()).catch(() => null) : null;
38006
+ return {
38007
+ ...site,
38008
+ metadata: {
38009
+ ...site.metadata ?? {},
38010
+ residentAppModulesEffective: effectiveResidentAppModules(
38011
+ org?.residentAppModules,
38012
+ site.metadata?.residentAppModules
38013
+ )
38014
+ }
38015
+ };
38016
+ } catch {
38017
+ return site;
38018
+ }
38019
+ }
37871
38020
  async function getSiteById(req, res, next) {
37872
38021
  const validation = Joi51.string().hex().required();
37873
38022
  const _id = req.params.id;
@@ -37880,7 +38029,7 @@ function useSiteController() {
37880
38029
  try {
37881
38030
  const site = await _getSiteById(_id);
37882
38031
  await requireSiteRead(req, _id, site);
37883
- res.json(site);
38032
+ res.json(await withResidentAppCeiling(site));
37884
38033
  return;
37885
38034
  } catch (error2) {
37886
38035
  logger66.log({ level: "error", message: error2.message });
@@ -37946,6 +38095,22 @@ function useSiteController() {
37946
38095
  }
37947
38096
  const { _id, ...rest } = value;
37948
38097
  await requireSiteWrite(req, _id);
38098
+ if (rest?.metadata?.residentAppModules) {
38099
+ const existing = await _getSiteById(_id);
38100
+ const org = existing?.orgId ? await _getOrgById(existing.orgId.toString()).catch(
38101
+ () => null
38102
+ ) : null;
38103
+ const above = residentAppModulesAboveCeiling(
38104
+ org?.residentAppModules,
38105
+ rest.metadata.residentAppModules
38106
+ );
38107
+ if (above.length) {
38108
+ next(
38109
+ new BadRequestError92(residentAppModulesAboveCeilingMessage(above))
38110
+ );
38111
+ return;
38112
+ }
38113
+ }
37949
38114
  await _updateById(_id, rest);
37950
38115
  res.json({ message: "Successfully updated site." });
37951
38116
  return;
@@ -42685,7 +42850,7 @@ function useCustomerSiteService() {
42685
42850
  import Joi60 from "joi";
42686
42851
  import {
42687
42852
  BadRequestError as BadRequestError107,
42688
- UnauthorizedError as UnauthorizedError11,
42853
+ UnauthorizedError as UnauthorizedError12,
42689
42854
  logger as logger79
42690
42855
  } from "@7365admin1/node-server-utils";
42691
42856
  async function requireEitherOrg(req, ...orgs) {
@@ -42694,7 +42859,7 @@ async function requireEitherOrg(req, ...orgs) {
42694
42859
  if (staffMayBypass(actor))
42695
42860
  return;
42696
42861
  if (wanted.length === 0 || !wanted.some((org) => actor.orgIds.includes(org))) {
42697
- throw new UnauthorizedError11("Not authorized.");
42862
+ throw new UnauthorizedError12("Not authorized.");
42698
42863
  }
42699
42864
  }
42700
42865
  function useCustomerSiteController() {
@@ -45906,7 +46071,7 @@ import {
45906
46071
  BadRequestError as BadRequestError121,
45907
46072
  InternalServerError as InternalServerError43,
45908
46073
  NotFoundError as NotFoundError34,
45909
- UnauthorizedError as UnauthorizedError12,
46074
+ UnauthorizedError as UnauthorizedError13,
45910
46075
  logger as logger91
45911
46076
  } from "@7365admin1/node-server-utils";
45912
46077
 
@@ -49440,8 +49605,8 @@ function useHidAmicoService() {
49440
49605
  await siteAccess.authorizeSite({ siteId, userId: value.userId, permissions });
49441
49606
  }
49442
49607
  } catch (error) {
49443
- if (error instanceof UnauthorizedError12) {
49444
- throw new UnauthorizedError12("You do not have permission to manage HID access at this site.");
49608
+ if (error instanceof UnauthorizedError13) {
49609
+ throw new UnauthorizedError13("You do not have permission to manage HID access at this site.");
49445
49610
  }
49446
49611
  throw error;
49447
49612
  }
@@ -49465,7 +49630,7 @@ function useHidAmicoService() {
49465
49630
  try {
49466
49631
  await authorizeSiteForCaller(String(reader.site || ""), userId);
49467
49632
  } catch (error) {
49468
- if (error instanceof UnauthorizedError12)
49633
+ if (error instanceof UnauthorizedError13)
49469
49634
  throw error;
49470
49635
  throw new NotFoundError34(HID_READER_NOT_FOUND);
49471
49636
  }
@@ -49517,10 +49682,10 @@ function useHidAmicoService() {
49517
49682
  async function assertUserReaderPermission(reader, userId, options = {}) {
49518
49683
  const permission = await getReaderPermissionForUser(reader, userId);
49519
49684
  if (!permission.granted) {
49520
- throw new UnauthorizedError12("You do not have HID access permission for this reader.");
49685
+ throw new UnauthorizedError13("You do not have HID access permission for this reader.");
49521
49686
  }
49522
49687
  if (options.intercom && !permission.intercom) {
49523
- throw new UnauthorizedError12("You do not have HID intercom permission for this reader.");
49688
+ throw new UnauthorizedError13("You do not have HID intercom permission for this reader.");
49524
49689
  }
49525
49690
  return permission;
49526
49691
  }
@@ -50858,10 +51023,10 @@ function useHidAmicoService() {
50858
51023
  const hasActiveMembership = memberships.some((membership) => membership.status !== "deleted" && membership.status !== "inactive");
50859
51024
  const resolvedIssuer = issuer || (hasResidentMembership ? "resident" : "property_management");
50860
51025
  if (resolvedIssuer === "resident" && !hasResidentMembership) {
50861
- throw new UnauthorizedError12("Only a Resident account can issue a Resident visitor QR code.");
51026
+ throw new UnauthorizedError13("Only a Resident account can issue a Resident visitor QR code.");
50862
51027
  }
50863
51028
  if (resolvedIssuer === "property_management" && !hasActiveMembership) {
50864
- throw new UnauthorizedError12("Only a site Property Management account can issue this visitor QR code.");
51029
+ throw new UnauthorizedError13("Only a site Property Management account can issue this visitor QR code.");
50865
51030
  }
50866
51031
  const configuredGateIds = site?.metadata?.hidQrCodePass?.qrGatePermissions?.[resolvedIssuer === "resident" ? "resident" : "propertyManagement"] || [];
50867
51032
  const gateReaderIds = configuredGateIds.filter((readerId) => typeof readerId === "string" && /^[a-f0-9]{24}$/i.test(readerId)).map(String);
@@ -53454,7 +53619,7 @@ function useVisitorTransactionService() {
53454
53619
  import Joi69 from "joi";
53455
53620
  import moment5 from "moment-timezone";
53456
53621
  import { ObjectId as ObjectId91 } from "mongodb";
53457
- import { BadRequestError as BadRequestError124, NotFoundError as NotFoundError36, InternalServerError as InternalServerError45, UnauthorizedError as UnauthorizedError13, logger as logger95 } from "@7365admin1/node-server-utils";
53622
+ import { BadRequestError as BadRequestError124, NotFoundError as NotFoundError36, InternalServerError as InternalServerError45, UnauthorizedError as UnauthorizedError14, logger as logger95 } from "@7365admin1/node-server-utils";
53458
53623
 
53459
53624
  // src/models/visitor-invite.model.ts
53460
53625
  import Joi67 from "joi";
@@ -58238,7 +58403,7 @@ function useVisitorTransactionController() {
58238
58403
  }
58239
58404
  const inviterUserId = callerId(req);
58240
58405
  if (!inviterUserId) {
58241
- next(new UnauthorizedError13("Not authorized."));
58406
+ next(new UnauthorizedError14("Not authorized."));
58242
58407
  return;
58243
58408
  }
58244
58409
  try {
@@ -58802,7 +58967,7 @@ function useGuestManagementController() {
58802
58967
  // src/controllers/person.controller.ts
58803
58968
  import Joi72 from "joi";
58804
58969
  import { BadRequestError as BadRequestError127, logger as logger98 } from "@7365admin1/node-server-utils";
58805
- import { NotFoundError as NotFoundError37, UnauthorizedError as UnauthorizedError14 } from "@7365admin1/node-server-utils";
58970
+ import { NotFoundError as NotFoundError37, UnauthorizedError as UnauthorizedError15 } from "@7365admin1/node-server-utils";
58806
58971
 
58807
58972
  // src/utils/self-signup-files.util.ts
58808
58973
  function dropUnsentFiles(body) {
@@ -58854,7 +59019,7 @@ function usePersonController() {
58854
59019
  }
58855
59020
  const org = person.org?.toString() ?? "";
58856
59021
  if (!org || !actor.orgIds.includes(org)) {
58857
- throw new UnauthorizedError14("Not authorized.");
59022
+ throw new UnauthorizedError15("Not authorized.");
58858
59023
  }
58859
59024
  return actor;
58860
59025
  }
@@ -58985,7 +59150,7 @@ function usePersonController() {
58985
59150
  });
58986
59151
  } else if (org) {
58987
59152
  if (!actor.orgIds.includes(org)) {
58988
- throw new UnauthorizedError14("Not authorized.");
59153
+ throw new UnauthorizedError15("Not authorized.");
58989
59154
  }
58990
59155
  } else {
58991
59156
  orgs = actor.orgIds;
@@ -63305,7 +63470,7 @@ function useSiteFacilityService() {
63305
63470
  import {
63306
63471
  BadRequestError as BadRequestError149,
63307
63472
  NotFoundError as NotFoundError43,
63308
- UnauthorizedError as UnauthorizedError15,
63473
+ UnauthorizedError as UnauthorizedError16,
63309
63474
  logger as logger117
63310
63475
  } from "@7365admin1/node-server-utils";
63311
63476
  import Joi84 from "joi";
@@ -63392,7 +63557,7 @@ function useSiteFacilityController() {
63392
63557
  } else {
63393
63558
  const { actor } = await siteReachOf(req);
63394
63559
  if (!actor.isSuperAdmin)
63395
- throw new UnauthorizedError15("Not authorized.");
63560
+ throw new UnauthorizedError16("Not authorized.");
63396
63561
  }
63397
63562
  const data = await _getAll({
63398
63563
  search,
@@ -66427,7 +66592,7 @@ function useBulletinBoardService() {
66427
66592
  import {
66428
66593
  BadRequestError as BadRequestError158,
66429
66594
  NotFoundError as NotFoundError51,
66430
- UnauthorizedError as UnauthorizedError16,
66595
+ UnauthorizedError as UnauthorizedError17,
66431
66596
  logger as logger126
66432
66597
  } from "@7365admin1/node-server-utils";
66433
66598
  import Joi92 from "joi";
@@ -66463,7 +66628,7 @@ function useBulletinBoardController() {
66463
66628
  } else {
66464
66629
  const { canReach } = await siteReachOf(req);
66465
66630
  if (!await canReach(scopeOf(value))) {
66466
- throw new UnauthorizedError16("Not authorized.");
66631
+ throw new UnauthorizedError17("Not authorized.");
66467
66632
  }
66468
66633
  }
66469
66634
  const data = await _add(value);
@@ -67020,7 +67185,7 @@ import { BadRequestError as BadRequestError164, logger as logger132 } from "@736
67020
67185
  import {
67021
67186
  BadRequestError as BadRequestError163,
67022
67187
  logger as logger131,
67023
- UnauthorizedError as UnauthorizedError17,
67188
+ UnauthorizedError as UnauthorizedError18,
67024
67189
  useAtlas as useAtlas90
67025
67190
  } from "@7365admin1/node-server-utils";
67026
67191
 
@@ -67404,7 +67569,7 @@ function useSiteBillingItemService() {
67404
67569
  function assertUnitAtSite(buildingUnit, site) {
67405
67570
  const siteId = site?.toString?.() ?? "";
67406
67571
  if (!siteId || (buildingUnit?.site?.toString() ?? "") !== siteId) {
67407
- throw new UnauthorizedError17("Not authorized.");
67572
+ throw new UnauthorizedError18("Not authorized.");
67408
67573
  }
67409
67574
  }
67410
67575
  async function add(value) {
@@ -67575,7 +67740,7 @@ function useSiteBillingItemService() {
67575
67740
  message: error.message
67576
67741
  });
67577
67742
  await session.abortTransaction();
67578
- if (error instanceof BadRequestError163 || error instanceof UnauthorizedError17) {
67743
+ if (error instanceof BadRequestError163 || error instanceof UnauthorizedError18) {
67579
67744
  throw error;
67580
67745
  }
67581
67746
  throw new BadRequestError163("Failed to update Site Billing Item.");
@@ -69544,7 +69709,7 @@ import Joi100 from "joi";
69544
69709
 
69545
69710
  // src/utils/resident-unit.util.ts
69546
69711
  import { ObjectId as ObjectId125 } from "mongodb";
69547
- import { UnauthorizedError as UnauthorizedError18, useAtlas as useAtlas96 } from "@7365admin1/node-server-utils";
69712
+ import { UnauthorizedError as UnauthorizedError19, useAtlas as useAtlas96 } from "@7365admin1/node-server-utils";
69548
69713
  async function requireOwnUnit(req, site, unitId) {
69549
69714
  const actor = await resolveInviteActor(callerId(req));
69550
69715
  if (staffMayBypass(actor))
@@ -69552,7 +69717,7 @@ async function requireOwnUnit(req, site, unitId) {
69552
69717
  const unit = unitId?.toString?.() ?? "";
69553
69718
  const siteId = site?.toString?.() ?? "";
69554
69719
  if (!ObjectId125.isValid(unit) || !ObjectId125.isValid(siteId) || !actor.id) {
69555
- throw new UnauthorizedError18("Not authorized.");
69720
+ throw new UnauthorizedError19("Not authorized.");
69556
69721
  }
69557
69722
  const db2 = useAtlas96.getDb();
69558
69723
  if (!db2)
@@ -69564,7 +69729,7 @@ async function requireOwnUnit(req, site, unitId) {
69564
69729
  status: { $ne: "deleted" }
69565
69730
  });
69566
69731
  if (!own)
69567
- throw new UnauthorizedError18("Not authorized.");
69732
+ throw new UnauthorizedError19("Not authorized.");
69568
69733
  }
69569
69734
 
69570
69735
  // src/controllers/site-unit-billing.controller.ts
@@ -78116,7 +78281,7 @@ function useOnlineFormRepo() {
78116
78281
  import {
78117
78282
  BadRequestError as BadRequestError204,
78118
78283
  NotFoundError as NotFoundError71,
78119
- UnauthorizedError as UnauthorizedError19,
78284
+ UnauthorizedError as UnauthorizedError20,
78120
78285
  logger as logger170
78121
78286
  } from "@7365admin1/node-server-utils";
78122
78287
  import Joi123 from "joi";
@@ -78188,10 +78353,10 @@ function useOnlineFormController() {
78188
78353
  if (site) {
78189
78354
  await requireSiteReach(req, site);
78190
78355
  } else if (!staffMayBypass(actor)) {
78191
- throw new UnauthorizedError19("Not authorized.");
78356
+ throw new UnauthorizedError20("Not authorized.");
78192
78357
  }
78193
78358
  if (org && !staffMayBypass(actor) && !actor.orgIds.includes(org)) {
78194
- throw new UnauthorizedError19("Not authorized.");
78359
+ throw new UnauthorizedError20("Not authorized.");
78195
78360
  }
78196
78361
  const data = await _getAll({ search, page, limit, status, org, site });
78197
78362
  res.json(data);
@@ -78256,7 +78421,7 @@ function useOnlineFormController() {
78256
78421
  if (payload.org) {
78257
78422
  const { actor } = await siteReachOf(req);
78258
78423
  if (!staffMayBypass(actor) && !actor.orgIds.includes(payload.org)) {
78259
- throw new UnauthorizedError19("Not authorized.");
78424
+ throw new UnauthorizedError20("Not authorized.");
78260
78425
  }
78261
78426
  }
78262
78427
  await _updateOnlineFormById(_id, payload);
@@ -85502,7 +85667,7 @@ import {
85502
85667
  BadRequestError as BadRequestError231,
85503
85668
  NotFoundError as NotFoundError80,
85504
85669
  InternalServerError as InternalServerError84,
85505
- UnauthorizedError as UnauthorizedError20,
85670
+ UnauthorizedError as UnauthorizedError21,
85506
85671
  useAtlas as useAtlas135,
85507
85672
  hashPassword as hashPassword4
85508
85673
  } from "@7365admin1/node-server-utils";
@@ -86425,10 +86590,10 @@ function useVerificationServiceV2() {
86425
86590
  const org = await getOrgById(orgId);
86426
86591
  const actor = await resolveInviteActor(invitedBy);
86427
86592
  if (!actor.id) {
86428
- throw new UnauthorizedError20("Sign in to continue.");
86593
+ throw new UnauthorizedError21("Sign in to continue.");
86429
86594
  }
86430
86595
  if (!staffMayBypass(actor) && !actor.orgIds.includes(orgId)) {
86431
- throw new UnauthorizedError20(
86596
+ throw new UnauthorizedError21(
86432
86597
  "You can only invite service providers to your own organisation's sites."
86433
86598
  );
86434
86599
  }
@@ -86741,7 +86906,7 @@ function useVerificationServiceV2() {
86741
86906
  const user = await _getUserById(userId).catch(() => null);
86742
86907
  const email = user?.email;
86743
86908
  if (!email) {
86744
- throw new UnauthorizedError20("Not authorized.");
86909
+ throw new UnauthorizedError21("Not authorized.");
86745
86910
  }
86746
86911
  return email;
86747
86912
  }
@@ -86779,7 +86944,7 @@ function useVerificationServiceV2() {
86779
86944
  throw new NotFoundError80("Invitation not found.");
86780
86945
  }
86781
86946
  if (invite.email.toLowerCase() !== email.toLowerCase()) {
86782
- throw new UnauthorizedError20("Not authorized.");
86947
+ throw new UnauthorizedError21("Not authorized.");
86783
86948
  }
86784
86949
  await _setOnboardingById({
86785
86950
  _id: inviteId,
@@ -88366,6 +88531,14 @@ function useRoleControllerV2() {
88366
88531
  if (value.org) {
88367
88532
  await requireOrgReach(req, value.org);
88368
88533
  }
88534
+ requireNoPlatformGrant(
88535
+ { type: value.type, org: value.org, permissions: [] },
88536
+ value.permissions
88537
+ );
88538
+ requireWithinModules(
88539
+ await moduleCeiling(value.org, value.site),
88540
+ value.permissions
88541
+ );
88369
88542
  const role = await _createRole(value);
88370
88543
  res.status(201).json({ message: "Successfully created role.", data: { role } });
88371
88544
  return;
@@ -90677,7 +90850,7 @@ import Joi159 from "joi";
90677
90850
  import { ObjectId as ObjectId180 } from "mongodb";
90678
90851
  import {
90679
90852
  InternalServerError as InternalServerError94,
90680
- UnauthorizedError as UnauthorizedError21,
90853
+ UnauthorizedError as UnauthorizedError22,
90681
90854
  useAtlas as useAtlas147
90682
90855
  } from "@7365admin1/node-server-utils";
90683
90856
  function db() {
@@ -90693,7 +90866,7 @@ function asObjectId(value) {
90693
90866
  function requireCaller(req) {
90694
90867
  const id = callerId(req);
90695
90868
  if (!id || !ObjectId180.isValid(id)) {
90696
- throw new UnauthorizedError21("Not authorized.");
90869
+ throw new UnauthorizedError22("Not authorized.");
90697
90870
  }
90698
90871
  return id;
90699
90872
  }
@@ -90701,7 +90874,7 @@ function requireSelfId(req, claimed) {
90701
90874
  const caller = requireCaller(req);
90702
90875
  const asked = claimed?.toString?.() ?? "";
90703
90876
  if (!asked || asked !== caller) {
90704
- throw new UnauthorizedError21("Not authorized.");
90877
+ throw new UnauthorizedError22("Not authorized.");
90705
90878
  }
90706
90879
  return caller;
90707
90880
  }
@@ -90709,11 +90882,11 @@ async function requireOwnChannel(req, channelId) {
90709
90882
  const caller = requireCaller(req);
90710
90883
  const _id = asObjectId(channelId);
90711
90884
  if (!_id)
90712
- throw new UnauthorizedError21("Not authorized.");
90885
+ throw new UnauthorizedError22("Not authorized.");
90713
90886
  const channel = await db().collection("channel-preloved").findOne({ _id }, { projection: { senderId: 1, receiverId: 1, postId: 1 } });
90714
90887
  const participants = [channel?.senderId, channel?.receiverId].map((id) => id?.toString?.() ?? "").filter(Boolean);
90715
90888
  if (!channel || !participants.includes(caller)) {
90716
- throw new UnauthorizedError21("Not authorized.");
90889
+ throw new UnauthorizedError22("Not authorized.");
90717
90890
  }
90718
90891
  return { caller, channel };
90719
90892
  }
@@ -90721,10 +90894,10 @@ async function requireOwnChatMessage(req, chatId) {
90721
90894
  const caller = requireCaller(req);
90722
90895
  const _id = asObjectId(chatId);
90723
90896
  if (!_id)
90724
- throw new UnauthorizedError21("Not authorized.");
90897
+ throw new UnauthorizedError22("Not authorized.");
90725
90898
  const message = await db().collection("chat-preloved").findOne({ _id }, { projection: { senderId: 1 } });
90726
90899
  if (!message || message.senderId?.toString?.() !== caller) {
90727
- throw new UnauthorizedError21("Not authorized.");
90900
+ throw new UnauthorizedError22("Not authorized.");
90728
90901
  }
90729
90902
  return caller;
90730
90903
  }
@@ -91150,7 +91323,7 @@ function useBidPrelovedService() {
91150
91323
  // src/controllers/bid-preloved.controller.ts
91151
91324
  import {
91152
91325
  BadRequestError as BadRequestError252,
91153
- UnauthorizedError as UnauthorizedError22,
91326
+ UnauthorizedError as UnauthorizedError23,
91154
91327
  logger as logger213
91155
91328
  } from "@7365admin1/node-server-utils";
91156
91329
  import Joi162 from "joi";
@@ -91202,7 +91375,7 @@ function useBidPrelovedController() {
91202
91375
  const bid = await _getById(params.id);
91203
91376
  const seller = await sellerOfPost(bid?.postId);
91204
91377
  if (!seller || seller !== caller) {
91205
- throw new UnauthorizedError22("Not authorized.");
91378
+ throw new UnauthorizedError23("Not authorized.");
91206
91379
  }
91207
91380
  const data = await _updateStatus(params.id, body.status);
91208
91381
  res.status(200).json(data);
@@ -91226,7 +91399,7 @@ function useBidPrelovedController() {
91226
91399
  const data = await _getById(params.id);
91227
91400
  const seller = await sellerOfPost(data?.postId);
91228
91401
  if (data?.buyerId?.toString?.() !== caller && seller !== caller) {
91229
- throw new UnauthorizedError22("Not authorized.");
91402
+ throw new UnauthorizedError23("Not authorized.");
91230
91403
  }
91231
91404
  res.status(200).json(data);
91232
91405
  } catch (error2) {
@@ -91624,7 +91797,7 @@ function useFormEntryRepo() {
91624
91797
  import {
91625
91798
  BadRequestError as BadRequestError254,
91626
91799
  NotFoundError as NotFoundError89,
91627
- UnauthorizedError as UnauthorizedError23,
91800
+ UnauthorizedError as UnauthorizedError24,
91628
91801
  logger as logger215
91629
91802
  } from "@7365admin1/node-server-utils";
91630
91803
  import Joi164 from "joi";
@@ -91734,7 +91907,7 @@ function useFormEntryController() {
91734
91907
  } else {
91735
91908
  const { actor } = await siteReachOf(req);
91736
91909
  if (!actor.isSuperAdmin)
91737
- throw new UnauthorizedError23("Not authorized.");
91910
+ throw new UnauthorizedError24("Not authorized.");
91738
91911
  }
91739
91912
  const data = await _getAll({ search, page, limit, status, org, site });
91740
91913
  res.json(data);
@@ -91785,7 +91958,7 @@ function useFormEntryController() {
91785
91958
  await requireSiteReach(req, rest.site);
91786
91959
  delete rest.userId;
91787
91960
  if (isOwner && rest.status && rest.status !== "pending") {
91788
- throw new UnauthorizedError23("Not authorized.");
91961
+ throw new UnauthorizedError24("Not authorized.");
91789
91962
  }
91790
91963
  await _updateFormEntryById(_id, rest);
91791
91964
  res.json({ message: "Successfully updated online form." });
@@ -91842,7 +92015,7 @@ function useFormEntryController() {
91842
92015
  async function residentFormSubmission(req, res, next) {
91843
92016
  const userId = callerId(req);
91844
92017
  if (!userId) {
91845
- next(new UnauthorizedError23("Not authorized."));
92018
+ next(new UnauthorizedError24("Not authorized."));
91846
92019
  return;
91847
92020
  }
91848
92021
  const payload = { ...req.body, userId };
@@ -93073,7 +93246,7 @@ function useHidAmicoController() {
93073
93246
  import {
93074
93247
  BadRequestError as BadRequestError257,
93075
93248
  logger as logger217,
93076
- UnauthorizedError as UnauthorizedError24
93249
+ UnauthorizedError as UnauthorizedError25
93077
93250
  } from "@7365admin1/node-server-utils";
93078
93251
  import Joi166 from "joi";
93079
93252
  function usePlatformTermsController() {
@@ -93089,7 +93262,7 @@ function usePlatformTermsController() {
93089
93262
  async function requireOwnRecord(req, user, { staffMayRead = false } = {}) {
93090
93263
  const id = callerId(req);
93091
93264
  if (!id) {
93092
- throw new UnauthorizedError24("Not authorized.");
93265
+ throw new UnauthorizedError25("Not authorized.");
93093
93266
  }
93094
93267
  if (id === user) {
93095
93268
  return id;
@@ -93097,7 +93270,7 @@ function usePlatformTermsController() {
93097
93270
  if (staffMayRead) {
93098
93271
  return await requireConsolePermission(req, "platform-terms", "see-platform-terms");
93099
93272
  }
93100
- throw new UnauthorizedError24("Not authorized.");
93273
+ throw new UnauthorizedError25("Not authorized.");
93101
93274
  }
93102
93275
  async function getLatest(_req, res, next) {
93103
93276
  try {
@@ -93306,7 +93479,7 @@ function useConsoleAuditController() {
93306
93479
  // src/controllers/notification.controller.ts
93307
93480
  import {
93308
93481
  BadRequestError as BadRequestError259,
93309
- UnauthorizedError as UnauthorizedError25,
93482
+ UnauthorizedError as UnauthorizedError26,
93310
93483
  logger as logger219
93311
93484
  } from "@7365admin1/node-server-utils";
93312
93485
  function useNotificationController() {
@@ -93324,10 +93497,10 @@ function useNotificationController() {
93324
93497
  function inboxOwner(req, claimed) {
93325
93498
  const caller = callerId5(req);
93326
93499
  if (!caller) {
93327
- throw new UnauthorizedError25("Not authorized.");
93500
+ throw new UnauthorizedError26("Not authorized.");
93328
93501
  }
93329
93502
  if (claimed && claimed !== caller) {
93330
- throw new UnauthorizedError25("Not authorized.");
93503
+ throw new UnauthorizedError26("Not authorized.");
93331
93504
  }
93332
93505
  return caller;
93333
93506
  }
@@ -93339,7 +93512,7 @@ function useNotificationController() {
93339
93512
  }
93340
93513
  try {
93341
93514
  if (!await isSuperAdmin(callerId5(req))) {
93342
- throw new UnauthorizedError25("Not authorized.");
93515
+ throw new UnauthorizedError26("Not authorized.");
93343
93516
  }
93344
93517
  const inserted = await _addMany(value.to, {
93345
93518
  title: value.title,
@@ -94174,6 +94347,7 @@ export {
94174
94347
  requirePlatformStaff,
94175
94348
  resetCameraTransports,
94176
94349
  residentAppModuleKeys,
94350
+ residentAppModulesSchema,
94177
94351
  residentFormEntry,
94178
94352
  resolutionRefusalReason,
94179
94353
  resolveCamera,