Keyless Extension Framework

Overview

The keyless extension is written in YAML format which defines the structure and configuration of a keyless extension.

Extension App Schema

Properties
Key
Required
Type
Description
name
yes
string
The name of the plugin
version
yes
A version identifier for your code.
platformVersion
yes
A version identifier for the Keyless execution environment.
accounts
no
List of web3 accounts that can be made into signers
actions
no
List of actions supported by this extension. Can be a create, get, delete or custom action over a particular resource
events
no
List of events this extension produce. Events include filters and therefore can be made into triggers for a workflow or specific actions
hydrators
no
Hydrators are ways to get data external into your app, e.g for searches and lists
authentication
no
Choose what scheme your API uses for authentication.
agents
no
Agent Schema
Specify agent configuration

Accounts Schema


Represent the non custodial account scheme
Details
  • Type - object
Properties
Key
Required
visibility
Type
Description
name
no
owner(read, write) user (read)
string
name of the scheme. Defaults to accounts[i] where i is the index of the account in the accounts list
privateKey
no
owner (read) user (read, write)
string
A private key that can be made into a signer
NOTE: visibility field here means who can see the value and who can provide (write) the value of this field.

Agents Schema


Represent available autonomous agent to call
Details
  • Type - object
Properties
Key
Required
visibility
Type
Description
name
yes
owner(read, write) user (read)
string
name of the scheme. Defaults to accounts[i] where i is the index of the account in the accounts list
description
no
owner (read) user (read, write)
string
A private key that can be made into a signer
prompt
model
functions
NOTE: visibility field here means who can see the value and who can provide (write) the value of this field.

Authentication Schema


Represent the custodial (API) account (authentication) scheme
Details
  • Type - object
Properties
Key
Required
Type
Description
name
no
string
name of the scheme. Defaults to accounts[i] where i is the index of the account in the accounts list
type
yes
string in ('basic''custom''digest''oauth1''oauth2''session')
Choose which scheme you want to use.
test
yes
A function or request that confirms the authentication is working.
fields
no
Fields you can request from the user before they connect your app to Keyless.

Actions Schema


Enumerates the actions your app has available for users.
Details
  • Type - object
Properties
Key
Required
Type
Description
^[a-zA-Z]+[a-zA-Z0-9_]*$
no
Any unique key can be used and its values will be validated against the Keyless Extension FrameworkKeyless Extension Framework .
Example
yaml
actions: createItem: display: label: "Create Item" description: "Creates a new item" handler: actor: require: "./path/to/file.js"

Action Schema


Definition of an action
Details
  • Type - object
Properties
Key
Required
Type
Description
key
yes
string
A key to uniquely identify this action
inputs
no
What should the form a user sees and configures look like?
outputs
no
What fields of data will this return?
display
yes
Configures the UI for this action.
handler
yes
Powers the functionality for this action
use_account
no
array [ string ]
if to give this action access to accounts
use_auth
no
boolean
if this action can requires authentication

Display Schema


Represents user visible informations for an action
Details
  • Type - object
Properties
Key
Required
Type
Description
label
yes
string
A short label like "New Record" or "Create Record in Project".
description
yes
string
A description of what this action does.

Handler Schema


Represents the fundamental mechanics of a create.
Details
  • Type - object
Properties
Key
Required
Type
Description
input
no
What should the form a user sees and configures look like?
output
no
What fields of data will this return?
type
yes
string in “function” | “contract” | “http”
type of handler
actor
yes
The function / endpoint the keyless execution engine will call when a workflow makes use of this action
concurrent
no
boolean
if this action can be invoked concurrently or a lock should should be applied

Dynamic Fields Schema


Represents an array of fields or functions. Like field schema but you can provide functions to create dynamic fields
Details
Example
yaml
DynamicFieldsSchema: - key: "Field1" label: "Field1" - require: "./some/path/to/file.js"

Events Schema


Represents an array of event produced by this extension.
Details
Example

Event Schema


Represent an event produced by an extension.
Details
  • Type - object
Properties
Key
Required
Type
Description
key
yes
string
A key to uniquely identify this event
matcher
no
string
a dot notation expression conveying which key of the input data object should be used as an identifier to match the event key.
input
no
What values are gonna be sent with
display
yes
Configures the UI for this action.
handler
yes
what should happen when there’s a new event
filter
no
string
an expression to filter out certain events based on specific conditions
subscribe
no
a call to subscribe to the web-hook event with this key
unsubscribe
no
a call to unsubscribe from the web-hook event with this key
Example
yaml
Events: key: NewDeposit matcher: "handler.input.data.eventType" display: label: "New Deposit Event" description: "This webhook event is produced whenever there's a new deposit" filter: "input.data.address == handler.input.data.fromAddress" subscribe: require: "./path/to/subscribe.js" unsubscribe: require: "./path/to/unsubscribe.js" handler: actor: require: "./path/to/actor.js" concurrent: false # or user can implement some distributed locking mechanism to avoid processing a single event multiple times

Hydrators Schema


List of hydrators to get data into the app.
Details
Example
yaml
Hydrators: - key: getAllWallets actor: require: "./path/to/actor.js" - key: getAllVaults actor: require: "./path/to/other/actor.js"

Request Schema


A representation of a HTTP request - you can use the {{syntax}} to inject authentication, field or global variables.
Details
  • Type - object
Properties
Key
Required
Type
Description
method
no
string in ('GET''PUT''POST''PATCH''DELETE''HEAD')
The HTTP method for the request.
url
yes
string
A URL for the request (we will parse the querystring and merge with params). Keys and values will not be re-encoded.
body
no
oneOf(nullstringobjectarray)
Can be nothing, a raw string or JSON (object or array).
params
no
A mapping of the query string - will get merged with any query params in the URL. Keys and values will be encoded.
headers
no
The HTTP headers for the request.
auth
no
oneOf(array[string],Keyless Extension FrameworkKeyless Extension Framework )
An object holding the auth parameters for OAuth1 request signing, like {oauth_token: 'abcd', oauth_token_secret: '1234'}. Or an array reserved (i.e. not implemented yet) to hold the username and password for Basic Auth. Like ['AzureDiamond', 'hunter2'].
Examples
yaml
RequestSchema: method: "GET" url: "https://ext.withkeyless.com" params: a: 1 b: 2 # OR RequestSchema: method: "POST" url: "https://ext.withkeyless.com" body: key1: 1 key2: 2 headers: header1: "some-value"

Function Schema


A primitive that accepts a reference to a function that has been deployed to Keyless environment and invokes the function
Details
  • Type - object
Properties
Key
Required
Type
Description
funcId
yes
string in $namespace.funcId
a unique id of a function to call along side the namespace
args
no
Inputs to be passed to the function call
deamon
no
boolean
defines if to treat this function as a deamon or call and wait for response. Useful for long running tasks
Examples
yaml
key: "$getItemsById"

Contract Call Schema


A keyless extension framework primitive that accepts contract configs (i.e contract address, abi.. etc) and invokes a specified method on the contract.
Details
  • Type - object
Properties
Key
Required
Type
Description
contractAddress
yes
`string`
address of the contract to call
method
yes
string
the contract method to invoke
args
no
arguments to this contract method call
value
no
number
the value to send along with the contract call
from
no
string
the caller of this contract
gasLimit
no
number
the gas Limit to use for this contract call
gasPrice
no
number
maxFeePerGas
no
number
maxPriorityFeePerGas
no
number
nonce
no
number
type
no
number
accessList
no
customData
no
ccipReadEnabled
no
boolean
This specifies if the CCIP read is enabled.
Examples
yaml
callContract: contractAddress: "0x..98" method: "transfer" args: amount: 10 to: "0x.."

FlatObjectSchema


An object whose values can only be primitives
Details
  • Type - object
Properties
Key
Required
Type
Description
{{string}}
no
anyOf(nullstringintegernumberboolean)
Any key may exist in this flat object as long as its values are simple.
Examples
yaml
FlatObjectSchema: string_value_key: "1" number_value_key: 2 decimal_value_key: 3.3 bool_value_key: false "some_string_key": "value"

Fields Schema


An array or collection of fields.
Details
Examples
yaml
FieldsSchema: - key: "Field1" label: "Field1" - key: "Field2" label: "Field2"

Field Schema


Defines a field an extension either needs as input, or gives as output. In addition to the requirements below, the following keys are mutually exclusive:
  • children & type
  • children & placeholder
  • children & helpText
Details
  • Type - object
Properties
Key
Required
Type
Description
key
yes
string
A unique machine readable key for this value (IE: "fname").
label
no
string
A human readable label for this value (IE: "First Name").
helpText
no
string
A human readable description of this value (IE: "The first part of a full name."). You can use Markdown.
type
no
string in ('string''text''integer''number''boolean''datetime''file''password''copy''code')
The type of this value. Use string for basic text input, text for a large, <textarea> style box, and code for a <textarea> with a fixed-width font. Field type of file will accept either a file object or a string. If a URL is provided in the string, Keyless will automatically make a GET for that file. Otherwise, a .txt file will be generated.
required
no
boolean
If this value is required or not.
placeholder
no
string
An example value that is not saved.
choices
no
An object of machine keys and human values to populate a static dropdown.
search
no
A reference to an hydrator that returns a list of items that can be used to power a dynamic search dropdown.
children
no
An array of child fields that define the structure of a sub-object for this field. Usually used for line items.
default
no
string
A default value.
dynamic
no
A reference to an hydrator that returns a list of items that can be used to power a dynamic search dropdown.
Example
yaml
FieldSchema: key: "Field1" label: "Field1"

Dynamic Input Schema


A object containing a reference to an hydrator and keys to map the hydrator data into a Keyless Extension FrameworkKeyless Extension Framework
Key
Required
Type
Description
hydrator
yes
an hydrator that provides data for this dynamic input. Must be an hydrator that returns and array of object
label_key
yes
string
the key to use as the choice label key
value_key
yes
string
the key to use as the choice label value

Dynamic Input Hydrator Schema


A object containing a reference to a dynamic hydrator
Key
Required
Type
Description
key
yes
a reference to a unique hydrator key
inputs
no
inputs to the hydrator
filter
no
boolean
if hydrator supports filtering

Field Choices Schema


A static dropdown of options. Which you use depends on your order and label requirements:
Need a label?
Does order matter
Table to Use
Yes
No
Object of value -> label
No
Yes
Array of Strings
Yes
Yes
Array of
Details
Examples
yaml
FieldChoicesSchema: a: '1' b: '2' c: '3' # OR FieldChoicesSchema: - "first" - "second" - "third"

Field Choice With Label Schema


An object describing a labeled choice in a static dropdown. Useful if the value a user picks isn't exactly what the workflow uses. For instance, when they click on a nickname, but the workflow uses the user's full name (image).
Details
  • Type - object
Properties
Key
Required
Type
Description
value
yes
string
The actual value that is sent into the Workflow. This is displayed as light grey text in the editor
label
yes
string
A human readable label for this value.
Example
yaml
FieldChoiceWithLabelSchema: label: "some_label" value: "some_value"

Hydrator Schema


A Keyless Extension FrameworkKeyless Extension Framework or Keyless Extension FrameworkKeyless Extension Framework that can be used to get data or list of data into the app.
Details
  • Type - object
Properties
Key
Required
Type
Description
key
yes
string
A unique identifier of this hydrator
actor
yes
The function / endpoint the keyless execution engine will call to get the required data
filter
no
boolean
if this is enabled, keyless will leave filtering items to the hydrator by passing a search value to it. otherwise, keyless will get all item and perform filtering from the UI. This can be useful in case of large lists where prefetching all items and filtering through from the UI may be sub-optimal
inputs
no
inputs to this hydrator

Ref Resource Schema


Reference a resource by key and the data it returns. In the format of: {resource_key}.{foreign_key}(.{human_label_key}).
Details
  • Type - string
  • Pattern - ^[a-zA-Z0-9_]+\.[a-zA-Z0-9_\s\[\]]+(\.[a-zA-Z0-9_\s\[\]]+(,[a-zA-Z0-9_\s\[\]]+)*)?$
Examples
  • 'hydrators.getListOfWallets'

Version Schema


Represents a simplified semver string, from 0.0.0 to 999.999.999.
Details
  • Type - string
  • Pattern - ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$
Examples
  • '1.0.0'
  • '2.11.3'
  • '999.999.999'
Anti-Examples
  • '1.0.0.0' - Must have only 2 periods
  • '1000.0.0' - Each number can be a maximum of 3 digits
  • 'v1.0.0' - No letters allowed
  • '1.0.0-beta' - undefined

Extension File Example


An example of what an extension file would typically look like. extension.yaml
yaml
# Meta name: "Transaction Sender" version: 1.0.0 platformVersion: 1.0.0 # Authentication accounts: - name: mainAccount authentication: - name: bitpowr type: api fields: - key: apiKey label: "Bitpowr API Key" required: true type: string # Actions actions: signMessageWithPrivateKey: inputs: - key: messageToSign label: "Message to sign" helpText: "Please provide the message you want to sign here" type: string required: true placeholder: "Message To Sign" - key: includeTimestamp label: "Include timestamp" helpText: "If to include timestamp in the signature. Can be useful to restrict the duration of validity of the signed message" choices: - "Yes" - "No" default: "No" display: label: "Sign Message With Private Key" description: "Sign a message with a provided key" handler: type: function actor: funcId: "$namespace.sign" outputs: - key: signedMessage label: "Signed Message" type: string required: true default: "" createWallet: use_auth: true inputs: - key: accountId label: "Account ID" type: string required: true dynamic: hydrator: getAccounts label_key: name label_value: accountId - key: asset label: "Asset Type" type: string required: true dynamic: hydrator: key: getAssetList inputs: - key: accountId value: ${{inputs.accountId}} label_key: name label_value: assetId - key: label label: "Label" type: string placeholder: "My Main Wallet" display: label: "Create Wallet" description: "Create a new wallet" handler: type: function actor: funcId: "$namespace.createWallet" transfer: use_account: - name: mainAccount inputs: - key: amount label: "Amount" type: number required: true - key: toAddress label: "To Address" type: string required: true display: label: "Transfer USDT" description: "Transfer usdt" handler: type: contract actor: contractAddress: "0x..98" method: "transfer" args: amount: 10 to: "0x.." # Events events: key: NewWallet matcher: "eventType" display: label: "New Wallet" description: "This event is produced when a new wallet is created." filter: ${{ evt.payload.accountId == "7f350a1c-a0f4-4920-ab18-5a89c8b596ce" }} subscribe: require: "./subscribe.js" deamon: true # this way we can subscribe to the event or just have a long polling logic in the subscribe function and run in the background unsubscribe: require: "./unsubscribe.js" # Hydrators hydrators: - key: getAccounts actor: require: "./get-accounts.js" - key: getAssetList inputs: - key: accountId type: string required: true actor: type: http config: url: "https://api.bitpowr.com/assets" method: GET params: page: 1 limit: 1000 # we wanna fetch all assets accountId: ${{ input.accountId }}