smoldot 1.0.4 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +58 -0
  2. package/dist/cjs/bytecode-browser.d.ts +5 -0
  3. package/dist/cjs/bytecode-browser.js +42 -0
  4. package/dist/cjs/bytecode-deno.d.ts +5 -0
  5. package/dist/cjs/bytecode-deno.js +87 -0
  6. package/dist/cjs/bytecode-nodejs.d.ts +5 -0
  7. package/dist/cjs/bytecode-nodejs.js +41 -0
  8. package/dist/cjs/index-browser.d.ts +2 -2
  9. package/dist/cjs/index-browser.js +10 -507
  10. package/dist/cjs/index-deno.d.ts +2 -2
  11. package/dist/cjs/index-deno.js +10 -283
  12. package/dist/cjs/index-nodejs.d.ts +2 -2
  13. package/dist/cjs/index-nodejs.js +10 -211
  14. package/dist/cjs/internals/bytecode/wasm0.js +4 -0
  15. package/dist/cjs/internals/bytecode/wasm1.js +4 -0
  16. package/dist/cjs/internals/bytecode/wasm2.js +4 -0
  17. package/dist/cjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
  18. package/dist/cjs/internals/client.js +376 -0
  19. package/dist/cjs/internals/local-instance.d.ts +144 -0
  20. package/dist/cjs/internals/local-instance.js +566 -0
  21. package/dist/cjs/internals/remote-instance.d.ts +38 -0
  22. package/dist/cjs/internals/remote-instance.js +374 -0
  23. package/dist/cjs/no-auto-bytecode-browser.d.ts +11 -0
  24. package/dist/cjs/no-auto-bytecode-browser.js +481 -0
  25. package/dist/cjs/no-auto-bytecode-deno.d.ts +10 -0
  26. package/dist/cjs/no-auto-bytecode-deno.js +220 -0
  27. package/dist/cjs/no-auto-bytecode-nodejs.d.ts +10 -0
  28. package/dist/cjs/no-auto-bytecode-nodejs.js +189 -0
  29. package/dist/cjs/{client.d.ts → public-types.d.ts} +51 -3
  30. package/dist/cjs/public-types.js +76 -0
  31. package/dist/cjs/worker-browser.d.ts +11 -0
  32. package/dist/cjs/worker-browser.js +63 -0
  33. package/dist/cjs/worker-deno.d.ts +11 -0
  34. package/dist/cjs/worker-deno.js +54 -0
  35. package/dist/cjs/worker-nodejs.d.ts +11 -0
  36. package/dist/cjs/worker-nodejs.js +55 -0
  37. package/dist/mjs/bytecode-browser.d.ts +5 -0
  38. package/dist/mjs/bytecode-browser.js +38 -0
  39. package/dist/mjs/bytecode-deno.d.ts +5 -0
  40. package/dist/mjs/bytecode-deno.js +83 -0
  41. package/dist/mjs/bytecode-nodejs.d.ts +5 -0
  42. package/dist/mjs/bytecode-nodejs.js +37 -0
  43. package/dist/mjs/index-browser.d.ts +2 -2
  44. package/dist/mjs/index-browser.js +4 -501
  45. package/dist/mjs/index-deno.d.ts +2 -2
  46. package/dist/mjs/index-deno.js +4 -277
  47. package/dist/mjs/index-nodejs.d.ts +2 -2
  48. package/dist/mjs/index-nodejs.js +4 -205
  49. package/dist/mjs/internals/bytecode/wasm0.js +1 -0
  50. package/dist/mjs/internals/bytecode/wasm1.js +1 -0
  51. package/dist/mjs/internals/bytecode/wasm2.js +1 -0
  52. package/dist/mjs/{instance/bindings-smoldot-light.d.ts → internals/client.d.ts} +15 -34
  53. package/dist/mjs/internals/client.js +372 -0
  54. package/dist/mjs/internals/local-instance.d.ts +144 -0
  55. package/dist/mjs/internals/local-instance.js +561 -0
  56. package/dist/mjs/internals/remote-instance.d.ts +38 -0
  57. package/dist/mjs/internals/remote-instance.js +369 -0
  58. package/dist/mjs/no-auto-bytecode-browser.d.ts +11 -0
  59. package/dist/mjs/no-auto-bytecode-browser.js +471 -0
  60. package/dist/mjs/no-auto-bytecode-deno.d.ts +10 -0
  61. package/dist/mjs/no-auto-bytecode-deno.js +210 -0
  62. package/dist/mjs/no-auto-bytecode-nodejs.d.ts +10 -0
  63. package/dist/mjs/no-auto-bytecode-nodejs.js +179 -0
  64. package/dist/mjs/{client.d.ts → public-types.d.ts} +51 -3
  65. package/dist/mjs/public-types.js +67 -0
  66. package/dist/mjs/worker-browser.d.ts +11 -0
  67. package/dist/mjs/worker-browser.js +59 -0
  68. package/dist/mjs/worker-deno.d.ts +11 -0
  69. package/dist/mjs/worker-deno.js +50 -0
  70. package/dist/mjs/worker-nodejs.d.ts +11 -0
  71. package/dist/mjs/worker-nodejs.js +51 -0
  72. package/package.json +40 -8
  73. package/dist/cjs/client.js +0 -172
  74. package/dist/cjs/instance/autogen/wasm0.js +0 -4
  75. package/dist/cjs/instance/autogen/wasm1.js +0 -4
  76. package/dist/cjs/instance/autogen/wasm2.js +0 -4
  77. package/dist/cjs/instance/bindings-smoldot-light.js +0 -285
  78. package/dist/cjs/instance/bindings-wasi.d.ts +0 -27
  79. package/dist/cjs/instance/bindings-wasi.js +0 -172
  80. package/dist/cjs/instance/bindings.d.ts +0 -31
  81. package/dist/cjs/instance/bindings.js +0 -5
  82. package/dist/cjs/instance/instance.d.ts +0 -45
  83. package/dist/cjs/instance/instance.js +0 -277
  84. package/dist/cjs/instance/raw-instance.d.ts +0 -56
  85. package/dist/cjs/instance/raw-instance.js +0 -129
  86. package/dist/mjs/client.js +0 -162
  87. package/dist/mjs/instance/autogen/wasm0.js +0 -1
  88. package/dist/mjs/instance/autogen/wasm1.js +0 -1
  89. package/dist/mjs/instance/autogen/wasm2.js +0 -1
  90. package/dist/mjs/instance/bindings-smoldot-light.js +0 -280
  91. package/dist/mjs/instance/bindings-wasi.d.ts +0 -27
  92. package/dist/mjs/instance/bindings-wasi.js +0 -170
  93. package/dist/mjs/instance/bindings.d.ts +0 -31
  94. package/dist/mjs/instance/bindings.js +0 -4
  95. package/dist/mjs/instance/instance.d.ts +0 -45
  96. package/dist/mjs/instance/instance.js +0 -269
  97. package/dist/mjs/instance/raw-instance.d.ts +0 -56
  98. package/dist/mjs/instance/raw-instance.js +0 -124
  99. /package/dist/cjs/{base64.d.ts → internals/base64.d.ts} +0 -0
  100. /package/dist/cjs/{base64.js → internals/base64.js} +0 -0
  101. /package/dist/cjs/{instance → internals}/buffer.d.ts +0 -0
  102. /package/dist/cjs/{instance → internals}/buffer.js +0 -0
  103. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
  104. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
  105. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
  106. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
  107. /package/dist/cjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
  108. /package/dist/mjs/{base64.d.ts → internals/base64.d.ts} +0 -0
  109. /package/dist/mjs/{base64.js → internals/base64.js} +0 -0
  110. /package/dist/mjs/{instance → internals}/buffer.d.ts +0 -0
  111. /package/dist/mjs/{instance → internals}/buffer.js +0 -0
  112. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.d.ts +0 -0
  113. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm.js +0 -0
  114. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm0.d.ts +0 -0
  115. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm1.d.ts +0 -0
  116. /package/dist/mjs/{instance/autogen → internals/bytecode}/wasm2.d.ts +0 -0
@@ -1,12 +1,9 @@
1
- import type { SmoldotWasmInstance } from './bindings.js';
2
- export interface Config {
3
- instance?: SmoldotWasmInstance;
4
- /**
5
- * Array used to store the buffers provided to the Rust code.
6
- *
7
- * When `buffer_size` or `buffer_index` are called, the buffer is found here.
8
- */
9
- bufferIndices: Array<Uint8Array>;
1
+ import { Client, ClientOptions, SmoldotBytecode } from '../public-types.js';
2
+ import * as instance from './local-instance.js';
3
+ /**
4
+ * Contains functions that the client will use when it needs to leverage the platform.
5
+ */
6
+ export interface PlatformBindings {
10
7
  /**
11
8
  * Tries to open a new connection using the given configuration.
12
9
  *
@@ -15,15 +12,13 @@ export interface Config {
15
12
  */
16
13
  connect(config: ConnectionConfig): Connection;
17
14
  /**
18
- * Closure to call when the Wasm instance calls `panic`.
19
- *
20
- * This callback will always be invoked from within a binding called the Wasm instance.
15
+ * Returns the number of milliseconds since an arbitrary epoch.
16
+ */
17
+ performanceNow: () => number;
18
+ /**
19
+ * Fills the given buffer with randomly-generated bytes.
21
20
  */
22
- onPanic: (message: string) => never;
23
- logCallback: (level: number, target: string, message: string) => void;
24
- jsonRpcResponsesNonEmptyCallback: (chainId: number) => void;
25
- advanceExecutionReadyCallback: () => void;
26
- currentTaskCallback?: (taskName: string | null) => void;
21
+ getRandomValues: (buffer: Uint8Array) => void;
27
22
  }
28
23
  /**
29
24
  * Connection to a remote node.
@@ -114,12 +109,9 @@ export interface Connection {
114
109
  */
115
110
  export interface ConnectionConfig {
116
111
  /**
117
- * Multiaddress in string format that describes which node to try to connect to.
118
- *
119
- * Note that this address shouldn't be trusted. The value in this field might have been chosen
120
- * by a potentially malicious peer.
112
+ * Parsed multiaddress, as returned by the `parseMultiaddr` function.
121
113
  */
122
- address: string;
114
+ address: instance.ParsedMultiaddr;
123
115
  /**
124
116
  * Callback called when the connection transitions from the `Opening` to the `Open` state.
125
117
  *
@@ -181,15 +173,4 @@ export interface ConnectionConfig {
181
173
  */
182
174
  onMessage: (message: Uint8Array, streamId?: number) => void;
183
175
  }
184
- /**
185
- * Emitted by `connect` if the multiaddress couldn't be parsed or contains an invalid protocol.
186
- *
187
- * @see connect
188
- */
189
- export declare class ConnectionError extends Error {
190
- constructor(message: string);
191
- }
192
- export default function (config: Config): {
193
- imports: WebAssembly.ModuleImports;
194
- killAll: () => void;
195
- };
176
+ export declare function start(options: ClientOptions, wasmModule: SmoldotBytecode | Promise<SmoldotBytecode>, platformBindings: PlatformBindings): Client;
@@ -0,0 +1,376 @@
1
+ "use strict";
2
+ // Smoldot
3
+ // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
4
+ // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.start = void 0;
16
+ // This program is free software: you can redistribute it and/or modify
17
+ // it under the terms of the GNU General Public License as published by
18
+ // the Free Software Foundation, either version 3 of the License, or
19
+ // (at your option) any later version.
20
+ // This program is distributed in the hope that it will be useful,
21
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
22
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
+ // GNU General Public License for more details.
24
+ // You should have received a copy of the GNU General Public License
25
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
26
+ const public_types_js_1 = require("../public-types.js");
27
+ const instance = require("./local-instance.js");
28
+ const remote = require("./remote-instance.js");
29
+ // This function is similar to the `start` function found in `index.ts`, except with an extra
30
+ // parameter containing the platform-specific bindings.
31
+ // Contrary to the one within `index.js`, this function is not supposed to be directly used.
32
+ function start(options, wasmModule, platformBindings) {
33
+ const logCallback = options.logCallback || ((level, target, message) => {
34
+ // The first parameter of the methods of `console` has some printf-like substitution
35
+ // capabilities. We don't really need to use this, but not using it means that the logs might
36
+ // not get printed correctly if they contain `%`.
37
+ if (level <= 1) {
38
+ console.error("[%s] %s", target, message);
39
+ }
40
+ else if (level == 2) {
41
+ console.warn("[%s] %s", target, message);
42
+ }
43
+ else if (level == 3) {
44
+ console.info("[%s] %s", target, message);
45
+ }
46
+ else if (level == 4) {
47
+ console.debug("[%s] %s", target, message);
48
+ }
49
+ else {
50
+ console.trace("[%s] %s", target, message);
51
+ }
52
+ });
53
+ if (!(wasmModule instanceof Promise)) {
54
+ wasmModule = Promise.resolve(wasmModule);
55
+ }
56
+ // Extract (to make sure the value doesn't change) and sanitize `cpuRateLimit`.
57
+ let cpuRateLimit = options.cpuRateLimit || 1.0;
58
+ if (isNaN(cpuRateLimit))
59
+ cpuRateLimit = 1.0;
60
+ if (cpuRateLimit > 1.0)
61
+ cpuRateLimit = 1.0;
62
+ if (cpuRateLimit < 0.0)
63
+ cpuRateLimit = 0.0;
64
+ // This object holds the state of everything.
65
+ const state = {
66
+ instance: { status: "not-created" },
67
+ chainIds: new WeakMap(),
68
+ currentTaskName: null,
69
+ connections: new Map(),
70
+ addChainResults: [],
71
+ onExecutorShutdownOrWasmPanic: () => { },
72
+ chains: new Map(),
73
+ };
74
+ // Callback called during the execution of the instance.
75
+ const eventCallback = (event) => {
76
+ switch (event.ty) {
77
+ case "wasm-panic": {
78
+ console.error("Smoldot has panicked" +
79
+ (state.currentTaskName ? (" while executing task `" + state.currentTaskName + "`") : "") +
80
+ ". This is a bug in smoldot. Please open an issue at " +
81
+ "https://github.com/smol-dot/smoldot/issues with the following message:\n" +
82
+ event.message);
83
+ state.instance = {
84
+ status: "destroyed",
85
+ error: new public_types_js_1.CrashError(event.message),
86
+ };
87
+ state.connections.forEach((connec) => connec.reset());
88
+ state.connections.clear();
89
+ for (const addChainResult of state.addChainResults) {
90
+ addChainResult({ success: false, error: "Smoldot has crashed" });
91
+ }
92
+ state.addChainResults = [];
93
+ for (const chain of Array.from(state.chains.values())) {
94
+ for (const callback of chain.jsonRpcResponsesPromises) {
95
+ callback();
96
+ }
97
+ chain.jsonRpcResponsesPromises = [];
98
+ }
99
+ state.chains.clear();
100
+ state.currentTaskName = null;
101
+ const cb = state.onExecutorShutdownOrWasmPanic;
102
+ state.onExecutorShutdownOrWasmPanic = () => { };
103
+ cb();
104
+ break;
105
+ }
106
+ case "executor-shutdown": {
107
+ const cb = state.onExecutorShutdownOrWasmPanic;
108
+ state.onExecutorShutdownOrWasmPanic = () => { };
109
+ cb();
110
+ break;
111
+ }
112
+ case "log": {
113
+ logCallback(event.level, event.target, event.message);
114
+ break;
115
+ }
116
+ case "add-chain-result": {
117
+ (state.addChainResults.shift())(event);
118
+ break;
119
+ }
120
+ case "json-rpc-responses-non-empty": {
121
+ // Notify every single promise found in `jsonRpcResponsesPromises`.
122
+ const callbacks = state.chains.get(event.chainId).jsonRpcResponsesPromises;
123
+ while (callbacks.length !== 0) {
124
+ (callbacks.shift())();
125
+ }
126
+ break;
127
+ }
128
+ case "current-task": {
129
+ state.currentTaskName = event.taskName;
130
+ break;
131
+ }
132
+ case "new-connection": {
133
+ const connectionId = event.connectionId;
134
+ state.connections.set(connectionId, platformBindings.connect({
135
+ address: event.address,
136
+ onConnectionReset(message) {
137
+ if (state.instance.status !== "ready")
138
+ throw new Error();
139
+ state.connections.delete(connectionId);
140
+ state.instance.instance.connectionReset(connectionId, message);
141
+ },
142
+ onMessage(message, streamId) {
143
+ if (state.instance.status !== "ready")
144
+ throw new Error();
145
+ state.instance.instance.streamMessage(connectionId, message, streamId);
146
+ },
147
+ onStreamOpened(streamId, direction, initialWritableBytes) {
148
+ if (state.instance.status !== "ready")
149
+ throw new Error();
150
+ state.instance.instance.streamOpened(connectionId, streamId, direction, initialWritableBytes);
151
+ },
152
+ onOpen(info) {
153
+ if (state.instance.status !== "ready")
154
+ throw new Error();
155
+ state.instance.instance.connectionOpened(connectionId, info);
156
+ },
157
+ onWritableBytes(numExtra, streamId) {
158
+ if (state.instance.status !== "ready")
159
+ throw new Error();
160
+ state.instance.instance.streamWritableBytes(connectionId, numExtra, streamId);
161
+ },
162
+ onStreamReset(streamId) {
163
+ if (state.instance.status !== "ready")
164
+ throw new Error();
165
+ state.instance.instance.streamReset(connectionId, streamId);
166
+ },
167
+ }));
168
+ break;
169
+ }
170
+ case "connection-reset": {
171
+ const connection = state.connections.get(event.connectionId);
172
+ connection.reset();
173
+ state.connections.delete(event.connectionId);
174
+ break;
175
+ }
176
+ case "connection-stream-open": {
177
+ const connection = state.connections.get(event.connectionId);
178
+ connection.openOutSubstream();
179
+ break;
180
+ }
181
+ case "connection-stream-reset": {
182
+ const connection = state.connections.get(event.connectionId);
183
+ connection.reset(event.streamId);
184
+ break;
185
+ }
186
+ case "stream-send": {
187
+ const connection = state.connections.get(event.connectionId);
188
+ connection.send(event.data, event.streamId);
189
+ break;
190
+ }
191
+ case "stream-send-close": {
192
+ const connection = state.connections.get(event.connectionId);
193
+ connection.closeSend(event.streamId);
194
+ break;
195
+ }
196
+ }
197
+ };
198
+ const portToWorker = options.portToWorker;
199
+ if (!portToWorker) {
200
+ // Start a local instance.
201
+ state.instance = {
202
+ status: "not-ready",
203
+ whenReady: wasmModule
204
+ .then((wasmModule) => {
205
+ return instance.startLocalInstance({
206
+ forbidTcp: options.forbidTcp || false,
207
+ forbidWs: options.forbidWs || false,
208
+ forbidNonLocalWs: options.forbidNonLocalWs || false,
209
+ forbidWss: options.forbidWss || false,
210
+ forbidWebRtc: options.forbidWebRtc || false,
211
+ maxLogLevel: options.maxLogLevel || 3,
212
+ cpuRateLimit,
213
+ envVars: [],
214
+ performanceNow: platformBindings.performanceNow,
215
+ getRandomValues: platformBindings.getRandomValues,
216
+ }, wasmModule.wasm, eventCallback);
217
+ })
218
+ .then((instance) => {
219
+ // The Wasm instance might have been crashed before this callback is called.
220
+ if (state.instance.status === "destroyed")
221
+ return;
222
+ state.instance = {
223
+ status: "ready",
224
+ instance,
225
+ };
226
+ })
227
+ };
228
+ }
229
+ else {
230
+ // Connect to the remote instance.
231
+ state.instance = {
232
+ status: "not-ready",
233
+ whenReady: remote.connectToInstanceServer({
234
+ wasmModule: wasmModule.then((b) => b.wasm),
235
+ forbidTcp: options.forbidTcp || false,
236
+ forbidWs: options.forbidWs || false,
237
+ forbidNonLocalWs: options.forbidNonLocalWs || false,
238
+ forbidWss: options.forbidWss || false,
239
+ forbidWebRtc: options.forbidWebRtc || false,
240
+ maxLogLevel: options.maxLogLevel || 3,
241
+ cpuRateLimit,
242
+ portToServer: portToWorker,
243
+ eventCallback
244
+ }).then((instance) => {
245
+ // The Wasm instance might have been crashed before this callback is called.
246
+ if (state.instance.status === "destroyed")
247
+ return;
248
+ state.instance = {
249
+ status: "ready",
250
+ instance,
251
+ };
252
+ })
253
+ };
254
+ }
255
+ return {
256
+ addChain: (options) => __awaiter(this, void 0, void 0, function* () {
257
+ if (state.instance.status === "not-ready")
258
+ yield state.instance.whenReady;
259
+ if (state.instance.status === "destroyed")
260
+ throw state.instance.error;
261
+ if (state.instance.status === "not-created" || state.instance.status === "not-ready")
262
+ throw new Error(); // Internal error, not supposed to ever happen.
263
+ // Passing a JSON object for the chain spec is an easy mistake, so we provide a more
264
+ // readable error.
265
+ if (!(typeof options.chainSpec === 'string'))
266
+ throw new Error("Chain specification must be a string");
267
+ let potentialRelayChainsIds = [];
268
+ if (!!options.potentialRelayChains) {
269
+ for (const chain of options.potentialRelayChains) {
270
+ // The content of `options.potentialRelayChains` are supposed to be chains earlier
271
+ // returned by `addChain`.
272
+ const id = state.chainIds.get(chain);
273
+ if (id === undefined) // It is possible for `id` to be missing if it has earlier been removed.
274
+ continue;
275
+ potentialRelayChainsIds.push(id);
276
+ }
277
+ }
278
+ const promise = new Promise((resolve) => state.addChainResults.push(resolve));
279
+ state.instance.instance.addChain(options.chainSpec, typeof options.databaseContent === 'string' ? options.databaseContent : "", potentialRelayChainsIds, !!options.disableJsonRpc);
280
+ const outcome = yield promise;
281
+ if (!outcome.success)
282
+ throw new public_types_js_1.AddChainError(outcome.error);
283
+ const chainId = outcome.chainId;
284
+ state.chains.set(chainId, {
285
+ jsonRpcResponsesPromises: new Array()
286
+ });
287
+ const newChain = {
288
+ sendJsonRpc: (request) => {
289
+ if (state.instance.status === "destroyed")
290
+ throw state.instance.error;
291
+ if (state.instance.status !== "ready")
292
+ throw new Error(); // Internal error. Never supposed to happen.
293
+ if (!state.chains.has(chainId))
294
+ throw new public_types_js_1.AlreadyDestroyedError();
295
+ if (options.disableJsonRpc)
296
+ throw new public_types_js_1.JsonRpcDisabledError();
297
+ if (request.length >= 64 * 1024 * 1024) {
298
+ throw new public_types_js_1.MalformedJsonRpcError();
299
+ }
300
+ ;
301
+ const retVal = state.instance.instance.request(request, chainId);
302
+ switch (retVal) {
303
+ case 0: break;
304
+ case 1: throw new public_types_js_1.MalformedJsonRpcError();
305
+ case 2: throw new public_types_js_1.QueueFullError();
306
+ default: throw new Error("Internal error: unknown json_rpc_send error code: " + retVal);
307
+ }
308
+ },
309
+ nextJsonRpcResponse: () => __awaiter(this, void 0, void 0, function* () {
310
+ if (!state.chains.has(chainId))
311
+ throw new public_types_js_1.AlreadyDestroyedError();
312
+ if (options.disableJsonRpc)
313
+ return Promise.reject(new public_types_js_1.JsonRpcDisabledError());
314
+ while (true) {
315
+ if (state.instance.status === "destroyed")
316
+ throw state.instance.error;
317
+ if (state.instance.status !== "ready")
318
+ throw new Error(); // Internal error. Never supposed to happen.
319
+ // Try to pop a message from the queue.
320
+ const message = state.instance.instance.peekJsonRpcResponse(chainId);
321
+ if (message)
322
+ return message;
323
+ // If no message is available, wait for one to be.
324
+ yield new Promise((resolve) => {
325
+ state.chains.get(chainId).jsonRpcResponsesPromises.push(resolve);
326
+ });
327
+ }
328
+ }),
329
+ remove: () => {
330
+ if (state.instance.status === "destroyed")
331
+ throw state.instance.error;
332
+ if (state.instance.status !== "ready")
333
+ throw new Error(); // Internal error. Never supposed to happen.
334
+ if (!state.chains.has(chainId))
335
+ throw new public_types_js_1.AlreadyDestroyedError();
336
+ console.assert(state.chainIds.has(newChain));
337
+ state.chainIds.delete(newChain);
338
+ for (const callback of state.chains.get(chainId).jsonRpcResponsesPromises) {
339
+ callback();
340
+ }
341
+ state.chains.delete(chainId);
342
+ state.instance.instance.removeChain(chainId);
343
+ },
344
+ };
345
+ state.chainIds.set(newChain, chainId);
346
+ return newChain;
347
+ }),
348
+ terminate: () => __awaiter(this, void 0, void 0, function* () {
349
+ if (state.instance.status === "not-ready")
350
+ yield state.instance.whenReady;
351
+ if (state.instance.status === "destroyed")
352
+ throw state.instance.error;
353
+ if (state.instance.status !== "ready")
354
+ throw new Error(); // Internal error. Never supposed to happen.
355
+ state.instance.instance.shutdownExecutor();
356
+ state.instance = { status: "destroyed", error: new public_types_js_1.AlreadyDestroyedError() };
357
+ state.connections.forEach((connec) => connec.reset());
358
+ state.connections.clear();
359
+ for (const addChainResult of state.addChainResults) {
360
+ addChainResult({ success: false, error: "Smoldot has crashed" });
361
+ }
362
+ state.addChainResults = [];
363
+ for (const chain of Array.from(state.chains.values())) {
364
+ for (const callback of chain.jsonRpcResponsesPromises) {
365
+ callback();
366
+ }
367
+ chain.jsonRpcResponsesPromises = [];
368
+ }
369
+ state.chains.clear();
370
+ state.currentTaskName = null;
371
+ // Wait for the `executor-shutdown` event to be generated.
372
+ yield new Promise((resolve) => state.onExecutorShutdownOrWasmPanic = resolve);
373
+ })
374
+ };
375
+ }
376
+ exports.start = start;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Configuration for {@link startLocalInstance}.
3
+ */
4
+ export interface Config {
5
+ forbidTcp: boolean;
6
+ forbidWs: boolean;
7
+ forbidNonLocalWs: boolean;
8
+ forbidWss: boolean;
9
+ forbidWebRtc: boolean;
10
+ /**
11
+ * Maximum level of the logs that are generated.
12
+ */
13
+ maxLogLevel: number;
14
+ /**
15
+ * Number between 0.0 and 1.0 indicating how much of the CPU time the instance is allowed to
16
+ * consume.
17
+ */
18
+ cpuRateLimit: number;
19
+ /**
20
+ * Environment variables that the instance can pull.
21
+ */
22
+ envVars: string[];
23
+ /**
24
+ * Returns the number of milliseconds since an arbitrary epoch.
25
+ */
26
+ performanceNow: () => number;
27
+ /**
28
+ * Fills the given buffer with randomly-generated bytes.
29
+ */
30
+ getRandomValues: (buffer: Uint8Array) => void;
31
+ }
32
+ export type Event = {
33
+ ty: "add-chain-result";
34
+ success: true;
35
+ chainId: number;
36
+ } | {
37
+ ty: "add-chain-result";
38
+ success: false;
39
+ error: string;
40
+ } | {
41
+ ty: "log";
42
+ level: number;
43
+ target: string;
44
+ message: string;
45
+ } | {
46
+ ty: "json-rpc-responses-non-empty";
47
+ chainId: number;
48
+ } | {
49
+ ty: "current-task";
50
+ taskName: string | null;
51
+ } | {
52
+ ty: "wasm-panic";
53
+ message: string;
54
+ } | {
55
+ ty: "executor-shutdown";
56
+ } | {
57
+ ty: "new-connection";
58
+ connectionId: number;
59
+ address: ParsedMultiaddr;
60
+ } | {
61
+ ty: "connection-reset";
62
+ connectionId: number;
63
+ } | {
64
+ ty: "connection-stream-open";
65
+ connectionId: number;
66
+ } | {
67
+ ty: "connection-stream-reset";
68
+ connectionId: number;
69
+ streamId: number;
70
+ } | {
71
+ ty: "stream-send";
72
+ connectionId: number;
73
+ streamId?: number;
74
+ data: Uint8Array;
75
+ } | {
76
+ ty: "stream-send-close";
77
+ connectionId: number;
78
+ streamId?: number;
79
+ };
80
+ export type ParsedMultiaddr = {
81
+ ty: "tcp";
82
+ hostname: string;
83
+ port: number;
84
+ } | {
85
+ ty: "websocket";
86
+ url: string;
87
+ } | {
88
+ ty: "webrtc";
89
+ targetPort: string;
90
+ ipVersion: string;
91
+ targetIp: string;
92
+ remoteCertMultibase: string;
93
+ };
94
+ export interface Instance {
95
+ request: (request: string, chainId: number) => number;
96
+ peekJsonRpcResponse: (chainId: number) => string | null;
97
+ addChain: (chainSpec: string, databaseContent: string, potentialRelayChains: number[], disableJsonRpc: boolean) => void;
98
+ removeChain: (chainId: number) => void;
99
+ /**
100
+ * Notifies the background executor that it should stop. Once it has effectively stopped,
101
+ * a `shutdown-finished` event will be generated.
102
+ * Note that the instance can technically still be used, and all the functions still work, but
103
+ * in practice nothing is being run in the background and as such it won't do much.
104
+ * Existing connections are *not* closed. It is the responsibility of the API user to close
105
+ * all connections.
106
+ */
107
+ shutdownExecutor: () => void;
108
+ connectionOpened: (connectionId: number, info: {
109
+ type: 'single-stream';
110
+ handshake: 'multistream-select-noise-yamux';
111
+ initialWritableBytes: number;
112
+ writeClosable: boolean;
113
+ } | {
114
+ type: 'multi-stream';
115
+ handshake: 'webrtc';
116
+ localTlsCertificateMultihash: Uint8Array;
117
+ remoteTlsCertificateMultihash: Uint8Array;
118
+ }) => void;
119
+ connectionReset: (connectionId: number, message: string) => void;
120
+ streamWritableBytes: (connectionId: number, numExtra: number, streamId?: number) => void;
121
+ streamMessage: (connectionId: number, message: Uint8Array, streamId?: number) => void;
122
+ streamOpened: (connectionId: number, streamId: number, direction: 'inbound' | 'outbound', initialWritableBytes: number) => void;
123
+ streamReset: (connectionId: number, streamId: number) => void;
124
+ }
125
+ /**
126
+ * Starts a new instance using the given configuration.
127
+ *
128
+ * Even though this function doesn't do anything asynchronous, it needs to be asynchronous due to
129
+ * the fact that `WebAssembly.instantiate` is for some reason asynchronous.
130
+ *
131
+ * After this function returns, the execution of CPU-heavy tasks of smoldot will happen
132
+ * asynchronously in the background.
133
+ *
134
+ * This instance is low-level in the sense that invalid input can lead to crashes and that input
135
+ * isn't sanitized. In other words, you know what you're doing.
136
+ */
137
+ export declare function startLocalInstance(config: Config, wasmModule: WebAssembly.Module, eventCallback: (event: Event) => void): Promise<Instance>;
138
+ export declare function parseMultiaddr(address: string, forbidTcp: boolean, forbidWs: boolean, forbidNonLocalWs: boolean, forbidWss: boolean, forbidWebRtc: boolean): {
139
+ success: true;
140
+ address: ParsedMultiaddr;
141
+ } | {
142
+ success: false;
143
+ error: string;
144
+ };