@@ -22,7 +22,7 @@ import Client from "../../client";
2222import getJsonResponse from "../../helpers/getJsonResponse" ;
2323import mergeDeep from "../../utils/mergeDeep" ;
2424import { ApplicationInfo } from "../../typings/applicationInfo" ;
25- import { ObjectSerializer , CloudDeviceApiRequest , CloudDeviceApiResponse , ConnectedDevicesResponse , DeviceStatusResponse , CloudDeviceApiSecuredRequest , CloudDeviceApiSecuredResponse , SaleToPOISecuredMessage } from "../../typings/cloudDevice/models" ;
25+ import { ObjectSerializer , CloudDeviceApiRequest , CloudDeviceApiResponse , ConnectedDevicesResponse , DeviceStatusResponse , CloudDeviceApiSecuredRequest , CloudDeviceApiSecuredResponse , SaleToPOISecuredMessage , SaleToPOIRequest } from "../../typings/cloudDevice/models" ;
2626import Resource from "../resource" ;
2727import { IRequest } from "../../typings/requestOptions" ;
2828import NexoSecurityManager from "../../security/nexoSecurityManager" ;
@@ -44,7 +44,8 @@ class CloudDeviceAPI extends Service {
4444 this . apiKeyRequired = true ;
4545 }
4646
47- private static setApplicationInfo ( request : CloudDeviceApiRequest ) : CloudDeviceApiRequest {
47+ // Add application information to a CloudDevice API request and sets the device POIID.
48+ private static setApplicationInfo ( request : CloudDeviceApiRequest , deviceId : string ) : CloudDeviceApiRequest {
4849 if ( request . SaleToPOIRequest . PaymentRequest ) {
4950 const applicationInfo = new ApplicationInfo ( ) ;
5051 const saleToAcquirerData = { applicationInfo } ;
@@ -56,6 +57,16 @@ class CloudDeviceAPI extends Service {
5657 mergeDeep ( request , reqWithAppInfo ) ;
5758 }
5859
60+ if ( true ) {
61+ request . SaleToPOIRequest = {
62+ ...request . SaleToPOIRequest ,
63+ MessageHeader : {
64+ ...request . SaleToPOIRequest ?. MessageHeader ,
65+ POIID : deviceId
66+ }
67+ } ;
68+ }
69+
5970 return ObjectSerializer . serialize ( request , "CloudDeviceApiRequest" ) ;
6071 }
6172
@@ -67,99 +78,202 @@ class CloudDeviceAPI extends Service {
6778 * @param deviceId - The unique identifier of the payment device that you send this request to (must match POIID in the MessageHeader).
6879 * @returns A promise that resolves to "ok" if the request was successful, or a CloudDeviceApiResponse if there is an error.
6980 */
70- public async ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest ) : Promise < string | CloudDeviceApiResponse > {
81+ public sendAsync ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest ) : Promise < string | CloudDeviceApiResponse > {
7182 const endpoint = this . baseUrl + "/merchants/{merchantAccount}/devices/{deviceId}/async"
7283 . replace ( "{" + "merchantAccount" + "}" , encodeURIComponent ( String ( merchantAccount ) ) )
7384 . replace ( "{" + "deviceId" + "}" , encodeURIComponent ( String ( deviceId ) ) ) ;
7485
7586 const resource = new Resource ( this , endpoint ) ;
7687
77- const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest ) ;
78-
79- // set deviceId
80- request . SaleToPOIRequest . MessageHeader . POIID = deviceId ;
88+ const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest , deviceId ) ;
8189
8290 return getJsonResponse < CloudDeviceApiRequest > (
83- resource ,
91+ resource ,
8492 request
8593 ) ;
8694 }
8795
88- /**
89- * Send an asynchronous payment request.
90- *
91- * @param merchantAccount - The unique identifier of the merchant account.
92- * @param deviceId - The unique identifier of the payment device that you send this request to (must match POIID in the MessageHeader).
93- * @param cloudDeviceApiRequest - The request to send.
94- * @param encryptionCredentialDetails - The details of the encryption credential used for encrypting the request payload (nexoBlob)
95- * @returns A promise that resolves to "ok" if the request was successful, or a CloudDeviceApiResponse if there is an error.
96- */
97- public asyncEncrypted ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest , encryptionCredentialDetails : EncryptionCredentialDetails ) : Promise < string | CloudDeviceApiSecuredResponse > {
98- const endpoint = this . baseUrl + "/merchants/{merchantAccount}/devices/{deviceId}/async"
99- . replace ( "{" + "merchantAccount" + "}" , encodeURIComponent ( String ( merchantAccount ) ) )
100- . replace ( "{" + "deviceId" + "}" , encodeURIComponent ( String ( deviceId ) ) ) ;
101-
102- const resource = new Resource ( this , endpoint ) ;
103-
104- const formattedRequest = ObjectSerializer . serialize ( cloudDeviceApiRequest , "CloudDeviceApiRequest" ) ;
105-
106- const saleToPoiSecuredMessage : SaleToPOISecuredMessage = NexoSecurityManager . encrypt (
107- cloudDeviceApiRequest . SaleToPOIRequest ?. MessageHeader ,
108- JSON . stringify ( formattedRequest ) ,
109- encryptionCredentialDetails ,
110- ) ;
111-
112- const securedPaymentRequest : CloudDeviceApiSecuredRequest = ObjectSerializer . serialize ( {
113- SaleToPOIRequest : saleToPoiSecuredMessage ,
114- } , "CloudDeviceApiSecuredRequest" ) ;
115-
116-
117- //const request = CloudDeviceAPI.setApplicationInfo(cloudDeviceApiRequest);
118- // set deviceId
119- //request.SaleToPOIRequest.MessageHeader.POIID = deviceId;
120-
121- const jsonResponse = getJsonResponse < CloudDeviceApiSecuredRequest , CloudDeviceApiSecuredResponse > (
122- resource ,
123- securedPaymentRequest
124- ) ;
125-
126- const cloudDeviceApiSecuredResponse : CloudDeviceApiSecuredResponse =
127- ObjectSerializer . deserialize ( jsonResponse , "CloudDeviceApiSecuredResponse" ) ;
128-
129- const response = NexoSecurityManager . decrypt (
130- cloudDeviceApiSecuredResponse . SaleToPOIResponse ,
131- encryptionCredentialDetails ,
132- ) ;
133- return ObjectSerializer . deserialize ( JSON . parse ( response ) , "CloudDeviceApiSecuredResponse" ) ;
96+ /**
97+ * Send an asynchronous encrypted payment request.
98+ *
99+ * @param merchantAccount - The unique identifier of the merchant account.
100+ * @param deviceId - The unique identifier of the payment device that you send this request to (must match POIID in the MessageHeader).
101+ * @param cloudDeviceApiRequest - The request to send.
102+ * @param encryptionCredentialDetails - The details of the encryption credential used for encrypting the request payload (nexoBlob)
103+ * @returns A promise that resolves to "ok" if the request was successful, or a CloudDeviceApiResponse if there is an error.
104+ *
105+ * @throws {CloudDeviceApiError } If an error occurs
106+ * @example
107+ * try {
108+ * const response = await client.sendEncryptedAsync(
109+ * "TestMerchant",
110+ * "P400Plus-123456789",
111+ * cloudDeviceApiRequest,
112+ * encryptionCredentialDetails
113+ * );
114+ * console.log("Decrypted response:", response);
115+ * } catch (err) {
116+ * if (err instanceof CloudDeviceApiError) {
117+ * console.error("CloudDevice API failed:", err.message);
118+ * console.error("Cause:", err.cause);
119+ * }
120+ * }
121+ */
122+ public async sendEncryptedAsync ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest , encryptionCredentialDetails : EncryptionCredentialDetails ) : Promise < string | CloudDeviceApiResponse > {
123+
124+ try {
125+
126+ const endpoint = this . baseUrl + "/merchants/{merchantAccount}/devices/{deviceId}/async"
127+ . replace ( "{" + "merchantAccount" + "}" , encodeURIComponent ( String ( merchantAccount ) ) )
128+ . replace ( "{" + "deviceId" + "}" , encodeURIComponent ( String ( deviceId ) ) ) ;
129+
130+ const resource = new Resource ( this , endpoint ) ;
131+
132+ const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest , deviceId ) ;
133+
134+ // extract the payload to encrypt (i.e. PaymentRequest)
135+ const payload = this . extractPayloadObject ( request . SaleToPOIRequest ) ;
136+
137+ // encrypt the payload and create SaleToPOISecuredMessage
138+ const saleToPoiSecuredMessage : SaleToPOISecuredMessage = NexoSecurityManager . encrypt (
139+ request . SaleToPOIRequest ?. MessageHeader ,
140+ JSON . stringify ( payload ) ,
141+ encryptionCredentialDetails ,
142+ ) ;
143+
144+ const securedPaymentRequest : CloudDeviceApiSecuredRequest = ObjectSerializer . serialize ( {
145+ SaleToPOIRequest : saleToPoiSecuredMessage ,
146+ } , "CloudDeviceApiSecuredRequest" ) ;
147+
148+ const jsonResponse = await getJsonResponse < CloudDeviceApiSecuredRequest , CloudDeviceApiSecuredResponse > (
149+ resource ,
150+ securedPaymentRequest
151+ ) ;
152+
153+ if ( typeof jsonResponse === "string" ) {
154+ // request was successful
155+ return jsonResponse ;
156+ }
157+
158+ const cloudDeviceApiSecuredResponse : CloudDeviceApiSecuredResponse =
159+ ObjectSerializer . deserialize ( jsonResponse , "CloudDeviceApiSecuredResponse" ) ;
160+
161+ // decrypt SaleToPOISecuredMessage
162+ const decryptedPayload = NexoSecurityManager . decrypt (
163+ cloudDeviceApiSecuredResponse . SaleToPOIResponse ,
164+ encryptionCredentialDetails ,
165+ ) ;
166+
167+ return ObjectSerializer . deserialize ( JSON . parse ( decryptedPayload ) , "CloudDeviceApiResponse" ) ;
168+
169+ } catch ( err : any ) {
170+ // an error has occurred
171+ console . error ( err ) ;
172+ throw new CloudDeviceApiError ( err ?. message || "Unknown error" , err ) ;
173+ }
134174 }
135-
175+
136176
137177 /**
138178 * Send a synchronous payment request.
179+ *
139180 * @param cloudDeviceApiRequest - The request to send.
140181 * @param merchantAccount - The unique identifier of the merchant account.
141182 * @param deviceId - The unique identifier of the payment device that you send this request to (must match POIID in the MessageHeader).
142183 * @returns A promise that resolves to a CloudDeviceApiResponse.
143184 */
144- public async sync ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest ) : Promise < CloudDeviceApiResponse > {
185+ public async sendSync ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest ) : Promise < CloudDeviceApiResponse > {
145186 const endpoint = this . baseUrl + "/merchants/{merchantAccount}/devices/{deviceId}/sync"
146187 . replace ( "{" + "merchantAccount" + "}" , encodeURIComponent ( String ( merchantAccount ) ) )
147188 . replace ( "{" + "deviceId" + "}" , encodeURIComponent ( String ( deviceId ) ) ) ;
148189
149190 const resource = new Resource ( this , endpoint ) ;
150191
151- const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest ) ;
152- // set deviceId
153- request . SaleToPOIRequest . MessageHeader . POIID = deviceId ;
192+ const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest , deviceId ) ;
154193
155194 const response = await getJsonResponse < CloudDeviceApiRequest , CloudDeviceApiResponse > (
156- resource ,
195+ resource ,
157196 request
158197 ) ;
159198
160199 return ObjectSerializer . deserialize ( response , "CloudDeviceApiResponse" ) ;
161200 }
162201
202+ /**
203+ * Send a synchronous encrypted payment request.
204+ *
205+ * @param merchantAccount - The unique identifier of the merchant account.
206+ * @param deviceId - The unique identifier of the payment device that you send this request to (must match POIID in the MessageHeader).
207+ * @param cloudDeviceApiRequest - The request to send.
208+ * @param encryptionCredentialDetails - The details of the encryption credential used for encrypting the request payload (nexoBlob)
209+ * @returns A promise that resolves to CloudDeviceApiSecuredResponse
210+ *
211+ * @throws {CloudDeviceApiError } If an error occurs
212+ * @example
213+ * try {
214+ * const response = await client.sendEncryptedSync(
215+ * "TestMerchant",
216+ * "P400Plus-123456789",
217+ * cloudDeviceApiRequest,
218+ * encryptionCredentialDetails
219+ * );
220+ * console.log("Decrypted response:", response);
221+ * } catch (err) {
222+ * if (err instanceof CloudDeviceApiError) {
223+ * console.error("CloudDevice API failed:", err.message);
224+ * console.error("Cause:", err.cause);
225+ * }
226+ * }
227+ */
228+ public async sendEncryptedSync ( merchantAccount : string , deviceId : string , cloudDeviceApiRequest : CloudDeviceApiRequest , encryptionCredentialDetails : EncryptionCredentialDetails ) : Promise < CloudDeviceApiResponse > {
229+
230+ try {
231+
232+ const endpoint = this . baseUrl + "/merchants/{merchantAccount}/devices/{deviceId}/sync"
233+ . replace ( "{" + "merchantAccount" + "}" , encodeURIComponent ( String ( merchantAccount ) ) )
234+ . replace ( "{" + "deviceId" + "}" , encodeURIComponent ( String ( deviceId ) ) ) ;
235+
236+ const resource = new Resource ( this , endpoint ) ;
237+
238+ const request = CloudDeviceAPI . setApplicationInfo ( cloudDeviceApiRequest , deviceId ) ;
239+
240+ // extract the payload to encrypt (i.e. PaymentRequest)
241+ const payload = this . extractPayloadObject ( request . SaleToPOIRequest ) ;
242+
243+ // encrypt the payload and create SaleToPOISecuredMessage
244+ const saleToPoiSecuredMessage : SaleToPOISecuredMessage = NexoSecurityManager . encrypt (
245+ request . SaleToPOIRequest ?. MessageHeader ,
246+ JSON . stringify ( payload ) ,
247+ encryptionCredentialDetails ,
248+ ) ;
249+
250+ const securedPaymentRequest : CloudDeviceApiSecuredRequest = ObjectSerializer . serialize ( {
251+ SaleToPOIRequest : saleToPoiSecuredMessage ,
252+ } , "CloudDeviceApiSecuredRequest" ) ;
253+
254+ const jsonResponse = await getJsonResponse < CloudDeviceApiSecuredRequest , CloudDeviceApiSecuredResponse > (
255+ resource ,
256+ securedPaymentRequest
257+ ) ;
258+
259+ const cloudDeviceApiSecuredResponse : CloudDeviceApiSecuredResponse =
260+ ObjectSerializer . deserialize ( jsonResponse , "CloudDeviceApiSecuredResponse" ) ;
261+
262+ // decrypt SaleToPOISecuredMessage
263+ const decryptedPayload = NexoSecurityManager . decrypt (
264+ cloudDeviceApiSecuredResponse . SaleToPOIResponse ,
265+ encryptionCredentialDetails ,
266+ ) ;
267+
268+ return ObjectSerializer . deserialize ( JSON . parse ( decryptedPayload ) , "CloudDeviceApiResponse" ) ;
269+
270+ } catch ( err : any ) {
271+ // an error has occurred
272+ console . error ( err ) ;
273+ throw new CloudDeviceApiError ( err ?. message || "Unknown error" , err ) ;
274+ }
275+ }
276+
163277 /**
164278 * Get a list of connected devices for a merchant account.
165279 *
@@ -176,7 +290,7 @@ class CloudDeviceAPI extends Service {
176290 let requestOptions : IRequest . Options = { } ;
177291 if ( store ) {
178292 requestOptions . params = { store } ;
179- }
293+ }
180294
181295 const response = await getJsonResponse < string , ConnectedDevicesResponse > (
182296 resource ,
@@ -210,6 +324,40 @@ class CloudDeviceAPI extends Service {
210324 return ObjectSerializer . deserialize ( response , "DeviceStatusResponse" ) ;
211325 }
212326
327+
328+ /**
329+ * Extract the payload request object
330+ */
331+ extractPayloadObject ( saleToPOIRequest : SaleToPOIRequest ) : { [ key : string ] : any } | null {
332+ for ( const attr of SaleToPOIRequest . attributeTypeMap ) {
333+ // ignore MessageHeader or SecurityTrailer
334+ if ( attr . name === "MessageHeader" || attr . name === "SecurityTrailer" ) {
335+ continue ; // skip header/trailer
336+ }
337+
338+ const value = ( saleToPOIRequest as any ) [ attr . name ] ;
339+ if ( value !== undefined && value !== null ) {
340+ return { [ attr . name ] : value } ;
341+ }
342+ }
343+ return null ;
344+ }
345+
346+ }
347+
348+
349+ /**
350+ * CloudDeviceApiError wraps any failure during the processing of Cloud Device API requests
351+ */
352+ export class CloudDeviceApiError extends Error {
353+ /**
354+ * @param {string } message - A human-readable error message.
355+ * @param {unknown } [cause] - The original error that triggered this failure.
356+ */
357+ constructor ( message : string , public cause ?: unknown ) {
358+ super ( message ) ;
359+ this . name = "CloudDeviceApiError" ;
360+ }
213361}
214362
215363export default CloudDeviceAPI ;
0 commit comments