@passgage/sdk-react-native 1.0.1 → 1.0.2

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.js CHANGED
@@ -27,24 +27,1199 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  ));
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
 
30
- // src/index.tsx
30
+ // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ApiClient: () => ApiClient,
34
+ AuthService: () => AuthService,
35
+ CheckInService: () => CheckInService,
36
+ DeviceAccessService: () => DeviceAccessService,
37
+ DeviceDirection: () => DeviceDirection,
38
+ DeviceUsage: () => DeviceUsage,
39
+ Endpoints: () => endpoints_exports,
40
+ EntranceType: () => EntranceType,
41
+ LocationService: () => LocationService,
42
+ NFCAccessService: () => NFCAccessService,
33
43
  PassgageAccessProvider: () => PassgageAccessProvider,
44
+ QRAccessService: () => QRAccessService,
45
+ RemoteWorkService: () => RemoteWorkService,
34
46
  SDK_VERSION: () => SDK_VERSION,
47
+ calculateDistance: () => calculateDistance,
48
+ checkOnLocation: () => checkOnLocation,
49
+ checkRepetitiveRead: () => checkRepetitiveRead,
50
+ clearReadRecords: () => clearReadRecords,
51
+ createApiClient: () => createApiClient,
52
+ formatDate: () => formatDate,
53
+ formatDateTime: () => formatDateTime,
54
+ formatISO: () => formatISO,
55
+ formatTime: () => formatTime,
56
+ parseISO: () => parseISO,
35
57
  useCheckIn: () => useCheckIn,
36
58
  useLocation: () => useLocation,
37
59
  useNFCScanner: () => useNFCScanner,
38
60
  usePassgageAccess: () => usePassgageAccess,
39
61
  usePassgageAuth: () => usePassgageAuth,
40
62
  useQRScanner: () => useQRScanner,
41
- useRemoteWork: () => useRemoteWork
63
+ useRemoteWork: () => useRemoteWork,
64
+ validateCoordinates: () => validateCoordinates,
65
+ validateDeviceId: () => validateDeviceId,
66
+ validateNFCCode: () => validateNFCCode,
67
+ validateQRCode: () => validateQRCode
42
68
  });
43
69
  module.exports = __toCommonJS(index_exports);
44
70
 
71
+ // src/api/client.ts
72
+ var import_axios = __toESM(require("axios"));
73
+ var ApiClient = class {
74
+ constructor(config) {
75
+ this.isRefreshing = false;
76
+ this.refreshQueue = [];
77
+ this.config = {
78
+ timeout: 3e4,
79
+ apiVersion: "v2",
80
+ ...config
81
+ };
82
+ this.axiosInstance = import_axios.default.create({
83
+ baseURL: `${this.config.baseURL}/api/${this.config.apiVersion}`,
84
+ timeout: this.config.timeout,
85
+ headers: {
86
+ "Content-Type": "application/json",
87
+ Accept: "application/json",
88
+ ...this.config.headers
89
+ }
90
+ });
91
+ this.setupInterceptors();
92
+ }
93
+ /**
94
+ * Setup request and response interceptors
95
+ */
96
+ setupInterceptors() {
97
+ this.axiosInstance.interceptors.request.use(
98
+ (config) => {
99
+ const skipAuth = config.skipAuth;
100
+ if (this.config.token && !skipAuth) {
101
+ config.headers.Authorization = `Bearer ${this.config.token}`;
102
+ }
103
+ return config;
104
+ },
105
+ (error) => {
106
+ return Promise.reject(this.handleError(error));
107
+ }
108
+ );
109
+ this.axiosInstance.interceptors.response.use(
110
+ (response) => response,
111
+ async (error) => {
112
+ const originalRequest = error.config;
113
+ if (error.response?.status === 401 && originalRequest && !originalRequest._retry) {
114
+ const skipAuth = originalRequest.skipAuth;
115
+ if (skipAuth) {
116
+ return Promise.reject(this.handleError(error));
117
+ }
118
+ if (this.config.onTokenRefreshNeeded) {
119
+ originalRequest._retry = true;
120
+ const retryOriginalRequest = new Promise((resolve, reject) => {
121
+ this.refreshQueue.push({
122
+ config: originalRequest,
123
+ resolve,
124
+ reject
125
+ });
126
+ });
127
+ if (!this.isRefreshing) {
128
+ this.isRefreshing = true;
129
+ try {
130
+ const newToken = await this.config.onTokenRefreshNeeded();
131
+ if (newToken) {
132
+ this.setToken(newToken);
133
+ this.refreshQueue.forEach(({ config, resolve, reject }) => {
134
+ if (config.headers) {
135
+ config.headers.Authorization = `Bearer ${newToken}`;
136
+ }
137
+ this.axiosInstance.request(config).then(resolve).catch(reject);
138
+ });
139
+ this.refreshQueue = [];
140
+ } else {
141
+ this.refreshQueue.forEach(({ reject }) => {
142
+ reject(new Error("Token refresh failed"));
143
+ });
144
+ this.refreshQueue = [];
145
+ if (this.config.onUnauthorized) {
146
+ this.config.onUnauthorized();
147
+ }
148
+ }
149
+ } catch (refreshError) {
150
+ this.refreshQueue.forEach(({ reject }) => {
151
+ reject(refreshError);
152
+ });
153
+ this.refreshQueue = [];
154
+ if (this.config.onUnauthorized) {
155
+ this.config.onUnauthorized();
156
+ }
157
+ } finally {
158
+ this.isRefreshing = false;
159
+ }
160
+ }
161
+ return retryOriginalRequest;
162
+ } else {
163
+ if (this.config.onUnauthorized) {
164
+ this.config.onUnauthorized();
165
+ }
166
+ }
167
+ }
168
+ const apiError = this.handleError(error);
169
+ if (this.config.onError) {
170
+ this.config.onError(apiError);
171
+ }
172
+ return Promise.reject(apiError);
173
+ }
174
+ );
175
+ }
176
+ /**
177
+ * Handle API errors
178
+ */
179
+ handleError(error) {
180
+ const responseData = error.response?.data;
181
+ const apiError = new Error(
182
+ responseData?.message || error.message || "An unknown error occurred"
183
+ );
184
+ apiError.code = error.code;
185
+ apiError.status = error.response?.status;
186
+ apiError.response = responseData;
187
+ return apiError;
188
+ }
189
+ /**
190
+ * Update authorization token
191
+ */
192
+ setToken(token) {
193
+ this.config.token = token || void 0;
194
+ }
195
+ /**
196
+ * Remove authorization token
197
+ */
198
+ clearToken() {
199
+ this.config.token = void 0;
200
+ }
201
+ /**
202
+ * Generic GET request
203
+ */
204
+ async get(options) {
205
+ const response = await this.axiosInstance.get(options.endpoint, {
206
+ params: options.params,
207
+ headers: options.headers,
208
+ ...options.config,
209
+ skipAuth: options.skipAuth
210
+ });
211
+ return response.data;
212
+ }
213
+ /**
214
+ * Generic POST request
215
+ */
216
+ async post(options) {
217
+ const response = await this.axiosInstance.post(
218
+ options.endpoint,
219
+ options.data,
220
+ {
221
+ params: options.params,
222
+ headers: options.headers,
223
+ ...options.config,
224
+ skipAuth: options.skipAuth
225
+ }
226
+ );
227
+ return response.data;
228
+ }
229
+ /**
230
+ * Generic PUT request
231
+ */
232
+ async put(options) {
233
+ const response = await this.axiosInstance.put(
234
+ options.endpoint,
235
+ options.data,
236
+ {
237
+ params: options.params,
238
+ headers: options.headers,
239
+ ...options.config,
240
+ skipAuth: options.skipAuth
241
+ }
242
+ );
243
+ return response.data;
244
+ }
245
+ /**
246
+ * Generic PATCH request
247
+ */
248
+ async patch(options) {
249
+ const response = await this.axiosInstance.patch(
250
+ options.endpoint,
251
+ options.data,
252
+ {
253
+ params: options.params,
254
+ headers: options.headers,
255
+ ...options.config,
256
+ skipAuth: options.skipAuth
257
+ }
258
+ );
259
+ return response.data;
260
+ }
261
+ /**
262
+ * Generic DELETE request
263
+ */
264
+ async delete(options) {
265
+ const response = await this.axiosInstance.delete(options.endpoint, {
266
+ params: options.params,
267
+ headers: options.headers,
268
+ ...options.config,
269
+ skipAuth: options.skipAuth
270
+ });
271
+ return response.data;
272
+ }
273
+ };
274
+ function createApiClient(config) {
275
+ return new ApiClient(config);
276
+ }
277
+
278
+ // src/api/endpoints.ts
279
+ var endpoints_exports = {};
280
+ __export(endpoints_exports, {
281
+ EP_BRANCHES: () => EP_BRANCHES,
282
+ EP_CREATE_QR: () => EP_CREATE_QR,
283
+ EP_DEVICES: () => EP_DEVICES,
284
+ EP_ENTRANCES: () => EP_ENTRANCES,
285
+ EP_LOCATION_VERIFICATION: () => EP_LOCATION_VERIFICATION,
286
+ EP_LOGIN: () => EP_LOGIN,
287
+ EP_ME: () => EP_ME,
288
+ EP_NFC_CHECK: () => EP_NFC_CHECK,
289
+ EP_QR_ACCESS: () => EP_QR_ACCESS,
290
+ EP_QR_CHECK: () => EP_QR_CHECK,
291
+ EP_QR_DEVICES: () => EP_QR_DEVICES,
292
+ EP_TOKEN: () => EP_TOKEN,
293
+ EP_TRIGGER_IOT: () => EP_TRIGGER_IOT,
294
+ EP_USERS: () => EP_USERS
295
+ });
296
+ var EP_LOGIN = "users/sign_in";
297
+ var EP_TOKEN = "token";
298
+ var EP_DEVICES = "devices";
299
+ var EP_QR_DEVICES = "devices/qr_devices";
300
+ var EP_QR_ACCESS = "qr_access/accessible_qrs";
301
+ var EP_QR_CHECK = "qr_check";
302
+ var EP_NFC_CHECK = "nfc_check";
303
+ var EP_ENTRANCES = "entrances";
304
+ var EP_CREATE_QR = "entrances/create_from_qr";
305
+ var EP_BRANCHES = "branches";
306
+ var EP_LOCATION_VERIFICATION = "location_verification_logs";
307
+ var EP_TRIGGER_IOT = "iot/trigger";
308
+ var EP_USERS = "users";
309
+ var EP_ME = "users/lite_me";
310
+
311
+ // src/models/common.ts
312
+ var EntranceType = /* @__PURE__ */ ((EntranceType2) => {
313
+ EntranceType2[EntranceType2["ENTRY"] = 0] = "ENTRY";
314
+ EntranceType2[EntranceType2["EXIT"] = 1] = "EXIT";
315
+ return EntranceType2;
316
+ })(EntranceType || {});
317
+ var DeviceUsage = /* @__PURE__ */ ((DeviceUsage2) => {
318
+ DeviceUsage2["PDKS"] = "pdks";
319
+ DeviceUsage2["MEETING_ROOM"] = "meeting_room";
320
+ DeviceUsage2["FOOD"] = "food";
321
+ return DeviceUsage2;
322
+ })(DeviceUsage || {});
323
+ var DeviceDirection = /* @__PURE__ */ ((DeviceDirection2) => {
324
+ DeviceDirection2[DeviceDirection2["ENTRY"] = 0] = "ENTRY";
325
+ DeviceDirection2[DeviceDirection2["EXIT"] = 1] = "EXIT";
326
+ DeviceDirection2[DeviceDirection2["BIDIRECTIONAL"] = 2] = "BIDIRECTIONAL";
327
+ return DeviceDirection2;
328
+ })(DeviceDirection || {});
329
+
330
+ // src/services/AuthService.ts
331
+ var AuthService = class {
332
+ constructor(apiClient) {
333
+ this.apiClient = apiClient;
334
+ }
335
+ /**
336
+ * Set token storage implementation
337
+ * This is used by platform-specific implementations (React Native, Android, iOS)
338
+ */
339
+ setTokenStorage(storage) {
340
+ this.tokenStorage = storage;
341
+ }
342
+ /**
343
+ * Login with credentials
344
+ *
345
+ * @param credentials - User login credentials (email/phone and password)
346
+ * @returns Login result with tokens on success
347
+ *
348
+ * @example
349
+ * ```typescript
350
+ * const result = await authService.login({
351
+ * login: 'user@example.com',
352
+ * password: 'password123'
353
+ * });
354
+ *
355
+ * if (result.success) {
356
+ * console.log('Access token:', result.tokens.access.token);
357
+ * } else {
358
+ * console.error('Login failed:', result.error);
359
+ * }
360
+ * ```
361
+ */
362
+ async login(credentials) {
363
+ try {
364
+ const requestBody = {
365
+ user: {
366
+ login: credentials.login,
367
+ password: credentials.password
368
+ }
369
+ };
370
+ const response = await this.apiClient.post({
371
+ endpoint: "/api/v2/users/sign_in",
372
+ data: requestBody,
373
+ skipAuth: true
374
+ // Don't send auth header for login
375
+ });
376
+ if (!response.success || !response.data?.tokens) {
377
+ return {
378
+ success: false,
379
+ error: response.message || "Login failed",
380
+ code: "LOGIN_FAILED"
381
+ };
382
+ }
383
+ const tokens = response.data.tokens;
384
+ if (this.tokenStorage) {
385
+ await this.tokenStorage.saveTokens(tokens);
386
+ }
387
+ this.apiClient.setToken(tokens.access.token);
388
+ let user;
389
+ try {
390
+ const userResult = await this.getCurrentUser();
391
+ if (userResult.success) {
392
+ user = userResult.user;
393
+ if (this.tokenStorage) {
394
+ await this.tokenStorage.saveUser(user);
395
+ }
396
+ }
397
+ } catch (error) {
398
+ console.warn("Failed to fetch user info after login:", error);
399
+ }
400
+ return {
401
+ success: true,
402
+ tokens,
403
+ user
404
+ };
405
+ } catch (error) {
406
+ return {
407
+ success: false,
408
+ error: error.message || "An error occurred during login",
409
+ code: error.code || "NETWORK_ERROR"
410
+ };
411
+ }
412
+ }
413
+ /**
414
+ * Refresh access token using refresh token
415
+ *
416
+ * @param refreshToken - The refresh token
417
+ * @returns Refresh result with new tokens on success
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * const result = await authService.refreshToken('refresh_token_here');
422
+ *
423
+ * if (result.success) {
424
+ * console.log('New access token:', result.tokens.access.token);
425
+ * }
426
+ * ```
427
+ */
428
+ async refreshToken(refreshToken) {
429
+ try {
430
+ const requestBody = {
431
+ refresh_token: refreshToken
432
+ };
433
+ const response = await this.apiClient.post({
434
+ endpoint: "/token",
435
+ data: requestBody,
436
+ skipAuth: true
437
+ });
438
+ if (!response.success || !response.data?.token || !response.data?.refresh_token) {
439
+ return {
440
+ success: false,
441
+ error: response.message || "Token refresh failed",
442
+ code: "REFRESH_FAILED"
443
+ };
444
+ }
445
+ const tokens = {
446
+ access: {
447
+ token: response.data.token,
448
+ expiresIn: "30 days"
449
+ },
450
+ refresh: {
451
+ token: response.data.refresh_token,
452
+ expiresIn: "30 days"
453
+ }
454
+ };
455
+ if (this.tokenStorage) {
456
+ await this.tokenStorage.saveTokens(tokens);
457
+ }
458
+ this.apiClient.setToken(tokens.access.token);
459
+ return {
460
+ success: true,
461
+ tokens
462
+ };
463
+ } catch (error) {
464
+ return {
465
+ success: false,
466
+ error: error.message || "An error occurred during token refresh",
467
+ code: error.code || "NETWORK_ERROR"
468
+ };
469
+ }
470
+ }
471
+ /**
472
+ * Get current user information
473
+ *
474
+ * @returns Result with user information
475
+ *
476
+ * @example
477
+ * ```typescript
478
+ * const result = await authService.getCurrentUser();
479
+ *
480
+ * if (result.success) {
481
+ * console.log('User name:', result.user.fullName);
482
+ * }
483
+ * ```
484
+ */
485
+ async getCurrentUser() {
486
+ try {
487
+ const response = await this.apiClient.get({
488
+ endpoint: "/api/v2/users/me"
489
+ });
490
+ if (!response.success || !response.data) {
491
+ return {
492
+ success: false,
493
+ error: response.message || "Failed to fetch user information"
494
+ };
495
+ }
496
+ const userData = response.data;
497
+ const user = {
498
+ id: userData.id,
499
+ email: userData.email,
500
+ firstName: userData.first_name,
501
+ lastName: userData.last_name,
502
+ company: {
503
+ id: userData.company.id,
504
+ name: userData.company.name
505
+ },
506
+ fullName: userData.full_name || `${userData.first_name} ${userData.last_name}`,
507
+ gsm: userData.gsm,
508
+ avatar: userData.avatar?.url,
509
+ jobTitle: userData.job_title,
510
+ birthDate: userData.birth_date,
511
+ cardNo: userData.card_no
512
+ };
513
+ return {
514
+ success: true,
515
+ user
516
+ };
517
+ } catch (error) {
518
+ return {
519
+ success: false,
520
+ error: error.message || "Failed to fetch user information"
521
+ };
522
+ }
523
+ }
524
+ /**
525
+ * Logout current user
526
+ * Clears tokens from storage and API client
527
+ *
528
+ * @example
529
+ * ```typescript
530
+ * await authService.logout();
531
+ * console.log('User logged out');
532
+ * ```
533
+ */
534
+ async logout() {
535
+ if (this.tokenStorage) {
536
+ await this.tokenStorage.clearTokens();
537
+ await this.tokenStorage.clearUser();
538
+ }
539
+ this.apiClient.setToken(null);
540
+ }
541
+ /**
542
+ * Check if user is authenticated
543
+ *
544
+ * @returns True if user has valid tokens
545
+ */
546
+ async isAuthenticated() {
547
+ if (!this.tokenStorage) {
548
+ return false;
549
+ }
550
+ const tokens = await this.tokenStorage.getTokens();
551
+ return tokens !== null && tokens.access.token.length > 0;
552
+ }
553
+ /**
554
+ * Get stored tokens
555
+ *
556
+ * @returns Stored tokens or null
557
+ */
558
+ async getStoredTokens() {
559
+ if (!this.tokenStorage) {
560
+ return null;
561
+ }
562
+ return await this.tokenStorage.getTokens();
563
+ }
564
+ /**
565
+ * Get stored user
566
+ *
567
+ * @returns Stored user or null
568
+ */
569
+ async getStoredUser() {
570
+ if (!this.tokenStorage) {
571
+ return null;
572
+ }
573
+ return await this.tokenStorage.getUser();
574
+ }
575
+ };
576
+
577
+ // src/utils/location.ts
578
+ function calculateDistance(lat1, lon1, lat2, lon2) {
579
+ const R = 6371e3;
580
+ const \u03C61 = lat1 * Math.PI / 180;
581
+ const \u03C62 = lat2 * Math.PI / 180;
582
+ const \u0394\u03C6 = (lat2 - lat1) * Math.PI / 180;
583
+ const \u0394\u03BB = (lon2 - lon1) * Math.PI / 180;
584
+ const a = Math.sin(\u0394\u03C6 / 2) * Math.sin(\u0394\u03C6 / 2) + Math.cos(\u03C61) * Math.cos(\u03C62) * Math.sin(\u0394\u03BB / 2) * Math.sin(\u0394\u03BB / 2);
585
+ const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
586
+ return R * c;
587
+ }
588
+ function checkOnLocation(targetLat, targetLon, allowedRange, userPosition) {
589
+ if (!userPosition) {
590
+ return { ok: false };
591
+ }
592
+ const distance = calculateDistance(
593
+ targetLat,
594
+ targetLon,
595
+ userPosition.latitude,
596
+ userPosition.longitude
597
+ );
598
+ return {
599
+ ok: distance <= allowedRange,
600
+ distance
601
+ };
602
+ }
603
+ function validateCoordinates(coords) {
604
+ if (!coords) {
605
+ return false;
606
+ }
607
+ const { latitude, longitude } = coords;
608
+ return typeof latitude === "number" && typeof longitude === "number" && latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180;
609
+ }
610
+
611
+ // src/utils/validation.ts
612
+ var READ_TIMEOUT = 15e3;
613
+ var readRecords = [];
614
+ function checkRepetitiveRead(code) {
615
+ const now = Date.now();
616
+ readRecords = readRecords.filter((record) => now - record.timestamp < READ_TIMEOUT);
617
+ const recentRead = readRecords.find(
618
+ (record) => record.code === code && now - record.timestamp < READ_TIMEOUT
619
+ );
620
+ if (recentRead) {
621
+ return false;
622
+ }
623
+ readRecords.push({ code, timestamp: now });
624
+ return true;
625
+ }
626
+ function clearReadRecords() {
627
+ readRecords = [];
628
+ }
629
+ function validateQRCode(code) {
630
+ return typeof code === "string" && code.length > 0;
631
+ }
632
+ function validateNFCCode(code) {
633
+ return typeof code === "string" && code.length > 0;
634
+ }
635
+ function validateDeviceId(id) {
636
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
637
+ return uuidRegex.test(id);
638
+ }
639
+
640
+ // src/utils/date.ts
641
+ function formatISO(date = /* @__PURE__ */ new Date()) {
642
+ return date.toISOString();
643
+ }
644
+ function formatDate(date = /* @__PURE__ */ new Date()) {
645
+ const year = date.getFullYear();
646
+ const month = String(date.getMonth() + 1).padStart(2, "0");
647
+ const day = String(date.getDate()).padStart(2, "0");
648
+ return `${year}-${month}-${day}`;
649
+ }
650
+ function formatTime(date = /* @__PURE__ */ new Date()) {
651
+ const hours = String(date.getHours()).padStart(2, "0");
652
+ const minutes = String(date.getMinutes()).padStart(2, "0");
653
+ return `${hours}:${minutes}`;
654
+ }
655
+ function formatDateTime(date = /* @__PURE__ */ new Date()) {
656
+ const dateStr = formatDate(date);
657
+ const timeStr = formatTime(date);
658
+ const seconds = String(date.getSeconds()).padStart(2, "0");
659
+ return `${dateStr} ${timeStr}:${seconds}`;
660
+ }
661
+ function parseISO(isoString) {
662
+ return new Date(isoString);
663
+ }
664
+
665
+ // src/services/QRAccessService.ts
666
+ var QRAccessService = class {
667
+ constructor(apiClient) {
668
+ this.apiClient = apiClient;
669
+ }
670
+ /**
671
+ * Validate QR code format
672
+ */
673
+ validateQRFormat(code) {
674
+ return validateQRCode(code);
675
+ }
676
+ /**
677
+ * Check if location validation is required
678
+ */
679
+ shouldValidateLocation(device) {
680
+ return device.range_matter === "1" && !!device.latitude && !!device.longitude;
681
+ }
682
+ /**
683
+ * Validate user location against device location
684
+ */
685
+ validateLocation(device, userLocation) {
686
+ if (!this.shouldValidateLocation(device)) {
687
+ return { valid: true };
688
+ }
689
+ if (!userLocation) {
690
+ return { valid: false };
691
+ }
692
+ const locationCheck = checkOnLocation(
693
+ device.latitude,
694
+ device.longitude,
695
+ device.range || 100,
696
+ userLocation
697
+ );
698
+ return {
699
+ valid: locationCheck.ok,
700
+ distance: locationCheck.distance
701
+ };
702
+ }
703
+ /**
704
+ * Validate QR code with full checks
705
+ */
706
+ async validateQR(options) {
707
+ const { qrCode, device, userLocation, skipLocationCheck, skipRepetitiveCheck } = options;
708
+ if (!this.validateQRFormat(qrCode)) {
709
+ return {
710
+ success: false,
711
+ message: "Invalid QR code format",
712
+ error: { code: "INVALID_QR_FORMAT" }
713
+ };
714
+ }
715
+ if (!skipRepetitiveCheck && !checkRepetitiveRead(qrCode)) {
716
+ return {
717
+ success: false,
718
+ message: "QR code was recently scanned. Please wait before scanning again.",
719
+ error: { code: "REPETITIVE_READ" }
720
+ };
721
+ }
722
+ if (!skipLocationCheck) {
723
+ const locationValidation = this.validateLocation(device, userLocation);
724
+ if (!locationValidation.valid) {
725
+ return {
726
+ success: false,
727
+ message: "You are not within the allowed range of this device",
728
+ error: {
729
+ code: "LOCATION_OUT_OF_RANGE",
730
+ details: locationValidation.distance ? `Distance: ${locationValidation.distance.toFixed(2)}m` : void 0
731
+ }
732
+ };
733
+ }
734
+ }
735
+ try {
736
+ const response = await this.apiClient.post({
737
+ endpoint: EP_QR_CHECK,
738
+ data: { qr_code: qrCode }
739
+ });
740
+ if (!response.success) {
741
+ return {
742
+ success: false,
743
+ message: response.message || "QR validation failed",
744
+ error: { code: "API_ERROR" }
745
+ };
746
+ }
747
+ return {
748
+ success: true,
749
+ message: "QR code validated successfully",
750
+ entrance: response.data
751
+ };
752
+ } catch (error) {
753
+ return {
754
+ success: false,
755
+ message: error.message || "Failed to validate QR code",
756
+ error: { code: "NETWORK_ERROR" }
757
+ };
758
+ }
759
+ }
760
+ /**
761
+ * Create entrance from QR code
762
+ */
763
+ async createEntranceFromQR(request) {
764
+ return this.apiClient.post({
765
+ endpoint: EP_CREATE_QR,
766
+ data: request
767
+ });
768
+ }
769
+ /**
770
+ * Trigger IoT device
771
+ */
772
+ async triggerIoTDevice(deviceId) {
773
+ return this.apiClient.post({
774
+ endpoint: `${EP_TRIGGER_IOT}/${deviceId}`
775
+ });
776
+ }
777
+ };
778
+
779
+ // src/services/NFCAccessService.ts
780
+ var NFCAccessService = class {
781
+ constructor(apiClient) {
782
+ this.apiClient = apiClient;
783
+ }
784
+ /**
785
+ * Validate NFC code format
786
+ */
787
+ validateNFCFormat(code) {
788
+ return validateNFCCode(code);
789
+ }
790
+ /**
791
+ * Check if location validation is required
792
+ */
793
+ shouldValidateLocation(device) {
794
+ return device.nfc_range_matter === "1" && !!device.latitude && !!device.longitude;
795
+ }
796
+ /**
797
+ * Validate user location against device location
798
+ */
799
+ validateLocation(device, userLocation) {
800
+ if (!this.shouldValidateLocation(device)) {
801
+ return { valid: true };
802
+ }
803
+ if (!userLocation) {
804
+ return { valid: false };
805
+ }
806
+ const locationCheck = checkOnLocation(
807
+ device.latitude,
808
+ device.longitude,
809
+ device.nfc_range || 100,
810
+ userLocation
811
+ );
812
+ return {
813
+ valid: locationCheck.ok,
814
+ distance: locationCheck.distance
815
+ };
816
+ }
817
+ /**
818
+ * Validate NFC code with full checks
819
+ */
820
+ async validateNFC(options) {
821
+ const { nfcCode, device, userLocation, skipLocationCheck, skipRepetitiveCheck } = options;
822
+ if (!this.validateNFCFormat(nfcCode)) {
823
+ return {
824
+ success: false,
825
+ message: "Invalid NFC code format",
826
+ error: { code: "INVALID_NFC_FORMAT" }
827
+ };
828
+ }
829
+ if (!skipRepetitiveCheck && !checkRepetitiveRead(nfcCode)) {
830
+ return {
831
+ success: false,
832
+ message: "NFC card was recently scanned. Please wait before scanning again.",
833
+ error: { code: "REPETITIVE_READ" }
834
+ };
835
+ }
836
+ if (!skipLocationCheck) {
837
+ const locationValidation = this.validateLocation(device, userLocation);
838
+ if (!locationValidation.valid) {
839
+ return {
840
+ success: false,
841
+ message: "You are not within the allowed range of this device",
842
+ error: {
843
+ code: "LOCATION_OUT_OF_RANGE",
844
+ details: locationValidation.distance ? `Distance: ${locationValidation.distance.toFixed(2)}m` : void 0
845
+ }
846
+ };
847
+ }
848
+ }
849
+ try {
850
+ const response = await this.apiClient.post({
851
+ endpoint: EP_NFC_CHECK,
852
+ data: { nfc_code: nfcCode }
853
+ });
854
+ if (!response.success) {
855
+ return {
856
+ success: false,
857
+ message: response.message || "NFC validation failed",
858
+ error: { code: "API_ERROR" }
859
+ };
860
+ }
861
+ return {
862
+ success: true,
863
+ message: "NFC card validated successfully",
864
+ entrance: response.data
865
+ };
866
+ } catch (error) {
867
+ return {
868
+ success: false,
869
+ message: error.message || "Failed to validate NFC card",
870
+ error: { code: "NETWORK_ERROR" }
871
+ };
872
+ }
873
+ }
874
+ };
875
+
876
+ // src/services/CheckInService.ts
877
+ var CheckInService = class {
878
+ constructor(apiClient) {
879
+ this.apiClient = apiClient;
880
+ }
881
+ /**
882
+ * Get nearby branches based on user location
883
+ */
884
+ async getNearbyBranches(request) {
885
+ const { latitude, longitude, radius } = request;
886
+ if (!validateCoordinates({ latitude, longitude })) {
887
+ throw new Error("Invalid coordinates provided");
888
+ }
889
+ return this.apiClient.get({
890
+ endpoint: EP_BRANCHES,
891
+ params: {
892
+ latitude,
893
+ longitude,
894
+ ...radius && { radius }
895
+ }
896
+ });
897
+ }
898
+ /**
899
+ * Check in to a branch
900
+ */
901
+ async checkIn(options) {
902
+ const { branchId, entranceType, userId, userLocation: _userLocation } = options;
903
+ try {
904
+ const entranceRequest = {
905
+ user_id: userId,
906
+ branch_id: branchId,
907
+ entrance_type: entranceType,
908
+ is_manual_recording: false
909
+ };
910
+ const response = await this.apiClient.post({
911
+ endpoint: EP_ENTRANCES,
912
+ data: entranceRequest
913
+ });
914
+ if (!response.success) {
915
+ return {
916
+ success: false,
917
+ message: response.message || "Check-in failed",
918
+ error: { code: "API_ERROR" }
919
+ };
920
+ }
921
+ return {
922
+ success: true,
923
+ message: "Check-in successful",
924
+ entrance: response.data
925
+ };
926
+ } catch (error) {
927
+ return {
928
+ success: false,
929
+ message: error.message || "Failed to check-in",
930
+ error: { code: "NETWORK_ERROR" }
931
+ };
932
+ }
933
+ }
934
+ /**
935
+ * Get branch by ID
936
+ */
937
+ async getBranchById(branchId) {
938
+ return this.apiClient.get({
939
+ endpoint: `${EP_BRANCHES}/${branchId}`
940
+ });
941
+ }
942
+ /**
943
+ * Get all branches (with pagination)
944
+ */
945
+ async getAllBranches(params) {
946
+ return this.apiClient.get({
947
+ endpoint: EP_BRANCHES,
948
+ params
949
+ });
950
+ }
951
+ };
952
+
953
+ // src/services/RemoteWorkService.ts
954
+ var RemoteWorkService = class {
955
+ constructor(apiClient) {
956
+ this.apiClient = apiClient;
957
+ }
958
+ /**
959
+ * Log remote work entry or exit
960
+ */
961
+ async logRemoteWork(options) {
962
+ const { userId, entranceType, timestamp, description } = options;
963
+ try {
964
+ const createdAt = timestamp ? typeof timestamp === "string" ? timestamp : formatISO(timestamp) : formatISO();
965
+ const entranceRequest = {
966
+ user_id: userId,
967
+ entrance_type: entranceType,
968
+ is_manual_recording: true,
969
+ is_remote_work: true,
970
+ created_at: createdAt,
971
+ description
972
+ };
973
+ const response = await this.apiClient.post({
974
+ endpoint: EP_ENTRANCES,
975
+ data: { entrance: entranceRequest }
976
+ });
977
+ if (!response.success) {
978
+ return {
979
+ success: false,
980
+ message: response.message || "Failed to log remote work",
981
+ error: { code: "API_ERROR" }
982
+ };
983
+ }
984
+ return {
985
+ success: true,
986
+ message: "Remote work logged successfully",
987
+ entrance: response.data
988
+ };
989
+ } catch (error) {
990
+ return {
991
+ success: false,
992
+ message: error.message || "Failed to log remote work",
993
+ error: { code: "NETWORK_ERROR" }
994
+ };
995
+ }
996
+ }
997
+ /**
998
+ * Log remote work entry
999
+ */
1000
+ async logEntry(options) {
1001
+ return this.logRemoteWork({
1002
+ ...options,
1003
+ entranceType: 0 /* ENTRY */
1004
+ });
1005
+ }
1006
+ /**
1007
+ * Log remote work exit
1008
+ */
1009
+ async logExit(options) {
1010
+ return this.logRemoteWork({
1011
+ ...options,
1012
+ entranceType: 1 /* EXIT */
1013
+ });
1014
+ }
1015
+ };
1016
+
1017
+ // src/services/DeviceAccessService.ts
1018
+ var DeviceAccessService = class {
1019
+ constructor(apiClient) {
1020
+ this.apiClient = apiClient;
1021
+ }
1022
+ /**
1023
+ * Get all devices
1024
+ */
1025
+ async getDevices(params) {
1026
+ return this.apiClient.get({
1027
+ endpoint: EP_DEVICES,
1028
+ params: params || { per_page: 100 }
1029
+ });
1030
+ }
1031
+ /**
1032
+ * Get all QR devices
1033
+ */
1034
+ async getQRDevices(params) {
1035
+ return this.apiClient.get({
1036
+ endpoint: EP_QR_DEVICES,
1037
+ params: params || { per_page: 100 }
1038
+ });
1039
+ }
1040
+ /**
1041
+ * Get all QR devices with pagination support
1042
+ */
1043
+ async getAllQRDevices() {
1044
+ const perPage = 50;
1045
+ let currentPage = 1;
1046
+ let allData = [];
1047
+ while (true) {
1048
+ const response = await this.getQRDevices({
1049
+ page: currentPage,
1050
+ per_page: perPage
1051
+ });
1052
+ if (!response.success || !response.data) {
1053
+ break;
1054
+ }
1055
+ allData = [...allData, ...response.data];
1056
+ if (!response.meta || !response.meta.total_pages) {
1057
+ break;
1058
+ }
1059
+ if (currentPage >= response.meta.total_pages) {
1060
+ break;
1061
+ }
1062
+ currentPage++;
1063
+ }
1064
+ return allData;
1065
+ }
1066
+ /**
1067
+ * Get accessible QR codes for current user
1068
+ */
1069
+ async getAccessibleQRs() {
1070
+ return this.apiClient.get({
1071
+ endpoint: EP_QR_ACCESS
1072
+ });
1073
+ }
1074
+ /**
1075
+ * Get user devices
1076
+ */
1077
+ async getUserDevices(request) {
1078
+ const { userId, page, per_page } = request;
1079
+ return this.apiClient.get({
1080
+ endpoint: `${EP_USERS}/${userId}/devices`,
1081
+ params: {
1082
+ ...page && { page },
1083
+ ...per_page && { per_page }
1084
+ }
1085
+ });
1086
+ }
1087
+ /**
1088
+ * Get device by ID
1089
+ */
1090
+ async getDeviceById(deviceId) {
1091
+ return this.apiClient.get({
1092
+ endpoint: `${EP_DEVICES}/${deviceId}`
1093
+ });
1094
+ }
1095
+ /**
1096
+ * Check if user has access to a device
1097
+ */
1098
+ async checkDeviceAccess(deviceId) {
1099
+ try {
1100
+ const response = await this.getAccessibleQRs();
1101
+ if (!response.success || !response.data) {
1102
+ return false;
1103
+ }
1104
+ return response.data.qr_ids.includes(deviceId);
1105
+ } catch {
1106
+ return false;
1107
+ }
1108
+ }
1109
+ /**
1110
+ * Find QR device by QR code ID
1111
+ */
1112
+ async findDeviceByQRCode(qrCodeId) {
1113
+ try {
1114
+ const devices = await this.getAllQRDevices();
1115
+ return devices.find((device) => device.qr_code_id === qrCodeId);
1116
+ } catch {
1117
+ return void 0;
1118
+ }
1119
+ }
1120
+ /**
1121
+ * Find QR device by NFC code
1122
+ */
1123
+ async findDeviceByNFCCode(nfcCode) {
1124
+ try {
1125
+ const devices = await this.getAllQRDevices();
1126
+ return devices.find((device) => device.nfc_code === nfcCode);
1127
+ } catch {
1128
+ return void 0;
1129
+ }
1130
+ }
1131
+ };
1132
+
1133
+ // src/services/LocationService.ts
1134
+ var LocationService = class {
1135
+ constructor(apiClient) {
1136
+ this.apiClient = apiClient;
1137
+ }
1138
+ /**
1139
+ * Log location verification
1140
+ */
1141
+ async logLocationVerification(log) {
1142
+ return this.apiClient.post({
1143
+ endpoint: EP_LOCATION_VERIFICATION,
1144
+ data: { log }
1145
+ });
1146
+ }
1147
+ /**
1148
+ * Create location verification log for QR scan
1149
+ */
1150
+ async logQRScan(params) {
1151
+ const log = {
1152
+ mobileLatitude: params.mobileLocation.latitude,
1153
+ mobileLongitude: params.mobileLocation.longitude,
1154
+ accuracy: params.mobileLocation.accuracy,
1155
+ altitude: params.mobileLocation.altitude,
1156
+ qrLatitude: params.qrLocation?.latitude ?? -1,
1157
+ qrLongitude: params.qrLocation?.longitude ?? -1,
1158
+ currentScreen: params.currentScreen,
1159
+ qr: params.qrCode,
1160
+ errorCode: params.errorCode,
1161
+ message: params.message,
1162
+ navigation_step: "qr_scan_location",
1163
+ isGps: true,
1164
+ deviceRange: params.deviceRange || 0,
1165
+ distance: params.distance,
1166
+ additionalInfo: params.additionalInfo || "",
1167
+ customData: params.customData
1168
+ };
1169
+ return this.logLocationVerification(log);
1170
+ }
1171
+ /**
1172
+ * Create location verification log for NFC scan
1173
+ */
1174
+ async logNFCScan(params) {
1175
+ const log = {
1176
+ mobileLatitude: params.mobileLocation.latitude,
1177
+ mobileLongitude: params.mobileLocation.longitude,
1178
+ accuracy: params.mobileLocation.accuracy,
1179
+ altitude: params.mobileLocation.altitude,
1180
+ qrLatitude: params.nfcLocation?.latitude ?? -1,
1181
+ qrLongitude: params.nfcLocation?.longitude ?? -1,
1182
+ currentScreen: params.currentScreen,
1183
+ qr: params.nfcCode,
1184
+ errorCode: params.errorCode,
1185
+ message: params.message,
1186
+ navigation_step: "nfc_scan_location",
1187
+ isGps: true,
1188
+ deviceRange: params.deviceRange || 0,
1189
+ distance: params.distance,
1190
+ additionalInfo: params.additionalInfo || "",
1191
+ customData: params.customData
1192
+ };
1193
+ return this.logLocationVerification(log);
1194
+ }
1195
+ /**
1196
+ * Create location verification log for check-in
1197
+ */
1198
+ async logCheckIn(params) {
1199
+ const log = {
1200
+ mobileLatitude: params.mobileLocation.latitude,
1201
+ mobileLongitude: params.mobileLocation.longitude,
1202
+ accuracy: params.mobileLocation.accuracy,
1203
+ altitude: params.mobileLocation.altitude,
1204
+ qrLatitude: params.branchLocation?.latitude ?? -1,
1205
+ qrLongitude: params.branchLocation?.longitude ?? -1,
1206
+ currentScreen: params.currentScreen,
1207
+ qr: "-",
1208
+ errorCode: params.errorCode,
1209
+ message: params.message,
1210
+ navigation_step: "check_in",
1211
+ isGps: true,
1212
+ deviceRange: 0,
1213
+ distance: params.distance,
1214
+ additionalInfo: params.additionalInfo || "buraday\u0131m",
1215
+ customData: params.customData
1216
+ };
1217
+ return this.logLocationVerification(log);
1218
+ }
1219
+ };
1220
+
45
1221
  // src/providers/PassgageAccessProvider.tsx
46
1222
  var import_react = __toESM(require("react"));
47
- var import_sdk_core = require("@passgage/sdk-core");
48
1223
 
49
1224
  // src/utils/secureStorage.ts
50
1225
  var Keychain = __toESM(require("react-native-keychain"));
@@ -183,7 +1358,7 @@ function PassgageAccessProvider({
183
1358
  const { apiClient, services } = (0, import_react.useMemo)(() => {
184
1359
  const secureStorage = createSecureStorage();
185
1360
  let authService;
186
- const client = (0, import_sdk_core.createApiClient)({
1361
+ const client = createApiClient({
187
1362
  baseURL: config.baseURL,
188
1363
  token: config.token,
189
1364
  apiVersion: config.apiVersion,
@@ -202,16 +1377,16 @@ function PassgageAccessProvider({
202
1377
  return null;
203
1378
  }
204
1379
  });
205
- authService = new import_sdk_core.AuthService(client);
1380
+ authService = new AuthService(client);
206
1381
  authService.setTokenStorage(secureStorage);
207
1382
  const allServices = {
208
1383
  authService,
209
- qrAccessService: new import_sdk_core.QRAccessService(client),
210
- nfcAccessService: new import_sdk_core.NFCAccessService(client),
211
- checkInService: new import_sdk_core.CheckInService(client),
212
- remoteWorkService: new import_sdk_core.RemoteWorkService(client),
213
- deviceAccessService: new import_sdk_core.DeviceAccessService(client),
214
- locationService: new import_sdk_core.LocationService(client)
1384
+ qrAccessService: new QRAccessService(client),
1385
+ nfcAccessService: new NFCAccessService(client),
1386
+ checkInService: new CheckInService(client),
1387
+ remoteWorkService: new RemoteWorkService(client),
1388
+ deviceAccessService: new DeviceAccessService(client),
1389
+ locationService: new LocationService(client)
215
1390
  };
216
1391
  return {
217
1392
  apiClient: client,
@@ -653,7 +1828,6 @@ function useCheckIn(options = {}) {
653
1828
 
654
1829
  // src/hooks/useRemoteWork.ts
655
1830
  var import_react7 = require("react");
656
- var import_sdk_core2 = require("@passgage/sdk-core");
657
1831
  function useRemoteWork() {
658
1832
  const { remoteWorkService } = usePassgageAccess();
659
1833
  const [isLoading, setIsLoading] = (0, import_react7.useState)(false);
@@ -686,13 +1860,13 @@ function useRemoteWork() {
686
1860
  );
687
1861
  const logEntry = (0, import_react7.useCallback)(
688
1862
  async (options) => {
689
- return logRemoteWork(import_sdk_core2.EntranceType.ENTRY, options);
1863
+ return logRemoteWork(0 /* ENTRY */, options);
690
1864
  },
691
1865
  [logRemoteWork]
692
1866
  );
693
1867
  const logExit = (0, import_react7.useCallback)(
694
1868
  async (options) => {
695
- return logRemoteWork(import_sdk_core2.EntranceType.EXIT, options);
1869
+ return logRemoteWork(1 /* EXIT */, options);
696
1870
  },
697
1871
  [logRemoteWork]
698
1872
  );
@@ -705,17 +1879,43 @@ function useRemoteWork() {
705
1879
  };
706
1880
  }
707
1881
 
708
- // src/index.tsx
709
- var SDK_VERSION = "1.0.0";
1882
+ // src/index.ts
1883
+ var SDK_VERSION = "1.0.2";
710
1884
  // Annotate the CommonJS export names for ESM import in node:
711
1885
  0 && (module.exports = {
1886
+ ApiClient,
1887
+ AuthService,
1888
+ CheckInService,
1889
+ DeviceAccessService,
1890
+ DeviceDirection,
1891
+ DeviceUsage,
1892
+ Endpoints,
1893
+ EntranceType,
1894
+ LocationService,
1895
+ NFCAccessService,
712
1896
  PassgageAccessProvider,
1897
+ QRAccessService,
1898
+ RemoteWorkService,
713
1899
  SDK_VERSION,
1900
+ calculateDistance,
1901
+ checkOnLocation,
1902
+ checkRepetitiveRead,
1903
+ clearReadRecords,
1904
+ createApiClient,
1905
+ formatDate,
1906
+ formatDateTime,
1907
+ formatISO,
1908
+ formatTime,
1909
+ parseISO,
714
1910
  useCheckIn,
715
1911
  useLocation,
716
1912
  useNFCScanner,
717
1913
  usePassgageAccess,
718
1914
  usePassgageAuth,
719
1915
  useQRScanner,
720
- useRemoteWork
1916
+ useRemoteWork,
1917
+ validateCoordinates,
1918
+ validateDeviceId,
1919
+ validateNFCCode,
1920
+ validateQRCode
721
1921
  });