@7365admin1/core 3.130.0 → 3.131.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
@@ -3703,6 +3703,63 @@ function useMemberRepo() {
3703
3703
  throw error;
3704
3704
  }
3705
3705
  }
3706
+ async function peoplePage(query2, page2, limit, rowStages) {
3707
+ const noSite = { $in: ["", null] };
3708
+ const orgWide = await collection.distinct("user", {
3709
+ org: query2.org,
3710
+ type: query2.type,
3711
+ siteId: noSite,
3712
+ status: { $ne: "deleted" }
3713
+ });
3714
+ const { type: orgType, siteId: pinned, ...rest } = query2;
3715
+ const limitedRow = {
3716
+ siteId: pinned ?? { $nin: ["", null] },
3717
+ user: { $nin: orgWide }
3718
+ };
3719
+ const head = [
3720
+ // `$text` (search) may only sit in the first stage.
3721
+ { $match: { ...rest, type: { $nin: ["resident", "admin"] } } },
3722
+ { $match: pinned ? limitedRow : { $or: [{ type: orgType }, limitedRow] } },
3723
+ { $sort: { _id: -1 } },
3724
+ {
3725
+ $group: {
3726
+ _id: { $ifNull: ["$user", "$_id"] },
3727
+ doc: { $first: "$$ROOT" },
3728
+ orgWide: {
3729
+ $max: { $and: [{ $eq: ["$type", orgType] }, { $in: [{ $ifNull: ["$siteId", ""] }, ["", null]] }] }
3730
+ },
3731
+ limitedTo: { $push: { siteId: "$siteId", siteName: "$siteName", role: "$role" } }
3732
+ }
3733
+ },
3734
+ {
3735
+ $replaceRoot: {
3736
+ newRoot: { $mergeObjects: ["$doc", { limitedTo: { $cond: ["$orgWide", [], "$limitedTo"] } }] }
3737
+ }
3738
+ }
3739
+ ];
3740
+ const items = await collection.aggregate([...head, { $sort: { _id: -1 } }, { $skip: page2 * limit }, { $limit: limit }, ...rowStages]).toArray();
3741
+ const [counted] = await collection.aggregate([...head, { $count: "n" }]).toArray();
3742
+ const ids2 = (key) => [...new Set(items.flatMap((i) => (i.limitedTo ?? []).map((l) => l[key]?.toString?.() ?? "")))].filter((id) => ObjectId14.isValid(id)).map((id) => new ObjectId14(id));
3743
+ const [sites, roles] = await Promise.all([
3744
+ db2.collection("sites").find({ _id: { $in: ids2("siteId") } }, { projection: { name: 1 } }).toArray(),
3745
+ db2.collection("roles").find({ _id: { $in: ids2("role") } }, { projection: { name: 1 } }).toArray()
3746
+ ]);
3747
+ const nameOf = (list) => new Map(list.map((d) => [d._id.toString(), d.name ?? ""]));
3748
+ const siteName = nameOf(sites);
3749
+ const roleName = nameOf(roles);
3750
+ for (const item of items) {
3751
+ const bySite = /* @__PURE__ */ new Map();
3752
+ for (const l of item.limitedTo ?? []) {
3753
+ const site = l.siteId?.toString?.() ?? "";
3754
+ const role = roleName.get(l.role?.toString?.() ?? "") ?? "";
3755
+ const entry = bySite.get(site) ?? { siteId: site, siteName: siteName.get(site) || l.siteName || "", roleName: "" };
3756
+ entry.roleName = [entry.roleName, role].filter(Boolean).join(", ");
3757
+ bySite.set(site, entry);
3758
+ }
3759
+ item.limitedTo = [...bySite.values()].sort((a, b) => a.siteName.localeCompare(b.siteName));
3760
+ }
3761
+ return { items, length: counted?.n ?? 0 };
3762
+ }
3706
3763
  async function getAll({
3707
3764
  search = "",
3708
3765
  page: page2 = 1,
@@ -3713,7 +3770,8 @@ function useMemberRepo() {
3713
3770
  siteIds,
3714
3771
  type = "",
3715
3772
  status = "",
3716
- roleState = ""
3773
+ roleState = "",
3774
+ people = false
3717
3775
  }) {
3718
3776
  limit = limit > 0 ? limit : 10;
3719
3777
  search = search || "";
@@ -3772,6 +3830,9 @@ function useMemberRepo() {
3772
3830
  query2.$or = await otherSiteRoleClauses2(query2.org);
3773
3831
  cacheOptions.roleState = roleState;
3774
3832
  }
3833
+ const peopleMode = people && type === "organization" && !!query2.org && !siteId && !roleState;
3834
+ if (peopleMode)
3835
+ cacheOptions.people = 1;
3775
3836
  const cacheKey = makeCacheKey5(namespace_collection3, cacheOptions);
3776
3837
  const cachedData = await getCache(cacheKey);
3777
3838
  if (cachedData) {
@@ -3779,15 +3840,7 @@ function useMemberRepo() {
3779
3840
  return cachedData;
3780
3841
  }
3781
3842
  try {
3782
- const items = await collection.aggregate([
3783
- { $match: query2 },
3784
- { $sort: { _id: -1 } },
3785
- // `paginate()` only LABELS the range ("11-20 of 42"); it does not
3786
- // slice. Without this $skip every page returned page 1's rows under
3787
- // a later page's heading. `page` is already zero-based above, and
3788
- // this is the same $skip/$limit pair the two getOrgs* reads use.
3789
- { $skip: page2 * limit },
3790
- { $limit: limit },
3843
+ const rowStages = [
3791
3844
  {
3792
3845
  $lookup: {
3793
3846
  from: "roles",
@@ -3861,11 +3914,29 @@ function useMemberRepo() {
3861
3914
  dateInvited: { $ifNull: ["$dateInvited", "$createdAt"] },
3862
3915
  siteId: 1,
3863
3916
  siteName: 1,
3864
- type: 1
3917
+ type: 1,
3918
+ limitedTo: 1
3865
3919
  }
3866
3920
  }
3867
- ]).toArray();
3868
- const length = await collection.countDocuments(query2);
3921
+ ];
3922
+ let items;
3923
+ let length;
3924
+ if (peopleMode) {
3925
+ ({ items, length } = await peoplePage(query2, page2, limit, rowStages));
3926
+ } else {
3927
+ items = await collection.aggregate([
3928
+ { $match: query2 },
3929
+ { $sort: { _id: -1 } },
3930
+ // `paginate()` only LABELS the range ("11-20 of 42"); it does not
3931
+ // slice. Without this $skip every page returned page 1's rows under
3932
+ // a later page's heading. `page` is already zero-based above, and
3933
+ // this is the same $skip/$limit pair the two getOrgs* reads use.
3934
+ { $skip: page2 * limit },
3935
+ { $limit: limit },
3936
+ ...rowStages
3937
+ ]).toArray();
3938
+ length = await collection.countDocuments(query2);
3939
+ }
3869
3940
  const data = { ...paginate5(items, page2, limit, length), total: length };
3870
3941
  setCache(cacheKey, data, 15 * 60).then(() => {
3871
3942
  logger8.info(`Cache set for key: ${cacheKey}`);
@@ -10133,15 +10204,15 @@ function robotConnectionText(robotName, online, minutes) {
10133
10204
  }
10134
10205
  var OFFLINE_FAULT_CODE = "OFFLINE";
10135
10206
  var SAME_OCCURRENCE_MS = 1e3;
10136
- function planFaultChanges(open, reading) {
10207
+ function planFaultChanges(open, reading2) {
10137
10208
  const byCode = new Map(open.map((r) => [r.code, r]));
10138
10209
  const want = [];
10139
- const offline = !reading.ok || reading.online === false;
10210
+ const offline = !reading2.ok || reading2.online === false;
10140
10211
  if (offline) {
10141
- const reason = reading.ok ? "" : String(reading.error ?? "").slice(0, 200);
10212
+ const reason = reading2.ok ? "" : String(reading2.error ?? "").slice(0, 200);
10142
10213
  want.push({ code: OFFLINE_FAULT_CODE, message: reason ? `Not reporting: ${reason}` : "Not reporting" });
10143
10214
  }
10144
- const fault = reading.ok && reading.fault?.code ? reading.fault : null;
10215
+ const fault = reading2.ok && reading2.fault?.code ? reading2.fault : null;
10145
10216
  if (fault)
10146
10217
  want.push({ code: fault.code, message: fault.message || fault.code, since: fault.since });
10147
10218
  const clear = [];
@@ -10173,12 +10244,12 @@ function planFaultChanges(open, reading) {
10173
10244
  return { open: toOpen, clear, refresh };
10174
10245
  }
10175
10246
  function robotFaultSweepConfig(env2 = process.env) {
10176
- const num3 = (v, def, min, max) => {
10247
+ const num4 = (v, def, min, max) => {
10177
10248
  const n = Math.floor(Number(v));
10178
10249
  return Number.isFinite(n) && String(v ?? "").trim() !== "" ? Math.min(max, Math.max(min, n)) : def;
10179
10250
  };
10180
10251
  const enabled = String(env2.ROBOT_FAULT_SWEEP ?? "on").trim().toLowerCase() !== "off";
10181
- const asked = num3(env2.ROBOT_FAULT_SWEEP_SECONDS, 60, 10, 3600);
10252
+ const asked = num4(env2.ROBOT_FAULT_SWEEP_SECONDS, 60, 10, 3600);
10182
10253
  const pick = (steps, v) => steps.filter((d) => d <= v).pop() ?? steps[0];
10183
10254
  const subMinute = asked < 60;
10184
10255
  const step = subMinute ? pick([10, 12, 15, 20, 30], asked) : pick([1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60], Math.floor(asked / 60));
@@ -10188,9 +10259,9 @@ function robotFaultSweepConfig(env2 = process.env) {
10188
10259
  enabled,
10189
10260
  seconds,
10190
10261
  cron: cron2,
10191
- concurrency: num3(env2.ROBOT_FAULT_SWEEP_CONCURRENCY, 4, 1, 16),
10192
- timeoutMs: num3(env2.ROBOT_FAULT_SWEEP_TIMEOUT_MS, 1e4, 1e3, 6e4),
10193
- offlineAlertMinutes: num3(env2.ROBOT_OFFLINE_ALERT_MINUTES, 10, 1, 1440)
10262
+ concurrency: num4(env2.ROBOT_FAULT_SWEEP_CONCURRENCY, 4, 1, 16),
10263
+ timeoutMs: num4(env2.ROBOT_FAULT_SWEEP_TIMEOUT_MS, 1e4, 1e3, 6e4),
10264
+ offlineAlertMinutes: num4(env2.ROBOT_OFFLINE_ALERT_MINUTES, 10, 1, 1440)
10194
10265
  };
10195
10266
  }
10196
10267
  function withTimeout(promise, ms2, label2 = "Timed out") {
@@ -23028,6 +23099,29 @@ async function requireNotOwnerUnlessOwner(req, orgId, targetUser) {
23028
23099
  return;
23029
23100
  throw new UnauthorizedError3("Only the organisation's owner can change the owner's access.");
23030
23101
  }
23102
+ async function requireMemberGrantor(req, input) {
23103
+ const { orgId, targetUser, roleId } = input;
23104
+ const siteId = input.siteId?.toString() ?? "";
23105
+ const id = await requireSiteAccessEditor(req, orgId);
23106
+ await requireNotOwnerUnlessOwner(req, orgId, targetUser);
23107
+ if (staffMayBypass(await resolveInviteActor(id)))
23108
+ return;
23109
+ if (siteId)
23110
+ await requireSiteServedByOrg(siteId, orgId);
23111
+ if (await hasOrgOwnership(id, orgId))
23112
+ return;
23113
+ const db2 = useAtlas36.getDb();
23114
+ if (!db2 || !ObjectId54.isValid(roleId))
23115
+ return;
23116
+ const role = await db2.collection("roles").findOne({ _id: new ObjectId54(roleId) }, { projection: { permissions: 1 } });
23117
+ if (isOwnerRole(role)) {
23118
+ const rows = await db2.collection("members").find({ user: new ObjectId54(id), org: new ObjectId54(orgId), status: "active" }, { projection: { role: 1 } }).toArray();
23119
+ const held = rows.map((m) => m.role?.toString?.() ?? "").filter((r) => ObjectId54.isValid(r)).map((r) => new ObjectId54(r));
23120
+ const holdsOwner = held.length ? await db2.collection("roles").countDocuments({ _id: { $in: held }, permissions: "*", status: "active" }) : 0;
23121
+ if (!holdsOwner)
23122
+ throw new UnauthorizedError3("Only the organisation's owner can give an owner role.");
23123
+ }
23124
+ }
23031
23125
  async function requireSiteReachInOrg(req, siteId, orgId) {
23032
23126
  if (await hasOrgOwnership(callerId(req), orgId)) {
23033
23127
  await requireSiteServedByOrg(siteId, orgId);
@@ -26079,7 +26173,7 @@ function usePersonRepo() {
26079
26173
  }
26080
26174
  async function pushVehicleById(id, plate, session) {
26081
26175
  const { plateNumber, recNo } = plate;
26082
- const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
26176
+ const updatedAt2 = (/* @__PURE__ */ new Date()).toISOString();
26083
26177
  const _id = toObjectId9(id);
26084
26178
  try {
26085
26179
  const updateExisting = await collection.updateOne(
@@ -26090,7 +26184,7 @@ function usePersonRepo() {
26090
26184
  {
26091
26185
  $set: {
26092
26186
  "plates.$.recNo": recNo,
26093
- updatedAt
26187
+ updatedAt: updatedAt2
26094
26188
  }
26095
26189
  },
26096
26190
  { session }
@@ -26106,7 +26200,7 @@ function usePersonRepo() {
26106
26200
  }
26107
26201
  },
26108
26202
  $set: {
26109
- updatedAt
26203
+ updatedAt: updatedAt2
26110
26204
  }
26111
26205
  },
26112
26206
  { session }
@@ -26117,7 +26211,7 @@ function usePersonRepo() {
26117
26211
  }
26118
26212
  }
26119
26213
  async function pullVehicleByRecNo(recNo, scope, session) {
26120
- const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
26214
+ const updatedAt2 = (/* @__PURE__ */ new Date()).toISOString();
26121
26215
  const owner = scope?.peopleId ? toObjectId9(scope.peopleId) : null;
26122
26216
  const site = scope?.site ? toObjectId9(scope.site) : null;
26123
26217
  if (!owner && !site) {
@@ -26156,7 +26250,7 @@ function usePersonRepo() {
26156
26250
  plates: match
26157
26251
  },
26158
26252
  $set: {
26159
- updatedAt
26253
+ updatedAt: updatedAt2
26160
26254
  }
26161
26255
  },
26162
26256
  { session }
@@ -28311,7 +28405,9 @@ function useMemberController() {
28311
28405
  siteId: Joi29.string().hex().optional().allow("", null),
28312
28406
  type: Joi29.string().required(),
28313
28407
  status: Joi29.string().required(),
28314
- roleState: Joi29.string().valid("other-site").optional().allow("", null)
28408
+ roleState: Joi29.string().valid("other-site").optional().allow("", null),
28409
+ // Organization app Members: every person, site-limited ones included.
28410
+ people: Joi29.boolean().truthy("1").falsy("0").optional().allow("", null)
28315
28411
  });
28316
28412
  const query2 = { ...req.query };
28317
28413
  const { error } = validation.validate(query2);
@@ -28366,7 +28462,8 @@ function useMemberController() {
28366
28462
  siteIds,
28367
28463
  type,
28368
28464
  status,
28369
- roleState: req.query.roleState ?? ""
28465
+ roleState: req.query.roleState ?? "",
28466
+ people: ["1", "true"].includes(String(req.query.people ?? ""))
28370
28467
  });
28371
28468
  res.json(items);
28372
28469
  return;
@@ -28507,7 +28604,7 @@ function useMemberController() {
28507
28604
  await requireOrgReach(req, orgId);
28508
28605
  await requireSelfEnrolRole(req, orgId, roleId);
28509
28606
  } else {
28510
- await requireOrgAccess(req, orgId);
28607
+ await requireMemberGrantor(req, { orgId, targetUser: userId, roleId, siteId });
28511
28608
  }
28512
28609
  const data = await _createMemberDirect({ userId, orgId, roleId, app, siteId, siteName, onboardingRequired, callerId: callerId(req) });
28513
28610
  res.status(201).json(data);
@@ -47611,7 +47708,7 @@ var MKeyLog = class {
47611
47708
  organization = "",
47612
47709
  serviceProvider = "",
47613
47710
  createdAt = /* @__PURE__ */ new Date(),
47614
- updatedAt = /* @__PURE__ */ new Date(),
47711
+ updatedAt: updatedAt2 = /* @__PURE__ */ new Date(),
47615
47712
  template,
47616
47713
  status = "Available",
47617
47714
  updatedBy = "",
@@ -47632,7 +47729,7 @@ var MKeyLog = class {
47632
47729
  this.organization = organization;
47633
47730
  this.serviceProvider = serviceProvider;
47634
47731
  this.createdAt = createdAt;
47635
- this.updatedAt = updatedAt;
47732
+ this.updatedAt = updatedAt2;
47636
47733
  this.template = template;
47637
47734
  this.status = status;
47638
47735
  this.updatedBy = updatedBy;
@@ -56287,7 +56384,7 @@ var MAccessCard = class {
56287
56384
  isLiftCard,
56288
56385
  liftAccessLevel,
56289
56386
  createdAt,
56290
- updatedAt,
56387
+ updatedAt: updatedAt2,
56291
56388
  assignedUnit,
56292
56389
  userType,
56293
56390
  doorName,
@@ -56314,7 +56411,7 @@ var MAccessCard = class {
56314
56411
  this.isLiftCard = isLiftCard;
56315
56412
  this.liftAccessLevel = liftAccessLevel;
56316
56413
  this.createdAt = createdAt;
56317
- this.updatedAt = updatedAt;
56414
+ this.updatedAt = updatedAt2;
56318
56415
  this.assignedUnit = assignedUnit;
56319
56416
  this.userType = userType;
56320
56417
  this.doorName = doorName;
@@ -56493,8 +56590,8 @@ function encryptPayload(payloadHex) {
56493
56590
  );
56494
56591
  return encrypted.toString("base64");
56495
56592
  }
56496
- function toHex(num3, length) {
56497
- return num3.toString(16).padStart(length * 2, "0");
56593
+ function toHex(num4, length) {
56594
+ return num4.toString(16).padStart(length * 2, "0");
56498
56595
  }
56499
56596
  function buildPayload(cardNumber, validityMinutes) {
56500
56597
  const randomHex = crypto7.randomBytes(2).toString("hex");
@@ -56674,8 +56771,8 @@ function UseAccessManagementRepo() {
56674
56771
  }
56675
56772
  }
56676
56773
  function generateCardNo() {
56677
- const num3 = Math.floor(Math.random() * 65536);
56678
- return num3.toString().padStart(10, "0");
56774
+ const num4 = Math.floor(Math.random() * 65536);
56775
+ return num4.toString().padStart(10, "0");
56679
56776
  }
56680
56777
  async function createQrData({
56681
56778
  cardNumber,
@@ -57915,13 +58012,13 @@ function UseAccessManagementRepo() {
57915
58012
  const prevCard = res && res?.[1]?.cardNo || "-1";
57916
58013
  const currentCard = res && res?.[0]?.cardNo || "0";
57917
58014
  let availableCardNo = [];
57918
- let num3 = parseInt(prevCard, 10) + 1;
58015
+ let num4 = parseInt(prevCard, 10) + 1;
57919
58016
  while (availableCardNo.length < (unit.length > 0 ? unit.length : quantity)) {
57920
- if (num3 === parseInt(currentCard, 10)) {
57921
- num3++;
58017
+ if (num4 === parseInt(currentCard, 10)) {
58018
+ num4++;
57922
58019
  }
57923
- availableCardNo.push(num3);
57924
- num3++;
58020
+ availableCardNo.push(num4);
58021
+ num4++;
57925
58022
  }
57926
58023
  const cardNumbers = availableCardNo.map(
57927
58024
  (no2) => no2.toString().padStart(10, "0")
@@ -63657,13 +63754,13 @@ function parseRobotCommand(body) {
63657
63754
  if (has2(k))
63658
63755
  return { ok: false, message: `${k} is not valid for a ${kind} command.` };
63659
63756
  }
63660
- const num3 = (k) => typeof b[k] === "number" && Number.isFinite(b[k]);
63661
- if (!num3("x") || !num3("y"))
63757
+ const num4 = (k) => typeof b[k] === "number" && Number.isFinite(b[k]);
63758
+ if (!num4("x") || !num4("y"))
63662
63759
  return { ok: false, message: `${kind} needs x and y (metres).` };
63663
63760
  if (kind === "navigate") {
63664
63761
  if (has2("floorNo"))
63665
63762
  return { ok: false, message: "floorNo is not valid for a navigate command." };
63666
- if (has2("theta") && !num3("theta"))
63763
+ if (has2("theta") && !num4("theta"))
63667
63764
  return { ok: false, message: "theta must be a number (radians)." };
63668
63765
  return {
63669
63766
  ok: true,
@@ -63675,7 +63772,7 @@ function parseRobotCommand(body) {
63675
63772
  }
63676
63773
  };
63677
63774
  }
63678
- if (!num3("theta"))
63775
+ if (!num4("theta"))
63679
63776
  return { ok: false, message: "relocalize needs theta (radians)." };
63680
63777
  if (!Number.isInteger(b.floorNo))
63681
63778
  return { ok: false, message: "relocalize needs an integer floorNo." };
@@ -64099,23 +64196,81 @@ var OUNITECH_CAPABILITIES = {
64099
64196
  var OUNITECH_PENDING_COMMANDS = ["pause", "resume", "cancel"].map(
64100
64197
  (kind) => ({ kind, reason: "awaiting Ounitech's robot-control action numbers" })
64101
64198
  );
64102
- function propertyNumber(row, key) {
64103
- const p = row.robotState?.properties?.find((x) => x?.key === key);
64104
- const n = p?.value != null && String(p.value).trim() !== "" ? Number(p.value) : NaN;
64105
- return Number.isFinite(n) ? n : null;
64106
- }
64107
64199
  var finite = (v) => typeof v === "number" && Number.isFinite(v);
64108
- function ounitechRobotFromHomeRow(row) {
64109
- const st = row.robotState ?? {};
64110
- const flag = finite(st.statusFlag) ? st.statusFlag : void 0;
64111
- const online = flag !== void 0 && flag !== 99;
64200
+ function num(v) {
64201
+ if (finite(v))
64202
+ return v;
64203
+ if (typeof v === "string" && v.trim() !== "") {
64204
+ const n = Number(v);
64205
+ return Number.isFinite(n) ? n : void 0;
64206
+ }
64207
+ return void 0;
64208
+ }
64209
+ function reading(st, key) {
64210
+ const v = st.properties?.find((x) => x?.key === key)?.value;
64211
+ return v == null || String(v).trim() === "" ? void 0 : String(v).trim();
64212
+ }
64213
+ var OUNITECH_FRESH_MS = 3 * 6e4;
64214
+ var STATUS_CODE_BY_READING = {
64215
+ \u5F85\u673A: 1,
64216
+ \u7A7A\u95F2: 1,
64217
+ \u6E05\u626B\u4E2D: 2,
64218
+ \u5DE5\u4F5C\u4E2D: 2,
64219
+ \u6682\u505C: 3,
64220
+ \u6682\u505C\u4E2D: 3,
64221
+ \u5EFA\u56FE\u4E2D: 4,
64222
+ \u56DE\u5145\u4E2D: 6,
64223
+ \u8FD4\u56DE\u5145\u7535: 6,
64224
+ \u6545\u969C: 7,
64225
+ \u5F02\u5E38: 7,
64226
+ \u5145\u7535\u4E2D: 8,
64227
+ \u65AD\u70B9\u5145\u7535\u4E2D: 16,
64228
+ \u5DF2\u5145\u6EE1: 9,
64229
+ \u5145\u6EE1: 9,
64230
+ \u6025\u505C: 11,
64231
+ \u5173\u673A: 14,
64232
+ \u79BB\u7EBF: 99
64233
+ };
64234
+ var JOB_WORDS = {
64235
+ \u5DF2\u7ED3\u675F: "job finished",
64236
+ \u5DF2\u5B8C\u6210: "job finished",
64237
+ \u5B8C\u6210: "job finished",
64238
+ \u6E05\u626B\u4E2D: "job in progress",
64239
+ \u8FDB\u884C\u4E2D: "job in progress",
64240
+ \u6682\u505C: "job paused",
64241
+ \u6682\u505C\u4E2D: "job paused",
64242
+ \u672A\u5F00\u59CB: "no job started",
64243
+ \u5DF2\u53D6\u6D88: "job cancelled",
64244
+ \u53D6\u6D88: "job cancelled"
64245
+ };
64246
+ function ounitechJobWords(st) {
64247
+ const v = reading(st, "job");
64248
+ return v ? JOB_WORDS[v] ?? null : null;
64249
+ }
64250
+ function updatedAt(v) {
64251
+ const n = num(v);
64252
+ if (n !== void 0)
64253
+ return n < 1e12 ? n * 1e3 : n;
64254
+ const t = typeof v === "string" ? Date.parse(v) : NaN;
64255
+ return Number.isFinite(t) ? t : null;
64256
+ }
64257
+ function ounitechRobotFromHomeRow(row, live2, now = Date.now()) {
64258
+ const listed = row.robotState ?? {};
64259
+ const st = live2 ? { ...listed, ...live2, properties: live2.properties?.length ? live2.properties : listed.properties } : listed;
64260
+ const statusReading = reading(st, "status");
64261
+ const flag = num(st.statusFlag) ?? (statusReading ? STATUS_CODE_BY_READING[statusReading] : void 0);
64262
+ const at2 = updatedAt(st.updateOn);
64263
+ const fresh = at2 !== null && now - at2 <= OUNITECH_FRESH_MS;
64264
+ const online = flag !== 99 && (flag !== void 0 || fresh);
64112
64265
  const mode = online ? robotMode(flag) : "UNAVAILABLE";
64113
- const pct = propertyNumber(row, "battery-percent") ?? (finite(st.battery) ? st.battery : null);
64266
+ const pct = num(reading(st, "battery-percent")) ?? num(st.battery) ?? null;
64114
64267
  const task = row.taskState;
64115
64268
  const jobPct = task && String(task.statusFlag) === "1" && finite(task.accPercent) ? Math.round(task.accPercent) : null;
64116
- const words = flag === void 0 ? "Unknown" : ROBOT_STATUS_NAMES[flag] ?? `Status ${flag}`;
64269
+ const words = flag !== void 0 ? ROBOT_STATUS_NAMES[flag] ?? `Status ${flag}` : online ? "Online - status not reported" : "Unknown";
64117
64270
  const model = String(row.modelCode || row.modelName || "").trim().slice(0, 40);
64118
- return {
64271
+ const x = num(st.x);
64272
+ const y = num(st.y);
64273
+ const robot = {
64119
64274
  robotSn: row.robotSn,
64120
64275
  name: row.aliasName || row.robotName,
64121
64276
  ...model ? { model } : {},
@@ -64125,8 +64280,16 @@ function ounitechRobotFromHomeRow(row) {
64125
64280
  batteryPercent: online && pct !== null && pct >= 0 && pct <= 100 ? Math.round(pct) : null,
64126
64281
  floorNo: Number.isInteger(row.floorNo) ? row.floorNo : null,
64127
64282
  floorKnown: Number.isInteger(row.floorNo),
64128
- position: online && finite(st.x) && finite(st.y) ? { x: st.x, y: st.y, theta: finite(st.theta) ? st.theta : 0 } : null
64283
+ position: online && x !== void 0 && y !== void 0 ? { x, y, theta: num(st.theta) ?? 0 } : null
64129
64284
  };
64285
+ if (online && (flag === 7 || Array.isArray(st.rtFaultList) && st.rtFaultList.length)) {
64286
+ robot.fault = ounitechFault(st.rtFaultList);
64287
+ }
64288
+ return robot;
64289
+ }
64290
+ function needsLiveState(row) {
64291
+ const f = num(row.robotState?.statusFlag);
64292
+ return finite(row.robotId) && (f === void 0 || f === 99 || f === 7);
64130
64293
  }
64131
64294
  function ounitechFault(list) {
64132
64295
  const f = Array.isArray(list) ? list[0] : null;
@@ -64143,6 +64306,9 @@ function ounitechFault(list) {
64143
64306
  var robotTime = (d) => robotCloudTimestamp(d, "yyyy-MM-dd HH:mm:ss", "Asia/Shanghai");
64144
64307
  function createOunitechAdapter(credentials, options) {
64145
64308
  const cloud = useRobotCloudService(credentials, options);
64309
+ async function liveFor(row) {
64310
+ return needsLiveState(row) ? cloud.getRobotState(row.robotId).catch(() => null) : null;
64311
+ }
64146
64312
  async function rowFor(robotSn) {
64147
64313
  return (await cloud.getHomeRobots()).find((r) => r.robotSn === robotSn) ?? null;
64148
64314
  }
@@ -64151,7 +64317,7 @@ function createOunitechAdapter(credentials, options) {
64151
64317
  displayName: "Ounitech (Q3-G / Q3-W)",
64152
64318
  capabilities: OUNITECH_CAPABILITIES,
64153
64319
  async listRobots() {
64154
- return (await cloud.getHomeRobots()).map(ounitechRobotFromHomeRow);
64320
+ return Promise.all((await cloud.getHomeRobots()).map(async (row) => ounitechRobotFromHomeRow(row, await liveFor(row))));
64155
64321
  },
64156
64322
  async getRobot(robotSn) {
64157
64323
  const row = await rowFor(robotSn);
@@ -64167,12 +64333,7 @@ function createOunitechAdapter(credentials, options) {
64167
64333
  position: null
64168
64334
  };
64169
64335
  }
64170
- const robot = ounitechRobotFromHomeRow(row);
64171
- if (row.robotState?.statusFlag === 7 && finite(row.robotId)) {
64172
- const state = await cloud.getRobotState(row.robotId).catch(() => null);
64173
- robot.fault = ounitechFault(state?.rtFaultList);
64174
- }
64175
- return robot;
64336
+ return ounitechRobotFromHomeRow(row, await liveFor(row));
64176
64337
  },
64177
64338
  async sendCommand(robotSn, command) {
64178
64339
  const options2 = {
@@ -64287,10 +64448,19 @@ function createOunitechAdapter(credentials, options) {
64287
64448
  const window = { timeFrom: robotTime(from), timeTo: robotTime(to) };
64288
64449
  await run("live state (get-robot-state-v2.0)", ROBOT_CLOUD_PATHS.robotState, { robotId }, async () => {
64289
64450
  const s = await cloud.getRobotState(robotId);
64451
+ const r = ounitechRobotFromHomeRow(row, s);
64452
+ const level2 = (...keys) => keys.map((k) => num(reading(s, k))).find((n) => n !== void 0) ?? null;
64453
+ const at2 = updatedAt(s.updateOn);
64290
64454
  return {
64455
+ online: r.online,
64456
+ status: r.statusName,
64457
+ job: ounitechJobWords(s),
64458
+ battery: r.batteryPercent,
64459
+ cleanWater: level2("clean-water", "clean-percent"),
64460
+ dirtyWater: level2("dirty-water", "dirty-percent"),
64461
+ fault: r.fault ?? null,
64291
64462
  statusFlag: s.statusFlag,
64292
- status: finite(s.statusFlag) ? ROBOT_STATUS_NAMES[s.statusFlag] ?? null : null,
64293
- updateOn: s.updateOn ? new Date(s.updateOn).toISOString() : null,
64463
+ updateOn: at2 !== null ? new Date(at2).toISOString() : null,
64294
64464
  x: s.x,
64295
64465
  y: s.y,
64296
64466
  theta: s.theta,
@@ -66222,7 +66392,7 @@ function statesByType(entry) {
66222
66392
  }
66223
66393
  var PADBOT_ONLINE_WINDOW_MS = 12e4;
66224
66394
  var ms = (t) => typeof t === "string" ? Date.parse(t) : NaN;
66225
- var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
66395
+ var num2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
66226
66396
  function padbotMode(states, now = Date.now()) {
66227
66397
  const hb = ms(states["1000"]?.updatedAt);
66228
66398
  const online = Number.isFinite(hb) && now - hb <= PADBOT_ONLINE_WINDOW_MS;
@@ -66230,7 +66400,7 @@ function padbotMode(states, now = Date.now()) {
66230
66400
  return { online: false, mode: "UNAVAILABLE", statusName: "Not reporting to PadBot" };
66231
66401
  const nav = states["1003"] ?? {};
66232
66402
  const work = states["1010"] ?? {};
66233
- const battery = num(states["1001"]?.batteryPercent);
66403
+ const battery = num2(states["1001"]?.batteryPercent);
66234
66404
  const charging = states["1002"]?.chargingState === 1;
66235
66405
  const type = Number(nav.actionType) || 0;
66236
66406
  const st = Number(nav.actionState) || 0;
@@ -66267,7 +66437,7 @@ function padbotCommandBlock(states, kind, now = Date.now()) {
66267
66437
  return "The robot is not reporting to PadBot, so it cannot take a command. Check it is switched on and connected.";
66268
66438
  if (states["1006"]?.emergencyStopState === 1)
66269
66439
  return "The robot's emergency stop button is pressed. Release the red button on the robot, then try again.";
66270
- const battery = num(states["1001"]?.batteryPercent);
66440
+ const battery = num2(states["1001"]?.batteryPercent);
66271
66441
  if (kind !== "return" && battery !== null && battery < 10)
66272
66442
  return `The battery is at ${battery}%. PadBot robots do not start jobs under 10%; send it to charge first.`;
66273
66443
  if (kind === "return" && [1, 2].includes(states["1002"]?.chargingState))
@@ -66289,7 +66459,7 @@ function padbotReadiness(states, now = Date.now()) {
66289
66459
  heartbeatAt: st["1000"]?.updatedAt ?? null,
66290
66460
  emergencyStopPressed: es.emergencyStopState === 1,
66291
66461
  wheelLockState: es.wheelLockState ?? null,
66292
- batteryPercent: num(st["1001"]?.batteryPercent),
66462
+ batteryPercent: num2(st["1001"]?.batteryPercent),
66293
66463
  chargingState: charging ?? null,
66294
66464
  map: { id: st["1007"]?.mapId ?? null, name: st["1007"]?.mapDisplayName ?? null, floor: st["1007"]?.floor ?? null },
66295
66465
  navigation: { actionType: nav.actionType ?? null, actionState: nav.actionState ?? null, message: nav.message ?? null, updatedAt: nav.updatedAt ?? null },
@@ -66346,19 +66516,19 @@ function padbotMotion(m, now) {
66346
66516
  }
66347
66517
  function networkText(net) {
66348
66518
  const say = (label2, v) => v < 0 ? ` \xB7 ${label2} ${v} dBm` : ` \xB7 ${label2} signal ${v}`;
66349
- const wifi = num(net?.wifi?.signalStrength);
66519
+ const wifi = num2(net?.wifi?.signalStrength);
66350
66520
  if (wifi !== null)
66351
66521
  return say("Wi-Fi", wifi);
66352
- const cell = num(net?.cellular?.signalStrength);
66522
+ const cell = num2(net?.cellular?.signalStrength);
66353
66523
  return cell !== null ? say("Mobile", cell) : "";
66354
66524
  }
66355
66525
  function padbotPlanShare(frame2, x, y) {
66356
- const w = num(frame2?.width), h = num(frame2?.height), r = num(frame2?.resolution);
66357
- const wx = num(x), wy = num(y);
66526
+ const w = num2(frame2?.width), h = num2(frame2?.height), r = num2(frame2?.resolution);
66527
+ const wx = num2(x), wy = num2(y);
66358
66528
  if (!w || !h || !r || r <= 0 || wx === null || wy === null)
66359
66529
  return null;
66360
- const px = (wx - (num(frame2?.originX) ?? 0)) / r;
66361
- const pyUp = (wy - (num(frame2?.originY) ?? 0)) / r;
66530
+ const px = (wx - (num2(frame2?.originX) ?? 0)) / r;
66531
+ const pyUp = (wy - (num2(frame2?.originY) ?? 0)) / r;
66362
66532
  const sx = px / w * 100, sy = 100 - pyUp / h * 100;
66363
66533
  if (sx < 0 || sx > 100 || sy < 0 || sy > 100)
66364
66534
  return null;
@@ -66388,9 +66558,9 @@ function padbotCurrentMap(maps, ids2, floor) {
66388
66558
  }
66389
66559
  function padbotChargingPoint(map) {
66390
66560
  const piles = (Array.isArray(map?.targetPoints) ? map.targetPoints : []).filter(
66391
- (t) => Number(t?.targetPointType) === 10 && num(t?.worldX) !== null && num(t?.worldY) !== null
66561
+ (t) => Number(t?.targetPointType) === 10 && num2(t?.worldX) !== null && num2(t?.worldY) !== null
66392
66562
  );
66393
- return piles.length === 1 ? { worldX: num(piles[0].worldX), worldY: num(piles[0].worldY), yaw: piles[0].yaw } : null;
66563
+ return piles.length === 1 ? { worldX: num2(piles[0].worldX), worldY: num2(piles[0].worldY), yaw: piles[0].yaw } : null;
66394
66564
  }
66395
66565
  var PADBOT_OTHER_MAP_TEXT = "The robot must be on this map first.";
66396
66566
  function padbotAlarmFault(alarm) {
@@ -66485,9 +66655,9 @@ function padbotPatrolRecord(r) {
66485
66655
  result: PATROL_RESULT[r?.completionState] ?? "unknown",
66486
66656
  startedAt: r?.startedAt ?? null,
66487
66657
  endedAt: r?.endedAt ?? null,
66488
- durationS: num(r?.duration),
66489
- distanceM: num(r?.mileage),
66490
- alarmCount: num(r?.alarmCount) ?? 0
66658
+ durationS: num2(r?.duration),
66659
+ distanceM: num2(r?.mileage),
66660
+ alarmCount: num2(r?.alarmCount) ?? 0
66491
66661
  };
66492
66662
  }
66493
66663
  function padbotCheckpointVisit(d) {
@@ -66497,15 +66667,15 @@ function padbotCheckpointVisit(d) {
66497
66667
  skipped: d?.skipped === true,
66498
66668
  imageUrl: d?.visibleLightImageUrl ?? null,
66499
66669
  thermalImageUrl: d?.thermalImageUrl ?? null,
66500
- centerTempC: num(d?.centerTemperature),
66501
- maxTempC: num(d?.maxTemperature)
66670
+ centerTempC: num2(d?.centerTemperature),
66671
+ maxTempC: num2(d?.maxTemperature)
66502
66672
  };
66503
66673
  }
66504
66674
  var asList = (d) => Array.isArray(d) ? d : Array.isArray(d?.items) ? d.items : Array.isArray(d?.list) ? d.list : Array.isArray(d?.records) ? d.records : [];
66505
66675
  var page = (data, map) => ({
66506
66676
  items: (Array.isArray(data?.items) ? data.items : []).map(map),
66507
- total: num(data?.totalItems) ?? 0,
66508
- pages: num(data?.totalPages) ?? 0
66677
+ total: num2(data?.totalItems) ?? 0,
66678
+ pages: num2(data?.totalPages) ?? 0
66509
66679
  });
66510
66680
  function createPadbotClient(credentials, options = {}) {
66511
66681
  const baseUrl = (options.baseUrl ?? padbotBaseUrl()).replace(/\/+$/, "");
@@ -66727,7 +66897,7 @@ function createPadbotAdapter(credentials, options = {}) {
66727
66897
  const { online, mode, statusName } = padbotMode(st, now());
66728
66898
  const floor = st["1007"]?.floor;
66729
66899
  const restBatteryAt = ms(st["1001"]?.updatedAt);
66730
- const battery = heard?.batteryPercent !== void 0 && (!Number.isFinite(restBatteryAt) || (heard.batteryAt ?? 0) > restBatteryAt) ? heard.batteryPercent : num(st["1001"]?.batteryPercent);
66900
+ const battery = heard?.batteryPercent !== void 0 && (!Number.isFinite(restBatteryAt) || (heard.batteryAt ?? 0) > restBatteryAt) ? heard.batteryPercent : num2(st["1001"]?.batteryPercent);
66731
66901
  const failed = lastFailure.get(`${account}:${robotSn}`);
66732
66902
  const showFailure = online && failed && now() - failed.at < PADBOT_FAILURE_SHOW_MS && /^(Standing by|Charging)/.test(statusName);
66733
66903
  const robot = {
@@ -66754,15 +66924,15 @@ function createPadbotAdapter(credentials, options = {}) {
66754
66924
  return robot;
66755
66925
  const [loc, openA] = await Promise.all([locRead, alarmRead]);
66756
66926
  const alarm = robot.fault ? null : openA;
66757
- const lx = num(loc?.worldX ?? loc?.x);
66758
- const ly = num(loc?.worldY ?? loc?.y);
66927
+ const lx = num2(loc?.worldX ?? loc?.x);
66928
+ const ly = num2(loc?.worldY ?? loc?.y);
66759
66929
  if (typeof loc?.mapId === "string" && loc.mapId)
66760
66930
  robot.mapId = loc.mapId;
66761
66931
  const map = await maps(robotSn).then((all) => padbotCurrentMap(all, [robot.mapId, st["1007"]?.mapId], robot.floorNo)).catch(() => null);
66762
66932
  if (map)
66763
66933
  robot.mapId = map.mapId;
66764
66934
  if (lx !== null && ly !== null) {
66765
- robot.position = { x: lx, y: ly, theta: (num(loc.yaw ?? loc.r) ?? 0) * Math.PI / 180 };
66935
+ robot.position = { x: lx, y: ly, theta: (num2(loc.yaw ?? loc.r) ?? 0) * Math.PI / 180 };
66766
66936
  robot.planPosition = padbotPlanShare(map, lx, ly);
66767
66937
  }
66768
66938
  const mo = motions.get(`${account}:${robotSn}`);
@@ -66782,7 +66952,7 @@ function createPadbotAdapter(credentials, options = {}) {
66782
66952
  const onCharger = [1, 2].includes(st["1002"]?.chargingState);
66783
66953
  const pile = onCharger && !robot.position ? padbotChargingPoint(map) : null;
66784
66954
  if (pile) {
66785
- robot.position = { x: pile.worldX, y: pile.worldY, theta: (num(pile.yaw) ?? 0) * Math.PI / 180 };
66955
+ robot.position = { x: pile.worldX, y: pile.worldY, theta: (num2(pile.yaw) ?? 0) * Math.PI / 180 };
66786
66956
  robot.planPosition = padbotPlanShare(map, pile.worldX, pile.worldY);
66787
66957
  if (!going || going.done)
66788
66958
  robot.statusName = `${robot.statusName} \xB7 At charger`;
@@ -66882,12 +67052,12 @@ function createPadbotAdapter(credentials, options = {}) {
66882
67052
  throw new BadRequestError137(block);
66883
67053
  lastFailure.delete(`${account}:${robotSn}`);
66884
67054
  const heard = padbotLive(account, robotSn)?.pose;
66885
- const lx = num(where?.loc?.worldX);
66886
- const ly = num(where?.loc?.worldY);
67055
+ const lx = num2(where?.loc?.worldX);
67056
+ const ly = num2(where?.loc?.worldY);
66887
67057
  let target = null;
66888
67058
  if (command.kind === "go-to-point") {
66889
67059
  const pt = (where?.all ?? []).flatMap((m) => Array.isArray(m?.targetPoints) ? m.targetPoints : []).find((t) => t?.targetPointId === command.targetPointId);
66890
- target = { name: String(pt?.name || "the chosen point"), x: num(pt?.worldX), y: num(pt?.worldY) };
67060
+ target = { name: String(pt?.name || "the chosen point"), x: num2(pt?.worldX), y: num2(pt?.worldY) };
66891
67061
  }
66892
67062
  motion = {
66893
67063
  kind: command.kind,
@@ -67939,11 +68109,11 @@ function decodeTrackingFrame(data) {
67939
68109
  if (!parsed || typeof parsed !== "object")
67940
68110
  return null;
67941
68111
  const frame2 = parsed;
67942
- const num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
67943
- const x = num3(frame2.x);
67944
- const y = num3(frame2.y);
67945
- const theta = num3(frame2.theta);
67946
- const statusFlag = num3(frame2.status);
68112
+ const num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
68113
+ const x = num4(frame2.x);
68114
+ const y = num4(frame2.y);
68115
+ const theta = num4(frame2.theta);
68116
+ const statusFlag = num4(frame2.status);
67947
68117
  if (x === null || y === null || theta === null || statusFlag === null) {
67948
68118
  return null;
67949
68119
  }
@@ -68467,22 +68637,22 @@ function useRobotFaultSweep(deps) {
68467
68637
  if (!robot)
68468
68638
  return;
68469
68639
  out.robots++;
68470
- let reading;
68640
+ let reading2;
68471
68641
  try {
68472
68642
  const state = deps?.readState ? await deps.readState(robot) : await readRobotState(robot, { timeoutMs: cfg.timeoutMs });
68473
68643
  if (deps?.readState)
68474
68644
  rememberRobotState(robot, state);
68475
- reading = { ok: true, online: state.online === true, fault: state.fault ?? null };
68476
- if (reading.fault)
68477
- Object.assign(reading.fault, { floorNo: state.floorNo ?? null });
68645
+ reading2 = { ok: true, online: state.online === true, fault: state.fault ?? null };
68646
+ if (reading2.fault)
68647
+ Object.assign(reading2.fault, { floorNo: state.floorNo ?? null });
68478
68648
  } catch (error) {
68479
68649
  if (deps?.readState)
68480
68650
  rememberRobotState(robot, null);
68481
- reading = { ok: false, error: error?.message ?? "no answer" };
68651
+ reading2 = { ok: false, error: error?.message ?? "no answer" };
68482
68652
  }
68483
68653
  const records = byRobot2.get(String(robot._id)) ?? [];
68484
68654
  const offlineRec = records.find((r) => r.code === OFFLINE_FAULT_CODE);
68485
- const plan = planFaultChanges(records, reading);
68655
+ const plan = planFaultChanges(records, reading2);
68486
68656
  for (const id of plan.clear) {
68487
68657
  await repo.clearFault(id);
68488
68658
  out.cleared++;
@@ -68495,7 +68665,7 @@ function useRobotFaultSweep(deps) {
68495
68665
  out.alerts++;
68496
68666
  }
68497
68667
  for (const f of plan.open) {
68498
- const detail = reading.ok && reading.fault?.code === f.code ? reading.fault : null;
68668
+ const detail = reading2.ok && reading2.fault?.code === f.code ? reading2.fault : null;
68499
68669
  const r = await openFaultRecord(robot, detail ? { ...detail, ...f } : f, { notify: true, notifyFn: deps?.notifyFn });
68500
68670
  if (r.opened)
68501
68671
  out.opened++;
@@ -69813,7 +69983,7 @@ function measurementScale(vertices, meas) {
69813
69983
  return est.length ? est.reduce((n, v) => n + v, 0) / est.length : null;
69814
69984
  }
69815
69985
  var pval = (p) => Array.isArray(p) ? p[1] : p;
69816
- var num2 = (v, fallback = 0) => v !== null && v !== "" && Number.isFinite(Number(v)) ? Number(v) : fallback;
69986
+ var num3 = (v, fallback = 0) => v !== null && v !== "" && Number.isFinite(Number(v)) ? Number(v) : fallback;
69817
69987
  var str60 = (v) => String(v ?? "").slice(0, 60);
69818
69988
  function decodeParams(raw) {
69819
69989
  const out = {};
@@ -69833,7 +70003,7 @@ function fileVertexParams(raw) {
69833
70003
  const v = raw[k];
69834
70004
  if (v === void 0 || v === null)
69835
70005
  continue;
69836
- out[k] = k.startsWith("is_") ? Boolean(v) : k === "merge_radius" ? clamp3(num2(v), 0, 100) : str60(v);
70006
+ out[k] = k.startsWith("is_") ? Boolean(v) : k === "merge_radius" ? clamp3(num3(v), 0, 100) : str60(v);
69837
70007
  }
69838
70008
  return out;
69839
70009
  }
@@ -69906,14 +70076,14 @@ function fromBuildingYaml(doc) {
69906
70076
  const raw = names.map((name) => {
69907
70077
  const y = doc.levels[name] ?? {};
69908
70078
  const vertices = (Array.isArray(y.vertices) ? y.vertices : []).map((v) => ({
69909
- x: num2(v?.[0]),
69910
- y: num2(v?.[1]) * flip,
70079
+ x: num3(v?.[0]),
70080
+ y: num3(v?.[1]) * flip,
69911
70081
  name: str60(v?.[3]),
69912
70082
  params: fileVertexParams(decodeParams(v?.[4]))
69913
70083
  }));
69914
- const fiducials = (Array.isArray(y.fiducials) ? y.fiducials : []).map((f) => ({ x: num2(f?.[0]), y: num2(f?.[1]) * flip, name: str60(f?.[2]) }));
69915
- const meas = edgeList(y.measurements).map((e) => [e.a, e.b, num2(e.p.distance)]);
69916
- return { name: str60(name), y, vertices, fiducials, meas, elevation: num2(y.elevation) };
70084
+ const fiducials = (Array.isArray(y.fiducials) ? y.fiducials : []).map((f) => ({ x: num3(f?.[0]), y: num3(f?.[1]) * flip, name: str60(f?.[2]) }));
70085
+ const meas = edgeList(y.measurements).map((e) => [e.a, e.b, num3(e.p.distance)]);
70086
+ return { name: str60(name), y, vertices, fiducials, meas, elevation: num3(y.elevation) };
69917
70087
  });
69918
70088
  const refName = raw.some((l) => l.name === doc.reference_level_name) ? String(doc.reference_level_name) : raw[0].name;
69919
70089
  const ref = raw.find((l) => l.name === refName);
@@ -69987,20 +70157,20 @@ function fromBuildingYaml(doc) {
69987
70157
  const extra = {};
69988
70158
  if (e.p.texture_name !== void 0 && e.p.texture_name !== "default")
69989
70159
  extra.textureName = str60(e.p.texture_name);
69990
- if (e.p.alpha !== void 0 && num2(e.p.alpha, 1) !== 1)
69991
- extra.alpha = clamp3(num2(e.p.alpha, 1), 0, 1);
69992
- if (e.p.texture_height !== void 0 && num2(e.p.texture_height, 2.5) !== 2.5)
69993
- extra.textureHeight = clamp3(num2(e.p.texture_height, 2.5), 0, 100);
69994
- if (e.p.texture_width !== void 0 && num2(e.p.texture_width, 1) !== 1)
69995
- extra.textureWidth = clamp3(num2(e.p.texture_width, 1), 0, 100);
69996
- if (e.p.texture_scale !== void 0 && num2(e.p.texture_scale, 1) !== 1)
69997
- extra.textureScale = clamp3(num2(e.p.texture_scale, 1), 0, 100);
70160
+ if (e.p.alpha !== void 0 && num3(e.p.alpha, 1) !== 1)
70161
+ extra.alpha = clamp3(num3(e.p.alpha, 1), 0, 1);
70162
+ if (e.p.texture_height !== void 0 && num3(e.p.texture_height, 2.5) !== 2.5)
70163
+ extra.textureHeight = clamp3(num3(e.p.texture_height, 2.5), 0, 100);
70164
+ if (e.p.texture_width !== void 0 && num3(e.p.texture_width, 1) !== 1)
70165
+ extra.textureWidth = clamp3(num3(e.p.texture_width, 1), 0, 100);
70166
+ if (e.p.texture_scale !== void 0 && num3(e.p.texture_scale, 1) !== 1)
70167
+ extra.textureScale = clamp3(num3(e.p.texture_scale, 1), 0, 100);
69998
70168
  level2.walls.push({ v1: ids2[e.a], v2: ids2[e.b], ...extra });
69999
70169
  }
70000
70170
  for (const e of edgeList(lv.y.doors).filter(ok)) {
70001
70171
  const type = String(e.p.type ?? "hinged");
70002
- const degrees = clamp3(num2(e.p.motion_degrees, 90), -360, 360);
70003
- const ratio = clamp3(num2(e.p.right_left_ratio, 1), 0, 10);
70172
+ const degrees = clamp3(num3(e.p.motion_degrees, 90), -360, 360);
70173
+ const ratio = clamp3(num3(e.p.right_left_ratio, 1), 0, 10);
70004
70174
  const plugin = str60(e.p.plugin ?? "normal");
70005
70175
  level2.doors.push({
70006
70176
  name: str60(e.p.name ?? "").trim() || `door_${level2.doors.length + 1}`,
@@ -70009,13 +70179,13 @@ function fromBuildingYaml(doc) {
70009
70179
  type: ["hinged", "double_hinged", "sliding", "double_sliding"].includes(type) ? type : "hinged",
70010
70180
  ...e.p.motion_axis === "end" ? { motionAxis: "end" } : {},
70011
70181
  ...degrees !== 90 ? { motionDegrees: degrees } : {},
70012
- ...num2(e.p.motion_direction, 1) < 0 ? { motionDirection: -1 } : {},
70182
+ ...num3(e.p.motion_direction, 1) < 0 ? { motionDirection: -1 } : {},
70013
70183
  ...ratio !== 1 ? { rightLeftRatio: ratio } : {},
70014
70184
  ...plugin !== "normal" ? { plugin } : {}
70015
70185
  });
70016
70186
  }
70017
70187
  for (const e of edgeList(lv.y.lanes).filter(ok)) {
70018
- const gi = Math.round(num2(e.p.graph_idx, 0));
70188
+ const gi = Math.round(num3(e.p.graph_idx, 0));
70019
70189
  if (gi < 0 || gi > 8) {
70020
70190
  warnings.push(`Floor ${lv.name}: a lane on graph ${gi} was skipped (graphs 0-8 only).`);
70021
70191
  continue;
@@ -70028,14 +70198,14 @@ function fromBuildingYaml(doc) {
70028
70198
  graphIdx: gi,
70029
70199
  bidirectional: e.p.bidirectional === true,
70030
70200
  ...orientation ? { orientation } : {},
70031
- ...num2(e.p.speed_limit) > 0 ? { speedLimit: clamp3(num2(e.p.speed_limit), 0, 20) } : {},
70201
+ ...num3(e.p.speed_limit) > 0 ? { speedLimit: clamp3(num3(e.p.speed_limit), 0, 20) } : {},
70032
70202
  ...e.p.mutex ? { mutex: str60(e.p.mutex) } : {},
70033
70203
  ...e.p.demo_mock_floor_name ? { demoMockFloorName: str60(e.p.demo_mock_floor_name) } : {},
70034
70204
  ...e.p.demo_mock_lift_name ? { demoMockLiftName: str60(e.p.demo_mock_lift_name) } : {}
70035
70205
  });
70036
70206
  }
70037
70207
  for (const e of edgeList(lv.y.measurements).filter(ok)) {
70038
- const d = num2(e.p.distance);
70208
+ const d = num3(e.p.distance);
70039
70209
  if (d >= 0.01)
70040
70210
  level2.measurements.push({ v1: ids2[e.a], v2: ids2[e.b], distanceM: Math.min(d, 1e4) });
70041
70211
  }
@@ -70066,14 +70236,14 @@ function fromBuildingYaml(doc) {
70066
70236
  if (ly?.reference_floor_name && !levelNames.has(ly.reference_floor_name)) {
70067
70237
  warnings.push(`Lift ${str60(liftName)}: its reference floor "${str60(ly.reference_floor_name)}" is not in the file; ${refName} was used.`);
70068
70238
  }
70069
- const c = applyXform(xf(refFloor), { x: num2(ly?.x), y: num2(ly?.y) * flip });
70239
+ const c = applyXform(xf(refFloor), { x: num3(ly?.x), y: num3(ly?.y) * flip });
70070
70240
  const doors = Object.entries(ly?.doors ?? {}).slice(0, 8).map(([dn, d]) => ({
70071
70241
  name: str60(dn),
70072
- type: MSG_LIFT_DOOR_TYPE[Math.round(num2(d?.door_type, 2))] ?? "double_sliding",
70073
- x: r3(clamp3(num2(d?.x), -20, 20)),
70074
- y: r3(clamp3(num2(d?.y), -20, 20)),
70075
- widthM: r3(clamp3(num2(d?.width, 1), 0.3, 10)),
70076
- axisYawRad: clamp3(num2(d?.motion_axis_orientation), -10, 10)
70242
+ type: MSG_LIFT_DOOR_TYPE[Math.round(num3(d?.door_type, 2))] ?? "double_sliding",
70243
+ x: r3(clamp3(num3(d?.x), -20, 20)),
70244
+ y: r3(clamp3(num3(d?.y), -20, 20)),
70245
+ widthM: r3(clamp3(num3(d?.width, 1), 0.3, 10)),
70246
+ axisYawRad: clamp3(num3(d?.motion_axis_orientation), -10, 10)
70077
70247
  }));
70078
70248
  const doorNames = new Set(doors.map((d) => d.name));
70079
70249
  const levelDoors = Object.entries(ly?.level_doors ?? {}).filter(([level2]) => levelNames.has(level2)).map(([level2, list]) => ({ level: level2, doors: (Array.isArray(list) ? list : []).map(str60).filter((d) => doorNames.has(d)) }));
@@ -70082,9 +70252,9 @@ function fromBuildingYaml(doc) {
70082
70252
  name: str60(liftName),
70083
70253
  x: r3(c.x),
70084
70254
  y: r3(c.y),
70085
- yawRad: clamp3(num2(ly?.yaw), -10, 10),
70086
- widthM: r3(clamp3(num2(ly?.width, 2), 0.3, 20)),
70087
- depthM: r3(clamp3(num2(ly?.depth, 2), 0.3, 20)),
70255
+ yawRad: clamp3(num3(ly?.yaw), -10, 10),
70256
+ widthM: r3(clamp3(num3(ly?.width, 2), 0.3, 20)),
70257
+ depthM: r3(clamp3(num3(ly?.depth, 2), 0.3, 20)),
70088
70258
  referenceFloor: refFloor,
70089
70259
  ...floorName(ly?.initial_floor_name) ? { initialFloor: floorName(ly.initial_floor_name) } : {},
70090
70260
  ...floorName(ly?.lowest_floor) ? { lowestFloor: floorName(ly.lowest_floor) } : {},
@@ -70138,7 +70308,7 @@ function fromNavGraph(doc, graphIdx) {
70138
70308
  level2.vertices = verts.map((v, k) => {
70139
70309
  const p = v?.[2] && typeof v[2] === "object" ? v[2] : {};
70140
70310
  const params = fileVertexParams(p);
70141
- return { id: `v${k + 1}`, x: r3(num2(v?.[0])), y: r3(num2(v?.[1])), ...p.name ? { name: str60(p.name) } : {}, ...Object.keys(params).length ? { params } : {} };
70311
+ return { id: `v${k + 1}`, x: r3(num3(v?.[0])), y: r3(num3(v?.[1])), ...p.name ? { name: str60(p.name) } : {}, ...Object.keys(params).length ? { params } : {} };
70142
70312
  });
70143
70313
  if (Array.isArray(ly?.lanes) && ly.lanes.length > 1e4)
70144
70314
  throw new RmfImportError(`Floor ${str60(name)} has more than 10000 one-way lanes - more than a building map can hold.`);
@@ -70178,7 +70348,7 @@ function fromNavGraph(doc, graphIdx) {
70178
70348
  graphIdx,
70179
70349
  bidirectional,
70180
70350
  ...o === "forward" || o === "backward" ? { orientation: o } : {},
70181
- ...num2(p.speed_limit) > 0 ? { speedLimit: clamp3(num2(p.speed_limit), 0, 20) } : {},
70351
+ ...num3(p.speed_limit) > 0 ? { speedLimit: clamp3(num3(p.speed_limit), 0, 20) } : {},
70182
70352
  ...p.mutex ? { mutex: str60(p.mutex) } : {},
70183
70353
  ...p.demo_mock_floor_name ? { demoMockFloorName: str60(p.demo_mock_floor_name) } : {},
70184
70354
  ...p.demo_mock_lift_name ? { demoMockLiftName: str60(p.demo_mock_lift_name) } : {}
@@ -82571,7 +82741,7 @@ function useAccessManagementController() {
82571
82741
  liftName,
82572
82742
  unit = [],
82573
82743
  createdAt,
82574
- updatedAt,
82744
+ updatedAt: updatedAt2,
82575
82745
  startDate,
82576
82746
  endDate,
82577
82747
  isWinsland
@@ -82607,7 +82777,7 @@ function useAccessManagementController() {
82607
82777
  startDate,
82608
82778
  endDate,
82609
82779
  createdAt,
82610
- updatedAt,
82780
+ updatedAt: updatedAt2,
82611
82781
  isWinsland
82612
82782
  });
82613
82783
  if (error) {
@@ -82629,7 +82799,7 @@ function useAccessManagementController() {
82629
82799
  startDate,
82630
82800
  endDate,
82631
82801
  createdAt,
82632
- updatedAt,
82802
+ updatedAt: updatedAt2,
82633
82803
  isWinsland
82634
82804
  });
82635
82805
  return res.status(201).json({
@@ -106646,6 +106816,7 @@ export {
106646
106816
  OUNITECH_BRAND,
106647
106817
  OUNITECH_BRAND_DEFINITION,
106648
106818
  OUNITECH_CAPABILITIES,
106819
+ OUNITECH_FRESH_MS,
106649
106820
  OUNITECH_PENDING_COMMANDS,
106650
106821
  OUNITECH_REGION_BASE_URLS,
106651
106822
  OUNITECH_TIMESTAMP_FORMAT,
@@ -107013,6 +107184,7 @@ export {
107013
107184
  orgRoleSets,
107014
107185
  orgSchema,
107015
107186
  ounitechFault,
107187
+ ounitechJobWords,
107016
107188
  ounitechRobotFromHomeRow,
107017
107189
  overnight_parking_requests_namespace_collection,
107018
107190
  padbotAccountKey,