Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@substrate/connect

Package Overview
Dependencies
Maintainers
16
Versions
113
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@substrate/connect - npm Package Compare versions

Comparing version 0.8.2 to 0.8.3

6

CHANGELOG.md

@@ -7,2 +7,8 @@ # Changelog

## 0.8.3 - 2023-12-07
### Changed
- Use `@polkadot-api/light-client-extension-helpers/web-page` ([#1603](https://github.com/paritytech/substrate-connect/pull/1603))
## 0.8.2 - 2023-12-06

@@ -9,0 +15,0 @@

201

dist/index.js

@@ -331,166 +331,38 @@ var __defProp = Object.defineProperty;

// src/connector/extension.ts
var listeners = /* @__PURE__ */ new Map();
if (typeof window === "object") {
window.addEventListener(
"message",
({ data }) => {
var _a;
if ((data == null ? void 0 : data.origin) !== "substrate-connect-extension")
return;
(_a = listeners.get(data.chainId)) == null ? void 0 : _a(data);
}
);
}
function getRandomChainId() {
const arr = new BigUint64Array(2);
crypto.getRandomValues(arr);
const result = arr[1] << BigInt(64) | arr[0];
return result.toString(36);
}
import { DOM_ELEMENT_ID } from "@substrate/connect-extension-protocol";
var wellKnownChainGenesisHashes = {
polkadot: "0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3",
ksmcc3: "0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe",
westend2: "0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e",
rococo_v2_2: "0x6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e"
};
var lightClientProviderPromise;
var createScClient2 = () => {
const internalAddChain = (isWellKnown, chainSpecOrWellKnownName, jsonRpcCallback, relayChainId) => __async(void 0, null, function* () {
let resolve;
const initFinished = new Promise((res) => {
resolve = () => res(null);
});
const chainState = {
id: getRandomChainId(),
state: {
state: "pending",
waitFinished: resolve
}
};
if (listeners.has(chainState.id))
throw new Error(
"Unexpectedly randomly generated the same chain ID twice despite 64bits of entropy"
if (!lightClientProviderPromise)
lightClientProviderPromise = import("@polkadot-api/light-client-extension-helpers/web-page").then(
({ getLightClientProvider }) => getLightClientProvider(DOM_ELEMENT_ID)
);
const internalAddChain = (isWellKnown, chainSpecOrWellKnownName, jsonRpcCallback, relayChainGenesisHash) => __async(void 0, null, function* () {
const lightClientProvider = yield lightClientProviderPromise;
let chain;
if (isWellKnown) {
const foundChain = Object.values(lightClientProvider.getChains()).find(
({ genesisHash }) => genesisHash === wellKnownChainGenesisHashes[chainSpecOrWellKnownName]
);
listeners.set(chainState.id, (msg) => {
switch (chainState.state.state) {
case "pending": {
const waitFinished = chainState.state.waitFinished;
switch (msg.type) {
case "chain-ready": {
chainState.state = {
state: "ok"
};
break;
}
case "error": {
chainState.state = {
state: "dead",
error: new CrashError(
"Error while creating the chain: " + msg.errorMessage
)
};
break;
}
default: {
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension"
);
}
}
waitFinished();
break;
}
case "ok": {
switch (msg.type) {
case "error": {
chainState.state = {
state: "dead",
error: new CrashError(
"Extension has killed the chain: " + msg.errorMessage
)
};
break;
}
case "rpc": {
if (jsonRpcCallback) {
jsonRpcCallback(msg.jsonRpcMessage);
} else {
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension"
);
}
break;
}
default: {
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension"
);
}
}
break;
}
case "dead": {
break;
}
}
});
if (isWellKnown) {
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-well-known-chain",
chainName: chainSpecOrWellKnownName
});
if (!foundChain)
throw new Error("Unknown well-known chain");
chain = foundChain;
} else {
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-chain",
chainSpec: chainSpecOrWellKnownName,
potentialRelayChainIds: relayChainId ? [relayChainId] : []
});
chain = yield lightClientProvider.getChain(
chainSpecOrWellKnownName,
relayChainGenesisHash
);
}
yield initFinished;
if (isWellKnown && chainState.state.state === "dead") {
let resolve2;
const initFinished2 = new Promise((res) => {
resolve2 = () => res(null);
});
chainState.state = {
state: "pending",
waitFinished: resolve2
};
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-chain",
chainSpec: yield getSpec(chainSpecOrWellKnownName),
potentialRelayChainIds: []
});
yield initFinished2;
}
if (chainState.state.state === "dead") {
throw chainState.state.error;
}
const chain = {
sendJsonRpc: (jsonRpcMessage) => {
if (chainState.state.state === "dead") {
throw chainState.state.error;
}
if (!jsonRpcCallback)
throw new JsonRpcDisabledError();
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "rpc",
jsonRpcMessage
});
const jsonRpcProvider = chain.connect(jsonRpcCallback);
return {
sendJsonRpc(rpc) {
jsonRpcProvider.send(rpc);
},
remove: () => {
if (chainState.state.state === "dead") {
throw chainState.state.error;
}
chainState.state = {
state: "dead",
error: new AlreadyDestroyedError()
};
listeners.delete(chainState.id);
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "remove-chain"
});
remove() {
jsonRpcProvider.disconnect();
},

@@ -502,7 +374,6 @@ addChain: function(chainSpec, jsonRpcCallback2) {

jsonRpcCallback2,
chainState.id
chain.genesisHash
);
}
};
return chain;
});

@@ -514,9 +385,7 @@ return {

};
function postToExtension(msg) {
window.postMessage(msg, "*");
}
// src/connector/index.ts
import { DOM_ELEMENT_ID } from "@substrate/connect-extension-protocol";
var isExtensionPresent = typeof document === "object" && typeof document.getElementById === "function" && !!document.getElementById(DOM_ELEMENT_ID);
import { DOM_ELEMENT_ID as DOM_ELEMENT_ID2 } from "@substrate/connect-extension-protocol";
var _a;
var isExtensionPresent = typeof document === "object" && typeof document.getElementById === "function" && !!document.getElementById(DOM_ELEMENT_ID2) && ((_a = document.getElementById(DOM_ELEMENT_ID2)) == null ? void 0 : _a.getAttribute("channelid")) === DOM_ELEMENT_ID2;
function createScClient3(config) {

@@ -523,0 +392,0 @@ const forceEmbedded = config == null ? void 0 : config.forceEmbeddedNode;

{
"name": "@substrate/connect",
"version": "0.8.2",
"version": "0.8.3",
"description": "Substrate-connect to Smoldot clients. Using either substrate extension with predefined clients or an internal smoldot client based on chainSpecs provided.",

@@ -45,4 +45,5 @@ "author": "Parity Team <admin@parity.io>",

"dependencies": {
"@substrate/connect-extension-protocol": "^1.0.1",
"@substrate/connect-known-chains": "^1.0.2",
"@polkadot-api/light-client-extension-helpers": "next",
"@substrate/connect-extension-protocol": "^2.0.0",
"@substrate/connect-known-chains": "^1.0.3",
"smoldot": "2.0.13"

@@ -49,0 +50,0 @@ },

@@ -0,34 +1,20 @@

import { DOM_ELEMENT_ID } from "@substrate/connect-extension-protocol"
import { type Chain, type JsonRpcCallback, type ScClient } from "./types.js"
import type {
ToApplication,
ToExtension,
} from "@substrate/connect-extension-protocol"
import {
AlreadyDestroyedError,
CrashError,
JsonRpcDisabledError,
type Chain,
type JsonRpcCallback,
type ScClient,
} from "./types.js"
RawChain,
LightClientProvider,
} from "@polkadot-api/light-client-extension-helpers/web-page"
import { WellKnownChain } from "../WellKnownChain.js"
import { getSpec } from "./getSpec.js"
const listeners = new Map<string, (msg: ToApplication) => void>()
if (typeof window === "object") {
window.addEventListener(
"message",
({ data }: MessageEvent<ToApplication>) => {
if (data?.origin !== "substrate-connect-extension") return
listeners.get(data.chainId)?.(data)
},
)
const wellKnownChainGenesisHashes: Record<string, string> = {
polkadot:
"0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3",
ksmcc3: "0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe",
westend2:
"0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e",
rococo_v2_2:
"0x6408de7737c59c238890533af25896a2c20608d8b380bb01029acb392781063e",
}
function getRandomChainId(): string {
const arr = new BigUint64Array(2)
// It can only be used from the browser, so this is fine.
crypto.getRandomValues(arr)
const result = (arr[1]! << BigInt(64)) | arr[0]!
return result.toString(36)
}
let lightClientProviderPromise: Promise<LightClientProvider>

@@ -45,2 +31,8 @@ /**

export const createScClient = (): ScClient => {
if (!lightClientProviderPromise)
lightClientProviderPromise = import(
"@polkadot-api/light-client-extension-helpers/web-page"
).then(({ getLightClientProvider }) =>
getLightClientProvider(DOM_ELEMENT_ID),
)
const internalAddChain = async (

@@ -50,195 +42,29 @@ isWellKnown: boolean,

jsonRpcCallback?: JsonRpcCallback,
relayChainId?: string,
relayChainGenesisHash?: string,
): Promise<Chain> => {
type ChainState =
| {
state: "pending"
waitFinished: () => void
}
| {
state: "ok"
}
| { state: "dead"; error: AlreadyDestroyedError | CrashError }
const lightClientProvider = await lightClientProviderPromise
let resolve: undefined | (() => void)
const initFinished = new Promise((res) => {
resolve = () => res(null)
})
const chainState: { id: string; state: ChainState } = {
id: getRandomChainId(),
state: {
state: "pending",
waitFinished: resolve!,
},
}
if (listeners.has(chainState.id))
throw new Error(
"Unexpectedly randomly generated the same chain ID twice despite 64bits of entropy",
let chain: RawChain
if (isWellKnown) {
const foundChain = Object.values(lightClientProvider.getChains()).find(
({ genesisHash }) =>
genesisHash === wellKnownChainGenesisHashes[chainSpecOrWellKnownName],
)
// Setup the listener for this chain.
// This listener should never be removed until we are no longer interested in this chain.
// Removing then re-adding the listener could cause messages to be missed.
listeners.set(chainState.id, (msg) => {
switch (chainState.state.state) {
case "pending": {
const waitFinished = chainState.state.waitFinished
switch (msg.type) {
case "chain-ready": {
chainState.state = {
state: "ok",
}
break
}
case "error": {
chainState.state = {
state: "dead",
error: new CrashError(
"Error while creating the chain: " + msg.errorMessage,
),
}
break
}
default: {
// Unexpected message. We ignore it.
// While it could be tempting to switch the chain to `dead`, the extension might
// think that the chain is still alive, and the state mismatch could have
// unpredictable and confusing consequences.
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension",
)
}
}
waitFinished()
break
}
case "ok": {
switch (msg.type) {
case "error": {
chainState.state = {
state: "dead",
error: new CrashError(
"Extension has killed the chain: " + msg.errorMessage,
),
}
break
}
case "rpc": {
if (jsonRpcCallback) {
jsonRpcCallback(msg.jsonRpcMessage)
} else {
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension",
)
}
break
}
default: {
// Unexpected message. We ignore it.
// While it could be tempting to switch the chain to `dead`, the extension might
// think that the chain is still alive, and the state mismatch could have
// unpredictable and confusing consequences.
console.warn(
"Unexpected message of type `msg.type` received from substrate-connect extension",
)
}
}
break
}
case "dead": {
// We don't expect any message anymore.
break
}
}
})
// Now that everything is ready to receive messages back from the extension, send the
// add-chain message.
if (isWellKnown) {
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-well-known-chain",
chainName: chainSpecOrWellKnownName,
})
if (!foundChain) throw new Error("Unknown well-known chain")
chain = foundChain
} else {
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-chain",
chainSpec: chainSpecOrWellKnownName,
potentialRelayChainIds: relayChainId ? [relayChainId] : [],
})
chain = await lightClientProvider.getChain(
chainSpecOrWellKnownName,
relayChainGenesisHash,
)
}
// Wait for the extension to send back either a confirmation or an error.
// Note that `initFinished` becomes ready when `chainState` has been modified. The outcome
// can be known by looking into `chainState`.
await initFinished
const jsonRpcProvider = chain.connect(jsonRpcCallback!)
// In the situation where we tried to create a well-known chain, the extension isn't supposed
// to ever return an error. There is however one situation where errors can happen: if the
// extension doesn't recognize the desired well-known chain because it uses a different list
// of well-known chains than this code. To handle this, we download the chain spec of the
// desired well-known chain and try again but this time as a non-well-known chain.
if (isWellKnown && chainState.state.state === "dead") {
// Note that we keep the same id for the chain for convenience.
let resolve: undefined | (() => void)
const initFinished = new Promise((res) => {
resolve = () => res(null)
})
chainState.state = {
state: "pending",
waitFinished: resolve!,
}
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "add-chain",
chainSpec: await getSpec(chainSpecOrWellKnownName),
potentialRelayChainIds: [],
})
await initFinished
}
// Now check the `chainState` to know if things have succeeded.
if (chainState.state.state === "dead") {
throw chainState.state.error
}
// Everything is successful.
const chain: Chain = {
sendJsonRpc: (jsonRpcMessage) => {
if (chainState.state.state === "dead") {
throw chainState.state.error
}
if (!jsonRpcCallback) throw new JsonRpcDisabledError()
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "rpc",
jsonRpcMessage,
})
return {
sendJsonRpc(rpc: string): void {
jsonRpcProvider.send(rpc)
},
remove: () => {
if (chainState.state.state === "dead") {
throw chainState.state.error
}
chainState.state = {
state: "dead",
error: new AlreadyDestroyedError(),
}
listeners.delete(chainState.id)
postToExtension({
origin: "substrate-connect-client",
chainId: chainState.id,
type: "remove-chain",
})
remove() {
jsonRpcProvider.disconnect()
},

@@ -253,8 +79,6 @@ addChain: function (

jsonRpcCallback,
chainState.id,
chain.genesisHash,
)
},
}
return chain
}

@@ -271,7 +95,1 @@

}
// Sends a message to the extension. This function primarly exists in order to provide strong
// typing for the message.
function postToExtension(msg: ToExtension) {
window.postMessage(msg, "*")
}

@@ -30,3 +30,5 @@ import {

typeof document.getElementById === "function" &&
!!document.getElementById(DOM_ELEMENT_ID)
!!document.getElementById(DOM_ELEMENT_ID) &&
document.getElementById(DOM_ELEMENT_ID)?.getAttribute("channelid") ===
DOM_ELEMENT_ID

@@ -33,0 +35,0 @@ /**

// eslint-disable-next-line import/no-extraneous-dependencies
import { beforeEach, beforeAll, it, describe, expect, vi } from "vitest"
import type { AddChainOptions, ClientOptions } from "smoldot"
import { WellKnownChain } from "../WellKnownChain"
import { WellKnownChain } from "../WellKnownChain.js"

@@ -125,3 +125,3 @@ class SdAlreadyDestroyedError extends Error {

it("does not eagerly instantiate the client", () => {
import("./smoldot-light").then((smoldot) => {
import("./smoldot-light.js").then((smoldot) => {
smoldot.createScClient()

@@ -136,3 +136,3 @@ mockedSmoldotLight =

it("terminates the internal client when all the chains, from all clients, have been removed", () => {
import("./smoldot-light").then(async (smoldot) => {
import("./smoldot-light.js").then(async (smoldot) => {
const { addWellKnownChain, addChain } = smoldot.createScClient()

@@ -163,3 +163,3 @@

it("handles race conditions on the client when adding/removing chains", () => {
import("./smoldot-light").then(async (smoldot) => {
import("./smoldot-light.js").then(async (smoldot) => {
const { addChain } = smoldot.createScClient()

@@ -183,3 +183,3 @@ const { addChain: addChain2 } = smoldot.createScClient()

it("propagates the correct chainSpec to smoldot", () => {
import("./smoldot-light").then(async (smoldot) => {
import("./smoldot-light.js").then(async (smoldot) => {
const { addChain, addWellKnownChain } = smoldot.createScClient()

@@ -214,3 +214,3 @@ const chainSpec = "testChainSpec"

it("propagates the correct potentialRelayChainIds to smoldot", () => {
import("./smoldot-light").then(async (smoldot) => {
import("./smoldot-light.js").then(async (smoldot) => {
const { addChain } = smoldot.createScClient()

@@ -217,0 +217,0 @@ let prevChains = await Promise.all(

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc