@substrate/connect-extension-protocol
Advanced tools
Comparing version
/** | ||
* `MessageFromManager` represents messages from the manager in the extension | ||
* background that are intended to be sent on to the `ExtensionProvider` in the | ||
* app. | ||
* @packageDocumentation | ||
* | ||
* This module contains the types and explanations of the communication | ||
* protocol between the JavaScript code embedded in a web page and the | ||
* substrate-connect extension. | ||
* | ||
* # Overview | ||
* | ||
* If a web page wants to use the features of the substrate-connect extension, | ||
* it must first check whether the extension is available by checking whether | ||
* there exists an element on the DOM whose `id` is equal to | ||
* {@link ToExtensionAddChain}. This DOM element is automatically inserted by | ||
* the extension when the page loads. | ||
* | ||
* If so, the web page can make use of the extension by sending messages on | ||
* its `window` by using `Window.postMessage`. These messages must conform to | ||
* the {@link ToExtension} interface defined below. | ||
* | ||
* The substrate-connect extension (more precisely, its content-script) listens | ||
* for "message" events (using `window.addEventListener("message", ...)`) and | ||
* replies by sending back messages using `Window.postMessage` as well. The | ||
* messages sent by the extension conform to the {@link ToApplication} | ||
* interface defined below. | ||
* | ||
* # Detailed usage | ||
* | ||
* In order to ask the substrate-connect extension to connect to a certain | ||
* chain, the web page must: | ||
* | ||
* - Randomly generate the so-called `chainId`, a string that will be used | ||
* to identify this specific chain connection during its lifetime. At least | ||
* 48 bits of entropy are recommended in order to avoid accidentally | ||
* generating the same string multiple times. | ||
* - Send a {@link ToExtensionAddChain} message (using `Window.postMessage`, | ||
* as explained in the previous section) containing this `chainid` and the | ||
* specification of the chain to connect to. | ||
* | ||
* Instead of a {@link ToExtensionAddChain} message, the web page can | ||
* alternatively send a {@link ToExtensionAddWellKnownChain} message and pass | ||
* a chain name recognized by the extension such as "polkadot" or "kusama", in | ||
* which case the extension will use the chain specification stored internally. | ||
* Doing so provides multiple advantages such as less bandwidth usage (as the | ||
* web page doesn't have to download the chain specification), and a faster | ||
* initialization as the extension is most likely already connected to that | ||
* chain. | ||
* | ||
* After a {@link ToExtensionAddChain} or a | ||
* {@link ToExtensionAddWellKnownChain} message has been sent, the extension | ||
* starts connecting to the chain, and later replies by sending back a | ||
* {@link ToApplicationChainReady} message in case of success, or a | ||
* {@link ToApplicationError} message in case of failure. This reply might | ||
* only be sent back after a few seconds or more, and the web page is | ||
* encouraged to display some kind of loading screen in the meanwhile. | ||
* | ||
* Note that the extension reserves the rights to stop supporting a chain that | ||
* used to be recognized by {@link ToExtensionAddWellKnownChain}. If the web | ||
* page has sent a {@link ToExtensionAddWellKnownChain} and receives back a | ||
* {@link ToApplicationError}, it should automatically fall back to | ||
* downloading the chain specification and sending a | ||
* {@link ToExtensionAddChain} instead. | ||
* | ||
* After a chain has been successfully initialized (i.e. a | ||
* {@link ToApplicationChainReady} message has been sent to the web page), the | ||
* web page can submit JSON-RPC requests and notifications to the chain client | ||
* by sending {@link ToExtensionRpc} messages. The chain client sends back | ||
* JSON-RPC responses and notifications using {@link ToApplicationRpc} | ||
* messages. | ||
* | ||
* Once a web page no longer wants to interface with a certain chain, it should | ||
* send a {@link ToExtensionRemoveChain} message to the extension in order for | ||
* resources to be de-allocated. | ||
* | ||
* At any point in time, the extension can send a {@link ToApplicationError} | ||
* message to indicate a critical problem with the chain or the extension that | ||
* prevents execution from continuing. This can include for example the | ||
* extension being disabled by the user, the underlying client crashing, a lack | ||
* of memory, etc. If that happens, the web page is encouraged stop using the | ||
* extension altogether. | ||
* | ||
* Note that if the extension sends a {@link ToApplicationError} message, | ||
* either before of after the chain is ready, the corresponding `chainId` is | ||
* immediately considered dead/removed, and the web page doesn't need to send | ||
* a {@link ToExtensionRemoveChain} message. | ||
*/ | ||
export interface MessageFromManager { | ||
/** Type of the message. Defines how to interpret the {@link payload} */ | ||
type: 'error' | 'rpc'; | ||
/** Payload of the message. Either a JSON encoded RPC response or an error message **/ | ||
payload: string; | ||
/** | ||
* `id` of the DOM elemeent automatically inserted by the extension when a web page loads. | ||
*/ | ||
export declare const DOM_ELEMENT_ID = "substrateConnectExtensionAvailable"; | ||
/** | ||
* Messages sent by the extension always conform to this interface. | ||
*/ | ||
export declare type ToApplication = ToApplicationHeader & (ToApplicationError | ToApplicationChainReady | ToApplicationRpc); | ||
/** | ||
* Header present in all messages sent by the extension. | ||
*/ | ||
interface ToApplicationHeader { | ||
/** | ||
* Messages sent by the extension are sent on the `window`, alongside with potentially | ||
* other messages that might be completely unrelated to substrate-connect. This `origin` field | ||
* indicates that this message indeed comes from the substrate-connect extension. | ||
*/ | ||
origin: "substrate-connect-extension"; | ||
} | ||
/** | ||
* ExtensionMessage represents messages sent via | ||
* `window.postMessage` from `ExtensionMessageRouter` to `ExtensionProvider` | ||
* as recieved by the `ExtensionProvider`. | ||
* Indicates that the given chain connection has encountered an error and can no longer continue. | ||
* | ||
* @remarks The browser wraps the message putting it in {@link data} | ||
* The chain is automatically considered as "dead". No {@link ToExtensionRemoveChain} message | ||
* needs to be sent. | ||
* | ||
* This message can happen either before or after a {@link ToApplicationChainReady} concerning | ||
* this chain has been sent. | ||
*/ | ||
export interface ExtensionMessage { | ||
data: ExtensionMessageData; | ||
interface ToApplicationError { | ||
type: "error"; | ||
chainId: string; | ||
/** | ||
* Human-readable message indicating the problem that happened. | ||
* | ||
* Note that, while this message is readable by a human, it is not meant to be displayed to | ||
* end users. The message itself can be rather cryptic, and is meant for developers to | ||
* understand the problem that happened. | ||
*/ | ||
errorMessage: string; | ||
} | ||
export interface ExtensionMessageData { | ||
/** origin is used to determine which side sent the message **/ | ||
origin: 'content-script'; | ||
/** message is telling the `ExtensionProvider` the port has been closed **/ | ||
disconnect?: boolean; | ||
/** message is the message from the manager to be forwarded to the app **/ | ||
message?: MessageFromManager; | ||
/** | ||
* Sent in response to a {@link ToExtensionAddChain} or {@link ToExtensionAddWellKnownChain} | ||
* message. Indicates that the given chain has a valid chain specification or name and is ready | ||
* to receive JSON-RPC requests. | ||
* | ||
* No {@link ToExtensionRpc} message must be sent before this message has been received. | ||
*/ | ||
interface ToApplicationChainReady { | ||
type: "chain-ready"; | ||
chainId: string; | ||
} | ||
/** | ||
* ExtensionListenHandler is a message handler type for receiving | ||
* `ProviderMessage` messages from the \@substrate/connect `ExtensionProvider` | ||
* in the extension. | ||
* JSON-RPC response or notification sent by the substrate-connect extension. | ||
*/ | ||
export declare type ExtensionListenHandler = (message: ProviderMessage) => void; | ||
interface ToApplicationRpc { | ||
type: "rpc"; | ||
chainId: string; | ||
jsonRpcMessage: string; | ||
} | ||
/** | ||
* extension provides strongly typed convenience wrappers around | ||
* the `window.postMessage` and `window.addEventListener` APIs used for | ||
* message passing on the extension side of communication. | ||
* Messages destined to the extension must conform to this interface. | ||
*/ | ||
export declare const extension: { | ||
/** send a message from the extension to the app **/ | ||
send: (message: ExtensionMessageData) => void; | ||
export declare type ToExtension = ToExtensionHeader & (ToExtensionAddChain | ToExtensionAddWellKnownChain | ToExtensionRpc | ToExtensionRemoveChain); | ||
/** | ||
* Header present in all messages destined to the extension. | ||
*/ | ||
interface ToExtensionHeader { | ||
/** | ||
* Listen to messages from the `ExtensionProvider` in the app sent to | ||
* the extension. | ||
* Messages destined to the extension are sent on the `window`, alongside with potentially | ||
* other messages that might be completely unrelated to substrate-connect. This `origin` field | ||
* indicates to the substrate-connect extension that this message is destined to it. | ||
*/ | ||
listen: (handler: ExtensionListenHandler) => void; | ||
}; | ||
origin: "substrate-connect-client"; | ||
} | ||
/** | ||
* ProviderMessage represents messages sent via `window.postMessage` from | ||
* `ExtensionProvider` to `ExtensionMessageRouter` as received by the extension. | ||
* Ask the extension to add a new connection to the chain with the given specification. | ||
*/ | ||
interface ToExtensionAddChain { | ||
type: "add-chain"; | ||
/** | ||
* Identifier for this chain used in all future messages concerning this chain. Allocated by | ||
* the sender of this message. It is recommended to generate this ID randomly, with at least | ||
* 48 bits of entropy. | ||
*/ | ||
chainId: string; | ||
/** | ||
* JSON document containing the specification of the chain. | ||
* | ||
* See the Substrate documentation for more information about the fields. | ||
* | ||
* Note that this specification is fully trusted. If an attacker can somehow alter this | ||
* specification, they can redirect the connection to a fake chain controlled by this attacker. | ||
* In other words, the role of the substrate-connect extension is to connect to the chain whose | ||
* specification is provided here, but not to have an opinion on whether this specification is | ||
* legitimate. | ||
*/ | ||
chainSpec: string; | ||
/** | ||
* List of `chainId`s of all chains that are part of the same trusted sandbox as the provided | ||
* chain specification. | ||
* | ||
* Set this to the list of all chains that are currently alive. | ||
* | ||
* If one of the chains isn't known by the extension, it gets silently removed from the array. | ||
* This is necessary in order to avoid race conditions, as the extension might have sent a | ||
* {@link ToApplicationError} message at the same time as this message has been sent. | ||
*/ | ||
potentialRelayChainIds: string[]; | ||
} | ||
/** | ||
* Ask the extension to add a new connection to the chain of the given name. | ||
* | ||
* @remarks The browser wraps the message putting it in {@link data} | ||
* The substrate-connect extension comes with some hardcoded chain names that applications can | ||
* connect to. This list of names isn't indicated here, as it can change over time. | ||
* | ||
* Because the extension reserves the right to remove support for a well-known chain in the future, | ||
* applications should fall back to {@link ToExtensionAddChain} if this well-known chain | ||
* connection fails. | ||
*/ | ||
export interface ProviderMessage { | ||
data: ProviderMessageData; | ||
} | ||
export interface ProviderMessageData { | ||
/** origin is used to determine which side sent the message **/ | ||
origin: 'extension-provider'; | ||
/** The name of the app to be used for display purposes in the extension UI **/ | ||
appName: string; | ||
/** The name of the blockchain network the app is talking to **/ | ||
interface ToExtensionAddWellKnownChain { | ||
type: "add-well-known-chain"; | ||
/** | ||
* Identifier for this chain used in all future messages concerning this chain. Allocated by | ||
* the sender of this message. It is recommended to generate this ID randomly, with at least | ||
* 48 bits of entropy. | ||
*/ | ||
chainId: string; | ||
/** | ||
* Name of the chain to connect to. | ||
*/ | ||
chainName: string; | ||
/** What action the `ExtensionMessageRouter` should take **/ | ||
action: 'forward' | 'connect' | 'disconnect'; | ||
/** The message the `ExtensionMessageRouter` should forward to the background **/ | ||
message?: MessageToManager; | ||
} | ||
/** | ||
* The message from the `ExtensionProvider` in the app that is intended to be | ||
* sent on to the manager in the extension background. | ||
* Send a JSON-RPC request concerning the given chain. | ||
* | ||
* Must not be sent before a {@link ToApplicationChainReady} message has been received. | ||
* | ||
* If the chain isn't known by the extension, this message is silently discarded. This is | ||
* necessary in order to avoid race conditions, as the extension might have sent a | ||
* {@link ToApplicationError} message at the same time as this message has been sent. | ||
*/ | ||
export interface MessageToManager { | ||
/** Type of the message. Defines how to interpret the {@link payload} */ | ||
type: 'associate' | 'rpc'; | ||
/** Payload of the message. Either a JSON encoded RPC response or the name of a network **/ | ||
payload: string; | ||
/** whether an RPC message is a subscription or not **/ | ||
subscription?: boolean; | ||
interface ToExtensionRpc { | ||
type: "rpc"; | ||
chainId: string; | ||
jsonRpcMessage: string; | ||
} | ||
/** | ||
* ProviderListenHandler is a message handler type for receiving | ||
* `ExtensionMessage` messages from the extension in the \@substrate/connect | ||
* `ExtensionProvider`. | ||
* Destroy the given chain. | ||
* | ||
* Applications are strongly encouraged to send this message when they don't need the given chain | ||
* anymore. | ||
* | ||
* If the chain isn't known by the extension, this message is silently discarded. This is | ||
* necessary in order to avoid race conditions, as the extension might have sent a | ||
* {@link ToApplicationError} message at the same time as this message has been sent. | ||
*/ | ||
export declare type ProviderListenHandler = (message: ExtensionMessage) => void; | ||
/** | ||
* provider provides properly typed convenience wrappers around the | ||
* `window.postMessage` and `window.addEventListener` APIs used for message | ||
* passing on the \@substrate/connect `ExtensionProvider` end of communication. | ||
*/ | ||
export declare const provider: { | ||
/** send a message from the app to the extension **/ | ||
send: (message: ProviderMessageData) => void; | ||
/** | ||
* Listen to messages from the `ExtensionMessageRouter` in the extension sent | ||
* to the app. | ||
*/ | ||
listen: (handler: ProviderListenHandler) => void; | ||
}; | ||
interface ToExtensionRemoveChain { | ||
type: "remove-chain"; | ||
chainId: string; | ||
} | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
/** | ||
* extension provides strongly typed convenience wrappers around | ||
* the `window.postMessage` and `window.addEventListener` APIs used for | ||
* message passing on the extension side of communication. | ||
* @packageDocumentation | ||
* | ||
* This module contains the types and explanations of the communication | ||
* protocol between the JavaScript code embedded in a web page and the | ||
* substrate-connect extension. | ||
* | ||
* # Overview | ||
* | ||
* If a web page wants to use the features of the substrate-connect extension, | ||
* it must first check whether the extension is available by checking whether | ||
* there exists an element on the DOM whose `id` is equal to | ||
* {@link ToExtensionAddChain}. This DOM element is automatically inserted by | ||
* the extension when the page loads. | ||
* | ||
* If so, the web page can make use of the extension by sending messages on | ||
* its `window` by using `Window.postMessage`. These messages must conform to | ||
* the {@link ToExtension} interface defined below. | ||
* | ||
* The substrate-connect extension (more precisely, its content-script) listens | ||
* for "message" events (using `window.addEventListener("message", ...)`) and | ||
* replies by sending back messages using `Window.postMessage` as well. The | ||
* messages sent by the extension conform to the {@link ToApplication} | ||
* interface defined below. | ||
* | ||
* # Detailed usage | ||
* | ||
* In order to ask the substrate-connect extension to connect to a certain | ||
* chain, the web page must: | ||
* | ||
* - Randomly generate the so-called `chainId`, a string that will be used | ||
* to identify this specific chain connection during its lifetime. At least | ||
* 48 bits of entropy are recommended in order to avoid accidentally | ||
* generating the same string multiple times. | ||
* - Send a {@link ToExtensionAddChain} message (using `Window.postMessage`, | ||
* as explained in the previous section) containing this `chainid` and the | ||
* specification of the chain to connect to. | ||
* | ||
* Instead of a {@link ToExtensionAddChain} message, the web page can | ||
* alternatively send a {@link ToExtensionAddWellKnownChain} message and pass | ||
* a chain name recognized by the extension such as "polkadot" or "kusama", in | ||
* which case the extension will use the chain specification stored internally. | ||
* Doing so provides multiple advantages such as less bandwidth usage (as the | ||
* web page doesn't have to download the chain specification), and a faster | ||
* initialization as the extension is most likely already connected to that | ||
* chain. | ||
* | ||
* After a {@link ToExtensionAddChain} or a | ||
* {@link ToExtensionAddWellKnownChain} message has been sent, the extension | ||
* starts connecting to the chain, and later replies by sending back a | ||
* {@link ToApplicationChainReady} message in case of success, or a | ||
* {@link ToApplicationError} message in case of failure. This reply might | ||
* only be sent back after a few seconds or more, and the web page is | ||
* encouraged to display some kind of loading screen in the meanwhile. | ||
* | ||
* Note that the extension reserves the rights to stop supporting a chain that | ||
* used to be recognized by {@link ToExtensionAddWellKnownChain}. If the web | ||
* page has sent a {@link ToExtensionAddWellKnownChain} and receives back a | ||
* {@link ToApplicationError}, it should automatically fall back to | ||
* downloading the chain specification and sending a | ||
* {@link ToExtensionAddChain} instead. | ||
* | ||
* After a chain has been successfully initialized (i.e. a | ||
* {@link ToApplicationChainReady} message has been sent to the web page), the | ||
* web page can submit JSON-RPC requests and notifications to the chain client | ||
* by sending {@link ToExtensionRpc} messages. The chain client sends back | ||
* JSON-RPC responses and notifications using {@link ToApplicationRpc} | ||
* messages. | ||
* | ||
* Once a web page no longer wants to interface with a certain chain, it should | ||
* send a {@link ToExtensionRemoveChain} message to the extension in order for | ||
* resources to be de-allocated. | ||
* | ||
* At any point in time, the extension can send a {@link ToApplicationError} | ||
* message to indicate a critical problem with the chain or the extension that | ||
* prevents execution from continuing. This can include for example the | ||
* extension being disabled by the user, the underlying client crashing, a lack | ||
* of memory, etc. If that happens, the web page is encouraged stop using the | ||
* extension altogether. | ||
* | ||
* Note that if the extension sends a {@link ToApplicationError} message, | ||
* either before of after the chain is ready, the corresponding `chainId` is | ||
* immediately considered dead/removed, and the web page doesn't need to send | ||
* a {@link ToExtensionRemoveChain} message. | ||
*/ | ||
export const extension = { | ||
/** send a message from the extension to the app **/ | ||
send: (message) => { | ||
window.postMessage(message, '*'); | ||
}, | ||
/** | ||
* Listen to messages from the `ExtensionProvider` in the app sent to | ||
* the extension. | ||
*/ | ||
listen: (handler) => { | ||
window.addEventListener('message', handler); | ||
} | ||
}; | ||
// READ THIS BEFORE MODIFYING ANYTHING BELOW | ||
// | ||
// This file contains the communication protocol between the web page and | ||
// extension. If you modify it, existing web pages will still continue to use | ||
// the previous version until they upgrade, which can take a long time. | ||
// Similarly, some users will still have versions of the extension installed | ||
// that use of the previous version of this protocol. If the modifications | ||
// to this protocol aren't done carefully, web pages might no longer being able | ||
// to talk to the extension, or worse: try to talk to the extension and | ||
// throw exceptions because their assumptions are violated. As such, be | ||
// extremely careful when doing modifications: either the modifications are | ||
// completely backwards-compatible, or an upgrade path must be carefully | ||
// planned. | ||
/** | ||
* provider provides properly typed convenience wrappers around the | ||
* `window.postMessage` and `window.addEventListener` APIs used for message | ||
* passing on the \@substrate/connect `ExtensionProvider` end of communication. | ||
* `id` of the DOM elemeent automatically inserted by the extension when a web page loads. | ||
*/ | ||
export const provider = { | ||
/** send a message from the app to the extension **/ | ||
send: (message) => { | ||
window.postMessage(message, '*'); | ||
}, | ||
/** | ||
* Listen to messages from the `ExtensionMessageRouter` in the extension sent | ||
* to the app. | ||
*/ | ||
listen: (handler) => { | ||
window.addEventListener('message', handler); | ||
} | ||
}; | ||
export const DOM_ELEMENT_ID = "substrateConnectExtensionAvailable"; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@substrate/connect-extension-protocol", | ||
"version": "0.3.0", | ||
"version": "1.0.0", | ||
"description": "Protocol for connect message passing with the extension", | ||
@@ -9,40 +9,9 @@ "main": "dist/index.js", | ||
"deep-clean": "yarn clean && rm -rf node_modules", | ||
"clean": "rm -rf dist/", | ||
"build": "tsc --build", | ||
"test": "echo \"No tests: this package is only types\"", | ||
"clean": "rm -rf dist/ tsconfig.tsbuildinfo", | ||
"build": "tsc -b", | ||
"test": "exit 0; #This package is only types", | ||
"lint": "yarn eslint . --ext .js,.ts" | ||
}, | ||
"author": "Parity Team <admin@parity.io>", | ||
"license": "GPL-3.0-only", | ||
"devDependencies": { | ||
"@typescript-eslint/parser": "^4.17.0", | ||
"eslint": "^7.21.0", | ||
"eslint-plugin-tsdoc": "^0.2.14", | ||
"typescript": "^4.2.3" | ||
}, | ||
"eslintConfig": { | ||
"root": true, | ||
"rules": { | ||
"@typescript-eslint/restrict-template-expressions": "off", | ||
"tsdoc/syntax": "warn" | ||
}, | ||
"parser": "@typescript-eslint/parser", | ||
"settings": {}, | ||
"plugins": [ | ||
"@typescript-eslint", | ||
"eslint-plugin-tsdoc" | ||
], | ||
"parserOptions": { | ||
"project": "./tsconfig.json", | ||
"createDefaultProgram": true | ||
}, | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:@typescript-eslint/recommended-requiring-type-checking" | ||
], | ||
"env": { | ||
"browser": true | ||
} | ||
} | ||
"license": "GPL-3.0-only" | ||
} |
# @substrate/connect-extension-protocol | ||
This is a module consisting (almost) only of types. These types are the types | ||
of the messages passed between apps using `@substrate/connect` and the browser | ||
extension. The package is shared between `@substrate/connect` and the | ||
extension. It exports wrappers to the `window.postMessage` API to be used on | ||
either side of the communication to have the typescript compiler enforce the | ||
contract between them. | ||
## Making and publishing | ||
If you make changes to this package. You **must** publish this package to npm | ||
before publishing `@substrate/connect` or the extension. | ||
of the messages exchanged between apps using `@substrate/connect` and the | ||
browser extension. This package is shared between `@substrate/connect` and the | ||
extension in order for the TypeScript compiler to enforce the contract between | ||
them. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
56593
508.79%0
-100%8
14.29%348
152.17%1
-66.67%8
-42.86%2
Infinity%