Skip to content

Commit ffcf2a6

Browse files
committed
feat: providers section longer
1 parent 297d3b5 commit ffcf2a6

File tree

4 files changed

+218
-7
lines changed

4 files changed

+218
-7
lines changed

docs/pages/providers.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ The entry point of Polkadot-API, `createClient(provider)` requires one `JsonRpcP
44

55
```ts
66
interface JsonRpcProvider {
7-
(onMessage: (message: string) => void) => JsonRpcConnection;
7+
(onMessage: (message: string) => void) => JsonRpcConnection;
88
}
99

1010
interface JsonRpcConnection {
11-
send: (message: string) => void;
12-
disconnect: () => void;
11+
send: (message: string) => void;
12+
disconnect: () => void;
1313
}
1414
```
1515

1616
Calling it will initiate a connection. Messages coming from the service will come through the `onMessage` call, and the returned connection handle can be used to send messages or terminate the connection.
1717

1818
Polkadot-API offers a couple of providers for some of the most used ways of connecting to a chain:
1919

20-
- `getWsProvider(uri: string)` from `polkadot-api/ws-provider/web` or `polkadot-api/ws-provider/node` to connect through WebSocket.
21-
- `getSmProvider(chain: smoldot.Chain)` from `polkadot-api/sm-provider` to connect through Smoldot.
20+
- [`getWsProvider`](/providers/ws) from `polkadot-api/ws-provider/web` or `polkadot-api/ws-provider/node` (depending on where your code is running) to connect through WebSocket.
21+
- [`getSmProvider`](/providers/sm) from `polkadot-api/sm-provider` to connect through Smoldot.
2222

23-
The `JsonRpcProvider` interface is designed so that it can be easily enhanced: You can wrap any JsonRpcProvider with another one that adds in more features, such as logging, statistics, or error recovery.
23+
The `JsonRpcProvider` interface is designed so that it can be easily enhanced: You can wrap any JsonRpcProvider with another one that adds in more features, such as logging, statistics, or error recovery. Let's see the two PAPI builtin providers in the next pages.
2424

2525
## Logs provider
2626

docs/pages/providers/sm.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
## Smoldot provider
2+
3+
We love light-clients, and smoldot is our favorite way to connect to networks!
4+
5+
Smoldot can be instantiated from PAPI using both the main thread or a worker. We strongly recommend using workers for it.
6+
7+
## Instantiation
8+
9+
### Main thread
10+
11+
This is the easiest way of them all of instantiating smoldot. It blocks the main thread and it might have some performance issues:
12+
13+
```ts
14+
import { start } from "polkadot-api/smoldot"
15+
16+
const smoldot = start()
17+
```
18+
19+
### WebWorker
20+
21+
[WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) are available in modern browser environments and [Bun](https://bun.sh). Having smoldot in a worker allows the main thread to be free to perform other tasks, since smoldot might block the main thread in some demanding tasks.
22+
23+
Different bundlers have slightly different ways of creating workers, let's see them.
24+
25+
- Vite:
26+
27+
This option is only guaranteed to work on Vite, but might work on other bundlers.
28+
29+
```ts
30+
import { startFromWorker } from "polkadot-api/smoldot/from-worker"
31+
import SmWorker from "polkadot-api/smoldot/worker?worker"
32+
33+
const smoldot = startFromWorker(new SmWorker())
34+
```
35+
36+
- Bun
37+
38+
This option is safer than the previous one and could work in other bundlers as well.
39+
40+
```ts
41+
import { startFromWorker } from "polkadot-api/smoldot/from-worker"
42+
43+
const smWorker = new Worker(import.meta.resolve("polkadot-api/smoldot/worker"))
44+
const smoldot = startFromWorker(smWorker)
45+
```
46+
47+
- Webpack
48+
49+
This option is the safest and should work in (almost) every bundler.
50+
51+
```ts
52+
import { startFromWorker } from "polkadot-api/smoldot/from-worker"
53+
54+
const smWorker = new Worker(
55+
new URL("polkadot-api/smoldot/worker", import.meta.url),
56+
)
57+
const smoldot = startFromWorker(smWorker)
58+
```
59+
60+
## Adding a chain
61+
62+
Once we have an instance of smoldot, we need to tell smoldot to connect to the chain we want. For that, we need the `chainSpec` of the chain. With `polkadot-api` we bundle chainspecs for certain well-known chains. We try to keep all 5 relay chains (Polkadot, Kusama, Westend, Paseo, and Rococo) and its system chains.
63+
64+
In order to add a solo-chain (or a relay chain), it is very simple:
65+
66+
```ts
67+
import { chainSpec } from "polkadot-api/chains/polkadot"
68+
69+
const polkadotChain: Promise<Chain> = smoldot.addChain({ chainSpec })
70+
```
71+
72+
In case it is a parachain, we will need both the `chainSpec` of the relay chain, and the parachain one. It is simple as well:
73+
74+
```ts
75+
import { polkadot, polkadot_asset_hub } from "polkadot-api/chains"
76+
77+
// without async-await
78+
const assetHubChain: Promise<Chain> = smoldot
79+
.addChain({ chainSpec: polkadot })
80+
.then((relayChain) =>
81+
smoldot.addChain({
82+
chainSpec: polkadot_asset_hub,
83+
potentialRelayChains: [relayChain],
84+
}),
85+
)
86+
87+
// or with an async-await structure:
88+
const assetHubChain: Promise<Chain> = smoldot.addChain({
89+
chainSpec: polkadot_asset_hub,
90+
potentialRelayChains: [await smoldot.addChain({ chainSpec: polkadot })],
91+
})
92+
```
93+
94+
## Getting the provider and initializing the client
95+
96+
Once we have a `Chain` (or `Promise<Chain>`), we can initialize the provider and the client.
97+
98+
```ts
99+
import { createClient } from "polkadot-api"
100+
import { getSmProvider } from "polkadot-api/sm-provider"
101+
102+
const chain = smoldot.addChain({ chainSpec })
103+
// no need to await!
104+
const provider = getSmProvider(chain)
105+
106+
const client = createClient(provider)
107+
```

docs/pages/providers/ws.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# WS Provider
2+
3+
The WS provider enables PAPI to interact with JSON-RPC servers via WebSocket connection, generally Polkadot-SDK based nodes that include a JSON-RPC server. This provider is an special one, since its shape extends `JsonRpcProvider` and has some extra goodies. First of all, let's see its shape:
4+
5+
```ts
6+
interface WsJsonRpcProvider extends JsonRpcProvider {
7+
switch: (uri?: string, protocol?: string[]) => void
8+
getStatus: () => StatusChange
9+
}
10+
11+
interface GetWsProvider {
12+
(
13+
uri: string,
14+
protocols?: string | string[],
15+
onStatusChanged?: (status: StatusChange) => void,
16+
): WsJsonRpcProvider
17+
(
18+
uri: string,
19+
onStatusChanged?: (status: StatusChange) => void,
20+
): WsJsonRpcProvider
21+
(
22+
endpoints: Array<string | { uri: string; protocol: string[] }>,
23+
onStatusChanged?: (status: StatusChange) => void,
24+
): WsJsonRpcProvider
25+
}
26+
```
27+
28+
In order to create the provider, there are three overloads for it. In a nutshell, one can pass one (or more) websocket `uri`s with its optional supported protocols. For example:
29+
30+
```ts
31+
import { getWsProvider } from "polkadot-api/ws-provider/web"
32+
33+
// one option
34+
getWsProvider("wss://myws.com")
35+
36+
// two options
37+
getWsProvider(["wss://myws.com", "wss://myfallbackws.com"])
38+
```
39+
40+
Passing more than one allows the provider to switch in case one particular websocket is down or has a wrong behavior. Besides that, the consumer can also force the switch with the exposed `switch` method, where they can specify optionally which socket to use instead.
41+
42+
## Connection status
43+
44+
The provider also has a `getStatus` method that it returns the current status of the connection. Let's see it:
45+
46+
```ts
47+
enum WsEvent {
48+
CONNECTING,
49+
CONNECTED,
50+
ERROR,
51+
CLOSE,
52+
}
53+
type WsConnecting = {
54+
type: WsEvent.CONNECTING
55+
uri: string
56+
protocols?: string | string[]
57+
}
58+
type WsConnected = {
59+
type: WsEvent.CONNECTED
60+
uri: string
61+
protocols?: string | string[]
62+
}
63+
type WsError = {
64+
type: WsEvent.ERROR
65+
event: any
66+
}
67+
type WsClose = {
68+
type: WsEvent.CLOSE
69+
event: any
70+
}
71+
type StatusChange = WsConnecting | WsConnected | WsError | WsClose
72+
```
73+
74+
- `CONNECTING`: The connection is still being opened. It includes which socket and protocols is trying to connect to.
75+
- `CONNECTED`: The connection has been established and is currently open. It includes which socket and protocols is trying to connect to.
76+
- `ERROR`: The connection had an error. The provider will try to reconnect to other websockets (if available) or the same one. It includes the event sent by the server.
77+
- `CLOSE`: The connection closed. If the server was the one closing the connection, the provider will try to reconnect to other websockets (if available) or the same one. It includes the event sent by the server.
78+
79+
`provider.getStatus()` returns the current status.
80+
81+
When creating the provider, the consumer can pass a callback that will be called every time the status changes:
82+
83+
```ts
84+
const provider = getWsProvider("wss://myws.com", (status) => {
85+
switch (status.type) {
86+
case WsEvent.CONNECTING:
87+
console.log("Connecting... 🔌")
88+
break
89+
case WsEvent.CONNECTED:
90+
console.log("Connected! ⚡")
91+
break
92+
case WsEvent.ERROR:
93+
console.log("Errored... 😢")
94+
break
95+
case WsEvent.CLOSE:
96+
console.log("Closed 🚪")
97+
break
98+
}
99+
})
100+
```

vocs.config.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ export default defineConfig({
2020
},
2121
{
2222
text: "Providers",
23-
link: "/providers",
23+
items: [
24+
{ text: "Providers", link: "/providers" },
25+
{ text: "WebSocket", link: "/providers/ws" },
26+
{ text: "Smoldot", link: "/providers/sm" },
27+
],
2428
},
2529
{
2630
text: "Codegen",

0 commit comments

Comments
 (0)