@7365admin1/layer-common 3.2.8-staging.205 → 3.2.8-staging.207

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.
@@ -169,13 +169,30 @@ const { menuItem: hidFaceReaderMenu } = useHidFaceReaderMenu({
169
169
  cacheKey: "layout-navigation-hid-site",
170
170
  });
171
171
 
172
- const { canManageEntryPass } = useSettingsPermission();
172
+ const HID_NAVIGATION_PERMISSIONS = [
173
+ "access-card-mgmt:see-all-card",
174
+ "access-card-mgmt:see-all-qr-tagging",
175
+ "access-card-mgmt:view",
176
+ "access-card-mgmt:add-access-card",
177
+ "access-card-mgmt:update-access-card",
178
+ "access-card-mgmt:delete-access-card",
179
+ "access-card-mgmt:assign-access-card",
180
+ "access-card-mgmt:manage-hid",
181
+ ];
182
+
183
+ const { userAppRole } = useLocalSetup();
184
+ const canAccessHid = computed(() => {
185
+ const permissions = userAppRole.value?.permissions ?? [];
186
+ return permissions.includes("*") || HID_NAVIGATION_PERMISSIONS.some(
187
+ (permission) => permissions.includes(permission),
188
+ );
189
+ });
173
190
 
174
191
  const navigationItems = computed(() => {
175
192
  const items = [...(props.navigationItems as TNavigationItem[])];
176
193
 
177
194
  if (
178
- canManageEntryPass.value &&
195
+ canAccessHid.value &&
179
196
  hidFaceReaderMenu.value &&
180
197
  !items.some((item) => item.title === hidFaceReaderMenu.value?.title)
181
198
  ) {
@@ -1,4 +1,4 @@
1
- type HidReaderPayload = {
1
+ export type HidReaderPayload = {
2
2
  site?: string;
3
3
  name?: string;
4
4
  location?: string;
@@ -6,14 +6,26 @@ type HidReaderPayload = {
6
6
  username?: string;
7
7
  password?: string;
8
8
  deviceId?: string;
9
+ serial?: string;
10
+ firmwareVersion?: string;
11
+ readerModel?: "VL35LF" | "VL70LF" | "unknown";
12
+ capabilities?: Record<string, boolean>;
9
13
  portalId?: number;
10
14
  portalName?: string;
11
15
  monitorPath?: string;
16
+ monitorStatus?: "unconfigured" | "configured" | "disabled" | "failed";
17
+ monitorEnabled?: boolean;
18
+ operatingMode?: "standalone" | "online";
19
+ cardReadingMode?: "unconfigured" | "pacs" | "csn" | "csn_for_mifare";
20
+ csnByteOrder?: "msb" | "lsb";
21
+ pacsFormat?: "raw" | "wiegand";
12
22
  enabled?: boolean;
13
23
  status?: string;
14
24
  lastSyncAt?: string;
15
25
  lastSyncStatus?: "idle" | "running" | "completed" | "failed";
16
26
  lastSyncMessage?: string;
27
+ lastCallbackAt?: string;
28
+ lastCallbackType?: string;
17
29
  };
18
30
 
19
31
  type HidIdentityPayload = {
@@ -24,10 +36,32 @@ type HidIdentityPayload = {
24
36
  person?: string;
25
37
  user?: string;
26
38
  member?: string;
39
+ serviceProvider?: string;
27
40
  visitor?: string;
28
- type?: "resident" | "staff" | "contractor" | "visitor" | "unknown";
41
+ type?: "resident" | "staff" | "contractor" | "visitor" | "admin" | "unknown";
29
42
  status?: "active" | "inactive" | "deleted";
30
- metadata?: Record<string, any>;
43
+ metadata?: Record<string, unknown>;
44
+ };
45
+
46
+ type HidApiRecord = {
47
+ [key: string]: unknown;
48
+ data?: HidApiRecord;
49
+ items?: HidApiRecord[];
50
+ identities?: HidApiRecord[];
51
+ users?: HidApiRecord[];
52
+ message?: string;
53
+ };
54
+ type HidCollectionResponse = HidApiRecord & {
55
+ items?: HidApiRecord[];
56
+ total?: number;
57
+ pages?: number;
58
+ pageRange?: string;
59
+ data?: HidApiRecord & {
60
+ items?: HidApiRecord[];
61
+ total?: number;
62
+ pages?: number;
63
+ pageRange?: string;
64
+ };
31
65
  };
32
66
 
33
67
  type HidVisitorQrData = {
@@ -74,7 +108,7 @@ export type HidPhysicalCard = {
74
108
  };
75
109
 
76
110
  type HidPhysicalCardInput =
77
- | { cardType: "pacs"; facilityCode: number; cardNumber: number }
111
+ | { cardType: "pacs"; facilityCode: string | number; cardNumber: string | number }
78
112
  | { cardType: "csn"; cardValue: string };
79
113
 
80
114
  export type HidSipAccountData = {
@@ -110,48 +144,68 @@ export function isUnknownSiteFieldError(error: unknown): boolean {
110
144
  export default function useHidAmico() {
111
145
  const basePath = "/api/access-management/hid";
112
146
 
113
- function getReaders(query: Record<string, any> = {}) {
114
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers`, {
147
+ function getReaders(query: HidApiRecord = {}) {
148
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers`, {
115
149
  method: "GET",
116
150
  query,
117
151
  });
118
152
  }
119
153
 
120
154
  function createReader(payload: HidReaderPayload) {
121
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers`, {
155
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers`, {
122
156
  method: "POST",
123
157
  body: payload,
124
158
  });
125
159
  }
126
160
 
127
161
  function updateReader(readerId: string, payload: HidReaderPayload) {
128
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}`, {
162
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}`, {
129
163
  method: "PATCH",
130
164
  body: payload,
131
165
  });
132
166
  }
133
167
 
134
168
  function deleteReader(readerId: string) {
135
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}`, {
169
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}`, {
136
170
  method: "DELETE",
137
171
  });
138
172
  }
139
173
 
140
174
  function testReader(readerId: string) {
141
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/test`, {
175
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/test`, {
142
176
  method: "POST",
143
177
  });
144
178
  }
145
179
 
146
- function syncReader(readerId: string, payload: Record<string, any> = {}) {
147
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/sync`, {
180
+ function syncReader(readerId: string, payload: HidApiRecord = {}) {
181
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/sync`, {
148
182
  method: "POST",
149
183
  body: payload,
150
184
  });
151
185
  }
152
186
 
153
- function runObjectOperation(readerId: string, payload: Record<string, any>) {
154
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/objects`, {
187
+ function configureReaderIntegration(readerId: string) {
188
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configure`, {
189
+ method: "POST",
190
+ });
191
+ }
192
+
193
+ function setReaderMonitor(readerId: string, enabled: boolean) {
194
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/monitor`, {
195
+ method: "PUT",
196
+ body: { enabled },
197
+ });
198
+ }
199
+
200
+ function setReaderOperatingMode(readerId: string, mode: "standalone" | "online") {
201
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/operating-mode`, {
202
+ method: "PUT",
203
+ body: { mode },
204
+ });
205
+ }
206
+
207
+ function runObjectOperation(readerId: string, payload: HidApiRecord) {
208
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/objects`, {
155
209
  method: "POST",
156
210
  body: payload,
157
211
  });
@@ -168,35 +222,61 @@ export default function useHidAmico() {
168
222
  }
169
223
 
170
224
  function getReaderConfiguration(readerId: string, payload: Record<string, string[]> = {}) {
171
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/configuration`, {
225
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configuration`, {
172
226
  method: "POST",
173
227
  body: payload,
174
228
  });
175
229
  }
176
230
 
177
- function setReaderConfiguration(readerId: string, payload: Record<string, any>) {
178
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/configuration`, {
231
+ function setReaderConfiguration(readerId: string, payload: HidApiRecord) {
232
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/configuration`, {
179
233
  method: "PUT",
180
234
  body: payload,
181
235
  });
182
236
  }
183
237
 
184
- function getIdentities(readerId: string, query: Record<string, any> = {}) {
185
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/identities`, {
238
+ function getIdentities(readerId: string, query: HidApiRecord = {}) {
239
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/identities`, {
240
+ method: "GET",
241
+ query,
242
+ });
243
+ }
244
+
245
+ function getReaderUsers(readerId: string, query: {
246
+ page?: number;
247
+ limit?: number;
248
+ search?: string;
249
+ status?: "mapped" | "unmapped" | "";
250
+ } = {}) {
251
+ return useNuxtApp().$api<HidCollectionResponse>(`${basePath}/readers/${readerId}/users`, {
252
+ method: "GET",
253
+ query,
254
+ });
255
+ }
256
+
257
+ function getReaderAccessLogs(readerId: string, query: {
258
+ page?: number;
259
+ limit?: number;
260
+ search?: string;
261
+ status?: "authorized" | "not_authorized" | "unknown" | "";
262
+ method?: "facial" | "qr_code" | "id_password" | "pin" | "card" | "";
263
+ tab?: "resident" | "visitor" | "administrator";
264
+ } = {}) {
265
+ return useNuxtApp().$api<HidCollectionResponse>(`${basePath}/readers/${readerId}/access-logs`, {
186
266
  method: "GET",
187
267
  query,
188
268
  });
189
269
  }
190
270
 
191
- function getLogs(readerId: string, query: Record<string, any> = {}) {
192
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/logs`, {
271
+ function getLogs(readerId: string, query: HidApiRecord = {}) {
272
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/logs`, {
193
273
  method: "GET",
194
274
  query,
195
275
  });
196
276
  }
197
277
 
198
278
  function getUserImage(readerId: string, hidUserId: string | number) {
199
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/users/${hidUserId}/image`, {
279
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/users/${hidUserId}/image`, {
200
280
  method: "GET",
201
281
  });
202
282
  }
@@ -323,40 +403,40 @@ export default function useHidAmico() {
323
403
  }
324
404
 
325
405
  function createIdentity(readerId: string, payload: HidIdentityPayload) {
326
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/identities`, {
406
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/identities`, {
327
407
  method: "POST",
328
408
  body: payload,
329
409
  });
330
410
  }
331
411
 
332
412
  function updateIdentity(identityId: string, payload: HidIdentityPayload) {
333
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/identities/${identityId}`, {
413
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/identities/${identityId}`, {
334
414
  method: "PATCH",
335
415
  body: payload,
336
416
  });
337
417
  }
338
418
 
339
419
  function deleteIdentity(identityId: string) {
340
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/identities/${identityId}`, {
420
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/identities/${identityId}`, {
341
421
  method: "DELETE",
342
422
  });
343
423
  }
344
424
 
345
425
  function getIntercomStatus(readerId: string) {
346
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/intercom/status`, {
426
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/status`, {
347
427
  method: "GET",
348
428
  });
349
429
  }
350
430
 
351
431
  function makeIntercomCall(readerId: string, target: string) {
352
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/intercom/call`, {
432
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/call`, {
353
433
  method: "POST",
354
434
  body: { target },
355
435
  });
356
436
  }
357
437
 
358
438
  function finalizeIntercomCall(readerId: string) {
359
- return useNuxtApp().$api<Record<string, any>>(`${basePath}/readers/${readerId}/intercom/hangup`, {
439
+ return useNuxtApp().$api<HidApiRecord>(`${basePath}/readers/${readerId}/intercom/hangup`, {
360
440
  method: "POST",
361
441
  });
362
442
  }
@@ -412,6 +492,9 @@ export default function useHidAmico() {
412
492
  deleteReader,
413
493
  testReader,
414
494
  syncReader,
495
+ configureReaderIntegration,
496
+ setReaderMonitor,
497
+ setReaderOperatingMode,
415
498
  runObjectOperation,
416
499
  issueVisitorQr,
417
500
  getReaderConfiguration,
@@ -429,6 +512,8 @@ export default function useHidAmico() {
429
512
  setUserPin,
430
513
  deleteUserPin,
431
514
  getIdentities,
515
+ getReaderUsers,
516
+ getReaderAccessLogs,
432
517
  createIdentity,
433
518
  updateIdentity,
434
519
  deleteIdentity,
@@ -5,6 +5,8 @@ type HidNavigationParams = {
5
5
  site: string;
6
6
  };
7
7
 
8
+ type HidNavigationSite = Record<string, unknown>;
9
+
8
10
  export default function useHidNavigation() {
9
11
  const { getSiteById } = useSiteSettings();
10
12
  const { getHidServiceEnabled } = useOptionalServices();
@@ -61,10 +63,10 @@ export default function useHidNavigation() {
61
63
  }: {
62
64
  org: Ref<string> | ComputedRef<string>;
63
65
  site: Ref<string> | ComputedRef<string>;
64
- fallbackSite?: Ref<Record<string, any> | undefined> | ComputedRef<Record<string, any> | undefined>;
66
+ fallbackSite?: Ref<HidNavigationSite | undefined> | ComputedRef<HidNavigationSite | undefined>;
65
67
  cacheKey?: string;
66
68
  }) {
67
- const siteDetails = ref<Record<string, any> | null>(null);
69
+ const siteDetails = ref<HidNavigationSite | null>(null);
68
70
 
69
71
  watch(
70
72
  site,
@@ -32,7 +32,15 @@ function normalizeServiceKey(value: unknown) {
32
32
  .replace(/[\s-]+/g, "_");
33
33
  }
34
34
 
35
- function itemHasService(item: any) {
35
+ type OptionalServiceRecord = Record<string, unknown>;
36
+
37
+ function toOptionalServiceRecord(value: unknown): OptionalServiceRecord {
38
+ return typeof value === "object" && value !== null && !Array.isArray(value)
39
+ ? value as OptionalServiceRecord
40
+ : {};
41
+ }
42
+
43
+ function itemHasService(item: unknown) {
36
44
  if (!item) return false;
37
45
 
38
46
  if (typeof item === "string") {
@@ -44,25 +52,26 @@ function itemHasService(item: any) {
44
52
  }
45
53
 
46
54
  if (typeof item === "object") {
55
+ const record = toOptionalServiceRecord(item);
47
56
  const key = normalizeServiceKey(
48
- item.key ??
49
- item.code ??
50
- item.name ??
51
- item.type ??
52
- item.service ??
53
- item.module ??
54
- item.feature,
57
+ record.key ??
58
+ record.code ??
59
+ record.name ??
60
+ record.type ??
61
+ record.service ??
62
+ record.module ??
63
+ record.feature,
55
64
  );
56
65
 
57
66
  const isEnabled =
58
- item.enabled ??
59
- item.active ??
60
- item.isEnabled ??
61
- (item.status ? item.status === "active" : true);
67
+ record.enabled ??
68
+ record.active ??
69
+ record.isEnabled ??
70
+ (record.status ? record.status === "active" : true);
62
71
 
63
72
  if (hidServiceKeys.includes(key)) return isEnabled !== false;
64
73
 
65
- return Object.values(item).some(itemHasService);
74
+ return Object.values(record).some(itemHasService);
66
75
  }
67
76
 
68
77
  return false;
@@ -74,10 +83,11 @@ export default function useOptionalServices() {
74
83
  () => ({}),
75
84
  );
76
85
 
77
- function hasHidService(source: Record<string, any> | null | undefined) {
86
+ function hasHidService(source: OptionalServiceRecord | null | undefined) {
78
87
  if (!source) return false;
79
88
 
80
- if (itemHasService(source.metadata?.services)) return true;
89
+ const metadata = toOptionalServiceRecord(source.metadata);
90
+ if (itemHasService(metadata.services)) return true;
81
91
 
82
92
  const presentGateFields = optionalServiceFields.filter((field) =>
83
93
  Object.prototype.hasOwnProperty.call(source, field),
@@ -90,7 +100,7 @@ export default function useOptionalServices() {
90
100
 
91
101
  function getHidServiceEnabled(
92
102
  siteId: string,
93
- source: Record<string, any> | null | undefined,
103
+ source: OptionalServiceRecord | null | undefined,
94
104
  ) {
95
105
  if (siteId && Object.prototype.hasOwnProperty.call(hidServiceOverrides.value, siteId)) {
96
106
  return hidServiceOverrides.value[siteId];
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.2.8-staging.205",
5
+ "version": "3.2.8-staging.207",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",