@7365admin1/core 3.64.5-staging.303 → 3.64.5-staging.304

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.
@@ -0,0 +1,27 @@
1
+ ---
2
+ "@7365admin1/core": minor
3
+ ---
4
+
5
+ Manpower live status: an authenticated namespace beside the open one
6
+
7
+ `/manpower` streams every client site's live staffing level — how many guards are
8
+ actually on shift against how many were promised — to anyone who connects, with no
9
+ credential of any kind.
10
+
11
+ This adds `/manpower-live`, carrying exactly the same `manpower-status-update`
12
+ events, which admits a socket only when the handshake presents a session id that
13
+ resolves to a live session. Every refusal is an identical `Unauthorized`, and a
14
+ session store that is down refuses rather than letting everyone in.
15
+
16
+ `/manpower` itself is deliberately unchanged: the Capacitor guard app installed on
17
+ phones today and the Nuxt security screen both connect to it with no credential and
18
+ would be cut off the moment it were tightened. Every update is emitted to both, so
19
+ the two feeds can never disagree, and both namespaces share one connection handler,
20
+ so a client on the authenticated feed still starts the poll and still gets an
21
+ immediate snapshot.
22
+
23
+ A live session is the whole check, deliberately. Scoping the feed to the caller's
24
+ own sites is not possible today: manpower lives in HRM Labs' vendor id space, none
25
+ of those site ids match ours, and no field links the two — a site check would empty
26
+ the screen for the one customer using it. That mapping is a schema change and
27
+ belongs to the leads.
package/dist/index.js CHANGED
@@ -536,13 +536,13 @@ var require_logger = __commonJS({
536
536
  "use strict";
537
537
  exports.__esModule = true;
538
538
  var _utils = require_utils();
539
- var logger226 = {
539
+ var logger227 = {
540
540
  methodMap: ["debug", "info", "warn", "error"],
541
541
  level: "info",
542
542
  // Maps a given level value to the `methodMap` indexes above.
543
543
  lookupLevel: function lookupLevel(level) {
544
544
  if (typeof level === "string") {
545
- var levelMap = _utils.indexOf(logger226.methodMap, level.toLowerCase());
545
+ var levelMap = _utils.indexOf(logger227.methodMap, level.toLowerCase());
546
546
  if (levelMap >= 0) {
547
547
  level = levelMap;
548
548
  } else {
@@ -553,9 +553,9 @@ var require_logger = __commonJS({
553
553
  },
554
554
  // Can be overridden in the host environment
555
555
  log: function log(level) {
556
- level = logger226.lookupLevel(level);
557
- if (typeof console !== "undefined" && logger226.lookupLevel(logger226.level) <= level) {
558
- var method = logger226.methodMap[level];
556
+ level = logger227.lookupLevel(level);
557
+ if (typeof console !== "undefined" && logger227.lookupLevel(logger227.level) <= level) {
558
+ var method = logger227.methodMap[level];
559
559
  if (!console[method]) {
560
560
  method = "log";
561
561
  }
@@ -566,7 +566,7 @@ var require_logger = __commonJS({
566
566
  }
567
567
  }
568
568
  };
569
- exports["default"] = logger226;
569
+ exports["default"] = logger227;
570
570
  module2.exports = exports["default"];
571
571
  }
572
572
  });
@@ -87847,6 +87847,52 @@ var isWithinHour = (alertTime, timeNow) => {
87847
87847
  var import_node_server_utils264 = require("@7365admin1/node-server-utils");
87848
87848
  var import_mongodb162 = require("mongodb");
87849
87849
  var import_moment_timezone11 = __toESM(require("moment-timezone"));
87850
+
87851
+ // src/utils/socket-session.util.ts
87852
+ var MANPOWER_LIVE_NAMESPACE = "/manpower-live";
87853
+ function sidFromHandshake(handshake) {
87854
+ const cookie = String(handshake?.headers?.cookie ?? "");
87855
+ const fromCookie = /(?:^|;\s*)sid=([^;]*)/.exec(cookie);
87856
+ if (fromCookie) {
87857
+ const value = decodeURIComponent(fromCookie[1]).trim();
87858
+ if (value)
87859
+ return value;
87860
+ }
87861
+ for (const key of ["sid", "token"]) {
87862
+ const value = handshake?.auth?.[key];
87863
+ if (typeof value === "string" && value.trim())
87864
+ return value.trim();
87865
+ }
87866
+ const header = handshake?.headers?.authorization;
87867
+ if (typeof header === "string" && header.trim()) {
87868
+ const value = header.trim();
87869
+ return value.toLowerCase().startsWith("bearer ") ? value.slice("bearer ".length).trim() : value;
87870
+ }
87871
+ return "";
87872
+ }
87873
+ function userIdOfSession(session) {
87874
+ if (!session || typeof session !== "object")
87875
+ return "";
87876
+ const record = session;
87877
+ return String(record.user ?? record._id ?? "").trim();
87878
+ }
87879
+ async function authoriseSocketSession(handshake, readSession) {
87880
+ const sid = sidFromHandshake(handshake);
87881
+ if (!sid)
87882
+ throw new Error("Unauthorized");
87883
+ let session;
87884
+ try {
87885
+ session = await readSession(sid);
87886
+ } catch {
87887
+ throw new Error("Unauthorized");
87888
+ }
87889
+ const userId = userIdOfSession(session);
87890
+ if (!userId)
87891
+ throw new Error("Unauthorized");
87892
+ return userId;
87893
+ }
87894
+
87895
+ // src/events/manpower.event.ts
87850
87896
  async function manpowerEvents(io) {
87851
87897
  let intervalId = null;
87852
87898
  let activeConnections = 0;
@@ -87907,8 +87953,7 @@ async function manpowerEvents(io) {
87907
87953
  newStatus = "Over";
87908
87954
  else if (actual < expected)
87909
87955
  newStatus = "Under";
87910
- const namespace2 = `/manpower`;
87911
- io.of(namespace2).emit("manpower-status-update", {
87956
+ const update = {
87912
87957
  siteId: doc.siteId,
87913
87958
  siteName: doc.siteName,
87914
87959
  shift: shift.key,
@@ -87916,7 +87961,9 @@ async function manpowerEvents(io) {
87916
87961
  actual,
87917
87962
  expected,
87918
87963
  selectedDateSGT
87919
- });
87964
+ };
87965
+ io.of("/manpower").emit("manpower-status-update", update);
87966
+ io.of(MANPOWER_LIVE_NAMESPACE).emit("manpower-status-update", update);
87920
87967
  }
87921
87968
  }
87922
87969
  };
@@ -87936,7 +87983,7 @@ async function manpowerEvents(io) {
87936
87983
  console.log(" Interval stopped.");
87937
87984
  }
87938
87985
  };
87939
- io.of("/manpower").on("connection", (socket) => {
87986
+ const onConnection = (socket) => {
87940
87987
  activeConnections += 1;
87941
87988
  const date = socket.handshake.query.date;
87942
87989
  if (activeConnections === 1) {
@@ -87951,7 +87998,26 @@ async function manpowerEvents(io) {
87951
87998
  stopInterval();
87952
87999
  }
87953
88000
  });
88001
+ };
88002
+ io.of("/manpower").on("connection", onConnection);
88003
+ const live = io.of(MANPOWER_LIVE_NAMESPACE);
88004
+ live.use(async (socket, next) => {
88005
+ try {
88006
+ const { getCache } = (0, import_node_server_utils264.useCache)("sessions");
88007
+ socket.data.userId = await authoriseSocketSession(
88008
+ socket.handshake,
88009
+ (sid) => getCache(`sid:${sid}`)
88010
+ );
88011
+ next();
88012
+ } catch (error) {
88013
+ import_node_server_utils264.logger.log({
88014
+ level: "debug",
88015
+ message: `[manpower] refused a socket: ${error?.message}`
88016
+ });
88017
+ next(new Error("Unauthorized"));
88018
+ }
87954
88019
  });
88020
+ live.on("connection", onConnection);
87955
88021
  }
87956
88022
 
87957
88023
  // src/services/reddot-payment.service.ts