LCOV - code coverage report
Current view: top level - dashql-app/src/connections/salesforce - salesforce_connection_state.ts Coverage Total Hit
Test: DashQL 915828b Lines: 99.8 % 481 480
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as connection from '@ankoh/dashql-jsonschema/connection.js';
       2              : import * as auth from '@ankoh/dashql-jsonschema/auth.js';
       3              : 
       4              : import type { DetailedError } from '../../utils/error.js';
       5              : 
       6              : import { VariantKind } from '../../utils/variant.js';
       7              : import { SalesforceDatabaseChannel } from './salesforce_api_client.js';
       8              : import { SALESFORCE_DATA_CLOUD_CONNECTOR, SIDB_CONNECTOR } from '../connector_info.js';
       9              : import type { SalesforceDetailsType } from '../connection_state_details.js';
      10              : import {
      11              :     ConnectionHealth,
      12              :     ConnectionState,
      13              :     ConnectionStatus,
      14              :     DELETE_CONNECTION,
      15              :     RESET_CONNECTION,
      16              : } from '../connection_state.js';
      17              : import { dateToTimestamp } from "../proto_helper.js";
      18              : 
      19              : /// The Salesforce connection state
      20              : export interface SalesforceConnectionStateDetails {
      21              :     /// The connection details
      22              :     proto: connection.SalesforceConnectionDetails;
      23              :     /// The Hyper connection
      24              :     channel: SalesforceDatabaseChannel | null;
      25              : }
      26              : 
      27              : /// Create the connection state details
      28            1 : export function createSalesforceConnectionStateDetails(params: connection.SalesforceConnectionParams): SalesforceConnectionStateDetails {
      29            1 :     return {
      30            1 :         proto: {
      31            1 :             setupTimings: {},
      32            1 :             setupParams: params
      33            1 :         },
      34            1 :         channel: null
      35            1 :     };
      36            1 : }
      37              : 
      38              : /// Unpack the connection state from the variant
      39            1 : export function getSalesforceConnectionDetails(state: ConnectionState | null): SalesforceConnectionStateDetails | null {
      40            1 :     if (state == null) return null;
      41            1 :     switch (state.details.type) {
      42            1 :         case SALESFORCE_DATA_CLOUD_CONNECTOR:
      43            1 :         case SIDB_CONNECTOR:
      44            1 :             return state.details.value;
      45            1 :         default: return null;
      46            1 :     }
      47            1 : }
      48              : 
      49            1 : export const SETUP_CANCELLED = Symbol('AUTH_CANCELLED');
      50            1 : export const SETUP_FAILED = Symbol('AUTH_FAILED');
      51            1 : export const SETUP_STARTED = Symbol('AUTH_STARTED');
      52              : 
      53            1 : export const SF_CHANNEL_SETUP_CANCELLED = Symbol('SF_CHANNEL_SETUP_CANCELLED');
      54            1 : export const SF_CHANNEL_SETUP_FAILED = Symbol('SF_CHANNEL_SETUP_FAILED');
      55            1 : export const SF_CHANNEL_SETUP_STARTED = Symbol('SF_CHANNEL_SETUP_STARTED');
      56            1 : export const SF_CHANNEL_READY = Symbol('SF_CHANNEL_READY');
      57              : 
      58            1 : export const GENERATING_PKCE_CHALLENGE = Symbol('GENERATING_PKCE_CHALLENGE');
      59            1 : export const GENERATED_PKCE_CHALLENGE = Symbol('GENERATED_PKCE_CHALLENGE');
      60            1 : export const OAUTH_NATIVE_LINK_OPENED = Symbol('OAUTH_NATIVE_LINK_OPENED');
      61            1 : export const OAUTH_WEB_WINDOW_CLOSED = Symbol('OAUTH_WEB_WINDOW_CLOSED');
      62            1 : export const OAUTH_WEB_WINDOW_OPENED = Symbol('OAUTH_WEB_WINDOW_OPENED');
      63            1 : export const RECEIVED_CORE_AUTH_CODE = Symbol('RECEIVED_AUTH_CODE');
      64            1 : export const REQUESTING_CORE_AUTH_TOKEN = Symbol('REQUESTING_CORE_AUTH_TOKEN');
      65            1 : export const RECEIVED_CORE_AUTH_TOKEN = Symbol('RECEIVED_CORE_ACCESS_TOKEN');
      66            1 : export const RECEIVED_CORE_USER_INFO = Symbol('RECEIVED_CORE_USER_INFO');
      67            1 : export const REQUESTING_DATA_CLOUD_ACCESS_TOKEN = Symbol('REQUESTING_DATA_CLOUD_ACCESS_TOKEN');
      68            1 : export const RECEIVED_DATA_CLOUD_ACCESS_TOKEN = Symbol('RECEIVED_DATA_CLOUD_ACCESS_TOKEN');
      69              : 
      70              : export type SalesforceConnectionStateAction =
      71              :     | VariantKind<typeof SETUP_CANCELLED, DetailedError>
      72              :     | VariantKind<typeof SETUP_FAILED, DetailedError>
      73              :     | VariantKind<typeof SETUP_STARTED, connection.SalesforceConnectionParams>
      74              :     | VariantKind<typeof GENERATED_PKCE_CHALLENGE, auth.OAuthPKCEChallenge>
      75              :     | VariantKind<typeof GENERATING_PKCE_CHALLENGE, null>
      76              :     | VariantKind<typeof OAUTH_NATIVE_LINK_OPENED, null>
      77              :     | VariantKind<typeof OAUTH_WEB_WINDOW_CLOSED, null>
      78              :     | VariantKind<typeof OAUTH_WEB_WINDOW_OPENED, null>
      79              :     | VariantKind<typeof RECEIVED_CORE_AUTH_CODE, auth.TemporaryToken>
      80              :     | VariantKind<typeof RECEIVED_CORE_AUTH_TOKEN, connection.SalesforceCoreAccessToken>
      81              :     | VariantKind<typeof RECEIVED_CORE_USER_INFO, connection.SalesforceCoreUserInfo>
      82              :     | VariantKind<typeof RECEIVED_DATA_CLOUD_ACCESS_TOKEN, connection.SalesforceDataCloudAccessToken>
      83              :     | VariantKind<typeof REQUESTING_CORE_AUTH_TOKEN, null>
      84              :     | VariantKind<typeof REQUESTING_DATA_CLOUD_ACCESS_TOKEN, null>
      85              :     | VariantKind<typeof SF_CHANNEL_READY, SalesforceDatabaseChannel>
      86              :     | VariantKind<typeof SF_CHANNEL_SETUP_CANCELLED, DetailedError>
      87              :     | VariantKind<typeof SF_CHANNEL_SETUP_FAILED, DetailedError>
      88              :     | VariantKind<typeof SF_CHANNEL_SETUP_STARTED, connection.HyperConnectionParams>
      89              :     | VariantKind<typeof RESET_CONNECTION, null>
      90              :     | VariantKind<typeof DELETE_CONNECTION, null>
      91              :     ;
      92              : 
      93            1 : export function reduceSalesforceConnectionState(state: ConnectionState, action: SalesforceConnectionStateAction): ConnectionState | null {
      94            1 :     const details = state.details.value as SalesforceConnectionStateDetails;
      95            1 :     const detailsType = state.details.type as SalesforceDetailsType;
      96            1 :     let next: ConnectionState | null = null;
      97            1 :     switch (action.type) {
      98            1 :         case DELETE_CONNECTION:
      99            1 :         case RESET_CONNECTION:
     100            1 :             details.channel?.close();
     101            1 :             next = {
     102            1 :                 ...state,
     103            1 :                 details: {
     104            1 :                     type: detailsType,
     105            1 :                     value: {
     106            1 :                         ...details,
     107            1 :                         proto: {
     108            1 :                             ...details.proto,
     109            1 :                             setupTimings: {},
     110            1 :                             setupParams: details.proto.setupParams,
     111            1 :                             setupError: undefined,
     112            1 :                             channelError: undefined,
     113            1 :                             healthCheckError: undefined,
     114            1 :                         },
     115            1 :                         channel: null,
     116            1 :                     }
     117            1 :                 },
     118            1 :             };
     119            1 :             break;
     120            1 :         case SETUP_STARTED: {
     121            1 :             const requestedAt = Date.now();
     122            1 :             const newDetails: SalesforceConnectionStateDetails = {
     123            1 :                 proto: {
     124            1 :                     ...details.proto,
     125            1 :                     setupTimings: {
     126            1 :                         ...details.proto.setupTimings,
     127            1 :                         authStartedAt: dateToTimestamp(new Date()),
     128            1 :                     },
     129            1 :                     setupParams: action.value,
     130            1 :                     setupError: undefined,
     131            1 :                     channelError: undefined,
     132            1 :                     healthCheckError: undefined,
     133            1 :                     oauthState: {
     134            1 :                         oauthParams: {
     135            1 :                             instanceUrl: action.value.instanceUrl,
     136            1 :                             appConsumerKey: action.value.appConsumerKey,
     137            1 :                             requestedAt,
     138            1 :                             expiresAt: requestedAt + (2 * 60 * 60 * 1000), // 2 hours
     139            1 :                         },
     140            1 :                         oauthPkce: details.proto.oauthState?.oauthPkce ?? ({ value: "", verifier: "" } as auth.OAuthPKCEChallenge),
     141            1 :                         coreAuthCode: details.proto.oauthState?.coreAuthCode ?? ({ token: "", createdAt: new Date().toISOString() } as auth.TemporaryToken),
     142            1 :                         coreAccessToken: details.proto.oauthState?.coreAccessToken ?? ({} as connection.SalesforceCoreAccessToken),
     143            1 :                         dataCloudAccessToken: details.proto.oauthState?.dataCloudAccessToken ?? ({} as connection.SalesforceDataCloudAccessToken),
     144            1 :                     }
     145            1 :                 },
     146            1 :                 channel: null,
     147            1 :             };
     148            1 :             next = {
     149            1 :                 ...state,
     150            1 :                 connectionStatus: ConnectionStatus.AUTH_STARTED,
     151            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     152            1 :                 metrics: state.metrics,
     153            1 :                 details: {
     154            1 :                     type: detailsType,
     155            1 :                     value: newDetails,
     156            1 :                 },
     157            1 :             };
     158            1 :             break
     159            1 :         }
     160            1 :         case SETUP_CANCELLED:
     161            1 :             next = {
     162            1 :                 ...state,
     163            1 :                 connectionStatus: ConnectionStatus.AUTH_CANCELLED,
     164            1 :                 connectionHealth: ConnectionHealth.CANCELLED,
     165              : 
     166            1 :                 details: {
     167            1 :                     type: detailsType,
     168            1 :                     value: {
     169            1 :                         ...details,
     170            1 :                         proto: {
     171            1 :                             ...details.proto,
     172            1 :                             setupTimings: {
     173            1 :                                 ...details.proto.setupTimings,
     174            1 :                                 authCancelledAt: dateToTimestamp(new Date()),
     175            1 :                             },
     176            1 :                             setupError: action.value
     177            1 :                         },
     178            1 :                         channel: null,
     179            1 :                     }
     180            1 :                 }
     181            1 :             };
     182            1 :             break;
     183            1 :         case SETUP_FAILED:
     184            1 :             next = {
     185            1 :                 ...state,
     186            1 :                 connectionStatus: ConnectionStatus.AUTH_FAILED,
     187            1 :                 connectionHealth: ConnectionHealth.FAILED,
     188            1 :                 details: {
     189            1 :                     type: detailsType,
     190            1 :                     value: {
     191            1 :                         ...details,
     192            1 :                         proto: {
     193            1 :                             ...details.proto,
     194            1 :                             setupTimings: {
     195            1 :                                 ...details.proto.setupTimings,
     196            1 :                                 authFailedAt: dateToTimestamp(new Date()),
     197            1 :                             },
     198            1 :                             setupError: action.value
     199            1 :                         },
     200            1 :                         channel: null,
     201            1 :                     }
     202            1 :                 }
     203            1 :             };
     204            1 :             break;
     205            1 :         case GENERATING_PKCE_CHALLENGE:
     206            1 :             next = {
     207            1 :                 ...state,
     208            1 :                 connectionStatus: ConnectionStatus.PKCE_GENERATION_STARTED,
     209            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     210            1 :                 details: {
     211            1 :                     type: detailsType,
     212            1 :                     value: {
     213            1 :                         ...details,
     214            1 :                         proto: {
     215            1 :                             ...details.proto,
     216            1 :                             setupTimings: {
     217            1 :                                 ...details.proto.setupTimings,
     218            1 :                                 pkceGenStartedAt: dateToTimestamp(new Date()),
     219            1 :                             },
     220            1 :                         },
     221            1 :                         channel: null,
     222            1 :                     }
     223            1 :                 }
     224            1 :             };
     225            1 :             break;
     226            1 :         case GENERATED_PKCE_CHALLENGE:
     227            1 :             next = {
     228            1 :                 ...state,
     229            1 :                 connectionStatus: ConnectionStatus.PKCE_GENERATED,
     230            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     231            1 :                 details: {
     232            1 :                     type: detailsType,
     233            1 :                     value: {
     234            1 :                         ...details,
     235            1 :                         proto: {
     236            1 :                             ...details.proto,
     237            1 :                             setupTimings: {
     238            1 :                                 ...details.proto.setupTimings,
     239            1 :                                 pkceGenFinishedAt: dateToTimestamp(new Date()),
     240            1 :                             },
     241            1 :                             oauthState: {
     242            1 :                                 oauthParams: details.proto.oauthState?.oauthParams ?? { instanceUrl: "", appConsumerKey: "", requestedAt: Date.now(), expiresAt: Date.now() },
     243            1 :                                 oauthPkce: action.value,
     244            1 :                                 coreAuthCode: details.proto.oauthState?.coreAuthCode ?? ({ token: "", createdAt: new Date().toISOString() } as auth.TemporaryToken),
     245            1 :                                 coreAccessToken: details.proto.oauthState?.coreAccessToken ?? ({} as connection.SalesforceCoreAccessToken),
     246            1 :                                 dataCloudAccessToken: details.proto.oauthState?.dataCloudAccessToken ?? ({} as connection.SalesforceDataCloudAccessToken),
     247            1 :                             }
     248            1 :                         },
     249            1 :                     }
     250            1 :                 }
     251            1 :             };
     252            1 :             break;
     253            1 :         case OAUTH_NATIVE_LINK_OPENED:
     254            1 :             next = {
     255            1 :                 ...state,
     256            1 :                 connectionStatus: ConnectionStatus.WAITING_FOR_OAUTH_CODE_VIA_LINK,
     257            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     258            1 :                 details: {
     259            1 :                     type: detailsType,
     260            1 :                     value: {
     261            1 :                         ...details,
     262            1 :                         proto: {
     263            1 :                             ...details.proto,
     264            1 :                             setupTimings: {
     265            1 :                                 ...details.proto.setupTimings,
     266            1 :                                 openedNativeAuthLinkAt: dateToTimestamp(new Date()),
     267            1 :                             },
     268            1 :                         },
     269            1 :                     }
     270            1 :                 }
     271            1 :             };
     272            1 :             break;
     273            1 :         case OAUTH_WEB_WINDOW_OPENED:
     274            1 :             next = {
     275            1 :                 ...state,
     276            1 :                 connectionStatus: ConnectionStatus.WAITING_FOR_OAUTH_CODE_VIA_WINDOW,
     277            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     278            1 :                 details: {
     279            1 :                     type: detailsType,
     280            1 :                     value: {
     281            1 :                         ...details,
     282            1 :                         proto: {
     283            1 :                             ...details.proto,
     284            1 :                             setupTimings: {
     285            1 :                                 ...details.proto.setupTimings,
     286            1 :                                 openedWebAuthWindowAt: dateToTimestamp(new Date()),
     287            1 :                             },
     288            1 :                         },
     289            1 :                     }
     290            1 :                 }
     291            1 :             };
     292            1 :             break;
     293            1 :         case OAUTH_WEB_WINDOW_CLOSED:
     294            1 :             next = {
     295            1 :                 ...state,
     296            1 :                 details: {
     297            1 :                     type: detailsType,
     298            1 :                     value: {
     299            1 :                         ...details,
     300            1 :                         proto: {
     301            1 :                             ...details.proto,
     302            1 :                             setupTimings: {
     303            1 :                                 ...details.proto.setupTimings,
     304            1 :                                 closedWebAuthWindowAt: dateToTimestamp(new Date()),
     305            1 :                             },
     306            1 :                         },
     307            1 :                     }
     308            1 :                 }
     309            1 :             };
     310            1 :             break;
     311            1 :         case RECEIVED_CORE_AUTH_CODE:
     312            1 :             next = {
     313            1 :                 ...state,
     314            1 :                 connectionStatus: ConnectionStatus.OAUTH_CODE_RECEIVED,
     315            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     316            1 :                 details: {
     317            1 :                     type: detailsType,
     318            1 :                     value: {
     319            1 :                         ...details,
     320            1 :                         proto: {
     321            1 :                             ...details.proto,
     322            1 :                             setupTimings: {
     323            1 :                                 ...details.proto.setupTimings,
     324            1 :                                 oauthCodeReceivedAt: dateToTimestamp(new Date()),
     325            1 :                             },
     326            1 :                             oauthState: {
     327            1 :                                 oauthParams: details.proto.oauthState?.oauthParams ?? { instanceUrl: "", appConsumerKey: "", requestedAt: Date.now(), expiresAt: Date.now() },
     328            1 :                                 oauthPkce: details.proto.oauthState?.oauthPkce ?? ({ value: "", verifier: "" } as auth.OAuthPKCEChallenge),
     329            1 :                                 coreAuthCode: action.value,
     330            1 :                                 coreAccessToken: details.proto.oauthState?.coreAccessToken ?? ({} as connection.SalesforceCoreAccessToken),
     331            1 :                                 dataCloudAccessToken: details.proto.oauthState?.dataCloudAccessToken ?? ({} as connection.SalesforceDataCloudAccessToken),
     332            1 :                             }
     333            1 :                         },
     334            1 :                     }
     335            1 :                 }
     336            1 :             };
     337            1 :             break;
     338            1 :         case REQUESTING_CORE_AUTH_TOKEN:
     339            1 :             next = {
     340            1 :                 ...state,
     341            1 :                 connectionStatus: ConnectionStatus.ACCESS_TOKEN_REQUESTED,
     342            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     343            1 :                 details: {
     344            1 :                     type: detailsType,
     345            1 :                     value: {
     346            1 :                         ...details,
     347            1 :                         proto: {
     348            1 :                             ...details.proto,
     349            1 :                             setupTimings: {
     350            1 :                                 ...details.proto.setupTimings,
     351            1 :                                 coreAccessTokenRequestedAt: dateToTimestamp(new Date()),
     352            1 :                             },
     353            1 :                         },
     354            1 :                     }
     355            1 :                 }
     356            1 :             };
     357            1 :             break;
     358            1 :         case RECEIVED_CORE_AUTH_TOKEN:
     359            1 :             next = {
     360            1 :                 ...state,
     361            1 :                 connectionStatus: ConnectionStatus.CORE_ACCESS_TOKEN_RECEIVED,
     362            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     363            1 :                 details: {
     364            1 :                     type: detailsType,
     365            1 :                     value: {
     366            1 :                         ...details,
     367            1 :                         proto: {
     368            1 :                             ...details.proto,
     369            1 :                             setupTimings: {
     370            1 :                                 ...details.proto.setupTimings,
     371            1 :                                 coreAccessTokenReceivedAt: dateToTimestamp(new Date()),
     372            1 :                             },
     373            1 :                             oauthState: {
     374            1 :                                 oauthParams: details.proto.oauthState?.oauthParams ?? { instanceUrl: "", appConsumerKey: "", requestedAt: Date.now(), expiresAt: Date.now() },
     375            1 :                                 oauthPkce: details.proto.oauthState?.oauthPkce ?? ({ value: "", verifier: "" } as auth.OAuthPKCEChallenge),
     376            1 :                                 coreAuthCode: details.proto.oauthState?.coreAuthCode ?? ({ token: "", createdAt: new Date().toISOString() } as auth.TemporaryToken),
     377            1 :                                 coreAccessToken: action.value,
     378            1 :                                 dataCloudAccessToken: details.proto.oauthState?.dataCloudAccessToken ?? ({} as connection.SalesforceDataCloudAccessToken),
     379            1 :                             }
     380            1 :                         },
     381            1 :                     }
     382            1 :                 }
     383            1 :             };
     384            1 :             break;
     385            1 :         case RECEIVED_CORE_USER_INFO: {
     386              :             // Persist the resolved account identity into setupParams.login so it is emitted as
     387              :             // the OAuth `login_hint` on subsequent connects and can be carried into shared
     388              :             // links/files. Resolving user info is best-effort (see salesforce_connection_setup):
     389              :             // if the connected app lacks the openid/profile scope we never reach this action.
     390            1 :             const resolvedLogin = action.value.preferredUsername ?? action.value.email ?? details.proto.setupParams?.login ?? "";
     391            1 :             next = {
     392            1 :                 ...state,
     393            1 :                 details: {
     394            1 :                     type: detailsType,
     395            1 :                     value: {
     396            1 :                         ...details,
     397            1 :                         proto: {
     398            1 :                             ...details.proto,
     399            1 :                             setupParams: details.proto.setupParams
     400            1 :                                 ? { ...details.proto.setupParams, login: resolvedLogin }
     401            0 :                                 : details.proto.setupParams,
     402            1 :                         },
     403            1 :                     }
     404            1 :                 }
     405            1 :             };
     406            1 :             break;
     407            1 :         }
     408            1 :         case REQUESTING_DATA_CLOUD_ACCESS_TOKEN:
     409            1 :             next = {
     410            1 :                 ...state,
     411            1 :                 connectionStatus: ConnectionStatus.DATA_CLOUD_TOKEN_REQUESTED,
     412            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     413            1 :                 details: {
     414            1 :                     type: detailsType,
     415            1 :                     value: {
     416            1 :                         ...details,
     417            1 :                         proto: {
     418            1 :                             ...details.proto,
     419            1 :                             setupTimings: {
     420            1 :                                 ...details.proto.setupTimings,
     421            1 :                                 dataCloudAccessTokenRequestedAt: dateToTimestamp(new Date()),
     422            1 :                             },
     423            1 :                         },
     424            1 :                     }
     425            1 :                 }
     426            1 :             };
     427            1 :             break;
     428            1 :         case RECEIVED_DATA_CLOUD_ACCESS_TOKEN:
     429            1 :             next = {
     430            1 :                 ...state,
     431            1 :                 connectionStatus: ConnectionStatus.DATA_CLOUD_TOKEN_RECEIVED,
     432            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     433            1 :                 details: {
     434            1 :                     type: detailsType,
     435            1 :                     value: {
     436            1 :                         ...details,
     437            1 :                         proto: {
     438            1 :                             ...details.proto,
     439            1 :                             setupTimings: {
     440            1 :                                 ...details.proto.setupTimings,
     441            1 :                                 dataCloudAccessTokenReceivedAt: dateToTimestamp(new Date()),
     442            1 :                             },
     443            1 :                             oauthState: {
     444            1 :                                 oauthParams: details.proto.oauthState?.oauthParams ?? { instanceUrl: "", appConsumerKey: "", requestedAt: Date.now(), expiresAt: Date.now() },
     445            1 :                                 oauthPkce: details.proto.oauthState?.oauthPkce ?? ({ value: "", verifier: "" } as auth.OAuthPKCEChallenge),
     446            1 :                                 coreAuthCode: details.proto.oauthState?.coreAuthCode ?? ({ token: "", createdAt: new Date().toISOString() } as auth.TemporaryToken),
     447            1 :                                 coreAccessToken: details.proto.oauthState?.coreAccessToken ?? ({} as connection.SalesforceCoreAccessToken),
     448            1 :                                 dataCloudAccessToken: action.value,
     449            1 :                             }
     450            1 :                         },
     451            1 :                     }
     452            1 :                 }
     453            1 :             };
     454            1 :             break;
     455            1 :         case SF_CHANNEL_SETUP_STARTED:
     456            1 :             next = {
     457            1 :                 ...state,
     458            1 :                 connectionStatus: ConnectionStatus.CHANNEL_SETUP_STARTED,
     459            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     460            1 :                 details: {
     461            1 :                     type: detailsType,
     462            1 :                     value: {
     463            1 :                         ...details,
     464            1 :                         proto: {
     465            1 :                             ...details.proto,
     466            1 :                             setupTimings: {
     467            1 :                                 ...details.proto.setupTimings,
     468            1 :                                 channelSetupStartedAt: dateToTimestamp(new Date()),
     469            1 :                             },
     470            1 :                         },
     471            1 :                         channel: null,
     472            1 :                     }
     473            1 :                 },
     474            1 :             };
     475            1 :             break;
     476            1 :         case SF_CHANNEL_SETUP_CANCELLED:
     477            1 :             next = {
     478            1 :                 ...state,
     479            1 :                 connectionStatus: ConnectionStatus.CHANNEL_SETUP_CANCELLED,
     480            1 :                 connectionHealth: ConnectionHealth.CANCELLED,
     481            1 :                 details: {
     482            1 :                     type: detailsType,
     483            1 :                     value: {
     484            1 :                         ...details,
     485            1 :                         proto: {
     486            1 :                             ...details.proto,
     487            1 :                             setupTimings: {
     488            1 :                                 ...details.proto.setupTimings,
     489            1 :                                 channelSetupCancelledAt: dateToTimestamp(new Date()),
     490            1 :                             },
     491            1 :                             channelError: action.value
     492            1 :                         },
     493            1 :                         channel: null
     494            1 :                     }
     495            1 :                 },
     496            1 :             };
     497            1 :             break;
     498            1 :         case SF_CHANNEL_SETUP_FAILED:
     499            1 :             next = {
     500            1 :                 ...state,
     501            1 :                 connectionStatus: ConnectionStatus.CHANNEL_SETUP_FAILED,
     502            1 :                 connectionHealth: ConnectionHealth.FAILED,
     503            1 :                 details: {
     504            1 :                     type: detailsType,
     505            1 :                     value: {
     506            1 :                         ...details,
     507            1 :                         proto: {
     508            1 :                             ...details.proto,
     509            1 :                             setupTimings: {
     510            1 :                                 ...details.proto.setupTimings,
     511            1 :                                 channelSetupFailedAt: dateToTimestamp(new Date()),
     512            1 :                             },
     513            1 :                             channelError: action.value
     514            1 :                         },
     515            1 :                         channel: null
     516            1 :                     }
     517            1 :                 },
     518            1 :             };
     519            1 :             break;
     520            1 :         case SF_CHANNEL_READY:
     521            1 :             next = {
     522            1 :                 ...state,
     523            1 :                 connectionStatus: ConnectionStatus.CHANNEL_READY,
     524            1 :                 connectionHealth: ConnectionHealth.CONNECTING,
     525            1 :                 details: {
     526            1 :                     type: detailsType,
     527            1 :                     value: {
     528            1 :                         ...details,
     529            1 :                         proto: {
     530            1 :                             ...details.proto,
     531            1 :                             setupTimings: {
     532            1 :                                 ...details.proto.setupTimings,
     533            1 :                                 channelReadyAt: dateToTimestamp(new Date()),
     534            1 :                             },
     535            1 :                         },
     536            1 :                         channel: action.value
     537            1 :                     }
     538            1 :                 },
     539            1 :             };
     540              :             break;
     541            1 :     }
     542            1 :     return next;
     543            1 : }
        

Generated by: LCOV version 2.0-1