diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 2491d2bb15..825772ebbe 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -20,7 +20,7 @@ jobs: timeout-minutes: 60 runs-on: ubuntu-latest container: - image: mcr.microsoft.com/playwright:v1.38.0-jammy + image: mcr.microsoft.com/playwright:v1.40.1-jammy steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 diff --git a/package-lock.json b/package-lock.json index bfef193320..816da99a9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,7 @@ "karma-webkit-launcher": "^2.1.0", "karma-webpack": "github:codymikol/karma-webpack#2337a82beb078c0d8e25ae8333a06249b8e72828", "lint-staged": "^14.0.1", - "playwright": "^1.38.1", + "playwright": "^1.40.1", "size-limit": "^11.0.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", @@ -2887,11 +2887,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", + "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "playwright": "1.38.1" + "playwright": "1.40.1" }, "bin": { "playwright": "cli.js" @@ -7891,9 +7892,9 @@ } }, "node_modules/datastore-core": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.6.tgz", - "integrity": "sha512-7Y79V6Iw5v8Ie2jCT6wiDBaWfZuTPzM3NcJxXOyEGRLJT0qgxa24Yxym83tTuu6rTOB+a+yZZWj0jB4F5lyg8w==", + "version": "9.2.7", + "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.7.tgz", + "integrity": "sha512-S5ADNGRy1p6kHT6Khld+FThe1ITHuUiyYQ84VX2Kv8s6cXDiUuLlYPBIbZaWIgqR/JwxQCwa+5/08w6BZSIAow==", "dependencies": { "@libp2p/logger": "^4.0.1", "err-code": "^3.0.1", @@ -12603,15 +12604,16 @@ } }, "node_modules/it-length-prefixed": { - "version": "9.0.3", - "license": "Apache-2.0 OR MIT", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-9.0.4.tgz", + "integrity": "sha512-lz28fykbG0jq7s5XtvlzGxO5BeSOw6ikymkRllxjL21V5VKLcvB4pHr9wPvEnsAJ2et1xpOk3BRTMq9XrhgKsg==", "dependencies": { "err-code": "^3.0.1", "it-reader": "^6.0.1", "it-stream-types": "^2.0.1", "uint8-varint": "^2.0.1", "uint8arraylist": "^2.0.0", - "uint8arrays": "^4.0.2" + "uint8arrays": "^5.0.1" }, "engines": { "node": ">=16.0.0", @@ -12629,6 +12631,19 @@ "uint8arraylist": "^2.4.1" } }, + "node_modules/it-length-prefixed/node_modules/multiformats": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.0.1.tgz", + "integrity": "sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA==" + }, + "node_modules/it-length-prefixed/node_modules/uint8arrays": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.1.tgz", + "integrity": "sha512-ND5RpJAnPgHmZT7hWD/2T4BwRp04j8NLKvMKC/7bhiEwEjUMkQ4kvBKiH6hOqbljd6qJ2xS8reL3vl1e33grOQ==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, "node_modules/it-map": { "version": "3.0.4", "license": "Apache-2.0 OR MIT", @@ -20782,11 +20797,12 @@ "license": "MIT" }, "node_modules/playwright": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.38.1" + "playwright-core": "1.40.1" }, "bin": { "playwright": "cli.js" @@ -20799,9 +20815,10 @@ } }, "node_modules/playwright-core": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", "dev": true, - "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, @@ -26260,7 +26277,7 @@ "name": "@waku/browser-tests", "version": "0.1.0", "devDependencies": { - "@playwright/test": "^1.37.1", + "@playwright/test": "^1.40.1", "@waku/create-app": "^0.1.1-7c24ffa", "dotenv-flow": "^3.3.0", "serve": "^14.2.1" @@ -26283,7 +26300,7 @@ "@waku/utils": "0.0.14", "debug": "^4.3.4", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", "p-event": "^6.0.0", "uint8arraylist": "^2.4.3", @@ -26490,7 +26507,7 @@ "@waku/utils": "0.0.14", "debug": "^4.3.4", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1" }, "devDependencies": { @@ -26624,7 +26641,7 @@ "allure-mocha": "^2.9.2", "chai": "^4.3.10", "cspell": "^7.3.2", - "datastore-core": "^9.2.6", + "datastore-core": "^9.2.7", "debug": "^4.3.4", "interface-datastore": "^8.2.5", "libp2p": "^0.46.14", @@ -28614,10 +28631,12 @@ } }, "@playwright/test": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.40.1.tgz", + "integrity": "sha512-EaaawMTOeEItCRvfmkI9v6rBkF1svM8wjl/YPRrg2N2Wmp+4qJYkWtJsbew1szfKKDm6fPLy4YAanBhIlf9dWw==", "dev": true, "requires": { - "playwright": "1.38.1" + "playwright": "1.40.1" } }, "@pnpm/config.env-replace": { @@ -29757,7 +29776,7 @@ "@waku/browser-tests": { "version": "file:packages/browser-tests", "requires": { - "@playwright/test": "^1.37.1", + "@playwright/test": "^1.40.1", "@waku/create-app": "^0.1.1-7c24ffa", "dotenv-flow": "^3.3.0", "serve": "^14.2.1" @@ -29790,7 +29809,7 @@ "ignore-loader": "^0.1.2", "isomorphic-fetch": "^3.0.0", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", "mocha": "^10.2.0", "npm-run-all": "^4.1.5", @@ -29980,7 +29999,7 @@ "cspell": "^7.3.2", "debug": "^4.3.4", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", "npm-run-all": "^4.1.5", "rollup": "^4.6.0", @@ -30070,7 +30089,7 @@ "chai": "^4.3.10", "chai-as-promised": "^7.1.1", "cspell": "^7.3.2", - "datastore-core": "^9.2.6", + "datastore-core": "^9.2.7", "debug": "^4.3.4", "dockerode": "^3.3.5", "fast-check": "^3.15.0", @@ -31925,9 +31944,9 @@ "version": "1.0.3" }, "datastore-core": { - "version": "9.2.6", - "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.6.tgz", - "integrity": "sha512-7Y79V6Iw5v8Ie2jCT6wiDBaWfZuTPzM3NcJxXOyEGRLJT0qgxa24Yxym83tTuu6rTOB+a+yZZWj0jB4F5lyg8w==", + "version": "9.2.7", + "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-9.2.7.tgz", + "integrity": "sha512-S5ADNGRy1p6kHT6Khld+FThe1ITHuUiyYQ84VX2Kv8s6cXDiUuLlYPBIbZaWIgqR/JwxQCwa+5/08w6BZSIAow==", "requires": { "@libp2p/logger": "^4.0.1", "err-code": "^3.0.1", @@ -34717,14 +34736,31 @@ } }, "it-length-prefixed": { - "version": "9.0.3", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-9.0.4.tgz", + "integrity": "sha512-lz28fykbG0jq7s5XtvlzGxO5BeSOw6ikymkRllxjL21V5VKLcvB4pHr9wPvEnsAJ2et1xpOk3BRTMq9XrhgKsg==", "requires": { "err-code": "^3.0.1", "it-reader": "^6.0.1", "it-stream-types": "^2.0.1", "uint8-varint": "^2.0.1", "uint8arraylist": "^2.0.0", - "uint8arrays": "^4.0.2" + "uint8arrays": "^5.0.1" + }, + "dependencies": { + "multiformats": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.0.1.tgz", + "integrity": "sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA==" + }, + "uint8arrays": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.1.tgz", + "integrity": "sha512-ND5RpJAnPgHmZT7hWD/2T4BwRp04j8NLKvMKC/7bhiEwEjUMkQ4kvBKiH6hOqbljd6qJ2xS8reL3vl1e33grOQ==", + "requires": { + "multiformats": "^13.0.0" + } + } } }, "it-length-prefixed-stream": { @@ -39737,11 +39773,13 @@ "version": "1.3.6" }, "playwright": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.40.1.tgz", + "integrity": "sha512-2eHI7IioIpQ0bS1Ovg/HszsN/XKNwEG1kbzSDDmADpclKc7CyqkHw7Mg2JCz/bbCxg25QUPcjksoMW7JcIFQmw==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.38.1" + "playwright-core": "1.40.1" }, "dependencies": { "fsevents": { @@ -39752,7 +39790,9 @@ } }, "playwright-core": { - "version": "1.38.1", + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.40.1.tgz", + "integrity": "sha512-+hkOycxPiV534c4HhpfX6yrlawqVUzITRKwHAmYfmsVreltEl6fAZJ3DPfLMOODw0H3s1Itd6MDCWmP1fl/QvQ==", "dev": true }, "playwright-test": { diff --git a/package.json b/package.json index 6f8af36092..08684136af 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "karma-webkit-launcher": "^2.1.0", "karma-webpack": "github:codymikol/karma-webpack#2337a82beb078c0d8e25ae8333a06249b8e72828", "lint-staged": "^14.0.1", - "playwright": "^1.38.1", + "playwright": "^1.40.1", "size-limit": "^11.0.1", "ts-loader": "^9.4.2", "ts-node": "^10.9.1", diff --git a/packages/browser-tests/package.json b/packages/browser-tests/package.json index ae58d24b85..65b09b1ccd 100644 --- a/packages/browser-tests/package.json +++ b/packages/browser-tests/package.json @@ -11,7 +11,7 @@ "test": "npx playwright test" }, "devDependencies": { - "@playwright/test": "^1.37.1", + "@playwright/test": "^1.40.1", "@waku/create-app": "^0.1.1-7c24ffa", "dotenv-flow": "^3.3.0", "serve": "^14.2.1" diff --git a/packages/core/package.json b/packages/core/package.json index 428c35d76a..499de5c9e6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -79,7 +79,7 @@ "@waku/utils": "0.0.14", "debug": "^4.3.4", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", "p-event": "^6.0.0", "uint8arraylist": "^2.4.3", diff --git a/packages/peer-exchange/package.json b/packages/peer-exchange/package.json index a02dd0e217..3b76606112 100644 --- a/packages/peer-exchange/package.json +++ b/packages/peer-exchange/package.json @@ -56,7 +56,7 @@ "@waku/utils": "0.0.14", "debug": "^4.3.4", "it-all": "^3.0.4", - "it-length-prefixed": "^9.0.1", + "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1" }, "devDependencies": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 2a100202b5..74c9e2bd2b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -8,6 +8,19 @@ ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" + }, + "./relay": { + "types": "./dist/relay/index.d.ts", + "import": "./dist/relay/index.js" + } + }, + "typesVersions": { + "*": { + "*": [ + "*", + "dist/*", + "dist/*/index" + ] } }, "type": "module", diff --git a/packages/sdk/src/create.ts b/packages/sdk/src/create.ts index 63e33ee482..4265fb6f4b 100644 --- a/packages/sdk/src/create.ts +++ b/packages/sdk/src/create.ts @@ -22,7 +22,6 @@ import type { Libp2pComponents, LightNode, ProtocolCreateOptions, - RelayNode, ShardingParams } from "@waku/interfaces"; import { wakuPeerExchangeDiscovery } from "@waku/peer-exchange"; @@ -136,47 +135,6 @@ export async function createLightNode( ) as LightNode; } -/** - * Create a Waku node that uses Waku Relay to send and receive messages, - * enabling some privacy preserving properties. - */ -export async function createRelayNode( - options?: ProtocolCreateOptions & WakuOptions & Partial -): Promise { - options = options ?? {}; - - if (options.shardInfo) { - ensureShardingConfigured(options.shardInfo); - } - - const libp2pOptions = options?.libp2p ?? {}; - const peerDiscovery = libp2pOptions.peerDiscovery ?? []; - if (options?.defaultBootstrap) { - peerDiscovery.push(...defaultPeerDiscoveries()); - Object.assign(libp2pOptions, { peerDiscovery }); - } - - const libp2p = await defaultLibp2p( - options.shardInfo, - wakuGossipSub(options), - libp2pOptions, - options?.userAgent - ); - - const relay = wakuRelay(options); - - return new WakuNode( - options, - options.pubsubTopics, - libp2p, - options.shardInfo, - undefined, - undefined, - undefined, - relay - ) as RelayNode; -} - /** * Create a Waku node that uses all Waku protocols. * diff --git a/packages/sdk/src/relay/index.ts b/packages/sdk/src/relay/index.ts new file mode 100644 index 0000000000..d02b989d93 --- /dev/null +++ b/packages/sdk/src/relay/index.ts @@ -0,0 +1,48 @@ +import { WakuNode, WakuOptions } from "@waku/core"; +import type { ProtocolCreateOptions, RelayNode } from "@waku/interfaces"; +import { RelayCreateOptions, wakuGossipSub, wakuRelay } from "@waku/relay"; + +import { defaultLibp2p, defaultPeerDiscoveries } from "../create.js"; + +/** + * Create a Waku node that uses Waku Relay to send and receive messages, + * enabling some privacy preserving properties. + * * @remarks + * This function creates a Relay Node using the Waku Relay protocol. + * While it is technically possible to use this function in a browser environment, + * it is not recommended due to potential performance issues and limited browser capabilities. + * If you are developing a browser-based application, consider alternative approaches like creating a Light Node + * or use this function with caution. + */ +export async function createRelayNode( + options?: ProtocolCreateOptions & WakuOptions & Partial +): Promise { + options = options ?? {}; + + const libp2pOptions = options?.libp2p ?? {}; + const peerDiscovery = libp2pOptions.peerDiscovery ?? []; + if (options?.defaultBootstrap) { + peerDiscovery.push(...defaultPeerDiscoveries()); + Object.assign(libp2pOptions, { peerDiscovery }); + } + + const libp2p = await defaultLibp2p( + options.shardInfo, + wakuGossipSub(options), + libp2pOptions, + options?.userAgent + ); + + const relay = wakuRelay(options); + + return new WakuNode( + options, + options.pubsubTopics, + libp2p, + options.shardInfo, + undefined, + undefined, + undefined, + relay + ) as RelayNode; +} diff --git a/packages/tests/package.json b/packages/tests/package.json index a1e6e15c55..364a245f8c 100644 --- a/packages/tests/package.json +++ b/packages/tests/package.json @@ -82,7 +82,7 @@ "allure-mocha": "^2.9.2", "chai": "^4.3.10", "cspell": "^7.3.2", - "datastore-core": "^9.2.6", + "datastore-core": "^9.2.7", "debug": "^4.3.4", "interface-datastore": "^8.2.5", "libp2p": "^0.46.14", diff --git a/packages/tests/tests/enr.node.spec.ts b/packages/tests/tests/enr.node.spec.ts index f6b7872b65..5959c31f9f 100644 --- a/packages/tests/tests/enr.node.spec.ts +++ b/packages/tests/tests/enr.node.spec.ts @@ -2,7 +2,7 @@ import { waitForRemotePeer } from "@waku/core"; import { EnrDecoder } from "@waku/enr"; import type { RelayNode } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { expect } from "chai"; import { makeLogFileName, NOISE_KEY_1, tearDownNodes } from "../src/index.js"; diff --git a/packages/tests/tests/relay/index.node.spec.ts b/packages/tests/tests/relay/index.node.spec.ts index d6bb19fcff..c62e0b2a3f 100644 --- a/packages/tests/tests/relay/index.node.spec.ts +++ b/packages/tests/tests/relay/index.node.spec.ts @@ -13,7 +13,7 @@ import { createDecoder as createSymDecoder, createEncoder as createSymEncoder } from "@waku/message-encryption/symmetric"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/relay/interop.node.spec.ts b/packages/tests/tests/relay/interop.node.spec.ts index 47cf2eeeba..1304bc9743 100644 --- a/packages/tests/tests/relay/interop.node.spec.ts +++ b/packages/tests/tests/relay/interop.node.spec.ts @@ -1,7 +1,7 @@ import type { PeerId } from "@libp2p/interface/peer-id"; import { DecodedMessage, waitForRemotePeer } from "@waku/core"; import { DefaultPubsubTopic, Protocols, RelayNode } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/relay/multiple_pubsub.node.spec.ts b/packages/tests/tests/relay/multiple_pubsub.node.spec.ts index f070eef140..f9d7fcc582 100644 --- a/packages/tests/tests/relay/multiple_pubsub.node.spec.ts +++ b/packages/tests/tests/relay/multiple_pubsub.node.spec.ts @@ -11,7 +11,7 @@ import { SingleShardInfo } from "@waku/interfaces"; import { Protocols } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { contentTopicToPubsubTopic, singleShardInfoToPubsubTopic diff --git a/packages/tests/tests/relay/publish.node.spec.ts b/packages/tests/tests/relay/publish.node.spec.ts index f550bb4a9e..1f4f8fe1ae 100644 --- a/packages/tests/tests/relay/publish.node.spec.ts +++ b/packages/tests/tests/relay/publish.node.spec.ts @@ -1,6 +1,6 @@ import { createEncoder } from "@waku/core"; import { IRateLimitProof, RelayNode, SendError } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/relay/subscribe.node.spec.ts b/packages/tests/tests/relay/subscribe.node.spec.ts index bb67659cf3..324820bf89 100644 --- a/packages/tests/tests/relay/subscribe.node.spec.ts +++ b/packages/tests/tests/relay/subscribe.node.spec.ts @@ -1,6 +1,6 @@ import { createDecoder, createEncoder } from "@waku/core"; import { DefaultPubsubTopic, RelayNode } from "@waku/interfaces"; -import { createRelayNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; diff --git a/packages/tests/tests/wait_for_remote_peer.node.spec.ts b/packages/tests/tests/wait_for_remote_peer.node.spec.ts index 2f1cd8d661..51608923b1 100644 --- a/packages/tests/tests/wait_for_remote_peer.node.spec.ts +++ b/packages/tests/tests/wait_for_remote_peer.node.spec.ts @@ -1,7 +1,8 @@ import { waitForRemotePeer } from "@waku/core"; import type { LightNode, RelayNode } from "@waku/interfaces"; import { DefaultPubsubTopic, Protocols } from "@waku/interfaces"; -import { createLightNode, createRelayNode } from "@waku/sdk"; +import { createLightNode } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { expect } from "chai"; import { diff --git a/packages/tests/tests/waku.node.spec.ts b/packages/tests/tests/waku.node.spec.ts index e7aa69f176..bfd812517d 100644 --- a/packages/tests/tests/waku.node.spec.ts +++ b/packages/tests/tests/waku.node.spec.ts @@ -14,9 +14,9 @@ import { } from "@waku/message-encryption/symmetric"; import { createLightNode, - createEncoder as createPlainEncoder, - createRelayNode + createEncoder as createPlainEncoder } from "@waku/sdk"; +import { createRelayNode } from "@waku/sdk/relay"; import { bytesToUtf8, utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai";