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

@edgeandnode/graph-auth-kit

v3.23.0

Published

Wallet authentication connect kit in The Graph suite of applications

Downloads

4,500

Readme

@edgeandnode/graph-auth-kit

Authentication Kit for connecting The Graph apps/dapps to a wallet.

Relies on/requires wagmi + viem for allowing users to connect their wallets and interact with the connected auth state context.

Exposes a simple useGraphAuthKit hook that lets the app open the connect modal, letting users connect to their wallet of choice (one of: injected/MetaMask, coinbase, WalletConnect, Safe). See integration example below.

Install

Currently, graph-auth-kit has a lot of peer deps needed to interact with the library. But this may change after testing. At the very least, wagmi, viem, @tanstack/react-query will be needed.

# with bun
bun add @edgeandnode/graph-auth-kit \
  @edgeandnode/common \
  @edgeandnode/gds \
  @edgeandnode/go \
  @emotion/react \
  @tanstack/react-query \
  cookies-next \
  [email protected] \
  theme-ui \
  [email protected] \
  wagmi

# with pnpm
pnpm add @edgeandnode/graph-auth-kit \
  @edgeandnode/common \
  @edgeandnode/gds \
  @edgeandnode/go \
  @emotion/react \
  @tanstack/react-query \
  cookies-next \
  [email protected] \
  theme-ui \
  [email protected] \
  wagmi

Usage

Properties:

  • config -> [REQUIRED]. The instantiated wagmi config instance.
  • queryClient -> [OPTIONAL]. The GraphAuthKitProvider renders a QueryClientProvider instance. Pass in an instantiated QueryClient to use, otherwise, GraphAuthKit will instantiate its own.
  • infuraKey -> [REQUIRED]
  • gatewayApiKey -> [OPTIONAL]. A The Graph Gateway API key used to query Subgraphs published on the Graph Network. Used for ENS name resolution

Example

  • Setup the GraphAuthKitProvider.
    • Note you do not need to add the ConnectModal component, the GraphAuthKitProvider renders it for us
    • Note you do not need to add the QueryClientProvider as GraphAuthKitProvider instantiates and renders it
      • you can pass a QueryClient instance to the GraphAuthKitProvider, otherwise, it will instantiate its own
// _app.tsx

import { QueryClient } from '@tanstack/react-query'
import { AppProps } from 'next'
import { useRef } from 'react'
import { createClient } from 'viem'
import { cookieStorage, createConfig, createStorage } from 'wagmi'
import { coinbaseWallet, injected, walletConnect } from 'wagmi/connectors'

import { AnalyticsProvider, GDSProvider } from '@edgeandnode/gds'
import {
  AUTH_STORAGE_KEY,
  buildInfuraHttpTransport,
  chainIsSupportedChain,
  DefChain,
  GraphAuthKitProvider,
  L1Chain,
  L1ChainTestnet,
  L2Chain,
  L2ChainTestnet,
} from '@edgeandnode/graph-auth-kit'

import { FutureNextLink } from '../components/FutureNextLink'
import { Layout } from '../components/Layout'

const infuraKey = process.env.INFURA_KEY!
const walletConnectProjectID = process.env.WALLETCONNECT_PROJECT_ID!
const gatewayApiKey = process.env.GATEWAY_API_KEY

import '@edgeandnode/gds/style.css'
import '../app.css'

const config = createConfig({
  chains: [L2Chain, L2ChainTestnet, L1Chain, L1ChainTestnet] as const,
  ssr: typeof window !== 'undefined',
  client(params) {
    const chain = chainIsSupportedChain(params.chain) ? params.chain : DefChain
    const transport = buildInfuraHttpTransport({
      chain: chain.id,
      infuraKey,
    })

    return createClient({
      chain,
      transport,
    })
  },
  connectors: [
    injected(),
    coinbaseWallet({
      appName: 'Boom',
    }),
    walletConnect({
      projectId: env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID,
      qrModalOptions: {
        themeMode: 'dark',
      },
    }),
  ],
  storage: createStorage({
    storage: cookieStorage,
    key: AUTH_STORAGE_KEY,
  }),
})

declare module 'wagmi' {
  interface Register {
    config: typeof config
  }
}

export default function App({ Component, router, pageProps }: AppProps) {
  const queryClient = useRef<QueryClient>()
  if (!queryClient.current) {
    queryClient.current = new QueryClient({
      defaultOptions: {
        queries: {
          // With SSR, we usually want to set some default staleTime
          // above 0 to avoid refetching immediately on the client
          staleTime: 60 * 1000,
        },
      },
    })
  }

  return (
    <GDSProvider clientRouter={router} clientLink={FutureNextLink} useLegacyTheme>
      <AnalyticsProvider
        app="EXPLORER"
        clientRouter={router}
        mixpanel={{
          sdk: mixpanel,
          token: process.env.MIXPANEL_TOKEN ?? null,
        }}
        googleAnalytics={{
          sdk: googleAnalytics,
          measurementId: process.env.GOOGLE_ANALYTICS_MEASUREMENT_ID ?? null,
        }}
      >
        <GraphAuthKitProvider
          config={config}
          queryClient={queryClient.current}
          infuraKey={infuraKey}
          gatewayApiKey={gatewayApiKey}
        >
          <Layout>
            <DefaultSeo {...defaultSEO} />
            <Component {...pageProps} />
          </Layout>
          <ReactQueryDevtools initialIsOpen={false} />
        </GraphAuthKitProvider>
      </AnalyticsProvider>
    </GDSProvider>
  )
}
  • Usage in a component
// components/Layout.tsx

import { ReactNode } from 'react'
import { useAccountEffect, useEnsName } from 'wagmi'

import { Layout as GDSLayout, UserProfile } from '@edgeandnode/gds'
import { GlobalFooter, GlobalHeader, NPSForm } from '@edgeandnode/go'
import { L1Chain, useGraphAuthKitConnector, useGraphAuthKit, useGraphAuthKitAccount } from '@edgeandnode/graph-auth-kit/hooks'

import { NavDropDownMenu } from './NavDropDownMenu'

export function Layout({ children }: Readonly<{ children: ReactNode }>) {
  const authkit = useGraphAuthKit()
  const { address } = useGraphAuthKitAccount()
  const { data: ens } = useEnsName({ address, blockTag: 'latest', chainId: L1Chain.id })
  const connector = useGraphAuthKitConnector()

  const walletConnected = Boolean(address)

  useAccountEffect({
    onConnect(data) {
      console.log('user connected wallet', {data})
    },
    onDisconnect() {
      console.log('user disconnected wallet')
    },
  })

  return (
    <GDSLayout
      header={
        <GlobalHeader
          activeProduct="EXPLORER"
          basePath="/explorer"
          showSupportButton={walletConnected}
          rigtContent={(defaultContent) => (
            <>
              {!walletConnected ?
                <GlobalHeader.ConnectButton onClick={() => authkit.openConnectModal()} />
              ) : (
                <UserProfile
                  ethereumAccount={address}
                  graphAccount={...}
                  ens={ens}
                  profileUrl={`/profile/${address}?view=Overview`}
                  profileUrlAs={`/profile/${address}?view=Overview`}
                  onConnect={() => authkit.openConnectModal()}
                  onDisconnect={() => authkit.disconnect()}
                  userDropDownMenu={<NavDropDownMenu />}
                  accountTag={connector === 'safe' ? 'multisig' : undefined}
                />
              )}
            </>
          )}
        />
      }
      footer={
        <>
          <NPSForm sx={{ mb: Spacing['64px'] }} />
          <GlobalFooter />
        </>
      }
    >
      {children}
    </GDSLayout>
  )
}

Hooks

  • useGraphAuthKitAccount -> This is an override of the wagmi useAccount hook. The reason is, if the user connects with a multisig, the wagmi context is connected with the user-selected EoA, so all of the wagmi context hooks reference this EoA and not the Safe. This returns the wagmi UseAccountReturnType but the address and addresses values include the entered Safe address. It also adds an eoa property that is the connected EoA address.
  • useGraphAuthKitConnector -> The user selected wallet/connector option.
  • useClientToEthersSigner -> Returns the [email protected] JsonRpcSigner or SafeEthersSigner if the user is connected via a multisig
  • useAuthAccount -> similar to the useGraphAuthKitAccount but requires the user to be authenticated and throws an error if not
  • useGraphAuthKitAccountEffect -> Override of the wagmi useAccountEffect hook that listens to account changes and the _enteredMultisigInfo on the inner context instance. If the account data changes, emits a onConnect or onDisconnect event, but in the onConnect also checks the useGraphAuthKitInnerContext()._enteredMultisigInfo value and if the user has connected via a multisig, returns the mutlsig as the address value and the connected EoA as the eoa value.
  • useGraphAuthKitWalletClient -> Override of the wagmi useWalletClient hook that returns the extended Safe viem actions if the user is connected to a multisig.
  • useGraphAuthKitWriteContract -> Override of the wagmi useWriteContract hook that creates the transaction on the Safe if the user is connected via multisig; otherwise, returns the useWriteContract mutation hook.

Components

  • Connected -> renders the passed in children only if the user is connected.
import { Connected } from '@edgeandnode/graph-auth-kit'

export function ShowMeConnected() {
  return <Connected>{(account) => <div>Connected Wallet: {account.address}</div>}</Connected>
}
  • Disconnected -> renders the passed in children only if the user id disconnected. Useful for rendering components like a "Connect Wallet" CTA that should only render if the user is not authenticated.
import { ExperimentalButton as Button } from '@edgeandnode/gds'
import { Disconnected, useGraphAuthKit } from '@edgeandnode/graph-auth-kit'

export function ShowMeDisconnected() {
  const authkit = useGraphAuthKit()

  return (
    <Disconnected>
      <Button variant="primary" onClick={() => authkit.openConnectModal()}>
        Connect Wallet
      </Button>
    </Disconnected>
  )
}
import { ExperimentalButton as Button } from '@edgeandnode/gds'
import { L2Chain, SwitchChain } from '@edgeandnode/graph-auth-kit'

export function LetMeSwitchChain() {
  return <SwitchChain requestedChain={L2Chain} />
}

References