-
-
Notifications
You must be signed in to change notification settings - Fork 1
UserInterface Implementation
As of tag v0.3.0-ui-4
on Feb 1, 2023.
This WILL change rapidly, and this document will be out of date within weeks.
A UserInterface
is an interface that species a number of methods that are called during either the login
or transact
calls on a Session.
/**
* Interface which a [[UserInteface]] plugins must implement.
*/
export interface UserInterface {
// Inform the UI that a login call has started
onLogin: (options?: LoginOptions) => void
// Inform the UI that a login call has completed
onLoginResult: () => void
// Ask the user to select a blockchain, and return the chain id
onSelectChain: (context: LoginContext) => Promise<Checksum256>
// Ask the user to select an account, and return the PermissionLevel
onSelectPermissionLevel: (context: LoginContext) => Promise<PermissionLevel>
// Ask the user to select a wallet, and return the index based on the metadata
onSelectWallet: (context: LoginContext) => Promise<number>
// Inform the UI that a transact call has started
onTransact: (context: TransactContext) => void
// Inform the UI that a transact call has completed
onTransactResult: (context: TransactResult) => void
// Update the displayed modal status from a TransactPlugin
status: (message: string) => void
}
The LoginContext
is passed to many of the .login()
calls to provide information to the UI about the login process and facilitate decision making.
/**
* Temporary context created for the duration of a [[Kit.login]] call.
*
* This context is used to store the state of the login request and
* provide a way for plugins to add hooks into the process.
*/
export class LoginContext {
// client: APIClient
chain: ChainDefinition
chains: ChainDefinition[] = []
hooks: LoginHooks = {
afterLogin: [],
beforeLogin: [],
}
ui: UserInterface
walletPlugins: WalletPluginMetadata[] = []
constructor(options: LoginContextOptions) {
// this.client = options.client
if (options.chains) {
this.chains = options.chains
}
this.chain = options.chain || this.chains[0]
this.walletPlugins = options.walletPlugins || []
this.ui = options.ui
// options.loginPlugins?.forEach((plugin: AbstractLoginPlugin) => {
// plugin.register(this)
// })
}
addHook(t: LoginHookTypes, hook: LoginHook) {
this.hooks[t].push(hook)
}
}
Just like the LoginContext
being used in .login()
calls, the TransactContext
is used in the .transact()
calls to facilitate UI interactions during a transaction.
/**
* Temporary context created for the duration of a [[Session.transact]] call.
*
* This context is used to store the state of the transact request and
* provide a way for plugins to add hooks into the process.
*/
export class TransactContext {
readonly abiProvider: AbiProvider
readonly client: APIClient
readonly fetch: Fetch
readonly hooks: TransactHooks = {
afterBroadcast: [],
afterSign: [],
beforeSign: [],
}
readonly permissionLevel: PermissionLevel
readonly transactPluginsOptions: TransactPluginsOptions
readonly ui: UserInterface
constructor(options: TransactContextOptions) {
this.abiProvider = options.abiProvider
this.client = options.client
this.fetch = options.fetch
this.permissionLevel = options.permissionLevel
this.transactPluginsOptions = options.transactPluginsOptions || {}
this.ui = options.ui
options.transactPlugins?.forEach((plugin: AbstractTransactPlugin) => {
plugin.register(this)
})
}
get accountName(): Name {
return this.permissionLevel.actor
}
get permissionName(): Name {
return this.permissionLevel.permission
}
get esrOptions(): SigningRequestEncodingOptions {
return {
abiProvider: this.abiProvider,
zlib,
}
}
addHook(t: TransactHookTypes, hook: TransactHook) {
this.hooks[t].push(hook)
}
async resolve(request: SigningRequest, expireSeconds = 120): Promise<ResolvedSigningRequest> {
// TODO: Cache the info/header first time the context resolves?
// If multiple plugins resolve the same request and call get_info, tapos might change
const info = await this.client.v1.chain.get_info()
const header = info.getTransactionHeader(expireSeconds)
// Load ABIs required to resolve this request
const abis = await request.fetchAbis(this.abiProvider)
// Resolve the request and return
return request.resolve(abis, this.permissionLevel, header)
}
}
This class implements UserInterface
and primarily just adds some potential logging for testing purposes. It also serves as an example of how the interface above can be implemented.
export class UserInterfaceHeadless implements UserInterface {
public consoleLog = false
public messages: string[] = []
public log(message: string) {
if (this.consoleLog) {
// eslint-disable-next-line no-console
console.info('UserInterfaceHeadless', message)
}
}
onLogin(options?: LoginOptions) {
this.log('onLogin: ' + JSON.stringify(options))
}
onLoginResult() {
this.log('onLoginResult')
}
public async onSelectPermissionLevel(context: LoginContext): Promise<PermissionLevel> {
throw new Error('The headless user interface does not support permission selection')
}
public async onSelectChain(context: LoginContext): Promise<Checksum256> {
throw new Error('The headless user interface does not support chain selection')
}
public async onSelectWallet(context: LoginContext): Promise<number> {
throw new Error('The headless user interface does not support wallet selection')
}
public async onTransact(context: TransactContext) {
this.log('onTransact' + String(context.accountName))
}
public async onTransactResult(context: TransactResult) {
this.log('onTransactResult' + String(context.transaction))
}
public status(message: string) {
this.messages.push(message)
this.log(message)
}
}
https://github.com/wharfkit/web-ui-renderer
The Web UI Renderer is a prototype that takes these interfaces and implements them as a SvelteKit rendered HTML element. All of the UserInterface
methods are implemented here:
https://github.com/wharfkit/web-ui-renderer/blob/master/src/index.ts
In order to create elements on the page and react to the events happening within the SessionKit.
The web-ui-renderer package also has a live development mode that you can run after cloning down the repo:
yarn dev
This will serve the following static HTML project, which implements both the Session Kit and the Web UI Renderer.
https://github.com/wharfkit/web-ui-renderer/blob/master/test/public/index.html