Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@civic/gateway-client-core

Package Overview
Dependencies
Maintainers
13
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@civic/gateway-client-core - npm Package Compare versions

Comparing version 1.0.0-alpha.0 to 1.0.0-beta.1

.nyc_output/56da86fc-16b9-46bd-bddb-f45b332d75e5.json

2

.nyc_output/processinfo/index.json

@@ -1,1 +0,1 @@

{"processes":{"6e9a9620-0f6c-4af3-a38b-81c6eeb40d35":{"parent":null,"children":[]},"f11699bf-c5ec-4ece-b42d-8caee4d4ec4d":{"parent":null,"children":[]}},"files":{"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/partnerReview.ts":["6e9a9620-0f6c-4af3-a38b-81c6eeb40d35"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/defaults.ts":["6e9a9620-0f6c-4af3-a38b-81c6eeb40d35","f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/gatekeeperClient.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/url.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/index.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/local.logger.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/provider.logger.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/gatekeeperApi.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/gatekeeperNetworkService.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/index.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/gateway.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/eventInterface.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/flow.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/orchestrate.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/listeners.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/civicPass.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/civicSign.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/fetch.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/inputs.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/remoteSign.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/issuance.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/errors.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/expiry.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/chain.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/refresh.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/userInteraction.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/userInteraction.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/partnerReview.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/state.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/stateMapping.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/flow.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/gatewayStatus.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/common.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/error.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/initialisation.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/issuance.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/partnerReview.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/refresh.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/flowParameters.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/log.ts":["f11699bf-c5ec-4ece-b42d-8caee4d4ec4d"]},"externalIds":{}}
{"processes":{"56da86fc-16b9-46bd-bddb-f45b332d75e5":{"parent":null,"children":[]},"c12ee5a8-3dd8-49ef-a4d1-cb2ed5f3462a":{"parent":null,"children":[]}},"files":{"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/gatekeeperClient.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/url.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/index.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/local.logger.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/logger/provider.logger.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/gatekeeperApi.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/gatekeeperNetworkService.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/index.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/chain.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/errors.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/gateway.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/eventInterface.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/flow.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/orchestrate.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/listeners.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/civicPass.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/civicSign.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/fetch.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/inputs.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/remoteSign.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/issuance.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/defaults.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5","c12ee5a8-3dd8-49ef-a4d1-cb2ed5f3462a"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/expiry.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/refresh.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/userInteraction.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/userInteraction.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/partnerReview.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/common.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/state.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/stateMapping.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/flow.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/gatewayStatus.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/error.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/initialisation.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/issuance.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/partnerReview.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/refresh.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/flowParameters.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/utils/object.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/types/log.ts":["56da86fc-16b9-46bd-bddb-f45b332d75e5"],"/Users/kevincolgan/code/ociv-gatekeeper/packages/gateway-client-core/src/state/partnerReview.ts":["c12ee5a8-3dd8-49ef-a4d1-cb2ed5f3462a"]},"externalIds":{}}

@@ -7,2 +7,3 @@ import { ClientCoreInput } from './types/clientCore';

export { GatewayStatus } from './types/gateway';
export type { LogLevel } from './types/log';
export type { ErrorWithCode } from './types/errors';

@@ -9,0 +10,0 @@ export type { PendingPayload } from './types/gatekeeperApi';

@@ -33,2 +33,3 @@ import { ListenerManager } from './listeners';

getRemoteSignInstance(): RemoteSignWindowEventEmitter;
lookupTokenState(): Promise<void>;
initialise(): Promise<void>;

@@ -35,0 +36,0 @@ reset(): void;

@@ -11,4 +11,6 @@ import { GatewayStatus, InternalGatewayStatus } from '../types/gateway';

};
export declare const payerIsWalletOwner: (state: GatewayCoreState) => boolean;
export declare const tokenNoGatekeeperRecordError: (state: GatewayCoreState) => boolean;
export declare const statusFromGatewayTokenIfExists: (state: GatewayCoreState) => InternalGatewayStatus | undefined;
export declare const handleGatewayTokenExistsStatus: (state: GatewayCoreState) => InternalGatewayStatus;
export declare const statusIfGatekeeperRecordRejected: (state: GatewayCoreState) => InternalGatewayStatus | undefined;
import { InternalGatewayStatus } from '../types/gateway';
import { GatewayCoreState } from '../types/gatewayCore';
export declare const handleChainError: (state: GatewayCoreState) => InternalGatewayStatus;
export declare const handleGatekeeperError: (state: GatewayCoreState) => InternalGatewayStatus;

@@ -8,2 +8,4 @@ import { GatewayCoreState, GatewayInput } from '../types/gatewayCore';

export declare const calculateFromGatekeeperIssuanceRequested: (state: GatewayCoreState) => InternalGatewayStatus | undefined;
export declare const calculateIssuanceRequestedDataCollectionRestart: (state: GatewayCoreState) => InternalGatewayStatus | undefined;
export declare const computeIssuanceDataCollectionRestart: (state: GatewayCoreState) => InternalGatewayStatus;
export declare const computeIssuanceRequested: (state: GatewayCoreState) => InternalGatewayStatus;

@@ -10,0 +12,0 @@ export declare const computeIssuanceAwaitingOnChainToken: (state: GatewayCoreState) => InternalGatewayStatus;

@@ -9,3 +9,3 @@ import { Mutate, StoreApi } from 'zustand/vanilla';

]>;
type WritableDraft<T> = {
export type WritableDraft<T> = {
-readonly [K in keyof T]: Draft<T[K]>;

@@ -36,2 +36,1 @@ };

export declare const createGatewayCoreStore: (options: DevtoolsOptions) => WritableDraft<Store>;
export {};

@@ -21,3 +21,2 @@ export declare enum CivicPassMessageEventResult {

REFRESH = "refresh",
PROOF_OF_WALLET_OWNERSHIP = "proofOfWalletOwnership",
STATUS = "status",

@@ -24,0 +23,0 @@ ERROR = "error",

@@ -6,3 +6,2 @@ export declare enum GatewayStatus {

COLLECTING_USER_INFORMATION = "COLLECTING_USER_INFORMATION",
PROOF_OF_WALLET_OWNERSHIP = "PROOF_OF_WALLET_OWNERSHIP",
IN_REVIEW = "IN_REVIEW",

@@ -32,2 +31,3 @@ REJECTED = "REJECTED",

ISSUANCE_AWAITING_TRANSACTION_SEND = "ISSUANCE_AWAITING_TRANSACTION_SEND",
ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND = "ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND",
ISSUANCE_AWAITING_ON_CHAIN_TOKEN = "ISSUANCE_AWAITING_ON_CHAIN_TOKEN",

@@ -39,2 +39,3 @@ ISSUANCE_RESTART_DATA_COLLECTION = "ISSUANCE_RESTART_DATA_COLLECTION",

REFRESH_AWAITING_TRANSACTION_SEND = "REFRESH_AWAITING_TRANSACTION_SEND",
REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND = "REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND",
REFRESH_AWAITING_ON_CHAIN_TOKEN = "REFRESH_AWAITING_ON_CHAIN_TOKEN",

@@ -41,0 +42,0 @@ RESTART_REFRESH = "RESTART_REFRESH"

@@ -33,2 +33,4 @@ import { ChainConfirmationTimeout, ChainError } from '../utils/errors';

flowType?: FlowType;
payload?: string;
referrer?: string;
};

@@ -59,2 +61,3 @@ export type ClientCoreOutput = {

expectedOnChainToken?: ChainConfirmationTimeout | null;
expectedTokenGatekeeperRecord?: ChainError | null;
};

@@ -61,0 +64,0 @@ };

@@ -25,2 +25,4 @@ import { Chain } from './chain';

disableInitialGatekeeperLookup?: boolean;
flowIdPrefix?: string;
referrer?: string;
};

@@ -27,0 +29,0 @@ export type DynamicGatewayClientParameters = {

@@ -9,2 +9,3 @@ import { LoggingInterface } from '../logger/provider.logger';

CHAIN_CONFIRMATION_TIMEOUT_ERROR: string;
EXPECTED_GATEKEEPER_RECORD: string;
};

@@ -11,0 +12,0 @@ export declare class ChainError extends Error {

import { FlowStatus, FlowType } from '../types/flow';
import { InternalGatewayStatus } from '../types/gateway';
import { GatewayCoreState } from '../types/gatewayCore';
export declare const DEFAULT_FLOW_ID_PREFIX = "GWC";
export declare const flowTypeFromState: (state: GatewayCoreState, computedInternalStatus: InternalGatewayStatus) => FlowType;

@@ -5,0 +6,0 @@ export declare const getFlowId: (state: GatewayCoreState, computedInternalStatus: InternalGatewayStatus) => string;

@@ -7,6 +7,6 @@ module.exports = {

all: true,
lines: 90,
functions: 89,
statements: 90,
branches: 75,
lines: 95,
functions: 91,
statements: 94,
branches: 85,
'skip-full': true,

@@ -13,0 +13,0 @@ include: ['src/**'],

{
"name": "@civic/gateway-client-core",
"version": "1.0.0-alpha.0",
"version": "1.0.0-beta.1",
"description": "Sample project for creating typescript library with support of iife and types.",

@@ -57,3 +57,3 @@ "main": "dist/civic-gateway-client-core.min.js",

"license": "MIT",
"gitHead": "27a99033abd4b3fbc67e89595638c828b5b8cef1"
"gitHead": "cc3dc99e5a7518de46b0f17c81ea6caff0028f4c"
}

@@ -62,3 +62,3 @@ import { default as fetchBuilder } from 'fetch-retry';

logError('retryOn error run out of retries', { error, attempt, retries, response, body });
return false;
throw error as Error;
}

@@ -65,0 +65,0 @@ logDebug('retrying on 5xx error', { error, attempt, retries, response, body });

@@ -12,2 +12,3 @@ import { v4 as uuid } from 'uuid';

export type { LogLevel } from './types/log';
export type { ErrorWithCode } from './types/errors';

@@ -14,0 +15,0 @@ export type { PendingPayload } from './types/gatekeeperApi';

@@ -31,2 +31,4 @@ /**

import { PartnerReview } from './partnerReview';
import { tokenNoGatekeeperRecordError } from './state/common';
import { ChainError, ErrorCode } from './utils/errors';

@@ -134,7 +136,3 @@ export class Orchestrator {

// TODO add error handling like in Ty's PR: https://github.com/civicteam/ociv-gatekeeper/pull/2977/files
async initialise() {
this.abortController = new AbortController();
this.gatewayCoreStore.getState().functions.reset();
async lookupTokenState() {
const retrieveGKRecord = async () => {

@@ -146,9 +144,20 @@ // call gatekeeperClient.getRecord to get gatekeeperRecord (if GKN requires it)

});
return this.gatekeeperClient.getGatekeeperRecordWithPayload().then((response) => {
if (this.abortController.signal.aborted) return;
this.gatewayCoreStore.setState((state) => {
state.inputs.gatekeeperRecord.status = InputStatus.COMPLETE;
state.inputs.gatekeeperRecord.received = response;
return this.gatekeeperClient
.getGatekeeperRecordWithPayload()
.then((response) => {
this.log.debug('getGatekeeperRecordWithPayload record', response);
if (this.abortController.signal.aborted) return;
this.gatewayCoreStore.setState((state) => {
state.inputs.gatekeeperRecord.status = InputStatus.COMPLETE;
state.inputs.gatekeeperRecord.received = response;
});
})
.catch((error) => {
this.log.error('Error retrieving gatekeeper record', error);
if (this.abortController.signal.aborted) return;
this.gatewayCoreStore.setState((state) => {
state.inputs.gatekeeperRecord.status = InputStatus.ERROR;
state.inputs.gatekeeperRecord.error = error;
});
});
});
};

@@ -162,11 +171,21 @@

});
return this.chainImplementation.findGatewayToken().then((response) => {
if (this.abortController.signal.aborted) return;
this.gatewayCoreStore.setState((state) => {
state.inputs.gatewayToken.status = InputStatus.COMPLETE;
if (response) {
state.inputs.gatewayToken.received = response;
}
return this.chainImplementation
.findGatewayToken()
.then((response) => {
if (this.abortController.signal.aborted) return;
this.gatewayCoreStore.setState((state) => {
state.inputs.gatewayToken.status = InputStatus.COMPLETE;
if (response) {
state.inputs.gatewayToken.received = response;
}
});
})
.catch((error) => {
if (this.abortController.signal.aborted) return;
this.log.error('Error retrieving gateway token', error);
this.gatewayCoreStore.setState((state) => {
state.inputs.gatewayToken.status = InputStatus.ERROR;
state.inputs.gatewayToken.error = error;
});
});
});
};

@@ -184,2 +203,10 @@

// TODO add error handling like in Ty's PR: https://github.com/civicteam/ociv-gatekeeper/pull/2977/files
async initialise() {
this.abortController = new AbortController();
this.gatewayCoreStore.getState().functions.reset();
this.lookupTokenState();
}
reset() {

@@ -190,2 +217,17 @@ this.initialise();

onInternalStatusChange(status: InternalGatewayStatus | null, previousStatus?: InternalGatewayStatus | null) {
if (status === GatewayStatus.ERROR) {
const fullState = this.gatewayCoreStore.getState();
if (tokenNoGatekeeperRecordError(fullState)) {
this.gatewayCoreStore.setState((state) => {
if (!state.internal.errors) {
state.internal.errors = {};
}
state.internal.errors.expectedTokenGatekeeperRecord = new ChainError(
'Token has no gatekeeper record',
ErrorCode.EXPECTED_GATEKEEPER_RECORD
);
});
}
return;
}
if (status === GatewayStatus.ACTIVE) {

@@ -204,3 +246,8 @@ // if the token has just turned active, finish the appropriate flow

}
if (status === ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND) {
if (
[
ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
].includes(status as ExtendedGatewayStatus)
) {
return this.issuance.sendTransaction();

@@ -207,0 +254,0 @@ }

@@ -19,2 +19,11 @@ import { isTokenRefreshRequired } from '../utils/expiry';

export const payerIsWalletOwner = (state: GatewayCoreState): boolean =>
!!(state.inputs.parameters?.payer === state.inputs.parameters?.wallet?.address);
export const tokenNoGatekeeperRecordError = (state: GatewayCoreState): boolean =>
!!(
state.inputs.gatewayToken?.received &&
state.inputs.gatekeeperRecord?.received?.state === GatekeeperAPIStatus.NOT_REQUESTED
);
/**

@@ -32,2 +41,5 @@ * if a gateway token is present in state, then derive the status from the token fields:

const gatewayToken = state.inputs.gatewayToken.received;
if (tokenNoGatekeeperRecordError(state)) {
return GatewayStatus.ERROR;
}
if (gatewayToken) {

@@ -34,0 +46,0 @@ const tokenRefreshRequired = isTokenRefreshRequired({

@@ -5,5 +5,6 @@ import { DEFAULT_MAX_CLIENT_SENDS_RETRIES } from '../utils/defaults';

import { GatewayCoreState } from '../types/gatewayCore';
import { payerIsWalletOwner } from './common';
export const handleChainError = (state: GatewayCoreState): InternalGatewayStatus => {
const isRefreshFlow = !!state.inputs.gatewayToken.received;
const isRefreshFlow = !!state.inputs.gatewayToken?.received;
if (

@@ -21,5 +22,11 @@ state.inputs.civicPass.received?.event === CivicPassMessageEventResult.FAILURE &&

) {
return isRefreshFlow
? ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND
: ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND;
if (isRefreshFlow) {
return payerIsWalletOwner(state)
? ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND
: ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND;
}
return payerIsWalletOwner(state)
? ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND
: ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND;
}

@@ -31,1 +38,12 @@ // handle a cancelled signMessage request

};
export const handleGatekeeperError = (state: GatewayCoreState): InternalGatewayStatus => {
const isRefreshFlow = !!state.inputs.gatewayToken.received;
if (
state.inputs.civicPass.received?.event === CivicPassMessageEventResult.FAILURE &&
state.inputs.civicPass.received?.action === CivicPassMessageAction.ERROR
) {
return isRefreshFlow ? ExtendedGatewayStatus.RESTART_REFRESH : ExtendedGatewayStatus.RESTART;
}
return state.internal?.status as InternalGatewayStatus;
};

@@ -6,2 +6,4 @@ import { FlowParameters, GatewayCoreState } from '../types/gatewayCore';

import { ChainError } from '../utils/errors';
import { isEmptyObject } from '../utils/object';
import { payerIsWalletOwner } from './common';

@@ -22,10 +24,16 @@ export const computeFlowParameters = (

}
// errors can be on civicSign or gatekeeperRecord
const errorCode =
state.internal.errors?.expectedTokenGatekeeperRecord?.errorCode ||
(state.internal.chainTransaction?.error as ChainError)?.errorCode ||
(state.inputs.gatekeeperRecord?.received?.errorCode as string | undefined) ||
(state.inputs.gatekeeperRecord?.received?.payload?.errorCode as string | undefined) ||
(state.inputs.civicSign.error as ChainError)?.errorCode;
(state.inputs.civicSign?.error as ChainError)?.errorCode;
const action = gatewayStatusToCivicPassAction[computedInternalStatus];
const flowId = getFlowId(state, computedInternalStatus);
const payload = isEmptyObject(state.inputs.gatekeeperRecord?.received?.payload)
? undefined
: JSON.stringify(state.inputs.gatekeeperRecord?.received?.payload);
const ownerSigns = !state.inputs.parameters.gatekeeperSendsTransaction && payerIsWalletOwner(state);
return {

@@ -35,4 +43,7 @@ // computed

flowId,
ownerSigns,
errorCode,
flowType: flowTypeFromState(state, computedInternalStatus),
...(payload ? { payload } : {}),
// from parameters

@@ -46,6 +57,5 @@ // TODO consider not returning these and just adding them in the gateway-client-react

did: state.inputs.parameters.chainImplementation.did,
ownerSigns: !state.inputs.parameters.gatekeeperSendsTransaction, // TODO add appropriate logic here
gatekeeperSendsTransaction: state.inputs.parameters.gatekeeperSendsTransaction,
partnerAppId: state.inputs.parameters.partnerAppId,
referrer: state.inputs.parameters.referrer,
instanceId: state.internal.instanceId,

@@ -55,4 +65,3 @@

signedTx: state.internal?.chainTransaction?.sentTxId,
errorCode,
};
};

@@ -6,6 +6,7 @@ import { prefixLogger } from '../logger';

import { handleGatewayTokenExistsStatus } from './common';
import { handleChainError } from './error';
import { handleChainError, handleGatekeeperError } from './error';
import { checkForInProgress, computeInitialState } from './initialisation';
import {
computeIssuanceAwaitingOnChainToken,
computeIssuanceDataCollectionRestart,
computeIssuanceInReview,

@@ -32,11 +33,2 @@ computeIssuanceRequested,

/**
* [ValidationStatus.COLLECTING]: GatewayStatus.COLLECTING_USER_INFORMATION,
[ValidationStatus.PROCESSING]: GatewayStatus.VALIDATING_USER_INFORMATION,
[ValidationStatus.IN_REVIEW]: GatewayStatus.VALIDATING_USER_INFORMATION,
[ValidationStatus.FAILED]: GatewayStatus.USER_INFORMATION_REJECTED,
[ValidationStatus.NOT_FOUND]: GatewayStatus.NOT_REQUESTED,
[ValidationStatus.COMPLETED]: GatewayStatus.USER_INFORMATION_VALIDATED,
*/
const validationProcessStatuses = [

@@ -92,7 +84,2 @@ GatewayStatus.COLLECTING_USER_INFORMATION,

},
// This is legacy and can eventually be removed
[GatewayStatus.PROOF_OF_WALLET_OWNERSHIP]: {
nextState: [],
compute: undefined,
},
[ExtendedGatewayStatus.ISSUANCE_CLIENT_PAYER_REQUESTED]: {

@@ -104,2 +91,3 @@ nextState: [

ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN, // civic-sends case

@@ -115,2 +103,3 @@ ExtendedGatewayStatus.TOKEN_IN_PARTNER_REVIEW,

ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN, // civic-sends case

@@ -134,2 +123,11 @@ ExtendedGatewayStatus.TOKEN_IN_PARTNER_REVIEW,

},
[ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND]: {
nextState: [
...gatewayTokenStatuses,
ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN,
ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION,
ExtendedGatewayStatus.CHAIN_TRANSACTION_ERROR,
],
compute: computeIssuanceInReview,
},
[ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN]: {

@@ -146,3 +144,3 @@ nextState: [...gatewayTokenStatuses, ExtendedGatewayStatus.CHAIN_TIMEOUT_ERROR],

],
compute: computeIssuanceRequested,
compute: computeIssuanceDataCollectionRestart,
},

@@ -162,4 +160,4 @@ [GatewayStatus.REVOKED]: {

[GatewayStatus.ERROR]: {
nextState: [],
compute: () => GatewayStatus.ERROR, // final state
nextState: [...gatewayTokenStatuses, ExtendedGatewayStatus.RESTART, ExtendedGatewayStatus.RESTART_REFRESH],
compute: handleGatekeeperError, // final state
},

@@ -191,2 +189,3 @@ [GatewayStatus.LOCATION_NOT_SUPPORTED]: {

ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN, // civic-sends case

@@ -196,2 +195,12 @@ ],

},
[ExtendedGatewayStatus.TOKEN_REFRESH_IN_REVIEW]: {
nextState: [
...gatewayTokenStatuses,
...errorStatuses,
ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN, // civic-sends case
],
compute: computeRefreshInReview,
},
[ExtendedGatewayStatus.REFRESH_CLIENT_PAYER_REQUESTED]: {

@@ -202,2 +211,3 @@ nextState: [

ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN,

@@ -216,26 +226,24 @@ ],

},
[ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND]: {
nextState: [
...gatewayTokenStatuses,
ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN,
ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION,
ExtendedGatewayStatus.CHAIN_TRANSACTION_ERROR,
],
compute: computeRefreshInReview,
},
[ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN]: {
nextState: [...gatewayTokenStatuses, ExtendedGatewayStatus.CHAIN_TIMEOUT_ERROR],
nextState: [...gatewayTokenStatuses, ...errorStatuses, ExtendedGatewayStatus.CHAIN_TIMEOUT_ERROR],
compute: computeRefreshAwaitingOnChainToken,
},
[GatewayStatus.VALIDATING_USER_INFORMATION]: {
nextState: [],
compute: undefined,
},
[GatewayStatus.USER_INFORMATION_REJECTED]: {
nextState: [],
compute: undefined,
},
[ExtendedGatewayStatus.AWAITING_OWNER_TRANSACTION]: {
nextState: [],
compute: undefined,
},
[ExtendedGatewayStatus.CHAIN_TIMEOUT_ERROR]: {
nextState: [...gatewayTokenStatuses, GatewayStatus.USER_INFORMATION_VALIDATED, ExtendedGatewayStatus.RESTART],
nextState: [
...gatewayTokenStatuses,
GatewayStatus.USER_INFORMATION_VALIDATED,
ExtendedGatewayStatus.RESTART,
ExtendedGatewayStatus.RESTART_REFRESH,
],
compute: handleChainError,
},
[ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION]: {
nextState: [],
compute: undefined,
},
[ExtendedGatewayStatus.CHAIN_TRANSACTION_ERROR]: {

@@ -245,3 +253,5 @@ nextState: [

ExtendedGatewayStatus.RESTART,
ExtendedGatewayStatus.RESTART_REFRESH,
ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND,
ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND,
ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN,

@@ -255,18 +265,32 @@ ],

},
[ExtendedGatewayStatus.TOKEN_REFRESH_IN_REVIEW]: {
nextState: [],
compute: undefined,
},
[ExtendedGatewayStatus.RESTART]: {
nextState: [...gatewayTokenStatuses, GatewayStatus.UNKNOWN],
compute: undefined,
compute: () => ExtendedGatewayStatus.RESTART,
},
[ExtendedGatewayStatus.RESTART_REFRESH]: {
nextState: [...gatewayTokenStatuses, GatewayStatus.UNKNOWN],
compute: undefined,
compute: () => ExtendedGatewayStatus.RESTART_REFRESH,
},
[ExtendedGatewayStatus.CHAIN_SIGN_MESSAGE_ERROR]: {
nextState: [],
nextState: [ExtendedGatewayStatus.RESTART, ExtendedGatewayStatus.RESTART_REFRESH],
compute: handleChainError,
},
// the states below are not currently being used by the events emmiter
// but they are included here in case they are needed in the future
[GatewayStatus.VALIDATING_USER_INFORMATION]: {
nextState: [],
compute: () => GatewayStatus.VALIDATING_USER_INFORMATION,
},
[GatewayStatus.USER_INFORMATION_REJECTED]: {
nextState: [],
compute: () => GatewayStatus.USER_INFORMATION_REJECTED,
},
[ExtendedGatewayStatus.AWAITING_OWNER_TRANSACTION]: {
nextState: [],
compute: () => ExtendedGatewayStatus.AWAITING_OWNER_TRANSACTION,
},
[ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION]: {
nextState: [],
compute: () => ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION,
},
};

@@ -273,0 +297,0 @@

@@ -8,9 +8,17 @@ import { InputStatus } from '../types/fetch';

export const computeChecking = (state: GatewayCoreState): InternalGatewayStatus | undefined => {
if (
!state.inputs.civicPass.status &&
(state.inputs.gatekeeperRecord.status === InputStatus.IN_PROGRESS ||
state.inputs.gatewayToken.status === InputStatus.IN_PROGRESS)
) {
return GatewayStatus.CHECKING;
if (!state.inputs.civicPass.status) {
if (
state.inputs.gatekeeperRecord.status === InputStatus.ERROR ||
state.inputs.gatewayToken.status === InputStatus.ERROR
) {
return GatewayStatus.ERROR;
}
if (
state.inputs.gatekeeperRecord.status === InputStatus.IN_PROGRESS ||
state.inputs.gatewayToken.status === InputStatus.IN_PROGRESS
) {
return GatewayStatus.CHECKING;
}
}
return undefined;

@@ -17,0 +25,0 @@ };

@@ -8,2 +8,3 @@ import { GatewayCoreState, GatewayInput } from '../types/gatewayCore';

validationProcessToGatewayStatus,
payerIsWalletOwner,
} from './common';

@@ -55,3 +56,6 @@ import { InputStatus } from '../types/fetch';

if (gatekeeperRecord.received?.transaction) {
return ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND;
if (payerIsWalletOwner(state)) {
return ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND;
}
return ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND;
}

@@ -67,9 +71,11 @@ return undefined;

): InternalGatewayStatus | undefined => {
const civicPassEvent = state.inputs.civicPass?.received;
const gatekeeperRecord = state.inputs.gatekeeperRecord;
// post-gatekeeper-issuance request
if (
gatekeeperRecord?.received?.state === GatekeeperAPIStatus.REQUESTED ||
gatekeeperRecord?.status === InputStatus.IN_PROGRESS
civicPassEvent && // we need a civic pass event to know data collection is complete
(gatekeeperRecord?.received?.state === GatekeeperAPIStatus.REQUESTED ||
gatekeeperRecord?.status === InputStatus.IN_PROGRESS)
) {
return state.inputs.parameters?.payer
return state.inputs.parameters?.payer && payerIsWalletOwner(state)
? ExtendedGatewayStatus.ISSUANCE_CLIENT_PAYER_REQUESTED

@@ -80,2 +86,24 @@ : GatewayStatus.IN_REVIEW;

export const calculateIssuanceRequestedDataCollectionRestart = (
state: GatewayCoreState
): InternalGatewayStatus | undefined => {
const civicPassEvent = state.inputs.civicPass?.received;
// handle the case where the user has an expired validation process
// TODO check the action when the iframe is updated to send the correct action
if (civicPassEvent?.event === CivicPassMessageEventResult.FAILURE) {
return ExtendedGatewayStatus.RESTART;
}
if (
civicPassEvent?.action === CivicPassMessageAction.ISSUANCE &&
civicPassEvent?.event === CivicPassMessageEventResult.SUCCESS
) {
return GatewayStatus.USER_INFORMATION_VALIDATED;
}
};
export const computeIssuanceDataCollectionRestart = (state: GatewayCoreState): InternalGatewayStatus =>
statusFromGatewayTokenIfExists(state) ||
calculateIssuanceRequestedDataCollectionRestart(state) ||
(state.internal?.status as InternalGatewayStatus);
export const computeIssuanceRequested = (state: GatewayCoreState): InternalGatewayStatus =>

@@ -82,0 +110,0 @@ statusFromGatewayTokenIfExists(state) ||

import { GatewayCoreState } from '../types/gatewayCore';
import { ExtendedGatewayStatus, GatewayStatus, InternalGatewayStatus } from '../types/gateway';
import { statusIfGatekeeperRecordRejected, statusFromGatewayTokenIfExists } from './common';
import { statusIfGatekeeperRecordRejected, statusFromGatewayTokenIfExists, payerIsWalletOwner } from './common';
import { InputStatus } from '../types/fetch';

@@ -15,10 +15,13 @@ import { CivicPassMessageAction, CivicPassMessageEventResult } from '../types/civicPass';

// otherwise restart the flow
if (state.internal.chainTransaction?.sentTxId) {
if (state.internal?.chainTransaction?.sentTxId) {
return ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN;
}
if (state.internal.chainTransaction?.error) {
if (state.internal?.chainTransaction?.error) {
return ExtendedGatewayStatus.CHAIN_TRANSACTION_ERROR;
}
if (gatekeeperRecord.received?.transaction) {
return ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND;
if (payerIsWalletOwner(state)) {
return ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND;
}
return ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND;
}

@@ -38,3 +41,3 @@ } else {

) {
return state.inputs.parameters?.payer
return state.inputs.parameters?.payer && payerIsWalletOwner(state)
? ExtendedGatewayStatus.REFRESH_CLIENT_PAYER_REQUESTED

@@ -76,3 +79,6 @@ : ExtendedGatewayStatus.REFRESH_IN_REVIEW;

export const computeRefreshStatus = (state: GatewayCoreState): InternalGatewayStatus =>
tokenNotRefreshRequired(state) || calculateRefreshStatus(state) || (state.internal?.status as InternalGatewayStatus);
tokenNotRefreshRequired(state) ||
statusIfGatekeeperRecordRejected(state) ||
calculateRefreshStatus(state) ||
(state.internal?.status as InternalGatewayStatus);

@@ -90,3 +96,4 @@ export const calculateFromRefreshAwaitingOnChain = (state: GatewayCoreState): InternalGatewayStatus | undefined => {

tokenNotRefreshRequired(state) ||
statusIfGatekeeperRecordRejected(state) ||
calculateFromRefreshAwaitingOnChain(state) ||
(state.internal?.status as InternalGatewayStatus);

@@ -56,3 +56,3 @@ /**

type WritableDraft<T> = {
export type WritableDraft<T> = {
-readonly [K in keyof T]: Draft<T[K]>;

@@ -59,0 +59,0 @@ };

@@ -5,3 +5,2 @@ import { CivicPassMessageAction } from '../types/civicPass';

export const gatewayStatusToCivicPassAction: Record<InternalGatewayStatus, CivicPassMessageAction> = {
[GatewayStatus.PROOF_OF_WALLET_OWNERSHIP]: CivicPassMessageAction.PROOF_OF_WALLET_OWNERSHIP,
[GatewayStatus.IN_REVIEW]: CivicPassMessageAction.TOKEN_IN_REVIEW,

@@ -25,2 +24,3 @@ [GatewayStatus.ERROR]: CivicPassMessageAction.ERROR,

[ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND]: CivicPassMessageAction.SIGN_TRANSACTION,
[ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND]: CivicPassMessageAction.TOKEN_IN_REVIEW,
[ExtendedGatewayStatus.ISSUANCE_CLIENT_PAYER_REQUESTED]: CivicPassMessageAction.SIGN_TRANSACTION,

@@ -42,2 +42,3 @@ [ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN]: CivicPassMessageAction.AWAITING_TRANSACTION_CONFIRMATION,

[ExtendedGatewayStatus.RESTART_REFRESH]: CivicPassMessageAction.REFRESH,
[ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND]: CivicPassMessageAction.TOKEN_REFRESH_IN_REVIEW,
};

@@ -85,2 +86,6 @@

return GatewayStatus.IN_REVIEW;
case ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND:
return GatewayStatus.IN_REVIEW;
case ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND:
return GatewayStatus.IN_REVIEW;
default:

@@ -87,0 +92,0 @@ // otherwise return GatewayStatus

@@ -22,3 +22,2 @@ export enum CivicPassMessageEventResult {

REFRESH = 'refresh',
PROOF_OF_WALLET_OWNERSHIP = 'proofOfWalletOwnership',
STATUS = 'status',

@@ -25,0 +24,0 @@ ERROR = 'error',

@@ -6,3 +6,2 @@ export enum GatewayStatus {

COLLECTING_USER_INFORMATION = 'COLLECTING_USER_INFORMATION', // the wallet owner is undergoing KYC
PROOF_OF_WALLET_OWNERSHIP = 'PROOF_OF_WALLET_OWNERSHIP', // the user needs to confirm wallet ownership,
IN_REVIEW = 'IN_REVIEW', // the token has been requested and civic gatekeeper is reviewing the request

@@ -34,2 +33,3 @@ REJECTED = 'REJECTED', // the token issuance request was rejected

ISSUANCE_AWAITING_TRANSACTION_SEND = 'ISSUANCE_AWAITING_TRANSACTION_SEND', // during issuance flow
ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND = 'ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND', // during issuance flow
ISSUANCE_AWAITING_ON_CHAIN_TOKEN = 'ISSUANCE_AWAITING_ON_CHAIN_TOKEN', // during issuance flow

@@ -42,2 +42,3 @@ ISSUANCE_RESTART_DATA_COLLECTION = 'ISSUANCE_RESTART_DATA_COLLECTION', // the user already requested a token but it didn't complete successfully

REFRESH_AWAITING_TRANSACTION_SEND = 'REFRESH_AWAITING_TRANSACTION_SEND',
REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND = 'REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND',
REFRESH_AWAITING_ON_CHAIN_TOKEN = 'REFRESH_AWAITING_ON_CHAIN_TOKEN',

@@ -44,0 +45,0 @@ RESTART_REFRESH = 'RESTART_REFRESH', // the user needs to restart the flow

@@ -36,2 +36,4 @@ import { ChainConfirmationTimeout, ChainError } from '../utils/errors';

flowType?: FlowType;
payload?: string;
referrer?: string;
};

@@ -65,2 +67,3 @@

expectedOnChainToken?: ChainConfirmationTimeout | null;
expectedTokenGatekeeperRecord?: ChainError | null;
};

@@ -67,0 +70,0 @@ };

@@ -28,2 +28,4 @@ import { Chain } from './chain';

disableInitialGatekeeperLookup?: boolean; // when set to true, the client will not call the GK-API on load
flowIdPrefix?: string; // a prefix to add to the flowId
referrer?: string; // the client referrer
};

@@ -30,0 +32,0 @@

@@ -11,2 +11,3 @@ import logger from '../logger';

CHAIN_CONFIRMATION_TIMEOUT_ERROR: '0x6', // the tx has been sent but hasn't confirmed on-chain within a timeout
EXPECTED_GATEKEEPER_RECORD: '0x7', // we have a token on chain but no correspondoing record in the gatekeeper
};

@@ -13,0 +14,0 @@

@@ -8,4 +8,3 @@ import { FlowStatus, FlowType } from '../types/flow';

const RC_FLOW_ID_PREFIX = 'GWRC'; // TODO consider making this an input
export const DEFAULT_FLOW_ID_PREFIX = 'GWC';
/**

@@ -27,9 +26,13 @@ * This derives the current flow type from the existing state and the next, computed state:

export const flowTypeFromState = (state: GatewayCoreState, computedInternalStatus: InternalGatewayStatus): FlowType => {
if (state.inputs.gatewayToken.received) {
if (state.inputs.gatewayToken?.received) {
const tokenRefreshRequired = isTokenRefreshRequired({
gatewayToken: state.inputs.gatewayToken.received,
gatewayToken: state.inputs.gatewayToken?.received,
tokenExpirationMarginSeconds: 0,
forceRequireRefresh: state.inputs.dynamicParameters?.forceRequireRefresh,
});
if (tokenRefreshRequired || state.internal.status?.includes('refresh')) {
if (
tokenRefreshRequired ||
state.internal.status?.toLowerCase().includes('refresh') ||
computedInternalStatus.toLowerCase().includes('refresh')
) {
return FlowType.REFRESH;

@@ -39,3 +42,3 @@ }

// handle the case where we find an ACTIVE token following the issuance flow
if (state.output?.flowParameters?.flowId.includes(FlowType.REFRESH)) {
if (state.output?.flowParameters?.flowId.toLowerCase().includes(FlowType.REFRESH.toLowerCase())) {
return FlowType.REFRESH;

@@ -45,3 +48,3 @@ }

// handle the case where we find an ACTIVE token following the issuance flow
if (state.output?.flowParameters?.flowId.includes(FlowType.ISSUANCE)) {
if (state.output?.flowParameters?.flowId.toLowerCase().includes(FlowType.ISSUANCE.toLowerCase())) {
return FlowType.ISSUANCE;

@@ -72,3 +75,3 @@ }

return !existingFlowId || existingFlowId === '' || !existingFlowId.includes(prefix)
? `${RC_FLOW_ID_PREFIX}_${prefix}${uuid()}`
? `${state.inputs.parameters?.flowIdPrefix || DEFAULT_FLOW_ID_PREFIX}_${prefix}${uuid()}`
: existingFlowId;

@@ -75,0 +78,0 @@ };

@@ -10,2 +10,3 @@ import { UserInteractionStatus } from '../types/userInteraction';

CivicPassMessageAction.TOKEN_REVOKED,
CivicPassMessageAction.TOKEN_FROZEN,
CivicPassMessageAction.TOKEN_REJECTED,

@@ -12,0 +13,0 @@ CivicPassMessageAction.FAILED_IP_CHECK,

import sinon from 'sinon';
import chai from 'chai';
import { GatekeeperClient } from '../src/gatekeeperClient';
import { GatekeeperClientConfig } from '../src/types/gatekeeperApi';
import { GatekeeperClient, isGkApiStatusFailure, isGkApiStatusRequestedRetriesExhausted } from '../src/gatekeeperClient';
import { GatekeeperAPIStatus, GatekeeperClientConfig } from '../src/types/gatekeeperApi';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
const { expect } = chai;
const sandbox = sinon.createSandbox();
describe('GatekeeperClient', function () {
let fetchStub: sinon.SinonStub<any[], any>;
let client: GatekeeperClient;
let abortController;
let abortController: AbortController;
afterEach(sandbox.restore);
beforeEach(() => {

@@ -62,3 +66,38 @@ // Setup the AbortController

describe('isGkApiStatusRequestedRetriesExhausted', () => {
it('should return true if status is 429', () => {
expect(isGkApiStatusRequestedRetriesExhausted(GatekeeperAPIStatus.REQUESTED_RETRIES_EXHAUSTED)).to.be.true;
});
it('should return false if status is not 429', () => {
expect(isGkApiStatusRequestedRetriesExhausted(200)).to.be.false;
});
});
describe('isGkApiStatusFailure', () => {
it('should return false if GK API status is REQUESTED', () => {
expect(isGkApiStatusFailure(GatekeeperAPIStatus.REQUESTED)).to.be.false;
});
it('should return false if GK API status is RETRIES_EXHAUSTED', () => {
expect(isGkApiStatusFailure(GatekeeperAPIStatus.REQUESTED_RETRIES_EXHAUSTED)).to.be.false;
});
it('should return false if code is below 400', () => {
expect(isGkApiStatusFailure(300)).to.be.false;
});
it('should return true if it is not REQUESTED, not RETRIES_EXHAUSTED and code is above 400', () => {
expect(isGkApiStatusFailure(GatekeeperAPIStatus.REJECTED)).to.be.true;
});
});
describe('abort', () => {
it('it should call abort on the AbortController', () => {
client.abort();
expect(abortController.signal.aborted).to.be.true;
});
});
// TODO: Add more tests to cover different scenarios like retries, error responses, etc.
});

@@ -110,3 +110,3 @@ import { step } from 'mocha-steps';

step('12. Expect the status to be rejected', async () => {
await sleep(1000);
await sleep(2000);
await testHelpers.expectRejected();

@@ -113,0 +113,0 @@ });

@@ -45,13 +45,12 @@ import { step } from 'mocha-steps';

step('4. Simulate a successfull client sending of transaction when presented to the user', async () => {
testHelpers.prepareSuccessfulHandleTransaction();
step('6. Emit a civic-pass event to initiate the GK-API issuance request', async () => {
await testHelpers.simulateSucessfulDataCollectionTriggeringGKTokenRequest();
});
step('5. Emit a civic-pass event to initiate the GK-API issuance request', async () => {
await testHelpers.simulateSucessfulDataCollectionTriggeringGKTokenRequest();
testHelpers.expectFlowIdToBeSet();
step('7. Expect token in review', () => {
testHelpers.expectCivicSendsInReview();
});
step(
'6. OnChain listener fires with active token and gateway status and gateway token are updated to active',
'8. OnChain listener fires with active token and gateway status and gateway token are updated to active',
async () => {

@@ -58,0 +57,0 @@ await testHelpers.simulateActiveOnChainToken();

@@ -55,4 +55,8 @@ import { step } from 'mocha-steps';

step('5. Wait for the GK refresh request to complete', async () => {
await sleep(2000);
});
step(
'5 OnChain listener fires with active token and gateway status and gateway token are updated to active',
'6 OnChain listener fires with active token and gateway status and gateway token are updated to active',
async () => {

@@ -59,0 +63,0 @@ await testHelpers.simulateActiveOnChainToken();

@@ -59,4 +59,12 @@ import { step } from 'mocha-steps';

step('6. Wait for the GK refresh request to complete', async () => {
await sleep(2000);
});
step('7. expect state to be IN_REVIEW', () => {
testHelpers.expectClientSendsInReview();
});
step(
'6 OnChain listener fires with active token and gateway status and gateway token are updated to active',
'8 OnChain listener fires with active token and gateway status and gateway token are updated to active',
async () => {

@@ -63,0 +71,0 @@ await testHelpers.simulateActiveOnChainToken();

@@ -17,3 +17,7 @@ import GatewayClientCore, {

import { GatekeeperAPIStatus } from '../../src/types/gatekeeperApi';
import { CivicPassMessageAction, CivicPassMessageEventResult, CivicPassMessageResponse } from '../../src/types/civicPass';
import {
CivicPassMessageAction,
CivicPassMessageEventResult,
CivicPassMessageResponse,
} from '../../src/types/civicPass';
import { CivicSignEventTypeRequest, CivicSignEventTypeResponse } from '../../src/types/civicSign';

@@ -206,2 +210,11 @@ import { GatewayClientParameters } from '../../src/types/parameters';

// add a delay of 1 seconds to simulate an async GK response
console.log('fetchStub args', [
`${this.chainImplementationStub.httpConfig.baseUrl}/?network=${this.inputs.network}&gatekeeperNetworkAddress=${this.inputs.gatekeeperNetwork}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(postRequestPayload),
signal: sinon.match.any,
},
]);
this.fetchStub

@@ -229,3 +242,4 @@ .withArgs(

gatekeeperAPIStatus: GatekeeperAPIStatus = GatekeeperAPIStatus.REJECTED,
errorCode?: string
errorCode?: string,
payload: Record<string, unknown> = {}
) {

@@ -246,4 +260,7 @@ this.fetchStub

errorCode,
...(payload ? { payload } : {}),
});
});
// stub GK issuance request to simulate a rejection
this.fetchStub

@@ -258,3 +275,3 @@ .withArgs(

address: this.inputs.walletAddress,
payer: this.inputs.walletAddress,
payer: this.inputs.clientSends ? this.inputs.walletAddress : undefined,
}),

@@ -269,4 +286,21 @@ signal: sinon.match.any,

errorCode,
...(payload ? { payload } : {}),
});
});
// stub GK refresh request to simulate a rejection
this.fetchStub
.withArgs(
`${this.chainImplementationStub.httpConfig.baseUrl}/${this.inputs.walletAddress}?network=${this.inputs.network}&gatekeeperNetworkAddress=${this.inputs.gatekeeperNetwork}`,
sinon.match({
method: 'PATCH',
})
)
.callsFake(async () => {
await sleep(1000);
return getFetchStub(gatekeeperAPIStatus, {
state: gatekeeperAPIStatus,
errorCode,
...(payload ? { payload } : {}),
});
});
}

@@ -304,2 +338,3 @@

gatekeeperSendsTransaction: !this.inputs.clientSends,
flowIdPrefix: 'GWRC',
...parameterOverrides,

@@ -451,3 +486,2 @@ },

});
// await sleep(2000);
// should have requested a token refresh

@@ -484,3 +518,2 @@ const url = this.fetchStub.getCall(0).args[0];

});
// await sleep(2000);
// should have requested the token issuance

@@ -535,2 +568,8 @@ const postMessageCallObj = this.fetchStub.getCall(0).args[1];

async prepareSuccessfulThirdPartyHandleTransaction() {
this.handleUserSignedTransactionStub.callsFake(() => {
return Promise.resolve(`${transactionId}_third_party`);
});
}
async simulateCivicPassChainFailureEvent() {

@@ -589,2 +628,10 @@ await this.emitter.emit('message', {

expectError(errorCode?: string) {
expect(this.clientOutput.gatewayStatus).to.equal(GatewayStatus.ERROR);
expect(this.clientOutput.flowParameters?.action).to.equal(CivicPassMessageAction.ERROR);
if (errorCode) {
expect(this.clientOutput.flowParameters?.errorCode).to.equal(errorCode);
}
}
getGatewayToken(expiry?: number): GatewayToken {

@@ -609,9 +656,16 @@ return {

stubFindToken(tokenDetails: Partial<GatewayToken>) {
stubFindToken(tokenDetails: Partial<GatewayToken> | null) {
this.findTokenStub.callsFake(async () => {
await sleep(100);
return Promise.resolve({ ...this.getGatewayToken(), ...tokenDetails });
return Promise.resolve(tokenDetails === null ? undefined : { ...this.getGatewayToken(), ...tokenDetails });
});
}
stubFindTokenRejection() {
this.findTokenStub.callsFake(async () => {
await sleep(100);
return Promise.reject(new Error('RPC error'));
});
}
expectActiveToken(expiry?: number) {

@@ -636,3 +690,19 @@ expect(this.clientOutput.gatewayStatus).to.equal(GatewayStatus.ACTIVE);

expectRejected(rejectionStatus = GatewayStatus.REJECTED, expectedErrorCode?: string) {
async simulateUserErrorRetryFlow(eventOverrides: Partial<CivicPassMessageResponse> = {}) {
await this.emitter.emit('message', {
data: {
action: CivicPassMessageAction.ERROR,
event: CivicPassMessageEventResult.FAILURE,
requiresProofOfWalletOwnership: false,
instanceId: this.client.instanceId,
...eventOverrides,
},
});
}
expectRejected(
rejectionStatus = GatewayStatus.REJECTED,
expectedErrorCode?: string,
expectedPayload?: Record<string, unknown>
) {
expect(this.clientOutput.gatewayStatus).to.equal(rejectionStatus);

@@ -642,2 +712,5 @@ if (expectedErrorCode) {

}
if (expectedPayload) {
expect(this.clientOutput?.flowParameters?.payload).to.equal(JSON.stringify(expectedPayload));
}
}

@@ -644,0 +717,0 @@

@@ -7,5 +7,7 @@ import sinon from 'sinon';

import { GatekeeperClient } from '../src/gatekeeperClient';
import { Chain, GatewayCoreState } from '../src';
import { Chain, ExtendedGatewayStatus, GatewayCoreState } from '../src';
import { Refresh } from '../src/refresh';
import * as expiryUtils from '../src/utils/expiry';
import { calculateFromRefreshInReview } from '../src/state/refresh';
import { InputStatus } from '../src/types/fetch';

@@ -63,6 +65,6 @@ chai.use(chaiSubset);

baseUrl: 'https://example.com',
queryParams: {
queryParams: {
network: '0x123',
},
headers: { },
},
headers: {},
},

@@ -142,3 +144,3 @@ } as unknown as Chain;

refresh = new Refresh(gatewayCoreStore, chainImplementation, gatekeeperClient, abortController);
const status = refresh.statusHasValidToken();
const status = refresh.statusHasValidToken();
expect(getStateStub).to.have.been.calledOnce;

@@ -160,3 +162,3 @@ expect(status).to.be.false;

refresh = new Refresh(gatewayCoreStore, chainImplementation, gatekeeperClient, abortController);
const status = refresh.statusHasValidToken();
const status = refresh.statusHasValidToken();
expect(getStateStub).to.have.been.calledOnce;

@@ -178,3 +180,3 @@ expect(status).to.be.true;

refresh = new Refresh(gatewayCoreStore, chainImplementation, gatekeeperClient, abortController);
const status = refresh.statusHasValidToken();
const status = refresh.statusHasValidToken();
expect(getStateStub).to.have.been.calledOnce;

@@ -184,2 +186,127 @@ expect(status).to.be.false;

});
context('calculateFromRefreshInReview', () => {
context('with a payer', () => {
context('with a gatekeeperRecord complete with no transaction', () => {
it('should return undefined', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'a-different-address',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: undefined,
},
},
},
} as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(undefined);
});
});
context('with a gatekeeperRecord complete with a transaction', () => {
context('with a payer different from the wallet owner', () => {
it('should return REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'a-different-address',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: 'test-transaction',
},
},
},
} as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.REFRESH_AWAITING_THIRD_PARTY_TRANSACTION_SEND);
});
});
context('with a payer equal to the wallet owner', () => {
it('should return REFRESH_AWAITING_TRANSACTION_SEND', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'test-payer',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: 'test-transaction',
},
},
},
} as unknown as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.REFRESH_AWAITING_TRANSACTION_SEND);
});
});
});
context('with a chainTransaction sentTxId', () => {
it('should return REFRESH_AWAITING_ON_CHAIN_TOKEN', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
},
},
internal: {
chainTransaction: {
sentTxId: 'test-tx-id',
},
},
} as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN);
});
});
context('with a chainTransaction error', () => {
it('should return CHAIN_TRANSACTION_ERROR', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
},
},
internal: {
chainTransaction: {
error: 'test-error',
},
},
} as unknown as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.CHAIN_TRANSACTION_ERROR);
});
});
});
context('with no payer set', () => {
it('should return REFRESH_AWAITING_ON_CHAIN_TOKEN', () => {
const state = {
inputs: {
parameters: {},
},
} as GatewayCoreState;
const result = calculateFromRefreshInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.REFRESH_AWAITING_ON_CHAIN_TOKEN);
});
});
});
});

@@ -6,2 +6,3 @@ import { InputStatus } from '../../src/types/fetch';

import chai from 'chai';
import sinon from 'sinon';
import { initialInputState } from '../../src/state/state';

@@ -11,3 +12,3 @@ import { CivicPassMessageAction, CivicPassMessageEventResult } from '../../src/types/civicPass';

import { GatekeeperAPIStatus } from '../../src/types/gatekeeperApi';
import sinon from 'sinon';
import * as common from '../../src/state/common';

@@ -19,2 +20,3 @@ const { expect } = chai;

afterEach(sandbox.restore);
context('after initialization with gateway status as CHECKING', () => {

@@ -127,2 +129,3 @@ const checkingState = {

});
context('with a civic-pass chain error failure', () => {

@@ -148,2 +151,42 @@ context('with too many client sends attempts', () => {

context('with internal status as CHAIN_SIGN_MESSAGE_ERROR', () => {
it('should set status to RESTART if it is not refreh flow', () => {
const state = {
inputs: {
...initialInputState,
civicPass: {
received: { event: CivicPassMessageEventResult.FAILURE, action: CivicPassMessageAction.CHAIN_ERROR },
},
gatewayToken: {
received: undefined,
},
},
internal: {
status: ExtendedGatewayStatus.CHAIN_SIGN_MESSAGE_ERROR,
},
} as unknown as GatewayCoreState;
const result = computeInternalStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.RESTART);
});
it('should set status to RESTART_REFRESH if it is a refreh flow', () => {
const state = {
inputs: {
...initialInputState,
civicPass: {
received: { event: CivicPassMessageEventResult.FAILURE, action: CivicPassMessageAction.CHAIN_ERROR },
},
gatewayToken: {
received: { state: 'ACTIVE' },
}
},
internal: {
status: ExtendedGatewayStatus.CHAIN_SIGN_MESSAGE_ERROR,
},
} as GatewayCoreState;
const result = computeInternalStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.RESTART_REFRESH);
});
});
context('with some client-sends attempts left', () => {

@@ -258,2 +301,111 @@ it('should set status to ISSUANCE_AWAITING_TRANSACTION_SEND', () => {

});
context('final states', () => {
[
ExtendedGatewayStatus.RESTART,
ExtendedGatewayStatus.RESTART_REFRESH,
GatewayStatus.ERROR,
GatewayStatus.REJECTED,
GatewayStatus.LOCATION_NOT_SUPPORTED,
GatewayStatus.VPN_NOT_SUPPORTED,
].forEach((finalStatus) => {
it(`should return the same status as ${finalStatus} is a final state`, () => {
const state = {
inputs: {
...initialInputState,
},
internal: {
status: finalStatus,
},
} as GatewayCoreState;
const result = computeInternalStatus(state);
expect(result).to.equal(finalStatus);
});
});
});
context('unhandled states', () => {
[
GatewayStatus.VALIDATING_USER_INFORMATION,
GatewayStatus.USER_INFORMATION_REJECTED,
ExtendedGatewayStatus.AWAITING_OWNER_TRANSACTION,
ExtendedGatewayStatus.AWAITING_OWNER_TRANSACTION,
ExtendedGatewayStatus.CONFIRM_OWNER_TRANSACTION,
].forEach((finalStatus) => {
it(`should return the same status as ${finalStatus} these status are not mapped to other states`, () => {
const state = {
inputs: {
...initialInputState,
},
internal: {
status: finalStatus,
},
} as GatewayCoreState;
const result = computeInternalStatus(state);
expect(result).to.equal(finalStatus);
});
});
});
context('with a state that is invalid or not mapped', () => {
it('should throw an error', () => {
const state = {
inputs: {
...initialInputState,
},
internal: {
status: 'known-invalid-status' as ExtendedGatewayStatus,
},
} as GatewayCoreState;
expect(() => computeInternalStatus(state)).to.throw('No transition function defined for known-invalid-status status');
})
});
context('with a computeFn that returns a new state that is not a valid transition', () => {
beforeEach(() => {
sandbox.stub(common, 'statusFromGatewayTokenIfExists').returns('invalid-state' as ExtendedGatewayStatus);
});
afterEach(() => {
sandbox.restore();
});
it('should throw an error', async () => {
const state = {
inputs: {
...initialInputState,
},
internal: {
status: GatewayStatus.UNKNOWN,
},
} as GatewayCoreState;
// stub the UNKNOWN compute function to return an invalid state for that transition
expect(() => computeInternalStatus(state)).to.throw(/Invalid transition/);
})
});
context('with a computeFn that returns a new state that is not a valid transition', () => {
beforeEach(() => {
sandbox.stub(common, 'statusFromGatewayTokenIfExists').returns('invalid-state' as ExtendedGatewayStatus);
});
afterEach(() => {
sandbox.restore();
});
it('should throw an error', async () => {
const state = {
inputs: {
...initialInputState,
},
internal: {
status: GatewayStatus.UNKNOWN,
},
} as GatewayCoreState;
// stub the UNKNOWN compute function to return an invalid state for that transition
expect(() => computeInternalStatus(state)).to.throw(/Invalid transition/);
})
});
});

@@ -1,7 +0,16 @@

import { ExtendedGatewayStatus, GatewayCoreState } from '../../src';
import { calculateFromIssuanceAwaitingOnChain, calculateFromIssuanceInReview } from '../../src/state/issuance';
import { ExtendedGatewayStatus, GatewayCoreState, GatewayStatus } from '../../src';
import {
calculateFromGatekeeperIssuanceRequested,
calculateFromIssuanceAwaitingOnChain,
calculateFromIssuanceInReview,
calculateIssuanceRequestedDataCollectionRestart,
calculateIssuanceStatus,
isInPartnerReview,
} from '../../src/state/issuance';
import { expect } from 'chai';
import { ErrorCode } from '../../src/utils/errors';
import { CivicPassMessageAction } from '../../src/types/civicPass';
import { CivicPassMessageAction, CivicPassMessageEventResult } from '../../src/types/civicPass';
import { InputStatus } from '../../src/types/fetch';
import { GatekeeperAPIStatus } from '../../src/types/gatekeeperApi';
import { validationProcessToGatewayStatus } from '../../src/state/common';

@@ -88,18 +97,46 @@ describe('issuance state unit tests', () => {

context('with a gatekeeperRecord complete with a transaction', () => {
it('should return ISSUANCE_AWAITING_TRANSACTION_SEND', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
context('with a payer different from the wallet owner', () => {
it('should return ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'a-different-address',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: 'test-transaction',
},
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: 'test-transaction',
} as GatewayCoreState;
const result = calculateFromIssuanceInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_AWAITING_THIRD_PARTY_TRANSACTION_SEND);
});
});
context('with a payer equal to the wallet owner', () => {
it('should return ISSUANCE_AWAITING_TRANSACTION_SEND', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'test-payer',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
transaction: 'test-transaction',
},
},
},
},
} as unknown as GatewayCoreState;
const result = calculateFromIssuanceInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND);
} as unknown as GatewayCoreState;
const result = calculateFromIssuanceInReview(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_AWAITING_TRANSACTION_SEND);
});
});

@@ -159,2 +196,323 @@ });

});
context('calculateIssuanceRequestedDataCollectionRestart', () => {
context('with a civicPass event of failure', () => {
it('should return RESTART', () => {
const state = {
inputs: {
civicPass: {
received: {
event: CivicPassMessageEventResult.FAILURE,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceRequestedDataCollectionRestart(state);
expect(result).to.equal(ExtendedGatewayStatus.RESTART);
});
});
context('with a civicPass issuance succcess', () => {
it('should return USER_INFORMATION_VALIDATED', () => {
const state = {
inputs: {
civicPass: {
received: {
action: CivicPassMessageAction.ISSUANCE,
event: CivicPassMessageEventResult.SUCCESS,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceRequestedDataCollectionRestart(state);
expect(result).to.equal(GatewayStatus.USER_INFORMATION_VALIDATED);
});
});
context('with no civicPass event', () => {
it('should return undefined', () => {
const state = {
inputs: {},
} as GatewayCoreState;
const result = calculateIssuanceRequestedDataCollectionRestart(state);
expect(result).to.be.undefined;
});
});
});
context('isInPartnerReview', () => {
context('with a pending payload set in the gatekeeperRecord', () => {
it('should return true', () => {
const gatekeeperRecord = {
received: {
payload: {
pending: 'test-pending',
},
},
} as unknown as GatewayCoreState['inputs']['gatekeeperRecord'];
const result = isInPartnerReview(gatekeeperRecord);
expect(result).to.be.true;
});
});
context('with a pending object directly set in the gatekeeperRecord', () => {
it('should return true', () => {
const gatekeeperRecord = {
received: {
pending: 'test-pending',
},
} as unknown as GatewayCoreState['inputs']['gatekeeperRecord'];
const result = isInPartnerReview(gatekeeperRecord);
expect(result).to.be.true;
});
});
context('with no pending payload set', () => {
it('should return false', () => {
const gatekeeperRecord = {
received: {},
} as unknown as GatewayCoreState['inputs']['gatekeeperRecord'];
const result = isInPartnerReview(gatekeeperRecord);
expect(result).to.be.false;
});
});
});
context('calculateIssuanceStatus', () => {
context('with a civicPass event of failure', () => {
it('should return RESTART', () => {
const state = {
inputs: {
civicPass: {
received: {
event: CivicPassMessageEventResult.FAILURE,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.RESTART);
});
});
context('with a civicPass issuance succcess', () => {
it('should return USER_INFORMATION_VALIDATED', () => {
const state = {
inputs: {
civicPass: {
received: {
action: CivicPassMessageAction.ISSUANCE,
event: CivicPassMessageEventResult.SUCCESS,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(GatewayStatus.USER_INFORMATION_VALIDATED);
});
});
context('with no civicPass event', () => {
context('with a GatekeeperAPIStatus of not-requested', () => {
context('with a validation status set', () => {
Object.entries(validationProcessToGatewayStatus).forEach(([validationStatus, gatewayStatus]) => {
context('with a civicPass payload status of ' + validationStatus, () => {
it('should return ' + gatewayStatus, () => {
const state = {
inputs: {
civicPass: {
received: {
payload: {
status: validationStatus,
},
},
},
gatekeeperRecord: {
status: GatekeeperAPIStatus.NOT_REQUESTED,
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(gatewayStatus);
});
});
});
});
context('with no validation status set', () => {
it('should return NOT_REQUESTED', () => {
const state = {
inputs: {
gatekeeperRecord: {
status: GatekeeperAPIStatus.NOT_REQUESTED,
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(GatewayStatus.NOT_REQUESTED);
});
});
});
context('with a GatekeeperAPIStatus of requested', () => {
context('if the record has a pending payload', () => {
it('should return TOKEN_IN_PARTNER_REVIEW', () => {
const state = {
inputs: {
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
state: GatekeeperAPIStatus.REQUESTED,
payload: {
pending: 'test-pending',
},
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.TOKEN_IN_PARTNER_REVIEW);
});
});
context('if a payer is set', () => {
context('with a civicPass event of issuance complete with no transaction', () => {
it('should return ISSUANCE_RESTART_DATA_COLLECTION', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
},
civicPass: {
received: {
action: 'test-action',
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
state: GatekeeperAPIStatus.REQUESTED,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_RESTART_DATA_COLLECTION);
});
});
});
context('if a payer is not set', () => {
it('should return ISSUANCE_AWAITING_ON_CHAIN_TOKEN', () => {
const state = {
inputs: {
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
state: GatekeeperAPIStatus.REQUESTED,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateIssuanceStatus(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_AWAITING_ON_CHAIN_TOKEN);
});
});
});
});
});
context('calculateFromGatekeeperIssuanceRequested', () => {
context('with a civicPass event', () => {
[
{
status: InputStatus.COMPLETE,
received: {
state: GatekeeperAPIStatus.REQUESTED,
},
},
{
status: InputStatus.IN_PROGRESS,
received: {
state: GatekeeperAPIStatus.NOT_REQUESTED,
},
},
].forEach((gatekeeperRecordState) => {
context(`with a gatekeeperRecord status of ${JSON.stringify(gatekeeperRecordState)}`, () => {
context('with a payer set', () => {
context('with the payer equal to the wallet owner', () => {
it('should return ISSUANCE_CLIENT_PAYER_REQUESTED', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'test-payer',
},
},
civicPass: {
received: {
action: CivicPassMessageAction.ISSUANCE,
},
},
gatekeeperRecord: gatekeeperRecordState,
},
} as unknown as GatewayCoreState;
const result = calculateFromGatekeeperIssuanceRequested(state);
expect(result).to.equal(ExtendedGatewayStatus.ISSUANCE_CLIENT_PAYER_REQUESTED);
});
});
context('with the payer different from the wallet owner', () => {
it('should return IN_REVIEW', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
wallet: {
address: 'a-different-address',
},
},
civicPass: {
received: {
action: CivicPassMessageAction.ISSUANCE,
},
},
gatekeeperRecord: gatekeeperRecordState,
},
} as unknown as GatewayCoreState;
const result = calculateFromGatekeeperIssuanceRequested(state);
expect(result).to.equal(GatewayStatus.IN_REVIEW);
});
});
});
});
});
context('with a gatekeeperRecord status not in-progress and not requested', () => {
it('should return undefined', () => {
const state = {
inputs: {
parameters: {
payer: 'test-payer',
},
civicPass: {
received: {
action: CivicPassMessageAction.ISSUANCE,
},
},
gatekeeperRecord: {
status: InputStatus.COMPLETE,
received: {
state: GatekeeperAPIStatus.REJECTED,
},
},
},
} as unknown as GatewayCoreState;
const result = calculateFromGatekeeperIssuanceRequested(state);
expect(result).to.be.undefined;
});
});
});
});
});

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc