smartcard 1.0.46 → 2.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.
@@ -0,0 +1,234 @@
1
+ #include "async_workers.h"
2
+ #include "pcsc_card.h"
3
+ #include "pcsc_errors.h"
4
+ #include <cstring>
5
+
6
+ // ============================================================================
7
+ // WaitForChangeWorker
8
+ // ============================================================================
9
+
10
+ WaitForChangeWorker::WaitForChangeWorker(
11
+ Napi::Env env,
12
+ SCARDCONTEXT context,
13
+ std::vector<std::string> readerNames,
14
+ std::vector<DWORD> currentStates,
15
+ DWORD timeout,
16
+ Napi::Promise::Deferred deferred)
17
+ : Napi::AsyncWorker(env),
18
+ context_(context),
19
+ readerNames_(std::move(readerNames)),
20
+ timeout_(timeout),
21
+ result_(SCARD_S_SUCCESS),
22
+ deferred_(deferred) {
23
+
24
+ // Initialize reader states
25
+ states_.resize(readerNames_.size());
26
+ for (size_t i = 0; i < readerNames_.size(); i++) {
27
+ memset(&states_[i], 0, sizeof(SCARD_READERSTATE));
28
+ states_[i].szReader = readerNames_[i].c_str();
29
+ states_[i].dwCurrentState = (i < currentStates.size()) ? currentStates[i] : SCARD_STATE_UNAWARE;
30
+ }
31
+ }
32
+
33
+ void WaitForChangeWorker::Execute() {
34
+ // This runs on worker thread - safe to block
35
+ result_ = SCardGetStatusChange(context_, timeout_, states_.data(), states_.size());
36
+ }
37
+
38
+ void WaitForChangeWorker::OnOK() {
39
+ Napi::Env env = Env();
40
+
41
+ if (result_ == SCARD_S_SUCCESS) {
42
+ // Build array of reader states
43
+ Napi::Array changes = Napi::Array::New(env);
44
+
45
+ for (size_t i = 0; i < states_.size(); i++) {
46
+ Napi::Object reader = Napi::Object::New(env);
47
+ reader.Set("name", Napi::String::New(env, readerNames_[i]));
48
+ reader.Set("state", Napi::Number::New(env, states_[i].dwEventState));
49
+ reader.Set("changed", Napi::Boolean::New(env,
50
+ (states_[i].dwEventState & SCARD_STATE_CHANGED) != 0));
51
+
52
+ if (states_[i].cbAtr > 0) {
53
+ reader.Set("atr", Napi::Buffer<uint8_t>::Copy(
54
+ env, states_[i].rgbAtr, states_[i].cbAtr));
55
+ } else {
56
+ reader.Set("atr", env.Null());
57
+ }
58
+
59
+ changes.Set(static_cast<uint32_t>(i), reader);
60
+ }
61
+
62
+ deferred_.Resolve(changes);
63
+ } else if (result_ == SCARD_E_CANCELLED) {
64
+ // Cancelled - resolve with null
65
+ deferred_.Resolve(env.Null());
66
+ } else if (result_ == SCARD_E_TIMEOUT) {
67
+ // Timeout - resolve with empty array
68
+ deferred_.Resolve(Napi::Array::New(env, 0));
69
+ } else {
70
+ deferred_.Reject(Napi::Error::New(env, GetPCSCErrorString(result_)).Value());
71
+ }
72
+ }
73
+
74
+ void WaitForChangeWorker::OnError(const Napi::Error& error) {
75
+ deferred_.Reject(error.Value());
76
+ }
77
+
78
+ // ============================================================================
79
+ // TransmitWorker
80
+ // ============================================================================
81
+
82
+ TransmitWorker::TransmitWorker(
83
+ Napi::Env env,
84
+ SCARDHANDLE card,
85
+ DWORD protocol,
86
+ std::vector<uint8_t> sendBuffer,
87
+ Napi::Promise::Deferred deferred)
88
+ : Napi::AsyncWorker(env),
89
+ card_(card),
90
+ protocol_(protocol),
91
+ sendBuffer_(std::move(sendBuffer)),
92
+ recvLength_(0),
93
+ result_(SCARD_S_SUCCESS),
94
+ deferred_(deferred) {
95
+ // Pre-allocate receive buffer (max APDU response size)
96
+ recvBuffer_.resize(258);
97
+ }
98
+
99
+ void TransmitWorker::Execute() {
100
+ // Select protocol-specific PCI structure
101
+ const SCARD_IO_REQUEST* pioSendPci;
102
+ if (protocol_ == SCARD_PROTOCOL_T0) {
103
+ pioSendPci = SCARD_PCI_T0;
104
+ } else if (protocol_ == SCARD_PROTOCOL_T1) {
105
+ pioSendPci = SCARD_PCI_T1;
106
+ } else {
107
+ pioSendPci = SCARD_PCI_RAW;
108
+ }
109
+
110
+ recvLength_ = static_cast<DWORD>(recvBuffer_.size());
111
+
112
+ result_ = SCardTransmit(
113
+ card_,
114
+ pioSendPci,
115
+ sendBuffer_.data(),
116
+ static_cast<DWORD>(sendBuffer_.size()),
117
+ nullptr,
118
+ recvBuffer_.data(),
119
+ &recvLength_
120
+ );
121
+ }
122
+
123
+ void TransmitWorker::OnOK() {
124
+ Napi::Env env = Env();
125
+
126
+ if (result_ == SCARD_S_SUCCESS) {
127
+ Napi::Buffer<uint8_t> buffer = Napi::Buffer<uint8_t>::Copy(
128
+ env, recvBuffer_.data(), recvLength_);
129
+ deferred_.Resolve(buffer);
130
+ } else {
131
+ deferred_.Reject(Napi::Error::New(env, GetPCSCErrorString(result_)).Value());
132
+ }
133
+ }
134
+
135
+ void TransmitWorker::OnError(const Napi::Error& error) {
136
+ deferred_.Reject(error.Value());
137
+ }
138
+
139
+ // ============================================================================
140
+ // ControlWorker
141
+ // ============================================================================
142
+
143
+ ControlWorker::ControlWorker(
144
+ Napi::Env env,
145
+ SCARDHANDLE card,
146
+ DWORD controlCode,
147
+ std::vector<uint8_t> sendBuffer,
148
+ Napi::Promise::Deferred deferred)
149
+ : Napi::AsyncWorker(env),
150
+ card_(card),
151
+ controlCode_(controlCode),
152
+ sendBuffer_(std::move(sendBuffer)),
153
+ bytesReturned_(0),
154
+ result_(SCARD_S_SUCCESS),
155
+ deferred_(deferred) {
156
+ // Pre-allocate receive buffer
157
+ recvBuffer_.resize(256);
158
+ }
159
+
160
+ void ControlWorker::Execute() {
161
+ result_ = SCardControl(
162
+ card_,
163
+ controlCode_,
164
+ sendBuffer_.empty() ? nullptr : sendBuffer_.data(),
165
+ static_cast<DWORD>(sendBuffer_.size()),
166
+ recvBuffer_.data(),
167
+ static_cast<DWORD>(recvBuffer_.size()),
168
+ &bytesReturned_
169
+ );
170
+ }
171
+
172
+ void ControlWorker::OnOK() {
173
+ Napi::Env env = Env();
174
+
175
+ if (result_ == SCARD_S_SUCCESS) {
176
+ Napi::Buffer<uint8_t> buffer = Napi::Buffer<uint8_t>::Copy(
177
+ env, recvBuffer_.data(), bytesReturned_);
178
+ deferred_.Resolve(buffer);
179
+ } else {
180
+ deferred_.Reject(Napi::Error::New(env, GetPCSCErrorString(result_)).Value());
181
+ }
182
+ }
183
+
184
+ void ControlWorker::OnError(const Napi::Error& error) {
185
+ deferred_.Reject(error.Value());
186
+ }
187
+
188
+ // ============================================================================
189
+ // ConnectWorker
190
+ // ============================================================================
191
+
192
+ ConnectWorker::ConnectWorker(
193
+ Napi::Env env,
194
+ SCARDCONTEXT context,
195
+ std::string readerName,
196
+ DWORD shareMode,
197
+ DWORD preferredProtocols,
198
+ Napi::Promise::Deferred deferred)
199
+ : Napi::AsyncWorker(env),
200
+ context_(context),
201
+ readerName_(std::move(readerName)),
202
+ shareMode_(shareMode),
203
+ preferredProtocols_(preferredProtocols),
204
+ card_(0),
205
+ activeProtocol_(0),
206
+ result_(SCARD_S_SUCCESS),
207
+ deferred_(deferred) {
208
+ }
209
+
210
+ void ConnectWorker::Execute() {
211
+ result_ = SCardConnect(
212
+ context_,
213
+ readerName_.c_str(),
214
+ shareMode_,
215
+ preferredProtocols_,
216
+ &card_,
217
+ &activeProtocol_
218
+ );
219
+ }
220
+
221
+ void ConnectWorker::OnOK() {
222
+ Napi::Env env = Env();
223
+
224
+ if (result_ == SCARD_S_SUCCESS) {
225
+ Napi::Object card = PCSCCard::NewInstance(env, card_, activeProtocol_, readerName_);
226
+ deferred_.Resolve(card);
227
+ } else {
228
+ deferred_.Reject(Napi::Error::New(env, GetPCSCErrorString(result_)).Value());
229
+ }
230
+ }
231
+
232
+ void ConnectWorker::OnError(const Napi::Error& error) {
233
+ deferred_.Reject(error.Value());
234
+ }
@@ -0,0 +1,100 @@
1
+ #pragma once
2
+
3
+ #include <napi.h>
4
+ #include <vector>
5
+ #include <string>
6
+ #include "platform/pcsc.h"
7
+
8
+ // Async worker for SCardGetStatusChange
9
+ class WaitForChangeWorker : public Napi::AsyncWorker {
10
+ public:
11
+ WaitForChangeWorker(Napi::Env env,
12
+ SCARDCONTEXT context,
13
+ std::vector<std::string> readerNames,
14
+ std::vector<DWORD> currentStates,
15
+ DWORD timeout,
16
+ Napi::Promise::Deferred deferred);
17
+
18
+ void Execute() override;
19
+ void OnOK() override;
20
+ void OnError(const Napi::Error& error) override;
21
+
22
+ private:
23
+ SCARDCONTEXT context_;
24
+ std::vector<std::string> readerNames_;
25
+ std::vector<SCARD_READERSTATE> states_;
26
+ DWORD timeout_;
27
+ LONG result_;
28
+ Napi::Promise::Deferred deferred_;
29
+ };
30
+
31
+ // Async worker for SCardTransmit
32
+ class TransmitWorker : public Napi::AsyncWorker {
33
+ public:
34
+ TransmitWorker(Napi::Env env,
35
+ SCARDHANDLE card,
36
+ DWORD protocol,
37
+ std::vector<uint8_t> sendBuffer,
38
+ Napi::Promise::Deferred deferred);
39
+
40
+ void Execute() override;
41
+ void OnOK() override;
42
+ void OnError(const Napi::Error& error) override;
43
+
44
+ private:
45
+ SCARDHANDLE card_;
46
+ DWORD protocol_;
47
+ std::vector<uint8_t> sendBuffer_;
48
+ std::vector<uint8_t> recvBuffer_;
49
+ DWORD recvLength_;
50
+ LONG result_;
51
+ Napi::Promise::Deferred deferred_;
52
+ };
53
+
54
+ // Async worker for SCardControl
55
+ class ControlWorker : public Napi::AsyncWorker {
56
+ public:
57
+ ControlWorker(Napi::Env env,
58
+ SCARDHANDLE card,
59
+ DWORD controlCode,
60
+ std::vector<uint8_t> sendBuffer,
61
+ Napi::Promise::Deferred deferred);
62
+
63
+ void Execute() override;
64
+ void OnOK() override;
65
+ void OnError(const Napi::Error& error) override;
66
+
67
+ private:
68
+ SCARDHANDLE card_;
69
+ DWORD controlCode_;
70
+ std::vector<uint8_t> sendBuffer_;
71
+ std::vector<uint8_t> recvBuffer_;
72
+ DWORD bytesReturned_;
73
+ LONG result_;
74
+ Napi::Promise::Deferred deferred_;
75
+ };
76
+
77
+ // Async worker for SCardConnect
78
+ class ConnectWorker : public Napi::AsyncWorker {
79
+ public:
80
+ ConnectWorker(Napi::Env env,
81
+ SCARDCONTEXT context,
82
+ std::string readerName,
83
+ DWORD shareMode,
84
+ DWORD preferredProtocols,
85
+ Napi::Promise::Deferred deferred);
86
+
87
+ void Execute() override;
88
+ void OnOK() override;
89
+ void OnError(const Napi::Error& error) override;
90
+
91
+ private:
92
+ SCARDCONTEXT context_;
93
+ std::string readerName_;
94
+ DWORD shareMode_;
95
+ DWORD preferredProtocols_;
96
+ SCARDHANDLE card_;
97
+ DWORD activeProtocol_;
98
+ LONG result_;
99
+ Napi::Promise::Deferred deferred_;
100
+ };
@@ -0,0 +1,248 @@
1
+ #include "pcsc_card.h"
2
+ #include "pcsc_errors.h"
3
+ #include "async_workers.h"
4
+ #include <cstring>
5
+
6
+ Napi::FunctionReference PCSCCard::constructor;
7
+
8
+ Napi::Object PCSCCard::Init(Napi::Env env, Napi::Object exports) {
9
+ Napi::Function func = DefineClass(env, "Card", {
10
+ InstanceAccessor("protocol", &PCSCCard::GetProtocolValue, nullptr),
11
+ InstanceAccessor("connected", &PCSCCard::GetConnectedValue, nullptr),
12
+ InstanceAccessor("atr", &PCSCCard::GetAtr, nullptr),
13
+ InstanceMethod("transmit", &PCSCCard::Transmit),
14
+ InstanceMethod("control", &PCSCCard::Control),
15
+ InstanceMethod("getStatus", &PCSCCard::GetStatus),
16
+ InstanceMethod("disconnect", &PCSCCard::Disconnect),
17
+ InstanceMethod("reconnect", &PCSCCard::Reconnect),
18
+ });
19
+
20
+ constructor = Napi::Persistent(func);
21
+ constructor.SuppressDestruct();
22
+
23
+ exports.Set("Card", func);
24
+ return exports;
25
+ }
26
+
27
+ Napi::Object PCSCCard::NewInstance(Napi::Env env, SCARDHANDLE card,
28
+ DWORD protocol, const std::string& readerName) {
29
+ Napi::Object obj = constructor.New({});
30
+ PCSCCard* cardObj = Napi::ObjectWrap<PCSCCard>::Unwrap(obj);
31
+ cardObj->card_ = card;
32
+ cardObj->protocol_ = protocol;
33
+ cardObj->readerName_ = readerName;
34
+ cardObj->connected_ = true;
35
+ return obj;
36
+ }
37
+
38
+ PCSCCard::PCSCCard(const Napi::CallbackInfo& info)
39
+ : Napi::ObjectWrap<PCSCCard>(info),
40
+ card_(0),
41
+ protocol_(SCARD_PROTOCOL_UNDEFINED),
42
+ connected_(false) {
43
+ // Properties set via NewInstance
44
+ }
45
+
46
+ PCSCCard::~PCSCCard() {
47
+ if (connected_ && card_ != 0) {
48
+ SCardDisconnect(card_, SCARD_LEAVE_CARD);
49
+ connected_ = false;
50
+ card_ = 0;
51
+ }
52
+ }
53
+
54
+ Napi::Value PCSCCard::GetProtocolValue(const Napi::CallbackInfo& info) {
55
+ return Napi::Number::New(info.Env(), protocol_);
56
+ }
57
+
58
+ Napi::Value PCSCCard::GetConnectedValue(const Napi::CallbackInfo& info) {
59
+ return Napi::Boolean::New(info.Env(), connected_);
60
+ }
61
+
62
+ Napi::Value PCSCCard::GetAtr(const Napi::CallbackInfo& info) {
63
+ Napi::Env env = info.Env();
64
+
65
+ if (!connected_) {
66
+ return env.Null();
67
+ }
68
+
69
+ // Get ATR via SCardStatus
70
+ DWORD readerLen = 0;
71
+ DWORD state = 0;
72
+ DWORD protocol = 0;
73
+ BYTE atr[MAX_ATR_SIZE];
74
+ DWORD atrLen = sizeof(atr);
75
+
76
+ LONG result = SCardStatus(card_, nullptr, &readerLen, &state, &protocol, atr, &atrLen);
77
+
78
+ if (result != SCARD_S_SUCCESS) {
79
+ return env.Null();
80
+ }
81
+
82
+ return Napi::Buffer<uint8_t>::Copy(env, atr, atrLen);
83
+ }
84
+
85
+ Napi::Value PCSCCard::Transmit(const Napi::CallbackInfo& info) {
86
+ Napi::Env env = info.Env();
87
+
88
+ if (!connected_) {
89
+ Napi::Error::New(env, "Card is not connected").ThrowAsJavaScriptException();
90
+ return env.Null();
91
+ }
92
+
93
+ if (info.Length() < 1) {
94
+ Napi::TypeError::New(env, "Expected command buffer").ThrowAsJavaScriptException();
95
+ return env.Null();
96
+ }
97
+
98
+ std::vector<uint8_t> sendBuffer;
99
+
100
+ if (info[0].IsBuffer()) {
101
+ Napi::Buffer<uint8_t> buffer = info[0].As<Napi::Buffer<uint8_t>>();
102
+ sendBuffer.assign(buffer.Data(), buffer.Data() + buffer.Length());
103
+ } else if (info[0].IsArray()) {
104
+ Napi::Array arr = info[0].As<Napi::Array>();
105
+ sendBuffer.reserve(arr.Length());
106
+ for (uint32_t i = 0; i < arr.Length(); i++) {
107
+ sendBuffer.push_back(static_cast<uint8_t>(arr.Get(i).As<Napi::Number>().Uint32Value()));
108
+ }
109
+ } else {
110
+ Napi::TypeError::New(env, "Expected Buffer or Array").ThrowAsJavaScriptException();
111
+ return env.Null();
112
+ }
113
+
114
+ // Create promise for async transmit
115
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
116
+
117
+ TransmitWorker* worker = new TransmitWorker(
118
+ env, card_, protocol_, sendBuffer, deferred);
119
+ worker->Queue();
120
+
121
+ return deferred.Promise();
122
+ }
123
+
124
+ Napi::Value PCSCCard::Control(const Napi::CallbackInfo& info) {
125
+ Napi::Env env = info.Env();
126
+
127
+ if (!connected_) {
128
+ Napi::Error::New(env, "Card is not connected").ThrowAsJavaScriptException();
129
+ return env.Null();
130
+ }
131
+
132
+ if (info.Length() < 1 || !info[0].IsNumber()) {
133
+ Napi::TypeError::New(env, "Expected control code").ThrowAsJavaScriptException();
134
+ return env.Null();
135
+ }
136
+
137
+ DWORD controlCode = info[0].As<Napi::Number>().Uint32Value();
138
+
139
+ std::vector<uint8_t> sendBuffer;
140
+ if (info.Length() > 1) {
141
+ if (info[1].IsBuffer()) {
142
+ Napi::Buffer<uint8_t> buffer = info[1].As<Napi::Buffer<uint8_t>>();
143
+ sendBuffer.assign(buffer.Data(), buffer.Data() + buffer.Length());
144
+ } else if (info[1].IsArray()) {
145
+ Napi::Array arr = info[1].As<Napi::Array>();
146
+ sendBuffer.reserve(arr.Length());
147
+ for (uint32_t i = 0; i < arr.Length(); i++) {
148
+ sendBuffer.push_back(static_cast<uint8_t>(arr.Get(i).As<Napi::Number>().Uint32Value()));
149
+ }
150
+ }
151
+ }
152
+
153
+ // Create promise for async control
154
+ Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
155
+
156
+ ControlWorker* worker = new ControlWorker(
157
+ env, card_, controlCode, sendBuffer, deferred);
158
+ worker->Queue();
159
+
160
+ return deferred.Promise();
161
+ }
162
+
163
+ Napi::Value PCSCCard::GetStatus(const Napi::CallbackInfo& info) {
164
+ Napi::Env env = info.Env();
165
+
166
+ if (!connected_) {
167
+ Napi::Error::New(env, "Card is not connected").ThrowAsJavaScriptException();
168
+ return env.Null();
169
+ }
170
+
171
+ DWORD readerLen = 0;
172
+ DWORD state = 0;
173
+ DWORD protocol = 0;
174
+ BYTE atr[MAX_ATR_SIZE];
175
+ DWORD atrLen = sizeof(atr);
176
+
177
+ // First call to get reader name length
178
+ LONG result = SCardStatus(card_, nullptr, &readerLen, &state, &protocol, atr, &atrLen);
179
+
180
+ if (result != SCARD_S_SUCCESS) {
181
+ Napi::Error::New(env, GetPCSCErrorString(result)).ThrowAsJavaScriptException();
182
+ return env.Null();
183
+ }
184
+
185
+ Napi::Object status = Napi::Object::New(env);
186
+ status.Set("state", Napi::Number::New(env, state));
187
+ status.Set("protocol", Napi::Number::New(env, protocol));
188
+ status.Set("atr", Napi::Buffer<uint8_t>::Copy(env, atr, atrLen));
189
+
190
+ return status;
191
+ }
192
+
193
+ Napi::Value PCSCCard::Disconnect(const Napi::CallbackInfo& info) {
194
+ Napi::Env env = info.Env();
195
+
196
+ if (!connected_) {
197
+ return env.Undefined();
198
+ }
199
+
200
+ DWORD disposition = SCARD_LEAVE_CARD;
201
+ if (info.Length() > 0 && info[0].IsNumber()) {
202
+ disposition = info[0].As<Napi::Number>().Uint32Value();
203
+ }
204
+
205
+ LONG result = SCardDisconnect(card_, disposition);
206
+ connected_ = false;
207
+ card_ = 0;
208
+
209
+ if (result != SCARD_S_SUCCESS) {
210
+ Napi::Error::New(env, GetPCSCErrorString(result)).ThrowAsJavaScriptException();
211
+ }
212
+
213
+ return env.Undefined();
214
+ }
215
+
216
+ Napi::Value PCSCCard::Reconnect(const Napi::CallbackInfo& info) {
217
+ Napi::Env env = info.Env();
218
+
219
+ if (!connected_) {
220
+ Napi::Error::New(env, "Card is not connected").ThrowAsJavaScriptException();
221
+ return env.Null();
222
+ }
223
+
224
+ DWORD shareMode = SCARD_SHARE_SHARED;
225
+ DWORD preferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
226
+ DWORD initialization = SCARD_LEAVE_CARD;
227
+
228
+ if (info.Length() > 0 && info[0].IsNumber()) {
229
+ shareMode = info[0].As<Napi::Number>().Uint32Value();
230
+ }
231
+ if (info.Length() > 1 && info[1].IsNumber()) {
232
+ preferredProtocols = info[1].As<Napi::Number>().Uint32Value();
233
+ }
234
+ if (info.Length() > 2 && info[2].IsNumber()) {
235
+ initialization = info[2].As<Napi::Number>().Uint32Value();
236
+ }
237
+
238
+ DWORD activeProtocol = 0;
239
+ LONG result = SCardReconnect(card_, shareMode, preferredProtocols, initialization, &activeProtocol);
240
+
241
+ if (result != SCARD_S_SUCCESS) {
242
+ Napi::Error::New(env, GetPCSCErrorString(result)).ThrowAsJavaScriptException();
243
+ return env.Null();
244
+ }
245
+
246
+ protocol_ = activeProtocol;
247
+ return Napi::Number::New(env, activeProtocol);
248
+ }
@@ -0,0 +1,41 @@
1
+ #pragma once
2
+
3
+ #include <napi.h>
4
+ #include <string>
5
+ #include <vector>
6
+ #include "platform/pcsc.h"
7
+
8
+ class PCSCCard : public Napi::ObjectWrap<PCSCCard> {
9
+ public:
10
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
11
+ static Napi::Object NewInstance(Napi::Env env, SCARDHANDLE card,
12
+ DWORD protocol, const std::string& readerName);
13
+
14
+ PCSCCard(const Napi::CallbackInfo& info);
15
+ ~PCSCCard();
16
+
17
+ // Accessors
18
+ SCARDHANDLE GetHandle() const { return card_; }
19
+ DWORD GetProtocol() const { return protocol_; }
20
+ bool IsConnected() const { return connected_; }
21
+
22
+ private:
23
+ static Napi::FunctionReference constructor;
24
+
25
+ SCARDHANDLE card_;
26
+ DWORD protocol_;
27
+ std::string readerName_;
28
+ bool connected_;
29
+
30
+ // JavaScript-exposed methods
31
+ Napi::Value Transmit(const Napi::CallbackInfo& info);
32
+ Napi::Value Control(const Napi::CallbackInfo& info);
33
+ Napi::Value GetStatus(const Napi::CallbackInfo& info);
34
+ Napi::Value Disconnect(const Napi::CallbackInfo& info);
35
+ Napi::Value Reconnect(const Napi::CallbackInfo& info);
36
+
37
+ // Getters
38
+ Napi::Value GetProtocolValue(const Napi::CallbackInfo& info);
39
+ Napi::Value GetConnectedValue(const Napi::CallbackInfo& info);
40
+ Napi::Value GetAtr(const Napi::CallbackInfo& info);
41
+ };