npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@civic/gateway-client-react

v1.2.4

Published

## Overview

Downloads

1,527

Readme

Civic Gateway Client React

Overview

The Civic gateway-client-react is a chain-agnostic wrapper for user Civic pass creation and refresh that instantiates the gateway-client-core and provides UI elements and listeners to it to listen for Civic pass data collection, and on-chain events. The Civic data-collection IFrame is instantiated and updated using the flowParameters output from the core instance, and the core Gateway Status and Gateway Token (if available) from the core are made available to dApp developers via the useGateway hook. The gateway-client-react library is intended to be used along with a gateway-chain-implementation to form a working on-chain gateway-client component used to issue passes on a desired chain.

Getting Started

1. Setting up your React project

You must have at least React 18 installed in your npm project.

2. Instantiate the gateway context and pass it a chain implementation

Surround any code that needs access to the gateway token with a GatewayContext, passing all the required props together. The example below combines a solana chain implementation with the gateway-client-react:

import { GatewayProvider } from "@civic/solana-gateway-react";
import { Connection, clusterApiUrl } from '@solana/web3.js';
// this is the solana chain implementation, other chains are available
import { SolanaChainImplementation } from '@civic/solana-gateway-chain-client';

// these values memoised because some are dependant on one-another so they need to all change together if an input changes
const gatewayProviderProps = useMemo(
    () => ({
        wallet: wallet?.publicKey?.toBase58() ? { publicKey: wallet?.publicKey?.toBase58() } : undefined,
        chainImplementation:
        wallet?.publicKey && wallet?.signTransaction && stage && gatekeeperNetwork?.toBase58()
            ? new SolanaChainImplementation({
            connection,
            cluster,
            publicKey: wallet.publicKey,
            signTransaction: wallet.signTransaction,
            signMessage: wallet.signMessage,
            gatekeeperNetworkAddress: gatekeeperNetwork,
            })
            : undefined,
        gatekeeperNetwork: gatekeeperNetwork?.toBase58(),
        options,
    }),
    [
        wallet?.publicKey?.toBase58(),
        connection?.rpcEndpoint,
        cluster,
        gatekeeperNetwork?.toBase58(),
    ]
);

<GatewayProvider
    wallet={gatewayProviderProps.wallet}
    chainImplementation={gatewayProviderProps.chainImplementation}
    stage={gatewayProviderProps.stage}
    gatekeeperNetwork={gatewayProviderProps.gatekeeperNetwork}
>
    {children}
</GatewayProvider>

where:

  • connection is a Solana connection to any Solana network, recommended commitment of 'processed'
  • cluster is the Solana network to use, i.e. devnet, mainnet-beta, testnet. This defaults to mainnet-beta, so should be set if a different connection endpoint is used than mainnet-beta
  • wallet contains publicKey, connected and signTransaction (see below)
  • gatekeeperNetwork is a Solana publicKey provided by the dApp, you can get choose a gatekeeper network to use from https://docs.civic.com/integration-guides/civic-idv-services/available-networks

3. Accessing or requesting the gateway token

The component will automatically look for a gateway token on chain. To access it once created:

import { useGateway } from "@civic/gateway-client-react";
const { gatewayToken } = useGateway()

If the wallet does not have a gateway token, request it using requestGatewayToken:

const { requestGatewayToken } = useGateway()

For example, by connecting it to a button component:

<button onclick={requestGatewayToken}>Validate your wallet</button>

Or by using Identity Button provided:

import IdentityButton from './lib/button/IdentityButton';
...
<IdentityButton />

4. IdentityButton behaviour

The IdentityButton is a reference implementation of a UI component to communicate to your dApp users the current status of their Gateway Token, or Gateway Token request. It changes appearance with text and icons to indicate when the user needs to take action and can be clicked by the user at any point in the process. The initial click for a new user will initiate the flow for the user to create a new Gateway Token. Once the user has gone through KYC and submitted their Gateway Token request via the Civic compliance iFrame, any subsequent click will launch the Civic Pass iframe with a screen describing the current status of the flow.

API Documentation

GatewayProvider

The GatewayProvider is a React component that gives children access to the GatewayContext through the useGateway function. This component holds the state for a given gateway token or gateway token request.


export type GatewayProviderProps = {
    // the address of the wallet connected to the dApp, can be undefined initially pre-user wallet connection
    walletAddress: string | undefined; 

    // the gatekeeper network public key address
    gatekeeperNetwork: string | undefined;

    // An implementation conforming to the Chain interface, representing the blockchain cluster you are interacting with
    // can be undefined during initialisation
    chainImplementation: ChainClientInterface | undefined;

    // [Optional] If this is set, the transaction must be signed by this payer, and the payer will
    // be charged the cost of the pass.
    // Leave unset (default) for the user to pay for the pass.
    // If set, you must also set handleTransaction. See an example below.
    payer?: string;

    // [Optional] If set, the gatekeeper will send the transaction to the blockchain. Defaults to false.
    // When true, `payer` must be false or unset, and `handleTransaction` must be unset.
    // Note: This is only supported for custom passes.
    gatekeeperSendsTransaction: boolean; 

    // [Optional] set Civic gatekeeper stage (testing only), defaults to 'prod'
    stage?: string;

    // [Optional] this will be passed to the gatekeeper in the x-civic-client header
    reactComponentVersion?: string;

    // [Optional]a react element that the dApp can wrap the iframe in to allow customer dApp styling
    wrapper?: React.FC;

    // [Optional] the url of your logo that will be shown, if set, during verification
    logo?: string;

     // [Optional] a redirect URL that can be used for deep-linking and mobile-web
    redirectUrl?: string;

    // [Optional] A set of client options (see 'Client Options' below)
    options?: Options;

    // [Optional] for gatekeeper networks that have pass expiry, set this value to prompt the user to refresh the pass this amount of seconds before the pass expires
    expiryMarginSeconds?: number; 

    // the partnerAppId provided by Civic, only for partners who have registered with Civic
    partnerAppId?: string; 

    // [Optional] When set to true, initiates the refresh flow if the user has an active token, even if the pass hasn't expired
    forceRequireRefresh?: boolean;

    // [Optional] the number of seconds after a transation has been sent to wait for a token before timing out.
    // Defaults to 2 minutes
    expectTokenTimeoutSeconds?: number;

    // [Optional] for use-cases where you want the fastest possible user-flow, and don't need any up-front location checks, this can be set to true so that the client will not call the GK-API on load. Defaults to false
    disableInitialGatekeeperLookup?: boolean;
};

GatewayStatus

The GatewayStatus is an enum that reveals the state of the requested Gateway Token.

export enum GatewayStatus {
  UNKNOWN = 0, // the wallet or gatekeeper network is not set
  CHECKING = 1, // the blockchain is being queried to find an existing gateway token
  NOT_REQUESTED = 2, // then token has not been requested
  COLLECTING_USER_INFORMATION = 3, // the wallet owner is undergoing KYC
  PROOF_OF_WALLET_OWNERSHIP = 4, // the user needs to confirm wallet ownership,
  IN_REVIEW = 5, // the token has been requested and civic gatekeeper is reviewing the request
  REJECTED = 6, // the token issuance request was rejected
  REVOKED = 7, // the token has been revoked
  FROZEN = 8, // the token has been frozen
  ACTIVE = 9, // the token has been issued successfully and is in an active state
  ERROR = 10, // something went wrong
  LOCATION_NOT_SUPPORTED = 11, // location is not currently supported
  VPN_NOT_SUPPORTED = 12, // vpn usage is not currently supported
  REFRESH_TOKEN_REQUIRED = 13, // waiting for the user to complete the civic pass refresh flow
  VALIDATING_USER_INFORMATION = 14, // validation process is currently being reviewed
  USER_INFORMATION_VALIDATED = 15, // validation process has finished processing
  USER_INFORMATION_REJECTED = 16, // validation process failed and needs to be restarted
}

useGateway

Any component wrapped by GatewayProvider can access the state and useful functions of the GatewayProvider through this function.

Returns the current context values for the GatewayContext by exposing the following properties.

export type GatewayProps = {
  requestGatewayToken: () => Promise<void>, // starts off gateway token process
  reinitialize: () => Promise<void> // reinitializes the GatewayClient instance
  gatewayStatus: GatewayStatus, // normally a value from a React hook state, defaults to GatewayStatus.UNKNOWN
  gatewayToken?: GatewayToken, // the current GatewayToken used in the dApp
  gatewayTokenTransaction: string, // if broadcastTransaction is false, this will be populated with any transactions generated by the backend
  pendingRequests?: PendingPayload; // an object containing ID(s) that a partner needs to resolve before a pass can be issued
}

const gatewayProps: GatewayProps = useGateway();

Client options

You can specify some options that affect the display behaviour of the Civic modal that the user interacts with:

export type Options = {
  // whether the Civic modal should appear automatically if the Civic Pass token state changes
  autoShowModal: boolean; 

  // debug | info | warn | error
  logLevel: LogLevel;

  // [Optional] When set to true, prevents the flow to automatically restart on user validation failure
  // Defaults to false
  disableAutoRestartOnValidationFailure?: boolean;
};

Triggering early pass refresh

If you want to force a user to refresh their pass before the pass has expired, the boolean value 'forceRequireRefresh' can be passed to the GatewayProviderProps, e.g. if you want the user to have to refresh if their pass is older than 1 day old:

const shouldForceRefresh = gatewayTokenExpiry < 1_DAY_FROM_NOW

<GatewayProvider wallet={...} gatekeeperNetwork={...} forceRequireRefresh={shouldForceRefresh}/>

This would cause the refresh flow to be initiated for a user with a pass that was created more than one day ago.

Paying for your customers' passes

By default, the user requesting the pass will pay transaction costs and the cost of the pass.

If you want to pay for the pass, you can set the payer prop in the GatewayProvider to the address of the payer.

You must also set handleTransaction.

For example, to pay for the pass using a backend service:

const handleTransaction = async (transaction: Transaction):Promise<string> => {
  // serialize the transaction to send to your backend. 
  const serializedTransaction = Buffer.from(transaction.serialize({
    requireAllSignatures: false,
  })).toString('base64');

  // call your backend to sign and send the transaction
  const response = await fetch('https://your-backend.com/sign-transaction', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ transaction: serializedTransaction }),
  });
  
  // return the tx signature
  const { signature } = await response.json();
  return signature;
};

return <GatewayProvider
  gatekeeperNetwork={GATEKEEPER_NETWORK}
  wallet={wallet}
  connection={connection}
  payer={payer}
  handleTransaction={handleTransaction}
>...</GatewayProvider>

Your backend code is up to you, but should look something like this (Warning - sample code - not for production):

import { TransactionRequest, Wallet } from 'ethers';

// Must match the public key set as the payer in the frontend
const keypair = /* your keypair */;

app.post('/sign-transaction', async (req: Request<{}, {}, { transction: string }>, res: Response) => {
  // parse the request into a transaction
  const { transaction } = await request.json();
  const parsedTransaction = Transaction.from(Buffer.from(transaction, 'base64'));

  // sign the transaction
  // WARNING - Do NOT sign arbitrary transactions sent from an unsecured client. Your funds may be at risk.
  // This code is for demonstration purposes only
  parsedTransaction.partialSign(keypair);

  // send the transaction.
  const signature = await connection.sendRawTransaction(parsedTransaction.serialize(), {
    preflightCommitment: "processed"
  });

  // wait for the transaction to confirm
  const blockhash = await connection.getLatestBlockhash();
  await connection.confirmTransaction({ signature, ...blockhash });

  // return the tx signature
  res.json({ signature });
});

Wrapper

You can customise how the verification flow is displayed by providing a custom wrapper.

...
const customWrapperStyle: CSS.Properties = {
  backgroundColor: 'rgba(0,0,0,1)',
  position: 'fixed',
  zIndex: 999,
  width: '100%',
  height: '100%',
  overflow: 'auto',
  paddingTop: '5%'
}

const customWrapperContentStyle: CSS.Properties = {
  backgroundColor: '#fefefe',
  margin: 'auto',
  width: '90%',
  position: 'relative',
}

export const CustomWrapper: React.FC = ({ children = null }) => {
  return (
    <div style={customWrapperStyle}>
      <div style={customWrapperContentStyle}>
        <img style={{ maxWidth: '20%' }} src={logo} className="app-logo" alt="logo"/>
        {children}
      </div>
    </div>
  )
}

Contributing

yarn build

Builds the app for production to the build folder. It correctly bundles React in production mode and optimizes the build for the best performance.

The build is minified and the filenames include the hashes.
Your app is ready to be deployed!

yarn publish

Publishes a new version of the React Component. We use beta releases before releasing an official release in the following format (major).(minor).(patch)-beta.(build number). You can release a beta with the following command yarn add @civic/solana-gateway-react@beta.

Automated publishing

To publish a new version of the react-component, add a Git tag and use a prefix along with the desired version number e.g.

solana-rc-0.7.0

Note that this method should only be used for production versions, not beta tags.