smartcard 2.0.1 → 2.0.3

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 (2) hide show
  1. package/lib/devices.js +38 -8
  2. package/package.json +1 -1
package/lib/devices.js CHANGED
@@ -50,6 +50,8 @@ class Devices extends EventEmitter {
50
50
  this._running = false;
51
51
  /** @type {Map<string, ReaderState>} */
52
52
  this._readers = new Map();
53
+ /** @type {Promise<void>} Event queue to serialize event handling */
54
+ this._eventQueue = Promise.resolve();
53
55
  }
54
56
 
55
57
  /**
@@ -131,10 +133,20 @@ class Devices extends EventEmitter {
131
133
 
132
134
  /**
133
135
  * Handle events from native monitor
136
+ * Queues events to prevent race conditions when multiple events arrive concurrently
137
+ * @param {MonitorEvent} event
138
+ */
139
+ _handleEvent(event) {
140
+ // Chain this event onto the queue to serialize processing
141
+ this._eventQueue = this._eventQueue.then(() => this._processEvent(event));
142
+ }
143
+
144
+ /**
145
+ * Process a single event (called sequentially via queue)
134
146
  * @param {MonitorEvent} event
135
147
  * @returns {Promise<void>}
136
148
  */
137
- async _handleEvent(event) {
149
+ async _processEvent(event) {
138
150
  if (!this._running) {
139
151
  return;
140
152
  }
@@ -143,7 +155,7 @@ class Devices extends EventEmitter {
143
155
 
144
156
  switch (type) {
145
157
  case 'reader-attached':
146
- this._handleReaderAttached(readerName, state, atr);
158
+ await this._handleReaderAttached(readerName, state, atr);
147
159
  break;
148
160
 
149
161
  case 'reader-detached':
@@ -170,8 +182,9 @@ class Devices extends EventEmitter {
170
182
  * @param {string} readerName
171
183
  * @param {number} state
172
184
  * @param {Buffer|null} atr
185
+ * @returns {Promise<void>}
173
186
  */
174
- _handleReaderAttached(readerName, state, atr) {
187
+ async _handleReaderAttached(readerName, state, atr) {
175
188
  // Initialize reader state
176
189
  this._readers.set(readerName, {
177
190
  hasCard: false,
@@ -189,7 +202,7 @@ class Devices extends EventEmitter {
189
202
 
190
203
  // Check if card is already present
191
204
  if ((state & SCARD_STATE_PRESENT) !== 0) {
192
- this._handleCardInserted(readerName, state, atr);
205
+ await this._handleCardInserted(readerName, state, atr);
193
206
  }
194
207
  }
195
208
 
@@ -233,10 +246,27 @@ class Devices extends EventEmitter {
233
246
  const reader = readers.find(r => r.name === readerName);
234
247
 
235
248
  if (reader) {
236
- const card = await reader.connect(
237
- SCARD_SHARE_SHARED,
238
- SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
239
- );
249
+ let card;
250
+ try {
251
+ // First try with both T=0 and T=1 protocols
252
+ card = await reader.connect(
253
+ SCARD_SHARE_SHARED,
254
+ SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1
255
+ );
256
+ } catch (dualProtocolErr) {
257
+ // If dual protocol fails (e.g., SCARD_W_UNRESPONSIVE_CARD),
258
+ // fallback to T=0 only (issue #34)
259
+ if (dualProtocolErr.message &&
260
+ dualProtocolErr.message.toLowerCase().includes('unresponsive')) {
261
+ card = await reader.connect(
262
+ SCARD_SHARE_SHARED,
263
+ SCARD_PROTOCOL_T0
264
+ );
265
+ } else {
266
+ // Re-throw if it's a different error
267
+ throw dualProtocolErr;
268
+ }
269
+ }
240
270
 
241
271
  state.card = card;
242
272
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smartcard",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "PC/SC bindings for Node.js using N-API - ABI stable across Node.js versions",
5
5
  "author": "Tom KP",
6
6
  "license": "MIT",