diff --git a/README.md b/README.md index 90d7807956..b285bbaacc 100644 --- a/README.md +++ b/README.md @@ -41,8 +41,8 @@ To get started - 3. Ensure that you have a recent version of Yarn, for development purposes [Yarn >=1.3.2](https://yarnpkg.com/docs/install) is required. 4. Install the dependencies by running `yarn` 5. Build the API Docs, via `yarn run build` -5. Ready! Now you can launch the API Docs, via `yarn gitbook serve` -6. Access the API Docs via [http://localhost:4000](http://localhost:4000) +6. Ready! Now you can launch the API Docs, via `yarn gitbook serve` +7. Access the API Docs via [http://localhost:4000](http://localhost:4000) ## tutorials diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index a8e1d68f6e..d90af1bf54 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -7,6 +7,11 @@ - [HttpProvider](rpc-provider/classes/_http_index_.httpprovider.md) - [WsProvider](rpc-provider/classes/_ws_index_.wsprovider.md) +## Node Interfaces +- [RPC](METHODS_RPC.md) +- [Storage chain state (runtime)](METHODS_STORAGE.md) +- [Extrinsics (runtime)](METHODS_EXTRINSICS.md) + ## Examples - [ApiPromise](examples/promise/README.md) diff --git a/package.json b/package.json index 6335fa8379..eae0a9ee2d 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,10 @@ "typescript": "^3.0.1" }, "scripts": { - "build": "polkadot-dev-build-ts && polkadot-dev-build-docs", + "build": "yarn run build:methodsdoc && polkadot-dev-build-ts && polkadot-dev-build-docs", "build:htmldoc": "yarn clean && typedoc --theme default --out docs/html", + "build:methodsdoc": "node packages/types/src/scripts/MetadataMdWrapper.js", + "build:decodedjson": "node packages/types/src/scripts/MetadataJsonDecodeWrapper.js", "check": "tslint --project . && tsc --noEmit", "clean": "polkadot-dev-clean-build", "postinstall": "polkadot-dev-yarn-only", @@ -25,6 +27,7 @@ "@polkadot/ts": "^0.1.30" }, "dependencies": { + "babel-plugin-module-resolver": "^3.1.1", "gitbook-plugin-include-codeblock": "^3.2.2", "gitbook-plugin-mermaid-gb3": "^2.1.0", "gitbook-plugin-sunlight-highlighter": "^0.4.3" diff --git a/packages/api/README.md b/packages/api/README.md index 2f5de34fb6..d6929dd0a1 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -4,22 +4,25 @@ The Polkadot-JS API provides easy-to-use wrappers around JSONRPC calls that flow The API wrappers provide a standard interface for use - -- A static `.create()` that returns an API istance when connected, decorated and ready-to use +- A static `.create()` that returns an API instance when connected, decorated and ready-to use - The above is just a wrapper for `new Api() `, exposing the `isReady` getter - `api.rpc.
.` provides access to actual RPC calls, be it for queries, submission or retrieving chain information + - [RPC (node interface)](../METHODS_RPC.md) - `api.query.
.` provides access to chain state queries. These are dynamically populated based on what the runtime provides -- `api.tx.
.` provides the ability to create transaction, like chain state, this list is populated from a runtime query + - [Storage chain state (runtime node interface)](../METHODS_STORAGE.md) +- `api.tx.
.` provides the ability to create a transaction, like chain state, this list is populated from a runtime query + - [Extrinsics (runtime node interface)](../METHODS_EXTRINSICS.md) ## API Selection There are two flavours of the API provided, one allowing a standard interface via JavaScript Promises and the second provides an Observable wrapper using [RxJS](https://github.com/ReactiveX/rxjs). Depending on your use-case and familiarity, you can choose either (or even both) for your application. -- [[ApiPromise]] All interface calls returns Promises, including the static `.create(...)`. Additionally any subscription method use `(value) => {}` callbacks, returning the value as the subscription is updated. -- [[ApiRx]] All interface calls return RxJS Observables, including the static `.create(...)`. In the same fashion and subscription-based methods return long-running Observables that update with the latest values. +- [[ApiPromise]] All interface calls returns Promises, including the static `.create(...)`. Additionally any subscription method uses `(value) => {}` callbacks, returning the value as the subscription is updated. +- [[ApiRx]] All interface calls return RxJS Observables, including the static `.create(...)`. In the same fashion subscription-based methods return long-running Observables that update with the latest values. ## Dynamic by default -Subtrate (on which Polkadot is built) used on-chain on-chain WASM runtimes, allowing for upgradability. Each runtime defining the actual chain extrinsics (submitted transactions and block intrinsics) as well as available entries in the chain state. Due to this, the API endpoints for queries and transactions are dynamically populated from the running chain. +Substrate (upon which Polkadot is built) uses on-chain WASM runtimes, allowing for upgradability. Each runtime defining the actual chain extrinsics (submitted transactions and block intrinsics) as well as available entries in the chain state. Due to this, the API endpoints for queries and transactions are dynamically populated from the running chain. Due to this dynamic nature, this API departs from traditional APIs which only has fixed endpoints, driving use by what is available by the runtime. As a start, this generic nature has a learning curve, although the provided documentation, examples and linked documentation tries to make that experience as seamless as possible. diff --git a/packages/rpc-provider/README.md b/packages/rpc-provider/README.md index 932c694953..6be0c2fc90 100644 --- a/packages/rpc-provider/README.md +++ b/packages/rpc-provider/README.md @@ -1,10 +1,10 @@ # @polkadot/rpc-provider -Generic transport providers to handle the transport of method calls to and from Polkadot clients from applications interacting with it. It provides an interface to making RPC class and is generally, unless you are operating at a low-level and taking care of encoding and decoding of parameters/results, it won't be directly used, rather only passed to a higher-level interface. +Generic transport providers to handle the transport of method calls to and from Polkadot clients from applications interacting with it. It provides an interface to making RPC calls and is generally, unless you are operating at a low-level and taking care of encoding and decoding of parameters/results, it won't be directly used, rather only passed to a higher-level interface. ## Provider Selection -There are two flavours of the providers provided, one allowing for using HTTP as a transport machanism, the other using WebSockets. It is generally recommended to use the [[WsProvider]] since in addition to standard calls, it allows for subscriptions where all changes to state can be pushed from the node to the client. +There are two flavours of the providers provided, one allowing for using HTTP as a transport mechanism, the other using WebSockets. It is generally recommended to use the [[WsProvider]] since in addition to standard calls, it allows for subscriptions where all changes to state can be pushed from the node to the client. Both providers are usable (as is the API), in both browser-based and Node.js environments. Polyfills for unsupported functionality are automatically applied based on feature-detection. diff --git a/packages/type-jsonrpc/README.md b/packages/type-jsonrpc/README.md index acd647a5be..d44358efd5 100644 --- a/packages/type-jsonrpc/README.md +++ b/packages/type-jsonrpc/README.md @@ -2,7 +2,7 @@ A definition of all the methods exposed in a general Polkadot client application. These are used not only to provide a comprehensive code-generated document of the available methods, but are also used in the API to auto-generate endpoints with the required type-checking. -For a list of currently exposed methods, see the [method documentation](docs/README.md). +For a list of currently exposed methods, see the [method documentation](docs/METHODS_RPC.md). ## Usage diff --git a/packages/type-jsonrpc/src/chain.ts b/packages/type-jsonrpc/src/chain.ts index e7d2caa866..2019becd01 100644 --- a/packages/type-jsonrpc/src/chain.ts +++ b/packages/type-jsonrpc/src/chain.ts @@ -40,7 +40,7 @@ const getHead: RpcMethodOpt = { }; const getRuntimeVersion: RpcMethodOpt = { - description: ' Get the runtime version', + description: 'Get the runtime version', params: [ createParam('hash', 'Hash', { isOptional: true }) ], diff --git a/packages/type-jsonrpc/src/index.ts b/packages/type-jsonrpc/src/index.ts index f393c0bcfd..a926ffac3d 100644 --- a/packages/type-jsonrpc/src/index.ts +++ b/packages/type-jsonrpc/src/index.ts @@ -2,12 +2,14 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. +import { RpcSection } from './types'; + import author from './author'; import chain from './chain'; import state from './state'; import system from './system'; -const interfaces = { +const interfaces: { [key: string]: RpcSection } = { author, chain, state, diff --git a/packages/types/babelConfig.js b/packages/types/babelConfig.js new file mode 100644 index 0000000000..ac9863dc5e --- /dev/null +++ b/packages/types/babelConfig.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +require('@babel/register')({ + extensions: ['.js', '.ts'], + plugins: [ + ['module-resolver', { + alias: { + '^@polkadot/types(.*)': './packages/types/src\\2' + } + }] + ] +}); diff --git a/packages/types/src/Metadata.spec.js b/packages/types/src/Metadata.spec.js index 0b84f7e049..f9dd2de6b5 100644 --- a/packages/types/src/Metadata.spec.js +++ b/packages/types/src/Metadata.spec.js @@ -8,7 +8,6 @@ import rpcdata from './Metadata.rpc'; describe('Metadata', () => { it('decodes properly', () => { const decoded = new Metadata().fromJSON(rpcdata); - const str = JSON.stringify(decoded.toJSON()); console.error(str); diff --git a/packages/types/src/scripts/METHODS_STORAGE_SUBSTRATE.md b/packages/types/src/scripts/METHODS_STORAGE_SUBSTRATE.md new file mode 100644 index 0000000000..374b0826c7 --- /dev/null +++ b/packages/types/src/scripts/METHODS_STORAGE_SUBSTRATE.md @@ -0,0 +1,26 @@ + +--- + +### substrate + +_These are keys that are always available to the runtime implementation_ + +▸ **code**(): `Bytes` +- **summary**: Wasm code of the runtime. + +▸ **heapPages**(): `u64` +- **summary**: Number of wasm linear memory pages required for execution of the runtime. + +▸ **authorityCount**(): `u32` +- **summary**: Number of authorities. + +▸ **authorityPrefix**(): `u32` +- **summary**: Prefix under which authorities are storied. + +▸ **extrinsicIndex**(): `u32` +- **summary**: Current extrinsic index (u32) is stored under this key. + +▸ **changesTrieConfig**(): `u32` +- **summary**: Changes trie configuration is stored under this key. + +--- diff --git a/packages/types/src/scripts/MetadataJsonDecode.ts b/packages/types/src/scripts/MetadataJsonDecode.ts new file mode 100644 index 0000000000..1478d94ec5 --- /dev/null +++ b/packages/types/src/scripts/MetadataJsonDecode.ts @@ -0,0 +1,29 @@ +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const fs = require('fs'); + +import Metadata from '../Metadata'; +import rpcdata from '../Metadata.rpc'; + +function metadataStringifyAsJson () { + const decoded = new Metadata().fromJSON(rpcdata); + + return JSON.stringify(decoded.toJSON(), null, 2); +} + +function writeToJson () { + const options = { encoding: 'ascii' }; + const writeStream = fs.createWriteStream('packages/types/src/Metadata.decoded.json', options); + + writeStream.write(metadataStringifyAsJson()); + + writeStream.on('finish', () => { + console.log('wrote all decoded metadata to JSON file'); + }); + + writeStream.end('\n'); +} + +writeToJson(); diff --git a/packages/types/src/scripts/MetadataJsonDecodeWrapper.js b/packages/types/src/scripts/MetadataJsonDecodeWrapper.js new file mode 100644 index 0000000000..c4af47e451 --- /dev/null +++ b/packages/types/src/scripts/MetadataJsonDecodeWrapper.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +require('../../babelConfig.js'); +require('./MetadataJsonDecode.ts'); diff --git a/packages/types/src/scripts/MetadataMd.ts b/packages/types/src/scripts/MetadataMd.ts new file mode 100644 index 0000000000..0db606eb1b --- /dev/null +++ b/packages/types/src/scripts/MetadataMd.ts @@ -0,0 +1,150 @@ +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const fs = require('fs'); +import { stringCamelCase, stringLowerFirst } from '@polkadot/util/string'; + +import interfaces from '../../../type-jsonrpc/src'; +import Metadata from '../Metadata'; +import rpcdata from '../Metadata.rpc'; +import Method from '../Method'; + +// some intro text goes in here +const DESC_RPC = '\n\n_The following RPC methods are the Remote Calls that are available by default and allow you to interact with the actual node, query, and submit. The RPCs are provided by Substrate itself. The RPCs are never exposed by the runtime._'; +const DESC_EXTRINSICS = '\n\n_The following Extrinsics methods are part of the default Substrate runtime. Since an Extrinsic is a holder of an object that is just an array of bytes to be included, it does not have a return._'; +const DESC_STORAGE = '\n\n_The following Storage methods are part of the default Substrate runtime._'; + +function addRpc () { + const renderHeading = `## JSON-RPC${DESC_RPC}\n`; + + return Object.keys(interfaces).reduce((md, sectionName) => { + const section = interfaces[sectionName]; + const renderSection = `${md}\n___\n\n### ${sectionName}\n\n_${section.description}_\n`; + + return Object.keys(section.methods).reduce((md, methodName) => { + const method = section.methods[methodName]; + const args = method.params.map(({ name, isOptional, type }) => { + return name + (isOptional ? '?' : '') + ': `' + type + '`'; + }).join(', '); + const type = '`' + method.type + '`'; + const isSub = method.isSubscription; + const renderMethod = `${md}\n▸ **${methodName}**(${args})`; + const renderReturnType = `: ${type}`; + const renderSignature = `${renderMethod}${renderReturnType}`; + const renderSignatureSub = `${renderMethod}**.subscribe**(CALLBACK)${renderReturnType}`; + const renderSummary = `${method && method.description ? `\n- **summary**: ${method.description}\n` : `\n\n`}`; + + return isSub ? `${renderSignatureSub}${renderSummary}` : `${renderSignature}${renderSummary}`; + }, renderSection); + }, renderHeading); +} + +function addExtrinsics (metadata: any) { + const renderHeading = `## Extrinsics${DESC_EXTRINSICS}`; + + return metadata.modules.reduce((md: string, meta: any) => { + if (!meta.module.call || !meta.module.call.functions.length) { + return md; + } + + const sectionName = stringCamelCase(meta.prefix.toString()); + const renderSection = `${md}\n___\n### ${sectionName}\n`; + + return meta.module.call.functions.reduce((md: string, func: any) => { + const methodName = stringCamelCase(func.name.toString()); + const args = Method.filterOrigin(func).map(({ name, type }) => `${name}: ` + '`' + type + '`').join(', '); + const doc = func.documentation.reduce((md: string, doc: string) => `${md} ${doc}`, ''); + const renderSignature = `${md}\n▸ **${methodName}**(${args})`; + const renderSummary = `${doc ? `\n- **summary**: ${doc}\n` : '\n'}`; + + return renderSignature + renderSummary; + }, renderSection); + }, renderHeading); +} + +function addStorage (metadata: any) { + const renderHeading = `## Storage${DESC_STORAGE}`; + + return metadata.modules.reduce((md: string, moduleMetadata: any) => { + if (!moduleMetadata.storage) { + return md; + } + + const sectionName = stringLowerFirst(moduleMetadata.storage.prefix.toString()); + const renderSection = `${md}\n___\n### ${sectionName}\n`; + + return moduleMetadata.storage.functions.reduce((md: string, func: any) => { + const methodName = stringLowerFirst(func.name.toString()); + const arg = func.type.isMap ? ('`' + func.type.asMap.key.toString() + '`') : ''; + const doc = func.documentation.reduce((md: string, doc: string) => `${md} ${doc}`, ''); + const renderSignature = `${md}\n▸ **${methodName}**(${arg}): ` + '`' + func.type + '`'; + const renderSummary = `${doc ? `\n- **summary**: ${doc}\n` : '\n'}`; + + return renderSignature + renderSummary; + }, renderSection); + }, renderHeading); +} + +function metadataStorageMethodsAsText () { + const metadata = new Metadata().fromJSON(rpcdata); + return addStorage(metadata); +} + +function metadataExtrinsicsMethodsAsText () { + const metadata = new Metadata().fromJSON(rpcdata); + return addExtrinsics(metadata); +} + +function writeToRpcMd () { + const options = { flags: 'w', encoding: 'utf8' }; + const writeStream = fs.createWriteStream('docs/METHODS_RPC.md', options); + + writeStream.write(addRpc()); + + writeStream.on('finish', () => { + console.log('wrote all rpc method metadata to Gitbook Markdown file'); + }); + + writeStream.end(); +} + +function writeToStorageMd () { + const optionsRead = { flags: 'r', encoding: 'utf8' }; + fs.readFile('packages/types/src/scripts/METHODS_STORAGE_SUBSTRATE.md', optionsRead, function read (err: Error, data: string) { + if (err) { + throw err; + } + + // 'utf8', 'ascii', 'binary', 'hex', 'base64', or 'utf16le' + const options = { flags: 'w', encoding: 'utf8' }; + const writeStream = fs.createWriteStream('docs/METHODS_STORAGE.md', options); + + writeStream.write(metadataStorageMethodsAsText()); + writeStream.write(data); + + // finish emitting event when all data flushed from stream + writeStream.on('finish', () => { + console.log('wrote all storage method metadata to Gitbook Markdown file'); + }); + + writeStream.end(); + }); +} + +function writeToExtrinsicsMd () { + const options = { flags: 'w', encoding: 'utf8' }; + const writeStream = fs.createWriteStream('docs/METHODS_EXTRINSICS.md', options); + + writeStream.write(metadataExtrinsicsMethodsAsText()); + + writeStream.on('finish', () => { + console.log('wrote all extrinsics method metadata to Gitbook Markdown file'); + }); + + writeStream.end(); +} + +writeToRpcMd(); +writeToStorageMd(); +writeToExtrinsicsMd(); diff --git a/packages/types/src/scripts/MetadataMdWrapper.js b/packages/types/src/scripts/MetadataMdWrapper.js new file mode 100644 index 0000000000..43eeea7468 --- /dev/null +++ b/packages/types/src/scripts/MetadataMdWrapper.js @@ -0,0 +1,7 @@ +#!/usr/bin/env node +// Copyright 2017-2018 @polkadot/types authors & contributors +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +require('../../babelConfig.js'); +require('./MetadataMd.ts');