@7365admin1/core 3.48.1-staging.173 → 3.48.1-staging.174

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.d.ts CHANGED
@@ -10913,6 +10913,7 @@ declare function useHidAmicoService(): {
10913
10913
  includePassword?: boolean;
10914
10914
  }) => Promise<THidAmicoReader>;
10915
10915
  authorizeReaderUser: (readerId: string, hidUserIdValue: string | number, userId: string) => Promise<THidAmicoReader>;
10916
+ authorizeVisitorForMember: (readerId: string, visitorId: string, userId: string) => Promise<THidAmicoReader>;
10916
10917
  authorizeSiteForCaller: (siteId: string, userId: string) => Promise<{
10917
10918
  site: mongodb.WithId<bson.Document> | null;
10918
10919
  siteObjectId: bson.ObjectId;
@@ -10936,6 +10937,23 @@ declare function useHidAmicoService(): {
10936
10937
  pages: number;
10937
10938
  pageRange: string;
10938
10939
  }>;
10940
+ getMemberReaderInfo: (readerId: string, userId: string) => Promise<{
10941
+ _id: string;
10942
+ name: string;
10943
+ location: string | undefined;
10944
+ status: "deleted" | "active" | "inactive" | "offline" | undefined;
10945
+ portalId: number | undefined;
10946
+ portalName: string | undefined;
10947
+ readerModel: "unknown" | "VL35LF" | "VL70LF" | undefined;
10948
+ cardReadingMode: "unconfigured" | "pacs" | "csn" | "csn_for_mifare" | undefined;
10949
+ capabilities: {
10950
+ card: boolean;
10951
+ facial: boolean;
10952
+ qr: boolean;
10953
+ pin: boolean;
10954
+ intercom: boolean;
10955
+ };
10956
+ }>;
10939
10957
  discoverReader: (value: Pick<THidAmicoReader, "baseUrl" | "username" | "password"> & Partial<Pick<THidAmicoReader, "readerModel">>) => Promise<{
10940
10958
  deviceId: string;
10941
10959
  serial: string;
@@ -11084,7 +11102,7 @@ declare function useHidAmicoService(): {
11084
11102
  pages: number;
11085
11103
  pageRange: string;
11086
11104
  }>;
11087
- listReaderUsers: (readerId: string, page?: number, limit?: number, search?: string, status?: "mapped" | "unmapped" | "", includeVisitors?: boolean) => Promise<{
11105
+ listReaderUsers: (readerId: string, page?: number, limit?: number, search?: string, status?: "mapped" | "unmapped" | "", includeVisitors?: boolean, userType?: "all" | "user" | "visitor") => Promise<{
11088
11106
  items: {
11089
11107
  reader: string;
11090
11108
  hidUserId: string;
@@ -11096,7 +11114,6 @@ declare function useHidAmicoService(): {
11096
11114
  facialEnrolled: boolean;
11097
11115
  };
11098
11116
  isAdministrator: boolean;
11099
- _id?: bson.ObjectId | undefined;
11100
11117
  }[];
11101
11118
  page: number;
11102
11119
  limit: number;
@@ -11153,6 +11170,15 @@ declare function useHidAmicoService(): {
11153
11170
  validFrom: string;
11154
11171
  expiresAt: string;
11155
11172
  }>;
11173
+ getVisitorQrForMember: (readerId: string, visitorId: string, userId: string) => Promise<{
11174
+ readerId: string;
11175
+ visitorId: string;
11176
+ qrValue: string;
11177
+ expiresAt: string;
11178
+ portalId: number | undefined;
11179
+ portalName: string | undefined;
11180
+ readerName: string;
11181
+ } | null>;
11156
11182
  revokeVisitorQr: (readerId: string, visitorId: string) => Promise<{
11157
11183
  readerId: string;
11158
11184
  visitorId: string;
@@ -11365,6 +11391,7 @@ declare function useHidAmicoController(): {
11365
11391
  authorizeManage: (req: Request, _res: Response, next: NextFunction) => Promise<void>;
11366
11392
  authorizeVisitor: (req: Request, _res: Response, next: NextFunction) => Promise<void>;
11367
11393
  listReaders: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11394
+ getMemberReaderInfo: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11368
11395
  discoverReader: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11369
11396
  createReader: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11370
11397
  updateReader: (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -11400,6 +11427,7 @@ declare function useHidAmicoController(): {
11400
11427
  setConfiguration: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11401
11428
  runObjectOperation: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11402
11429
  issueVisitorQr: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11430
+ getVisitorQr: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11403
11431
  revokeVisitorQr: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11404
11432
  getProfileFacial: (req: Request, res: Response, next: NextFunction) => Promise<void>;
11405
11433
  setProfileFacial: (req: Request, res: Response, next: NextFunction) => Promise<void>;
package/dist/index.js CHANGED
@@ -43262,7 +43262,7 @@ var schemaHidAmicoIdentity = import_joi64.default.object({
43262
43262
  var schemaCreateHidAmicoIdentity = import_joi64.default.object({
43263
43263
  site: objectIdSchema2.optional(),
43264
43264
  hidUserId: import_joi64.default.alternatives(import_joi64.default.string(), import_joi64.default.number()).optional().allow(null, ""),
43265
- registration: import_joi64.default.string().trim().required(),
43265
+ registration: import_joi64.default.string().trim().optional().allow(""),
43266
43266
  cardNo: import_joi64.default.string().optional().allow(null, ""),
43267
43267
  person: objectIdSchema2.optional().allow(null, ""),
43268
43268
  user: objectIdSchema2.optional().allow(null, ""),
@@ -43409,7 +43409,8 @@ var schemaHidAmicoReaderUserQuery = import_joi64.default.object({
43409
43409
  limit: import_joi64.default.number().integer().min(1).max(100).default(10),
43410
43410
  search: import_joi64.default.string().trim().max(100).allow("").default(""),
43411
43411
  status: import_joi64.default.string().valid("mapped", "unmapped").allow("").default(""),
43412
- includeVisitors: import_joi64.default.boolean().default(false)
43412
+ includeVisitors: import_joi64.default.boolean().default(false),
43413
+ userType: import_joi64.default.string().valid("all", "user", "visitor").default("all")
43413
43414
  });
43414
43415
  var schemaHidAmicoAccessLogQuery = import_joi64.default.object({
43415
43416
  page: import_joi64.default.number().integer().min(1).default(1),
@@ -44928,18 +44929,34 @@ function getSecretKey() {
44928
44929
  return import_crypto2.default.createHash("sha256").update(secret).digest();
44929
44930
  }
44930
44931
  function getReaderCapabilities(readerModel, firmwareVersion) {
44932
+ const isAmicoBiometricReader2 = readerModel === "VL35LF" || readerModel === "VL70LF";
44931
44933
  return {
44932
- card: hidFirmwareAtLeast(firmwareVersion, "6.5.1"),
44934
+ // VL35LF/VL70LF expose the relevant credential functions even when the
44935
+ // installed product firmware reports a 2.x version rather than the legacy
44936
+ // API version scheme.
44937
+ card: isAmicoBiometricReader2 || hidFirmwareAtLeast(firmwareVersion, "6.5.1"),
44933
44938
  // VL35LF and VL70LF are biometric readers. Some deployed readers report
44934
44939
  // their device firmware as 2.x even though their face API is available.
44935
- facial: readerModel === "VL35LF" || readerModel === "VL70LF",
44936
- qr: hidFirmwareAtLeast(firmwareVersion, "6.5.1"),
44937
- pin: hidFirmwareAtLeast(firmwareVersion, "6.9.0"),
44940
+ facial: isAmicoBiometricReader2,
44941
+ qr: isAmicoBiometricReader2 || hidFirmwareAtLeast(firmwareVersion, "6.5.1"),
44942
+ pin: isAmicoBiometricReader2 || hidFirmwareAtLeast(firmwareVersion, "6.9.0"),
44938
44943
  intercom: readerModel === "VL70LF"
44939
44944
  };
44940
44945
  }
44946
+ function isAmicoBiometricReader(reader) {
44947
+ return reader.readerModel === "VL35LF" || reader.readerModel === "VL70LF";
44948
+ }
44941
44949
  function readerSupportsFacial(reader) {
44942
- return reader.capabilities?.facial === true || reader.readerModel === "VL35LF" || reader.readerModel === "VL70LF";
44950
+ return reader.capabilities?.facial === true || isAmicoBiometricReader(reader);
44951
+ }
44952
+ function readerSupportsCredential(reader, capability) {
44953
+ if (reader.capabilities?.[capability] === true)
44954
+ return true;
44955
+ if (capability === "facial")
44956
+ return readerSupportsFacial(reader);
44957
+ if (capability === "intercom")
44958
+ return reader.readerModel === "VL70LF";
44959
+ return isAmicoBiometricReader(reader);
44943
44960
  }
44944
44961
  function getMonitorConfiguration(callbackToken) {
44945
44962
  const configured = String(process.env.HID_AMICO_MONITOR_URL || "").trim();
@@ -45095,14 +45112,25 @@ function createVisitorQrCredential(visitorId, readerId) {
45095
45112
  }
45096
45113
  async function configureVisitorQrReader(client) {
45097
45114
  const requestedConfiguration = {
45115
+ general: ["online", "local_identification"],
45098
45116
  face_id: ["qrcode_legacy_mode_enabled"],
45099
45117
  identifier: ["qrcode_identification_enabled", "multi_factor_authentication"]
45100
45118
  };
45101
45119
  const currentConfiguration = await client.getConfiguration(requestedConfiguration);
45102
45120
  const current = isUnknownRecord2(currentConfiguration) ? currentConfiguration : {};
45121
+ const currentGeneral = isUnknownRecord2(current.general) ? current.general : {};
45103
45122
  const currentFaceId = isUnknownRecord2(current.face_id) ? current.face_id : {};
45104
45123
  const currentIdentifier = isUnknownRecord2(current.identifier) ? current.identifier : {};
45105
45124
  let changed = false;
45125
+ if (String(currentGeneral.online ?? "") !== "0" || String(currentGeneral.local_identification ?? "") !== "1") {
45126
+ await client.setConfiguration({
45127
+ general: {
45128
+ online: "0",
45129
+ local_identification: "1"
45130
+ }
45131
+ });
45132
+ changed = true;
45133
+ }
45106
45134
  if (String(currentFaceId.qrcode_legacy_mode_enabled ?? "") !== VISITOR_QR_FORMAT) {
45107
45135
  await client.setConfiguration({
45108
45136
  face_id: { qrcode_legacy_mode_enabled: VISITOR_QR_FORMAT }
@@ -45122,9 +45150,10 @@ async function configureVisitorQrReader(client) {
45122
45150
  }
45123
45151
  const configuration = await client.getConfiguration(requestedConfiguration);
45124
45152
  const savedConfiguration = isUnknownRecord2(configuration) ? configuration : {};
45153
+ const general = isUnknownRecord2(savedConfiguration.general) ? savedConfiguration.general : {};
45125
45154
  const faceId = isUnknownRecord2(savedConfiguration.face_id) ? savedConfiguration.face_id : {};
45126
45155
  const identifier = isUnknownRecord2(savedConfiguration.identifier) ? savedConfiguration.identifier : {};
45127
- if (String(faceId.qrcode_legacy_mode_enabled ?? "") !== VISITOR_QR_FORMAT || String(identifier.qrcode_identification_enabled ?? "") !== "1" || String(identifier.multi_factor_authentication ?? "") !== "0") {
45156
+ if (String(general.online ?? "") !== "0" || String(general.local_identification ?? "") !== "1" || String(faceId.qrcode_legacy_mode_enabled ?? "") !== VISITOR_QR_FORMAT || String(identifier.qrcode_identification_enabled ?? "") !== "1" || String(identifier.multi_factor_authentication ?? "") !== "0") {
45128
45157
  throw new import_node_server_utils132.BadRequestError(
45129
45158
  "The HID reader did not retain alphanumeric QR configuration."
45130
45159
  );
@@ -46357,6 +46386,17 @@ function useHidAmicoService() {
46357
46386
  return reader;
46358
46387
  return authorizeReader(readerId, userId);
46359
46388
  }
46389
+ async function authorizeVisitorForMember(readerId, visitorId, userId) {
46390
+ const reader = await entitleReaderForSelf(readerId, userId);
46391
+ const visitor = await visitorRepo.getVisitorTransactionById(visitorId);
46392
+ const visitorSiteId = String(visitor?.site?._id || visitor?.site || "");
46393
+ if (!visitorSiteId || visitorSiteId !== String(reader.site || "")) {
46394
+ throw new import_node_server_utils132.BadRequestError("Visitor and HID reader must belong to the same site.");
46395
+ }
46396
+ if (String(visitor?.createdBy || "") === userId)
46397
+ return reader;
46398
+ return authorizeReader(readerId, userId);
46399
+ }
46360
46400
  async function getActiveReader(id) {
46361
46401
  const reader = await repo.getById(id, { includePassword: true });
46362
46402
  if (reader.enabled === false || reader.status === "inactive" || reader.status === "deleted") {
@@ -46365,7 +46405,7 @@ function useHidAmicoService() {
46365
46405
  return reader;
46366
46406
  }
46367
46407
  function assertReaderCapability(reader, capability) {
46368
- if (reader.capabilities?.[capability] || capability === "facial" && readerSupportsFacial(reader)) {
46408
+ if (readerSupportsCredential(reader, capability)) {
46369
46409
  return;
46370
46410
  }
46371
46411
  const requirement = capability === "pin" ? "firmware 6.9.0 or newer" : capability === "intercom" ? "a VL70LF reader" : "firmware 6.5.1 or newer";
@@ -46809,6 +46849,26 @@ function useHidAmicoService() {
46809
46849
  async function listReaders(value) {
46810
46850
  return repo.list(value);
46811
46851
  }
46852
+ async function getMemberReaderInfo(readerId, userId) {
46853
+ const reader = await entitleReaderForSelf(readerId, userId);
46854
+ return {
46855
+ _id: String(reader._id),
46856
+ name: reader.name,
46857
+ location: reader.location,
46858
+ status: reader.status,
46859
+ portalId: reader.portalId,
46860
+ portalName: reader.portalName,
46861
+ readerModel: reader.readerModel,
46862
+ cardReadingMode: reader.cardReadingMode,
46863
+ capabilities: {
46864
+ card: readerSupportsCredential(reader, "card"),
46865
+ facial: readerSupportsFacial(reader),
46866
+ qr: readerSupportsCredential(reader, "qr"),
46867
+ pin: readerSupportsCredential(reader, "pin"),
46868
+ intercom: readerSupportsCredential(reader, "intercom")
46869
+ }
46870
+ };
46871
+ }
46812
46872
  async function deleteReader(id) {
46813
46873
  return repo.markDeleted(id);
46814
46874
  }
@@ -46983,7 +47043,7 @@ function useHidAmicoService() {
46983
47043
  async function listIdentities(value) {
46984
47044
  return repo.listIdentities(value);
46985
47045
  }
46986
- async function listReaderUsers(readerId, page = 1, limit = 10, search = "", status = "", includeVisitors = false) {
47046
+ async function listReaderUsers(readerId, page = 1, limit = 10, search = "", status = "", includeVisitors = false, userType = "all") {
46987
47047
  const reader = await getActiveReader(readerId);
46988
47048
  const offset = (page - 1) * limit;
46989
47049
  const client = new HidAmicoClient(reader);
@@ -47000,54 +47060,22 @@ function useHidAmicoService() {
47000
47060
  let rows = [];
47001
47061
  let reportedTotal = null;
47002
47062
  let hasMore = false;
47003
- if (!status) {
47004
- const response = await client.loadObjects({
47005
- object: "users",
47006
- where: { users: userWhere },
47007
- limit: 500,
47008
- offset: 0,
47009
- order: ["id", "ascending"]
47010
- });
47011
- const deviceRows = getHidObjectRows(response, "users").filter((row) => includeVisitors || Number(row.user_type_id) !== 1);
47012
- reportedTotal = deviceRows.length;
47013
- rows = deviceRows.slice(offset, offset + limit);
47014
- hasMore = offset + rows.length < deviceRows.length;
47015
- } else {
47016
- const linkedIdentities = await repo.listActiveIdentities(readerId);
47017
- const mappedUserIds = new Set(
47018
- linkedIdentities.map((identity) => String(identity.hidUserId || "")).filter(Boolean)
47019
- );
47020
- const matchedRows = [];
47021
- const targetCount = offset + limit + 1;
47022
- let deviceOffset = 0;
47023
- let exhausted = status === "mapped" && mappedUserIds.size === 0;
47024
- const chunkSize = 100;
47025
- while (!exhausted && matchedRows.length < targetCount) {
47026
- const response = await client.loadObjects({
47027
- object: "users",
47028
- where: { users: userWhere },
47029
- limit: chunkSize,
47030
- offset: deviceOffset,
47031
- order: ["id", "ascending"]
47032
- });
47033
- const batch = getHidObjectRows(response, "users");
47034
- batch.forEach((row) => {
47035
- if (!includeVisitors && Number(row.user_type_id) === 1)
47036
- return;
47037
- const mapped = mappedUserIds.has(String(row.id ?? ""));
47038
- if (status === "mapped" && mapped || status === "unmapped" && !mapped) {
47039
- matchedRows.push(row);
47040
- }
47041
- });
47042
- deviceOffset += batch.length;
47043
- exhausted = batch.length < chunkSize;
47044
- }
47045
- rows = matchedRows.slice(offset, offset + limit);
47046
- hasMore = matchedRows.length > offset + limit || !exhausted;
47047
- }
47048
- const userIds = rows.map((row) => String(row.id ?? "")).filter(Boolean);
47049
- const [identities, administratorFlags, facialUserIds] = await Promise.all([
47050
- repo.findIdentitiesByHidUserIds(readerId, userIds),
47063
+ const response = await client.loadObjects({
47064
+ object: "users",
47065
+ where: { users: userWhere },
47066
+ limit: 500,
47067
+ offset: 0,
47068
+ order: ["id", "ascending"]
47069
+ });
47070
+ const deviceRows = getHidObjectRows(response, "users");
47071
+ const filteredRows = deviceRows.filter((row) => {
47072
+ const isVisitor = Number(row.user_type_id) === 1;
47073
+ return userType === "visitor" ? isVisitor : userType === "user" ? !isVisitor : true;
47074
+ });
47075
+ reportedTotal = filteredRows.length;
47076
+ rows = filteredRows.slice(offset, offset + limit);
47077
+ hasMore = offset + rows.length < filteredRows.length;
47078
+ const [administratorFlags, facialUserIds] = await Promise.all([
47051
47079
  Promise.all(rows.map(async (row) => {
47052
47080
  const userId = Number(row.id);
47053
47081
  if (!Number.isSafeInteger(userId) || userId <= 0)
@@ -47062,24 +47090,17 @@ function useHidAmicoService() {
47062
47090
  })),
47063
47091
  readerSupportsFacial(reader) ? client.listUserImageIds().catch(() => []) : Promise.resolve([])
47064
47092
  ]);
47065
- const identityMap = new Map(
47066
- identities.map((identity) => [String(identity.hidUserId), identity])
47067
- );
47068
47093
  const facialUserIdSet = new Set(facialUserIds.map(String));
47069
47094
  const items = rows.map((row, index) => {
47070
- const identity = identityMap.get(String(row.id ?? ""));
47071
- const identityMetadata = identity && isUnknownRecord2(identity.metadata) ? identity.metadata : {};
47072
- const facialEnrolled = facialUserIdSet.has(String(row.id ?? "")) || identityMetadata.facialEnrolled === true;
47095
+ const facialEnrolled = facialUserIdSet.has(String(row.id ?? ""));
47073
47096
  return {
47074
47097
  ...row,
47075
- ...identity || {},
47076
47098
  reader: readerId,
47077
- hidUserId: String(row.id ?? identity?.hidUserId ?? ""),
47078
- registration: String(row.registration ?? identity?.registration ?? ""),
47099
+ hidUserId: String(row.id ?? ""),
47100
+ registration: String(row.registration ?? ""),
47079
47101
  metadata: {
47080
- ...identityMetadata,
47081
- name: String(row.name ?? identityMetadata.name ?? ""),
47082
- hidUserTypeId: row.user_type_id ?? identityMetadata.hidUserTypeId,
47102
+ name: String(row.name ?? ""),
47103
+ hidUserTypeId: row.user_type_id,
47083
47104
  facialEnrolled,
47084
47105
  ...facialEnrolled ? { facialData: String(row.id ?? "") } : {}
47085
47106
  },
@@ -47404,6 +47425,7 @@ function useHidAmicoService() {
47404
47425
  site: reader.site,
47405
47426
  type: "visitor_qr_reader_configured",
47406
47427
  payload: {
47428
+ operatingMode: "standalone",
47407
47429
  qrFormat: VISITOR_QR_FORMAT,
47408
47430
  qrcodeIdentificationEnabled: "1",
47409
47431
  multiFactorAuthentication: "0"
@@ -47550,7 +47572,11 @@ function useHidAmicoService() {
47550
47572
  site: reader.site
47551
47573
  });
47552
47574
  }
47553
- await repo.updateById(readerId, { status: "active", lastSeenAt: /* @__PURE__ */ new Date() });
47575
+ await repo.updateById(readerId, {
47576
+ status: "active",
47577
+ lastSeenAt: /* @__PURE__ */ new Date(),
47578
+ operatingMode: "standalone"
47579
+ });
47554
47580
  await repo.addEvent({
47555
47581
  reader: readerId,
47556
47582
  site: reader.site,
@@ -47593,6 +47619,32 @@ function useHidAmicoService() {
47593
47619
  await client.logout();
47594
47620
  }
47595
47621
  }
47622
+ async function getVisitorQrForMember(readerId, visitorId, userId) {
47623
+ const reader = await authorizeVisitorForMember(readerId, visitorId, userId);
47624
+ const result = await repo.listIdentities({
47625
+ reader: readerId,
47626
+ type: "visitor",
47627
+ status: "active",
47628
+ page: 1,
47629
+ limit: 500
47630
+ });
47631
+ const identities = Array.isArray(result.items) ? result.items : [];
47632
+ const identity = identities.find((item) => String(item.visitor || "") === visitorId);
47633
+ const metadata = identity && isUnknownRecord2(identity.metadata) ? identity.metadata : {};
47634
+ const qrValue = String(metadata.qrValue || identity?.cardNo || "").trim();
47635
+ const expiresAt = String(metadata.expiresAt || "").trim();
47636
+ if (!qrValue || !expiresAt)
47637
+ return null;
47638
+ return {
47639
+ readerId,
47640
+ visitorId,
47641
+ qrValue,
47642
+ expiresAt,
47643
+ portalId: reader.portalId,
47644
+ portalName: reader.portalName,
47645
+ readerName: reader.name
47646
+ };
47647
+ }
47596
47648
  async function getProfileFacial(readerId, userId) {
47597
47649
  const reader = await getActiveReader(readerId);
47598
47650
  const context = await getProfileEnrollmentContext(readerId, reader, userId);
@@ -47759,47 +47811,25 @@ function useHidAmicoService() {
47759
47811
  try {
47760
47812
  await client.login();
47761
47813
  const facialUserIds = await getReaderFacialUserIds(client);
47762
- const activeIdentities = await repo.listActiveIdentities(readerId);
47763
- const identitiesByUserId = new Map(
47764
- activeIdentities.filter((identity) => identity._id && identity.hidUserId !== void 0).map((identity) => [String(identity.hidUserId), identity])
47765
- );
47766
- const syncedAt = (/* @__PURE__ */ new Date()).toISOString();
47767
- let syncedCount = 0;
47768
- let unmappedCount = 0;
47769
- for (const hidUserId of facialUserIds) {
47770
- const identity = identitiesByUserId.get(String(hidUserId));
47771
- if (!identity?._id) {
47772
- unmappedCount += 1;
47773
- continue;
47774
- }
47775
- const metadata = isUnknownRecord2(identity.metadata) ? identity.metadata : {};
47776
- await repo.updateIdentity(identity._id, {
47777
- metadata: {
47778
- ...metadata,
47779
- facialData: String(hidUserId),
47780
- facialEnrolled: true,
47781
- facialSyncedAt: syncedAt
47782
- }
47783
- });
47784
- syncedCount += 1;
47785
- }
47786
- const message = [
47787
- facialUserIds.length ? `Detected ${facialUserIds.length} facial enrollment(s) on the HID reader.` : "No facial enrollments found on the HID reader.",
47788
- syncedCount ? `${syncedCount} mapped HID user(s) updated.` : "",
47789
- unmappedCount ? `${unmappedCount} facial enrollment(s) still need HID User Mapping.` : ""
47790
- ].filter(Boolean).join(" ");
47814
+ const message = facialUserIds.length ? `Found ${facialUserIds.length} Amico user(s) with facial data. Facial status and images are read directly from the reader.` : "No facial enrollments found on the HID reader.";
47791
47815
  await repo.updateById(readerId, { status: "active", lastSeenAt: /* @__PURE__ */ new Date() });
47792
47816
  await repo.addEvent({
47793
47817
  reader: readerId,
47794
47818
  site: reader.site,
47795
47819
  type: "facial_sync",
47796
- payload: { facialDetected: facialUserIds.length, syncedCount, unmappedCount }
47820
+ payload: {
47821
+ facialDetected: facialUserIds.length,
47822
+ source: "amico",
47823
+ hidUserIds: facialUserIds
47824
+ }
47797
47825
  });
47798
47826
  return {
47799
47827
  readerId,
47800
47828
  facialDetected: facialUserIds.length,
47801
- syncedCount,
47802
- unmappedCount,
47829
+ // Retain these response fields for existing clients. A direct refresh
47830
+ // has no unmapped records and does not write a second iService copy.
47831
+ syncedCount: facialUserIds.length,
47832
+ unmappedCount: 0,
47803
47833
  message
47804
47834
  };
47805
47835
  } catch (error) {
@@ -47976,7 +48006,7 @@ function useHidAmicoService() {
47976
48006
  async function listUserCards(readerId, hidUserIdValue) {
47977
48007
  const reader = await getActiveReader(readerId);
47978
48008
  assertReaderCapability(reader, "card");
47979
- const cardType = assertReaderCardProfile(reader);
48009
+ const cardType = reader.cardReadingMode === "pacs" || reader.cardReadingMode === "csn" ? reader.cardReadingMode : "unknown";
47980
48010
  const hidUserId = Number(hidUserIdValue);
47981
48011
  const client = new HidAmicoClient(reader);
47982
48012
  try {
@@ -48936,9 +48966,11 @@ function useHidAmicoService() {
48936
48966
  return {
48937
48967
  authorizeReader,
48938
48968
  authorizeReaderUser,
48969
+ authorizeVisitorForMember,
48939
48970
  authorizeSiteForCaller,
48940
48971
  authorizeHidAccess,
48941
48972
  listReaders,
48973
+ getMemberReaderInfo,
48942
48974
  discoverReader,
48943
48975
  createReader,
48944
48976
  updateReader,
@@ -48958,6 +48990,7 @@ function useHidAmicoService() {
48958
48990
  deleteIdentity,
48959
48991
  runObjectOperation,
48960
48992
  issueVisitorQr,
48993
+ getVisitorQrForMember,
48961
48994
  revokeVisitorQr,
48962
48995
  queueVisitorQrJob,
48963
48996
  processVisitorQrGatewayJobs,
@@ -85966,6 +85999,20 @@ function useHidAmicoController() {
85966
85999
  next(error2);
85967
86000
  }
85968
86001
  }
86002
+ async function getMemberReaderInfo(req, res, next) {
86003
+ const { error, value } = schemaHidAmicoReaderIdParams.validate(req.params);
86004
+ if (error) {
86005
+ next(new import_node_server_utils294.BadRequestError(error.message));
86006
+ return;
86007
+ }
86008
+ try {
86009
+ res.json({
86010
+ data: await service.getMemberReaderInfo(value.readerId, getAuthenticatedUserId(req))
86011
+ });
86012
+ } catch (requestError) {
86013
+ next(requestError);
86014
+ }
86015
+ }
85969
86016
  async function createReader(req, res, next) {
85970
86017
  const { error, value } = schemaHidAmicoReader.validate(req.body);
85971
86018
  if (error) {
@@ -86153,7 +86200,8 @@ function useHidAmicoController() {
86153
86200
  query2.value.limit,
86154
86201
  query2.value.search,
86155
86202
  query2.value.status,
86156
- query2.value.includeVisitors
86203
+ query2.value.includeVisitors,
86204
+ query2.value.userType
86157
86205
  ));
86158
86206
  } catch (error) {
86159
86207
  next(error);
@@ -86359,6 +86407,11 @@ function useHidAmicoController() {
86359
86407
  return;
86360
86408
  }
86361
86409
  try {
86410
+ await service.authorizeVisitorForMember(
86411
+ params.value.readerId,
86412
+ body.value.visitorId,
86413
+ getAuthenticatedUserId(req)
86414
+ );
86362
86415
  res.status(201).json({
86363
86416
  data: await service.issueVisitorQr(params.value.readerId, body.value)
86364
86417
  });
@@ -86366,6 +86419,24 @@ function useHidAmicoController() {
86366
86419
  next(error);
86367
86420
  }
86368
86421
  }
86422
+ async function getVisitorQr(req, res, next) {
86423
+ const { error, value } = schemaHidAmicoVisitorImageParams.validate(req.params);
86424
+ if (error) {
86425
+ next(new import_node_server_utils294.BadRequestError(error.message));
86426
+ return;
86427
+ }
86428
+ try {
86429
+ res.json({
86430
+ data: await service.getVisitorQrForMember(
86431
+ value.readerId,
86432
+ value.visitorId,
86433
+ getAuthenticatedUserId(req)
86434
+ )
86435
+ });
86436
+ } catch (requestError) {
86437
+ next(requestError);
86438
+ }
86439
+ }
86369
86440
  async function discoverReader(req, res, next) {
86370
86441
  const { error, value } = schemaDiscoverHidAmicoReader.validate(req.body);
86371
86442
  if (error) {
@@ -86399,7 +86470,7 @@ function useHidAmicoController() {
86399
86470
  return;
86400
86471
  }
86401
86472
  try {
86402
- await authorizeReader(req, value.readerId);
86473
+ await authorizeReaderUser(req, value.readerId, value.hidUserId);
86403
86474
  res.json({ data: await service.listUserCards(value.readerId, value.hidUserId) });
86404
86475
  } catch (requestError) {
86405
86476
  next(requestError);
@@ -86433,7 +86504,7 @@ function useHidAmicoController() {
86433
86504
  return;
86434
86505
  }
86435
86506
  try {
86436
- await authorizeReader(req, params.value.readerId);
86507
+ await authorizeReaderUser(req, params.value.readerId, params.value.hidUserId);
86437
86508
  res.status(201).json({
86438
86509
  data: await service.enrollUserCard(
86439
86510
  params.value.readerId,
@@ -86466,7 +86537,7 @@ function useHidAmicoController() {
86466
86537
  return;
86467
86538
  }
86468
86539
  try {
86469
- await authorizeReader(req, value.readerId);
86540
+ await authorizeReaderUser(req, value.readerId, value.hidUserId);
86470
86541
  res.json({
86471
86542
  data: await service.deleteUserCard(
86472
86543
  value.readerId,
@@ -86725,6 +86796,7 @@ function useHidAmicoController() {
86725
86796
  authorizeManage,
86726
86797
  authorizeVisitor,
86727
86798
  listReaders,
86799
+ getMemberReaderInfo,
86728
86800
  discoverReader,
86729
86801
  createReader,
86730
86802
  updateReader,
@@ -86760,6 +86832,7 @@ function useHidAmicoController() {
86760
86832
  setConfiguration,
86761
86833
  runObjectOperation,
86762
86834
  issueVisitorQr,
86835
+ getVisitorQr,
86763
86836
  revokeVisitorQr,
86764
86837
  getProfileFacial,
86765
86838
  setProfileFacial,