@ledgerhq/device-management-kit 0.0.0-io-revamp-20250620163214 → 0.0.0-io-revamp-20250624161931
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/lib/cjs/src/api/transport/model/DeviceConnectionStateMachine.js +1 -1
- package/lib/cjs/src/api/transport/model/DeviceConnectionStateMachine.js.map +3 -3
- package/lib/cjs/src/api/transport/model/DeviceConnectionStateMachine.test.js +1 -1
- package/lib/cjs/src/api/transport/model/DeviceConnectionStateMachine.test.js.map +3 -3
- package/lib/esm/src/api/transport/model/DeviceConnectionStateMachine.js +1 -1
- package/lib/esm/src/api/transport/model/DeviceConnectionStateMachine.js.map +3 -3
- package/lib/esm/src/api/transport/model/DeviceConnectionStateMachine.test.js +1 -1
- package/lib/esm/src/api/transport/model/DeviceConnectionStateMachine.test.js.map +3 -3
- package/lib/types/src/api/transport/model/DeviceConnectionStateMachine.d.ts.map +1 -1
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +1 -1
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";var
|
1
|
+
"use strict";var l=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var C=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var y=(s,n)=>{for(var i in n)l(s,i,{get:n[i],enumerable:!0})},v=(s,n,i,c)=>{if(n&&typeof n=="object"||typeof n=="function")for(let o of C(n))!R.call(s,o)&&o!==i&&l(s,o,{get:()=>n[o],enumerable:!(c=D(n,o))||c.enumerable});return s};var h=s=>v(l({},"__esModule",{value:!0}),s);var b={};y(b,{DeviceConnectionStateMachine:()=>T});module.exports=h(b);var t=require("purify-ts"),r=require("xstate"),m=require("../../command/utils/CommandUtils"),A=require("../../Error"),d=require("./Errors");class T{deviceId;deviceAdpuSender;machineActor;timeoutDuration;timeout=null;startReconnectionTimeout(){this.timeout=setTimeout(()=>{this.machineActor.send({type:"ReconnectionTimedOut"})},this.timeoutDuration)}constructor(n){this.deviceId=n.deviceId,this.deviceAdpuSender=n.deviceApduSender,this.timeoutDuration=n.timeoutDuration,this.machineActor=(0,r.createActor)(S({sendApduFn:(i,c,o)=>this.sendApduToDeviceConnection(i,c,o),startReconnectionTimeout:()=>this.startReconnectionTimeout(),cancelReconnectionTimeout:()=>{this.timeout&&(clearTimeout(this.timeout),this.timeout=null)},tryToReconnect:()=>{n.tryToReconnect(this.timeoutDuration)},onTerminated:n.onTerminated,closeConnection:()=>{this.deviceAdpuSender.closeConnection()}})),this.machineActor.start()}sendApduToDeviceConnection(n,i,c){this.deviceAdpuSender.sendApdu(n,i,c).then(o=>{o.caseOf({Left:a=>{this.machineActor.send({type:"ApduSendingError",error:a})},Right:a=>{this.machineActor.send({type:"ApduResponseReceived",apduResponse:a})}})}).catch(o=>{this.machineActor.send({type:"ApduSendingError",error:new A.UnknownDeviceExchangeError(o)})})}getDependencies(){return this.deviceAdpuSender.getDependencies()}setDependencies(n){this.deviceAdpuSender.setDependencies(n)}getDeviceId(){return this.deviceId}sendApdu(n,i,c){return new Promise(o=>{this.machineActor.send({type:"SendApduCalled",apdu:n,triggersDisconnection:!!i,abortTimeout:c,responseCallback:o})})}async setupConnection(){await this.deviceAdpuSender.setupConnection()}eventDeviceConnected(){this.machineActor.send({type:"DeviceConnected"})}eventDeviceDisconnected(){this.machineActor.send({type:"DeviceDisconnected"})}closeConnection(){this.machineActor.send({type:"CloseConnectionCalled"})}}function S({sendApduFn:s,startReconnectionTimeout:n,cancelReconnectionTimeout:i,tryToReconnect:c,onTerminated:o,closeConnection:a}){return(0,r.setup)({types:{},actions:{startTimer:()=>{n()},cancelTimer:()=>{i()},reconnectionTimeoutEvent:(0,r.emit)({type:"ReconnectionTimedOut"}),sendApdu:({context:e})=>{e.apduInProgress.map(({apdu:p,abortTimeout:u})=>{s(p,!1,u)})},sendApduResponse:({context:e},p)=>{e.apduInProgress.map(({responseCallback:u})=>u(p.response))},sendGetAppAndVersion:()=>{s(Uint8Array.from([176,1,0,0,0]),!1)},tryToReconnect:()=>{c()},clearApduInProgress:(0,r.assign)({apduInProgress:t.Nothing}),clearApduResponse:(0,r.assign)({apduResponse:t.Nothing}),signalTermination:()=>{o()},closeConnection:()=>{a()}},guards:{isApduThatTriggersDisconnection:({context:e,event:p})=>p.type!=="ApduResponseReceived"?!1:e.apduInProgress.caseOf({Just:({triggersDisconnection:u,apdu:g})=>(u||m.CommandUtils.isApduThatTriggersDisconnection(g))&&m.CommandUtils.isSuccessResponse(p.apduResponse),Nothing:()=>!1}),isSendApduBusyError:({event:e})=>e.type!=="ApduResponseReceived"?!1:e.apduResponse.statusCode[0]===102&&e.apduResponse.statusCode[1]===1}}).createMachine({id:"deviceConnection",initial:"Connected",context:{apduInProgress:t.Nothing,apduResponse:t.Nothing},states:{Connected:{on:{DeviceDisconnected:{target:"WaitingForReconnection"},SendApduCalled:{target:"SendingApdu",actions:(0,r.assign)({apduInProgress:({event:e})=>t.Maybe.of({apdu:e.apdu,triggersDisconnection:e.triggersDisconnection,abortTimeout:e.abortTimeout,responseCallback:e.responseCallback})})},CloseConnectionCalled:{target:"Terminated"}}},SendingApdu:{entry:"sendApdu",on:{ApduResponseReceived:[{guard:"isApduThatTriggersDisconnection",target:"WaitingForDisconnection",actions:[(0,r.assign)({apduResponse:({event:e})=>t.Maybe.of(e.apduResponse)})]},{target:"Connected",actions:[{type:"sendApduResponse",params:({event:e})=>({response:(0,t.Right)(e.apduResponse)})},{type:"clearApduInProgress"}]}],ApduSendingError:{target:"Connected",actions:[{type:"sendApduResponse",params:({event:e})=>({response:(0,t.Left)(e.error)})},"clearApduInProgress"]},DeviceDisconnected:{target:"WaitingForReconnection",actions:[{type:"sendApduResponse",params:{response:(0,t.Left)(new d.DeviceDisconnectedWhileSendingError)}},"clearApduInProgress"]},CloseConnectionCalled:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:(0,t.Left)(new d.DeviceDisconnectedWhileSendingError)}},"clearApduInProgress"]},SendApduCalled:{actions:({event:e})=>{e.responseCallback((0,t.Left)(new d.AlreadySendingApduError))}}}},WaitingForDisconnection:{entry:["sendGetAppAndVersion"],exit:[{type:"sendApduResponse",params:({context:e})=>({response:e.apduResponse.caseOf({Just:p=>(0,t.Right)(p),Nothing:()=>(0,t.Left)(new A.UnknownDeviceExchangeError)})})},{type:"clearApduInProgress"},{type:"clearApduResponse"}],on:{ApduResponseReceived:[{guard:"isSendApduBusyError",actions:["sendGetAppAndVersion"],target:"WaitingForDisconnection"},{target:"Connected"}],ApduSendingError:[{target:"WaitingForReconnection"}],SendApduCalled:{actions:({event:e})=>{e.responseCallback((0,t.Left)(new d.AlreadySendingApduError))}},DeviceDisconnected:{target:"WaitingForReconnection"},CloseConnectionCalled:{target:"Terminated"}}},WaitingForReconnection:{entry:["startTimer","tryToReconnect"],on:{DeviceConnected:{target:"Connected",actions:"cancelTimer"},SendApduCalled:{target:"WaitingForReconnectionWithQueuedSendApdu",actions:(0,r.assign)({apduInProgress:({event:e})=>t.Maybe.of({apdu:e.apdu,triggersDisconnection:e.triggersDisconnection,abortTimeout:e.abortTimeout,responseCallback:e.responseCallback})})},ReconnectionTimedOut:{target:"Terminated"},CloseConnectionCalled:{target:"Terminated"}}},WaitingForReconnectionWithQueuedSendApdu:{on:{DeviceConnected:{target:"SendingApdu",actions:"cancelTimer"},ReconnectionTimedOut:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:(0,t.Left)(new d.DeviceDisconnectedBeforeSendingApdu)}},{type:"clearApduInProgress"}]},CloseConnectionCalled:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:(0,t.Left)(new d.DeviceDisconnectedWhileSendingError)}},"clearApduInProgress"]},SendApduCalled:{actions:({event:e})=>{e.responseCallback((0,t.Left)(new d.AlreadySendingApduError))}}}},Terminated:{entry:["signalTermination","closeConnection"],type:"final"}}})}0&&(module.exports={DeviceConnectionStateMachine});
|
2
2
|
//# sourceMappingURL=DeviceConnectionStateMachine.js.map
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../../../src/api/transport/model/DeviceConnectionStateMachine.ts"],
|
4
|
-
"sourcesContent": ["// import { createBrowserInspector } from \"@statelyai/inspect\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\nimport { type Actor, and, assign, createActor, emit, setup } from \"xstate\";\n\nimport { CommandUtils } from \"@api/command/utils/CommandUtils\";\nimport { type ApduResponse } from \"@api/device-session/ApduResponse\";\nimport { type DmkError, UnknownDeviceExchangeError } from \"@api/Error\";\nimport { type DeviceId } from \"@api/types\";\n\nimport { type DeviceApduSender } from \"./DeviceApduSender\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedBeforeSendingApdu,\n DeviceDisconnectedWhileSendingError,\n SendApduTimeoutError,\n} from \"./Errors\";\n\n// const { inspect } = createBrowserInspector();\n\ntype DeviceDisconnectedEvent = {\n type: \"DeviceDisconnected\";\n};\n\ntype DeviceConnectedEvent = {\n type: \"DeviceConnected\";\n};\n\ntype ApduResponseReceived = {\n type: \"ApduResponseReceived\";\n apduResponse: ApduResponse;\n};\n\ntype ApduSendingError = {\n type: \"ApduSendingError\";\n error: DmkError;\n};\n\ntype SendApduCalled = {\n type: \"SendApduCalled\";\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n};\n\ntype ReconnectionTimedOut = {\n type: \"ReconnectionTimedOut\";\n};\n\ntype CloseConnectionCalled = {\n type: \"CloseConnectionCalled\";\n};\n\nexport type Events =\n | DeviceDisconnectedEvent\n | DeviceConnectedEvent\n | ApduResponseReceived\n | ApduSendingError\n | SendApduCalled\n | CloseConnectionCalled\n | ReconnectionTimedOut;\n\nexport type DeviceConnectionStateMachineParams<Dependencies> = {\n deviceId: DeviceId;\n deviceApduSender: DeviceApduSender<Dependencies>;\n timeoutDuration: number;\n tryToReconnect: (timeoutDuration: number) => void;\n onTerminated: () => void;\n};\n\nexport class DeviceConnectionStateMachine<Dependencies> {\n private deviceId: DeviceId;\n private deviceAdpuSender: DeviceApduSender<Dependencies>;\n\n private machineActor: Actor<ReturnType<typeof makeStateMachine>>;\n\n private timeoutDuration: number;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n startReconnectionTimeout() {\n this.timeout = setTimeout(() => {\n this.machineActor.send({ type: \"ReconnectionTimedOut\" });\n }, this.timeoutDuration);\n }\n\n constructor(params: DeviceConnectionStateMachineParams<Dependencies>) {\n this.deviceId = params.deviceId;\n this.deviceAdpuSender = params.deviceApduSender;\n this.timeoutDuration = params.timeoutDuration;\n this.machineActor = createActor(\n makeStateMachine({\n sendApduFn: (apdu, triggersDisconnection, abortTimeout) =>\n this.sendApduToDeviceConnection(\n apdu,\n triggersDisconnection,\n abortTimeout,\n ),\n startReconnectionTimeout: () => this.startReconnectionTimeout(),\n cancelReconnectionTimeout: () => {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n },\n tryToReconnect: () => {\n params.tryToReconnect(this.timeoutDuration);\n },\n onTerminated: params.onTerminated,\n closeConnection: () => {\n this.deviceAdpuSender.closeConnection();\n },\n }),\n // {\n // // inspect,\n // },\n );\n this.machineActor.start();\n }\n\n private sendApduToDeviceConnection(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ) {\n this.deviceAdpuSender\n .sendApdu(apdu, triggersDisconnection, abortTimeout)\n .then((response) => {\n response.caseOf({\n Left: (error) => {\n this.machineActor.send({ type: \"ApduSendingError\", error });\n },\n Right: (apduResponse) => {\n this.machineActor.send({\n type: \"ApduResponseReceived\",\n apduResponse,\n });\n },\n });\n })\n .catch((error) => {\n this.machineActor.send({\n type: \"ApduSendingError\",\n error: new UnknownDeviceExchangeError(error),\n });\n });\n }\n\n /**\n * Called by the transport\n */\n\n public getDependencies(): Dependencies {\n return this.deviceAdpuSender.getDependencies();\n }\n\n public setDependencies(dependencies: Dependencies) {\n this.deviceAdpuSender.setDependencies(dependencies);\n }\n\n public getDeviceId() {\n return this.deviceId;\n }\n\n public sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n return new Promise((responseCallback) => {\n this.machineActor.send({\n type: \"SendApduCalled\",\n apdu,\n triggersDisconnection: !!triggersDisconnection,\n abortTimeout,\n responseCallback,\n });\n });\n }\n\n public async setupConnection() {\n await this.deviceAdpuSender.setupConnection();\n }\n\n // State Machine Events\n\n public eventDeviceConnected() {\n this.machineActor.send({ type: \"DeviceConnected\" });\n }\n\n public eventDeviceDisconnected() {\n this.machineActor.send({ type: \"DeviceDisconnected\" });\n }\n\n public closeConnection() {\n this.machineActor.send({ type: \"CloseConnectionCalled\" });\n }\n}\n\n/**\n * The total timeout must be superior to 5s because on Android,\n * we take 5s to detect a disconnection.\n */\nconst MAX_GET_APP_AND_VERSION_ATTEMPTS = 6;\nconst GET_APP_AND_VERSION_TIMEOUT = 1000;\n\nfunction makeStateMachine({\n sendApduFn,\n startReconnectionTimeout,\n cancelReconnectionTimeout,\n tryToReconnect,\n onTerminated,\n closeConnection,\n}: {\n sendApduFn: (\n apdu: Uint8Array,\n triggersDisconnection: boolean,\n abortTimeout?: number,\n ) => void;\n startReconnectionTimeout: () => void;\n cancelReconnectionTimeout: () => void;\n tryToReconnect: () => void;\n onTerminated: () => void;\n closeConnection: () => void;\n}) {\n return setup({\n types: {} as {\n context: {\n apduInProgress: Maybe<{\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n }>;\n apduResponse: Maybe<ApduResponse>;\n getAppAndVersionAttempts: number;\n };\n events: Events;\n },\n actions: {\n // event transitions\n startTimer: () => {\n startReconnectionTimeout();\n },\n cancelTimer: () => {\n cancelReconnectionTimeout();\n },\n reconnectionTimeoutEvent: emit({ type: \"ReconnectionTimedOut\" }),\n sendApdu: ({ context }) => {\n context.apduInProgress.map(({ apdu, abortTimeout }) => {\n sendApduFn(apdu, false, abortTimeout);\n });\n },\n sendApduResponse: (\n { context },\n params: { response: Either<DmkError, ApduResponse> },\n ) => {\n context.apduInProgress.map(({ responseCallback }) =>\n responseCallback(params.response),\n );\n },\n sendGetAppAndVersion: () => {\n sendApduFn(\n Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]),\n false,\n GET_APP_AND_VERSION_TIMEOUT,\n );\n },\n incrementGetAppAndVersionAttempts: assign({\n getAppAndVersionAttempts: ({ context }) =>\n context.getAppAndVersionAttempts + 1,\n }),\n resetGetAppAndVersionAttempts: assign({\n getAppAndVersionAttempts: 0,\n }),\n tryToReconnect: () => {\n tryToReconnect();\n },\n clearApduInProgress: assign({\n apduInProgress: Nothing,\n }),\n clearApduResponse: assign({\n apduResponse: Nothing,\n }),\n signalTermination: () => {\n onTerminated();\n },\n closeConnection: () => {\n closeConnection(); // ASK: how do we handle errors ?\n },\n },\n guards: {\n isApduThatTriggersDisconnection: ({ context, event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return context.apduInProgress.caseOf({\n Just: ({ triggersDisconnection, apdu }) => {\n const res =\n (triggersDisconnection ||\n CommandUtils.isApduThatTriggersDisconnection(apdu)) &&\n CommandUtils.isSuccessResponse(event.apduResponse);\n return res;\n },\n Nothing: () => false,\n });\n },\n isSendApduTimeoutError: ({ event }) => {\n if (event.type !== \"ApduSendingError\") {\n return false;\n }\n return event.error instanceof SendApduTimeoutError;\n },\n hasReachedGetAppAndVersionMaxAttempts: ({ context }) => {\n return (\n context.getAppAndVersionAttempts >= MAX_GET_APP_AND_VERSION_ATTEMPTS\n );\n },\n },\n }).createMachine({\n /** @xstate-layout N4IgpgJg5mDOIC5QTANwJYGMwGED2AdgWJgC7qEB0+RJpkAxACJpZgukCGmAFpANoAGALqJQABzyx05QmJAAPRAA4A7AGZKywQEYAnAFYATMoAsBg6fUA2ADQgAnolUnKBjUdXXVpnUb0aAL6B9igY2DTEZBQE1IRR9BAMAMpgBBAAguIQAK44nAA2BQIi8pLSsgTySgjW6oKU6uo61kbWyh06Vsr2TgjqAZR6HUaWXcrqBmrBoawR8XQxcbRkjDgFUrgL0YT5RSWiSCDlMjHVKnrWjaO6ev6qlnp6vYim1qaN9YLqGuPKOjpVDMQGE2JFFlRUul0AQoFlcgx4TkAEpwSQEWBgVHYdCoA5lKSnORHGpNVSUPwGXQDQSmNTDF4IZTWPRDJotUw+HwAnTA0HzFaVShQiAwuHZHKIiWo2DozHYsC4gQ6Q4SQmVc79TxDIzqG6eJq+VSM94NPQ6CYuUzmQGCax8uZbQVLEVipFS3Ku2EAUQATr68L6hKrjuqziTEJNNHrTG1dIIDE8jLTGVTlJQboI2i56QZeSEQY7wTtYl7xQiWOF2GAuLx8UcThqIwh-OmdBZPF0qQCBoydIJlAZKK0jP4bHntBaHVXi0Ky+71ptZzE9sUIMGCRVw6Aau2dJQ6WZlMM-D9+89HIh++mbndVHpdNYLAnp2DtnO0qLYe6RUjV-W1S3Ykd0QABac1KFpbx3kHCxumNS9ak5SDTHNax0NUDRfFMV8BQSJYAHVOFOWEADFA2xd8YmYR0MlIWs+HXUoGzDYDFEQQx90mVozABJ9BAvPo6iuFpRgtQRdDUWNcKdfCqCIkioHI31KOdQgUk-P9CjXDcWKAqpmx0dR-gpCTaXNUxvh7RkvCHWlaWM9RfC6dCZOXeTiPIMiKJIKj1NUuSCAAFXQABbSAAHkclIXTAKJAyQIQLpBHJAEXB8AS1HvdRGT0a0D2ZZpBxjSc3L82IFK8pSfMwcqGEXTF3IIf8mJDRtt3YpLLPJZMWkmTtzJyxD+1UBofifVQOm8YyWjKtSKs8sVlICiECAImQeAARRyMAdogX8JRoqs6IYgDQ30zUjJ8CkWQmYZbOsFLGWzUyzE5bssx8ObAsoSqlpq8r1tILadr2g6ERWksQvCiAopi5i4qbRKjH7Bo4N1dsvFjOxEIeIwUPQ9o9AGSYvG+1bfsW7yVN8+agZB3bIHByUGtk1aWti874s1FGJOHYy6gTLo3lMVN7wPBNVAtbRRg0IEC35NmS0pxTltpwL6e2xn9s0w7mY5hGuaRzrAWZIYBJpc0pd1E18tNMZLOMAwnOCAsCDwFB4CORWms3bnm1AozWSgrHYMsYyEL6FGKXcDleMMO5rXJ5XZ0gP3jZqB4evaLwXEeqwnJNKYDypWlzHePwcIVotyuFT83QldOOpqWNU30A8rEmrMjPcAJk6FP7qch432rY3dxnN1onlaZ9idy5NILuCxl+UEwrH7wiqeqmnarpjatbB3Xcibser3eckfmd3xOkrnpce0DMjHMeoAgLjeqCCsBfVCmFOESE+EqdSfnmNwLJjBPBSs0QwuV3CQWPN3AwT4LTtldoEIAA */\n id: \"deviceConnection\",\n initial: \"Connected\",\n context: {\n apduInProgress: Nothing,\n apduResponse: Nothing,\n getAppAndVersionAttempts: 0,\n },\n states: {\n Connected: {\n on: {\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n SendApduCalled: {\n target: \"SendingApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n SendingApdu: {\n entry: \"sendApdu\",\n on: {\n ApduResponseReceived: [\n {\n guard: \"isApduThatTriggersDisconnection\",\n target: \"WaitingForDisconnection\",\n actions: [\n assign({\n apduResponse: ({ event }) => Maybe.of(event.apduResponse),\n }),\n ],\n },\n {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Right(event.apduResponse),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n ],\n },\n ],\n ApduSendingError: {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Left(event.error),\n };\n },\n },\n \"clearApduInProgress\",\n ],\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n WaitingForDisconnection: {\n entry: [\"sendGetAppAndVersion\", \"incrementGetAppAndVersionAttempts\"],\n exit: [\n \"resetGetAppAndVersionAttempts\",\n {\n type: \"sendApduResponse\",\n params: ({ context }) => {\n return {\n response: context.apduResponse.caseOf({\n Just: (apduResponse) => Right(apduResponse),\n Nothing: () => Left(new UnknownDeviceExchangeError()),\n }),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n { type: \"clearApduResponse\" },\n ],\n on: {\n ApduResponseReceived: {\n target: \"Connected\",\n },\n ApduSendingError: [\n {\n guard: and([\n \"isSendApduTimeoutError\",\n \"hasReachedGetAppAndVersionMaxAttempts\",\n ]),\n target: \"Terminated\",\n },\n {\n guard: \"isSendApduTimeoutError\",\n actions: [\n \"sendGetAppAndVersion\",\n \"incrementGetAppAndVersionAttempts\",\n ],\n target: \"WaitingForDisconnection\",\n },\n {\n target: \"WaitingForReconnection\",\n },\n ],\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnection: {\n entry: [\"startTimer\", \"tryToReconnect\"],\n on: {\n DeviceConnected: {\n target: \"Connected\",\n actions: \"cancelTimer\",\n },\n SendApduCalled: {\n target: \"WaitingForReconnectionWithQueuedSendApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnectionWithQueuedSendApdu: {\n on: {\n DeviceConnected: {\n target: \"SendingApdu\",\n actions: \"cancelTimer\",\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedBeforeSendingApdu()),\n },\n },\n {\n type: \"clearApduInProgress\",\n },\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n // TODO: ADD INACTIVE STATE\n Terminated: {\n entry: [\"signalTermination\", \"closeConnection\"],\n type: \"final\",\n },\n },\n });\n}\n"],
|
5
|
-
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,kCAAAE,IAAA,eAAAC,EAAAH,GACA,IAAAI,EAAyD,qBACzDC,
|
6
|
-
"names": ["DeviceConnectionStateMachine_exports", "__export", "DeviceConnectionStateMachine", "__toCommonJS", "import_purify_ts", "import_xstate", "import_CommandUtils", "import_Error", "import_Errors", "params", "makeStateMachine", "apdu", "triggersDisconnection", "abortTimeout", "response", "error", "apduResponse", "dependencies", "responseCallback", "
|
4
|
+
"sourcesContent": ["// import { createBrowserInspector } from \"@statelyai/inspect\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\nimport { type Actor, assign, createActor, emit, setup } from \"xstate\";\n\nimport { CommandUtils } from \"@api/command/utils/CommandUtils\";\nimport { type ApduResponse } from \"@api/device-session/ApduResponse\";\nimport { type DmkError, UnknownDeviceExchangeError } from \"@api/Error\";\nimport { type DeviceId } from \"@api/types\";\n\nimport { type DeviceApduSender } from \"./DeviceApduSender\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedBeforeSendingApdu,\n DeviceDisconnectedWhileSendingError,\n} from \"./Errors\";\n\n// const { inspect } = createBrowserInspector();\n\ntype DeviceDisconnectedEvent = {\n type: \"DeviceDisconnected\";\n};\n\ntype DeviceConnectedEvent = {\n type: \"DeviceConnected\";\n};\n\ntype ApduResponseReceived = {\n type: \"ApduResponseReceived\";\n apduResponse: ApduResponse;\n};\n\ntype ApduSendingError = {\n type: \"ApduSendingError\";\n error: DmkError;\n};\n\ntype SendApduCalled = {\n type: \"SendApduCalled\";\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n};\n\ntype ReconnectionTimedOut = {\n type: \"ReconnectionTimedOut\";\n};\n\ntype CloseConnectionCalled = {\n type: \"CloseConnectionCalled\";\n};\n\nexport type Events =\n | DeviceDisconnectedEvent\n | DeviceConnectedEvent\n | ApduResponseReceived\n | ApduSendingError\n | SendApduCalled\n | CloseConnectionCalled\n | ReconnectionTimedOut;\n\nexport type DeviceConnectionStateMachineParams<Dependencies> = {\n deviceId: DeviceId;\n deviceApduSender: DeviceApduSender<Dependencies>;\n timeoutDuration: number;\n tryToReconnect: (timeoutDuration: number) => void;\n onTerminated: () => void;\n};\n\nexport class DeviceConnectionStateMachine<Dependencies> {\n private deviceId: DeviceId;\n private deviceAdpuSender: DeviceApduSender<Dependencies>;\n\n private machineActor: Actor<ReturnType<typeof makeStateMachine>>;\n\n private timeoutDuration: number;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n startReconnectionTimeout() {\n this.timeout = setTimeout(() => {\n this.machineActor.send({ type: \"ReconnectionTimedOut\" });\n }, this.timeoutDuration);\n }\n\n constructor(params: DeviceConnectionStateMachineParams<Dependencies>) {\n this.deviceId = params.deviceId;\n this.deviceAdpuSender = params.deviceApduSender;\n this.timeoutDuration = params.timeoutDuration;\n this.machineActor = createActor(\n makeStateMachine({\n sendApduFn: (apdu, triggersDisconnection, abortTimeout) =>\n this.sendApduToDeviceConnection(\n apdu,\n triggersDisconnection,\n abortTimeout,\n ),\n startReconnectionTimeout: () => this.startReconnectionTimeout(),\n cancelReconnectionTimeout: () => {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n },\n tryToReconnect: () => {\n params.tryToReconnect(this.timeoutDuration);\n },\n onTerminated: params.onTerminated,\n closeConnection: () => {\n this.deviceAdpuSender.closeConnection();\n },\n }),\n // {\n // // inspect,\n // },\n );\n this.machineActor.start();\n }\n\n private sendApduToDeviceConnection(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ) {\n this.deviceAdpuSender\n .sendApdu(apdu, triggersDisconnection, abortTimeout)\n .then((response) => {\n response.caseOf({\n Left: (error) => {\n this.machineActor.send({ type: \"ApduSendingError\", error });\n },\n Right: (apduResponse) => {\n this.machineActor.send({\n type: \"ApduResponseReceived\",\n apduResponse,\n });\n },\n });\n })\n .catch((error) => {\n this.machineActor.send({\n type: \"ApduSendingError\",\n error: new UnknownDeviceExchangeError(error),\n });\n });\n }\n\n /**\n * Called by the transport\n */\n\n public getDependencies(): Dependencies {\n return this.deviceAdpuSender.getDependencies();\n }\n\n public setDependencies(dependencies: Dependencies) {\n this.deviceAdpuSender.setDependencies(dependencies);\n }\n\n public getDeviceId() {\n return this.deviceId;\n }\n\n public sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n return new Promise((responseCallback) => {\n this.machineActor.send({\n type: \"SendApduCalled\",\n apdu,\n triggersDisconnection: !!triggersDisconnection,\n abortTimeout,\n responseCallback,\n });\n });\n }\n\n public async setupConnection() {\n await this.deviceAdpuSender.setupConnection();\n }\n\n // State Machine Events\n\n public eventDeviceConnected() {\n this.machineActor.send({ type: \"DeviceConnected\" });\n }\n\n public eventDeviceDisconnected() {\n this.machineActor.send({ type: \"DeviceDisconnected\" });\n }\n\n public closeConnection() {\n this.machineActor.send({ type: \"CloseConnectionCalled\" });\n }\n}\n\nfunction makeStateMachine({\n sendApduFn,\n startReconnectionTimeout,\n cancelReconnectionTimeout,\n tryToReconnect,\n onTerminated,\n closeConnection,\n}: {\n sendApduFn: (\n apdu: Uint8Array,\n triggersDisconnection: boolean,\n abortTimeout?: number,\n ) => void;\n startReconnectionTimeout: () => void;\n cancelReconnectionTimeout: () => void;\n tryToReconnect: () => void;\n onTerminated: () => void;\n closeConnection: () => void;\n}) {\n return setup({\n types: {} as {\n context: {\n apduInProgress: Maybe<{\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n }>;\n apduResponse: Maybe<ApduResponse>;\n };\n events: Events;\n },\n actions: {\n // event transitions\n startTimer: () => {\n startReconnectionTimeout();\n },\n cancelTimer: () => {\n cancelReconnectionTimeout();\n },\n reconnectionTimeoutEvent: emit({ type: \"ReconnectionTimedOut\" }),\n sendApdu: ({ context }) => {\n context.apduInProgress.map(({ apdu, abortTimeout }) => {\n sendApduFn(apdu, false, abortTimeout);\n });\n },\n sendApduResponse: (\n { context },\n params: { response: Either<DmkError, ApduResponse> },\n ) => {\n context.apduInProgress.map(({ responseCallback }) =>\n responseCallback(params.response),\n );\n },\n sendGetAppAndVersion: () => {\n sendApduFn(Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false);\n },\n tryToReconnect: () => {\n tryToReconnect();\n },\n clearApduInProgress: assign({\n apduInProgress: Nothing,\n }),\n clearApduResponse: assign({\n apduResponse: Nothing,\n }),\n signalTermination: () => {\n onTerminated();\n },\n closeConnection: () => {\n closeConnection(); // ASK: how do we handle errors ?\n },\n },\n guards: {\n isApduThatTriggersDisconnection: ({ context, event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return context.apduInProgress.caseOf({\n Just: ({ triggersDisconnection, apdu }) => {\n const res =\n (triggersDisconnection ||\n CommandUtils.isApduThatTriggersDisconnection(apdu)) &&\n CommandUtils.isSuccessResponse(event.apduResponse);\n return res;\n },\n Nothing: () => false,\n });\n },\n isSendApduBusyError: ({ event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return (\n event.apduResponse.statusCode[0] === 0x66 &&\n event.apduResponse.statusCode[1] === 0x01\n );\n },\n },\n }).createMachine({\n /** @xstate-layout N4IgpgJg5mDOIC5QTANwJYGMwGED2AdgWJgC7qEB0+RJpkAxACJpZgukCGmAFpANoAGALqJQABzyx05QmJAAPRAA4A7AGZKywQEYAnAFYATMoAsBg6fUA2ADQgAnolUnKBjUdXXVpnUb0aAL6B9igY2DTEZBQE1IRR9BAMAMpgBBAAguIQAK44nAA2BQIi8pLSsgTySgjW6oKU6uo61kbWyh06Vsr2TgjqAZR6HUaWXcrqBmrBoawR8XQxcbRkjDgFUrgL0YT5RSWiSCDlMjHVKnrWjaO6ev6qlnp6vYim1qaN9YLqGuPKOjpVDMQGE2JFFlRUul0AQoFlcgx4TkAEpwSQEWBgVHYdCoA5lKSnORHGpNVSUPwGXQDQSmNTDF4IZTWPRDJotUw+HwAnTA0HzFaVShQiAwuHZHKIiWo2DozHYsC4gQ6Q4SQmVc79TxDIzqG6eJq+VSM94NPQ6CYuUzmQGCax8uZbQVLEVipFS3Ku2EAUQATr68L6hKrjuqziTEJNNHrTG1dIIDE8jLTGVTlJQboI2i56QZeSEQY7wTtYl7xQiWOF2GAuLx8UcThqIwh-OmdBZPF0qQCBoydIJlAZKK0jP4bHntBaHVXi0Ky+71ptZzE9sUIMGCRVw6Aau2dJQ6WZlMM-D9+89HIh++mbndVHpdNYLAnp2DtnO0qLYe6RUjV-W1S3Ykd0QABac1KFpbx3kHCxumNS9ak5SDTHNax0NUDRfFMV8BQSJYAHVOFOWEADFA2xd8YmYR0MlIWs+HXUoGzDYDFEQQx90mVozABJ9BAvPo6iuFpRgtQRdDUWNcKdfCqCIkioHI31KOdQgUk-P9CjXDcWKAqpmx0dR-gpCTaXNUxvh7RkvCHWlaWM9RfC6dCZOXeTiPIMiKJIKj1NUuSCAAFXQABbSAAHkclIXTAKJAyQIQLpBHJAEXB8AS1HvdRGT0a0D2ZZpBxjSc3L82IFK8pSfMwcqGEXTF3IIf8mJDRtt3YpLLPJZMWkmTtzJyxD+1UBofifVQOm8YyWjKtSKs8sVlICiECAImQeAARRyMAdogX8JRoqs6IYgDQ30zUjJ8CkWQmYZbOsFLGWzUyzE5bssx8ObAsoSqlpq8r1tILadr2g6ERWksQvCiAopi5i4qbRKjH7Bo4N1dsvFjOxEIeIwUPQ9o9AGSYvG+1bfsW7yVN8+agZB3bIHByUGtk1aWti874s1FGJOHYy6gTLo3lMVN7wPBNVAtbRRg0IEC35NmS0pxTltpwL6e2xn9s0w7mY5hGuaRzrAWZIYBJpc0pd1E18tNMZLOMAwnOCAsCDwFB4CORWms3bnm1AozWSgrHYMsYyEL6FGKXcDleMMO5rXJ5XZ0gP3jZqB4evaLwXEeqwnJNKYDypWlzHePwcIVotyuFT83QldOOpqWNU30A8rEmrMjPcAJk6FP7qch432rY3dxnN1onlaZ9idy5NILuCxl+UEwrH7wiqeqmnarpjatbB3Xcibser3eckfmd3xOkrnpce0DMjHMeoAgLjeqCCsBfVCmFOESE+EqdSfnmNwLJjBPBSs0QwuV3CQWPN3AwT4LTtldoEIAA */\n id: \"deviceConnection\",\n initial: \"Connected\",\n context: {\n apduInProgress: Nothing,\n apduResponse: Nothing,\n },\n states: {\n Connected: {\n on: {\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n SendApduCalled: {\n target: \"SendingApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n SendingApdu: {\n entry: \"sendApdu\",\n on: {\n ApduResponseReceived: [\n {\n guard: \"isApduThatTriggersDisconnection\",\n target: \"WaitingForDisconnection\",\n actions: [\n assign({\n apduResponse: ({ event }) => Maybe.of(event.apduResponse),\n }),\n ],\n },\n {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Right(event.apduResponse),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n ],\n },\n ],\n ApduSendingError: {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Left(event.error),\n };\n },\n },\n \"clearApduInProgress\",\n ],\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n WaitingForDisconnection: {\n entry: [\"sendGetAppAndVersion\"],\n exit: [\n {\n type: \"sendApduResponse\",\n params: ({ context }) => {\n return {\n response: context.apduResponse.caseOf({\n Just: (apduResponse) => Right(apduResponse),\n Nothing: () => Left(new UnknownDeviceExchangeError()),\n }),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n { type: \"clearApduResponse\" },\n ],\n on: {\n ApduResponseReceived: [\n {\n guard: \"isSendApduBusyError\",\n actions: [\"sendGetAppAndVersion\"],\n target: \"WaitingForDisconnection\",\n },\n {\n target: \"Connected\",\n },\n ],\n ApduSendingError: [\n {\n target: \"WaitingForReconnection\",\n },\n ],\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnection: {\n entry: [\"startTimer\", \"tryToReconnect\"],\n on: {\n DeviceConnected: {\n target: \"Connected\",\n actions: \"cancelTimer\",\n },\n SendApduCalled: {\n target: \"WaitingForReconnectionWithQueuedSendApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnectionWithQueuedSendApdu: {\n on: {\n DeviceConnected: {\n target: \"SendingApdu\",\n actions: \"cancelTimer\",\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedBeforeSendingApdu()),\n },\n },\n {\n type: \"clearApduInProgress\",\n },\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n // TODO: ADD INACTIVE STATE\n Terminated: {\n entry: [\"signalTermination\", \"closeConnection\"],\n type: \"final\",\n },\n },\n });\n}\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["DeviceConnectionStateMachine_exports", "__export", "DeviceConnectionStateMachine", "__toCommonJS", "import_purify_ts", "import_xstate", "import_CommandUtils", "import_Error", "import_Errors", "params", "makeStateMachine", "apdu", "triggersDisconnection", "abortTimeout", "response", "error", "apduResponse", "dependencies", "responseCallback", "sendApduFn", "startReconnectionTimeout", "cancelReconnectionTimeout", "tryToReconnect", "onTerminated", "closeConnection", "context", "event"]
|
7
7
|
}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";var
|
1
|
+
"use strict";var n=require("purify-ts/Either"),e=require("vitest"),A=require("../../device-session/ApduResponse"),m=require("./DeviceConnectionStateMachine"),i=require("./Errors");(0,e.describe)("DeviceConnectionStateMachine",()=>{let d;const s={sendApdu:e.vi.fn(),getDependencies:e.vi.fn(),setDependencies:e.vi.fn(),closeConnection:e.vi.fn(),setupConnection:e.vi.fn()},t=new A.ApduResponse({statusCode:Uint8Array.from([144,0]),data:new Uint8Array}),p=new A.ApduResponse({statusCode:Uint8Array.from([102,1]),data:new Uint8Array});(0,e.beforeEach)(()=>{e.vi.useFakeTimers(),d=new m.DeviceConnectionStateMachine({deviceId:"deviceId",deviceApduSender:s,timeoutDuration:1e3,tryToReconnect:e.vi.fn(),onTerminated:e.vi.fn()})}),(0,e.afterEach)(()=>{e.vi.useRealTimers(),e.vi.restoreAllMocks()}),(0,e.describe)("Send APDUs",()=>{(0,e.it)("should send APDU successfully",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const a=await d.sendApdu(o);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(1),(0,e.expect)(a).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should send several APDUs successfully",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const r=await d.sendApdu(o),u=await d.sendApdu(a);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(2),(0,e.expect)(r).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should not send several APDUs in parallel",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const r=d.sendApdu(o),u=await d.sendApdu(a),c=await r;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(1),(0,e.expect)(c).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Left)(new i.AlreadySendingApduError))}),(0,e.it)("Disconnected while sending APDU",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const a=d.sendApdu(o);d.eventDeviceDisconnected();const r=await a;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(1),(0,e.expect)(r).toStrictEqual((0,n.Left)(new i.DeviceDisconnectedWhileSendingError))}),(0,e.it)("Request disconnection while sending APDU",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const a=d.sendApdu(o);d.closeConnection();const r=await a;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(1),(0,e.expect)(r).toStrictEqual((0,n.Left)(new i.DeviceDisconnectedWhileSendingError))})}),(0,e.describe)("Send APDUs triggering disconnection",()=>{(0,e.it)("should send one APDU successfully",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const a=await d.sendApdu(o,!0);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(2),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),(0,e.expect)(a).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should send several APDUs successfully",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce((0,n.Right)(t)).mockRejectedValueOnce(new Error("Transport error")).mockResolvedValueOnce((0,n.Right)(t));const r=d.sendApdu(o,!0);await Promise.resolve(),d.eventDeviceDisconnected(),d.eventDeviceConnected();const u=d.sendApdu(a),c=await r,l=await u;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(3),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),(0,e.expect)(c).toStrictEqual((0,n.Right)(t)),(0,e.expect)(l).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should send a second APDU after reconnection",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce((0,n.Right)(t)).mockRejectedValueOnce(new Error("Transport error")).mockResolvedValueOnce((0,n.Right)(t));const r=await d.sendApdu(o,!0);d.eventDeviceDisconnected(),d.eventDeviceConnected();const u=await d.sendApdu(a);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(3),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),(0,e.expect)(r).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should send a second APDU without reconnection, after GetAppAndVersion response",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce((0,n.Right)(t)).mockResolvedValueOnce((0,n.Right)(t)).mockResolvedValueOnce((0,n.Right)(t));const r=await d.sendApdu(o,!0),u=await d.sendApdu(a);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(3),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),(0,e.expect)(r).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should send a second APDU without reconnection, after GetAppAndVersion retries",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce((0,n.Right)(t)).mockResolvedValueOnce((0,n.Right)(p)).mockResolvedValueOnce((0,n.Right)(p)).mockResolvedValueOnce((0,n.Right)(t)).mockResolvedValueOnce((0,n.Right)(t));const r=await d.sendApdu(o,!0),u=await d.sendApdu(a);(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(5),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),(0,e.expect)(r).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Right)(t))}),(0,e.it)("should not send several APDUs in parallel",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));const r=d.sendApdu(o,!0),u=await d.sendApdu(a),c=await r;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(2),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),(0,e.expect)(c).toStrictEqual((0,n.Right)(t)),(0,e.expect)(u).toStrictEqual((0,n.Left)(new i.AlreadySendingApduError))}),(0,e.it)("should send another APDU in promise handler",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));let r;const u=await d.sendApdu(o,!0).then(l=>(r=d.sendApdu(a),l));d.eventDeviceDisconnected(),d.eventDeviceConnected();const c=await r;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(3),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),(0,e.expect)(u).toStrictEqual((0,n.Right)(t)),(0,e.expect)(c).toStrictEqual((0,n.Right)(t))}),(0,e.it)("send an APDU while device is reconnecting",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t)),d.eventDeviceDisconnected();const a=d.sendApdu(o,!0);d.eventDeviceConnected();const r=await a;(0,e.expect)(s.sendApdu).toHaveBeenCalledTimes(2),(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),(0,e.expect)(r).toStrictEqual((0,n.Right)(t))}),(0,e.it)("Close while an APDU is waiting for reconnection",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue((0,n.Right)(t));let r;const u=d.sendApdu(o,!0);await Promise.resolve(),d.eventDeviceDisconnected();const c=await u;r=d.sendApdu(a),d.closeConnection();const l=await r;(0,e.expect)(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),(0,e.expect)(c).toStrictEqual((0,n.Right)(t)),(0,e.expect)(l).toStrictEqual((0,n.Left)(new i.DeviceDisconnectedWhileSendingError))})})});
|
2
2
|
//# sourceMappingURL=DeviceConnectionStateMachine.test.js.map
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../../../src/api/transport/model/DeviceConnectionStateMachine.test.ts"],
|
4
|
-
"sourcesContent": ["import { Left, Right } from \"purify-ts/Either\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { ApduResponse } from \"@api/device-session/ApduResponse\";\n\nimport { type SendApduResult } from \"./DeviceConnection\";\nimport { DeviceConnectionStateMachine } from \"./DeviceConnectionStateMachine\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedWhileSendingError,\n} from \"./Errors\";\n\ndescribe(\"DeviceConnectionStateMachine\", () => {\n let machine: DeviceConnectionStateMachine<void>;\n const mockApduSender = {\n sendApdu: vi.fn(),\n getDependencies: vi.fn(),\n setDependencies: vi.fn(),\n closeConnection: vi.fn(),\n setupConnection: vi.fn(),\n };\n\n beforeEach(() => {\n vi.useFakeTimers();\n machine = new DeviceConnectionStateMachine<void>({\n deviceId: \"deviceId\",\n deviceApduSender: mockApduSender,\n timeoutDuration: 1000,\n tryToReconnect: vi.fn(),\n onTerminated: vi.fn(),\n });\n });\n\n afterEach(() => {\n vi.useRealTimers();\n vi.restoreAllMocks();\n });\n\n describe(\"Send APDUs\", () => {\n it(\"should send APDU successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send several APDUs successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu);\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should not send several APDUs in parallel\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n const result2 = await machine.sendApdu(apdu2);\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Left(new AlreadySendingApduError()));\n });\n\n it(\"Disconnected while sending APDU\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n machine.eventDeviceDisconnected();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n\n it(\"Request disconnection while sending APDU\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n machine.closeConnection();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n });\n\n describe(\"Send APDUs triggering disconnection\", () => {\n it(\"should send one APDU successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send several APDUs successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise1 = machine.sendApdu(apdu, true);\n await Promise.resolve(); // Allow the first APDU to be sent and processed before the disconnection event\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const promise2 = machine.sendApdu(apdu2);\n const result1 = await promise1;\n const result2 = await promise2;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n\n expect(result1).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send a second APDU after reconnection\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should not send several APDUs in parallel\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu, true);\n const result2 = await machine.sendApdu(apdu2);\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Left(new AlreadySendingApduError()));\n });\n\n it(\"should send another APDU in promise handler\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n let promise: Promise<SendApduResult> | undefined = undefined;\n const result = await machine.sendApdu(apdu, true).then((value) => {\n promise = machine.sendApdu(apdu2);\n return value;\n });\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const result2 = await promise!;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"send an APDU while device is reconnecting\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n machine.eventDeviceDisconnected();\n const promise = machine.sendApdu(apdu, true);\n machine.eventDeviceConnected();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"Close while an APDU is waiting for reconnection\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n let promise: Promise<SendApduResult> | undefined = undefined;\n const promise1 = machine.sendApdu(apdu, true);\n await Promise.resolve(); // Allow the first APDU promise to resolve before triggering disconnection\n machine.eventDeviceDisconnected();\n const result1 = await promise1;\n promise = machine.sendApdu(apdu2);\n machine.closeConnection();\n const result2 = await promise!;\n\n // THEN\n // expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result1).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n });\n});\n"],
|
5
|
-
"mappings": "aAAA,IAAAA,EAA4B,4BAC5BC,EAAgE,kBAEhEC,EAA6B,4CAG7BC,EAA6C,0CAC7CC,EAGO,uBAEP,YAAS,+BAAgC,IAAM,CAC7C,IAAIC,EACJ,MAAMC,EAAiB,CACrB,SAAU,KAAG,GAAG,EAChB,gBAAiB,KAAG,GAAG,EACvB,gBAAiB,KAAG,GAAG,EACvB,gBAAiB,KAAG,GAAG,EACvB,gBAAiB,KAAG,GAAG,CACzB,
|
6
|
-
"names": ["import_Either", "import_vitest", "import_ApduResponse", "import_DeviceConnectionStateMachine", "import_Errors", "machine", "mockApduSender", "
|
4
|
+
"sourcesContent": ["import { Left, Right } from \"purify-ts/Either\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\n\nimport { ApduResponse } from \"@api/device-session/ApduResponse\";\n\nimport { type SendApduResult } from \"./DeviceConnection\";\nimport { DeviceConnectionStateMachine } from \"./DeviceConnectionStateMachine\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedWhileSendingError,\n} from \"./Errors\";\n\ndescribe(\"DeviceConnectionStateMachine\", () => {\n let machine: DeviceConnectionStateMachine<void>;\n const mockApduSender = {\n sendApdu: vi.fn(),\n getDependencies: vi.fn(),\n setDependencies: vi.fn(),\n closeConnection: vi.fn(),\n setupConnection: vi.fn(),\n };\n\n const apduResponse = new ApduResponse({\n statusCode: Uint8Array.from([0x90, 0x00]),\n data: new Uint8Array(),\n });\n const apduResponseErrorBusy = new ApduResponse({\n statusCode: Uint8Array.from([0x66, 0x01]),\n data: new Uint8Array(),\n });\n\n beforeEach(() => {\n vi.useFakeTimers();\n machine = new DeviceConnectionStateMachine<void>({\n deviceId: \"deviceId\",\n deviceApduSender: mockApduSender,\n timeoutDuration: 1000,\n tryToReconnect: vi.fn(),\n onTerminated: vi.fn(),\n });\n });\n\n afterEach(() => {\n vi.useRealTimers();\n vi.restoreAllMocks();\n });\n\n describe(\"Send APDUs\", () => {\n it(\"should send APDU successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send several APDUs successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu);\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should not send several APDUs in parallel\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n const result2 = await machine.sendApdu(apdu2);\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Left(new AlreadySendingApduError()));\n });\n\n it(\"Disconnected while sending APDU\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n machine.eventDeviceDisconnected();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n\n it(\"Request disconnection while sending APDU\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu);\n machine.closeConnection();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(1);\n expect(result).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n });\n\n describe(\"Send APDUs triggering disconnection\", () => {\n it(\"should send one APDU successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send several APDUs successfully\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu\n .mockResolvedValueOnce(Right(apduResponse))\n .mockRejectedValueOnce(new Error(\"Transport error\"))\n .mockResolvedValueOnce(Right(apduResponse));\n\n // WHEN\n const promise1 = machine.sendApdu(apdu, true);\n await Promise.resolve(); // Allow the first APDU to be sent and processed before the disconnection event\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const promise2 = machine.sendApdu(apdu2);\n const result1 = await promise1;\n const result2 = await promise2;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n\n expect(result1).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send a second APDU after reconnection\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu\n .mockResolvedValueOnce(Right(apduResponse))\n .mockRejectedValueOnce(new Error(\"Transport error\"))\n .mockResolvedValueOnce(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send a second APDU without reconnection, after GetAppAndVersion response\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu\n .mockResolvedValueOnce(Right(apduResponse))\n .mockResolvedValueOnce(Right(apduResponse))\n .mockResolvedValueOnce(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should send a second APDU without reconnection, after GetAppAndVersion retries\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu\n .mockResolvedValueOnce(Right(apduResponse))\n .mockResolvedValueOnce(Right(apduResponseErrorBusy))\n .mockResolvedValueOnce(Right(apduResponseErrorBusy))\n .mockResolvedValueOnce(Right(apduResponse))\n .mockResolvedValueOnce(Right(apduResponse));\n\n // WHEN\n const result = await machine.sendApdu(apdu, true);\n const result2 = await machine.sendApdu(apdu2);\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(5);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined],\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"should not send several APDUs in parallel\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n const promise = machine.sendApdu(apdu, true);\n const result2 = await machine.sendApdu(apdu2);\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Left(new AlreadySendingApduError()));\n });\n\n it(\"should send another APDU in promise handler\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n let promise: Promise<SendApduResult> | undefined = undefined;\n const result = await machine.sendApdu(apdu, true).then((value) => {\n promise = machine.sendApdu(apdu2);\n return value;\n });\n machine.eventDeviceDisconnected();\n machine.eventDeviceConnected();\n const result2 = await promise!;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(3);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n [apdu2, false, undefined],\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(Right(apduResponse));\n });\n\n it(\"send an APDU while device is reconnecting\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n machine.eventDeviceDisconnected();\n const promise = machine.sendApdu(apdu, true);\n machine.eventDeviceConnected();\n const result = await promise;\n\n // THEN\n expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result).toStrictEqual(Right(apduResponse));\n });\n\n it(\"Close while an APDU is waiting for reconnection\", async () => {\n // GIVEN\n const apdu = Uint8Array.from([1, 2, 3, 4]);\n const apdu2 = Uint8Array.from([9, 2, 3, 4]);\n mockApduSender.sendApdu.mockResolvedValue(Right(apduResponse));\n\n // WHEN\n let promise: Promise<SendApduResult> | undefined = undefined;\n const promise1 = machine.sendApdu(apdu, true);\n await Promise.resolve(); // Allow the first APDU promise to resolve before triggering disconnection\n machine.eventDeviceDisconnected();\n const result1 = await promise1;\n promise = machine.sendApdu(apdu2);\n machine.closeConnection();\n const result2 = await promise!;\n\n // THEN\n // expect(mockApduSender.sendApdu).toHaveBeenCalledTimes(2);\n expect(mockApduSender.sendApdu.mock.calls).toEqual([\n [apdu, false, undefined],\n [Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false, undefined], // GetAppAndVersion APDU sent after a successful result from an APDU that triggers disconnection\n ]);\n expect(result1).toStrictEqual(Right(apduResponse));\n expect(result2).toStrictEqual(\n Left(new DeviceDisconnectedWhileSendingError()),\n );\n });\n });\n});\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["import_Either", "import_vitest", "import_ApduResponse", "import_DeviceConnectionStateMachine", "import_Errors", "machine", "mockApduSender", "apduResponse", "apduResponseErrorBusy", "apdu", "result", "apdu2", "result2", "promise", "promise1", "promise2", "result1", "value"]
|
7
7
|
}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{Left as o,Maybe as
|
1
|
+
import{Left as o,Maybe as l,Nothing as a,Right as g}from"purify-ts";import{assign as p,createActor as y,emit as v,setup as h}from"xstate";import{CommandUtils as D}from"../../command/utils/CommandUtils";import{UnknownDeviceExchangeError as C}from"../../Error";import{AlreadySendingApduError as m,DeviceDisconnectedBeforeSendingApdu as T,DeviceDisconnectedWhileSendingError as A}from"./Errors";class x{deviceId;deviceAdpuSender;machineActor;timeoutDuration;timeout=null;startReconnectionTimeout(){this.timeout=setTimeout(()=>{this.machineActor.send({type:"ReconnectionTimedOut"})},this.timeoutDuration)}constructor(n){this.deviceId=n.deviceId,this.deviceAdpuSender=n.deviceApduSender,this.timeoutDuration=n.timeoutDuration,this.machineActor=y(S({sendApduFn:(r,s,t)=>this.sendApduToDeviceConnection(r,s,t),startReconnectionTimeout:()=>this.startReconnectionTimeout(),cancelReconnectionTimeout:()=>{this.timeout&&(clearTimeout(this.timeout),this.timeout=null)},tryToReconnect:()=>{n.tryToReconnect(this.timeoutDuration)},onTerminated:n.onTerminated,closeConnection:()=>{this.deviceAdpuSender.closeConnection()}})),this.machineActor.start()}sendApduToDeviceConnection(n,r,s){this.deviceAdpuSender.sendApdu(n,r,s).then(t=>{t.caseOf({Left:c=>{this.machineActor.send({type:"ApduSendingError",error:c})},Right:c=>{this.machineActor.send({type:"ApduResponseReceived",apduResponse:c})}})}).catch(t=>{this.machineActor.send({type:"ApduSendingError",error:new C(t)})})}getDependencies(){return this.deviceAdpuSender.getDependencies()}setDependencies(n){this.deviceAdpuSender.setDependencies(n)}getDeviceId(){return this.deviceId}sendApdu(n,r,s){return new Promise(t=>{this.machineActor.send({type:"SendApduCalled",apdu:n,triggersDisconnection:!!r,abortTimeout:s,responseCallback:t})})}async setupConnection(){await this.deviceAdpuSender.setupConnection()}eventDeviceConnected(){this.machineActor.send({type:"DeviceConnected"})}eventDeviceDisconnected(){this.machineActor.send({type:"DeviceDisconnected"})}closeConnection(){this.machineActor.send({type:"CloseConnectionCalled"})}}function S({sendApduFn:u,startReconnectionTimeout:n,cancelReconnectionTimeout:r,tryToReconnect:s,onTerminated:t,closeConnection:c}){return h({types:{},actions:{startTimer:()=>{n()},cancelTimer:()=>{r()},reconnectionTimeoutEvent:v({type:"ReconnectionTimedOut"}),sendApdu:({context:e})=>{e.apduInProgress.map(({apdu:i,abortTimeout:d})=>{u(i,!1,d)})},sendApduResponse:({context:e},i)=>{e.apduInProgress.map(({responseCallback:d})=>d(i.response))},sendGetAppAndVersion:()=>{u(Uint8Array.from([176,1,0,0,0]),!1)},tryToReconnect:()=>{s()},clearApduInProgress:p({apduInProgress:a}),clearApduResponse:p({apduResponse:a}),signalTermination:()=>{t()},closeConnection:()=>{c()}},guards:{isApduThatTriggersDisconnection:({context:e,event:i})=>i.type!=="ApduResponseReceived"?!1:e.apduInProgress.caseOf({Just:({triggersDisconnection:d,apdu:R})=>(d||D.isApduThatTriggersDisconnection(R))&&D.isSuccessResponse(i.apduResponse),Nothing:()=>!1}),isSendApduBusyError:({event:e})=>e.type!=="ApduResponseReceived"?!1:e.apduResponse.statusCode[0]===102&&e.apduResponse.statusCode[1]===1}}).createMachine({id:"deviceConnection",initial:"Connected",context:{apduInProgress:a,apduResponse:a},states:{Connected:{on:{DeviceDisconnected:{target:"WaitingForReconnection"},SendApduCalled:{target:"SendingApdu",actions:p({apduInProgress:({event:e})=>l.of({apdu:e.apdu,triggersDisconnection:e.triggersDisconnection,abortTimeout:e.abortTimeout,responseCallback:e.responseCallback})})},CloseConnectionCalled:{target:"Terminated"}}},SendingApdu:{entry:"sendApdu",on:{ApduResponseReceived:[{guard:"isApduThatTriggersDisconnection",target:"WaitingForDisconnection",actions:[p({apduResponse:({event:e})=>l.of(e.apduResponse)})]},{target:"Connected",actions:[{type:"sendApduResponse",params:({event:e})=>({response:g(e.apduResponse)})},{type:"clearApduInProgress"}]}],ApduSendingError:{target:"Connected",actions:[{type:"sendApduResponse",params:({event:e})=>({response:o(e.error)})},"clearApduInProgress"]},DeviceDisconnected:{target:"WaitingForReconnection",actions:[{type:"sendApduResponse",params:{response:o(new A)}},"clearApduInProgress"]},CloseConnectionCalled:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:o(new A)}},"clearApduInProgress"]},SendApduCalled:{actions:({event:e})=>{e.responseCallback(o(new m))}}}},WaitingForDisconnection:{entry:["sendGetAppAndVersion"],exit:[{type:"sendApduResponse",params:({context:e})=>({response:e.apduResponse.caseOf({Just:i=>g(i),Nothing:()=>o(new C)})})},{type:"clearApduInProgress"},{type:"clearApduResponse"}],on:{ApduResponseReceived:[{guard:"isSendApduBusyError",actions:["sendGetAppAndVersion"],target:"WaitingForDisconnection"},{target:"Connected"}],ApduSendingError:[{target:"WaitingForReconnection"}],SendApduCalled:{actions:({event:e})=>{e.responseCallback(o(new m))}},DeviceDisconnected:{target:"WaitingForReconnection"},CloseConnectionCalled:{target:"Terminated"}}},WaitingForReconnection:{entry:["startTimer","tryToReconnect"],on:{DeviceConnected:{target:"Connected",actions:"cancelTimer"},SendApduCalled:{target:"WaitingForReconnectionWithQueuedSendApdu",actions:p({apduInProgress:({event:e})=>l.of({apdu:e.apdu,triggersDisconnection:e.triggersDisconnection,abortTimeout:e.abortTimeout,responseCallback:e.responseCallback})})},ReconnectionTimedOut:{target:"Terminated"},CloseConnectionCalled:{target:"Terminated"}}},WaitingForReconnectionWithQueuedSendApdu:{on:{DeviceConnected:{target:"SendingApdu",actions:"cancelTimer"},ReconnectionTimedOut:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:o(new T)}},{type:"clearApduInProgress"}]},CloseConnectionCalled:{target:"Terminated",actions:[{type:"sendApduResponse",params:{response:o(new A)}},"clearApduInProgress"]},SendApduCalled:{actions:({event:e})=>{e.responseCallback(o(new m))}}}},Terminated:{entry:["signalTermination","closeConnection"],type:"final"}}})}export{x as DeviceConnectionStateMachine};
|
2
2
|
//# sourceMappingURL=DeviceConnectionStateMachine.js.map
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"version": 3,
|
3
3
|
"sources": ["../../../../../../src/api/transport/model/DeviceConnectionStateMachine.ts"],
|
4
|
-
"sourcesContent": ["// import { createBrowserInspector } from \"@statelyai/inspect\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\nimport { type Actor, and, assign, createActor, emit, setup } from \"xstate\";\n\nimport { CommandUtils } from \"@api/command/utils/CommandUtils\";\nimport { type ApduResponse } from \"@api/device-session/ApduResponse\";\nimport { type DmkError, UnknownDeviceExchangeError } from \"@api/Error\";\nimport { type DeviceId } from \"@api/types\";\n\nimport { type DeviceApduSender } from \"./DeviceApduSender\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedBeforeSendingApdu,\n DeviceDisconnectedWhileSendingError,\n SendApduTimeoutError,\n} from \"./Errors\";\n\n// const { inspect } = createBrowserInspector();\n\ntype DeviceDisconnectedEvent = {\n type: \"DeviceDisconnected\";\n};\n\ntype DeviceConnectedEvent = {\n type: \"DeviceConnected\";\n};\n\ntype ApduResponseReceived = {\n type: \"ApduResponseReceived\";\n apduResponse: ApduResponse;\n};\n\ntype ApduSendingError = {\n type: \"ApduSendingError\";\n error: DmkError;\n};\n\ntype SendApduCalled = {\n type: \"SendApduCalled\";\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n};\n\ntype ReconnectionTimedOut = {\n type: \"ReconnectionTimedOut\";\n};\n\ntype CloseConnectionCalled = {\n type: \"CloseConnectionCalled\";\n};\n\nexport type Events =\n | DeviceDisconnectedEvent\n | DeviceConnectedEvent\n | ApduResponseReceived\n | ApduSendingError\n | SendApduCalled\n | CloseConnectionCalled\n | ReconnectionTimedOut;\n\nexport type DeviceConnectionStateMachineParams<Dependencies> = {\n deviceId: DeviceId;\n deviceApduSender: DeviceApduSender<Dependencies>;\n timeoutDuration: number;\n tryToReconnect: (timeoutDuration: number) => void;\n onTerminated: () => void;\n};\n\nexport class DeviceConnectionStateMachine<Dependencies> {\n private deviceId: DeviceId;\n private deviceAdpuSender: DeviceApduSender<Dependencies>;\n\n private machineActor: Actor<ReturnType<typeof makeStateMachine>>;\n\n private timeoutDuration: number;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n startReconnectionTimeout() {\n this.timeout = setTimeout(() => {\n this.machineActor.send({ type: \"ReconnectionTimedOut\" });\n }, this.timeoutDuration);\n }\n\n constructor(params: DeviceConnectionStateMachineParams<Dependencies>) {\n this.deviceId = params.deviceId;\n this.deviceAdpuSender = params.deviceApduSender;\n this.timeoutDuration = params.timeoutDuration;\n this.machineActor = createActor(\n makeStateMachine({\n sendApduFn: (apdu, triggersDisconnection, abortTimeout) =>\n this.sendApduToDeviceConnection(\n apdu,\n triggersDisconnection,\n abortTimeout,\n ),\n startReconnectionTimeout: () => this.startReconnectionTimeout(),\n cancelReconnectionTimeout: () => {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n },\n tryToReconnect: () => {\n params.tryToReconnect(this.timeoutDuration);\n },\n onTerminated: params.onTerminated,\n closeConnection: () => {\n this.deviceAdpuSender.closeConnection();\n },\n }),\n // {\n // // inspect,\n // },\n );\n this.machineActor.start();\n }\n\n private sendApduToDeviceConnection(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ) {\n this.deviceAdpuSender\n .sendApdu(apdu, triggersDisconnection, abortTimeout)\n .then((response) => {\n response.caseOf({\n Left: (error) => {\n this.machineActor.send({ type: \"ApduSendingError\", error });\n },\n Right: (apduResponse) => {\n this.machineActor.send({\n type: \"ApduResponseReceived\",\n apduResponse,\n });\n },\n });\n })\n .catch((error) => {\n this.machineActor.send({\n type: \"ApduSendingError\",\n error: new UnknownDeviceExchangeError(error),\n });\n });\n }\n\n /**\n * Called by the transport\n */\n\n public getDependencies(): Dependencies {\n return this.deviceAdpuSender.getDependencies();\n }\n\n public setDependencies(dependencies: Dependencies) {\n this.deviceAdpuSender.setDependencies(dependencies);\n }\n\n public getDeviceId() {\n return this.deviceId;\n }\n\n public sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n return new Promise((responseCallback) => {\n this.machineActor.send({\n type: \"SendApduCalled\",\n apdu,\n triggersDisconnection: !!triggersDisconnection,\n abortTimeout,\n responseCallback,\n });\n });\n }\n\n public async setupConnection() {\n await this.deviceAdpuSender.setupConnection();\n }\n\n // State Machine Events\n\n public eventDeviceConnected() {\n this.machineActor.send({ type: \"DeviceConnected\" });\n }\n\n public eventDeviceDisconnected() {\n this.machineActor.send({ type: \"DeviceDisconnected\" });\n }\n\n public closeConnection() {\n this.machineActor.send({ type: \"CloseConnectionCalled\" });\n }\n}\n\n/**\n * The total timeout must be superior to 5s because on Android,\n * we take 5s to detect a disconnection.\n */\nconst MAX_GET_APP_AND_VERSION_ATTEMPTS = 6;\nconst GET_APP_AND_VERSION_TIMEOUT = 1000;\n\nfunction makeStateMachine({\n sendApduFn,\n startReconnectionTimeout,\n cancelReconnectionTimeout,\n tryToReconnect,\n onTerminated,\n closeConnection,\n}: {\n sendApduFn: (\n apdu: Uint8Array,\n triggersDisconnection: boolean,\n abortTimeout?: number,\n ) => void;\n startReconnectionTimeout: () => void;\n cancelReconnectionTimeout: () => void;\n tryToReconnect: () => void;\n onTerminated: () => void;\n closeConnection: () => void;\n}) {\n return setup({\n types: {} as {\n context: {\n apduInProgress: Maybe<{\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n }>;\n apduResponse: Maybe<ApduResponse>;\n getAppAndVersionAttempts: number;\n };\n events: Events;\n },\n actions: {\n // event transitions\n startTimer: () => {\n startReconnectionTimeout();\n },\n cancelTimer: () => {\n cancelReconnectionTimeout();\n },\n reconnectionTimeoutEvent: emit({ type: \"ReconnectionTimedOut\" }),\n sendApdu: ({ context }) => {\n context.apduInProgress.map(({ apdu, abortTimeout }) => {\n sendApduFn(apdu, false, abortTimeout);\n });\n },\n sendApduResponse: (\n { context },\n params: { response: Either<DmkError, ApduResponse> },\n ) => {\n context.apduInProgress.map(({ responseCallback }) =>\n responseCallback(params.response),\n );\n },\n sendGetAppAndVersion: () => {\n sendApduFn(\n Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]),\n false,\n GET_APP_AND_VERSION_TIMEOUT,\n );\n },\n incrementGetAppAndVersionAttempts: assign({\n getAppAndVersionAttempts: ({ context }) =>\n context.getAppAndVersionAttempts + 1,\n }),\n resetGetAppAndVersionAttempts: assign({\n getAppAndVersionAttempts: 0,\n }),\n tryToReconnect: () => {\n tryToReconnect();\n },\n clearApduInProgress: assign({\n apduInProgress: Nothing,\n }),\n clearApduResponse: assign({\n apduResponse: Nothing,\n }),\n signalTermination: () => {\n onTerminated();\n },\n closeConnection: () => {\n closeConnection(); // ASK: how do we handle errors ?\n },\n },\n guards: {\n isApduThatTriggersDisconnection: ({ context, event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return context.apduInProgress.caseOf({\n Just: ({ triggersDisconnection, apdu }) => {\n const res =\n (triggersDisconnection ||\n CommandUtils.isApduThatTriggersDisconnection(apdu)) &&\n CommandUtils.isSuccessResponse(event.apduResponse);\n return res;\n },\n Nothing: () => false,\n });\n },\n isSendApduTimeoutError: ({ event }) => {\n if (event.type !== \"ApduSendingError\") {\n return false;\n }\n return event.error instanceof SendApduTimeoutError;\n },\n hasReachedGetAppAndVersionMaxAttempts: ({ context }) => {\n return (\n context.getAppAndVersionAttempts >= MAX_GET_APP_AND_VERSION_ATTEMPTS\n );\n },\n },\n }).createMachine({\n /** @xstate-layout N4IgpgJg5mDOIC5QTANwJYGMwGED2AdgWJgC7qEB0+RJpkAxACJpZgukCGmAFpANoAGALqJQABzyx05QmJAAPRAA4A7AGZKywQEYAnAFYATMoAsBg6fUA2ADQgAnolUnKBjUdXXVpnUb0aAL6B9igY2DTEZBQE1IRR9BAMAMpgBBAAguIQAK44nAA2BQIi8pLSsgTySgjW6oKU6uo61kbWyh06Vsr2TgjqAZR6HUaWXcrqBmrBoawR8XQxcbRkjDgFUrgL0YT5RSWiSCDlMjHVKnrWjaO6ev6qlnp6vYim1qaN9YLqGuPKOjpVDMQGE2JFFlRUul0AQoFlcgx4TkAEpwSQEWBgVHYdCoA5lKSnORHGpNVSUPwGXQDQSmNTDF4IZTWPRDJotUw+HwAnTA0HzFaVShQiAwuHZHKIiWo2DozHYsC4gQ6Q4SQmVc79TxDIzqG6eJq+VSM94NPQ6CYuUzmQGCax8uZbQVLEVipFS3Ku2EAUQATr68L6hKrjuqziTEJNNHrTG1dIIDE8jLTGVTlJQboI2i56QZeSEQY7wTtYl7xQiWOF2GAuLx8UcThqIwh-OmdBZPF0qQCBoydIJlAZKK0jP4bHntBaHVXi0Ky+71ptZzE9sUIMGCRVw6Aau2dJQ6WZlMM-D9+89HIh++mbndVHpdNYLAnp2DtnO0qLYe6RUjV-W1S3Ykd0QABac1KFpbx3kHCxumNS9ak5SDTHNax0NUDRfFMV8BQSJYAHVOFOWEADFA2xd8YmYR0MlIWs+HXUoGzDYDFEQQx90mVozABJ9BAvPo6iuFpRgtQRdDUWNcKdfCqCIkioHI31KOdQgUk-P9CjXDcWKAqpmx0dR-gpCTaXNUxvh7RkvCHWlaWM9RfC6dCZOXeTiPIMiKJIKj1NUuSCAAFXQABbSAAHkclIXTAKJAyQIQLpBHJAEXB8AS1HvdRGT0a0D2ZZpBxjSc3L82IFK8pSfMwcqGEXTF3IIf8mJDRtt3YpLLPJZMWkmTtzJyxD+1UBofifVQOm8YyWjKtSKs8sVlICiECAImQeAARRyMAdogX8JRoqs6IYgDQ30zUjJ8CkWQmYZbOsFLGWzUyzE5bssx8ObAsoSqlpq8r1tILadr2g6ERWksQvCiAopi5i4qbRKjH7Bo4N1dsvFjOxEIeIwUPQ9o9AGSYvG+1bfsW7yVN8+agZB3bIHByUGtk1aWti874s1FGJOHYy6gTLo3lMVN7wPBNVAtbRRg0IEC35NmS0pxTltpwL6e2xn9s0w7mY5hGuaRzrAWZIYBJpc0pd1E18tNMZLOMAwnOCAsCDwFB4CORWms3bnm1AozWSgrHYMsYyEL6FGKXcDleMMO5rXJ5XZ0gP3jZqB4evaLwXEeqwnJNKYDypWlzHePwcIVotyuFT83QldOOpqWNU30A8rEmrMjPcAJk6FP7qch432rY3dxnN1onlaZ9idy5NILuCxl+UEwrH7wiqeqmnarpjatbB3Xcibser3eckfmd3xOkrnpce0DMjHMeoAgLjeqCCsBfVCmFOESE+EqdSfnmNwLJjBPBSs0QwuV3CQWPN3AwT4LTtldoEIAA */\n id: \"deviceConnection\",\n initial: \"Connected\",\n context: {\n apduInProgress: Nothing,\n apduResponse: Nothing,\n getAppAndVersionAttempts: 0,\n },\n states: {\n Connected: {\n on: {\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n SendApduCalled: {\n target: \"SendingApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n SendingApdu: {\n entry: \"sendApdu\",\n on: {\n ApduResponseReceived: [\n {\n guard: \"isApduThatTriggersDisconnection\",\n target: \"WaitingForDisconnection\",\n actions: [\n assign({\n apduResponse: ({ event }) => Maybe.of(event.apduResponse),\n }),\n ],\n },\n {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Right(event.apduResponse),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n ],\n },\n ],\n ApduSendingError: {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Left(event.error),\n };\n },\n },\n \"clearApduInProgress\",\n ],\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n WaitingForDisconnection: {\n entry: [\"sendGetAppAndVersion\", \"incrementGetAppAndVersionAttempts\"],\n exit: [\n \"resetGetAppAndVersionAttempts\",\n {\n type: \"sendApduResponse\",\n params: ({ context }) => {\n return {\n response: context.apduResponse.caseOf({\n Just: (apduResponse) => Right(apduResponse),\n Nothing: () => Left(new UnknownDeviceExchangeError()),\n }),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n { type: \"clearApduResponse\" },\n ],\n on: {\n ApduResponseReceived: {\n target: \"Connected\",\n },\n ApduSendingError: [\n {\n guard: and([\n \"isSendApduTimeoutError\",\n \"hasReachedGetAppAndVersionMaxAttempts\",\n ]),\n target: \"Terminated\",\n },\n {\n guard: \"isSendApduTimeoutError\",\n actions: [\n \"sendGetAppAndVersion\",\n \"incrementGetAppAndVersionAttempts\",\n ],\n target: \"WaitingForDisconnection\",\n },\n {\n target: \"WaitingForReconnection\",\n },\n ],\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnection: {\n entry: [\"startTimer\", \"tryToReconnect\"],\n on: {\n DeviceConnected: {\n target: \"Connected\",\n actions: \"cancelTimer\",\n },\n SendApduCalled: {\n target: \"WaitingForReconnectionWithQueuedSendApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnectionWithQueuedSendApdu: {\n on: {\n DeviceConnected: {\n target: \"SendingApdu\",\n actions: \"cancelTimer\",\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedBeforeSendingApdu()),\n },\n },\n {\n type: \"clearApduInProgress\",\n },\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n // TODO: ADD INACTIVE STATE\n Terminated: {\n entry: [\"signalTermination\", \"closeConnection\"],\n type: \"final\",\n },\n },\n });\n}\n"],
|
5
|
-
"mappings": "AACA,OAAsB,QAAAA,EAAM,SAAAC,EAAO,WAAAC,EAAS,SAAAC,MAAa,YACzD,OAAqB,
|
6
|
-
"names": ["Left", "Maybe", "Nothing", "Right", "
|
4
|
+
"sourcesContent": ["// import { createBrowserInspector } from \"@statelyai/inspect\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\nimport { type Actor, assign, createActor, emit, setup } from \"xstate\";\n\nimport { CommandUtils } from \"@api/command/utils/CommandUtils\";\nimport { type ApduResponse } from \"@api/device-session/ApduResponse\";\nimport { type DmkError, UnknownDeviceExchangeError } from \"@api/Error\";\nimport { type DeviceId } from \"@api/types\";\n\nimport { type DeviceApduSender } from \"./DeviceApduSender\";\nimport {\n AlreadySendingApduError,\n DeviceDisconnectedBeforeSendingApdu,\n DeviceDisconnectedWhileSendingError,\n} from \"./Errors\";\n\n// const { inspect } = createBrowserInspector();\n\ntype DeviceDisconnectedEvent = {\n type: \"DeviceDisconnected\";\n};\n\ntype DeviceConnectedEvent = {\n type: \"DeviceConnected\";\n};\n\ntype ApduResponseReceived = {\n type: \"ApduResponseReceived\";\n apduResponse: ApduResponse;\n};\n\ntype ApduSendingError = {\n type: \"ApduSendingError\";\n error: DmkError;\n};\n\ntype SendApduCalled = {\n type: \"SendApduCalled\";\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n};\n\ntype ReconnectionTimedOut = {\n type: \"ReconnectionTimedOut\";\n};\n\ntype CloseConnectionCalled = {\n type: \"CloseConnectionCalled\";\n};\n\nexport type Events =\n | DeviceDisconnectedEvent\n | DeviceConnectedEvent\n | ApduResponseReceived\n | ApduSendingError\n | SendApduCalled\n | CloseConnectionCalled\n | ReconnectionTimedOut;\n\nexport type DeviceConnectionStateMachineParams<Dependencies> = {\n deviceId: DeviceId;\n deviceApduSender: DeviceApduSender<Dependencies>;\n timeoutDuration: number;\n tryToReconnect: (timeoutDuration: number) => void;\n onTerminated: () => void;\n};\n\nexport class DeviceConnectionStateMachine<Dependencies> {\n private deviceId: DeviceId;\n private deviceAdpuSender: DeviceApduSender<Dependencies>;\n\n private machineActor: Actor<ReturnType<typeof makeStateMachine>>;\n\n private timeoutDuration: number;\n private timeout: ReturnType<typeof setTimeout> | null = null;\n\n startReconnectionTimeout() {\n this.timeout = setTimeout(() => {\n this.machineActor.send({ type: \"ReconnectionTimedOut\" });\n }, this.timeoutDuration);\n }\n\n constructor(params: DeviceConnectionStateMachineParams<Dependencies>) {\n this.deviceId = params.deviceId;\n this.deviceAdpuSender = params.deviceApduSender;\n this.timeoutDuration = params.timeoutDuration;\n this.machineActor = createActor(\n makeStateMachine({\n sendApduFn: (apdu, triggersDisconnection, abortTimeout) =>\n this.sendApduToDeviceConnection(\n apdu,\n triggersDisconnection,\n abortTimeout,\n ),\n startReconnectionTimeout: () => this.startReconnectionTimeout(),\n cancelReconnectionTimeout: () => {\n if (this.timeout) {\n clearTimeout(this.timeout);\n this.timeout = null;\n }\n },\n tryToReconnect: () => {\n params.tryToReconnect(this.timeoutDuration);\n },\n onTerminated: params.onTerminated,\n closeConnection: () => {\n this.deviceAdpuSender.closeConnection();\n },\n }),\n // {\n // // inspect,\n // },\n );\n this.machineActor.start();\n }\n\n private sendApduToDeviceConnection(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ) {\n this.deviceAdpuSender\n .sendApdu(apdu, triggersDisconnection, abortTimeout)\n .then((response) => {\n response.caseOf({\n Left: (error) => {\n this.machineActor.send({ type: \"ApduSendingError\", error });\n },\n Right: (apduResponse) => {\n this.machineActor.send({\n type: \"ApduResponseReceived\",\n apduResponse,\n });\n },\n });\n })\n .catch((error) => {\n this.machineActor.send({\n type: \"ApduSendingError\",\n error: new UnknownDeviceExchangeError(error),\n });\n });\n }\n\n /**\n * Called by the transport\n */\n\n public getDependencies(): Dependencies {\n return this.deviceAdpuSender.getDependencies();\n }\n\n public setDependencies(dependencies: Dependencies) {\n this.deviceAdpuSender.setDependencies(dependencies);\n }\n\n public getDeviceId() {\n return this.deviceId;\n }\n\n public sendApdu(\n apdu: Uint8Array,\n triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n return new Promise((responseCallback) => {\n this.machineActor.send({\n type: \"SendApduCalled\",\n apdu,\n triggersDisconnection: !!triggersDisconnection,\n abortTimeout,\n responseCallback,\n });\n });\n }\n\n public async setupConnection() {\n await this.deviceAdpuSender.setupConnection();\n }\n\n // State Machine Events\n\n public eventDeviceConnected() {\n this.machineActor.send({ type: \"DeviceConnected\" });\n }\n\n public eventDeviceDisconnected() {\n this.machineActor.send({ type: \"DeviceDisconnected\" });\n }\n\n public closeConnection() {\n this.machineActor.send({ type: \"CloseConnectionCalled\" });\n }\n}\n\nfunction makeStateMachine({\n sendApduFn,\n startReconnectionTimeout,\n cancelReconnectionTimeout,\n tryToReconnect,\n onTerminated,\n closeConnection,\n}: {\n sendApduFn: (\n apdu: Uint8Array,\n triggersDisconnection: boolean,\n abortTimeout?: number,\n ) => void;\n startReconnectionTimeout: () => void;\n cancelReconnectionTimeout: () => void;\n tryToReconnect: () => void;\n onTerminated: () => void;\n closeConnection: () => void;\n}) {\n return setup({\n types: {} as {\n context: {\n apduInProgress: Maybe<{\n apdu: Uint8Array;\n triggersDisconnection: boolean;\n abortTimeout?: number;\n responseCallback: (response: Either<DmkError, ApduResponse>) => void;\n }>;\n apduResponse: Maybe<ApduResponse>;\n };\n events: Events;\n },\n actions: {\n // event transitions\n startTimer: () => {\n startReconnectionTimeout();\n },\n cancelTimer: () => {\n cancelReconnectionTimeout();\n },\n reconnectionTimeoutEvent: emit({ type: \"ReconnectionTimedOut\" }),\n sendApdu: ({ context }) => {\n context.apduInProgress.map(({ apdu, abortTimeout }) => {\n sendApduFn(apdu, false, abortTimeout);\n });\n },\n sendApduResponse: (\n { context },\n params: { response: Either<DmkError, ApduResponse> },\n ) => {\n context.apduInProgress.map(({ responseCallback }) =>\n responseCallback(params.response),\n );\n },\n sendGetAppAndVersion: () => {\n sendApduFn(Uint8Array.from([0xb0, 0x01, 0x00, 0x00, 0x00]), false);\n },\n tryToReconnect: () => {\n tryToReconnect();\n },\n clearApduInProgress: assign({\n apduInProgress: Nothing,\n }),\n clearApduResponse: assign({\n apduResponse: Nothing,\n }),\n signalTermination: () => {\n onTerminated();\n },\n closeConnection: () => {\n closeConnection(); // ASK: how do we handle errors ?\n },\n },\n guards: {\n isApduThatTriggersDisconnection: ({ context, event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return context.apduInProgress.caseOf({\n Just: ({ triggersDisconnection, apdu }) => {\n const res =\n (triggersDisconnection ||\n CommandUtils.isApduThatTriggersDisconnection(apdu)) &&\n CommandUtils.isSuccessResponse(event.apduResponse);\n return res;\n },\n Nothing: () => false,\n });\n },\n isSendApduBusyError: ({ event }) => {\n if (event.type !== \"ApduResponseReceived\") {\n return false;\n }\n return (\n event.apduResponse.statusCode[0] === 0x66 &&\n event.apduResponse.statusCode[1] === 0x01\n );\n },\n },\n }).createMachine({\n /** @xstate-layout N4IgpgJg5mDOIC5QTANwJYGMwGED2AdgWJgC7qEB0+RJpkAxACJpZgukCGmAFpANoAGALqJQABzyx05QmJAAPRAA4A7AGZKywQEYAnAFYATMoAsBg6fUA2ADQgAnolUnKBjUdXXVpnUb0aAL6B9igY2DTEZBQE1IRR9BAMAMpgBBAAguIQAK44nAA2BQIi8pLSsgTySgjW6oKU6uo61kbWyh06Vsr2TgjqAZR6HUaWXcrqBmrBoawR8XQxcbRkjDgFUrgL0YT5RSWiSCDlMjHVKnrWjaO6ev6qlnp6vYim1qaN9YLqGuPKOjpVDMQGE2JFFlRUul0AQoFlcgx4TkAEpwSQEWBgVHYdCoA5lKSnORHGpNVSUPwGXQDQSmNTDF4IZTWPRDJotUw+HwAnTA0HzFaVShQiAwuHZHKIiWo2DozHYsC4gQ6Q4SQmVc79TxDIzqG6eJq+VSM94NPQ6CYuUzmQGCax8uZbQVLEVipFS3Ku2EAUQATr68L6hKrjuqziTEJNNHrTG1dIIDE8jLTGVTlJQboI2i56QZeSEQY7wTtYl7xQiWOF2GAuLx8UcThqIwh-OmdBZPF0qQCBoydIJlAZKK0jP4bHntBaHVXi0Ky+71ptZzE9sUIMGCRVw6Aau2dJQ6WZlMM-D9+89HIh++mbndVHpdNYLAnp2DtnO0qLYe6RUjV-W1S3Ykd0QABac1KFpbx3kHCxumNS9ak5SDTHNax0NUDRfFMV8BQSJYAHVOFOWEADFA2xd8YmYR0MlIWs+HXUoGzDYDFEQQx90mVozABJ9BAvPo6iuFpRgtQRdDUWNcKdfCqCIkioHI31KOdQgUk-P9CjXDcWKAqpmx0dR-gpCTaXNUxvh7RkvCHWlaWM9RfC6dCZOXeTiPIMiKJIKj1NUuSCAAFXQABbSAAHkclIXTAKJAyQIQLpBHJAEXB8AS1HvdRGT0a0D2ZZpBxjSc3L82IFK8pSfMwcqGEXTF3IIf8mJDRtt3YpLLPJZMWkmTtzJyxD+1UBofifVQOm8YyWjKtSKs8sVlICiECAImQeAARRyMAdogX8JRoqs6IYgDQ30zUjJ8CkWQmYZbOsFLGWzUyzE5bssx8ObAsoSqlpq8r1tILadr2g6ERWksQvCiAopi5i4qbRKjH7Bo4N1dsvFjOxEIeIwUPQ9o9AGSYvG+1bfsW7yVN8+agZB3bIHByUGtk1aWti874s1FGJOHYy6gTLo3lMVN7wPBNVAtbRRg0IEC35NmS0pxTltpwL6e2xn9s0w7mY5hGuaRzrAWZIYBJpc0pd1E18tNMZLOMAwnOCAsCDwFB4CORWms3bnm1AozWSgrHYMsYyEL6FGKXcDleMMO5rXJ5XZ0gP3jZqB4evaLwXEeqwnJNKYDypWlzHePwcIVotyuFT83QldOOpqWNU30A8rEmrMjPcAJk6FP7qch432rY3dxnN1onlaZ9idy5NILuCxl+UEwrH7wiqeqmnarpjatbB3Xcibser3eckfmd3xOkrnpce0DMjHMeoAgLjeqCCsBfVCmFOESE+EqdSfnmNwLJjBPBSs0QwuV3CQWPN3AwT4LTtldoEIAA */\n id: \"deviceConnection\",\n initial: \"Connected\",\n context: {\n apduInProgress: Nothing,\n apduResponse: Nothing,\n },\n states: {\n Connected: {\n on: {\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n SendApduCalled: {\n target: \"SendingApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n SendingApdu: {\n entry: \"sendApdu\",\n on: {\n ApduResponseReceived: [\n {\n guard: \"isApduThatTriggersDisconnection\",\n target: \"WaitingForDisconnection\",\n actions: [\n assign({\n apduResponse: ({ event }) => Maybe.of(event.apduResponse),\n }),\n ],\n },\n {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Right(event.apduResponse),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n ],\n },\n ],\n ApduSendingError: {\n target: \"Connected\",\n actions: [\n {\n type: \"sendApduResponse\",\n // https://stately.ai/docs/actions#dynamic-action-parameters\n params: ({ event }) => {\n return {\n response: Left(event.error),\n };\n },\n },\n \"clearApduInProgress\",\n ],\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n WaitingForDisconnection: {\n entry: [\"sendGetAppAndVersion\"],\n exit: [\n {\n type: \"sendApduResponse\",\n params: ({ context }) => {\n return {\n response: context.apduResponse.caseOf({\n Just: (apduResponse) => Right(apduResponse),\n Nothing: () => Left(new UnknownDeviceExchangeError()),\n }),\n };\n },\n },\n { type: \"clearApduInProgress\" },\n { type: \"clearApduResponse\" },\n ],\n on: {\n ApduResponseReceived: [\n {\n guard: \"isSendApduBusyError\",\n actions: [\"sendGetAppAndVersion\"],\n target: \"WaitingForDisconnection\",\n },\n {\n target: \"Connected\",\n },\n ],\n ApduSendingError: [\n {\n target: \"WaitingForReconnection\",\n },\n ],\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n DeviceDisconnected: {\n target: \"WaitingForReconnection\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnection: {\n entry: [\"startTimer\", \"tryToReconnect\"],\n on: {\n DeviceConnected: {\n target: \"Connected\",\n actions: \"cancelTimer\",\n },\n SendApduCalled: {\n target: \"WaitingForReconnectionWithQueuedSendApdu\",\n actions: assign({\n apduInProgress: ({ event }) => {\n return Maybe.of({\n apdu: event.apdu,\n triggersDisconnection: event.triggersDisconnection,\n abortTimeout: event.abortTimeout,\n responseCallback: event.responseCallback,\n });\n },\n }),\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n },\n },\n },\n WaitingForReconnectionWithQueuedSendApdu: {\n on: {\n DeviceConnected: {\n target: \"SendingApdu\",\n actions: \"cancelTimer\",\n },\n ReconnectionTimedOut: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedBeforeSendingApdu()),\n },\n },\n {\n type: \"clearApduInProgress\",\n },\n ],\n },\n CloseConnectionCalled: {\n target: \"Terminated\",\n actions: [\n {\n type: \"sendApduResponse\",\n params: {\n response: Left(new DeviceDisconnectedWhileSendingError()),\n },\n },\n \"clearApduInProgress\",\n ],\n },\n SendApduCalled: {\n actions: ({ event }) => {\n event.responseCallback(Left(new AlreadySendingApduError()));\n },\n },\n },\n },\n // TODO: ADD INACTIVE STATE\n Terminated: {\n entry: [\"signalTermination\", \"closeConnection\"],\n type: \"final\",\n },\n },\n });\n}\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["Left", "Maybe", "Nothing", "Right", "assign", "createActor", "emit", "setup", "CommandUtils", "UnknownDeviceExchangeError", "AlreadySendingApduError", "DeviceDisconnectedBeforeSendingApdu", "DeviceDisconnectedWhileSendingError", "DeviceConnectionStateMachine", "params", "makeStateMachine", "apdu", "triggersDisconnection", "abortTimeout", "response", "error", "apduResponse", "dependencies", "responseCallback", "sendApduFn", "startReconnectionTimeout", "cancelReconnectionTimeout", "tryToReconnect", "onTerminated", "closeConnection", "context", "event"]
|
7
7
|
}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
import{Left as
|
1
|
+
import{Left as p,Right as n}from"purify-ts/Either";import{afterEach as U,beforeEach as w,describe as m,expect as e,it as c,vi as i}from"vitest";import{ApduResponse as x}from"../../device-session/ApduResponse";import{DeviceConnectionStateMachine as D}from"./DeviceConnectionStateMachine";import{AlreadySendingApduError as y,DeviceDisconnectedWhileSendingError as f}from"./Errors";m("DeviceConnectionStateMachine",()=>{let d;const s={sendApdu:i.fn(),getDependencies:i.fn(),setDependencies:i.fn(),closeConnection:i.fn(),setupConnection:i.fn()},t=new x({statusCode:Uint8Array.from([144,0]),data:new Uint8Array}),v=new x({statusCode:Uint8Array.from([102,1]),data:new Uint8Array});w(()=>{i.useFakeTimers(),d=new D({deviceId:"deviceId",deviceApduSender:s,timeoutDuration:1e3,tryToReconnect:i.fn(),onTerminated:i.fn()})}),U(()=>{i.useRealTimers(),i.restoreAllMocks()}),m("Send APDUs",()=>{c("should send APDU successfully",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const a=await d.sendApdu(o);e(s.sendApdu).toHaveBeenCalledTimes(1),e(a).toStrictEqual(n(t))}),c("should send several APDUs successfully",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const r=await d.sendApdu(o),u=await d.sendApdu(a);e(s.sendApdu).toHaveBeenCalledTimes(2),e(r).toStrictEqual(n(t)),e(u).toStrictEqual(n(t))}),c("should not send several APDUs in parallel",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const r=d.sendApdu(o),u=await d.sendApdu(a),l=await r;e(s.sendApdu).toHaveBeenCalledTimes(1),e(l).toStrictEqual(n(t)),e(u).toStrictEqual(p(new y))}),c("Disconnected while sending APDU",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const a=d.sendApdu(o);d.eventDeviceDisconnected();const r=await a;e(s.sendApdu).toHaveBeenCalledTimes(1),e(r).toStrictEqual(p(new f))}),c("Request disconnection while sending APDU",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const a=d.sendApdu(o);d.closeConnection();const r=await a;e(s.sendApdu).toHaveBeenCalledTimes(1),e(r).toStrictEqual(p(new f))})}),m("Send APDUs triggering disconnection",()=>{c("should send one APDU successfully",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const a=await d.sendApdu(o,!0);e(s.sendApdu).toHaveBeenCalledTimes(2),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),e(a).toStrictEqual(n(t))}),c("should send several APDUs successfully",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce(n(t)).mockRejectedValueOnce(new Error("Transport error")).mockResolvedValueOnce(n(t));const r=d.sendApdu(o,!0);await Promise.resolve(),d.eventDeviceDisconnected(),d.eventDeviceConnected();const u=d.sendApdu(a),l=await r,A=await u;e(s.sendApdu).toHaveBeenCalledTimes(3),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),e(l).toStrictEqual(n(t)),e(A).toStrictEqual(n(t))}),c("should send a second APDU after reconnection",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce(n(t)).mockRejectedValueOnce(new Error("Transport error")).mockResolvedValueOnce(n(t));const r=await d.sendApdu(o,!0);d.eventDeviceDisconnected(),d.eventDeviceConnected();const u=await d.sendApdu(a);e(s.sendApdu).toHaveBeenCalledTimes(3),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),e(r).toStrictEqual(n(t)),e(u).toStrictEqual(n(t))}),c("should send a second APDU without reconnection, after GetAppAndVersion response",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce(n(t)).mockResolvedValueOnce(n(t)).mockResolvedValueOnce(n(t));const r=await d.sendApdu(o,!0),u=await d.sendApdu(a);e(s.sendApdu).toHaveBeenCalledTimes(3),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),e(r).toStrictEqual(n(t)),e(u).toStrictEqual(n(t))}),c("should send a second APDU without reconnection, after GetAppAndVersion retries",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValueOnce(n(t)).mockResolvedValueOnce(n(v)).mockResolvedValueOnce(n(v)).mockResolvedValueOnce(n(t)).mockResolvedValueOnce(n(t));const r=await d.sendApdu(o,!0),u=await d.sendApdu(a);e(s.sendApdu).toHaveBeenCalledTimes(5),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),e(r).toStrictEqual(n(t)),e(u).toStrictEqual(n(t))}),c("should not send several APDUs in parallel",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue(n(t));const r=d.sendApdu(o,!0),u=await d.sendApdu(a),l=await r;e(s.sendApdu).toHaveBeenCalledTimes(2),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),e(l).toStrictEqual(n(t)),e(u).toStrictEqual(p(new y))}),c("should send another APDU in promise handler",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue(n(t));let r;const u=await d.sendApdu(o,!0).then(A=>(r=d.sendApdu(a),A));d.eventDeviceDisconnected(),d.eventDeviceConnected();const l=await r;e(s.sendApdu).toHaveBeenCalledTimes(3),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0],[a,!1,void 0]]),e(u).toStrictEqual(n(t)),e(l).toStrictEqual(n(t))}),c("send an APDU while device is reconnecting",async()=>{const o=Uint8Array.from([1,2,3,4]);s.sendApdu.mockResolvedValue(n(t)),d.eventDeviceDisconnected();const a=d.sendApdu(o,!0);d.eventDeviceConnected();const r=await a;e(s.sendApdu).toHaveBeenCalledTimes(2),e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),e(r).toStrictEqual(n(t))}),c("Close while an APDU is waiting for reconnection",async()=>{const o=Uint8Array.from([1,2,3,4]),a=Uint8Array.from([9,2,3,4]);s.sendApdu.mockResolvedValue(n(t));let r;const u=d.sendApdu(o,!0);await Promise.resolve(),d.eventDeviceDisconnected();const l=await u;r=d.sendApdu(a),d.closeConnection();const A=await r;e(s.sendApdu.mock.calls).toEqual([[o,!1,void 0],[Uint8Array.from([176,1,0,0,0]),!1,void 0]]),e(l).toStrictEqual(n(t)),e(A).toStrictEqual(p(new f))})})});
|
2
2
|
//# sourceMappingURL=DeviceConnectionStateMachine.test.js.map
|