@leosprograms/graphql-client-holochain
Version:
ValueFlows GraphQLClient configurations, providing pluggable backend datasources for different distributed, federated and client/server infrastructure.
116 lines (107 loc) • 3.67 kB
text/typescript
/**
* GraphQL client interface for Holochain connection
*
* @package hREA GraphQL client
* @since 2020-07-14
*/
// @ts-nocheck
import { ApolloClient, InMemoryCache, NormalizedCacheObject } from '@apollo/client/core/index.js'
import { SchemaLink } from '@apollo/link-schema'
import bindSchema, {
autoConnect,
BindSchemaOptions,
DNAIdMappings,
ExtensionOptions,
ResolverOptions
} from '@leosprograms/vf-graphql-holochain'
/* For external client. Are optional because
`conductorUri` and `appID`
may be autodetected or taken from environment variables
and `dnaConfig` discovered through a functional connection
to holochain
*/
interface AutoConnectionOptions {
weaveAppAgentClient?: any
dnaConfig?: DNAIdMappings
conductorUri?: string
adminConductorUri?: string
appID?: string
}
export type ClientOptions = Pick<ResolverOptions, 'traceAppSignals'>
& Pick<BindSchemaOptions, 'enabledVFModules'>
& ExtensionOptions
& AutoConnectionOptions
/*
This method creates the GraphQLSchema from
the given options, and then builds an Graphql Apollo Client
with the basic InMemoryCache with that schema.
*/
export async function initGraphQLClient(options: BindSchemaOptions) {
const schema = await bindSchema(options)
return new ApolloClient({
cache: new InMemoryCache({
dataIdFromObject(object) {
switch (object.__typename) {
case 'Unit':
return `Unit:${object.id}`; // Custom ID for `Unit` type objects
// No default case needed; Apollo handles other types automatically
}
// Implicitly returns `undefined` for types not handled above,
// so Apollo uses the default ID generation logic
},
}),
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
},
query: {
fetchPolicy: 'cache-first',
},
},
link: new SchemaLink({ schema })
})
}
/*
This is a zero-config option method (and the main export)
where you can generate a GraphQL Apollo Client
and have all configuration handled internally for you.
It is intended for the less advanced/customized use cases,
but still offers basic levels of configuration.
*/
async function connect(options: ClientOptions = {}) {
let bindSchemaOptions: BindSchemaOptions
// autodetect `CellId`s if the config is missing some of the necessary values
// also autodetect `conductorUri` `adminConductorUri` and `appID` since the caller can leave those undefined
// in the options object (and pass them instead from either
// environment variables or introspected from the Holochain Launcher)
if (!options.dnaConfig || !options.conductorUri || !options.adminConductorUri || !options.appID) {
let { dnaConfig, conductorUri, adminConductorUri, appId } = await autoConnect(
options.weaveAppAgentClient,
options.conductorUri,
options.adminConductorUri,
options.appID,
// traceAppSignals needs to be passed during
// the first initialization of the AppWebsocket
options.traceAppSignals
)
bindSchemaOptions = {
...options,
weaveAppAgentClient: options.weaveAppAgentClient,
dnaConfig,
conductorUri,
adminConductorUri,
appId,
}
} else {
// the difference between BindSchemaOptions and ClientOptions
// is that for BindSchemaOptions `dnaConfig` and `conductorUri` must
// be defined, and in this logical branch
// we've established that, making this a safe
// type cast
bindSchemaOptions = {
...options as BindSchemaOptions
}
}
return await initGraphQLClient(bindSchemaOptions)
}
export default connect