diff --git a/src/account-creation.ts b/src/account-creation.ts index 69f61de..f53e68c 100644 --- a/src/account-creation.ts +++ b/src/account-creation.ts @@ -1,5 +1,7 @@ -import {Checksum256, Checksum256Type, NameType, PermissionLevel, PublicKey} from '@wharfkit/antelope' -import { LocaleDefinitions } from '.' +import {Checksum256Type, NameType, Struct, FetchProvider, APIClient} from '@wharfkit/antelope' +import {Logo} from '@wharfkit/common' +import type {ChainDefinition, Fetch, LocaleDefinitions} from '@wharfkit/common' +import {UserInterface} from '.' /** * The static configuration of an [[AccountCreationPlugin]]. @@ -9,58 +11,90 @@ export interface AccountCreationPluginConfig { * Indicates if the pp requires the user to manually select the blockchain to authorize against. */ requiresChainSelect: boolean - /** - * Indicates if the [[AccountCreationPlugin]] requires the user to select an account name to use from a list. - */ - requiresAccountNameSelect?: boolean /** * If set, indicates which blockchains are compatible with this [[AccountCreationPlugin]]. */ supportedChains?: Checksum256Type[] - /** - * Indicates the return url to be used to return users to the site after the account creation service is used. - */ - returnUrl?: string } /** - * The metadata of an [[AccountCreationPlugin]] for display purposes. + * The metadata of an [[AccountCreationPlugin]]. */ -export interface AccountCreationPluginMetadata { +@Struct.type('account_creation_plugin_metadata') +export class AccountCreationPluginMetadata extends Struct { /** * A display name for the account creation service that is presented to users. */ - name?: string + @Struct.field('string', {optional: true}) declare name?: string /** - * A wallet description to further identify the account creation service for users. + * A description to further identify the account creation service for users. */ - description?: string + @Struct.field('string', {optional: true}) declare description?: string /** * Account creation service branding. */ - logo?: string + @Struct.field(Logo, {optional: true}) declare logo?: Logo /** * Link to the homepage for the account creation service. */ - homepage?: string - /** - * The public key being used by the account creation plugin. - */ - publicKey?: PublicKey + @Struct.field('string', {optional: true}) declare homepage?: string + + static from(data) { + return new AccountCreationPluginMetadata({ + ...data, + logo: data.logo ? Logo.from(data.logo) : undefined, + }) + } } +/** + * Options for createAccount call. + **/ +export interface CreateAccountOptions { + chain?: ChainDefinition + chains?: ChainDefinition[] + accountName?: NameType +} /** - * The response for a login call of a [[WalletPlugin]]. + * The response for a createAccount call. */ -export interface AccountCreationPluginCreateResponse { - chain: Checksum256 - permissionLevel: PermissionLevel +export interface CreateAccountResponse { + chain: ChainDefinition + accountName: NameType } -interface AccountCreationContext { - chain: Checksum256 - accountName: NameType +export interface CreateAccountContextOptions { + appName?: NameType + // client: APIClient + chain?: ChainDefinition + chains?: ChainDefinition[] + fetch: Fetch + accountCreationPlugins?: AccountCreationPlugin[] + ui: UserInterface +} + +export class CreateAccountContext { + appName?: string + chain?: ChainDefinition + chains: ChainDefinition[] = [] + fetch: Fetch + ui: UserInterface + constructor(options: CreateAccountContextOptions) { + this.appName = String(options.appName) + if (options.chains) { + this.chains = options.chains + } + if (options.chain) { + this.chain = options.chain + } + this.fetch = options.fetch + this.ui = options.ui + } + + getClient(chain: ChainDefinition): APIClient { + return new APIClient({provider: new FetchProvider(chain.url, {fetch: this.fetch})}) + } } /** @@ -70,10 +104,12 @@ interface AccountCreationContext { export interface AccountCreationPlugin { /** A URL friendly (lower case, no spaces, etc) ID for this plugin - Used in serialization */ get id(): string + + /** A display name for the account creation service that is presented to users. */ + get name(): string + /** The [[SessionKit]] configuration parameters for this [[WalletPlugin]]. */ config: AccountCreationPluginConfig - /** The metadata for the [[WalletPlugin]] itself. */ - metadata: AccountCreationPluginMetadata /** Any translations this plugin requires */ translations?: LocaleDefinitions @@ -82,19 +118,19 @@ export interface AccountCreationPlugin { * * @param context The [[AccountCreationContext]] for the [[WalletPlugin]] to use. */ - create(context: AccountCreationContext): Promise + create(options: CreateAccountContext): Promise } /** * Abstract class which all 3rd party [[AccountCreation]] implementations may extend. */ -export abstract class AbstractAccounCreationPlugin implements AccountCreationPlugin { +export abstract class AbstractAccountCreationPlugin implements AccountCreationPlugin { config: AccountCreationPluginConfig = { requiresChainSelect: true, - requiresAccountNameSelect: true, } - metadata: AccountCreationPluginMetadata = {} + metadata: AccountCreationPluginMetadata = new AccountCreationPluginMetadata({}) translations?: LocaleDefinitions abstract get id(): string - abstract create(context: AccountCreationContext): Promise + abstract get name(): string + abstract create(options: CreateAccountOptions): Promise } diff --git a/src/index-module.ts b/src/index-module.ts index 0ac5a17..aeadb8f 100644 --- a/src/index-module.ts +++ b/src/index-module.ts @@ -6,3 +6,4 @@ export * from './transact' export * from './ui' export * from './utils' export * from './wallet' +export * from './account-creation' diff --git a/src/kit.ts b/src/kit.ts index 0a72247..284fe58 100644 --- a/src/kit.ts +++ b/src/kit.ts @@ -1,4 +1,4 @@ -import type {ChainDefinitionType, Fetch} from '@wharfkit/common' +import {ChainDefinition, type ChainDefinitionType, type Fetch} from '@wharfkit/common' import type {Contract} from '@wharfkit/contract' import { Checksum256, @@ -8,7 +8,6 @@ import { PermissionLevel, PermissionLevelType, } from '@wharfkit/antelope' -import {ChainDefinition} from '@wharfkit/common' import { AbstractLoginPlugin, @@ -29,20 +28,8 @@ import { import {WalletPlugin, WalletPluginLoginResponse, WalletPluginMetadata} from './wallet' import {UserInterface} from './ui' import {getFetch} from './utils' -import { AccountCreationPlugin } from './account-creation' +import {AccountCreationPlugin, CreateAccountOptions, CreateAccountResponse, CreateAccountContext} from './account-creation' -export interface CreateAccountOptions { - chain?: ChainDefinition | Checksum256Type - chains?: Checksum256Type[] - accountCreationPlugins?: AccountCreationPlugin[] - transactPlugins?: TransactPlugin[] - transactPluginsOptions?: TransactPluginsOptions -} - -export interface CreateAccountResult { - account: NameType - chain: Checksum256Type -} export interface LoginOptions { chain?: ChainDefinition | Checksum256Type @@ -171,14 +158,8 @@ export class SessionKit { /** * Request account creation. - * - * @mermaid - Account creation sequence diagram - * flowchart LR - * A((Create Account)) --> B{{"Hook(s): beforeCreateAccount"}} - * B --> C[Account Creation Plugin] - * C --> D[Session] */ - async createAccount(options?: CreateAccountOptions): Promise { + async createAccount(options?: CreateAccountOptions): Promise { try { if (this.accountCreationPlugins.length === 0) { throw new Error('No account creation plugins available.') @@ -191,7 +172,7 @@ export class SessionKit { title: 'Select an account creation service', elements: this.accountCreationPlugins.map((p) => ({ type: 'button', - label: p.metadata.name, + label: p.name, data: p.id, })), }) @@ -204,21 +185,49 @@ export class SessionKit { if (!accountCreationPlugin) { throw new Error('No account creation plugin selected.') } - - // Initialize the account creator object - const accountCreator = new AccountCreator({ - supportedChains: accountCreationPlugin.config.supportedChains, - scope: 'wallet', - returnUrl: accountCreationPlugin.config.returnUrl, + + let chain: ChainDefinition | undefined + + const chains: ChainDefinition[] = + (options?.chains || this.chains).filter(c => { + return accountCreationPlugin?.config.supportedChains?.find(supportedChainId => c.id.equals(supportedChainId)) + }) + + if (options?.chain) { + chain = options?.chain + } else if (chains.length === 1) { + chain = chains[0] + } else if (accountCreationPlugin.config.requiresChainSelect && chains.length > 1) { + const chainIndex = await this.ui.prompt({ + title: 'Select a chain to create an account on', + elements: chains.map((c, index) => ({ + type: 'button', + label: c.name, + data: index, + })), + }) + + console.log({ chainIndex }) + + chain = chains[chainIndex as number] + } + + const createAccountContext = new CreateAccountContext({ + appName: this.appName, + chain, + chains, + fetch: this.fetch, + accountCreationPlugins: this.accountCreationPlugins, + ui: this.ui, }) - // Open a popup window prompting the user to create an account. - return accountCreator.createAccount() + return accountCreationPlugin.create(createAccountContext) } catch (error: any) { await this.ui.onError(error) throw new Error(error) } } + /** * Request a session from an account. *