import { grpc } from '@improbable-eng/grpc-web' ; import { Context , defaultHost } from '@textile/context' ; import { Identity } from '@textile/crypto' ; import { WebsocketTransport } from '@textile/grpc-transport' ; import { Client , CollectionConfig } from '@textile/threads-client' ; import * as pb from '@textile/threads-client-grpc/threads_pb' ; import * as api from '@textile/threads-client-grpc/threads_pb_service' ; import type { ThreadID } from '@textile/threads-id' ; export interface GrpcConfig { serviceHost : string ; transport : grpc . TransportFactory ; debug : boolean ; metadata : grpc . Metadata ; } export { CollectionConfig } ; export const defaults = { serviceHost : defaultHost , transport : WebsocketTransport ( ) , debug : false , metadata : new grpc . Metadata ( ) , } ; export function createClient ( opts = { } ) { const config = { ... defaults , ... opts } ; return new api . APIClient ( config . serviceHost , { transport : config . transport , debug : config . debug , } ) ; } export function createDbClient ( config = { } ) { const json = { } ; config . metadata ?. forEach ( ( key , values ) => ( json [ key ] = values ) ) ; const context = Object . keys ( json ) . length > 0 ? Context . fromJSON ( json , config . serviceHost ) : new Context ( config . serviceHost ) ; const client = new Client ( context ) ; return client ; } param identity param opts example export async function getToken ( identity , config ? ) { const opts = { ... defaults , ... config } ; return getTokenChallenge ( identity . public . toString ( ) , async ( challenge ) => { return identity . sign ( challenge ) ; } , opts ) ; } param publicKey param callback param config example export async function getTokenChallenge ( publicKey , callback , config ? ) { const opts = { ... defaults , ... config } ; const client = createClient ( opts ) ; const bidi = client . getToken ( opts . metadata ) ; return new Promise < string > ( ( resolve , reject ) => { let token = '' ; bidi . on ( 'data' , async ( message ) => { if ( message . hasChallenge ( ) ) { const challenge = message . getChallenge_asU8 ( ) ; const signature = await callback ( challenge ) ; const req = new pb . GetTokenRequest ( ) ; req . setSignature ( signature ) ; bidi . write ( req ) ; } else if ( message . hasToken ( ) ) { token = message . getToken ( ) ; bidi . end ( ) ; } } ) ; bidi . on ( 'end' , ( status ) => { if ( status ?. code === grpc . Code . OK ) { resolve ( token ) ; } else { reject ( new Error ( status ?. details ) ) ; } } ) ; const req = new pb . GetTokenRequest ( ) ; req . setKey ( publicKey ) ; bidi . write ( req ) ; } ) ; } export async function newDB ( name , threadID , collections , config ? ) { const opts = { ... defaults , ... config } ; const client = createClient ( opts ) ; const requestMessage = new pb . NewDBRequest ( ) ; requestMessage . setDbid ( threadID . toBytes ( ) ) ; requestMessage . setName ( name ) ; const collectionsList = [ ] ; for ( const collection of collections ) { const config = new pb . CollectionConfig ( ) ; config . setName ( collection . name ) ; config . setSchema ( collection . schema ) ; const indexesList = [ ] ; for ( const index of collection . indexes ?? [ ] ) { const idx = new pb . Index ( ) ; idx . setPath ( index . path ) ; idx . setUnique ( index . unique ) ; indexesList . push ( idx ) ; } config . setIndexesList ( indexesList ) ; collectionsList . push ( config ) ; } requestMessage . setCollectionsList ( collectionsList ) ; return new Promise < string > ( ( resolve , reject ) => { client . newDB ( requestMessage , opts . metadata ?? new grpc . Metadata ( ) , ( error , responseMessage ) => { if ( error ) reject ( new Error ( error . message ) ) ; const success = Boolean ( responseMessage ?. toObject ( ) ) ; const id = threadID . toString ( ) ; if ( success ) resolve ( id ) ; else reject ( new Error ( `Unable to create thread with id = ${ id }` ) ) ; } ) ; } ) ; }