react-native-telpo 1.0.0

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.
Files changed (37) hide show
  1. package/README.md +300 -0
  2. package/lib/commonjs/index.js +40 -0
  3. package/lib/commonjs/index.js.map +1 -0
  4. package/lib/commonjs/nfc/index.js +322 -0
  5. package/lib/commonjs/nfc/index.js.map +1 -0
  6. package/lib/commonjs/printer/index.js +379 -0
  7. package/lib/commonjs/printer/index.js.map +1 -0
  8. package/lib/commonjs/scanner/index.js +301 -0
  9. package/lib/commonjs/scanner/index.js.map +1 -0
  10. package/lib/commonjs/types/index.js +37 -0
  11. package/lib/commonjs/types/index.js.map +1 -0
  12. package/lib/module/index.js +27 -0
  13. package/lib/module/index.js.map +1 -0
  14. package/lib/module/nfc/index.js +317 -0
  15. package/lib/module/nfc/index.js.map +1 -0
  16. package/lib/module/printer/index.js +374 -0
  17. package/lib/module/printer/index.js.map +1 -0
  18. package/lib/module/scanner/index.js +294 -0
  19. package/lib/module/scanner/index.js.map +1 -0
  20. package/lib/module/types/index.js +38 -0
  21. package/lib/module/types/index.js.map +1 -0
  22. package/lib/typescript/index.d.ts +21 -0
  23. package/lib/typescript/index.d.ts.map +1 -0
  24. package/lib/typescript/nfc/index.d.ts +83 -0
  25. package/lib/typescript/nfc/index.d.ts.map +1 -0
  26. package/lib/typescript/printer/index.d.ts +91 -0
  27. package/lib/typescript/printer/index.d.ts.map +1 -0
  28. package/lib/typescript/scanner/index.d.ts +81 -0
  29. package/lib/typescript/scanner/index.d.ts.map +1 -0
  30. package/lib/typescript/types/index.d.ts +114 -0
  31. package/lib/typescript/types/index.d.ts.map +1 -0
  32. package/package.json +104 -0
  33. package/src/index.ts +55 -0
  34. package/src/nfc/index.ts +362 -0
  35. package/src/printer/index.ts +432 -0
  36. package/src/scanner/index.tsx +397 -0
  37. package/src/types/index.ts +161 -0
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # react-native-telpo
2
+
3
+ Production-ready React Native SDK for **Telpo** POS and ticket validation devices.
4
+
5
+ | Module | Feature | Devices |
6
+ |---|---|---|
7
+ | `TelpoPrinter` | Thermal receipt & ticket printing | M1, TPS320 |
8
+ | `TelpoNfc` | NFC / contactless card UID reading | T20, TPS320 |
9
+ | `TelpoScanner` | QR code & barcode scanning | T20, M1, TPS320 |
10
+
11
+ > **Android only.** Telpo devices run Android. iOS is not supported for printing or NFC.
12
+
13
+ ---
14
+
15
+ ## Installation
16
+
17
+ ```sh
18
+ npm install react-native-telpo
19
+ ```
20
+
21
+ ### Required peer dependencies
22
+
23
+ Install all three — only the modules you use will actually load at runtime:
24
+
25
+ ```sh
26
+ npm install \
27
+ @haroldtran/react-native-thermal-printer \
28
+ react-native-nfc-manager \
29
+ react-native-vision-camera
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Android Setup
35
+
36
+ ### 1. `android/build.gradle` — Add JitPack
37
+
38
+ ```groovy
39
+ allprojects {
40
+ repositories {
41
+ // ...
42
+ maven { url "https://jitpack.io" }
43
+ }
44
+ }
45
+ ```
46
+
47
+ ### 2. `android/app/build.gradle` — Min SDK
48
+
49
+ ```groovy
50
+ android {
51
+ defaultConfig {
52
+ minSdkVersion 21 // Required by vision-camera
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### 3. `android/app/src/main/AndroidManifest.xml` — Permissions
58
+
59
+ ```xml
60
+ <!-- USB printer (M1 / TPS320 internal printer) -->
61
+ <uses-feature android:name="android.hardware.usb.host" />
62
+
63
+ <!-- NFC (T20 / TPS320) -->
64
+ <uses-permission android:name="android.permission.NFC" />
65
+ <uses-feature android:name="android.hardware.nfc" android:required="false" />
66
+
67
+ <!-- Camera (scanner) -->
68
+ <uses-permission android:name="android.permission.CAMERA" />
69
+
70
+ <!-- Bluetooth printer (optional) -->
71
+ <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
72
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
73
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Usage
79
+
80
+ ### Printer — Telpo M1 / TPS320
81
+
82
+ ```typescript
83
+ import { TelpoPrinter } from 'react-native-telpo';
84
+
85
+ // 1. Initialise (once, e.g. in useEffect or app start)
86
+ const initResult = await TelpoPrinter.init();
87
+ if (!initResult.success) {
88
+ console.error(initResult.error.message);
89
+ return;
90
+ }
91
+
92
+ // 2. Connect (USB = internal printer, default)
93
+ const connectResult = await TelpoPrinter.connect(); // connectionType: 'USB' by default
94
+ if (!connectResult.success) {
95
+ console.error(connectResult.error.message);
96
+ return;
97
+ }
98
+
99
+ // 3. Print a bus ticket
100
+ const printResult = await TelpoPrinter.printTicket({
101
+ operatorName: 'City Bus Services',
102
+ route: 'Route 42 — City Centre → Airport',
103
+ passenger: 'John Doe',
104
+ ticketId: 'TKT-001234',
105
+ fare: 'SLE 5.00',
106
+ dateTime: '2025-06-06 14:30:00', // optional, defaults to now
107
+ extras: { 'Bus No': 'BUS-007' },
108
+ footer: 'Thank you for travelling!',
109
+ });
110
+
111
+ // 4. Disconnect when done
112
+ await TelpoPrinter.disconnect();
113
+ ```
114
+
115
+ #### Print custom lines
116
+
117
+ ```typescript
118
+ await TelpoPrinter.printLines([
119
+ { text: 'CITY BUS', alignment: 'CENTER', bold: true, fontSize: 'LARGE' },
120
+ { text: '================================', alignment: 'CENTER' },
121
+ { text: 'Ticket: TKT-001234', alignment: 'LEFT' },
122
+ { text: 'Fare: SLE 5.00', alignment: 'LEFT' },
123
+ ]);
124
+ ```
125
+
126
+ #### Bluetooth printer
127
+
128
+ ```typescript
129
+ await TelpoPrinter.connect({
130
+ connectionType: 'BLUETOOTH',
131
+ bluetoothAddress: 'AA:BB:CC:DD:EE:FF',
132
+ });
133
+ ```
134
+
135
+ ---
136
+
137
+ ### NFC — Telpo T20 / TPS320
138
+
139
+ #### Single tap (one-shot read)
140
+
141
+ ```typescript
142
+ import { TelpoNfc } from 'react-native-telpo';
143
+
144
+ // Initialise once
145
+ await TelpoNfc.init();
146
+
147
+ // Wait for a card tap — resolves when card is detected
148
+ const result = await TelpoNfc.readTag();
149
+
150
+ if (result.success) {
151
+ const { uid, technology } = result.data;
152
+ console.log('Card UID:', uid); // "04:AB:12:CD:EF:01:23"
153
+ console.log('Technology:', technology); // "NfcA" | "IsoDep" | ...
154
+ // → now do YOUR validation logic with uid
155
+ } else {
156
+ console.error(result.error.message);
157
+ }
158
+ ```
159
+
160
+ #### Continuous listening (validation gate)
161
+
162
+ ```typescript
163
+ import { TelpoNfc } from 'react-native-telpo';
164
+
165
+ // Start listening — fires callback on every tap
166
+ TelpoNfc.startListening((result) => {
167
+ if (result.success) {
168
+ const uid = result.data.uid;
169
+ // → call your API, update state, play sound, etc.
170
+ console.log('Card tapped:', uid);
171
+ } else {
172
+ console.error('NFC error:', result.error.message);
173
+ }
174
+ });
175
+
176
+ // Later, when unmounting:
177
+ await TelpoNfc.stopListening();
178
+ ```
179
+
180
+ #### With timeout
181
+
182
+ ```typescript
183
+ // Auto-cancel if no card tapped within 10 seconds
184
+ const result = await TelpoNfc.readTag({}, 10_000);
185
+ ```
186
+
187
+ ---
188
+
189
+ ### Scanner — QR / Barcode
190
+
191
+ #### Hook + View (recommended)
192
+
193
+ ```typescript
194
+ import { useTelpoScanner, TelpoScannerView } from 'react-native-telpo';
195
+ import type { ScanResult } from 'react-native-telpo';
196
+
197
+ function ValidatorScreen() {
198
+ const scanner = useTelpoScanner({
199
+ onResult: (result) => {
200
+ if (result.success) {
201
+ const { value, format, timestamp } = result.data;
202
+ console.log('Scanned:', value);
203
+ // → value is the raw ticket ID / QR content
204
+ // → do YOUR lookup logic here
205
+ }
206
+ },
207
+ options: {
208
+ formats: ['QR_CODE', 'CODE_128'], // filter to specific formats
209
+ deduplicateMs: 1500, // ignore same code for 1.5s
210
+ },
211
+ });
212
+
213
+ return (
214
+ <TelpoScannerView
215
+ scanner={scanner}
216
+ style={{ flex: 1 }}
217
+ showOverlay={true}
218
+ overlayColor="#00FF88"
219
+ />
220
+ );
221
+ }
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Result Pattern
227
+
228
+ Every async method returns `TelpoResult<T>`:
229
+
230
+ ```typescript
231
+ type TelpoResult<T> =
232
+ | { success: true; data: T }
233
+ | { success: false; error: { code: TelpoErrorCode; message: string } };
234
+ ```
235
+
236
+ Always check `result.success` before accessing `result.data`:
237
+
238
+ ```typescript
239
+ const result = await TelpoPrinter.printTicket({ ticketId: 'TKT-001' });
240
+
241
+ if (result.success) {
242
+ // result.data is void for print methods
243
+ console.log('Printed!');
244
+ } else {
245
+ // result.error.code is a TelpoErrorCode enum value
246
+ switch (result.error.code) {
247
+ case 'PRINTER_NO_PAPER':
248
+ alert('Out of paper!');
249
+ break;
250
+ case 'PRINTER_NOT_CONNECTED':
251
+ alert('Printer not connected!');
252
+ break;
253
+ default:
254
+ console.error(result.error.message);
255
+ }
256
+ }
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Error Codes
262
+
263
+ | Code | Module | Meaning |
264
+ |---|---|---|
265
+ | `PRINTER_NOT_CONNECTED` | Printer | connect() not called or failed |
266
+ | `PRINTER_NO_PAPER` | Printer | Paper out |
267
+ | `PRINTER_INIT_FAILED` | Printer | init() failed or iOS |
268
+ | `PRINTER_PRINT_FAILED` | Printer | Print job failed |
269
+ | `PRINTER_PERMISSION_DENIED` | Printer | USB permission denied |
270
+ | `NFC_NOT_SUPPORTED` | NFC | Device has no NFC chip |
271
+ | `NFC_DISABLED` | NFC | NFC is off in settings |
272
+ | `NFC_SCAN_CANCELLED` | NFC | User/timeout cancelled |
273
+ | `NFC_READ_FAILED` | NFC | Tag read error |
274
+ | `NFC_ALREADY_LISTENING` | NFC | startListening() already active |
275
+ | `SCANNER_CAMERA_PERMISSION_DENIED` | Scanner | Camera access denied |
276
+ | `SCANNER_NOT_ACTIVE` | Scanner | Library not loaded |
277
+
278
+ ---
279
+
280
+ ## TypeScript
281
+
282
+ The SDK is fully typed. Import types from the root:
283
+
284
+ ```typescript
285
+ import type {
286
+ TelpoResult,
287
+ TelpoError,
288
+ TelpoErrorCode,
289
+ PrintTicket,
290
+ PrintLine,
291
+ NfcTag,
292
+ ScanResult,
293
+ } from 'react-native-telpo';
294
+ ```
295
+
296
+ ---
297
+
298
+ ## License
299
+
300
+ MIT
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "ErrorCode", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _types.TelpoErrorCode;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "TelpoNfc", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _nfc.TelpoNfc;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "TelpoPrinter", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _printer.TelpoPrinter;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "TelpoScannerView", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _scanner.TelpoScannerView;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "useTelpoScanner", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _scanner.useTelpoScanner;
34
+ }
35
+ });
36
+ var _printer = require("./printer");
37
+ var _nfc = require("./nfc");
38
+ var _scanner = require("./scanner");
39
+ var _types = require("./types");
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_printer","require","_nfc","_scanner","_types"],"sourceRoot":"..\\..\\src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,IAAAA,QAAA,GAAAC,OAAA;AACA,IAAAC,IAAA,GAAAD,OAAA;AACA,IAAAE,QAAA,GAAAF,OAAA;AAmCA,IAAAG,MAAA,GAAAH,OAAA","ignoreList":[]}
@@ -0,0 +1,322 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.TelpoNfc = void 0;
7
+ var _types = require("../types");
8
+ /**
9
+ * TelpoNfc
10
+ *
11
+ * Wraps react-native-nfc-manager to provide a clean, typed API
12
+ * for reading NFC/contactless card UIDs on Telpo T20 and TPS320.
13
+ *
14
+ * Supports: ISO 14443-A/B (NfcA, NfcB), IsoDep, Mifare Classic,
15
+ * Mifare Ultralight, and NDEF tags.
16
+ *
17
+ * Returns the raw card UID as a hex string — you handle validation.
18
+ */
19
+
20
+ // Lazy-loaded to prevent crash if peer dep is missing
21
+ let NfcManager;
22
+ let NfcTechEnum;
23
+ let NfcEvents;
24
+ function loadNfcLib() {
25
+ try {
26
+ const lib = require('react-native-nfc-manager');
27
+ NfcManager = lib.default;
28
+ NfcTechEnum = lib.NfcTech;
29
+ NfcEvents = lib.NfcEvents;
30
+ } catch {
31
+ throw buildError(_types.TelpoErrorCode.NFC_NOT_SUPPORTED, 'Peer dependency react-native-nfc-manager is not installed. Run: npm install react-native-nfc-manager');
32
+ }
33
+ }
34
+
35
+ // ── Helpers ───────────────────────────────────────────────────────────────────
36
+
37
+ function buildError(code, message, raw) {
38
+ return {
39
+ code,
40
+ message,
41
+ raw
42
+ };
43
+ }
44
+ function wrapSuccess(data) {
45
+ return {
46
+ success: true,
47
+ data
48
+ };
49
+ }
50
+ function wrapError(error) {
51
+ return {
52
+ success: false,
53
+ error
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Convert a byte array to a colon-separated hex string.
59
+ * e.g. [0x04, 0xAB, 0x12] → "04:AB:12"
60
+ */
61
+ function bytesToHex(bytes) {
62
+ return bytes.map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(':');
63
+ }
64
+ function mapTech(tech) {
65
+ // Map our type to the NfcTech enum values from the library
66
+ const map = {
67
+ NfcA: 'NfcA',
68
+ NfcB: 'NfcB',
69
+ IsoDep: 'IsoDep',
70
+ MifareClassic: 'MifareClassic',
71
+ MifareUltralight: 'MifareUltralight',
72
+ Ndef: 'Ndef'
73
+ };
74
+ return map[tech];
75
+ }
76
+ function detectTechnology(tag) {
77
+ if (tag.techTypes?.includes('android.nfc.tech.MifareClassic')) return 'MifareClassic';
78
+ if (tag.techTypes?.includes('android.nfc.tech.MifareUltralight')) return 'MifareUltralight';
79
+ if (tag.techTypes?.includes('android.nfc.tech.IsoDep')) return 'IsoDep';
80
+ if (tag.techTypes?.includes('android.nfc.tech.NfcB')) return 'NfcB';
81
+ if (tag.techTypes?.includes('android.nfc.tech.Ndef')) return 'Ndef';
82
+ return 'NfcA';
83
+ }
84
+
85
+ // ── State ─────────────────────────────────────────────────────────────────────
86
+
87
+ let _started = false;
88
+ let _listening = false;
89
+
90
+ // ── Module ────────────────────────────────────────────────────────────────────
91
+
92
+ /**
93
+ * TelpoNfc
94
+ *
95
+ * @example
96
+ * // One-time setup (call in your app root or screen init)
97
+ * await TelpoNfc.init();
98
+ *
99
+ * // Start listening for a card tap — resolves immediately on tap
100
+ * const result = await TelpoNfc.readTag();
101
+ * if (result.success) {
102
+ * console.log(result.data.uid); // "04:AB:12:CD:EF:01:23"
103
+ * }
104
+ *
105
+ * // For continuous listening (e.g. validator gate)
106
+ * TelpoNfc.startListening((result) => {
107
+ * if (result.success) {
108
+ * handleCard(result.data.uid);
109
+ * }
110
+ * });
111
+ * // Later:
112
+ * TelpoNfc.stopListening();
113
+ */
114
+ const TelpoNfc = exports.TelpoNfc = {
115
+ get _started() {
116
+ return _started;
117
+ },
118
+ set _started(value) {
119
+ _started = value;
120
+ },
121
+ get _listening() {
122
+ return _listening;
123
+ },
124
+ set _listening(value) {
125
+ _listening = value;
126
+ },
127
+ /**
128
+ * Initialise NFC and verify it is supported and enabled on the device.
129
+ * Call once on app start or screen mount.
130
+ */
131
+ async init() {
132
+ try {
133
+ loadNfcLib();
134
+ } catch (e) {
135
+ return wrapError(e);
136
+ }
137
+ try {
138
+ const supported = await NfcManager.isSupported();
139
+ if (!supported) {
140
+ return wrapError(buildError(_types.TelpoErrorCode.NFC_NOT_SUPPORTED, 'NFC is not supported on this device.'));
141
+ }
142
+ if (!_started) {
143
+ await NfcManager.start();
144
+ _started = true;
145
+ }
146
+ const enabled = await NfcManager.isEnabled();
147
+ if (!enabled) {
148
+ return wrapError(buildError(_types.TelpoErrorCode.NFC_DISABLED, 'NFC is disabled. Please enable NFC in device settings.'));
149
+ }
150
+ return wrapSuccess(undefined);
151
+ } catch (e) {
152
+ return wrapError(buildError(_types.TelpoErrorCode.NFC_NOT_SUPPORTED, 'Failed to initialise NFC', e));
153
+ }
154
+ },
155
+ /**
156
+ * Wait for a single NFC tag tap and resolve with its UID.
157
+ * Rejects if cancelled or an error occurs.
158
+ *
159
+ * This is the recommended approach for a "tap once" validation flow.
160
+ *
161
+ * @param options.technologies NFC technologies to accept (default: all)
162
+ * @param timeoutMs Auto-cancel after N ms (default: no timeout)
163
+ */
164
+ async readTag(options = {}, timeoutMs) {
165
+ if (!_started) {
166
+ const initResult = await TelpoNfc.init();
167
+ if (!initResult.success) return initResult;
168
+ }
169
+ if (_listening) {
170
+ return wrapError(buildError(_types.TelpoErrorCode.NFC_ALREADY_LISTENING, 'NFC is already in continuous-listen mode. Call stopListening() first.'));
171
+ }
172
+ const techs = (options.technologies ?? ['NfcA', 'NfcB', 'IsoDep', 'MifareClassic', 'MifareUltralight', 'Ndef']).map(mapTech).map(t => NfcTechEnum[t]).filter(Boolean);
173
+ let timeoutHandle = null;
174
+ try {
175
+ const tagPromise = new Promise(async (resolve, reject) => {
176
+ try {
177
+ await NfcManager.requestTechnology(techs);
178
+ const rawTag = await NfcManager.getTag();
179
+ if (!rawTag) {
180
+ reject(buildError(_types.TelpoErrorCode.NFC_READ_FAILED, 'No tag data returned.'));
181
+ return;
182
+ }
183
+ const uid = rawTag.id ? bytesToHex(rawTag.id) : 'UNKNOWN';
184
+ const technology = detectTechnology(rawTag);
185
+ resolve({
186
+ uid,
187
+ technology,
188
+ raw: rawTag
189
+ });
190
+ } catch (e) {
191
+ if (e?.message?.includes('Cancel') || e?.message?.includes('cancel')) {
192
+ reject(buildError(_types.TelpoErrorCode.NFC_SCAN_CANCELLED, 'NFC scan was cancelled.'));
193
+ } else {
194
+ reject(buildError(_types.TelpoErrorCode.NFC_READ_FAILED, 'Failed to read NFC tag', e));
195
+ }
196
+ } finally {
197
+ await NfcManager.cancelTechnologyRequest().catch(() => null);
198
+ }
199
+ });
200
+ let tag;
201
+ if (timeoutMs) {
202
+ tag = await Promise.race([tagPromise, new Promise((_, reject) => {
203
+ timeoutHandle = setTimeout(() => {
204
+ NfcManager.cancelTechnologyRequest().catch(() => null);
205
+ reject(buildError(_types.TelpoErrorCode.NFC_SCAN_CANCELLED, `NFC scan timed out after ${timeoutMs}ms.`));
206
+ }, timeoutMs);
207
+ })]);
208
+ } else {
209
+ tag = await tagPromise;
210
+ }
211
+ return wrapSuccess(tag);
212
+ } catch (e) {
213
+ const err = e;
214
+ if (err.code) return wrapError(err);
215
+ return wrapError(buildError(_types.TelpoErrorCode.NFC_READ_FAILED, 'Unexpected NFC error', e));
216
+ } finally {
217
+ if (timeoutHandle !== null) clearTimeout(timeoutHandle);
218
+ }
219
+ },
220
+ /**
221
+ * Start continuous NFC listening — ideal for a validation gate that
222
+ * must handle many card taps without user interaction.
223
+ *
224
+ * The callback fires every time a card is tapped.
225
+ * Call `stopListening()` to end the session.
226
+ *
227
+ * @example
228
+ * TelpoNfc.startListening((result) => {
229
+ * if (result.success) {
230
+ * console.log('Card UID:', result.data.uid);
231
+ * }
232
+ * }, { technologies: ['NfcA', 'IsoDep'] });
233
+ */
234
+ startListening(onTag, options = {}) {
235
+ if (!_started) {
236
+ // Auto-init in background; errors surface via callback
237
+ TelpoNfc.init().then(initResult => {
238
+ if (!initResult.success) {
239
+ onTag(initResult);
240
+ return;
241
+ }
242
+ _startEventLoop(onTag, options);
243
+ });
244
+ return;
245
+ }
246
+ _startEventLoop(onTag, options);
247
+ },
248
+ /**
249
+ * Stop continuous NFC listening started by `startListening()`.
250
+ */
251
+ async stopListening() {
252
+ _listening = false;
253
+ if (!NfcManager) return;
254
+ NfcManager.setEventListener(NfcEvents.DiscoverTag, null);
255
+ NfcManager.setEventListener(NfcEvents.SessionClosed, null);
256
+ try {
257
+ await NfcManager.unregisterTagEvent();
258
+ } catch {
259
+ // Ignore — may already be unregistered
260
+ }
261
+ },
262
+ /**
263
+ * Whether NFC is supported and enabled on this device.
264
+ * Returns false if not initialised yet.
265
+ */
266
+ async isAvailable() {
267
+ try {
268
+ loadNfcLib();
269
+ const supported = await NfcManager.isSupported();
270
+ if (!supported) return false;
271
+ return await NfcManager.isEnabled();
272
+ } catch {
273
+ return false;
274
+ }
275
+ },
276
+ /** Whether the continuous listener is currently active. */
277
+ isListening() {
278
+ return _listening;
279
+ },
280
+ /** Whether NfcManager has been started. */
281
+ isStarted() {
282
+ return _started;
283
+ }
284
+ };
285
+
286
+ // ── Internal event loop for startListening ───────────────────────────────────
287
+
288
+ function _startEventLoop(onTag, _options) {
289
+ if (_listening) {
290
+ onTag(wrapError(buildError(_types.TelpoErrorCode.NFC_ALREADY_LISTENING, 'NFC listener is already active.')));
291
+ return;
292
+ }
293
+ _listening = true;
294
+ const _handleTag = rawTag => {
295
+ if (!rawTag) {
296
+ onTag(wrapError(buildError(_types.TelpoErrorCode.NFC_READ_FAILED, 'Empty tag received.')));
297
+ return;
298
+ }
299
+ const uid = rawTag.id ? bytesToHex(rawTag.id) : 'UNKNOWN';
300
+ const technology = detectTechnology(rawTag);
301
+ onTag(wrapSuccess({
302
+ uid,
303
+ technology,
304
+ raw: rawTag
305
+ }));
306
+ };
307
+ const _handleClose = () => {
308
+ if (_listening) {
309
+ // Session closed unexpectedly — restart
310
+ NfcManager.registerTagEvent().catch(() => {
311
+ _listening = false;
312
+ });
313
+ }
314
+ };
315
+ NfcManager.setEventListener(NfcEvents.DiscoverTag, _handleTag);
316
+ NfcManager.setEventListener(NfcEvents.SessionClosed, _handleClose);
317
+ NfcManager.registerTagEvent().catch(e => {
318
+ _listening = false;
319
+ onTag(wrapError(buildError(_types.TelpoErrorCode.NFC_READ_FAILED, 'Failed to register NFC tag event', e)));
320
+ });
321
+ }
322
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_types","require","NfcManager","NfcTechEnum","NfcEvents","loadNfcLib","lib","default","NfcTech","buildError","TelpoErrorCode","NFC_NOT_SUPPORTED","code","message","raw","wrapSuccess","data","success","wrapError","error","bytesToHex","bytes","map","b","toString","padStart","toUpperCase","join","mapTech","tech","NfcA","NfcB","IsoDep","MifareClassic","MifareUltralight","Ndef","detectTechnology","tag","techTypes","includes","_started","_listening","TelpoNfc","exports","value","init","e","supported","isSupported","start","enabled","isEnabled","NFC_DISABLED","undefined","readTag","options","timeoutMs","initResult","NFC_ALREADY_LISTENING","techs","technologies","t","filter","Boolean","timeoutHandle","tagPromise","Promise","resolve","reject","requestTechnology","rawTag","getTag","NFC_READ_FAILED","uid","id","technology","NFC_SCAN_CANCELLED","cancelTechnologyRequest","catch","race","_","setTimeout","err","clearTimeout","startListening","onTag","then","_startEventLoop","stopListening","setEventListener","DiscoverTag","SessionClosed","unregisterTagEvent","isAvailable","isListening","isStarted","_options","_handleTag","_handleClose","registerTagEvent"],"sourceRoot":"..\\..\\..\\src","sources":["nfc/index.ts"],"mappings":"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","ignoreList":[]}