diff --git a/.changeset/angry-humans-happen.md b/.changeset/angry-humans-happen.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/angry-humans-happen.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/big-boxes-tan.md b/.changeset/big-boxes-tan.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/big-boxes-tan.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/bright-elephants-shop.md b/.changeset/bright-elephants-shop.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/bright-elephants-shop.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/early-humans-count.md b/.changeset/early-humans-count.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/early-humans-count.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/eight-ladybugs-cheer.md b/.changeset/eight-ladybugs-cheer.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/eight-ladybugs-cheer.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/flat-dodos-crash.md b/.changeset/flat-dodos-crash.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/flat-dodos-crash.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/fresh-terms-yell.md b/.changeset/fresh-terms-yell.md new file mode 100644 index 0000000000..d3600a5c0b --- /dev/null +++ b/.changeset/fresh-terms-yell.md @@ -0,0 +1,10 @@ +--- +"@fuel-ts/program": minor +"@fuel-ts/providers": minor +"@fuel-ts/wallet": minor +"@fuel-ts/predicate": minor +--- + +- Transaction execution can now be await with the `{awaitExecution: true}` option on `Provider.sendTransaction` +- Added same functionality to accounts (unlocked wallet, predicate) +- `BaseInvocationScope` internally now uses `{awaitExecution: true}` to reduce amount of network calls diff --git a/.changeset/funny-radios-doubt.md b/.changeset/funny-radios-doubt.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/funny-radios-doubt.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/giant-pumpkins-refuse.md b/.changeset/giant-pumpkins-refuse.md new file mode 100644 index 0000000000..7e1b1c12c6 --- /dev/null +++ b/.changeset/giant-pumpkins-refuse.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/abi-coder": minor +--- + +Improve decode validation of ABI Coders diff --git a/.changeset/gorgeous-tips-walk.md b/.changeset/gorgeous-tips-walk.md new file mode 100644 index 0000000000..aaf5d8d2bd --- /dev/null +++ b/.changeset/gorgeous-tips-walk.md @@ -0,0 +1,7 @@ +--- +"create-fuels": patch +"fuels": patch +"@fuel-ts/utils": patch +--- + +Fixing and internalizing `findBinPath` utility diff --git a/.changeset/happy-days-repeat.md b/.changeset/happy-days-repeat.md new file mode 100644 index 0000000000..26a20c4540 --- /dev/null +++ b/.changeset/happy-days-repeat.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/wallet": minor +--- + +Made provider argument optional for wallet instantiation diff --git a/.changeset/honest-schools-complain.md b/.changeset/honest-schools-complain.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/honest-schools-complain.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/kind-hotels-divide.md b/.changeset/kind-hotels-divide.md new file mode 100644 index 0000000000..7683a22911 --- /dev/null +++ b/.changeset/kind-hotels-divide.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/transactions": minor +--- + +update deposit and withdraw doc page diff --git a/.changeset/late-mugs-kick.md b/.changeset/late-mugs-kick.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/late-mugs-kick.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/odd-kids-buy.md b/.changeset/odd-kids-buy.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/odd-kids-buy.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/olive-clocks-double.md b/.changeset/olive-clocks-double.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/olive-clocks-double.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/perfect-kangaroos-speak.md b/.changeset/perfect-kangaroos-speak.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/perfect-kangaroos-speak.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/poor-ravens-enjoy.md b/.changeset/poor-ravens-enjoy.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/poor-ravens-enjoy.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/rare-snails-shave.md b/.changeset/rare-snails-shave.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/rare-snails-shave.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/real-owls-leave.md b/.changeset/real-owls-leave.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/real-owls-leave.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/rotten-seas-battle.md b/.changeset/rotten-seas-battle.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/rotten-seas-battle.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/selfish-wombats-dance.md b/.changeset/selfish-wombats-dance.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/selfish-wombats-dance.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/serious-laws-judge.md b/.changeset/serious-laws-judge.md new file mode 100644 index 0000000000..23babd84b1 --- /dev/null +++ b/.changeset/serious-laws-judge.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/providers": minor +"@fuel-ts/errors": patch +--- + +Implemented GraphQL subscriptions diff --git a/.changeset/sharp-clocks-camp.md b/.changeset/sharp-clocks-camp.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/sharp-clocks-camp.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/smart-lemons-end.md b/.changeset/smart-lemons-end.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/smart-lemons-end.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/soft-falcons-agree.md b/.changeset/soft-falcons-agree.md new file mode 100644 index 0000000000..114d1a3c8c --- /dev/null +++ b/.changeset/soft-falcons-agree.md @@ -0,0 +1,7 @@ +--- +"@fuel-ts/providers": minor +"@fuel-ts/wallet": minor +"@fuel-ts/wallet-manager": minor +--- + +accepting string as address instead of only AbstractAddress diff --git a/.changeset/soft-wombats-smell.md b/.changeset/soft-wombats-smell.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/soft-wombats-smell.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/spicy-ducks-invent.md b/.changeset/spicy-ducks-invent.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/spicy-ducks-invent.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/stale-lizards-shop.md b/.changeset/stale-lizards-shop.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/stale-lizards-shop.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/swift-students-ring.md b/.changeset/swift-students-ring.md new file mode 100644 index 0000000000..6ec5502856 --- /dev/null +++ b/.changeset/swift-students-ring.md @@ -0,0 +1,5 @@ +--- +"create-fuels": minor +--- + +Update supported node version in create fuels diff --git a/.changeset/tasty-hotels-pay.md b/.changeset/tasty-hotels-pay.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/tasty-hotels-pay.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/tasty-pets-run.md b/.changeset/tasty-pets-run.md new file mode 100644 index 0000000000..4216a1257b --- /dev/null +++ b/.changeset/tasty-pets-run.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/interfaces": patch +"@fuel-ts/utils": patch +--- + +Remove ethers dependency from the utils package diff --git a/.changeset/tender-onions-reflect.md b/.changeset/tender-onions-reflect.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/tender-onions-reflect.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/tender-tips-whisper.md b/.changeset/tender-tips-whisper.md new file mode 100644 index 0000000000..d7132a6ef2 --- /dev/null +++ b/.changeset/tender-tips-whisper.md @@ -0,0 +1,28 @@ +--- +"fuels": minor +"@fuel-ts/utils": minor +"@fuel-ts/wallet": minor +--- + +chore!: share single chainconfig and `launchNode` utility throughout the codebase. + +- `startFuelCore` now re-uses `launchNode` instead of having its own node-launching logic +- `@fuel-ts/utils` now exports a `defaultChainConfig` and a `defaultConsensusKey` which is used everywhere in the source code. +- The `chainConfig.json` file inside the `.fuel-core` folder at the root also uses the same chain config. The `run-node` script has been modified to copy over the contents of the chain config file from the utils package. + +# Breaking Changes + +- Multiple fuel-core config-related options have been removed from `LaunchNodeOptions`: + + - `chainConfigPath` + - `consensusKey` + - `useInMemoryDb` + - `poaInstant` + +- The only way to pass in these config values now is through the `args` property, i.e.: + +```ts +const { cleanup, ip, port } = await launchNode({ + args: ["--poa-interval-period", "750ms", "--poa-instant", "false"], +}); +``` diff --git a/.changeset/thick-windows-tease.md b/.changeset/thick-windows-tease.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/thick-windows-tease.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/twenty-clocks-peel.md b/.changeset/twenty-clocks-peel.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/twenty-clocks-peel.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/warm-poems-swim.md b/.changeset/warm-poems-swim.md new file mode 100644 index 0000000000..c4462671a8 --- /dev/null +++ b/.changeset/warm-poems-swim.md @@ -0,0 +1,6 @@ +--- +"@fuel-ts/signer": minor +--- + +- Stopped exporting `getCurve()` / secp256k1 +- Replaced `elliptic` with `@noble/curves` diff --git a/.changeset/wet-dots-marry.md b/.changeset/wet-dots-marry.md new file mode 100644 index 0000000000..60c9eeba54 --- /dev/null +++ b/.changeset/wet-dots-marry.md @@ -0,0 +1,5 @@ +--- +"@fuel-ts/providers": minor +--- + +Made getOperations to consider multiple assets transfer for a Transfer Asset operation diff --git a/.changeset/wicked-timers-push.md b/.changeset/wicked-timers-push.md new file mode 100644 index 0000000000..a845151cc8 --- /dev/null +++ b/.changeset/wicked-timers-push.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.eslintignore b/.eslintignore index 3e521fec0b..af1f9fa550 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,7 +4,9 @@ dist/ out/ apps/demo-fuels/src/sway-programs-api -apps/demo-typegen/src/generated-types +apps/demo-typegen/src/contract-types +apps/demo-typegen/src/script-types +apps/demo-typegen/src/predicate-types apps/demo-nextjs apps/demo-react-cra apps/demo-react-vite diff --git a/.eslintrc.js b/.eslintrc.js index 370c57d37c..6e46310f85 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,6 +21,12 @@ module.exports = { }, }, rules: { + 'no-restricted-syntax': [ + 'off', + { + selector: 'ForOfStatement', + }, + ], '@typescript-eslint/no-non-null-assertion': 1, // Disable error on devDependencies importing since this isn't a TS library 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], @@ -56,7 +62,6 @@ module.exports = { 'warn', { argsIgnorePattern: '^_', - varsIgnorePattern: '^_', }, ], '@typescript-eslint/no-explicit-any': 'error', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1616404c9e..a37a76de9b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @digorithm @arboleya @camsjams @Torres-ssf @Dhaiwat10 @danielbate @nedsalk +* @digorithm @arboleya @Torres-ssf @Dhaiwat10 @danielbate @nedsalk diff --git a/.github/actions/ci-setup/action.yaml b/.github/actions/ci-setup/action.yaml index 9343b93b1c..aff49b09ed 100644 --- a/.github/actions/ci-setup/action.yaml +++ b/.github/actions/ci-setup/action.yaml @@ -2,7 +2,7 @@ name: "CI Setup" inputs: node-version: description: "Node version" - default: 18.17.1 + default: 20.10.0 pnpm-version: description: "PNPM version" default: 8.9.0 diff --git a/.github/actions/test-setup/action.yaml b/.github/actions/test-setup/action.yaml index 94cadf1e6a..b6541ef9e5 100644 --- a/.github/actions/test-setup/action.yaml +++ b/.github/actions/test-setup/action.yaml @@ -2,7 +2,7 @@ name: "Test Setup" inputs: node-version: description: "Node version" - default: 18.17.1 + default: 20.10.0 pnpm-version: description: "PNPM version" default: 8.9.0 diff --git a/.github/rc-list.md b/.github/rc-list.md new file mode 100644 index 0000000000..57069e7c6e --- /dev/null +++ b/.github/rc-list.md @@ -0,0 +1,148 @@ +- [ ] African Elephant +- [ ] Albatross +- [ ] Alpaca +- [ ] Angelfish +- [ ] Ant +- [ ] Appaloosa +- [ ] Arabian Horse +- [ ] Arctic Fox +- [ ] Asian Elephant +- [ ] Bactrian Camel +- [ ] Bald Eagle +- [ ] Beagle +- [ ] Bee +- [ ] Beluga Whale +- [ ] Black Bear +- [ ] Blue Jay +- [ ] Blue Whale +- [ ] Bobcat +- [ ] Brown Bear +- [ ] Bulldog +- [ ] Butterfly +- [ ] Camel +- [ ] Caracal +- [ ] Cardinal +- [ ] Cheetah +- [ ] Chicken +- [ ] Chimpanzee +- [ ] Clownfish +- [ ] Clydesdale +- [ ] Cockatoo +- [ ] Cockroach +- [ ] Coral +- [ ] Cougar +- [ ] Coyote +- [ ] Crab +- [ ] Cricket +- [ ] Crow +- [ ] Cuttlefish +- [ ] Dachshund +- [ ] Dingo +- [ ] Dolphin +- [ ] Domestic Cat +- [ ] Domestic Dog +- [ ] Dragonfly +- [ ] Dromedary +- [ ] Duck +- [ ] Elephant +- [ ] Falcon +- [ ] Fennec Fox +- [ ] Finch +- [ ] Firefly +- [ ] Flamingo +- [ ] Friesian +- [ ] German Shepherd +- [ ] Giraffe +- [ ] Golden Retriever +- [ ] Goose +- [ ] Gorilla +- [ ] Grasshopper +- [ ] Grevy's Zebra +- [ ] Grizzly Bear +- [ ] Hawk +- [ ] Hermit Crab +- [ ] Hippopotamus +- [ ] Hornet +- [ ] Horse +- [ ] Hummingbird +- [ ] Humpback Whale +- [ ] Husky +- [ ] Hyena +- [ ] Jaguar +- [ ] Jellyfish +- [ ] Kangaroo +- [ ] Katydid +- [ ] Kingfisher +- [ ] Koala +- [ ] Labrador Retriever +- [ ] Ladybug +- [ ] Leopard +- [ ] Lion +- [ ] Llama +- [ ] Lobster +- [ ] Lynx +- [ ] Macaw +- [ ] Magpie +- [ ] Manatee +- [ ] Mantis Shrimp +- [ ] Moth +- [ ] Mountain Lion +- [ ] Mountain Zebra +- [ ] Mustang +- [ ] Narwhal +- [ ] Nautilus +- [ ] Octopus +- [ ] Orca +- [ ] Ostrich +- [ ] Owl +- [ ] Palomino +- [ ] Panda +- [ ] Panther +- [ ] Parrot +- [ ] Peacock +- [ ] Pelican +- [ ] Penguin +- [ ] Pigeon +- [ ] Plains Zebra +- [ ] Polar Bear +- [ ] Pony +- [ ] Poodle +- [ ] Praying Mantis +- [ ] Pufferfish +- [ ] Puffin +- [ ] Quarter Horse +- [ ] Raven +- [ ] Red Panda +- [ ] Rhino +- [ ] Rhinoceros Beetle +- [ ] Robin +- [ ] Rooster +- [ ] Rottweiler +- [x] Salamander +- [ ] Scarab Beetle +- [ ] Sea Anemone +- [ ] Sea Cucumber +- [ ] Sea Lion +- [ ] Sea Urchin +- [ ] Seahorse +- [ ] Seal +- [ ] Serval +- [ ] Shetland Pony +- [ ] Shrimp +- [ ] Snow Leopard +- [ ] Sparrow +- [ ] Sperm Whale +- [ ] Squid +- [ ] Starfish +- [ ] Stork +- [ ] Swan +- [ ] Thoroughbred +- [ ] Tiger +- [ ] Toucan +- [ ] Turkey +- [ ] VicuΓ±a +- [ ] Walrus +- [ ] Wasp +- [ ] Wolf +- [ ] Woodpecker +- [ ] Zebra diff --git a/.github/workflows/pr-lint.yaml b/.github/workflows/pr-lint.yaml index 6978cf6b1f..de7a77c30d 100644 --- a/.github/workflows/pr-lint.yaml +++ b/.github/workflows/pr-lint.yaml @@ -19,6 +19,14 @@ jobs: - uses: amannn/action-semantic-pull-request@v4 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + types: | + feat + fix + chore + docs + ci + rc validate-changeset: name: Validate PR Changeset diff --git a/.github/workflows/rc-release.yaml b/.github/workflows/rc-release.yaml new file mode 100644 index 0000000000..e50d9082af --- /dev/null +++ b/.github/workflows/rc-release.yaml @@ -0,0 +1,69 @@ +name: Release to @rc- tag on npm + +on: + pull_request: + branches: + - "master" + +jobs: + release-pr: + # Switch to `true` for release candidates + if: ${{ true && startsWith(github.head_ref, 'rc/') }} + name: "Release RC to npm" + runs-on: ubuntu-latest + permissions: write-all + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.ref }} + + - name: CI Setup + uses: ./.github/actions/ci-setup + + - name: Ensure NPM access + run: npm whoami + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Build + run: pnpm build + + - name: Get RC name + uses: frabert/replace-string-action@v2 + id: rc_name + with: + string: ${{ github.head_ref }} + pattern: "rc/" + replace-with: "rc-" + + - name: Release to @${{ steps.rc_name.outputs.replaced }} tag on npm + id: release + run: | + echo "${{ steps.rc_name.outputs.replaced }}" + pnpm changeset:next + git add .changeset/fuel-labs-ci.md + pnpm changeset version --snapshot ${{ steps.rc_name.outputs.replaced }} + changetsets=$(pnpm changeset publish --tag ${{ steps.rc_name.outputs.replaced }}) + published_version=$(echo "$changetsets" | grep -oP '@\K([0-9]+\.){2}[0-9]+-${{ steps.rc_name.outputs.replaced }}-\d+' | head -1) + echo "published_version=$published_version" >> $GITHUB_OUTPUT + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Add PR comment + uses: mshick/add-pr-comment@v2 + with: + message: | + RC published under the `${{ steps.rc_name.outputs.replaced }}` tag. + + Install it: + ```bash + pnpm add fuels@${{ steps.rc_name.outputs.replaced }} + pnpm add fuels@${{ steps.release.outputs.published_version }} + ``` + Check it out: + - https://www.npmjs.com/package/fuels/v/${{ steps.rc_name.outputs.replaced }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f09ae9d77f..e2b8da8fd2 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -17,8 +17,19 @@ jobs: doc-folder-path: "apps/docs/src" spellcheck-config-path: "apps/docs/.spellcheck.yml" - test: - runs-on: buildjet-4vcpu-ubuntu-2204 + environments: + runs-on: ubuntu-latest + # name will be node@ or browser + name: ${{ matrix.env.name }}${{ matrix.env.name == 'node' && '@' || ''}}${{ matrix.env.name == 'node' && matrix.env.version || ''}} + strategy: + fail-fast: false + matrix: + env: + [ + { name: node, version: 18.18.2 }, + { name: node, version: 20 }, + { name: browser }, + ] timeout-minutes: 25 steps: - name: Checkout @@ -26,6 +37,8 @@ jobs: - name: CI Setup uses: ./.github/actions/test-setup + with: + node-version: ${{ matrix.env.version || 20 }} - name: Verify package.json integrity run: pnpm lint:package-jsons @@ -40,43 +53,86 @@ jobs: - name: Lint run: pnpm lint + - name: Validate Tests + run: pnpm test:validate + + - name: Run Tests - ${{ matrix.env.name }} + run: pnpm ci:test --${{ matrix.env.name }} + + - name: Upload Coverage - ${{ matrix.env.name }} + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.env.name }} + path: coverage/environments/${{ matrix.env.name }} + + test: + runs-on: ubuntu-latest + needs: [environments] + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: CI Setup + uses: ./.github/actions/test-setup + + - name: Generate Coverage Directory + run: mkdir -p coverage/environments + + - name: Download Coverage Artifact for Node Tests + uses: actions/download-artifact@v3 + with: + name: node + path: coverage/environments + + - name: Generate Coverage + run: pnpm test:coverage-merge + - name: Find PR Number uses: jwalton/gh-find-current-pr@v1 id: findPr - - name: Run tests and collect coverage - if: ${{ !steps.findPr.outputs.number }} - run: pnpm ci:test -- --json --coverage --testLocationInResults --outputFile=report.master.json - - - name: Upload coverage to Github artifacts + - name: Upload Master Coverage Artifact uses: actions/upload-artifact@v3 if: ${{ !steps.findPr.outputs.number }} with: - name: coverage-reports - path: report.master.json + name: coverage-master + path: coverage/report - - name: Download coverage artifact + - name: Download Master Coverage Artifact uses: dawidd6/action-download-artifact@v2 - if: ${{ steps.findPr.outputs.number }} + # change to pr number check when rc/salamander has been merged + if: false with: workflow: test.yaml branch: master - name: coverage-reports - path: coverage-reports + name: coverage-master + path: coverage-master + + - name: Download Master Coverage Artifact (temporary) + uses: dawidd6/action-download-artifact@v2 + if: ${{ (steps.findPr.outputs.number) }} + with: + workflow: test.yaml + run_id: 7625704138 + name: coverage-master + path: coverage-master + + - name: Generate Coverage Diff + if: ${{ (steps.findPr.outputs.number) }} + run: pnpm test:coverage-diff - - name: Run tests and post reports to PR - uses: ArtiomTr/jest-coverage-report-action@v2 + - name: Report Coverage + uses: thollander/actions-comment-pull-request@v2 if: ${{ steps.findPr.outputs.number }} with: - github-token: ${{ secrets.GITHUB_TOKEN }} - package-manager: pnpm - annotations: failed-tests - test-script: pnpm ci:test - prnumber: ${{ steps.findPr.outputs.number }} - base-coverage-file: coverage-reports/report.master.json - - live-tests: - name: Run Live Tests + filePath: coverage/report/coverage-diff.txt + pr_number: ${{ (steps.findPr.outputs.number) }} + comment_tag: diff + mode: recreate + create_if_not_exists: true + + test-e2e: + name: e2e if: github.head_ref == 'changeset-release/master' runs-on: ubuntu-latest timeout-minutes: 5 diff --git a/.gitignore b/.gitignore index b75e9f4c6f..0f6c8b2285 100644 --- a/.gitignore +++ b/.gitignore @@ -148,3 +148,6 @@ Forc.lock # dir used by fuel-core for storing db data .fuel-core/db + +# This chainConfig is copied over from @fuel-ts/utils at runtime, no need to track it +.fuel-core/configs/chainConfig.json \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 4a1f488b6c..d5a159609d 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -18.17.1 +20.10.0 diff --git a/.nycrc b/.nycrc new file mode 100644 index 0000000000..c455077f07 --- /dev/null +++ b/.nycrc @@ -0,0 +1,15 @@ +{ + "extends": "@istanbuljs/nyc-config-typescript", + "reporter": ["json-summary"], + "include": ["packages", "internal", "apps"], + "exclude": [ + "**/node_modules/**", + "**/dist/**", + "**/test/**", + "**/*.test.ts", + "**/*.d.ts", + "packages/fuel-gauge/**", + "apps/demo-*", + "apps/docs" + ] +} diff --git a/.prettierignore b/.prettierignore index 056b5fbe74..b1453972f9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,7 +8,9 @@ apps/demo-fuels/src/sway-programs-api apps/demo-nextjs apps/demo-react-cra apps/demo-react-vite -apps/demo-typegen/src/generated-types +apps/demo-typegen/src/contract-types +apps/demo-typegen/src/script-types +apps/demo-typegen/src/predicate-types apps/docs/.vitepress/cache/ packages/fuels/test/fixtures/project diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f9973f0034..05ca390723 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,6 @@ { "recommendations": [ - "orta.vscode-jest", + "ZixuanChen.vitest-explorer", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint" ] diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7b10da99fa..0000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "configurations": [ - { - "type": "node", - "name": "vscode-jest-tests.v2", - "request": "launch", - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "disableOptimisticBPs": true, - "program": "${workspaceFolder}/node_modules/jest/bin/jest.js", - "cwd": "${workspaceFolder}", - "args": [ - "--runInBand", - "--watchAll=false", - "--testNamePattern", - "${jest.testNamePattern}", - "--runTestsByPath", - "${jest.testFile}" - ] - } - ] -} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c67d51409e..acfb6efa03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,14 +107,17 @@ And then run the tests in another terminal tab: # run all tests pnpm test -# run tests while passing other flags to sub-program -pnpm test -- --coverage --my-other-flag +# watch all tests +pnpm test:watch # run tests for a specific package -pnpm test packages/my-desired-package +pnpm test:filter packages/my-desired-package # run tests for a specific file -pnpm test packages/my-desired-package/src/my.test.ts +pnpm test:filter packages/my-desired-package/src/my.test.ts + +# run tests while passing other flags to sub-program +pnpm test -- --coverage --my-other-flag ``` Or if you want to start a local Fuel-Core node and run all tests serially you can do: diff --git a/README.md b/README.md index c4a6173541..2fd1abbf38 100644 --- a/README.md +++ b/README.md @@ -7,20 +7,20 @@ [![test](https://github.com/FuelLabs/fuels-ts/actions/workflows/test.yaml/badge.svg)](https://github.com/FuelLabs/fuels-ts/actions/workflows/test.yaml) [![npm](https://img.shields.io/npm/v/fuels)](https://www.npmjs.com/package/fuels) -[![docs](https://img.shields.io/badge/docs-fuels.ts-brightgreen.svg?style=flat)](https://fuellabs.github.io/fuels-ts/) +[![docs](https://img.shields.io/badge/docs-fuels.ts-brightgreen.svg?style=flat)](https://docs.fuel.network/docs/fuels-ts/) [![discord](https://img.shields.io/badge/chat%20on-discord-orange?&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/xfpK4Pe) # Resources -The [documentation](https://fuellabs.github.io/fuels-ts) site is your main stop for resources. +The [documentation](https://docs.fuel.network/docs/fuels-ts/) site is your main stop for resources. -- [Quickstart](https://fuellabs.github.io/fuel-docs/master/quickstart/developer-quickstart.html) -- [Documentation](https://fuellabs.github.io/fuels-ts) - - [Wallets](https://fuellabs.github.io/fuels-ts/guide/wallets/) - - [Contracts](https://fuellabs.github.io/fuels-ts/guide/contracts/) - - [Scripts](https://fuellabs.github.io/fuels-ts/guide/scripts/) - - [Predicates](https://fuellabs.github.io/fuels-ts/guide/predicates/) - - [ABI Typegen](https://fuellabs.github.io/fuels-ts/guide/abi-typegen/) +- [Quickstart](https://docs.fuel.network/docs/intro/quickstart-contract/) +- [Documentation](https://docs.fuel.network/docs/fuels-ts/) + - [Wallets](https://docs.fuel.network/docs/fuels-ts/wallets/) + - [Contracts](https://docs.fuel.network/docs/fuels-ts/contracts/) + - [Scripts](https://docs.fuel.network/docs/fuels-ts/scripts/) + - [Predicates](https://docs.fuel.network/docs/fuels-ts/predicates/) + - [ABI Typegen](https://docs.fuel.network/docs/fuels-ts/abi-typegen/) - [Contributing](https://github.com/FuelLabs/fuels-ts/blob/master/CONTRIBUTING.md) - [The Fuel Forum](https://forum.fuel.network/) - [The Fuel Ecosystem](#the-fuel-ecosystem) @@ -51,7 +51,7 @@ console.log(new Wallet("0x0000...0000")); Fuels include some utility commands via built-in CLI tool. -Check the [docs](https://fuellabs.github.io/fuels-ts) for more info. +Check the [docs](https://docs.fuel.network/docs/fuels-ts/) for more info. ```console $ npm add fuels @@ -80,8 +80,8 @@ Commands: Learn more about the Fuel Ecosystem. -- [🌴 Sway](https://fuellabs.github.io/sway/) β€” The new language, empowering everyone to build reliable and efficient smart contracts -- [🧰 Forc](https://fuellabs.github.io/sway/v0.30.1/forc/index.html) β€” The Fuel toolbox: _Build, deploy and manage your sway projects_ +- [🌴 Sway](https://docs.fuel.network/docs/sway/) β€” The new language, empowering everyone to build reliable and efficient smart contracts +- [🧰 Forc](https://docs.fuel.network/docs/forc/) β€” The Fuel toolbox: _Build, deploy and manage your sway projects_ - [βš™οΈ Fuel Core](https://github.com/FuelLabs/fuel-core) β€” The new FuelVM, a blazingly fast blockchain VM - [πŸ”— Fuel Specs](https://github.com/FuelLabs/fuel-specs) β€” The Fuel protocol specifications - [πŸ’Ό Fuels Wallet](https://github.com/FuelLabs/fuels-wallet) β€” The Official Fuels Wallet diff --git a/apps/demo-fuels/src/index.test.ts b/apps/demo-fuels/src/index.test.ts index bbe32a6c31..cb5d1d61c6 100644 --- a/apps/demo-fuels/src/index.test.ts +++ b/apps/demo-fuels/src/index.test.ts @@ -14,6 +14,10 @@ import { SampleAbi__factory } from './sway-programs-api'; import bytecode from './sway-programs-api/contracts/SampleAbi.hex'; let gasPrice: BN; + +/** + * @group node + */ describe('ExampleContract', () => { beforeAll(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/apps/demo-fuels/tsdoc.json b/apps/demo-fuels/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/apps/demo-fuels/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/apps/demo-nextjs/public/inter.ttf b/apps/demo-nextjs/public/inter.ttf new file mode 100644 index 0000000000..5e4851f0ab Binary files /dev/null and b/apps/demo-nextjs/public/inter.ttf differ diff --git a/apps/demo-nextjs/src/app/layout.tsx b/apps/demo-nextjs/src/app/layout.tsx index 71b3fbf054..5e58c28261 100644 --- a/apps/demo-nextjs/src/app/layout.tsx +++ b/apps/demo-nextjs/src/app/layout.tsx @@ -1,7 +1,7 @@ import './globals.css' -import { Inter } from 'next/font/google' +import localFont from 'next/font/local' -const inter = Inter({ subsets: ['latin'] }) +const inter = localFont({ src: '../../public/inter.ttf' }) export const metadata = { title: 'Create Next App', diff --git a/apps/demo-typegen/contract/src/main.sw b/apps/demo-typegen/contract/src/main.sw index c81680df79..cae4ca17db 100644 --- a/apps/demo-typegen/contract/src/main.sw +++ b/apps/demo-typegen/contract/src/main.sw @@ -1,4 +1,4 @@ -// #region Testing-with-jest-rust +// #region Testing-in-ts-rust contract; abi DemoContract { @@ -10,4 +10,4 @@ impl DemoContract for Contract { input } } -// #endregion Testing-with-jest-rust +// #endregion Testing-in-ts-rust diff --git a/apps/demo-typegen/package.json b/apps/demo-typegen/package.json index 84e0f90725..c105a25e3d 100644 --- a/apps/demo-typegen/package.json +++ b/apps/demo-typegen/package.json @@ -5,8 +5,14 @@ "author": "Fuel Labs (https://fuel.network/)", "scripts": { "pretest": "run-s build:forc build:types", - "build:forc": "pnpm fuels-forc build -p contract", - "build:types": "pnpm fuels typegen -i contract/out/debug/demo-contract-abi.json -o src/generated-types" + "build:forc": "run-p forc:*", + "forc:contract": "pnpm fuels-forc build -p contract", + "forc:script": "pnpm fuels-forc build -p script", + "forc:predicate": "pnpm fuels-forc build -p predicate", + "build:types": "run-p types:*", + "types:contract": "pnpm fuels typegen -i contract/out/debug/demo-contract-abi.json -o src/contract-types", + "types:script": "pnpm fuels typegen -i script/out/debug/script-abi.json -o src/script-types --script", + "types:predicate": "pnpm fuels typegen -i predicate/out/debug/predicate-abi.json -o src/predicate-types --predicate" }, "license": "Apache-2.0", "dependencies": { diff --git a/apps/demo-typegen/predicate/.gitignore b/apps/demo-typegen/predicate/.gitignore new file mode 100644 index 0000000000..77d3844f58 --- /dev/null +++ b/apps/demo-typegen/predicate/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/apps/demo-typegen/predicate/Forc.toml b/apps/demo-typegen/predicate/Forc.toml new file mode 100644 index 0000000000..b3325bf145 --- /dev/null +++ b/apps/demo-typegen/predicate/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "predicate" + +[dependencies] diff --git a/packages/fuels/test/fixtures/project/predicates/predicate/src/main.sw b/apps/demo-typegen/predicate/src/main.sw similarity index 100% rename from packages/fuels/test/fixtures/project/predicates/predicate/src/main.sw rename to apps/demo-typegen/predicate/src/main.sw diff --git a/apps/demo-typegen/script/.gitignore b/apps/demo-typegen/script/.gitignore new file mode 100644 index 0000000000..77d3844f58 --- /dev/null +++ b/apps/demo-typegen/script/.gitignore @@ -0,0 +1,2 @@ +out +target diff --git a/apps/demo-typegen/script/Forc.toml b/apps/demo-typegen/script/Forc.toml new file mode 100644 index 0000000000..937fd72852 --- /dev/null +++ b/apps/demo-typegen/script/Forc.toml @@ -0,0 +1,7 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "script" + +[dependencies] diff --git a/apps/demo-typegen/script/src/main.sw b/apps/demo-typegen/script/src/main.sw new file mode 100644 index 0000000000..93cb6bc581 --- /dev/null +++ b/apps/demo-typegen/script/src/main.sw @@ -0,0 +1,5 @@ +script; + +fn main() -> u8 { + 10 +} diff --git a/apps/demo-typegen/src/demo.test.ts b/apps/demo-typegen/src/demo.test.ts index 484f865eef..7402402564 100644 --- a/apps/demo-typegen/src/demo.test.ts +++ b/apps/demo-typegen/src/demo.test.ts @@ -1,18 +1,49 @@ -// #region Testing-with-jest-ts +// #region Testing-in-ts-ts import { safeExec } from '@fuel-ts/errors/test-utils'; import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; import type { BN } from 'fuels'; -import { ContractFactory, Provider, toHex, BaseAssetId, Wallet, FUEL_NETWORK_URL } from 'fuels'; - -import { DemoContractAbi__factory } from './generated-types'; -import bytecode from './generated-types/DemoContractAbi.hex'; +import { + ContractFactory, + Provider, + toHex, + BaseAssetId, + Wallet, + FUEL_NETWORK_URL, + Address, +} from 'fuels'; + +import storageSlots from '../contract/out/debug/demo-contract-storage_slots.json'; + +import { DemoContractAbi__factory } from './contract-types'; +import bytecode from './contract-types/DemoContractAbi.hex'; +import { PredicateAbi__factory } from './predicate-types'; +import { ScriptAbi__factory } from './script-types'; let gasPrice: BN; + +/** + * @group node + */ describe('ExampleContract', () => { beforeAll(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); ({ minGasPrice: gasPrice } = provider.getGasConfig()); }); + it('with imported storage slots', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); + + // #region typegen-demo-contract-storage-slots + // #context import storageSlots from './contract/out/debug/demo-contract-storage_slots.json'; + + const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet, { + storageSlots, + gasPrice, + }); + // #endregion typegen-demo-contract-storage-slots + + expect(contract.id).toBeTruthy(); + }); it('should return the input', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); @@ -20,6 +51,7 @@ describe('ExampleContract', () => { // Deploy const factory = new ContractFactory(bytecode, DemoContractAbi__factory.abi, wallet); const contract = await factory.deployContract({ gasPrice }); + const contractId = contract.id; // Call const { value } = await contract.functions @@ -31,11 +63,15 @@ describe('ExampleContract', () => { expect(value.toHex()).toEqual(toHex(1337)); // You can also make a call using the factory - const contractInstance = DemoContractAbi__factory.connect(contract.id, wallet); + // #region typegen-demo-contract-factory-connect + // #context import { DemoContractAbi__factory } from './types'; + + const contractInstance = DemoContractAbi__factory.connect(contractId, wallet); const { value: v2 } = await contractInstance.functions .return_input(1337) .txParams({ gasPrice, gasLimit: 10_000 }) .call(); + // #endregion typegen-demo-contract-factory-connect expect(v2.toHex()).toBe(toHex(1337)); }); @@ -43,8 +79,13 @@ describe('ExampleContract', () => { const provider = await Provider.create(FUEL_NETWORK_URL); const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); + // #region typegen-demo-contract-factory-deploy + // #context import { DemoContractAbi__factory } from './types'; + // #context import bytecode from './types/DemoContractAbi.hex'; + // Deploy const contract = await DemoContractAbi__factory.deployContract(bytecode, wallet, { gasPrice }); + // #endregion typegen-demo-contract-factory-deploy // Call const { value } = await contract.functions @@ -56,7 +97,7 @@ describe('ExampleContract', () => { expect(value.toHex()).toEqual(toHex(1337)); }); }); -// #endregion Testing-with-jest-ts +// #endregion Testing-in-ts-ts it('should throw when simulating via contract factory with wallet with no resources', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); @@ -89,3 +130,58 @@ it('should throw when dry running via contract factory with wallet with no resou expect((error).message).toMatch('not enough coins to fit the target'); }); + +test('Example script', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); + + // TODO: investigate why do we need to specify the gasLimit here. If we don't specify it, the call fails saying `FuelError: Gas limit '0' is lower than the required: '19'.` + + // #region typegen-demo-script + // #context import { ScriptAbi__factory } from './types'; + + const script = ScriptAbi__factory.createInstance(wallet); + const { value } = await script.functions + .main() + .txParams({ + gasPrice: provider.getGasConfig().minGasPrice, + gasLimit: 10_000, + }) + .call(); + // #endregion typegen-demo-script + // @ts-expect-error TODO: investitage - typegen is expecting value to be a number but the value being returned is the string '0xa' + expect(value.toNumber()).toBe(10); +}); + +test('Example predicate', async () => { + // #region typegen-demo-predicate + // #context import { PredicateAbi__factory } from './types'; + + // In this exchange, we are first transferring some coins to the predicate + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = await generateTestWallet(provider, [[500_000, BaseAssetId]]); + const receiver = Wallet.fromAddress(Address.fromRandom(), provider); + + const predicate = PredicateAbi__factory.createInstance(provider); + + const tx = await wallet.transfer(predicate.address, 100_000, BaseAssetId, { + gasPrice: provider.getGasConfig().minGasPrice, + gasLimit: 50, + }); + await tx.wait(); + + const initialPredicateBalance = await predicate.getBalance(); + + // Then we are transferring some coins from the predicate to a random address (receiver) + const tx2 = await predicate.transfer(receiver.address, 50_000, BaseAssetId, { + gasPrice: provider.getGasConfig().minGasPrice, + gasLimit: 50, + }); + await tx2.wait(); + + expect((await receiver.getBalance()).toNumber()).toEqual(50_000); + expect((await predicate.getBalance()).toNumber()).toBeLessThan( + initialPredicateBalance.toNumber() + ); + // #endregion typegen-demo-predicate +}); diff --git a/apps/demo-typegen/tsdoc.json b/apps/demo-typegen/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/apps/demo-typegen/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts b/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts index e7dff25913..deca9db380 100644 --- a/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts +++ b/apps/docs-snippets/src/guide/contracts/call-parameters.test.ts @@ -4,6 +4,9 @@ import { BN, BaseAssetId } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/contracts/calls-with-different-wallets.test.ts b/apps/docs-snippets/src/guide/contracts/calls-with-different-wallets.test.ts index c0f4d3c7ea..232eec8f9c 100644 --- a/apps/docs-snippets/src/guide/contracts/calls-with-different-wallets.test.ts +++ b/apps/docs-snippets/src/guide/contracts/calls-with-different-wallets.test.ts @@ -4,6 +4,9 @@ import { FUEL_NETWORK_URL, Provider, WalletUnlocked } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let deployedContract: Contract; diff --git a/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts b/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts index a9326298b2..25349667a0 100644 --- a/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts +++ b/apps/docs-snippets/src/guide/contracts/configurable-constants.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe('configurable-constants', () => { let wallet: WalletUnlocked; diff --git a/apps/docs-snippets/src/guide/contracts/contract-balance.test.ts b/apps/docs-snippets/src/guide/contracts/contract-balance.test.ts index 513b03add9..cfa83ec3e4 100644 --- a/apps/docs-snippets/src/guide/contracts/contract-balance.test.ts +++ b/apps/docs-snippets/src/guide/contracts/contract-balance.test.ts @@ -4,6 +4,9 @@ import { Wallet, BN, BaseAssetId, Provider, FUEL_NETWORK_URL } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts b/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts index d946b662a1..7aa93a9de0 100644 --- a/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts +++ b/apps/docs-snippets/src/guide/contracts/cost-estimation.test.ts @@ -3,6 +3,9 @@ import { BaseAssetId, type Contract, type Provider } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts b/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts index 290a232020..1bee45e5e2 100644 --- a/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts +++ b/apps/docs-snippets/src/guide/contracts/deploying-contracts.test.ts @@ -5,6 +5,9 @@ import { join } from 'path'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let PRIVATE_KEY: string; let projectsPath: string; diff --git a/apps/docs-snippets/src/guide/contracts/index.test.ts b/apps/docs-snippets/src/guide/contracts/index.test.ts index 9f59c61fbd..b2a627007e 100644 --- a/apps/docs-snippets/src/guide/contracts/index.test.ts +++ b/apps/docs-snippets/src/guide/contracts/index.test.ts @@ -3,6 +3,9 @@ import type { Contract } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts b/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts index 603a71f3a8..63a2c8e493 100644 --- a/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts +++ b/apps/docs-snippets/src/guide/contracts/inter-contract-calls.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let wallet: WalletUnlocked; let simpleToken: Contract; diff --git a/apps/docs-snippets/src/guide/contracts/logs.test.ts b/apps/docs-snippets/src/guide/contracts/logs.test.ts index 8bc759e3a0..9bdec2f849 100644 --- a/apps/docs-snippets/src/guide/contracts/logs.test.ts +++ b/apps/docs-snippets/src/guide/contracts/logs.test.ts @@ -4,6 +4,9 @@ import { BN } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts b/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts index bb30ec6eff..10580b42d7 100644 --- a/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts +++ b/apps/docs-snippets/src/guide/contracts/managing-deployed-contracts.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let contractId: AbstractAddress; diff --git a/apps/docs-snippets/src/guide/contracts/multicalls.test.ts b/apps/docs-snippets/src/guide/contracts/multicalls.test.ts index 5568668519..0f99c71676 100644 --- a/apps/docs-snippets/src/guide/contracts/multicalls.test.ts +++ b/apps/docs-snippets/src/guide/contracts/multicalls.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let echoContract: Contract; let counterContract: Contract; diff --git a/apps/docs-snippets/src/guide/contracts/simulate-transactions.test.ts b/apps/docs-snippets/src/guide/contracts/simulate-transactions.test.ts index 496670b215..847771c308 100644 --- a/apps/docs-snippets/src/guide/contracts/simulate-transactions.test.ts +++ b/apps/docs-snippets/src/guide/contracts/simulate-transactions.test.ts @@ -8,6 +8,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { it('should successfully simulate contract call with forwarded amount', async () => { const contract = await createAndDeployContractFromProject( diff --git a/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts b/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts index eb7f369d53..7c5ce65d7b 100644 --- a/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts +++ b/apps/docs-snippets/src/guide/contracts/transaction-parameters.test.ts @@ -4,6 +4,9 @@ import { BN, PolicyType } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts b/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts new file mode 100644 index 0000000000..dfc1b2c120 --- /dev/null +++ b/apps/docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts @@ -0,0 +1,64 @@ +import type { Contract, WalletUnlocked, Provider } from 'fuels'; +import { ContractFactory, BaseAssetId, Wallet, ZeroBytes32, getAssetId } from 'fuels'; + +import { + DocSnippetProjectsEnum, + getDocsSnippetsForcProject, +} from '../../../test/fixtures/forc-projects'; +import { getTestWallet } from '../../utils'; + +/** + * @group node + */ +describe(__filename, () => { + let sender: WalletUnlocked; + let liquidityPoolContract: Contract; + let provider: Provider; + + beforeAll(async () => { + sender = await getTestWallet(); + + const { abiContents, binHexlified } = getDocsSnippetsForcProject( + DocSnippetProjectsEnum.LIQUIDITY_POOL + ); + provider = sender.provider; + const factory = new ContractFactory(binHexlified, abiContents, sender); + const { minGasPrice } = sender.provider.getGasConfig(); + liquidityPoolContract = await factory.deployContract({ gasPrice: minGasPrice }); + }); + + it('deposit and withdraw cookbook guide', async () => { + // #region deposit-and-withdraw-cookbook-2 + const depositAmount = 100_000; + const liquidityOwner = Wallet.generate({ provider }); + + // the subId used to mint the new asset is a zero b256 on the contract + const subId = ZeroBytes32; + const contractId = liquidityPoolContract.id.toB256(); + + const assetId = getAssetId(contractId, subId); + + await liquidityPoolContract.functions + .deposit({ value: liquidityOwner.address.toB256() }) + .callParams({ forward: [depositAmount, BaseAssetId] }) + .txParams({ gasLimit: 1_000, variableOutputs: 1, gasPrice: 1 }) + .call(); + + const liquidityAmount = await liquidityOwner.getBalance(assetId); + + expect(liquidityAmount.toNumber()).toBe(depositAmount * 2); + // #endregion deposit-and-withdraw-cookbook-2 + + // #region deposit-and-withdraw-cookbook-3 + await liquidityPoolContract.functions + .withdraw({ value: liquidityOwner.address.toB256() }) + .callParams({ forward: [depositAmount, BaseAssetId] }) + .txParams({ gasLimit: 1_000, variableOutputs: 1, gasPrice: 1 }) + .call(); + + const baseAssetAfterWithdraw = await liquidityOwner.getBalance(BaseAssetId); + + expect(baseAssetAfterWithdraw.toNumber()).toBe(depositAmount / 2); + // #endregion deposit-and-withdraw-cookbook-3 + }); +}); diff --git a/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts b/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts index 59f3e2c042..d1ca605fd9 100644 --- a/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts +++ b/apps/docs-snippets/src/guide/cookbook/transferring-assets.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let sender: WalletUnlocked; let deployedContract: Contract; diff --git a/apps/docs-snippets/src/guide/predicates/index.test.ts b/apps/docs-snippets/src/guide/predicates/index.test.ts index 57ea16c317..ddeaaff06f 100644 --- a/apps/docs-snippets/src/guide/predicates/index.test.ts +++ b/apps/docs-snippets/src/guide/predicates/index.test.ts @@ -2,6 +2,9 @@ import { FUEL_NETWORK_URL, Provider, Predicate } from 'fuels'; import { DocSnippetProjectsEnum, getDocsSnippetsForcProject } from '../../../test/fixtures/forc-projects'; +/** + * @group node + */ describe(__filename, () => { const { abiContents: jsonAbi, binHexlified: binary } = getDocsSnippetsForcProject( DocSnippetProjectsEnum.RETURN_TRUE_PREDICATE diff --git a/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts b/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts index 8321c6e58f..4178f0cac6 100644 --- a/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts +++ b/apps/docs-snippets/src/guide/predicates/predicate-with-configurable.test.ts @@ -6,6 +6,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let wallet: WalletUnlocked; let gasPrice: BN; diff --git a/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts b/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts index 6cd38a81e0..857fbd5fd2 100644 --- a/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts +++ b/apps/docs-snippets/src/guide/predicates/send-and-spend-funds-from-predicates.test.ts @@ -8,6 +8,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let walletWithFunds: WalletUnlocked; let provider: Provider; @@ -54,7 +57,7 @@ describe(__filename, () => { }); const tx2 = await predicate.transfer( - receiverWallet.address, + receiverWallet.address.toB256(), amountToPredicate - 1000, BaseAssetId, { diff --git a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts index ad2c185150..4149cfe75c 100644 --- a/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts +++ b/apps/docs-snippets/src/guide/scripts/script-custom-transaction.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { defaultTxParams, getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let wallet: WalletUnlocked; let provider: Provider; diff --git a/apps/docs-snippets/src/guide/scripts/script-with-configurable.test.ts b/apps/docs-snippets/src/guide/scripts/script-with-configurable.test.ts index ef604f4757..7951238aa5 100644 --- a/apps/docs-snippets/src/guide/scripts/script-with-configurable.test.ts +++ b/apps/docs-snippets/src/guide/scripts/script-with-configurable.test.ts @@ -7,6 +7,9 @@ import { } from '../../../test/fixtures/forc-projects'; import { getTestWallet } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let wallet: WalletUnlocked; let gasPrice: BN; diff --git a/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts b/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts index ac2b561074..0c59f59342 100644 --- a/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts +++ b/apps/docs-snippets/src/guide/testing/tweaking-the-blockchain.test.ts @@ -1,5 +1,8 @@ import { FUEL_NETWORK_URL, Provider, fromTai64ToUnix } from 'fuels'; +/** + * @group node + */ test('produceBlocks with custom timestamp docs snippet', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const latestBlock = await provider.getBlock('latest'); diff --git a/apps/docs-snippets/src/guide/types/address.test.ts b/apps/docs-snippets/src/guide/types/address.test.ts index c0674b945e..320c9bdff4 100644 --- a/apps/docs-snippets/src/guide/types/address.test.ts +++ b/apps/docs-snippets/src/guide/types/address.test.ts @@ -1,5 +1,8 @@ import { Address, FUEL_NETWORK_URL, Provider, Wallet } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should successfully create new address from bech32 string', () => { // #region address-2 diff --git a/apps/docs-snippets/src/guide/types/arrays.test.ts b/apps/docs-snippets/src/guide/types/arrays.test.ts index ce931fefa6..cd354c77dc 100644 --- a/apps/docs-snippets/src/guide/types/arrays.test.ts +++ b/apps/docs-snippets/src/guide/types/arrays.test.ts @@ -4,6 +4,9 @@ import { BN } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/asset-id.test.ts b/apps/docs-snippets/src/guide/types/asset-id.test.ts index 71143ec6c7..c02dff2916 100644 --- a/apps/docs-snippets/src/guide/types/asset-id.test.ts +++ b/apps/docs-snippets/src/guide/types/asset-id.test.ts @@ -4,6 +4,9 @@ import { Address } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe('AssetId', () => { let contract: Contract; const Bits256: B256Address = '0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c'; diff --git a/apps/docs-snippets/src/guide/types/bech32.test.ts b/apps/docs-snippets/src/guide/types/bech32.test.ts index cba787e748..e7ff0cf9f7 100644 --- a/apps/docs-snippets/src/guide/types/bech32.test.ts +++ b/apps/docs-snippets/src/guide/types/bech32.test.ts @@ -1,5 +1,8 @@ import { Address } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should successfully generate a bech32 address', () => { // #region bech32-2 diff --git a/apps/docs-snippets/src/guide/types/bits256.test.ts b/apps/docs-snippets/src/guide/types/bits256.test.ts index de25250585..ce25061804 100644 --- a/apps/docs-snippets/src/guide/types/bits256.test.ts +++ b/apps/docs-snippets/src/guide/types/bits256.test.ts @@ -1,5 +1,8 @@ import { Address, arrayify, getRandomB256, hexlify } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should successfully generate and validate bit256 hexed string', () => { // #region bits256-1 diff --git a/apps/docs-snippets/src/guide/types/bits512.test.ts b/apps/docs-snippets/src/guide/types/bits512.test.ts index d067ad4be2..d177f866de 100644 --- a/apps/docs-snippets/src/guide/types/bits512.test.ts +++ b/apps/docs-snippets/src/guide/types/bits512.test.ts @@ -4,6 +4,9 @@ import { Wallet } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/bytes.test.ts b/apps/docs-snippets/src/guide/types/bytes.test.ts index 12f11cc1de..b3f58668da 100644 --- a/apps/docs-snippets/src/guide/types/bytes.test.ts +++ b/apps/docs-snippets/src/guide/types/bytes.test.ts @@ -3,6 +3,9 @@ import type { Contract, Bytes } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe('Bytes', () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/bytes32.test.ts b/apps/docs-snippets/src/guide/types/bytes32.test.ts index 4adcbc9ee9..e02398ba93 100644 --- a/apps/docs-snippets/src/guide/types/bytes32.test.ts +++ b/apps/docs-snippets/src/guide/types/bytes32.test.ts @@ -1,6 +1,9 @@ import type { Bytes } from 'fuels'; import { arrayify, hexlify, randomBytes } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should successfully generate and convert byte32 to hexlified string', () => { // #region bytes32-1 diff --git a/apps/docs-snippets/src/guide/types/conversion.test.ts b/apps/docs-snippets/src/guide/types/conversion.test.ts index 081ae61829..7db51567ae 100644 --- a/apps/docs-snippets/src/guide/types/conversion.test.ts +++ b/apps/docs-snippets/src/guide/types/conversion.test.ts @@ -16,6 +16,9 @@ import { getDocsSnippetsForcProject, } from '../../../test/fixtures/forc-projects'; +/** + * @group node + */ describe(__filename, () => { const { abiContents: abi } = getDocsSnippetsForcProject(DocSnippetProjectsEnum.ECHO_VALUES); let provider: Provider; diff --git a/apps/docs-snippets/src/guide/types/enums.test.ts b/apps/docs-snippets/src/guide/types/enums.test.ts index becc21746e..2e383ab4c4 100644 --- a/apps/docs-snippets/src/guide/types/enums.test.ts +++ b/apps/docs-snippets/src/guide/types/enums.test.ts @@ -3,6 +3,9 @@ import type { Contract } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/evm-address.test.ts b/apps/docs-snippets/src/guide/types/evm-address.test.ts index c425bdbb24..0d617996f9 100644 --- a/apps/docs-snippets/src/guide/types/evm-address.test.ts +++ b/apps/docs-snippets/src/guide/types/evm-address.test.ts @@ -4,6 +4,9 @@ import { Address } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe('EvMAddress', () => { let contract: Contract; const Bits256: B256AddressEvm = diff --git a/apps/docs-snippets/src/guide/types/options.test.ts b/apps/docs-snippets/src/guide/types/options.test.ts index 996c24c137..683e05d08f 100644 --- a/apps/docs-snippets/src/guide/types/options.test.ts +++ b/apps/docs-snippets/src/guide/types/options.test.ts @@ -3,6 +3,9 @@ import type { Contract } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/raw-slice.test.ts b/apps/docs-snippets/src/guide/types/raw-slice.test.ts index 8c8ce63b1d..04acc25869 100644 --- a/apps/docs-snippets/src/guide/types/raw-slice.test.ts +++ b/apps/docs-snippets/src/guide/types/raw-slice.test.ts @@ -3,6 +3,9 @@ import type { Contract, BN, RawSlice } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe('RawSlice', () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/std-string.test.ts b/apps/docs-snippets/src/guide/types/std-string.test.ts index 6132853a2c..20233482f7 100644 --- a/apps/docs-snippets/src/guide/types/std-string.test.ts +++ b/apps/docs-snippets/src/guide/types/std-string.test.ts @@ -3,6 +3,9 @@ import type { Contract, StdString } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe('StdString', () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/string.test.ts b/apps/docs-snippets/src/guide/types/string.test.ts index eaf9228bc5..7a22511e91 100644 --- a/apps/docs-snippets/src/guide/types/string.test.ts +++ b/apps/docs-snippets/src/guide/types/string.test.ts @@ -3,6 +3,9 @@ import type { BN, Contract } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; let gasPrice: BN; diff --git a/apps/docs-snippets/src/guide/types/struct.test.ts b/apps/docs-snippets/src/guide/types/struct.test.ts index c06024bc22..c4cbd6c94f 100644 --- a/apps/docs-snippets/src/guide/types/struct.test.ts +++ b/apps/docs-snippets/src/guide/types/struct.test.ts @@ -1,3 +1,6 @@ +/** + * @group node + */ describe(__filename, () => { it('should successfully validate struct representation', () => { // #region struct-2 diff --git a/apps/docs-snippets/src/guide/types/tuples.test.ts b/apps/docs-snippets/src/guide/types/tuples.test.ts index b19fef5e8b..4809432212 100644 --- a/apps/docs-snippets/src/guide/types/tuples.test.ts +++ b/apps/docs-snippets/src/guide/types/tuples.test.ts @@ -4,6 +4,9 @@ import { BN } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/types/vector.test.ts b/apps/docs-snippets/src/guide/types/vector.test.ts index cee03dc093..0c550f657e 100644 --- a/apps/docs-snippets/src/guide/types/vector.test.ts +++ b/apps/docs-snippets/src/guide/types/vector.test.ts @@ -4,6 +4,9 @@ import { BN, getRandomB256 } from 'fuels'; import { DocSnippetProjectsEnum } from '../../../test/fixtures/forc-projects'; import { createAndDeployContractFromProject } from '../../utils'; +/** + * @group node + */ describe(__filename, () => { let contract: Contract; diff --git a/apps/docs-snippets/src/guide/wallet-manager/getting-started-with-wallet-manager.test.ts b/apps/docs-snippets/src/guide/wallet-manager/getting-started-with-wallet-manager.test.ts index 8872219eb7..7383ca54cc 100644 --- a/apps/docs-snippets/src/guide/wallet-manager/getting-started-with-wallet-manager.test.ts +++ b/apps/docs-snippets/src/guide/wallet-manager/getting-started-with-wallet-manager.test.ts @@ -1,6 +1,9 @@ import { WalletManager } from '@fuel-ts/wallet-manager'; import { FUEL_NETWORK_URL, Provider, Wallet } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('instantiates the WalletManager', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/apps/docs-snippets/src/guide/wallet-manager/locking-and-unlocking-wallet-manager.test.ts b/apps/docs-snippets/src/guide/wallet-manager/locking-and-unlocking-wallet-manager.test.ts index 7414ac345b..3fd7dfa275 100644 --- a/apps/docs-snippets/src/guide/wallet-manager/locking-and-unlocking-wallet-manager.test.ts +++ b/apps/docs-snippets/src/guide/wallet-manager/locking-and-unlocking-wallet-manager.test.ts @@ -1,6 +1,9 @@ import { WalletManager } from '@fuel-ts/wallet-manager'; import { FUEL_NETWORK_URL, Provider } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts b/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts index 2dc6d69840..3a52746d65 100644 --- a/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts +++ b/apps/docs-snippets/src/guide/wallets/encrypting-and-decrypting-json-wallets.test.ts @@ -1,5 +1,8 @@ import { FUEL_NETWORK_URL, Provider, Wallet } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { it('should successfully encrypt wallet', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/apps/docs-snippets/src/utils.ts b/apps/docs-snippets/src/utils.ts index aa21997bc5..06e69e3bbd 100644 --- a/apps/docs-snippets/src/utils.ts +++ b/apps/docs-snippets/src/utils.ts @@ -45,11 +45,7 @@ export const getTestWallet = async (seedQuantities?: CoinQuantityLike[]) => { // funding the transaction with the required quantities await genesisWallet.fund(request, requiredQuantities, minFee); - // execute the transaction, transferring resources to the test wallet - const response = await genesisWallet.sendTransaction(request); - - // wait for the transaction to be confirmed - await response.wait(); + await genesisWallet.sendTransaction(request, { awaitExecution: true }); // return the test wallet return testWallet; diff --git a/apps/docs-snippets/test/fixtures/forc-projects/Forc.toml b/apps/docs-snippets/test/fixtures/forc-projects/Forc.toml index ba78a81940..866df5611d 100644 --- a/apps/docs-snippets/test/fixtures/forc-projects/Forc.toml +++ b/apps/docs-snippets/test/fixtures/forc-projects/Forc.toml @@ -2,6 +2,7 @@ members = [ "counter", "echo-enum", + "liquidity-pool", "log-values", "sum-script", "echo-values", diff --git a/apps/docs-snippets/test/fixtures/forc-projects/index.ts b/apps/docs-snippets/test/fixtures/forc-projects/index.ts index 91b257ed3e..a09b1bcbfb 100644 --- a/apps/docs-snippets/test/fixtures/forc-projects/index.ts +++ b/apps/docs-snippets/test/fixtures/forc-projects/index.ts @@ -13,6 +13,7 @@ export enum DocSnippetProjectsEnum { ECHO_U64_ARRAY = 'echo-u64-array', RETURN_CONTEXT = 'return-context', TOKEN_DEPOSITOR = 'token-depositor', + LIQUIDITY_POOL = 'liquidity-pool', SIMPLE_PREDICATE = 'simple-predicate', ECHO_CONFIGURABLES = 'echo-configurables', TRANSFER_TO_ADDRESS = 'transfer-to-address', diff --git a/packages/fuel-gauge/test/fixtures/forc-projects/liquidity-pool/Forc.toml b/apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/Forc.toml similarity index 86% rename from packages/fuel-gauge/test/fixtures/forc-projects/liquidity-pool/Forc.toml rename to apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/Forc.toml index fe0f80317d..6fbb1a576a 100644 --- a/packages/fuel-gauge/test/fixtures/forc-projects/liquidity-pool/Forc.toml +++ b/apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/Forc.toml @@ -1,5 +1,6 @@ [project] authors = ["Fuel Labs "] +entry = "main.sw" license = "Apache-2.0" name = "liquidity-pool" diff --git a/apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/src/main.sw b/apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/src/main.sw new file mode 100644 index 0000000000..3f4a16b761 --- /dev/null +++ b/apps/docs-snippets/test/fixtures/forc-projects/liquidity-pool/src/main.sw @@ -0,0 +1,51 @@ +// #region deposit-and-withdraw-cookbook-1 +contract; + +use std::{ + call_frames::{ + msg_asset_id, + }, + context::msg_amount, + token::{ + mint_to_address, + transfer_to_address, + }, +}; +use std::constants::ZERO_B256; + +abi LiquidityPool { + #[payable] + fn deposit(recipient: Address); + #[payable] + fn withdraw(recipient: Address); +} + +const BASE_TOKEN: AssetId = AssetId::from( + 0x0000000000000000000000000000000000000000000000000000000000000000, +); + +impl LiquidityPool for Contract { + #[payable] + fn deposit(recipient: Address) { + assert(BASE_TOKEN == msg_asset_id()); + assert(0 < msg_amount()); + + // Mint two times the amount. + let amount_to_mint = msg_amount() * 2; + + // Mint some LP token based upon the amount of the base token. + mint_to_address(recipient, ZERO_B256, amount_to_mint); + } + + #[payable] + fn withdraw(recipient: Address) { + assert(0 < msg_amount()); + + // Amount to withdraw. + let amount_to_transfer = msg_amount() / 2; + + // Transfer base token to recipient. + transfer_to_address(recipient, BASE_TOKEN, amount_to_transfer); + } +} +// #endregion deposit-and-withdraw-cookbook-1 diff --git a/apps/docs-snippets/tsdoc.json b/apps/docs-snippets/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/apps/docs-snippets/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/apps/docs/.vitepress/config.ts b/apps/docs/.vitepress/config.ts index 2cb972c496..cfe47caff1 100644 --- a/apps/docs/.vitepress/config.ts +++ b/apps/docs/.vitepress/config.ts @@ -240,6 +240,10 @@ export default defineConfig({ text: 'Querying the Chain', link: '/guide/providers/querying-the-chain', }, + { + text: 'Retrying calls', + link: '/guide/providers/retrying-calls', + }, ], }, { @@ -395,8 +399,8 @@ export default defineConfig({ collapsed: true, items: [ { - text: 'Testing with Jest', - link: '/guide/testing/testing-with-jest', + text: 'Testing in TS', + link: '/guide/testing/testing-in-ts', }, { text: 'Setting Up a Custom Chain', diff --git a/apps/docs/.vitepress/plugins/codeInContextPlugin.test.ts b/apps/docs/.vitepress/plugins/codeInContextPlugin.test.ts index b013f21516..89e7c6b970 100644 --- a/apps/docs/.vitepress/plugins/codeInContextPlugin.test.ts +++ b/apps/docs/.vitepress/plugins/codeInContextPlugin.test.ts @@ -9,6 +9,9 @@ import { import MarkdownIt from 'markdown-it'; import Token from 'markdown-it/lib/token'; +/** + * @group node + */ describe('codeInContextPlugin', () => { describe('isCodeSnippetToken', () => { it('should returns true for valid code snippet tokens', () => { diff --git a/apps/docs/src/guide/abi-typegen/index.md b/apps/docs/src/guide/abi-typegen/index.md index 96271ec4f5..1f2ec28e05 100644 --- a/apps/docs/src/guide/abi-typegen/index.md +++ b/apps/docs/src/guide/abi-typegen/index.md @@ -2,13 +2,13 @@ import { data } from '../../versions.data' const { forc } = data const abiUrl = ` - https://fuellabs.github.io/sway/v${forc}/book/sway-program-types/smart_contracts.html#the-abi-declaration + https://docs.fuel.network/docs/sway/sway-program-types/smart_contracts/#the-abi-declaration ` const contractsUrl = ` - https://fuellabs.github.io/sway/v${forc}/book/sway-program-types/smart_contracts.html + https://docs.fuel.network/docs/sway/sway-program-types/smart_contracts/ ` const scriptsUrl = ` - https://fuellabs.github.io/sway/v${forc}/book/sway-program-types/scripts.html + https://docs.fuel.network/docs/sway/sway-program-types/scripts/ ` diff --git a/apps/docs/src/guide/abi-typegen/using-generated-types.md b/apps/docs/src/guide/abi-typegen/using-generated-types.md index 27c793061f..3d99576011 100644 --- a/apps/docs/src/guide/abi-typegen/using-generated-types.md +++ b/apps/docs/src/guide/abi-typegen/using-generated-types.md @@ -10,49 +10,19 @@ pnpm fuels typegen -i ./abis/*-abi.json -o ./types We can use these files like so: - - -```ts -import { Wallet } from "fuels"; -import { MyContract__factory } from "./types"; - -const contractId = "0x..."; -const wallet = Wallet.fromAddress("..."); -const contract = MyContract__factory.connect(contractId, wallet); - -// All contract methods are available under functions with the correct types -const { transactionId, value } = await contract.functions.my_fn(1).call(); - -console.log(transactionId, value); -``` +<<< @/../../demo-typegen/src/demo.test.ts#typegen-demo-contract-factory-connect{ts:line-numbers} ## Contract Let's use the Contract class to deploy a contract: -```ts -import { Wallet } from "fuels"; -import { MyContract__factory } from "./types"; -import bytecode from "./types/MyContract.hex.ts"; - -const wallet = Wallet.fromAddress("..."); - -const contract = await MyContract__factory.deployContract(bytecode, wallet); - -console.log(contract.id); -``` +<<< @/../../demo-typegen/src/demo.test.ts#typegen-demo-contract-factory-deploy{ts:line-numbers} ### Autoloading of Storage Slots Typegen tries to resolve, auto-load, and embed the [Storage Slots](../contracts//storage-slots.md) for your Contract within the `MyContract__factory` class. Still, you can override it alongside other options from [`DeployContractOptions`](https://github.com/FuelLabs/fuels-ts/blob/a64b67b9fb2d7f764ab9151a21d2266bf2df3643/packages/contract/src/contract-factory.ts#L19-L24), when calling the `deployContract` method: -```ts -import storageSlots from "../contract/out/debug/storage-slots.json"; - -const contract = await MyContract__factory.deployContract(bytecode, wallet, { - storageSlots, -}); -``` +<<< @/../../demo-typegen/src/demo.test.ts#typegen-demo-contract-storage-slots{ts:line-numbers} ## Script @@ -64,27 +34,11 @@ pnpm fuels typegen -i ./abis/*-abi.json -o ./types --script We can use these files like so: - - -```ts -import { Wallet } from "fuels"; -import { MyScript__factory } from "./types"; - -const wallet = Wallet.fromAddress("..."); -const script = ScriptAbi__factory.createInstance(wallet); - -const { value, logs } = await script.functions.main(1).call(); - -console.log({ value, logs }); -``` +<<< @/../../demo-typegen/src/demo.test.ts#typegen-demo-script{ts:line-numbers} ## Predicate -Consider the following predicate: - -<<< @/../../../packages/fuel-gauge/test/fixtures/forc-projects/predicate-main-args-struct/src/main.sw#Predicate-main-args{ts:line-numbers} - -Now, after generating types via: +After generating types via: ```console pnpm fuels typegen -i ./abis/*-abi.json -o ./types --predicate @@ -92,30 +46,7 @@ pnpm fuels typegen -i ./abis/*-abi.json -o ./types --predicate We can use these files like so: - - -```ts -import { Wallet } from "fuels"; -import { MyPredicate__factory } from "./types"; - -const wallet = Wallet.fromAddress("..."); -const predicate = MyPredicate__factory.createInstance(); - -await predicate - .setData({ - has_account: true, - total_complete: 100, - }) - .transfer(wallet.address, ); - -const walletBalance = await wallet.getBalance(); -const predicateBalance = await predicate.getBalance(); - -console.log({ - walletBalance, - predicateBalance, -}); -``` +<<< @/../../demo-typegen/src/demo.test.ts#typegen-demo-predicate{ts:line-numbers} See also: diff --git a/apps/docs/src/guide/contracts/deploying-contracts.md b/apps/docs/src/guide/contracts/deploying-contracts.md index f9edf0df2a..5cb2cf34aa 100644 --- a/apps/docs/src/guide/contracts/deploying-contracts.md +++ b/apps/docs/src/guide/contracts/deploying-contracts.md @@ -1,8 +1,8 @@ # Deploying Contracts diff --git a/apps/docs/src/guide/cookbook/deposit-and-withdraw.md b/apps/docs/src/guide/cookbook/deposit-and-withdraw.md index fa70f04532..0ae4806e3c 100644 --- a/apps/docs/src/guide/cookbook/deposit-and-withdraw.md +++ b/apps/docs/src/guide/cookbook/deposit-and-withdraw.md @@ -1,37 +1,15 @@ # Deposit And Withdraw -Consider the following contracts: +Consider the following contract: -<<< @/../../../packages/fuel-gauge/test/fixtures/forc-projects/token_contract/src/main.sw#token-contract{rust:line-numbers} +<<< @/../../docs-snippets/test/fixtures/forc-projects/liquidity-pool/src/main.sw#deposit-and-withdraw-cookbook-1{rust:line-numbers} -<<< @/../../../packages/fuel-gauge/test/fixtures/forc-projects/liquidity-pool/src/main.sw#liquidity-pool-contract{rust:line-numbers} +As the name implies, this contract represents a simplified version of a liquidity pool. The `deposit()` method allows you to supply an arbitrary amount of `BASE_TOKEN`. In response, it mints twice the amount of the liquidity asset to the caller's address. Similarly, the `withdraw()` method transfers half the amount of the `BASE_TOKEN` back to the caller's address. -The first contract is a contract that represents a simple token. +Now, let's deposit some tokens into the liquidity pool contract. Since this requires forwarding assets to the contract, we need to pass the appropriate values to `callParams` when creating a contract call. -The second contract, as its name suggests, represents a simplified example of a liquidity pool contract. The method deposit() expects you to supply an arbitrary amount of the `base_token`. As a result, it mints double the amount of the liquidity asset to the calling address. Analogously, if you call `withdraw()` supplying it with the liquidity asset, it will transfer half that amount of the `base_token` back to the calling address except for deducting it from the contract balance instead of minting it. - -The first step towards interacting with any contract in the TypeScript SDK is using the `typegen` CLI utility to generate type-safe bindings for the contract methods: - -```sh -$ npx fuels typegen -i ./contract/out/debug/*-abi.json -o ./contract-types -``` - -Next, let's setup a [`Wallet`](../wallets/index.md) and seed it with some coins. We will need these coins to deploy the contracts and to interact with them. - -<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#deposit-and-withdraw-cookbook-wallet-setup{ts:line-numbers} - -Let's now deploy both the contracts and set them up. - -<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#deposit-and-withdraw-cookbook-contract-deployments{ts:line-numbers} - -Next, let's mint some tokens and transfer them to our wallet. - -<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#deposit-and-withdraw-cookbook-mint-and-transfer{ts:line-numbers} - -Now, let's deposit some tokens into the liquidity pool contract. Since we have to transfer assets to the contract, we create the appropriate [`callParams`](../contracts/call-parameters.md) and chain them to the method call. - -<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#deposit-and-withdraw-cookbook-deposit{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts#deposit-and-withdraw-cookbook-2{ts:line-numbers} As a final demonstration, let's use all our liquidity asset balance to withdraw from the pool and confirm we retrieved the initial amount. For this, we get our liquidity asset balance and supply it to the `withdraw()` function via `callParams`. -<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#deposit-and-withdraw-cookbook-withdraw{ts:line-numbers} +<<< @/../../docs-snippets/src/guide/cookbook/deposit-and-withdraw.test.ts#deposit-and-withdraw-cookbook-3{ts:line-numbers} diff --git a/apps/docs/src/guide/predicates/index.md b/apps/docs/src/guide/predicates/index.md index 1fede44dfa..50e07ba663 100644 --- a/apps/docs/src/guide/predicates/index.md +++ b/apps/docs/src/guide/predicates/index.md @@ -1,8 +1,8 @@ # Predicates diff --git a/apps/docs/src/guide/providers/retrying-calls.md b/apps/docs/src/guide/providers/retrying-calls.md new file mode 100644 index 0000000000..e5a3651a26 --- /dev/null +++ b/apps/docs/src/guide/providers/retrying-calls.md @@ -0,0 +1,5 @@ +# Retrying calls + +The default behavior of calls done via the `Provider` towards a fuel node is that they'll fail if the connection breaks. Specifying retry options allows you to customize how many additional attempts you want to make when the connection to the node breaks before ultimately throwing an error. You can also specify the back-off algorithm as well as the base delay that algorithm will use to calculate the wait time for each request. + +<<< @/../../../packages/providers/test/auto-retry-fetch.test.ts#provider-retry-options{ts:line-numbers} diff --git a/apps/docs/src/guide/scripts/index.md b/apps/docs/src/guide/scripts/index.md index 6743b331e5..bc1262823f 100644 --- a/apps/docs/src/guide/scripts/index.md +++ b/apps/docs/src/guide/scripts/index.md @@ -2,7 +2,7 @@ import { data } from '../../versions.data' const { forc } = data const url = ` - https://fuellabs.github.io/sway/v${forc}/book/sway-program-types/scripts.html#scripts-and-the-sdks + https://docs.fuel.network/docs/sway/sway-program-types/scripts/#scripts-and-the-sdks ` diff --git a/apps/docs/src/guide/scripts/instantiating-a-script.md b/apps/docs/src/guide/scripts/instantiating-a-script.md index 952762707e..6f8ddf1c2c 100644 --- a/apps/docs/src/guide/scripts/instantiating-a-script.md +++ b/apps/docs/src/guide/scripts/instantiating-a-script.md @@ -2,7 +2,7 @@ import { data } from '../../versions.data' const { forc } = data const url = ` - https://fuellabs.github.io/sway/v${forc}/book/introduction/index.html + https://docs.fuel.network/docs/sway/introduction/ ` diff --git a/apps/docs/src/guide/testing/index.md b/apps/docs/src/guide/testing/index.md index d90f2bc74e..d0e7a69657 100644 --- a/apps/docs/src/guide/testing/index.md +++ b/apps/docs/src/guide/testing/index.md @@ -1,7 +1,7 @@ # Testing @@ -10,11 +10,11 @@ In order to test your Sway and TS-SDK applications, you can test your code in a 1. Testing with TS-SDK: Compiling you Sway code and connecting to the methods using TS-SDK and JS testing frameworks 2. Using `forc test` see the Sway docs for more info -3. Using [the Rust SDK](https://fuellabs.github.io/fuels-rs/v0.31.1/testing/index.html) +3. Using [the Rust SDK](https://docs.fuel.network/docs/fuels-rs/testing/) ### Testing with TS-SDK -To test your Sway applications using the TS-SDK, you can pick whatever testing library or framework you feel comfortable with. There isn't any specific testing framework needed, it is entirely up to the user. That being said, the TS-SDK uses [Jest](https://jestjs.io/) for its tests. +To test your Sway applications using the TS-SDK, you can pick whatever testing library or framework you feel comfortable with. There isn't any specific testing framework needed, it is entirely up to the user. That being said, the TS-SDK uses [`Vitest`](https://vitest.dev/) for its tests. ### Wallet Test Utilities @@ -40,4 +40,4 @@ stop(); See also: 1. [Setting up test wallets](../wallets/test-wallets.md) -2. [Testing with Jest](./testing-with-jest.md) +2. [Testing in TS](./testing-in-ts.md) diff --git a/apps/docs/src/guide/testing/setting-up-a-custom-chain.md b/apps/docs/src/guide/testing/setting-up-a-custom-chain.md index 825e1dd693..f965ab9916 100644 --- a/apps/docs/src/guide/testing/setting-up-a-custom-chain.md +++ b/apps/docs/src/guide/testing/setting-up-a-custom-chain.md @@ -4,7 +4,7 @@ The `launchNodeAndGetWallets` method lets you launch a local Fuel node with vari In the code snippet below, we provide a custom chain config file to the `launchNodeAndGetWallets` method. You can use a chain config file to customize things like the chain's consensus parameters or specify some initial states for the chain. Click here to see what a chain config file looks like: [`chainConfig.json`](https://github.com/FuelLabs/fuels-ts/blob/master/.fuel-core/configs/chainConfig.json) -<<< @/../../../packages/wallet/src/test-utils/launchNode.test.ts#launchNode-custom-config{ts:line-numbers} +<<< @/../../../packages/wallet/src/test-utils/launchNodeAndGetWallets.test.ts#launchNode-custom-config{ts:line-numbers} ## Customization options diff --git a/apps/docs/src/guide/testing/testing-in-ts.md b/apps/docs/src/guide/testing/testing-in-ts.md new file mode 100644 index 0000000000..fa8eec5a01 --- /dev/null +++ b/apps/docs/src/guide/testing/testing-in-ts.md @@ -0,0 +1,13 @@ +# Testing in TS + +As noted in [the testing intro](./index.md), you are free to test your Sway and TS-SDK code with any JS framework available. Below we have an example of how to load and test a contract using `Vitest`, but the general principles and steps are the same for any testing harness. + +Here is a simple Sway program that takes an input and then returns it: + +<<< @/../../demo-typegen/contract/src/main.sw#Testing-in-ts-rust{rust:line-numbers} + +Here is JavaScript code testing the above program using a conventional `Vitest` setup: + +<<< @/../../demo-typegen/src/demo.test.ts#Testing-in-ts-ts{ts:line-numbers} + +> **Note:** The TS-SDK has recently migrated to `Vitest` however it follows a very similar API to Jest, and the above example applies to Jest also. \ No newline at end of file diff --git a/apps/docs/src/guide/testing/testing-with-jest.md b/apps/docs/src/guide/testing/testing-with-jest.md deleted file mode 100644 index 9f7b536a2d..0000000000 --- a/apps/docs/src/guide/testing/testing-with-jest.md +++ /dev/null @@ -1,11 +0,0 @@ -# Testing with Jest - -As noted in [the testing intro](./index.md), you are free to test your Sway and TS-SDK code with any JS framework available. Below we have an example of how to load and test a contract using Jest, but the general principles and steps are the same for any testing harness. - -Here is a simple Sway program that takes an input and then returns it: - -<<< @/../../demo-typegen/contract/src/main.sw#Testing-with-jest-rust{rust:line-numbers} - -Here is JavaScript code testing the above program using a conventional Jest setup: - -<<< @/../../demo-typegen/src/demo.test.ts#Testing-with-jest-ts{ts:line-numbers} diff --git a/apps/docs/src/guide/types/index.md b/apps/docs/src/guide/types/index.md index 5fbe40c321..4a7180d8d9 100644 --- a/apps/docs/src/guide/types/index.md +++ b/apps/docs/src/guide/types/index.md @@ -18,6 +18,6 @@ In this section, you will learn about: As you progress through the documentation, you may find it helpful to refer back to the following resources: -- [Sway Documentation](https://fuellabs.github.io/sway/): Explore the Sway documentation homepage for an overview of Sway Types, as well as other sections. +- [Sway Documentation](https://docs.fuel.network/docs/sway/): Explore the Sway documentation homepage for an overview of Sway Types, as well as other sections. - [The Fuel Book](https://fuelbook.fuel.network/master/index.html): A comprehensive guide to the whole Fuel ecosystem. diff --git a/apps/docs/src/guide/wallets/access.md b/apps/docs/src/guide/wallets/access.md index df6facfcbc..b44aaa2405 100644 --- a/apps/docs/src/guide/wallets/access.md +++ b/apps/docs/src/guide/wallets/access.md @@ -27,6 +27,12 @@ provides greater access via its private key. <<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#wallets{ts:line-numbers} +## Optional Provider + +You can choose not to pass through a provider argument on `Wallet` construction: + +<<< @/../../../packages/fuel-gauge/src/doc-examples.test.ts#wallet-optional-provider{ts:line-numbers} + ## Transitioning States A [`WalletLocked`](../../api/Wallet/WalletLocked.md) instance can be unlocked by providing the private key: diff --git a/apps/docs/src/index.md b/apps/docs/src/index.md index d5d8b08c28..2b1fbced0e 100644 --- a/apps/docs/src/index.md +++ b/apps/docs/src/index.md @@ -1,7 +1,7 @@ @@ -15,7 +15,7 @@ Please visit the Fuel's [installation guide](https://docs.fuel.network/guides/in ## Developer Quickstart Guide -We recommend starting with the [Developer Quickstart](https://fuellabs.github.io/fuel-docs/master/quickstart/developer-quickstart.html) for a walk through on building your first DApp on Fuel. +We recommend starting with the [Developer Quickstart](https://docs.fuel.network/docs/intro/quickstart-contract/) for a walk through on building your first DApp on Fuel. - [Guide](./guide/) - [Sample Application](https://github.com/FuelLabs/beta2-quickstart) @@ -25,7 +25,7 @@ We recommend starting with the [Developer Quickstart](https://fuellabs.github.io Learn more about the Fuel Ecosystem. -- [🌴 Sway](https://fuellabs.github.io/sway/) the new language. Empowering everyone to build reliable and efficient smart contracts. +- [🌴 Sway](https://docs.fuel.network/docs/sway/) the new language. Empowering everyone to build reliable and efficient smart contracts. - 🧰 Forc the Fuel toolbox. Build, deploy and manage your sway projects. - [βš™οΈ Fuel Core](https://github.com/FuelLabs/fuel-core) the new FuelVM, a blazingly fast blockchain VM. - [πŸ”— Fuel Specs](https://github.com/FuelLabs/fuel-specs) the Fuel protocol specifications. diff --git a/internal/check-tests/README.md b/internal/check-tests/README.md new file mode 100644 index 0000000000..8b4c4eedc0 --- /dev/null +++ b/internal/check-tests/README.md @@ -0,0 +1,5 @@ +This package validates our environment testing setup. + +It ensures that environment specific functionalities should be supported by the SDK. + +If one of these tests fails, it may indicate that an environment is configured incorrectly. diff --git a/internal/check-tests/package.json b/internal/check-tests/package.json new file mode 100644 index 0000000000..40bbfeed32 --- /dev/null +++ b/internal/check-tests/package.json @@ -0,0 +1,12 @@ +{ + "private": true, + "name": "@internal/check-tests", + "files": [ + "dist" + ], + "scripts": { + "build": "tsc --noEmit" + }, + "license": "Apache-2.0", + "version": null +} diff --git a/internal/check-tests/src/all.test.ts b/internal/check-tests/src/all.test.ts new file mode 100644 index 0000000000..8e2a0847a9 --- /dev/null +++ b/internal/check-tests/src/all.test.ts @@ -0,0 +1,11 @@ +import { testAll } from './index'; + +/** + * @group node + * @group browser + */ +describe('in:everywhere', () => { + it('should work everywhere', () => { + expect(testAll()).toEqual('thank you'); + }); +}); diff --git a/internal/check-tests/src/browser.test.ts b/internal/check-tests/src/browser.test.ts new file mode 100644 index 0000000000..2cac616e56 --- /dev/null +++ b/internal/check-tests/src/browser.test.ts @@ -0,0 +1,10 @@ +import { testEach } from './index'; + +/** + * @group browser + */ +describe('in:browser', () => { + it('should work on browser', () => { + expect(testEach()).toEqual('browser'); + }); +}); diff --git a/internal/check-tests/src/index.ts b/internal/check-tests/src/index.ts new file mode 100644 index 0000000000..b78b737db7 --- /dev/null +++ b/internal/check-tests/src/index.ts @@ -0,0 +1,20 @@ +const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined'; + +const isNode = + typeof process !== 'undefined' && process.versions != null && process.versions.node != null; + +export const testEach = (): string => { + let env: string; + + if (isBrowser) { + env = 'browser'; + } else if (isNode) { + env = 'node'; + } else { + throw new Error('Oops, no browser/node detected'); + } + + return env; +}; + +export const testAll = (): string => 'thank you'; diff --git a/internal/check-tests/src/node.test.ts b/internal/check-tests/src/node.test.ts new file mode 100644 index 0000000000..e62c3ba703 --- /dev/null +++ b/internal/check-tests/src/node.test.ts @@ -0,0 +1,10 @@ +import { testEach } from './index'; + +/** + * @group node + */ +describe('in:node', () => { + it('should work on node', () => { + expect(testEach()).toEqual('node'); + }); +}); diff --git a/internal/check-tests/tsconfig.json b/internal/check-tests/tsconfig.json new file mode 100644 index 0000000000..b0fced27d7 --- /dev/null +++ b/internal/check-tests/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist" + }, + "include": ["src"] +} diff --git a/internal/check-tests/tsdoc.json b/internal/check-tests/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/internal/check-tests/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index c202af65e1..0000000000 --- a/jest.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from '@jest/types'; - -const config: Config.InitialOptions = { - preset: 'ts-jest', - testEnvironment: 'node', - setupFiles: ['./jest.env.ts'], - testPathIgnorePatterns: ['/node_modules/', '/dist/'], - modulePathIgnorePatterns: [ - '/dist/', - '/apps/demo-nextjs', - '/apps/demo-react-cra', - '/dist/demo-react-vite', - ], - coveragePathIgnorePatterns: [ - '/dist/', - '/test/', - '.test.ts', - '.d.ts', - '/fuel-gauge/', - '/apps/demo-*', - ], - testTimeout: 15000, - transform: { - '\\.hbs$': 'jest-text-transformer', - }, -}; - -export default config; diff --git a/nodemon.config.json b/nodemon.config.json index 2cf1fb9a45..b972bfeec7 100644 --- a/nodemon.config.json +++ b/nodemon.config.json @@ -11,6 +11,8 @@ "**/Forc.lock", "**/getBuiltinVersions.ts", "**/out/debug/**", - "apps/demo-typegen/src/generated-types/**" + "apps/demo-typegen/src/contract-types/**", + "apps/demo-typegen/src/predicate-types/**", + "apps/demo-typegen/src/script-types/**" ] } diff --git a/package.json b/package.json index 1b916ce63d..5d0f840cbf 100644 --- a/package.json +++ b/package.json @@ -5,20 +5,24 @@ "author": "Fuel Labs (https://fuel.network/)", "private": true, "engines": { - "node": "^18.17.1", + "node": "^18.18.2 || ^20.0.0", "pnpm": "^8.9.0" }, "packageManager": "pnpm@8.9.0", "scripts": { - "dan": "tsx ./scripts/release-unpublish.ts", "dev": "nodemon --config nodemon.config.json -x 'pnpm build:packages'", "build": "turbo run build --cache-dir=.turbo", "build:packages": "turbo run build --filter=!docs", - "ci:test": "./scripts/ci-test.sh", + "ci:test": "./scripts/tests-ci.sh", "pretest": "turbo run pretest", - "test": "jest --no-cache --runInBand --coverage", - "test:e2e": "jest --no-cache --runInBand packages/fuel-gauge/src/e2e-script.test.ts", - "test:watch": "jest --no-cache --watchAll", + "test": "vitest --run --coverage --config vite.node.config.mts $(scripts/tests-find.sh --node)", + "test:filter": "vitest --run --coverage --config vite.node.config.mts", + "test:coverage-merge": "tsx ./scripts/tests-coverage-merge.ts", + "test:coverage-diff": "tsx ./scripts/tests-coverage-diff.ts", + "test:watch": "vitest --watch --config vite.node.config.mts $(scripts/tests-find.sh --node)", + "test:validate": "./scripts/tests-validate.sh", + "test:browser": "vitest --run --coverage --config vite.browser.config.mts $(scripts/tests-find.sh --browser)", + "test:e2e": "vitest --run --config vite.node.config.mts $(scripts/tests-find.sh --e2e)", "lint": "run-s lint:check prettier:check", "lint:check": "eslint . --ext .ts --max-warnings 0", "lint:fix": "pnpm lint:check --fix", @@ -50,17 +54,20 @@ "@changesets/get-github-info": "^0.5.2", "@fuel-ts/forc": "workspace:*", "@fuel-ts/fuel-core": "workspace:*", + "@fuel-ts/utils": "workspace:*", "@fuel-ts/versions": "workspace:^", "@internal/tsup": "workspace:*", - "@jest/types": "^29.5.0", - "@types/jest": "^29.5.0", + "@istanbuljs/nyc-config-typescript": "^1.0.2", "@types/node": "18.15.3", "@types/node-fetch": "^2.6.2", "@types/web": "^0.0.65", "@typescript-eslint/eslint-plugin": "^6.9.0", "@typescript-eslint/parser": "^6.9.0", + "@vitest/browser": "^1.1.3", + "@vitest/coverage-istanbul": "^1.1.3", "compare-versions": "^6.1.0", "conventional-changelog-angular": "^5.0.13", + "coverage-diff": "^3.2.0", "dotenv": "^9.0.2", "eslint": "^8.52.0", "eslint-config-airbnb-base": "^15.0.0", @@ -74,23 +81,26 @@ "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-tsdoc": "^0.2.17", - "ethers": "^6.7.1", "glob": "^10.2.6", - "jest": "^29.7.0", - "jest-text-transformer": "^1.0.4", + "memfs": "^4.6.0", "nodemon": "^2.0.22", "npm-run-all": "^4.1.5", + "nyc": "^15.1.0", "open": "^8.4.0", "prettier": "^3.0.3", "rimraf": "^3.0.2", "textlint": "^13.3.2", "textlint-rule-no-dead-link": "^5.1.2", "ts-generator": "^0.1.1", - "ts-jest": "^29.1.1", "tsup": "^6.7.0", - "tsx": "^3.12.7", + "tsx": "^4.7.0", "turbo": "^1.8.8", - "typescript": "~5.2.2" + "typescript": "~5.2.2", + "vite": "^5.0.11", + "vite-plugin-node-polyfills": "^0.17.0", + "vite-plugin-plain-text": "^1.4.2", + "vitest": "^1.1.3", + "webdriverio": "^8.27.0" }, "pnpm": { "overrides": { diff --git a/packages/abi-coder/README.md b/packages/abi-coder/README.md index 24cd682c3f..dbd65ed798 100644 --- a/packages/abi-coder/README.md +++ b/packages/abi-coder/README.md @@ -18,7 +18,7 @@ This module is responsible for encoding and decoding the Application Binary Inte -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/abi-coder/package.json b/packages/abi-coder/package.json index e253d7d062..c164333c9f 100644 --- a/packages/abi-coder/package.json +++ b/packages/abi-coder/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/abi-coder/src/coders/abstract-coder.ts b/packages/abi-coder/src/coders/abstract-coder.ts index c14e1e7301..51ce8c2610 100644 --- a/packages/abi-coder/src/coders/abstract-coder.ts +++ b/packages/abi-coder/src/coders/abstract-coder.ts @@ -1,4 +1,3 @@ -import { FuelError, type ErrorCode } from '@fuel-ts/errors'; import type { BN } from '@fuel-ts/math'; import type { BytesLike } from 'ethers'; @@ -88,10 +87,6 @@ export abstract class Coder { this.encodedLength = encodedLength; } - throwError(errorCode: ErrorCode, message: string): never { - throw new FuelError(errorCode, message); - } - abstract encode(value: TInput, length?: number): Uint8Array; abstract decode(data: Uint8Array, offset: number, length?: number): [TDecoded, number]; diff --git a/packages/abi-coder/src/coders/array.test.ts b/packages/abi-coder/src/coders/array.test.ts index 64b93ead7b..82603d7f26 100644 --- a/packages/abi-coder/src/coders/array.test.ts +++ b/packages/abi-coder/src/coders/array.test.ts @@ -1,7 +1,7 @@ import { FuelError, ErrorCode } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; -import { U8_MAX } from '../../test/utils/constants'; +import { U32_MAX, U8_MAX } from '../../test/utils/constants'; import type { SmallBytesOptions } from './abstract-coder'; import { ArrayCoder } from './array'; @@ -9,6 +9,9 @@ import { BooleanCoder } from './boolean'; import { EnumCoder } from './enum'; import { NumberCoder } from './number'; +/** + * @group node + */ describe('ArrayCoder', () => { const sbOptions: SmallBytesOptions = { isSmallBytes: true, @@ -105,4 +108,34 @@ describe('ArrayCoder', () => { new FuelError(ErrorCode.ENCODE_ERROR, 'Types/values length mismatch.') ); }); + + it('throws when decoding empty bytes', async () => { + const coder = new ArrayCoder(new NumberCoder('u8'), 1); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid array data size.') + ); + }); + + it('throws when decoding invalid bytes (too small)', async () => { + const coder = new ArrayCoder(new NumberCoder('u8'), 8); + const input = new Uint8Array([0]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid array data size.') + ); + }); + + it('throws when decoding vec larger than max size', async () => { + const coder = new ArrayCoder(new NumberCoder('u8'), 8); + const input = new Uint8Array(U32_MAX + 1); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid array data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/array.ts b/packages/abi-coder/src/coders/array.ts index 6490716347..2fe43d807d 100644 --- a/packages/abi-coder/src/coders/array.ts +++ b/packages/abi-coder/src/coders/array.ts @@ -1,5 +1,6 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { MAX_BYTES } from '../constants'; import { concatWithDynamicData } from '../utilities'; import type { TypesOfCoder } from './abstract-coder'; @@ -23,17 +24,21 @@ export class ArrayCoder extends Coder< encode(value: InputValueOf): Uint8Array { if (!Array.isArray(value)) { - this.throwError(ErrorCode.ENCODE_ERROR, `Expected array value.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Expected array value.`); } if (this.length !== value.length) { - this.throwError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); } return concatWithDynamicData(Array.from(value).map((v) => this.coder.encode(v))); } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < this.encodedLength || data.length > MAX_BYTES) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid array data size.`); + } + let newOffset = offset; const decodedValue = Array(this.length) .fill(0) diff --git a/packages/abi-coder/src/coders/b256.test.ts b/packages/abi-coder/src/coders/b256.test.ts index 14942b654e..e581cd7b1e 100644 --- a/packages/abi-coder/src/coders/b256.test.ts +++ b/packages/abi-coder/src/coders/b256.test.ts @@ -1,5 +1,12 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; + import { B256Coder } from './b256'; +/** + * @group node + * @group browser + */ describe('B256Coder', () => { const B256_DECODED = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; const B256_ENCODED = new Uint8Array([ @@ -43,52 +50,67 @@ describe('B256Coder', () => { expect(actualLength).toBe(expectedLength); }); - it('should throw an error when encoding a 256 bit hash string that is too short', () => { + it('should throw an error when encoding a 256 bit hash string that is too short', async () => { const invalidInput = B256_DECODED.slice(0, B256_DECODED.length - 1); - expect(() => { - coder.encode(invalidInput); - }).toThrow('Invalid b256'); + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid b256.') + ); }); - it('should throw an error when decoding an encoded 256 bit hash string that is too short', () => { + it('should throw an error when decoding an encoded 256 bit hash string that is too short', async () => { const invalidInput = B256_ENCODED.slice(0, B256_ENCODED.length - 1); - expect(() => { - coder.decode(invalidInput, 0); - }).toThrow(); + await expectToThrowFuelError( + () => coder.decode(invalidInput, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b256 data size.') + ); }); - it('should throw an error when encoding a 256 bit hash string that is too long', () => { + it('should throw an error when encoding a 256 bit hash string that is too long', async () => { const invalidInput = `${B256_DECODED}0`; - expect(() => { - coder.encode(invalidInput); - }).toThrow('Invalid b256'); + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid b256.') + ); }); - it('should throw an error when encoding a 512 bit hash string', () => { + it('should throw an error when encoding a 512 bit hash string', async () => { const B512 = '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; - expect(() => { - coder.encode(B512); - }).toThrow('Invalid b256'); + await expectToThrowFuelError( + () => coder.encode(B512), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid b256.') + ); }); - it('should throw an error when decoding an encoded 256 bit hash string that is too long', () => { - const invalidInput = new Uint8Array(Array.from(Array(32).keys())); + it('should throw an error when encoding a 256 bit hash string that is not a hex string', async () => { + const invalidInput = 'not a hex string'; - expect(() => { - coder.decode(invalidInput, 1); - }).toThrow('Invalid size for b256'); + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid b256.') + ); }); - it('should throw an error when encoding a 256 bit hash string that is not a hex string', () => { - const invalidInput = 'not a hex string'; + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b256 data size.') + ); + }); + + it('should throw an error when decoding an encoded b256 bit hash string that is too long', async () => { + const invalidInput = new Uint8Array(Array.from(Array(65).keys())); - expect(() => { - coder.encode(invalidInput); - }).toThrow('Invalid b256'); + await expectToThrowFuelError( + () => coder.decode(invalidInput, 62), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b256 byte data size.') + ); }); }); diff --git a/packages/abi-coder/src/coders/b256.ts b/packages/abi-coder/src/coders/b256.ts index 4b76a1a13b..d8e28eee0f 100644 --- a/packages/abi-coder/src/coders/b256.ts +++ b/packages/abi-coder/src/coders/b256.ts @@ -1,12 +1,14 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toHex } from '@fuel-ts/math'; import { getBytesCopy } from 'ethers'; +import { WORD_SIZE } from '../constants'; + import { Coder } from './abstract-coder'; export class B256Coder extends Coder { constructor() { - super('b256', 'b256', 32); + super('b256', 'b256', WORD_SIZE * 4); } encode(value: string): Uint8Array { @@ -14,23 +16,30 @@ export class B256Coder extends Coder { try { encodedValue = getBytesCopy(value); } catch (error) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); } - if (encodedValue.length !== 32) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); + if (encodedValue.length !== this.encodedLength) { + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); } return encodedValue; } decode(data: Uint8Array, offset: number): [string, number] { - let bytes = data.slice(offset, offset + 32); + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid b256 data size.`); + } + + let bytes = data.slice(offset, offset + this.encodedLength); + const decoded = bn(bytes); if (decoded.isZero()) { bytes = new Uint8Array(32); } - if (bytes.length !== 32) { - this.throwError(ErrorCode.DECODE_ERROR, `'Invalid size for b256'.`); + + if (bytes.length !== this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid b256 byte data size.`); } + return [toHex(bytes, 32), offset + 32]; } } diff --git a/packages/abi-coder/src/coders/b512.test.ts b/packages/abi-coder/src/coders/b512.test.ts index a83cc3d799..2a62b738a2 100644 --- a/packages/abi-coder/src/coders/b512.test.ts +++ b/packages/abi-coder/src/coders/b512.test.ts @@ -1,5 +1,12 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; + import { B512Coder } from './b512'; +/** + * @group node + * @group browser + */ describe('B512Coder', () => { const B512_DECODED = '0x8e9dda6f7793745ac5aacf9e907cae30b2a01fdf0d23b7750a85c6a44fca0c29f0906f9d1f1e92e6a1fb3c3dcef3cc3b3cdbaae27e47b9d9a4c6a4fce4cf16b2'; @@ -55,14 +62,6 @@ describe('B512Coder', () => { }).toThrow(/Invalid struct B512/); }); - it('should throw an error when decoding an encoded 512 bit hash string that is too short', () => { - const invalidInput = B512_ENCODED.slice(0, B512_ENCODED.length - 1); - - expect(() => { - coder.decode(invalidInput, 0); - }).toThrow('Invalid size for b512'); - }); - it('should throw an error when encoding a 512 bit hash string that is too long', () => { const invalidInput = `${B512_DECODED}0`; @@ -79,14 +78,6 @@ describe('B512Coder', () => { }).toThrow(/Invalid struct B512/); }); - it('should throw an error when decoding an encoded 512 bit hash string that is too long', () => { - const invalidInput = new Uint8Array(Array.from(Array(32).keys())); - - expect(() => { - coder.decode(invalidInput, 1); - }).toThrow('Invalid size for b512'); - }); - it('should throw an error when encoding a 512 bit hash string that is not a hex string', () => { const invalidInput = 'not a hex string'; @@ -94,4 +85,31 @@ describe('B512Coder', () => { coder.encode(invalidInput); }).toThrow(/Invalid struct B512/); }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b512 data size.') + ); + }); + + it('should throw an error when decoding an encoded 512 bit hash string that is too short', async () => { + const invalidInput = B512_ENCODED.slice(0, B512_ENCODED.length - 1); + + await expectToThrowFuelError( + () => coder.decode(invalidInput, 8), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b512 data size.') + ); + }); + + it('should throw an error when decoding an encoded 512 bit hash string that is too long', async () => { + const invalidInput = new Uint8Array(Array.from(Array(65).keys())); + + await expectToThrowFuelError( + () => coder.decode(invalidInput, 8), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid b512 byte data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/b512.ts b/packages/abi-coder/src/coders/b512.ts index 94059e4ee6..3af4cb74a2 100644 --- a/packages/abi-coder/src/coders/b512.ts +++ b/packages/abi-coder/src/coders/b512.ts @@ -1,12 +1,14 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toHex } from '@fuel-ts/math'; import { getBytesCopy } from 'ethers'; +import { WORD_SIZE } from '../constants'; + import { Coder } from './abstract-coder'; export class B512Coder extends Coder { constructor() { - super('b512', 'struct B512', 64); + super('b512', 'struct B512', WORD_SIZE * 8); } encode(value: string): Uint8Array { @@ -14,23 +16,30 @@ export class B512Coder extends Coder { try { encodedValue = getBytesCopy(value); } catch (error) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); } - if (encodedValue.length !== 64) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); + if (encodedValue.length !== this.encodedLength) { + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); } return encodedValue; } decode(data: Uint8Array, offset: number): [string, number] { - let bytes = data.slice(offset, offset + 64); + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid b512 data size.`); + } + + let bytes = data.slice(offset, offset + this.encodedLength); + const decoded = bn(bytes); if (decoded.isZero()) { bytes = new Uint8Array(64); } - if (bytes.length !== 64) { - this.throwError(ErrorCode.DECODE_ERROR, `Invalid size for b512.`); + + if (bytes.length !== this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid b512 byte data size.`); } - return [toHex(bytes, 64), offset + 64]; + + return [toHex(bytes, this.encodedLength), offset + this.encodedLength]; } } diff --git a/packages/abi-coder/src/coders/boolean.test.ts b/packages/abi-coder/src/coders/boolean.test.ts index cbe6234181..35c39ee2f4 100644 --- a/packages/abi-coder/src/coders/boolean.test.ts +++ b/packages/abi-coder/src/coders/boolean.test.ts @@ -3,11 +3,17 @@ import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { BooleanCoder } from './boolean'; -jest.mock('@fuel-ts/math', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/math'), -})); +vi.mock('@fuel-ts/math', async () => { + const mod = await vi.importActual('@fuel-ts/math'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('BooleanCoder', () => { const TRUE_DECODED = true; const TRUE_ENCODED = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]); @@ -64,4 +70,13 @@ describe('BooleanCoder', () => { new FuelError(ErrorCode.DECODE_ERROR, 'Invalid boolean value.') ); }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid boolean data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/boolean.ts b/packages/abi-coder/src/coders/boolean.ts index 7f03ea06d7..2784daef6d 100644 --- a/packages/abi-coder/src/coders/boolean.ts +++ b/packages/abi-coder/src/coders/boolean.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn, toBytes } from '@fuel-ts/math'; import type { SmallBytesOptions } from './abstract-coder'; @@ -26,7 +26,7 @@ export class BooleanCoder extends Coder { const isTrueBool = value === true || value === false; if (!isTrueBool) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid boolean value.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid boolean value.`); } const output: Uint8Array = toBytes(value ? 1 : 0, this.paddingLength); @@ -39,20 +39,25 @@ export class BooleanCoder extends Coder { } decode(data: Uint8Array, offset: number): [boolean, number] { + if (data.length < this.paddingLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid boolean data size.`); + } + let bytes; if (this.options.isRightPadded) { - bytes = bn(data.slice(offset, offset + 1)); + bytes = data.slice(offset, offset + 1); } else { - bytes = bn(data.slice(offset, offset + this.paddingLength)); + bytes = data.slice(offset, offset + this.paddingLength); } - if (bytes.isZero()) { + const decodedValue = bn(bytes); + if (decodedValue.isZero()) { return [false, offset + this.paddingLength]; } - if (!bytes.eq(bn(1))) { - this.throwError(ErrorCode.DECODE_ERROR, `Invalid boolean value.`); + if (!decodedValue.eq(bn(1))) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid boolean value.`); } return [true, offset + this.paddingLength]; diff --git a/packages/abi-coder/src/coders/byte.test.ts b/packages/abi-coder/src/coders/byte.test.ts index 7891d84792..d2038acc5f 100644 --- a/packages/abi-coder/src/coders/byte.test.ts +++ b/packages/abi-coder/src/coders/byte.test.ts @@ -5,6 +5,10 @@ import type { Uint8ArrayWithDynamicData } from '../utilities'; import { ByteCoder } from './byte'; +/** + * @group node + * @group browser + */ describe('ByteCoder', () => { it('should encode a byte', () => { const coder = new ByteCoder(); @@ -56,4 +60,40 @@ describe('ByteCoder', () => { expect(actual).toEqual(expected); expect(newOffset).toEqual(24); }); + + it('should decode a byte [with padding]', () => { + const coder = new ByteCoder(); + const input = new Uint8Array([ + 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 11, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 0, 0, 0, 0, 0, + ]); + const expected = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + + const [actual, newOffset] = coder.decode(input, 0); + + expect(actual).toEqual(expected); + expect(newOffset).toEqual(24); + }); + + it('throws when decoding empty bytes', async () => { + const coder = new ByteCoder(); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid byte data size.') + ); + }); + + it('throws when decoding empty byte data', async () => { + const coder = new ByteCoder(); + const input = new Uint8Array([ + 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, + ]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid bytes byte data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/byte.ts b/packages/abi-coder/src/coders/byte.ts index 13e4314186..64aebaba9e 100644 --- a/packages/abi-coder/src/coders/byte.ts +++ b/packages/abi-coder/src/coders/byte.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; import { concat } from '@fuel-ts/utils'; @@ -17,7 +17,7 @@ export class ByteCoder extends Coder { encode(value: number[]): Uint8Array { if (!Array.isArray(value)) { - this.throwError(ErrorCode.ENCODE_ERROR, `Expected array value.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Expected array value.`); } const parts: Uint8Array[] = []; @@ -54,9 +54,17 @@ export class ByteCoder extends Coder { } decode(data: Uint8Array, offset: number): [Uint8Array, number] { + if (data.length < BASE_VECTOR_OFFSET) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid byte data size.`); + } + const len = data.slice(16, 24); - const length = bn(new U64Coder().decode(len, 0)[0]).toNumber(); - const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + length * 8); + const encodedLength = bn(new U64Coder().decode(len, 0)[0]).toNumber(); + const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + encodedLength); + + if (byteData.length !== encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid bytes byte data size.`); + } return [byteData, offset + BASE_VECTOR_OFFSET]; } diff --git a/packages/abi-coder/src/coders/enum.test.ts b/packages/abi-coder/src/coders/enum.test.ts index 476a9257b7..2bf17f9888 100644 --- a/packages/abi-coder/src/coders/enum.test.ts +++ b/packages/abi-coder/src/coders/enum.test.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { bn } from '@fuel-ts/math'; import { U64_MAX } from '../../test/utils/constants'; @@ -7,6 +9,10 @@ import { BooleanCoder } from './boolean'; import { EnumCoder } from './enum'; import { U64Coder } from './u64'; +/** + * @group node + * @group browser + */ describe('EnumCoder', () => { const coder = new EnumCoder('TestEnum', { a: new BooleanCoder(), b: new U64Coder() }); @@ -57,9 +63,9 @@ describe('EnumCoder', () => { }); it('should throw an error when decoded value accesses an invalid index', () => { - const input = new Uint8Array(Array.from(Array(3).keys())); + const input = new Uint8Array(Array.from(Array(8).keys())); expect(() => { - coder.decode(input, 1); + coder.decode(input, 0); }).toThrow('Invalid caseIndex'); }); @@ -94,4 +100,11 @@ describe('EnumCoder', () => { ) ).toThrow(); }); + + it('throws when decoding empty bytes', async () => { + await expectToThrowFuelError( + () => coder.decode(new Uint8Array(), 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid enum data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/enum.ts b/packages/abi-coder/src/coders/enum.ts index 6f4e3ae1b1..c579b9b997 100644 --- a/packages/abi-coder/src/coders/enum.ts +++ b/packages/abi-coder/src/coders/enum.ts @@ -78,6 +78,10 @@ export class EnumCoder> extends Coder< } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < this.#encodedValueSize) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid enum data size.`); + } + let newOffset = offset; let decoded; diff --git a/packages/abi-coder/src/coders/number.test.ts b/packages/abi-coder/src/coders/number.test.ts index 4b1c4cda22..13f610d555 100644 --- a/packages/abi-coder/src/coders/number.test.ts +++ b/packages/abi-coder/src/coders/number.test.ts @@ -5,6 +5,10 @@ import { U8_MAX, U16_MAX, U32_MAX } from '../../test/utils/constants'; import { NumberCoder } from './number'; +/** + * @group node + * @group browser + */ describe('NumberCoder', () => { it('should encode min u8 number as a u8 coder', () => { const coder = new NumberCoder('u8'); @@ -120,13 +124,14 @@ describe('NumberCoder', () => { expect(actualLength).toBe(expectedLength); }); - it('should throw if a negative number is encoded', () => { + it('should throw if a negative number is encoded', async () => { const coder = new NumberCoder('u8'); const invalidInput = -1; - expect(() => { - coder.encode(invalidInput); - }).toThrow('Invalid u8'); + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid u8.') + ); }); it('should throw if coder is too small for number size', async () => { @@ -138,4 +143,24 @@ describe('NumberCoder', () => { new FuelError(ErrorCode.ENCODE_ERROR, `Invalid u8, too many bytes.`) ); }); + + it('throws when decoding empty bytes', async () => { + const coder = new NumberCoder('u32'); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid number data size.') + ); + }); + + it('throws when decoding empty byte data', async () => { + const coder = new NumberCoder('u32'); + const input = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); + + await expectToThrowFuelError( + () => coder.decode(input, 8), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid number byte data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/number.ts b/packages/abi-coder/src/coders/number.ts index a8d9ee7710..757f5dfbaf 100644 --- a/packages/abi-coder/src/coders/number.ts +++ b/packages/abi-coder/src/coders/number.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { toNumber, toBytes } from '@fuel-ts/math'; import type { SmallBytesOptions } from './abstract-coder'; @@ -48,11 +48,11 @@ export class NumberCoder extends Coder { try { bytes = toBytes(value); } catch (error) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}.`); } if (bytes.length > this.length) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}, too many bytes.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.baseType}, too many bytes.`); } const output = toBytes(bytes, this.paddingLength); @@ -77,11 +77,20 @@ export class NumberCoder extends Coder { } decode(data: Uint8Array, offset: number): [number, number] { + if (data.length < this.paddingLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number data size.`); + } + if (this.baseType === 'u8') { return this.decodeU8(data, offset); } - const bytes = data.slice(offset, offset + 8).slice(8 - this.length, 8); + let bytes = data.slice(offset, offset + this.paddingLength); + bytes = bytes.slice(8 - this.length, 8); + + if (bytes.length !== this.paddingLength - (this.paddingLength - this.length)) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid number byte data size.`); + } return [toNumber(bytes), offset + 8]; } diff --git a/packages/abi-coder/src/coders/option.test.ts b/packages/abi-coder/src/coders/option.test.ts index 09d11df865..75c661d63f 100644 --- a/packages/abi-coder/src/coders/option.test.ts +++ b/packages/abi-coder/src/coders/option.test.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { BN } from '@fuel-ts/math'; import { U8_MAX } from '../../test/utils/constants'; @@ -6,6 +8,10 @@ import { U8_MAX } from '../../test/utils/constants'; import { OptionCoder } from './option'; import { U64Coder } from './u64'; +/** + * @group node + * @group browser + */ describe('OptionCoder', () => { it('should encode a some u64 option ', () => { const coder = new OptionCoder('test option', { Some: new U64Coder() }); @@ -51,4 +57,24 @@ describe('OptionCoder', () => { expect(actualValue).toBe(expectedValue); expect(actualLength).toBe(expectedLength); }); + + it('throws when decoding empty bytes', async () => { + const coder = new OptionCoder('test option', { None: new U64Coder() }); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid option data size.') + ); + }); + + it('should throw when decoding invalid byte data size (too small)', async () => { + const coder = new OptionCoder('test option', { None: new U64Coder() }); + const input = new Uint8Array([0, 0]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid option data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/option.ts b/packages/abi-coder/src/coders/option.ts index 33b447ec14..16a43f23bf 100644 --- a/packages/abi-coder/src/coders/option.ts +++ b/packages/abi-coder/src/coders/option.ts @@ -1,3 +1,5 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; + import type { Coder } from './abstract-coder'; import type { InputValueOf, DecodedValueOf } from './enum'; import { EnumCoder } from './enum'; @@ -20,6 +22,10 @@ export class OptionCoder> extends EnumCode } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid option data size.`); + } + const [decoded, newOffset] = super.decode(data, offset); return [this.toOption(decoded) as DecodedValueOf, newOffset]; } diff --git a/packages/abi-coder/src/coders/raw-slice.test.ts b/packages/abi-coder/src/coders/raw-slice.test.ts index a30d821fed..d863cb2595 100644 --- a/packages/abi-coder/src/coders/raw-slice.test.ts +++ b/packages/abi-coder/src/coders/raw-slice.test.ts @@ -6,6 +6,10 @@ import type { Uint8ArrayWithDynamicData } from '../utilities'; import { RawSliceCoder } from './raw-slice'; +/** + * @group node + * @group browser + */ describe('RawSliceCoder', () => { it('should encode a raw-slice', () => { const coder = new RawSliceCoder(); @@ -43,4 +47,34 @@ describe('RawSliceCoder', () => { expect(actual.map((v: BN) => v.toNumber())).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); expect(newOffset).toEqual(80); }); + + it('throws when decoding empty bytes', async () => { + const coder = new RawSliceCoder(); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid raw slice data size.') + ); + }); + + it('should throw when decoding invalid data size (too small)', async () => { + const coder = new RawSliceCoder(); + const input = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 1]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid raw slice data size.') + ); + }); + + it('should throw when decoding invalid data size (remainder)', async () => { + const coder = new RawSliceCoder(); + const input = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 1]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid raw slice data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/raw-slice.ts b/packages/abi-coder/src/coders/raw-slice.ts index 843c41ad37..1bad4981dd 100644 --- a/packages/abi-coder/src/coders/raw-slice.ts +++ b/packages/abi-coder/src/coders/raw-slice.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { BN } from '@fuel-ts/math'; import { WORD_SIZE } from '../constants'; @@ -16,7 +16,7 @@ export class RawSliceCoder extends Coder { encode(value: number[]): Uint8Array { if (!Array.isArray(value)) { - this.throwError(ErrorCode.ENCODE_ERROR, `Expected array value.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Expected array value.`); } const parts: Uint8Array[] = []; @@ -39,7 +39,11 @@ export class RawSliceCoder extends Coder { } decode(data: Uint8Array, offset: number): [BN[], number] { - const internalCoder = new ArrayCoder(new U64Coder(), data.length / 8); + if (data.length < BASE_RAW_SLICE_OFFSET || data.length % WORD_SIZE !== 0) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid raw slice data size.`); + } + + const internalCoder = new ArrayCoder(new U64Coder(), data.length / WORD_SIZE); const decoded = internalCoder.decode(data, offset); return decoded; diff --git a/packages/abi-coder/src/coders/stdString.test.ts b/packages/abi-coder/src/coders/stdString.test.ts index 6c7a039cdf..28cf0a16f7 100644 --- a/packages/abi-coder/src/coders/stdString.test.ts +++ b/packages/abi-coder/src/coders/stdString.test.ts @@ -1,7 +1,14 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; + import type { Uint8ArrayWithDynamicData } from '../utilities'; import { StdStringCoder } from './stdString'; +/** + * @group node + * @group browser + */ describe('StdStringCoder', () => { it('should encode an empty string', () => { const coder = new StdStringCoder(); @@ -89,4 +96,26 @@ describe('StdStringCoder', () => { expect(actual).toEqual(expected); expect(newOffset).toEqual(40); }); + + it('throws when decoding a string with empty bytes', async () => { + const coder = new StdStringCoder(); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid std string data size.') + ); + }); + + it('throws when decoding a string with empty byte data', async () => { + const coder = new StdStringCoder(); + const input = new Uint8Array([ + 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, + ]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid std string byte data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/stdString.ts b/packages/abi-coder/src/coders/stdString.ts index 6eef7cb83b..8270a0955b 100644 --- a/packages/abi-coder/src/coders/stdString.ts +++ b/packages/abi-coder/src/coders/stdString.ts @@ -1,3 +1,4 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; import { concat } from '@fuel-ts/utils'; import { toUtf8Bytes, toUtf8String } from 'ethers'; @@ -50,9 +51,18 @@ export class StdStringCoder extends Coder { } decode(data: Uint8Array, offset: number): [string, number] { + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid std string data size.`); + } + const len = data.slice(16, 24); - const length = bn(new U64Coder().decode(len, 0)[0]).toNumber(); - const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + length); + const encodedLength = bn(new U64Coder().decode(len, 0)[0]).toNumber(); + const byteData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + encodedLength); + + if (byteData.length !== encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid std string byte data size.`); + } + const value = toUtf8String(byteData); return [value, offset + BASE_VECTOR_OFFSET]; } diff --git a/packages/abi-coder/src/coders/string.test.ts b/packages/abi-coder/src/coders/string.test.ts index c84237946d..c7056a7deb 100644 --- a/packages/abi-coder/src/coders/string.test.ts +++ b/packages/abi-coder/src/coders/string.test.ts @@ -1,7 +1,14 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; + import { U8_MAX } from '../../test/utils/constants'; import { StringCoder } from './string'; +/** + * @group node + * @group browser + */ describe('StringCoder', () => { const STRING_MIN_DECODED = ''; const STRING_MIN_ENCODED = new Uint8Array(); @@ -44,22 +51,28 @@ describe('StringCoder', () => { expect(actualLength).toBe(expectedLength); }); - it('should throw when encoding a string that is too big', () => { + it('should throw when encoding a string that is too big', async () => { const coder = new StringCoder(0); const invalidInput = STRING_MAX_DECODED; - expect(() => { - coder.encode(invalidInput); - }).toThrow(); + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Value length mismatch during encode.') + ); }); - it('should throw when encoding a string that is too small', () => { + it('should throw when encoding a string that is too small', async () => { const coder = new StringCoder(1); const invalidInput = STRING_MIN_DECODED; expect(() => { coder.encode(invalidInput); }).toThrow(); + + await expectToThrowFuelError( + () => coder.encode(invalidInput), + new FuelError(ErrorCode.ENCODE_ERROR, 'Value length mismatch during encode.') + ); }); it('should not completely decode a string that is too big for the coder', () => { @@ -70,4 +83,24 @@ describe('StringCoder', () => { expect(actualValue).not.toBe(STRING_MAX_DECODED); expect(actualLength).toBe(8); }); + + it('throws when decoding empty bytes', async () => { + const coder = new StringCoder(1); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid string data size.') + ); + }); + + it('throws when decoding empty byte data', async () => { + const coder = new StringCoder(1); + const input = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); + + await expectToThrowFuelError( + () => coder.decode(input, 8), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid string byte data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/string.ts b/packages/abi-coder/src/coders/string.ts index d866fa3c39..746c8e8c4c 100644 --- a/packages/abi-coder/src/coders/string.ts +++ b/packages/abi-coder/src/coders/string.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { concat } from '@fuel-ts/utils'; import { toUtf8Bytes, toUtf8String } from 'ethers'; @@ -18,7 +18,7 @@ export class StringCoder extends Coder extends Coder { const STRUCT_NAME = 'TestStruct'; const coder = new StructCoder(STRUCT_NAME, { a: new BooleanCoder(), b: new U64Coder() }); @@ -128,4 +134,22 @@ describe('StructCoder', () => { ) ).toThrow(`Invalid struct ${STRUCT_NAME}`); }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid struct data size.') + ); + }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid struct data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/struct.ts b/packages/abi-coder/src/coders/struct.ts index a351586d1e..3b8c883be4 100644 --- a/packages/abi-coder/src/coders/struct.ts +++ b/packages/abi-coder/src/coders/struct.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { concatWithDynamicData, @@ -41,7 +41,7 @@ export class StructCoder> extends Coder< const fieldValue = value[fieldName]; if (!(fieldCoder instanceof OptionCoder) && fieldValue == null) { - this.throwError( + throw new FuelError( ErrorCode.ENCODE_ERROR, `Invalid ${this.type}. Field "${fieldName}" not present.` ); @@ -60,6 +60,10 @@ export class StructCoder> extends Coder< } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid struct data size.`); + } + let newOffset = offset; const decodedValue = Object.keys(this.coders).reduce((obj, fieldName) => { const fieldCoder = this.coders[fieldName]; diff --git a/packages/abi-coder/src/coders/tuple.test.ts b/packages/abi-coder/src/coders/tuple.test.ts index d54934c197..a8d15eeeef 100644 --- a/packages/abi-coder/src/coders/tuple.test.ts +++ b/packages/abi-coder/src/coders/tuple.test.ts @@ -1,4 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { bn } from '@fuel-ts/math'; import { U64_MAX } from '../../test/utils/constants'; @@ -7,6 +9,10 @@ import { BooleanCoder } from './boolean'; import { TupleCoder } from './tuple'; import { U64Coder } from './u64'; +/** + * @group node + * @group browser + */ describe('Tuple Coder', () => { const coder = new TupleCoder<[BooleanCoder, U64Coder]>([new BooleanCoder(), new U64Coder()]); @@ -105,4 +111,22 @@ describe('Tuple Coder', () => { ) ).toThrow(); }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid tuple data size.') + ); + }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid tuple data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/tuple.ts b/packages/abi-coder/src/coders/tuple.ts index 9a2564607d..b52b41477b 100644 --- a/packages/abi-coder/src/coders/tuple.ts +++ b/packages/abi-coder/src/coders/tuple.ts @@ -1,4 +1,4 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { concatWithDynamicData, @@ -31,7 +31,7 @@ export class TupleCoder extends Coder< encode(value: InputValueOf): Uint8Array { if (this.coders.length !== value.length) { - this.throwError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Types/values length mismatch.`); } return concatWithDynamicData( @@ -46,6 +46,10 @@ export class TupleCoder extends Coder< } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid tuple data size.`); + } + let newOffset = offset; const decodedValue = this.coders.map((coder) => { let decoded; diff --git a/packages/abi-coder/src/coders/u64.test.ts b/packages/abi-coder/src/coders/u64.test.ts index b4307fe052..a22e1ff42c 100644 --- a/packages/abi-coder/src/coders/u64.test.ts +++ b/packages/abi-coder/src/coders/u64.test.ts @@ -1,9 +1,15 @@ +import { ErrorCode, FuelError } from '@fuel-ts/errors'; +import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; import { BN, bn } from '@fuel-ts/math'; import { U8_MAX, U16_MAX, U32_MAX, U64_MAX } from '../../test/utils/constants'; import { U64Coder } from './u64'; +/** + * @group node + * @group browser + */ describe('U64Coder', () => { const coder = new U64Coder(); @@ -102,9 +108,28 @@ describe('U64Coder', () => { expect(actualLength).toBe(expectedLength); }); - it('should throw an error when encoding an invalid u64', () => { - expect(() => { - coder.encode(bn(U64_MAX).add(1)); - }).toThrow('Invalid u64'); + it('should throw an error when encoding an invalid u64', async () => { + await expectToThrowFuelError( + () => coder.encode(bn(U64_MAX).add(1)), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid u64.') + ); + }); + + it('throws when decoding empty bytes', async () => { + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid u64 data size.') + ); + }); + + it('throws when decoding empty byte data', async () => { + const input = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7]); + + await expectToThrowFuelError( + () => coder.decode(input, 8), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid u64 byte data size.') + ); }); }); diff --git a/packages/abi-coder/src/coders/u64.ts b/packages/abi-coder/src/coders/u64.ts index 3d837aab33..bfa021e70f 100644 --- a/packages/abi-coder/src/coders/u64.ts +++ b/packages/abi-coder/src/coders/u64.ts @@ -1,30 +1,38 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { BN, BNInput } from '@fuel-ts/math'; import { bn, toBytes } from '@fuel-ts/math'; +import { WORD_SIZE } from '../constants'; + import { Coder } from './abstract-coder'; export class U64Coder extends Coder { constructor() { - super('u64', 'u64', 8); + super('u64', 'u64', WORD_SIZE); } encode(value: BNInput): Uint8Array { let bytes; try { - bytes = toBytes(value, 8); + bytes = toBytes(value, WORD_SIZE); } catch (error) { - this.throwError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Invalid ${this.type}.`); } return bytes; } decode(data: Uint8Array, offset: number): [BN, number] { - let bytes = data.slice(offset, offset + 8); - bytes = bytes.slice(0, 8); + if (data.length < this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid ${this.type} data size.`); + } + const byteData = data.slice(offset, offset + this.encodedLength); + + if (byteData.length !== this.encodedLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid ${this.type} byte data size.`); + } - return [bn(bytes), offset + 8]; + return [bn(byteData), offset + WORD_SIZE]; } } diff --git a/packages/abi-coder/src/coders/vec.test.ts b/packages/abi-coder/src/coders/vec.test.ts index f9e0b73af4..122bc8606b 100644 --- a/packages/abi-coder/src/coders/vec.test.ts +++ b/packages/abi-coder/src/coders/vec.test.ts @@ -1,6 +1,7 @@ import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { expectToThrowFuelError } from '@fuel-ts/errors/test-utils'; +import { U32_MAX } from '../../test/utils/constants'; import type { Uint8ArrayWithDynamicData } from '../utilities'; import type { SmallBytesOptions } from './abstract-coder'; @@ -8,6 +9,9 @@ import { BooleanCoder } from './boolean'; import { NumberCoder } from './number'; import { VecCoder } from './vec'; +/** + * @group node + */ describe('VecCoder', () => { const sbOptions: SmallBytesOptions = { isSmallBytes: true, @@ -47,4 +51,36 @@ describe('VecCoder', () => { expect(actual).toEqual(expected); expect(newOffset).toEqual(24); }); + + it('throws when decoding empty vec bytes', async () => { + const coder = new VecCoder(new NumberCoder('u8')); + const input = new Uint8Array(0); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.ENCODE_ERROR, 'Invalid vec data size.') + ); + }); + + it('throws when decoding empty vec byte data', async () => { + const coder = new VecCoder(new NumberCoder('u8')); + const input = new Uint8Array([ + 0, 0, 0, 0, 3, 255, 255, 225, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 255, + ]); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid vec byte data size.') + ); + }); + + it('throws when decoding vec larger than max size', async () => { + const coder = new VecCoder(new NumberCoder('u8')); + const input = new Uint8Array(U32_MAX + 1); + + await expectToThrowFuelError( + () => coder.decode(input, 0), + new FuelError(ErrorCode.DECODE_ERROR, 'Invalid vec data size.') + ); + }); }); diff --git a/packages/abi-coder/src/coders/vec.ts b/packages/abi-coder/src/coders/vec.ts index 666b5ea715..ce00085f7f 100644 --- a/packages/abi-coder/src/coders/vec.ts +++ b/packages/abi-coder/src/coders/vec.ts @@ -1,6 +1,7 @@ -import { ErrorCode } from '@fuel-ts/errors'; +import { ErrorCode, FuelError } from '@fuel-ts/errors'; import { bn } from '@fuel-ts/math'; +import { MAX_BYTES } from '../constants'; import type { Uint8ArrayWithDynamicData } from '../utilities'; import { concatWithDynamicData, BASE_VECTOR_OFFSET, chunkByLength } from '../utilities'; @@ -24,7 +25,7 @@ export class VecCoder extends Coder< encode(value: InputValueOf): Uint8Array { if (!Array.isArray(value)) { - this.throwError(ErrorCode.ENCODE_ERROR, `Expected array value.`); + throw new FuelError(ErrorCode.ENCODE_ERROR, `Expected array value.`); } const parts: Uint8Array[] = []; @@ -48,12 +49,19 @@ export class VecCoder extends Coder< } decode(data: Uint8Array, offset: number): [DecodedValueOf, number] { + if (data.length < BASE_VECTOR_OFFSET || data.length > MAX_BYTES) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec data size.`); + } + const len = data.slice(16, 24); - const length = bn(new U64Coder().decode(len, 0)[0]).toNumber(); - const vectorRawData = data.slice( - BASE_VECTOR_OFFSET, - BASE_VECTOR_OFFSET + length * this.coder.encodedLength - ); + const encodedLength = bn(new U64Coder().decode(len, 0)[0]).toNumber(); + const vectorRawDataLength = encodedLength * this.coder.encodedLength; + const vectorRawData = data.slice(BASE_VECTOR_OFFSET, BASE_VECTOR_OFFSET + vectorRawDataLength); + + if (vectorRawData.length !== vectorRawDataLength) { + throw new FuelError(ErrorCode.DECODE_ERROR, `Invalid vec byte data size.`); + } + return [ chunkByLength(vectorRawData, this.coder.encodedLength).map( (chunk) => this.coder.decode(chunk, 0)[0] diff --git a/packages/abi-coder/src/constants.ts b/packages/abi-coder/src/constants.ts index 453837b966..5358c00be4 100644 --- a/packages/abi-coder/src/constants.ts +++ b/packages/abi-coder/src/constants.ts @@ -19,6 +19,7 @@ export const ADDRESS_LEN = BYTES_32; export const NONCE_LEN = BYTES_32; export const TX_LEN = WORD_SIZE * 4; export const TX_POINTER_LEN = WORD_SIZE * 2; +export const MAX_BYTES = 2 ** 32 - 1; // Max u32 export const calculateVmTxMemory = ({ maxInputs }: { maxInputs: number }) => BYTES_32 + // Tx ID diff --git a/packages/abi-coder/src/utilities.test.ts b/packages/abi-coder/src/utilities.test.ts index 1eb978f256..d0e04ab529 100644 --- a/packages/abi-coder/src/utilities.test.ts +++ b/packages/abi-coder/src/utilities.test.ts @@ -3,6 +3,10 @@ import { concat } from '@fuel-ts/utils'; import type { Uint8ArrayWithDynamicData } from './utilities'; import { unpackDynamicData, concatWithDynamicData } from './utilities'; +/** + * @group node + * @group browser + */ describe('Abi Coder Utilities', () => { it('can concatWithVectorData [no dynamicData, should match original concat]', () => { const data1 = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 24]); diff --git a/packages/abi-coder/test/interface.test.ts b/packages/abi-coder/test/interface.test.ts index e8933804c3..207ab3a914 100644 --- a/packages/abi-coder/test/interface.test.ts +++ b/packages/abi-coder/test/interface.test.ts @@ -49,6 +49,9 @@ function encodeVectorFully( const exhaustiveExamplesInterface = new Interface(exhaustiveExamplesAbi); +/** + * @group node + */ describe('Abi interface', () => { it('can retrieve a function fragment', () => { const fn = exhaustiveExamplesInterface.functions.entry_one; diff --git a/packages/abi-coder/tsdoc.json b/packages/abi-coder/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/abi-coder/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/abi-typegen/README.md b/packages/abi-typegen/README.md index be3540555b..767cc52c95 100644 --- a/packages/abi-typegen/README.md +++ b/packages/abi-typegen/README.md @@ -17,7 +17,7 @@ See the full ABI-spec [here](https://github.com/FuelLabs/fuel-specs/blob/master/ ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/abi-typegen/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/abi-typegen/) ## Installation diff --git a/packages/abi-typegen/package.json b/packages/abi-typegen/package.json index 5958ca010d..2f101172f8 100644 --- a/packages/abi-typegen/package.json +++ b/packages/abi-typegen/package.json @@ -10,7 +10,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/abi-typegen/src/AbiTypeGen.test.ts b/packages/abi-typegen/src/AbiTypeGen.test.ts index 5581d49833..bf42604796 100644 --- a/packages/abi-typegen/src/AbiTypeGen.test.ts +++ b/packages/abi-typegen/src/AbiTypeGen.test.ts @@ -7,18 +7,23 @@ import * as assembleContractsMod from './utils/assembleContracts'; import * as assemblePredicatesMod from './utils/assemblePredicates'; import * as assembleScriptsMod from './utils/assembleScripts'; +/** + * @group node + */ describe('AbiTypegen.ts', () => { // Use as e sample of HORRIBLE auto-code-formatting function mockAllDeps() { - const assembleContracts = jest + const assembleContracts = vi .spyOn(assembleContractsMod, 'assembleContracts') - .mockImplementation(); + .mockImplementation(() => []); - const assembleScripts = jest.spyOn(assembleScriptsMod, 'assembleScripts').mockImplementation(); + const assembleScripts = vi + .spyOn(assembleScriptsMod, 'assembleScripts') + .mockImplementation(() => []); - const assemblePredicates = jest + const assemblePredicates = vi .spyOn(assemblePredicatesMod, 'assemblePredicates') - .mockImplementation(); + .mockImplementation(() => []); return { assembleContracts, @@ -27,8 +32,13 @@ describe('AbiTypegen.ts', () => { }; } - beforeEach(jest.resetAllMocks); - afterEach(jest.resetAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); + + afterEach(() => { + vi.resetAllMocks(); + }); test('should create multiple ABI instances for: contracts', () => { const { assembleContracts, assembleScripts, assemblePredicates } = mockAllDeps(); @@ -75,7 +85,7 @@ describe('AbiTypegen.ts', () => { test('should throw for unknown programType', async () => { const { assembleContracts, assembleScripts, assemblePredicates } = mockAllDeps(); - const programType = 'nope' as ProgramTypeEnum; // forced cast to cause error + const programType = 'nope' as ProgramTypeEnum; const { error } = await safeExec(() => { getNewAbiTypegen({ programType, includeBinFiles: true }); diff --git a/packages/abi-typegen/src/abi/Abi.test.ts b/packages/abi-typegen/src/abi/Abi.test.ts index 01a50cf80e..7fc76c5f5e 100644 --- a/packages/abi-typegen/src/abi/Abi.test.ts +++ b/packages/abi-typegen/src/abi/Abi.test.ts @@ -15,18 +15,21 @@ import { EnumType } from './types/EnumType'; import { OptionType } from './types/OptionType'; import { VectorType } from './types/VectorType'; +/** + * @group node + */ describe('Abi.ts', () => { /* Test helpers */ function mockAllDeps() { - const parseTypes = jest.spyOn(parseTypesMod, 'parseTypes').mockImplementation(() => []); + const parseTypes = vi.spyOn(parseTypesMod, 'parseTypes').mockImplementation(() => []); - const parseFunctions = jest + const parseFunctions = vi .spyOn(parseFunctionsMod, 'parseFunctions') .mockImplementation(() => []); - const parseConfigurables = jest + const parseConfigurables = vi .spyOn(parseConfigurablesMod, 'parseConfigurables') .mockImplementation(() => []); diff --git a/packages/abi-typegen/src/abi/configurable/Configurable.test.ts b/packages/abi-typegen/src/abi/configurable/Configurable.test.ts index 515e7cbe6c..3122d5263f 100644 --- a/packages/abi-typegen/src/abi/configurable/Configurable.test.ts +++ b/packages/abi-typegen/src/abi/configurable/Configurable.test.ts @@ -8,6 +8,9 @@ import * as findTypeMod from '../../utils/findType'; import { Configurable } from './Configurable'; +/** + * @group node + */ describe('Configurable.ts', () => { function mockAllDeps() { const rawAbiType: IRawAbiTypeRoot = { @@ -25,10 +28,12 @@ describe('Configurable.ts', () => { }, rawAbiType, requiredFuelsMembersImports: [], - parseComponentsAttributes: jest.fn(), + parseComponentsAttributes: vi.fn(), }; - const findType = jest.spyOn(findTypeMod, 'findType').mockReturnValue(type); + const findType = vi + .spyOn(findTypeMod, 'findType') + .mockImplementation(vi.fn().mockReturnValue(type)); return { type, diff --git a/packages/abi-typegen/src/abi/functions/Function.test.ts b/packages/abi-typegen/src/abi/functions/Function.test.ts index ccb4a45002..8eaabb796c 100644 --- a/packages/abi-typegen/src/abi/functions/Function.test.ts +++ b/packages/abi-typegen/src/abi/functions/Function.test.ts @@ -6,6 +6,9 @@ import { parseTypes } from '../../utils/parseTypes'; import { Function } from './Function'; +/** + * @group node + */ describe('Function.ts', () => { /* Method: `getDeclaration` diff --git a/packages/abi-typegen/src/abi/types/ArrayType.test.ts b/packages/abi-typegen/src/abi/types/ArrayType.test.ts index f5b5ddf974..aac57706da 100644 --- a/packages/abi-typegen/src/abi/types/ArrayType.test.ts +++ b/packages/abi-typegen/src/abi/types/ArrayType.test.ts @@ -10,8 +10,13 @@ import * as parseTypeArgumentsMod from '../../utils/parseTypeArguments'; import { ArrayType } from './ArrayType'; import { TupleType } from './TupleType'; +/** + * @group node + */ describe('ArrayType.ts', () => { - beforeEach(jest.restoreAllMocks); + beforeEach(() => { + vi.restoreAllMocks(); + }); test('should properly evaluate type suitability', () => { const suitableForTuple = ArrayType.isSuitableFor({ type: TupleType.swayType }); @@ -22,7 +27,7 @@ describe('ArrayType.ts', () => { }); test('should properly parse type attributes: simple', () => { - const parseTypeArguments = jest.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); + const parseTypeArguments = vi.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); const project = getTypegenForcProject(AbiTypegenProjectsEnum.STRUCT_WITH_ARRAY); @@ -40,7 +45,7 @@ describe('ArrayType.ts', () => { }); test('should properly parse type attributes: nested', () => { - const parseTypeArguments = jest.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); + const parseTypeArguments = vi.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); const project = getTypegenForcProject(AbiTypegenProjectsEnum.ARRAY_WITH_GENERICS); diff --git a/packages/abi-typegen/src/abi/types/AssetIdType.test.ts b/packages/abi-typegen/src/abi/types/AssetIdType.test.ts index cbfe43ac48..e4dcf999db 100644 --- a/packages/abi-typegen/src/abi/types/AssetIdType.test.ts +++ b/packages/abi-typegen/src/abi/types/AssetIdType.test.ts @@ -1,6 +1,9 @@ import { AssetIdType } from './AssetIdType'; import { BoolType } from './BoolType'; +/** + * @group node + */ describe('AssetIdType.ts', () => { test('should properly parse type attributes', () => { const b512 = new AssetIdType({ diff --git a/packages/abi-typegen/src/abi/types/B256Type.test.ts b/packages/abi-typegen/src/abi/types/B256Type.test.ts index bcd502bb1e..904d57ffb1 100644 --- a/packages/abi-typegen/src/abi/types/B256Type.test.ts +++ b/packages/abi-typegen/src/abi/types/B256Type.test.ts @@ -1,6 +1,9 @@ import { B256Type } from './B256Type'; import { BoolType } from './BoolType'; +/** + * @group node + */ describe('B256Type.ts', () => { test('should properly parse type attributes', () => { const b256 = new B256Type({ diff --git a/packages/abi-typegen/src/abi/types/B512Type.test.ts b/packages/abi-typegen/src/abi/types/B512Type.test.ts index fbf2cb8c8b..65be8cda76 100644 --- a/packages/abi-typegen/src/abi/types/B512Type.test.ts +++ b/packages/abi-typegen/src/abi/types/B512Type.test.ts @@ -1,6 +1,9 @@ import { B512Type } from './B512Type'; import { BoolType } from './BoolType'; +/** + * @group node + */ describe('B512Type.ts', () => { test('should properly parse type attributes', () => { const b512 = new B512Type({ diff --git a/packages/abi-typegen/src/abi/types/BoolType.test.ts b/packages/abi-typegen/src/abi/types/BoolType.test.ts index 19d13cbba5..203f4ff203 100644 --- a/packages/abi-typegen/src/abi/types/BoolType.test.ts +++ b/packages/abi-typegen/src/abi/types/BoolType.test.ts @@ -1,6 +1,9 @@ import { BoolType } from './BoolType'; import { U16Type } from './U16Type'; +/** + * @group node + */ describe('BoolType.ts', () => { test('should properly parse type attributes', () => { const bool = new BoolType({ diff --git a/packages/abi-typegen/src/abi/types/BytesType.test.ts b/packages/abi-typegen/src/abi/types/BytesType.test.ts index 7d081332d1..44ace6cc41 100644 --- a/packages/abi-typegen/src/abi/types/BytesType.test.ts +++ b/packages/abi-typegen/src/abi/types/BytesType.test.ts @@ -1,6 +1,9 @@ import { BytesType } from './BytesType'; import { StructType } from './StructType'; +/** + * @group node + */ describe('BytesType.ts', () => { test('should properly parse type attributes', () => { const bytes = new BytesType({ diff --git a/packages/abi-typegen/src/abi/types/EnumType.test.ts b/packages/abi-typegen/src/abi/types/EnumType.test.ts index ef143ffb4c..bbe407502b 100644 --- a/packages/abi-typegen/src/abi/types/EnumType.test.ts +++ b/packages/abi-typegen/src/abi/types/EnumType.test.ts @@ -11,6 +11,9 @@ import type { EnumType } from './EnumType'; import { StructType } from './StructType'; import { U16Type } from './U16Type'; +/** + * @group node + */ describe('EnumType.ts', () => { /* Test helpers diff --git a/packages/abi-typegen/src/abi/types/EvmAddressType.test.ts b/packages/abi-typegen/src/abi/types/EvmAddressType.test.ts index acba25c590..a3345fc121 100644 --- a/packages/abi-typegen/src/abi/types/EvmAddressType.test.ts +++ b/packages/abi-typegen/src/abi/types/EvmAddressType.test.ts @@ -11,9 +11,12 @@ import { EvmAddressType } from './EvmAddressType'; import { StructType } from './StructType'; import { VectorType } from './VectorType'; +/** + * @group node + */ describe('EvmAddressType.ts', () => { test('should properly parse type attributes', () => { - const parseTypeArguments = jest.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); + const parseTypeArguments = vi.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); const project = getTypegenForcProject(AbiTypegenProjectsEnum.EVM_ADDRESS); diff --git a/packages/abi-typegen/src/abi/types/GenericType.test.ts b/packages/abi-typegen/src/abi/types/GenericType.test.ts index 9dadff39f9..be4d6c1b3b 100644 --- a/packages/abi-typegen/src/abi/types/GenericType.test.ts +++ b/packages/abi-typegen/src/abi/types/GenericType.test.ts @@ -1,6 +1,9 @@ import { GenericType } from './GenericType'; import { StructType } from './StructType'; +/** + * @group node + */ describe('GenericType.ts', () => { test('should properly parse type attributes', () => { const generic = new GenericType({ diff --git a/packages/abi-typegen/src/abi/types/OptionType.test.ts b/packages/abi-typegen/src/abi/types/OptionType.test.ts index 231e5c2000..2e8d80f7b3 100644 --- a/packages/abi-typegen/src/abi/types/OptionType.test.ts +++ b/packages/abi-typegen/src/abi/types/OptionType.test.ts @@ -9,6 +9,9 @@ import { makeType } from '../../utils/makeType'; import { EnumType } from './EnumType'; import { OptionType } from './OptionType'; +/** + * @group node + */ describe('OptionType.ts', () => { /* Test helpers diff --git a/packages/abi-typegen/src/abi/types/RawUntypedPtr.test.ts b/packages/abi-typegen/src/abi/types/RawUntypedPtr.test.ts index 544165c388..21f34af07b 100644 --- a/packages/abi-typegen/src/abi/types/RawUntypedPtr.test.ts +++ b/packages/abi-typegen/src/abi/types/RawUntypedPtr.test.ts @@ -1,6 +1,9 @@ import { RawUntypedPtr } from './RawUntypedPtr'; import { U8Type } from './U8Type'; +/** + * @group node + */ describe('RawUntypedPtrType.ts', () => { test('should properly parse type attributes', () => { const rawUntypedPtr = new RawUntypedPtr({ diff --git a/packages/abi-typegen/src/abi/types/RawUntypedSlice.test.ts b/packages/abi-typegen/src/abi/types/RawUntypedSlice.test.ts index dff7d7121c..a300099c7d 100644 --- a/packages/abi-typegen/src/abi/types/RawUntypedSlice.test.ts +++ b/packages/abi-typegen/src/abi/types/RawUntypedSlice.test.ts @@ -1,6 +1,9 @@ import { RawUntypedSlice } from './RawUntypedSlice'; import { StructType } from './StructType'; +/** + * @group node + */ describe('RawUntypedSlice.ts', () => { test('should properly parse type attributes', () => { const rawSlice = new RawUntypedSlice({ diff --git a/packages/abi-typegen/src/abi/types/StdStringType.test.ts b/packages/abi-typegen/src/abi/types/StdStringType.test.ts index 8d87fc6974..46624dc9d1 100644 --- a/packages/abi-typegen/src/abi/types/StdStringType.test.ts +++ b/packages/abi-typegen/src/abi/types/StdStringType.test.ts @@ -1,6 +1,9 @@ import { StdStringType } from './StdStringType'; import { StructType } from './StructType'; +/** + * @group node + */ describe('StdStringType.ts', () => { test('should properly parse type attributes', () => { const stdString = new StdStringType({ diff --git a/packages/abi-typegen/src/abi/types/StrSlicesType.test.ts b/packages/abi-typegen/src/abi/types/StrSlicesType.test.ts index 285c42afe5..ac9242642a 100644 --- a/packages/abi-typegen/src/abi/types/StrSlicesType.test.ts +++ b/packages/abi-typegen/src/abi/types/StrSlicesType.test.ts @@ -3,6 +3,9 @@ import { StdStringType } from './StdStringType'; import { StrSliceType } from './StrSliceType'; import { StrType } from './StrType'; +/** + * @group node + */ describe('StrSlicesType.ts', () => { test('should properly parse type attributes', () => { const strSlices = new StrSliceType({ diff --git a/packages/abi-typegen/src/abi/types/StrType.test.ts b/packages/abi-typegen/src/abi/types/StrType.test.ts index 6da95512f2..ff14193100 100644 --- a/packages/abi-typegen/src/abi/types/StrType.test.ts +++ b/packages/abi-typegen/src/abi/types/StrType.test.ts @@ -1,6 +1,9 @@ import { BoolType } from './BoolType'; import { StrType } from './StrType'; +/** + * @group node + */ describe('StrType.ts', () => { test('should properly parse type attributes', () => { const str = new StrType({ diff --git a/packages/abi-typegen/src/abi/types/StructType.test.ts b/packages/abi-typegen/src/abi/types/StructType.test.ts index 7f275ecaca..05237215cd 100644 --- a/packages/abi-typegen/src/abi/types/StructType.test.ts +++ b/packages/abi-typegen/src/abi/types/StructType.test.ts @@ -14,9 +14,12 @@ import { StdStringType } from './StdStringType'; import { StructType } from './StructType'; import { U16Type } from './U16Type'; +/** + * @group node + */ describe('StructType.ts', () => { test('should properly parse type attributes', () => { - const parseTypeArguments = jest.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); + const parseTypeArguments = vi.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); const project = getTypegenForcProject(AbiTypegenProjectsEnum.STRUCT_SIMPLE); diff --git a/packages/abi-typegen/src/abi/types/TupleType.test.ts b/packages/abi-typegen/src/abi/types/TupleType.test.ts index ec43dbe5f1..51b8eded04 100644 --- a/packages/abi-typegen/src/abi/types/TupleType.test.ts +++ b/packages/abi-typegen/src/abi/types/TupleType.test.ts @@ -10,9 +10,12 @@ import * as parseTypeArgumentsMod from '../../utils/parseTypeArguments'; import { ArrayType } from './ArrayType'; import { TupleType } from './TupleType'; +/** + * @group node + */ describe('TupleType.ts', () => { test('should properly parse type attributes', () => { - const parseTypeArguments = jest.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); + const parseTypeArguments = vi.spyOn(parseTypeArgumentsMod, 'parseTypeArguments'); const project = getTypegenForcProject(AbiTypegenProjectsEnum.TUPLE_SIMPLE); const rawTypes = project.abiContents.types; diff --git a/packages/abi-typegen/src/abi/types/U16Type.test.ts b/packages/abi-typegen/src/abi/types/U16Type.test.ts index b9c59d8590..4ef9f20688 100644 --- a/packages/abi-typegen/src/abi/types/U16Type.test.ts +++ b/packages/abi-typegen/src/abi/types/U16Type.test.ts @@ -1,6 +1,9 @@ import { U16Type } from './U16Type'; import { U32Type } from './U32Type'; +/** + * @group node + */ describe('U16Type.ts', () => { test('should properly parse type attributes', () => { const u16 = new U16Type({ diff --git a/packages/abi-typegen/src/abi/types/U32Type.test.ts b/packages/abi-typegen/src/abi/types/U32Type.test.ts index 8020f02b2f..2d442c3ee4 100644 --- a/packages/abi-typegen/src/abi/types/U32Type.test.ts +++ b/packages/abi-typegen/src/abi/types/U32Type.test.ts @@ -1,6 +1,9 @@ import { U32Type } from './U32Type'; import { U64Type } from './U64Type'; +/** + * @group node + */ describe('U32Type.ts', () => { test('should properly parse type attributes', () => { const u32 = new U32Type({ diff --git a/packages/abi-typegen/src/abi/types/U64Type.test.ts b/packages/abi-typegen/src/abi/types/U64Type.test.ts index 0503548032..97c47d08ae 100644 --- a/packages/abi-typegen/src/abi/types/U64Type.test.ts +++ b/packages/abi-typegen/src/abi/types/U64Type.test.ts @@ -1,6 +1,9 @@ import { U32Type } from './U32Type'; import { U64Type } from './U64Type'; +/** + * @group node + */ describe('U64Type.ts', () => { test('should properly parse type attributes', () => { const u64 = new U64Type({ diff --git a/packages/abi-typegen/src/abi/types/U8Type.test.ts b/packages/abi-typegen/src/abi/types/U8Type.test.ts index bd31eacbb6..87b9828c71 100644 --- a/packages/abi-typegen/src/abi/types/U8Type.test.ts +++ b/packages/abi-typegen/src/abi/types/U8Type.test.ts @@ -1,6 +1,9 @@ import { U16Type } from './U16Type'; import { U8Type } from './U8Type'; +/** + * @group node + */ describe('U8Type.ts', () => { test('should properly parse type attributes', () => { const u8 = new U8Type({ diff --git a/packages/abi-typegen/src/abi/types/VectorType.test.ts b/packages/abi-typegen/src/abi/types/VectorType.test.ts index fbb97706dc..ca6b22a0ed 100644 --- a/packages/abi-typegen/src/abi/types/VectorType.test.ts +++ b/packages/abi-typegen/src/abi/types/VectorType.test.ts @@ -1,6 +1,9 @@ import { StructType } from './StructType'; import { VectorType } from './VectorType'; +/** + * @group node + */ describe('VectorType.ts', () => { test('should properly parse type attributes', () => { const vector = new VectorType({ diff --git a/packages/abi-typegen/src/cli.test.ts b/packages/abi-typegen/src/cli.test.ts index ef0fe525bb..683ffafca4 100644 --- a/packages/abi-typegen/src/cli.test.ts +++ b/packages/abi-typegen/src/cli.test.ts @@ -9,21 +9,30 @@ import { run, runCliAction } from './cli'; import * as runTypegenMod from './runTypegen'; import { ProgramTypeEnum } from './types/enums/ProgramTypeEnum'; +/** + * @group node + */ describe('cli.ts', () => { function mockDeps(params?: { runTypegenError: Error }) { - const runTypegen = jest.spyOn(runTypegenMod, 'runTypegen').mockImplementation(() => { + const runTypegen = vi.spyOn(runTypegenMod, 'runTypegen').mockImplementation(() => { if (params?.runTypegenError) { throw params?.runTypegenError; } }); - const exit = jest.spyOn(process, 'exit').mockImplementation(); - const err = jest.spyOn(stderr, 'write').mockImplementation(); + + const exit = vi.spyOn(process, 'exit').mockImplementation(vi.fn()); + const err = vi.spyOn(stderr, 'write').mockResolvedValue(true); return { exit, err, runTypegen }; } - beforeEach(jest.resetAllMocks); - afterEach(jest.restoreAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); test('should call runTypegen with proper params: for Contracts', async () => { const { runTypegen } = mockDeps(); diff --git a/packages/abi-typegen/src/index.test.ts b/packages/abi-typegen/src/index.test.ts index 62a9b1d764..2de17d17b4 100644 --- a/packages/abi-typegen/src/index.test.ts +++ b/packages/abi-typegen/src/index.test.ts @@ -1,5 +1,8 @@ import * as indexMod from './index'; +/** + * @group node + */ describe('index.ts', () => { test('should export AbiTypeGen class', () => { expect(indexMod.AbiTypeGen).toBeTruthy(); diff --git a/packages/abi-typegen/src/runTypegen.test.ts b/packages/abi-typegen/src/runTypegen.test.ts index 1ca5777fa0..dab049f18e 100644 --- a/packages/abi-typegen/src/runTypegen.test.ts +++ b/packages/abi-typegen/src/runTypegen.test.ts @@ -12,6 +12,9 @@ import { import { runTypegen } from './runTypegen'; import { ProgramTypeEnum } from './types/enums/ProgramTypeEnum'; +/** + * @group node + */ describe('runTypegen.js', () => { test('should run typegen, using: globals', async () => { const project = getTypegenForcProject(AbiTypegenProjectsEnum.FULL); @@ -157,7 +160,7 @@ describe('runTypegen.js', () => { }); test('should log messages to stdout', async () => { - const stdoutWrite = jest.spyOn(process.stdout, 'write').mockImplementation(); + const stdoutWrite = vi.spyOn(process.stdout, 'write').mockResolvedValue(true); // setup temp sway project const project = getTypegenForcProject(AbiTypegenProjectsEnum.SCRIPT); @@ -252,6 +255,67 @@ describe('runTypegen.js', () => { ); }); + test('should write messages to stdout', async () => { + const project = getTypegenForcProject(AbiTypegenProjectsEnum.FULL); + + // compute filepaths + const cwd = process.cwd(); + const inputs = [project.inputGlobal]; + const output = project.tempDir; + const normalizedName = project.normalizedName; + const programType = ProgramTypeEnum.CONTRACT; + const silent = false; + + // duplicates ABI JSON so we can validate if all inputs + // are being collected (and not only the first one) + const from = project.abiPath; + const to = from.replace('-abi.json', '2-abi.json'); + + // also duplicates BIN file + const fromBin = project.binPath; + const toBin = fromBin.replace('.bin', '2.bin'); + + cpSync(from, to); + cpSync(fromBin, toBin); + + // mocking + const write = vi.spyOn(process.stdout, 'write').mockReturnValue(true); + + // executes program + const fn = () => + runTypegen({ + cwd, + inputs, + output, + programType, + silent, + }); + + const { error } = await safeExec(fn); + + // validates execution was ok + expect(error).toBeFalsy(); + + // check if all files were created + const files = [ + join(output, 'index.ts'), + join(output, 'common.d.ts'), + join(output, `${normalizedName}Abi.d.ts`), + join(output, `${normalizedName}2Abi.d.ts`), + join(output, 'factories', `${normalizedName}Abi__factory.ts`), + join(output, `${normalizedName}Abi.hex.ts`), + join(output, `${normalizedName}2Abi.hex.ts`), + ]; + + expect(files.length).toEqual(7); + + files.forEach((f) => { + expect(existsSync(f)).toEqual(true); + }); + + expect(write).toHaveBeenCalled(); + }); + test('should error for no ABI in inputs', async () => { const cwd = process.cwd(); const inputs = ['./*-abis.json']; // abi don't exist diff --git a/packages/abi-typegen/src/templates/common/common.test.ts b/packages/abi-typegen/src/templates/common/common.test.ts index 601981e6a6..6209fb706a 100644 --- a/packages/abi-typegen/src/templates/common/common.test.ts +++ b/packages/abi-typegen/src/templates/common/common.test.ts @@ -2,6 +2,9 @@ import { mockVersions } from '../../../test/utils/mockVersions'; import { renderCommonTemplate } from './common'; +/** + * @group node + */ describe('templates/common', () => { test('should render common template', () => { // mocking diff --git a/packages/abi-typegen/src/templates/common/index.test.ts b/packages/abi-typegen/src/templates/common/index.test.ts index f49e9aa97f..bf5355502c 100644 --- a/packages/abi-typegen/src/templates/common/index.test.ts +++ b/packages/abi-typegen/src/templates/common/index.test.ts @@ -9,6 +9,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { renderIndexTemplate } from './index'; +/** + * @group node + */ describe('templates/index', () => { test('should render index template', () => { // mocking diff --git a/packages/abi-typegen/src/templates/contract/bytecode.test.ts b/packages/abi-typegen/src/templates/contract/bytecode.test.ts index f8af661789..e110dfb93a 100644 --- a/packages/abi-typegen/src/templates/contract/bytecode.test.ts +++ b/packages/abi-typegen/src/templates/contract/bytecode.test.ts @@ -7,6 +7,9 @@ import { mockVersions } from '../../../test/utils/mockVersions'; import { renderBytecodeTemplate } from './bytecode'; +/** + * @group node + */ describe('templates/contract/bytecode', () => { test('should render bytecode template', () => { // mocking diff --git a/packages/abi-typegen/src/templates/contract/dts.test.ts b/packages/abi-typegen/src/templates/contract/dts.test.ts index 2e6b59ff9b..15e6221b6a 100644 --- a/packages/abi-typegen/src/templates/contract/dts.test.ts +++ b/packages/abi-typegen/src/templates/contract/dts.test.ts @@ -10,6 +10,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { renderDtsTemplate } from './dts'; +/** + * @group node + */ describe('templates/dts', () => { test('should render dts template', () => { // mocking diff --git a/packages/abi-typegen/src/templates/contract/factory.test.ts b/packages/abi-typegen/src/templates/contract/factory.test.ts index 04c3311d2e..fc7fd116af 100644 --- a/packages/abi-typegen/src/templates/contract/factory.test.ts +++ b/packages/abi-typegen/src/templates/contract/factory.test.ts @@ -9,6 +9,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { renderFactoryTemplate } from './factory'; +/** + * @group node + */ describe('templates/factory', () => { test('should render factory template', () => { // mocking diff --git a/packages/abi-typegen/src/templates/predicate/factory.test.ts b/packages/abi-typegen/src/templates/predicate/factory.test.ts index bfe6c49409..7d5e0e91d0 100644 --- a/packages/abi-typegen/src/templates/predicate/factory.test.ts +++ b/packages/abi-typegen/src/templates/predicate/factory.test.ts @@ -12,6 +12,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { renderFactoryTemplate } from './factory'; +/** + * @group node + */ describe('factory.ts', () => { test('should render factory template', () => { const { restore } = mockVersions(); diff --git a/packages/abi-typegen/src/templates/renderHbsTemplate.test.ts b/packages/abi-typegen/src/templates/renderHbsTemplate.test.ts index c9e2253eec..d1e0633ff8 100644 --- a/packages/abi-typegen/src/templates/renderHbsTemplate.test.ts +++ b/packages/abi-typegen/src/templates/renderHbsTemplate.test.ts @@ -2,6 +2,9 @@ import { mockVersions } from '../../test/utils/mockVersions'; import { renderHbsTemplate } from './renderHbsTemplate'; +/** + * @group node + */ describe('renderHbsTemplate.ts', () => { test('should render given template w/ data while injecting header', () => { // mocking diff --git a/packages/abi-typegen/src/templates/script/factory.test.ts b/packages/abi-typegen/src/templates/script/factory.test.ts index c4618a3b99..0267d01492 100644 --- a/packages/abi-typegen/src/templates/script/factory.test.ts +++ b/packages/abi-typegen/src/templates/script/factory.test.ts @@ -12,6 +12,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { renderFactoryTemplate } from './factory'; +/** + * @group node + */ describe('factory.ts', () => { test('should render factory template', () => { const { restore } = mockVersions(); diff --git a/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts b/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts index c2b5f9f519..70425c68df 100644 --- a/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts +++ b/packages/abi-typegen/src/templates/utils/formatConfigurables.test.ts @@ -1,5 +1,8 @@ import { formatConfigurables } from './formatConfigurables'; +/** + * @group node + */ describe('formatConfigurables.ts', () => { function mockAllDeps() { const rawAbiType = { @@ -17,7 +20,7 @@ describe('formatConfigurables.ts', () => { }, rawAbiType, requiredFuelsMembersImports: [], - parseComponentsAttributes: jest.fn(), + parseComponentsAttributes: vi.fn(), }; const rawAbiConfigurable = { diff --git a/packages/abi-typegen/src/templates/utils/formatEnums.test.ts b/packages/abi-typegen/src/templates/utils/formatEnums.test.ts index 114cf94784..e760962614 100644 --- a/packages/abi-typegen/src/templates/utils/formatEnums.test.ts +++ b/packages/abi-typegen/src/templates/utils/formatEnums.test.ts @@ -7,6 +7,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { formatEnums } from './formatEnums'; +/** + * @group node + */ describe('formatEnums.ts', () => { test('should format enums just fine', () => { const project = getTypegenForcProject(AbiTypegenProjectsEnum.ENUM_OF_ENUMS); diff --git a/packages/abi-typegen/src/templates/utils/formatImports.test.ts b/packages/abi-typegen/src/templates/utils/formatImports.test.ts index 6fc9a0ca70..ce4f79b224 100644 --- a/packages/abi-typegen/src/templates/utils/formatImports.test.ts +++ b/packages/abi-typegen/src/templates/utils/formatImports.test.ts @@ -3,6 +3,9 @@ import { U8Type } from '../../abi/types/U8Type'; import { formatImports } from './formatImports'; +/** + * @group node + */ describe('formatImports.ts', () => { const baseMembers = ['Contract']; diff --git a/packages/abi-typegen/src/templates/utils/formatStructs.test.ts b/packages/abi-typegen/src/templates/utils/formatStructs.test.ts index 1a7bb64fea..f00d5a0f00 100644 --- a/packages/abi-typegen/src/templates/utils/formatStructs.test.ts +++ b/packages/abi-typegen/src/templates/utils/formatStructs.test.ts @@ -7,6 +7,9 @@ import { ProgramTypeEnum } from '../../types/enums/ProgramTypeEnum'; import { formatStructs } from './formatStructs'; +/** + * @group node + */ describe('formatStructs.ts', () => { test('should format structs just fine', () => { const project = getTypegenForcProject(AbiTypegenProjectsEnum.STRUCT_SIMPLE); diff --git a/packages/abi-typegen/src/utils/assembleContracts.test.ts b/packages/abi-typegen/src/utils/assembleContracts.test.ts index bda3ae13db..887c6fbecf 100644 --- a/packages/abi-typegen/src/utils/assembleContracts.test.ts +++ b/packages/abi-typegen/src/utils/assembleContracts.test.ts @@ -7,25 +7,28 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { assembleContracts } from './assembleContracts'; +/** + * @group node + */ describe('assembleContracts.ts', () => { function mockAllDeps() { - jest.resetAllMocks(); + vi.resetAllMocks(); - const renderCommonTemplate = jest + const renderCommonTemplate = vi .spyOn(renderCommonTemplateMod, 'renderCommonTemplate') - .mockImplementation(); + .mockReturnValue(''); - const renderFactoryTemplate = jest + const renderFactoryTemplate = vi .spyOn(renderFactoryTemplateMod, 'renderFactoryTemplate') - .mockImplementation(); + .mockReturnValue(''); - const renderIndexTemplate = jest + const renderIndexTemplate = vi .spyOn(renderIndexTemplateMod, 'renderIndexTemplate') - .mockImplementation(); + .mockReturnValue(''); - const renderBytecodeTemplate = jest + const renderBytecodeTemplate = vi .spyOn(renderBytecodeTemplateMod, 'renderBytecodeTemplate') - .mockImplementation(); + .mockReturnValue(''); return { renderCommonTemplate, diff --git a/packages/abi-typegen/src/utils/assemblePredicates.test.ts b/packages/abi-typegen/src/utils/assemblePredicates.test.ts index 04c7a9d8f2..603d87a9ec 100644 --- a/packages/abi-typegen/src/utils/assemblePredicates.test.ts +++ b/packages/abi-typegen/src/utils/assemblePredicates.test.ts @@ -6,19 +6,22 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { assemblePredicates } from './assemblePredicates'; +/** + * @group node + */ describe('assemblePredicates.ts', () => { function mockAllDeps() { - const renderCommonTemplate = jest + const renderCommonTemplate = vi .spyOn(renderCommonTemplateMod, 'renderCommonTemplate') - .mockImplementation(); + .mockImplementation(vi.fn().mockResolvedValue('')); - const renderFactoryTemplate = jest + const renderFactoryTemplate = vi .spyOn(renderFactoryTemplateMod, 'renderFactoryTemplate') - .mockImplementation(); + .mockImplementation(vi.fn().mockResolvedValue('')); - const renderIndexTemplate = jest + const renderIndexTemplate = vi .spyOn(renderIndexTemplateMod, 'renderIndexTemplate') - .mockImplementation(); + .mockImplementation(vi.fn().mockResolvedValue('')); return { renderCommonTemplate, @@ -27,8 +30,13 @@ describe('assemblePredicates.ts', () => { }; } - beforeEach(jest.resetAllMocks); - afterEach(jest.restoreAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); test('should assemble all files from Predicate ABI ', () => { const { renderCommonTemplate, renderFactoryTemplate, renderIndexTemplate } = mockAllDeps(); @@ -42,7 +50,7 @@ describe('assemblePredicates.ts', () => { includeBinFiles: true, }); - jest.resetAllMocks(); + vi.resetAllMocks(); const files = assemblePredicates({ abis, outputDir }); @@ -65,7 +73,7 @@ describe('assemblePredicates.ts', () => { includeBinFiles: true, }); - jest.resetAllMocks(); + vi.resetAllMocks(); const files = assemblePredicates({ abis, outputDir }); diff --git a/packages/abi-typegen/src/utils/assembleScripts.test.ts b/packages/abi-typegen/src/utils/assembleScripts.test.ts index 0be690ba72..d7cdfbb942 100644 --- a/packages/abi-typegen/src/utils/assembleScripts.test.ts +++ b/packages/abi-typegen/src/utils/assembleScripts.test.ts @@ -6,19 +6,22 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { assembleScripts } from './assembleScripts'; +/** + * @group node + */ describe('assembleScripts.ts', () => { function mockAllDeps() { - const renderCommonTemplate = jest + const renderCommonTemplate = vi .spyOn(renderCommonTemplateMod, 'renderCommonTemplate') - .mockImplementation(); + .mockResolvedValue(''); - const renderFactoryTemplate = jest + const renderFactoryTemplate = vi .spyOn(renderFactoryTemplateMod, 'renderFactoryTemplate') - .mockImplementation(); + .mockResolvedValue(''); - const renderIndexTemplate = jest + const renderIndexTemplate = vi .spyOn(renderIndexTemplateMod, 'renderIndexTemplate') - .mockImplementation(); + .mockResolvedValue(''); return { renderCommonTemplate, @@ -27,8 +30,13 @@ describe('assembleScripts.ts', () => { }; } - beforeEach(jest.resetAllMocks); - afterEach(jest.restoreAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); test('should assemble all files from Script ABI ', () => { const { renderCommonTemplate, renderFactoryTemplate, renderIndexTemplate } = mockAllDeps(); @@ -42,7 +50,7 @@ describe('assembleScripts.ts', () => { includeBinFiles: true, }); - jest.resetAllMocks(); + vi.resetAllMocks(); const files = assembleScripts({ abis, outputDir }); @@ -65,7 +73,7 @@ describe('assembleScripts.ts', () => { includeBinFiles: true, }); - jest.resetAllMocks(); + vi.resetAllMocks(); const files = assembleScripts({ abis, outputDir }); diff --git a/packages/abi-typegen/src/utils/collectBinFilePaths.test.ts b/packages/abi-typegen/src/utils/collectBinFilePaths.test.ts index 72d6bb5db8..5c061a1e3b 100644 --- a/packages/abi-typegen/src/utils/collectBinFilePaths.test.ts +++ b/packages/abi-typegen/src/utils/collectBinFilePaths.test.ts @@ -7,18 +7,27 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { collectBinFilepaths } from './collectBinFilePaths'; import * as validateBinFileMod from './validateBinFile'; +/** + * @group node + */ describe('collectBinFilePaths.ts', () => { const script = getTypegenForcProject(AbiTypegenProjectsEnum.SCRIPT); const predicate = getTypegenForcProject(AbiTypegenProjectsEnum.PREDICATE); const contract = getTypegenForcProject(AbiTypegenProjectsEnum.MINIMAL); function mockDeps() { - const validateBinFile = jest.spyOn(validateBinFileMod, 'validateBinFile').mockImplementation(); + const validateBinFile = vi + .spyOn(validateBinFileMod, 'validateBinFile') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .mockResolvedValue({} as any); + // const validateBinFile = vi.spyOn(validateBinFileMod, 'validateBinFile').getMockImplementation(); return { validateBinFile }; } - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); test('should collect bin files for Scripts', () => { const { validateBinFile } = mockDeps(); diff --git a/packages/abi-typegen/src/utils/collectStorageSlotsFilePaths.test.ts b/packages/abi-typegen/src/utils/collectStorageSlotsFilePaths.test.ts index a449db7392..4bbb9ad285 100644 --- a/packages/abi-typegen/src/utils/collectStorageSlotsFilePaths.test.ts +++ b/packages/abi-typegen/src/utils/collectStorageSlotsFilePaths.test.ts @@ -3,12 +3,17 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { collectStorageSlotsFilepaths } from './collectStorageSlotsFilePaths'; +/** + * @group node + */ describe('collectStorageSlotsFilePaths.ts', () => { const script = getTypegenForcProject(AbiTypegenProjectsEnum.SCRIPT); const predicate = getTypegenForcProject(AbiTypegenProjectsEnum.PREDICATE); const contract = getTypegenForcProject(AbiTypegenProjectsEnum.MINIMAL); - afterEach(jest.restoreAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); test('should collect storage slot files', () => { const contractStorageSlots = collectStorageSlotsFilepaths({ diff --git a/packages/abi-typegen/src/utils/extractStructName.test.ts b/packages/abi-typegen/src/utils/extractStructName.test.ts index b5df918687..0e70135454 100644 --- a/packages/abi-typegen/src/utils/extractStructName.test.ts +++ b/packages/abi-typegen/src/utils/extractStructName.test.ts @@ -5,6 +5,9 @@ import type { IRawAbiTypeRoot } from '../types/interfaces/IRawAbiType'; import { extractStructName } from './extractStructName'; +/** + * @group node + */ describe('extractStructName.ts', () => { /* Test helpers diff --git a/packages/abi-typegen/src/utils/findType.test.ts b/packages/abi-typegen/src/utils/findType.test.ts index 1fba83a080..2f7fd78a66 100644 --- a/packages/abi-typegen/src/utils/findType.test.ts +++ b/packages/abi-typegen/src/utils/findType.test.ts @@ -6,6 +6,9 @@ import type { IType } from '../types/interfaces/IType'; import { findType } from './findType'; import { makeType } from './makeType'; +/** + * @group node + */ describe('findType.ts', () => { test('should find type', () => { const rawAbiType: IRawAbiTypeRoot = { @@ -17,7 +20,7 @@ describe('findType.ts', () => { const type: IType = makeType({ rawAbiType }); - const parseComponentsAttributesSpy = jest.spyOn(type, 'parseComponentsAttributes'); + const parseComponentsAttributesSpy = vi.spyOn(type, 'parseComponentsAttributes'); const typeId = 1; const types: IType[] = [type]; // array with type to be found diff --git a/packages/abi-typegen/src/utils/makeConfigurable.test.ts b/packages/abi-typegen/src/utils/makeConfigurable.test.ts index 0c46ed4f71..726c713a21 100644 --- a/packages/abi-typegen/src/utils/makeConfigurable.test.ts +++ b/packages/abi-typegen/src/utils/makeConfigurable.test.ts @@ -2,6 +2,9 @@ import { Configurable } from '../abi/configurable/Configurable'; import { makeConfigurable } from './makeConfigurable'; +/** + * @group node + */ describe('makeConfigurable.ts', () => { function mockAllDeps() { const rawAbiType = { @@ -19,7 +22,7 @@ describe('makeConfigurable.ts', () => { }, rawAbiType, requiredFuelsMembersImports: [], - parseComponentsAttributes: jest.fn(), + parseComponentsAttributes: vi.fn(), }; const rawAbiConfigurable = { diff --git a/packages/abi-typegen/src/utils/makeFunction.test.ts b/packages/abi-typegen/src/utils/makeFunction.test.ts index 302c6cc2a2..d1ad5f1b15 100644 --- a/packages/abi-typegen/src/utils/makeFunction.test.ts +++ b/packages/abi-typegen/src/utils/makeFunction.test.ts @@ -5,6 +5,9 @@ import type { IType } from '../types/interfaces/IType'; import { makeFunction } from './makeFunction'; import { makeType } from './makeType'; +/** + * @group node + */ describe('functions.ts', () => { test('should instantiate a new Function instance', () => { const rawU8: IRawAbiTypeRoot = { diff --git a/packages/abi-typegen/src/utils/makeType.test.ts b/packages/abi-typegen/src/utils/makeType.test.ts index 6e1cfbe0e4..29c96c0936 100644 --- a/packages/abi-typegen/src/utils/makeType.test.ts +++ b/packages/abi-typegen/src/utils/makeType.test.ts @@ -5,6 +5,9 @@ import type { IRawAbiTypeRoot } from '../types/interfaces/IRawAbiType'; import { makeType } from './makeType'; +/** + * @group node + */ describe('makeType.ts', () => { test('should create a new Type instance just fine', () => { const rawAbiType: IRawAbiTypeRoot = { diff --git a/packages/abi-typegen/src/utils/parseConfigurables.test.ts b/packages/abi-typegen/src/utils/parseConfigurables.test.ts index 5517a8b689..51a07b8dbc 100644 --- a/packages/abi-typegen/src/utils/parseConfigurables.test.ts +++ b/packages/abi-typegen/src/utils/parseConfigurables.test.ts @@ -1,6 +1,9 @@ import * as makeConfigurableMod from './makeConfigurable'; import { parseConfigurables } from './parseConfigurables'; +/** + * @group node + */ describe('parseConfigurables.ts', () => { function mockAllDeps() { const rawAbiType = { @@ -18,7 +21,7 @@ describe('parseConfigurables.ts', () => { }, rawAbiType, requiredFuelsMembersImports: [], - parseComponentsAttributes: jest.fn(), + parseComponentsAttributes: vi.fn(), }; const rawAbiConfigurable = { @@ -37,7 +40,7 @@ describe('parseConfigurables.ts', () => { rawAbiConfigurable, }; - const makeConfigurable = jest + const makeConfigurable = vi .spyOn(makeConfigurableMod, 'makeConfigurable') .mockReturnValue(configurable); diff --git a/packages/abi-typegen/src/utils/parseFunctions.test.ts b/packages/abi-typegen/src/utils/parseFunctions.test.ts index 75909f2eca..e3533a5333 100644 --- a/packages/abi-typegen/src/utils/parseFunctions.test.ts +++ b/packages/abi-typegen/src/utils/parseFunctions.test.ts @@ -5,6 +5,9 @@ import type { IType } from '../types/interfaces/IType'; import { makeType } from './makeType'; import { parseFunctions } from './parseFunctions'; +/** + * @group node + */ describe('functions.ts', () => { test('should parse an array of raw abi functions', () => { const rawU8: IRawAbiTypeRoot = { diff --git a/packages/abi-typegen/src/utils/parseTypeArguments.test.ts b/packages/abi-typegen/src/utils/parseTypeArguments.test.ts index a2479b6b3d..397e624733 100644 --- a/packages/abi-typegen/src/utils/parseTypeArguments.test.ts +++ b/packages/abi-typegen/src/utils/parseTypeArguments.test.ts @@ -63,6 +63,9 @@ const defautRawTypes: IRawAbiTypeRoot[] = [ }, ]; +/** + * @group node + */ describe('parseTypeArguments.ts', () => { /* Test helpers diff --git a/packages/abi-typegen/src/utils/parseTypes.test.ts b/packages/abi-typegen/src/utils/parseTypes.test.ts index e86359764d..63213bb2bb 100644 --- a/packages/abi-typegen/src/utils/parseTypes.test.ts +++ b/packages/abi-typegen/src/utils/parseTypes.test.ts @@ -2,6 +2,9 @@ import type { IRawAbiTypeRoot } from '../types/interfaces/IRawAbiType'; import { parseTypes } from './parseTypes'; +/** + * @group node + */ describe('types.ts', () => { test('should parse an array of raw abi types', () => { const rawU8: IRawAbiTypeRoot = { diff --git a/packages/abi-typegen/src/utils/shouldSkipType.test.ts b/packages/abi-typegen/src/utils/shouldSkipType.test.ts index dc15d1c348..6faa48fe65 100644 --- a/packages/abi-typegen/src/utils/shouldSkipType.test.ts +++ b/packages/abi-typegen/src/utils/shouldSkipType.test.ts @@ -1,6 +1,9 @@ import { shouldSkipAbiType } from './shouldSkipAbiType'; import { supportedTypes } from './supportedTypes'; +/** + * @group node + */ describe('types.ts', () => { test('should always skip these types', () => { expect(shouldSkipAbiType({ type: '()' })).toEqual(true); diff --git a/packages/abi-typegen/src/utils/supportedTypes.test.ts b/packages/abi-typegen/src/utils/supportedTypes.test.ts index 2a36f578e0..391d9e6ed4 100644 --- a/packages/abi-typegen/src/utils/supportedTypes.test.ts +++ b/packages/abi-typegen/src/utils/supportedTypes.test.ts @@ -1,5 +1,8 @@ import { supportedTypes } from './supportedTypes'; +/** + * @group node + */ describe('supportedTypes.ts', () => { test('should export all supported types', () => { expect(supportedTypes.length).toEqual(21); diff --git a/packages/abi-typegen/src/utils/validateBinFile.test.ts b/packages/abi-typegen/src/utils/validateBinFile.test.ts index 35bc863962..4a1f0b9f26 100644 --- a/packages/abi-typegen/src/utils/validateBinFile.test.ts +++ b/packages/abi-typegen/src/utils/validateBinFile.test.ts @@ -2,6 +2,9 @@ import { ProgramTypeEnum } from '../types/enums/ProgramTypeEnum'; import { validateBinFile } from './validateBinFile'; +/** + * @group node + */ describe('validateBinFile.ts', () => { test('should not throw for existent Script BIN file', () => { const params = { diff --git a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs index 35bfe22e30..0693e86bdf 100644 --- a/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs +++ b/packages/abi-typegen/test/fixtures/templates/contract/bytecode.hbs @@ -9,4 +9,4 @@ Fuel-Core version: 33.33.33 */ -export default '0x740000034700000000000000000000445dfcc00110fff3005d4060495d47f001134904407648000272f0007b36f000001aec5000910000005c43f000244000004700000001000000000000000000000055b7ae10'\ +export default '0x740000034700000000000000000000445dfcc00110fff3005d4060495d47f001134904407648000272f0007b36f000001aec5000910000005c43f000244000004700000001000000000000000000000055b7ae10' \ No newline at end of file diff --git a/packages/abi-typegen/test/utils/mockVersions.ts b/packages/abi-typegen/test/utils/mockVersions.ts index ce7421caeb..bf0b666a74 100644 --- a/packages/abi-typegen/test/utils/mockVersions.ts +++ b/packages/abi-typegen/test/utils/mockVersions.ts @@ -9,10 +9,13 @@ import * as versionsMod from '@fuel-ts/versions'; * * https://stackoverflow.com/a/72885576 */ -jest.mock('@fuel-ts/versions', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/versions'), -})); +vi.mock('@fuel-ts/versions', async () => { + const mod = await vi.importActual('@fuel-ts/versions'); + return { + __esModule: true, + ...mod, + }; +}); export function mockVersions( values: { @@ -25,12 +28,12 @@ export function mockVersions( FUEL_CORE: '33.33.33', } ) { - const mock = jest.replaceProperty(versionsMod, 'versions', values); + const mock = vi.spyOn(versionsMod, 'versions', 'get').mockReturnValue(values); return { versions: values, restore() { - mock.restore(); + mock.mockRestore(); }, }; } diff --git a/packages/abi-typegen/tsdoc.json b/packages/abi-typegen/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/abi-typegen/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/address/README.md b/packages/address/README.md index d3a9ceb234..1bc2595404 100644 --- a/packages/address/README.md +++ b/packages/address/README.md @@ -16,7 +16,7 @@ This module contains the utilities for encoding and decoding address and contrac ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/types/address.html) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/types/address/) ## Usage diff --git a/packages/address/package.json b/packages/address/package.json index 24954d358b..cb1c373ece 100644 --- a/packages/address/package.json +++ b/packages/address/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/address/src/address.test.ts b/packages/address/src/address.test.ts index c01cb002b9..964e1e7dc7 100644 --- a/packages/address/src/address.test.ts +++ b/packages/address/src/address.test.ts @@ -25,6 +25,10 @@ const ADDRESS_BYTES = [ const expectedAddress = 'fuel1785jcs4epy625cmjuv9u269rymmwv6s6q2y9jhnw877nj2j08ehqce3rxf'; const expectedB256Address = '0xf1e92c42b90934aa6372e30bc568a326f6e66a1a0288595e6e3fbd392a4f3e6e'; +/** + * @group node + * @group browser + */ describe('Address utils', () => { test('fromBech32 (bech32 to decoded bech32)', () => { const result = utils.fromBech32(ADDRESS_BECH32); diff --git a/packages/contract/README.md b/packages/contract/README.md index a399d3306f..a3d0eeb949 100644 --- a/packages/contract/README.md +++ b/packages/contract/README.md @@ -16,7 +16,7 @@ This module allows for a simple way to serialize calls and transactions to an on ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/contracts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/contracts/) ## Usage diff --git a/packages/contract/package.json b/packages/contract/package.json index 5e1982e796..8ba72eee8e 100644 --- a/packages/contract/package.json +++ b/packages/contract/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/contract/src/contract-factory.ts b/packages/contract/src/contract-factory.ts index 430cff694f..6838e6fbfe 100644 --- a/packages/contract/src/contract-factory.ts +++ b/packages/contract/src/contract-factory.ts @@ -152,8 +152,9 @@ export default class ContractFactory { transactionRequest.maxFee = this.account.provider.getGasConfig().maxGasPerTx; await this.account.fund(transactionRequest, requiredQuantities, maxFee); - const response = await this.account.sendTransaction(transactionRequest); - await response.wait(); + await this.account.sendTransaction(transactionRequest, { + awaitExecution: true, + }); return new Contract(contractId, this.interface, this.account); } diff --git a/packages/create-fuels/package.json b/packages/create-fuels/package.json index 136e5c98e2..4bde52b49d 100644 --- a/packages/create-fuels/package.json +++ b/packages/create-fuels/package.json @@ -11,7 +11,7 @@ "templates" ], "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "license": "Apache-2.0", "scripts": { diff --git a/packages/create-fuels/test/cli.test.ts b/packages/create-fuels/test/cli.test.ts index a172bccfbc..5c7b36e825 100644 --- a/packages/create-fuels/test/cli.test.ts +++ b/packages/create-fuels/test/cli.test.ts @@ -3,6 +3,9 @@ import { join } from 'path'; import { runScaffoldCli } from '../src/cli'; +/** + * @group node + */ test('create-fuels extracts the template to the specified directory', async () => { // move the templates folder from the root of the project to the root of the create-fuels package temporarily. // this is needed because of the way the create-fuels package is setup. diff --git a/packages/create-fuels/tsconfig.json b/packages/create-fuels/tsconfig.json index d84d8e0585..3529ad76cd 100644 --- a/packages/create-fuels/tsconfig.json +++ b/packages/create-fuels/tsconfig.json @@ -3,6 +3,6 @@ "compilerOptions": { "outDir": "./dist" }, - "include": ["src", "scripts"], + "include": ["src", "scripts", "test"], "exclude": ["templates"] } diff --git a/packages/create-fuels/tsdoc.json b/packages/create-fuels/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/create-fuels/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/crypto/README.md b/packages/crypto/README.md index 539fe19ccc..65af022d0f 100644 --- a/packages/crypto/README.md +++ b/packages/crypto/README.md @@ -18,7 +18,7 @@ This module contains the utilities for encrypting and decrypting data objects us -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/crypto/package.json b/packages/crypto/package.json index c19842bf48..9e4bdb3f9a 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "browser": { "./dist/index.mjs": "./dist/index.browser.mjs" diff --git a/packages/crypto/src/shared/keccak256.test.ts b/packages/crypto/src/shared/keccak256.test.ts index 730e2835ed..ca130a2621 100644 --- a/packages/crypto/src/shared/keccak256.test.ts +++ b/packages/crypto/src/shared/keccak256.test.ts @@ -1,20 +1,24 @@ -import * as ethereumCryptography from 'ethereum-cryptography/keccak'; - import { bufferFromString } from '..'; -import { keccak256 } from './keccak256'; +import { keccak256 as keccak } from './keccak256'; -describe('keccak256', () => { - afterEach(jest.restoreAllMocks); +const data = bufferFromString('hashedKey'); - it('hashes using keccak256', () => { - const data = bufferFromString('hashedKey'); +vi.mock('ethereum-cryptography/keccak', () => ({ + keccak256: vi.fn(() => data), +})); - const mock = jest.spyOn(ethereumCryptography, 'keccak256').mockImplementationOnce(() => data); +/** + * @group node + */ +describe('keccak256', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); - const hashedKey = keccak256(data); + it('hashes using keccak256', () => { + const hashedKey = keccak(data); - expect(mock).toBeCalledTimes(1); expect(hashedKey).toEqual(data); }); }); diff --git a/packages/crypto/src/shared/scrypt.test.ts b/packages/crypto/src/shared/scrypt.test.ts index 06660b9ab3..571a2371d1 100644 --- a/packages/crypto/src/shared/scrypt.test.ts +++ b/packages/crypto/src/shared/scrypt.test.ts @@ -1,20 +1,23 @@ -import * as ethereumCryptography from 'ethereum-cryptography/scrypt'; - import { bufferFromString } from '..'; import type { IScryptParams } from '../types'; import { scrypt } from './scrypt'; -describe('scrypt', () => { - afterEach(jest.restoreAllMocks); +const data = bufferFromString('hashedKey'); - it('hashes using scrypt', () => { - const mockedHashedKey = bufferFromString('hashedKey'); +vi.mock('ethereum-cryptography/scrypt', () => ({ + scryptSync: vi.fn(() => data), +})); - const mock = jest - .spyOn(ethereumCryptography, 'scryptSync') - .mockImplementationOnce(() => mockedHashedKey); +/** + * @group node + */ +describe('scrypt', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + it('hashes using scrypt', () => { const password = bufferFromString('password'); const salt = bufferFromString('salt'); @@ -29,7 +32,6 @@ describe('scrypt', () => { const hashedKey = scrypt(params); - expect(mock).toBeCalledTimes(1); - expect(hashedKey).toEqual(mockedHashedKey); + expect(hashedKey).toEqual(data); }); }); diff --git a/packages/crypto/test/aes-ctr.test.ts b/packages/crypto/test/aes-ctr.test.ts index ae14cc0a33..46b4ce2671 100644 --- a/packages/crypto/test/aes-ctr.test.ts +++ b/packages/crypto/test/aes-ctr.test.ts @@ -1,7 +1,11 @@ -import { envs } from './envs'; +import { encrypt, decrypt } from '..'; +/** + * @group node + * @group browser + */ describe('Keystore', () => { - it.each(envs)('Encrypt and Decrypt', async ({ encrypt, decrypt }) => { + it('Encrypt and Decrypt', async () => { const password = '0b540281-f87b-49ca-be37-2264c7f260f7'; const data = { name: 'test', @@ -17,7 +21,7 @@ describe('Keystore', () => { expect(decryptedResult).toEqual(data); }); - it.each(envs)('Decrypt with wrong password should throw', async ({ encrypt, decrypt }) => { + it('Decrypt with wrong password should throw', async () => { const password = '0b540281-f87b-49ca-be37-2264c7f260f7'; const data = { name: 'test', @@ -27,7 +31,7 @@ describe('Keystore', () => { await expect(decrypt(`${password}123`, encryptedResult)).rejects.toThrow('Invalid credentials'); }); - it.each(envs)('Decrypt Loop', async ({ decrypt }) => { + it('Decrypt Loop', async () => { const INPUTS = [ { data: '07yJczBTonXWyKdJfEcx', diff --git a/packages/crypto/test/bufferFromString.test.ts b/packages/crypto/test/bufferFromString.test.ts index 40a89b714e..992ba30a12 100644 --- a/packages/crypto/test/bufferFromString.test.ts +++ b/packages/crypto/test/bufferFromString.test.ts @@ -1,31 +1,27 @@ -import { envs } from './envs'; +import { bufferFromString } from '..'; +/** + * @group node + * @group browser + */ describe('bufferFromString', () => { const buffer = new Uint8Array([104, 101, 108, 108, 111]); // ASCII values for "hello" - it.each(envs)( - 'should correctly convert string to Uint8Array with base64 encoding in %s environment', - ({ bufferFromString }) => { - const string = 'aGVsbG8='; // "hello" in Base64 - const result = bufferFromString(string, 'base64'); - expect(result).toStrictEqual(buffer); // ASCII values for "hello" - } - ); + it('should correctly convert string to Uint8Array with base64 encoding in a node environment', () => { + const string = 'aGVsbG8='; // "hello" in Base64 + const result = bufferFromString(string, 'base64'); + expect(result).toStrictEqual(buffer); // ASCII values for "hello" + }); - it.each(envs)( - 'should correctly convert string to Uint8Array with utf-8 encoding in %s environment', - ({ bufferFromString }) => { - const string = 'hello'; - const result = bufferFromString(string, 'utf-8'); - expect(result).toStrictEqual(buffer); // ASCII values for "hello" - } - ); - it.each(envs)( - 'should correctly convert string to Uint8Array with hex encoding in %s environment', - ({ bufferFromString }) => { - const string = '68656c6c6f'; // "hello" in Hex - const result = bufferFromString(string, 'hex'); - expect(result).toStrictEqual(buffer); // ASCII values for "hello" - } - ); + it('should correctly convert string to Uint8Array with utf-8 encoding in a node environment', () => { + const string = 'hello'; + const result = bufferFromString(string, 'utf-8'); + expect(result).toStrictEqual(buffer); // ASCII values for "hello" + }); + + it('should correctly convert string to Uint8Array with hex encoding in a node environment', () => { + const string = '68656c6c6f'; // "hello" in Hex + const result = bufferFromString(string, 'hex'); + expect(result).toStrictEqual(buffer); // ASCII values for "hello" + }); }); diff --git a/packages/crypto/test/encryptJsonWalletData.test.ts b/packages/crypto/test/encryptJsonWalletData.test.ts index 1018ef8901..56438e8614 100644 --- a/packages/crypto/test/encryptJsonWalletData.test.ts +++ b/packages/crypto/test/encryptJsonWalletData.test.ts @@ -1,18 +1,18 @@ -import { envs } from './envs'; - +import { encryptJsonWalletData, decryptJsonWalletData, randomBytes } from '..'; +/** + * @group node + * @group browser + */ describe('encryptJsonWalletData', () => { - it.each(envs)( - 'should encrypt and decrypt json wallet data correctly in %s environment', - async ({ encryptJsonWalletData, decryptJsonWalletData, randomBytes }) => { - const testData = new Uint8Array([104, 101, 108, 108, 111]); - const testKey = randomBytes(16); - const testIv = randomBytes(16); + it('should encrypt and decrypt json wallet data correctly in a node environment', async () => { + const testData = new Uint8Array([104, 101, 108, 108, 111]); + const testKey = randomBytes(16); + const testIv = randomBytes(16); - const encryptedData = await encryptJsonWalletData(testData, testKey, testIv); - expect(encryptedData).not.toEqual(testData); // ensure data was encrypted + const encryptedData = await encryptJsonWalletData(testData, testKey, testIv); + expect(encryptedData).not.toEqual(testData); // ensure data was encrypted - const decryptedData = await decryptJsonWalletData(encryptedData, testKey, testIv); - expect(decryptedData).toEqual(testData); // ensure data was decrypted correctly - } - ); + const decryptedData = await decryptJsonWalletData(encryptedData, testKey, testIv); + expect(decryptedData).toEqual(testData); // ensure data was decrypted correctly + }); }); diff --git a/packages/crypto/test/envs.ts b/packages/crypto/test/envs.ts deleted file mode 100644 index 007eb74ee8..0000000000 --- a/packages/crypto/test/envs.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as node from '../src/index'; -// import * as browser from '../src/index.browser'; - -export const envs = [ - { toString: () => 'node', ...node }, - // { toString: () => 'browser', ...browser }, TODO: Uncomment when running tests in browser is supported -]; diff --git a/packages/crypto/test/stringFromBuffer.test.ts b/packages/crypto/test/stringFromBuffer.test.ts index e6be8e2395..1647b13ccc 100644 --- a/packages/crypto/test/stringFromBuffer.test.ts +++ b/packages/crypto/test/stringFromBuffer.test.ts @@ -1,29 +1,24 @@ -import { envs } from './envs'; +import { stringFromBuffer } from '..'; +/** + * @group node + * @group browser + */ describe('stringFromBuffer', () => { const buffer = new Uint8Array([104, 101, 108, 108, 111]); // ASCII values for "hello" - it.each(envs)( - 'should correctly convert Uint8Array to string with base64 encoding in %s environment', - ({ stringFromBuffer }) => { - const result = stringFromBuffer(buffer, 'base64'); - expect(result).toEqual('aGVsbG8='); // "hello" in Base64 - } - ); + it('should correctly convert Uint8Array to string with base64 encoding in a node environment', () => { + const result = stringFromBuffer(buffer, 'base64'); + expect(result).toEqual('aGVsbG8='); // "hello" in Base64 + }); - it.each(envs)( - 'should correctly convert Uint8Array to string with utf-8 encoding in %s environment', - ({ stringFromBuffer }) => { - const result = stringFromBuffer(buffer, 'utf-8'); - expect(result).toEqual('hello'); - } - ); + it('should correctly convert Uint8Array to string with utf-8 encoding in a node environment', () => { + const result = stringFromBuffer(buffer, 'utf-8'); + expect(result).toEqual('hello'); + }); - it.each(envs)( - 'should correctly convert Uint8Array to string with hex encoding in %s environment', - ({ stringFromBuffer }) => { - const result = stringFromBuffer(buffer, 'hex'); - expect(result).toEqual('68656c6c6f'); // "hello" in Hex - } - ); + it('should correctly convert Uint8Array to string with hex encoding in a node environment', () => { + const result = stringFromBuffer(buffer, 'hex'); + expect(result).toEqual('68656c6c6f'); // "hello" in Hex + }); }); diff --git a/packages/crypto/tsdoc.json b/packages/crypto/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/crypto/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/errors/README.md b/packages/errors/README.md index bde1e5f4f5..acb3452bea 100644 --- a/packages/errors/README.md +++ b/packages/errors/README.md @@ -20,7 +20,7 @@ This package contains core utilities regarding throwing errors internally inside -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/errors/package.json b/packages/errors/package.json index 2328c5da98..65e23f389c 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/errors/src/error-codes.ts b/packages/errors/src/error-codes.ts index 244c1d463f..e02c67180e 100644 --- a/packages/errors/src/error-codes.ts +++ b/packages/errors/src/error-codes.ts @@ -49,6 +49,7 @@ export enum ErrorCode { CONVERTING_FAILED = 'converting-error', ELEMENT_NOT_FOUND = 'element-not-found', MISSING_REQUIRED_PARAMETER = 'missing-required-parameter', + INVALID_REQUEST = 'invalid-request', UNEXPECTED_HEX_VALUE = 'unexpected-hex-value', // transaction diff --git a/packages/errors/src/fuel-error.test.ts b/packages/errors/src/fuel-error.test.ts index b77ffc6fb0..33e73fd5e2 100644 --- a/packages/errors/src/fuel-error.test.ts +++ b/packages/errors/src/fuel-error.test.ts @@ -3,6 +3,10 @@ import { versions } from '@fuel-ts/versions'; import { FuelError, ErrorCode } from '.'; import { expectToThrowFuelError } from './test-utils/expect-to-throw-fuel-error'; +/** + * @group node + * @group browser + */ it('has properties set as expected on creation', () => { const message = 'whatever'; const error = new FuelError(FuelError.CODES.PARSE_FAILED, message); diff --git a/packages/errors/src/test-utils.test.ts b/packages/errors/src/test-utils.test.ts index 5514bff4cb..f1352fcb13 100644 --- a/packages/errors/src/test-utils.test.ts +++ b/packages/errors/src/test-utils.test.ts @@ -1,6 +1,10 @@ import * as indexMod from './test-utils'; -describe(__filename, () => { +/** + * @group node + * @group browser + */ +describe('test utils', () => { test('should export all test utilities', () => { expect(indexMod.expectToThrowFuelError).toBeTruthy(); expect(indexMod.safeExec).toBeTruthy(); diff --git a/packages/errors/src/test-utils/expect-to-throw-fuel-error.test.ts b/packages/errors/src/test-utils/expect-to-throw-fuel-error.test.ts index 640d9f3818..bd20f07f35 100644 --- a/packages/errors/src/test-utils/expect-to-throw-fuel-error.test.ts +++ b/packages/errors/src/test-utils/expect-to-throw-fuel-error.test.ts @@ -2,6 +2,10 @@ import { FuelError } from '..'; import { expectToThrowFuelError } from './expect-to-throw-fuel-error'; +/** + * @group node + * @group browser + */ describe('expect-to-throw-fuel-error', () => { const otherError = new Error('Original Error'); const fuelError = new FuelError(FuelError.CODES.PARSE_FAILED, 'FuelError 1'); diff --git a/packages/errors/src/test-utils/safeExec.test.ts b/packages/errors/src/test-utils/safeExec.test.ts index b58dcd7f8c..09aea1a8b8 100644 --- a/packages/errors/src/test-utils/safeExec.test.ts +++ b/packages/errors/src/test-utils/safeExec.test.ts @@ -1,5 +1,9 @@ import { safeExec } from './safeExec'; +/** + * @group node + * @group browser + */ describe('safeExec.js', () => { it('should catch error', async () => { const ERROR_MSG = 'I am an error.'; diff --git a/packages/errors/tsdoc.json b/packages/errors/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/errors/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/fuel-gauge/src/advanced-logging.test.ts b/packages/fuel-gauge/src/advanced-logging.test.ts index 32f74899b1..eb3110a120 100644 --- a/packages/fuel-gauge/src/advanced-logging.test.ts +++ b/packages/fuel-gauge/src/advanced-logging.test.ts @@ -18,6 +18,9 @@ beforeAll(async () => { ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); +/** + * @group node + */ describe('Advanced Logging', () => { it('can get log data', async () => { const { value, logs } = await contractInstance.functions diff --git a/packages/fuel-gauge/src/auth-testing.test.ts b/packages/fuel-gauge/src/auth-testing.test.ts index 7e69e2135c..a5824035ca 100644 --- a/packages/fuel-gauge/src/auth-testing.test.ts +++ b/packages/fuel-gauge/src/auth-testing.test.ts @@ -15,6 +15,9 @@ let contractInstance: Contract; let wallet: WalletUnlocked; let gasPrice: BN; +/** + * @group node + */ describe('Auth Testing', () => { beforeAll(async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/packages/fuel-gauge/src/await-execution.test.ts b/packages/fuel-gauge/src/await-execution.test.ts new file mode 100644 index 0000000000..34010ac7b9 --- /dev/null +++ b/packages/fuel-gauge/src/await-execution.test.ts @@ -0,0 +1,97 @@ +import { launchNode } from '@fuel-ts/wallet/test-utils'; +import { + Provider, + WalletUnlocked, + randomBytes, + Wallet, + BaseAssetId, + FUEL_NETWORK_URL, +} from 'fuels'; + +/** + * @group node + */ +describe('await-execution', () => { + test('awaiting execution of a transaction on the provider works', async () => { + const { cleanup, ip, port } = await launchNode({ + args: ['--poa-instant', 'false', '--poa-interval-period', '400ms'], + }); + const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); + + const genesisWallet = new WalletUnlocked( + process.env.GENESIS_SECRET || randomBytes(32), + nodeProvider + ); + + const destination = Wallet.generate({ provider: nodeProvider }); + + const transfer = await genesisWallet.createTransfer(destination.address, 100, BaseAssetId, { + gasPrice: nodeProvider.getGasConfig().minGasPrice, + gasLimit: 10_000, + }); + + transfer.updateWitnessByOwner( + genesisWallet.address, + await genesisWallet.signTransaction(transfer) + ); + + const response = await nodeProvider.sendTransaction(transfer, { awaitExecution: true }); + + expect(response.gqlTransaction?.status?.type).toBe('SuccessStatus'); + + cleanup(); + }); + + test.skip('transferring funds with awaitExecution works', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const genesisWallet = new WalletUnlocked( + process.env.GENESIS_SECRET || randomBytes(32), + provider + ); + + const sendTransactionSpy = vi.spyOn(provider, 'sendTransaction'); + + const destination = Wallet.generate({ provider }); + + await genesisWallet.transfer( + destination.address, + 100, + BaseAssetId, + { + gasPrice: provider.getGasConfig().minGasPrice, + gasLimit: 10_000, + } + // { awaitExecution: true } + ); + + expect(sendTransactionSpy).toHaveBeenCalledTimes(1); + const awaitExecutionArg = sendTransactionSpy.mock.calls[0][1]; + expect(awaitExecutionArg).toMatchObject({ awaitExecution: true }); + }); + + test.skip('withdrawToBaseLayer works with awaitExecution', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const genesisWallet = new WalletUnlocked( + process.env.GENESIS_SECRET || randomBytes(32), + provider + ); + + const sendTransactionSpy = vi.spyOn(provider, 'sendTransaction'); + + const destination = Wallet.generate({ provider }); + + await genesisWallet.withdrawToBaseLayer( + destination.address, + 100, + { + gasPrice: provider.getGasConfig().minGasPrice, + gasLimit: 10_000, + } + // { awaitExecution: true } + ); + + expect(sendTransactionSpy).toHaveBeenCalledTimes(1); + const awaitExecutionArg = sendTransactionSpy.mock.calls[0][1]; + expect(awaitExecutionArg).toMatchObject({ awaitExecution: true }); + }); +}); diff --git a/packages/fuel-gauge/src/bytes.test.ts b/packages/fuel-gauge/src/bytes.test.ts index 00328174aa..c547c927b3 100644 --- a/packages/fuel-gauge/src/bytes.test.ts +++ b/packages/fuel-gauge/src/bytes.test.ts @@ -30,6 +30,9 @@ const setup = async (balance = 500_000) => { return wallet; }; +/** + * @group node + */ describe('Bytes Tests', () => { let gasPrice: BN; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/call-test-contract.test.ts b/packages/fuel-gauge/src/call-test-contract.test.ts index 9b83a5bd2b..c875966963 100644 --- a/packages/fuel-gauge/src/call-test-contract.test.ts +++ b/packages/fuel-gauge/src/call-test-contract.test.ts @@ -16,6 +16,9 @@ const setupContract = createSetupConfig({ const U64_MAX = bn(2).pow(64).sub(1); +/** + * @group node + */ describe('CallTestContract', () => { let gasPrice: BN; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/configurable-contract.test.ts b/packages/fuel-gauge/src/configurable-contract.test.ts index 77485283bc..5462dfb5c2 100644 --- a/packages/fuel-gauge/src/configurable-contract.test.ts +++ b/packages/fuel-gauge/src/configurable-contract.test.ts @@ -25,6 +25,9 @@ const defaultValues = { }, }; +/** + * @group node + */ describe('Configurable Contract', () => { let wallet: WalletUnlocked; let factory: ContractFactory; diff --git a/packages/fuel-gauge/src/contract-factory.test.ts b/packages/fuel-gauge/src/contract-factory.test.ts index 9f89a87abb..84053d2472 100644 --- a/packages/fuel-gauge/src/contract-factory.test.ts +++ b/packages/fuel-gauge/src/contract-factory.test.ts @@ -14,6 +14,9 @@ import { import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; +/** + * @group node + */ describe('Contract Factory', () => { let gasPrice: BN; diff --git a/packages/fuel-gauge/src/contract.test.ts b/packages/fuel-gauge/src/contract.test.ts index 4d7803d8b7..a1d7ae26b8 100644 --- a/packages/fuel-gauge/src/contract.test.ts +++ b/packages/fuel-gauge/src/contract.test.ts @@ -162,6 +162,9 @@ const txPointer = '0x00000000000000000000000000000000'; const AltToken = '0x0101010101010101010101010101010101010101010101010101010101010101'; +/** + * @group node + */ describe('Contract', () => { let gasPrice: BN; beforeAll(async () => { @@ -171,11 +174,11 @@ describe('Contract', () => { it('generates function methods on a simple contract', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - const spy = jest.spyOn(provider, 'sendTransaction'); + const spy = vi.spyOn(provider, 'sendTransaction'); const wallet = await generateTestWallet(provider, [[1_000, BaseAssetId]]); const contract = new Contract(ZeroBytes32, jsonFragment, wallet); const fragment = contract.interface.getFunction('entry_one'); - const interfaceSpy = jest.spyOn(fragment, 'encodeArguments'); + const interfaceSpy = vi.spyOn(fragment, 'encodeArguments'); try { await contract.functions.entry_one(42); @@ -189,11 +192,11 @@ describe('Contract', () => { it('generates function methods on a complex contract', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); - const spy = jest.spyOn(provider, 'sendTransaction'); + const spy = vi.spyOn(provider, 'sendTransaction'); const wallet = await generateTestWallet(provider, [[1_000, BaseAssetId]]); const contract = new Contract(ZeroBytes32, complexFragment, wallet); const fragment = contract.interface.getFunction('tuple_function'); - const interfaceSpy = jest.spyOn(fragment, 'encodeArguments'); + const interfaceSpy = vi.spyOn(fragment, 'encodeArguments'); try { await contract.functions.tuple_function({ @@ -966,7 +969,7 @@ describe('Contract', () => { const amountToContract = 100; - const tx = await wallet.transferToContract(contract.id, amountToContract, asset, { + const tx = await wallet.transferToContract(contract.id.toB256(), amountToContract, asset, { gasPrice, gasLimit: 10_000, }); diff --git a/packages/fuel-gauge/src/coverage-contract.test.ts b/packages/fuel-gauge/src/coverage-contract.test.ts index 86341df09d..4a8f571b57 100644 --- a/packages/fuel-gauge/src/coverage-contract.test.ts +++ b/packages/fuel-gauge/src/coverage-contract.test.ts @@ -48,6 +48,9 @@ enum ColorEnumOutput { Blue = 'Blue', } +/** + * @group node + */ describe('Coverage Contract', () => { it('can return outputs', async () => { // Call contract methods diff --git a/packages/fuel-gauge/src/doc-examples.test.ts b/packages/fuel-gauge/src/doc-examples.test.ts index 2ef0ec692d..e69efa90ea 100644 --- a/packages/fuel-gauge/src/doc-examples.test.ts +++ b/packages/fuel-gauge/src/doc-examples.test.ts @@ -23,7 +23,6 @@ import { Wallet, WalletUnlocked, Signer, - ContractFactory, ZeroBytes32, BaseAssetId, FUEL_NETWORK_URL, @@ -35,9 +34,6 @@ const { abiContents: callTestAbi } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.CALL_TEST_CONTRACT ); -const { binHexlified: liquidityPoolContractBytecode, abiContents: liquidityPoolABI } = - getFuelGaugeForcProject(FuelGaugeProjectsEnum.LIQUIDITY_POOL); - const { binHexlified: predicateTriple } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_TRIPLE_SIG ); @@ -46,9 +42,6 @@ const { binHexlified: testPredicateTrue } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_TRUE ); -const { binHexlified: tokenContractBytecode, abiContents: tokenContractABI } = - getFuelGaugeForcProject(FuelGaugeProjectsEnum.TOKEN_CONTRACT); - const PUBLIC_KEY = '0x2f34bc0df4db0ec391792cedb05768832b49b1aa3a2dd8c30054d1af00f67d00b74b7acbbf3087c8e0b1a4c343db50aa471d21f278ff5ce09f07795d541fb47e'; @@ -62,6 +55,9 @@ const ADDRESS_BYTES = new Uint8Array([ 89, 94, 110, 63, 189, 57, 42, 79, 62, 110, ]); +/** + * @group node + */ describe('Doc Examples', () => { let gasPrice: BN; @@ -197,6 +193,22 @@ describe('Doc Examples', () => { expect(balances.length).toEqual(0); }); + it('it can be created without a provider', async () => { + // #region wallet-optional-provider + // #context import { Wallet, WalletUnlocked } from 'fuels'; + + // You can create a wallet, without a provider + let unlockedWallet: WalletUnlocked = Wallet.generate(); + unlockedWallet = Wallet.fromPrivateKey(unlockedWallet.privateKey); + + // All non-provider dependent methods are available + unlockedWallet.lock(); + + // All provider dependent methods will throw + await expect(() => unlockedWallet.getCoins()).rejects.toThrow(/Provider not set/); + // #endregion wallet-optional-provider + }); + it('it can work sign messages with wallets', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); // #region wallet-message-signing @@ -468,91 +480,4 @@ describe('Doc Examples', () => { // assert that predicate funds now belong to the receiver expect(bn(receiverBalance).gte(bn(amountToReceiver))).toBeTruthy(); }); - - test.skip('deposit and withdraw cookbook guide', async () => { - // #region deposit-and-withdraw-cookbook-wallet-setup - const provider = await Provider.create(FUEL_NETWORK_URL); - const PRIVATE_KEY = '0x862512a2363db2b3a375c0d4bbbd27172180d89f23f2e259bac850ab02619301'; - const wallet = Wallet.fromPrivateKey(PRIVATE_KEY, provider); - await seedTestWallet(wallet, [{ assetId: BaseAssetId, amount: bn(100_000) }]); - // #endregion deposit-and-withdraw-cookbook-wallet-setup - - // #region deposit-and-withdraw-cookbook-contract-deployments - const tokenContractFactory = new ContractFactory( - tokenContractBytecode, - tokenContractABI, - wallet - ); - const tokenContract = await tokenContractFactory.deployContract({ gasPrice }); - const tokenContractID = tokenContract.id; - - const liquidityPoolContractFactory = new ContractFactory( - liquidityPoolContractBytecode, - liquidityPoolABI, - wallet - ); - const liquidityPoolContract = await liquidityPoolContractFactory.deployContract({ gasPrice }); - const liquidityPoolContractID = liquidityPoolContract.id; - await liquidityPoolContract.functions.set_base_token(tokenContractID).call(); - // #endregion deposit-and-withdraw-cookbook-contract-deployments - - // mint some base tokens to the current wallet - // #region deposit-and-withdraw-cookbook-mint-and-transfer - await tokenContract.functions.mint_coins(500, 1).call(); - await tokenContract.functions - .transfer_coins_to_output( - 200, - { - value: tokenContract.id, - }, - { - value: wallet.address.toB256(), - } - ) - .txParams({ - variableOutputs: 1, - gasPrice, - }) - .call(); - // #endregion deposit-and-withdraw-cookbook-mint-and-transfer - - // deposit base tokens into the liquidity pool - // #region deposit-and-withdraw-cookbook-deposit - await liquidityPoolContract.functions - .deposit({ - value: wallet.address.toB256(), - }) - .callParams({ - forward: { - amount: bn(100), - assetId: tokenContractID.toB256(), - }, - }) - .call(); - // #endregion deposit-and-withdraw-cookbook-deposit - - // verify balances - expect(await wallet.getBalance(tokenContractID.toB256())).toEqual(bn(100)); - expect(await wallet.getBalance(liquidityPoolContractID.toB256())).toEqual(bn(200)); - - // withdraw base tokens from the liquidity pool - // #region deposit-and-withdraw-cookbook-withdraw - const lpTokenBalance = await wallet.getBalance(liquidityPoolContractID.toB256()); - await liquidityPoolContract.functions - .withdraw({ - value: wallet.address.toB256(), - }) - .callParams({ - forward: { - amount: lpTokenBalance, - assetId: liquidityPoolContractID.toB256(), - }, - }) - .call(); - // #endregion deposit-and-withdraw-cookbook-withdraw - - // verify balances again - expect(await wallet.getBalance(tokenContractID.toB256())).toEqual(bn(200)); - expect(await wallet.getBalance(liquidityPoolContractID.toB256())).toEqual(bn(0)); - }); }); diff --git a/packages/fuel-gauge/src/e2e-script.test.ts b/packages/fuel-gauge/src/e2e-script.test.ts index 1211610fed..01eee0d941 100644 --- a/packages/fuel-gauge/src/e2e-script.test.ts +++ b/packages/fuel-gauge/src/e2e-script.test.ts @@ -73,6 +73,10 @@ type MainArgs = [ VecInAStructInAVec, // VEC_IN_A_VEC_IN_A_STRUCT_IN_A_VEC ]; +/** + * @group node + * @group e2e + */ describe('Live Script Test', () => { it('can use script against live Fuel Node', async () => { if (!process.env.FUEL_NETWORK_GENESIS_KEY) { diff --git a/packages/fuel-gauge/src/edge-cases.test.ts b/packages/fuel-gauge/src/edge-cases.test.ts index 4b4601f9f6..6e904c5083 100644 --- a/packages/fuel-gauge/src/edge-cases.test.ts +++ b/packages/fuel-gauge/src/edge-cases.test.ts @@ -1,5 +1,8 @@ import { getSetupContract } from './utils'; +/** + * @group node + */ describe('Edge Cases', () => { it('can run collision_in_fn_names', async () => { const contract = await getSetupContract('collision_in_fn_names')(); diff --git a/packages/fuel-gauge/src/fee.test.ts b/packages/fuel-gauge/src/fee.test.ts index 0482d6f9cc..b44e0a4d2f 100644 --- a/packages/fuel-gauge/src/fee.test.ts +++ b/packages/fuel-gauge/src/fee.test.ts @@ -14,6 +14,9 @@ import { import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; +/** + * @group node + */ describe('Fee', () => { const assetA: string = '0x0101010101010101010101010101010101010101010101010101010101010101'; const assetB: string = '0x0202020202020202020202020202020202020202020202020202020202020202'; diff --git a/packages/fuel-gauge/src/funding-transaction.test.ts b/packages/fuel-gauge/src/funding-transaction.test.ts index 344ab933c4..6bb36b665d 100644 --- a/packages/fuel-gauge/src/funding-transaction.test.ts +++ b/packages/fuel-gauge/src/funding-transaction.test.ts @@ -9,6 +9,9 @@ import { bn, } from 'fuels'; +/** + * @group node + */ describe(__filename, () => { let mainWallet: Account; let provider: Provider; @@ -78,7 +81,7 @@ describe(__filename, () => { expect(bn((request.inputs[0]).amount).toNumber()).toBe(300); expect(maxFee.gt(300)).toBeTruthy(); - const getResourcesToSpendSpy = jest.spyOn(sender, 'getResourcesToSpend'); + const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); await sender.fund(request, requiredQuantities, maxFee); @@ -129,7 +132,7 @@ describe(__filename, () => { expect(bn((request.inputs[0]).amount).toNumber()).toBe(1000); expect(maxFee.lt(1000)).toBeTruthy(); - const getResourcesToSpendSpy = jest.spyOn(sender, 'getResourcesToSpend'); + const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); await sender.fund(request, requiredQuantities, maxFee); @@ -169,7 +172,7 @@ describe(__filename, () => { // TX request does NOT carry any resources, it needs to be funded expect(request.inputs.length).toBe(0); - const getResourcesToSpendSpy = jest.spyOn(sender, 'getResourcesToSpend'); + const getResourcesToSpendSpy = vi.spyOn(sender, 'getResourcesToSpend'); await sender.fund(request, requiredQuantities, maxFee); diff --git a/packages/fuel-gauge/src/generic-types-contract.test.ts b/packages/fuel-gauge/src/generic-types-contract.test.ts index 3a3c792d18..116ef79ec3 100644 --- a/packages/fuel-gauge/src/generic-types-contract.test.ts +++ b/packages/fuel-gauge/src/generic-types-contract.test.ts @@ -8,6 +8,9 @@ const { binHexlified: contractBytecode, abiContents: abiJSON } = getFuelGaugeFor FuelGaugeProjectsEnum.GENERIC_TYPES_CONTRACT ); +/** + * @group node + */ describe('GenericTypesContract', () => { it('should call complex contract function with generic type', async () => { const contract = await setup({ diff --git a/packages/fuel-gauge/src/min-gas.test.ts b/packages/fuel-gauge/src/min-gas.test.ts index e82019c721..d9dfb2958c 100644 --- a/packages/fuel-gauge/src/min-gas.test.ts +++ b/packages/fuel-gauge/src/min-gas.test.ts @@ -17,6 +17,9 @@ import { import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; +/** + * @group node + */ describe(__filename, () => { it('sets gas requirements (contract)', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); diff --git a/packages/fuel-gauge/src/multi-token-contract.test.ts b/packages/fuel-gauge/src/multi-token-contract.test.ts index b5357cacc6..72dd7bbc1c 100644 --- a/packages/fuel-gauge/src/multi-token-contract.test.ts +++ b/packages/fuel-gauge/src/multi-token-contract.test.ts @@ -26,6 +26,9 @@ const subIds = [ '0xdf78cb1e1a1b31fff104eb0baf734a4767a1b1373687c29a26bf1a2b22d1a3c5', ]; +/** + * @group node + */ describe('MultiTokenContract', () => { let gasPrice: BN; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/payable-annotation.test.ts b/packages/fuel-gauge/src/payable-annotation.test.ts index 211f3786ec..da1104405a 100644 --- a/packages/fuel-gauge/src/payable-annotation.test.ts +++ b/packages/fuel-gauge/src/payable-annotation.test.ts @@ -22,6 +22,9 @@ beforeAll(async () => { ({ minGasPrice: gasPrice } = contract.provider.getGasConfig()); }); +/** + * @group node + */ test('allow sending coins to payable functions', async () => { // This should not fail because the function is payable await expect( diff --git a/packages/fuel-gauge/src/policies.test.ts b/packages/fuel-gauge/src/policies.test.ts index d79583b45d..43f21e9c92 100644 --- a/packages/fuel-gauge/src/policies.test.ts +++ b/packages/fuel-gauge/src/policies.test.ts @@ -16,6 +16,9 @@ import { getFuelGaugeForcProject, FuelGaugeProjectsEnum } from '../test/fixtures import { createSetupConfig } from './utils'; +/** + * @group node + */ describe('Policies', () => { let provider: Provider; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts index b826f79b23..0d54b84d22 100644 --- a/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts +++ b/packages/fuel-gauge/src/predicate-conditional-inputs.test.ts @@ -12,6 +12,9 @@ import { import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures'; +/** + * @group node + */ describe('PredicateConditionalInputs', () => { const assetIdA = '0x0101010101010101010101010101010101010101010101010101010101010101'; const assetIdB = '0x0202020202020202020202020202020202020202020202020202020202020202'; diff --git a/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts b/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts index 6c6dcd50fb..6a52eb84c5 100644 --- a/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-arguments.test.ts @@ -6,6 +6,9 @@ import type { Validation } from '../types/predicate'; import { setupWallets, assertBalances, fundPredicate } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: predicateBytesAddress, abiContents: predicateAbiMainArgsAddress } = getFuelGaugeForcProject(FuelGaugeProjectsEnum.PREDICATE_ADDRESS); diff --git a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts index 68d834b8fa..c4aec565fb 100644 --- a/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-configurables.test.ts @@ -13,6 +13,9 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtu import { fundPredicate, assertBalance } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: predicateBytesTrue, abiContents: predicateAbiTrue } = getFuelGaugeForcProject(FuelGaugeProjectsEnum.PREDICATE_TRUE); diff --git a/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts b/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts index a2e6381e3d..cb802fe7fb 100644 --- a/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-estimations.test.ts @@ -13,6 +13,9 @@ import { import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtures'; import type { Validation } from '../types/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: predicateTrueBytecode } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_TRUE diff --git a/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts b/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts index 55b0561dc2..4740b6fbee 100644 --- a/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-evaluations.test.ts @@ -5,6 +5,9 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtu import { setupWallets, assertBalances, fundPredicate } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: predicateBytesTrue } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_TRUE diff --git a/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts b/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts index d3cdfc7394..d8e8093053 100644 --- a/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-input-data.test.ts @@ -5,6 +5,9 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../../test/fixtu import { setupWallets, fundPredicate } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified, abiContents } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_INPUT_DATA diff --git a/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts b/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts index daed4ba398..81c464af8f 100644 --- a/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-invalidations.test.ts @@ -6,6 +6,9 @@ import type { Validation } from '../types/predicate'; import { fundPredicate, setupWallets } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: predicateBytesMainArgsStruct, abiContents: predicateAbiMainArgsStruct } = getFuelGaugeForcProject(FuelGaugeProjectsEnum.PREDICATE_MAIN_ARGS_STRUCT); diff --git a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts index d780c15b53..ff92f02d3f 100644 --- a/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-with-contract.test.ts @@ -16,12 +16,16 @@ import type { Validation } from '../types/predicate'; import { fundPredicate, setupContractWithConfig } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: contractBytes, abiContents: contractAbi } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.CALL_TEST_CONTRACT ); - const { binHexlified: liquidityPoolBytes, abiContents: liquidityPoolAbi } = - getFuelGaugeForcProject(FuelGaugeProjectsEnum.LIQUIDITY_POOL); + const { binHexlified: tokenPoolBytes, abiContents: tokenPoolAbi } = getFuelGaugeForcProject( + FuelGaugeProjectsEnum.TOKEN_CONTRACT + ); const { abiContents: predicateAbiMainArgsStruct } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.PREDICATE_MAIN_ARGS_STRUCT @@ -83,8 +87,8 @@ describe('Predicate', () => { it('calls a predicate and uses proceeds for a contract call', async () => { const contract = await new ContractFactory( - liquidityPoolBytes, - liquidityPoolAbi, + tokenPoolBytes, + tokenPoolAbi, wallet ).deployContract({ gasPrice }); @@ -94,15 +98,10 @@ describe('Predicate', () => { contract.account = receiver; await expect( contract.functions - .deposit({ - value: receiver.address.toB256(), - }) - .callParams({ - forward: [100, BaseAssetId], - }) + .mint_coins(200) .txParams({ gasPrice, - gasLimit: 10_000, + gasLimit: 1_000, }) .call() ).rejects.toThrow(/not enough coins to fit the target/); @@ -136,23 +135,12 @@ describe('Predicate', () => { // calling the contract with the receiver account (with resources) const contractAmount = 10; const { - transactionResult: { fee: receiverTxFee1 }, - } = await contract.functions - .set_base_token(BaseAssetId) - .txParams({ gasPrice, gasLimit: 10_000 }) - .call(); - const { - transactionResult: { fee: receiverTxFee2 }, + transactionResult: { fee: receiverTxFee }, } = await contract.functions - .deposit({ - value: receiver.address.toB256(), - }) - .callParams({ - forward: [contractAmount, BaseAssetId], - }) + .mint_coins(200) .txParams({ gasPrice, - gasLimit: 10_000, + gasLimit: 1_000, }) .call(); @@ -160,11 +148,7 @@ describe('Predicate', () => { const remainingPredicateBalance = toNumber(await predicate.getBalance()); const expectedFinalReceiverBalance = - initialReceiverBalance + - amountToReceiver - - contractAmount - - receiverTxFee1.toNumber() - - receiverTxFee2.toNumber(); + initialReceiverBalance + amountToReceiver - contractAmount - receiverTxFee.toNumber(); expectToBeInRange({ value: finalReceiverBalance, diff --git a/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts b/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts index 6f78d60378..2dcf40d58b 100644 --- a/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts +++ b/packages/fuel-gauge/src/predicate/predicate-with-script.test.ts @@ -8,6 +8,9 @@ import type { Validation } from '../types/predicate'; import { fundPredicate } from './utils/predicate'; +/** + * @group node + */ describe('Predicate', () => { const { binHexlified: scriptBytes, abiContents: scriptAbi } = getFuelGaugeForcProject( FuelGaugeProjectsEnum.SCRIPT_MAIN_ARGS diff --git a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts index 427a53b77f..ec42d86e5f 100644 --- a/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts +++ b/packages/fuel-gauge/src/predicate/utils/predicate/fundPredicate.ts @@ -17,8 +17,7 @@ export const fundPredicate = async ( request.gasLimit = gasUsed; await wallet.fund(request, requiredQuantities, minFee); - const tx = await wallet.sendTransaction(request); - await tx.waitForResult(); + await wallet.sendTransaction(request, { awaitExecution: true }); return predicate.getBalance(); }; diff --git a/packages/fuel-gauge/src/raw-slice.test.ts b/packages/fuel-gauge/src/raw-slice.test.ts index 47bed5d273..aaac3d2001 100644 --- a/packages/fuel-gauge/src/raw-slice.test.ts +++ b/packages/fuel-gauge/src/raw-slice.test.ts @@ -33,6 +33,9 @@ beforeAll(async () => { ({ minGasPrice: gasPrice } = contractInstance.provider.getGasConfig()); }); +/** + * @group node + */ describe('Raw Slice Tests', () => { it('should test raw slice output', async () => { const INPUT = 10; diff --git a/packages/fuel-gauge/src/revert-error.test.ts b/packages/fuel-gauge/src/revert-error.test.ts index 10ff83a422..7c6e816e43 100644 --- a/packages/fuel-gauge/src/revert-error.test.ts +++ b/packages/fuel-gauge/src/revert-error.test.ts @@ -18,6 +18,9 @@ import { FuelGaugeProjectsEnum, getFuelGaugeForcProject } from '../test/fixtures let contractInstance: Contract; let wallet: WalletUnlocked; +/** + * @group node + */ describe('Revert Error Testing', () => { let gasPrice: BN; diff --git a/packages/fuel-gauge/src/script-main-args.test.ts b/packages/fuel-gauge/src/script-main-args.test.ts index d753d4cae9..40d1074760 100644 --- a/packages/fuel-gauge/src/script-main-args.test.ts +++ b/packages/fuel-gauge/src/script-main-args.test.ts @@ -19,6 +19,9 @@ type Baz = { x: number; }; +/** + * @group node + */ describe('Script Coverage', () => { let gasPrice: BN; diff --git a/packages/fuel-gauge/src/script-with-configurable.test.ts b/packages/fuel-gauge/src/script-with-configurable.test.ts index a33ae0695f..702195a142 100644 --- a/packages/fuel-gauge/src/script-with-configurable.test.ts +++ b/packages/fuel-gauge/src/script-with-configurable.test.ts @@ -10,6 +10,9 @@ const defaultValues = { let wallet: WalletUnlocked; +/** + * @group node + */ describe('Script With Configurable', () => { let gasPrice: BN; diff --git a/packages/fuel-gauge/src/script-with-vectors.test.ts b/packages/fuel-gauge/src/script-with-vectors.test.ts index 6a94c9c240..a85bda6186 100644 --- a/packages/fuel-gauge/src/script-with-vectors.test.ts +++ b/packages/fuel-gauge/src/script-with-vectors.test.ts @@ -13,6 +13,9 @@ const setup = async (balance = 500_000) => { return wallet; }; +/** + * @group node + */ describe('Script With Vectors', () => { let gasPrice: BN; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/small-bytes.test.ts b/packages/fuel-gauge/src/small-bytes.test.ts index 14a99bfee8..fd0ed3883f 100644 --- a/packages/fuel-gauge/src/small-bytes.test.ts +++ b/packages/fuel-gauge/src/small-bytes.test.ts @@ -5,6 +5,9 @@ import { join } from 'path'; import { getSetupContract, createWallet } from './utils'; +/** + * @group node + */ describe('small-bytes', () => { const smallBytesProjectDir = join(__dirname, '../test/fixtures/forc-projects/small-bytes'); diff --git a/packages/fuel-gauge/src/std-lib-string.test.ts b/packages/fuel-gauge/src/std-lib-string.test.ts index e6e5e34b2e..424e0daaaa 100644 --- a/packages/fuel-gauge/src/std-lib-string.test.ts +++ b/packages/fuel-gauge/src/std-lib-string.test.ts @@ -24,6 +24,9 @@ const setup = async (balance = 500_000) => { return wallet; }; +/** + * @group node + */ describe('std-lib-string Tests', () => { const { binHexlified: predicateStdString, abiContents: predicateStdStringAbi } = getFuelGaugeForcProject(FuelGaugeProjectsEnum.PREDICATE_STD_LIB_STRING); diff --git a/packages/fuel-gauge/src/storage-test-contract.test.ts b/packages/fuel-gauge/src/storage-test-contract.test.ts index c296eb5501..fe9b2ada00 100644 --- a/packages/fuel-gauge/src/storage-test-contract.test.ts +++ b/packages/fuel-gauge/src/storage-test-contract.test.ts @@ -29,6 +29,9 @@ const setup = async () => { return contract; }; +/** + * @group node + */ describe('StorageTestContract', () => { let gasPrice: BN; beforeAll(async () => { diff --git a/packages/fuel-gauge/src/token-test-contract.test.ts b/packages/fuel-gauge/src/token-test-contract.test.ts index c0fc280795..3e2e2895ab 100644 --- a/packages/fuel-gauge/src/token-test-contract.test.ts +++ b/packages/fuel-gauge/src/token-test-contract.test.ts @@ -31,6 +31,9 @@ beforeAll(async () => { gasPrice = provider.getGasConfig().minGasPrice; }); +/** + * @group node + */ describe('TokenTestContract', () => { it('Can mint and transfer coins', async () => { // New wallet to transfer coins and check balance diff --git a/packages/fuel-gauge/src/transaction-response.test.ts b/packages/fuel-gauge/src/transaction-response.test.ts index e205ba6d1c..bdd2ec0030 100644 --- a/packages/fuel-gauge/src/transaction-response.test.ts +++ b/packages/fuel-gauge/src/transaction-response.test.ts @@ -1,7 +1,18 @@ -import { generateTestWallet } from '@fuel-ts/wallet/test-utils'; -import type { BN, WalletUnlocked } from 'fuels'; -import { BaseAssetId, FUEL_NETWORK_URL, Provider, TransactionResponse, Wallet } from 'fuels'; - +import { generateTestWallet, launchNode } from '@fuel-ts/wallet/test-utils'; +import type { BN } from 'fuels'; +import { + BaseAssetId, + FUEL_NETWORK_URL, + Provider, + TransactionResponse, + Wallet, + randomBytes, + WalletUnlocked, +} from 'fuels'; + +/** + * @group node + */ describe('TransactionSummary', () => { let provider: Provider; let adminWallet: WalletUnlocked; @@ -75,25 +86,33 @@ describe('TransactionSummary', () => { }); it('should ensure waitForResult always waits for the transaction to be processed', async () => { - const destination = Wallet.generate({ - provider, + const { cleanup, ip, port } = await launchNode({ + args: ['--poa-interval-period', '750ms', '--poa-instant', 'false'], }); + const nodeProvider = await Provider.create(`http://${ip}:${port}/graphql`); - const { id: transactionId } = await adminWallet.transfer( + const genesisWallet = new WalletUnlocked( + process.env.GENESIS_SECRET || randomBytes(32), + nodeProvider + ); + + const destination = Wallet.generate({ provider: nodeProvider }); + + const { id: transactionId } = await genesisWallet.transfer( destination.address, 100, BaseAssetId, { gasPrice, gasLimit: 10_000 } ); + const response = await TransactionResponse.create(transactionId, nodeProvider); - const response = new TransactionResponse(transactionId, provider); - - expect(response.gqlTransaction).toBeUndefined(); + expect(response.gqlTransaction?.status?.type).toBe('SubmittedStatus'); await response.waitForResult(); - expect(response.gqlTransaction?.status?.type).toBeDefined(); - expect(response.gqlTransaction?.status?.type).not.toEqual('SubmittedStatus'); + expect(response.gqlTransaction?.status?.type).toEqual('SuccessStatus'); expect(response.gqlTransaction?.id).toBe(transactionId); + + cleanup(); }); }); diff --git a/packages/fuel-gauge/src/transaction-summary.test.ts b/packages/fuel-gauge/src/transaction-summary.test.ts index bb5d57ba8e..dc9810fd70 100644 --- a/packages/fuel-gauge/src/transaction-summary.test.ts +++ b/packages/fuel-gauge/src/transaction-summary.test.ts @@ -19,6 +19,9 @@ import { Wallet, } from 'fuels'; +/** + * @group node + */ describe('TransactionSummary', () => { let provider: Provider; let wallet: WalletUnlocked; diff --git a/packages/fuel-gauge/src/vector-types.test.ts b/packages/fuel-gauge/src/vector-types.test.ts index 841e2bd587..05d8b6370d 100644 --- a/packages/fuel-gauge/src/vector-types.test.ts +++ b/packages/fuel-gauge/src/vector-types.test.ts @@ -84,6 +84,9 @@ const setup = async (balance = 500_000) => { return wallet; }; +/** + * @group node + */ describe('Vector Types Validation', () => { let gasPrice: BN; diff --git a/packages/fuel-gauge/src/vectors.test.ts b/packages/fuel-gauge/src/vectors.test.ts index 7e94057c23..3f9b49b1b5 100644 --- a/packages/fuel-gauge/src/vectors.test.ts +++ b/packages/fuel-gauge/src/vectors.test.ts @@ -17,6 +17,9 @@ enum SmallEnum { Empty = 'Empty', } +/** + * @group node + */ describe('Vector Tests', () => { it('should test u8 vector input/output', async () => { const INPUT = [8, 6, 7, 5, 3, 0, 9]; diff --git a/packages/fuel-gauge/test/fixtures/forc-projects/Forc.toml b/packages/fuel-gauge/test/fixtures/forc-projects/Forc.toml index 6e8bb25e02..02c4857fb8 100644 --- a/packages/fuel-gauge/test/fixtures/forc-projects/Forc.toml +++ b/packages/fuel-gauge/test/fixtures/forc-projects/Forc.toml @@ -11,7 +11,6 @@ members = [ "configurable-contract", "coverage-contract", "generic-types-contract", - "liquidity-pool", "multi-token-contract", "payable-annotation", "predicate-address", diff --git a/packages/fuel-gauge/test/fixtures/forc-projects/coverage-contract/src/main.sw b/packages/fuel-gauge/test/fixtures/forc-projects/coverage-contract/src/main.sw index 83fea8c70b..5115d6fdab 100644 --- a/packages/fuel-gauge/test/fixtures/forc-projects/coverage-contract/src/main.sw +++ b/packages/fuel-gauge/test/fixtures/forc-projects/coverage-contract/src/main.sw @@ -1,14 +1,14 @@ contract; -use std::*; use core::*; -use std::storage::*; -use std::contract_id::ContractId; -use std::vec::Vec; -use std::option::Option; +use std::*; use std::assert::assert; -use std::logging::log; use std::b512::B512; +use std::contract_id::ContractId; +use std::logging::log; +use std::option::Option; +use std::storage::*; +use std::vec::Vec; pub struct U8Struct { i: u8, diff --git a/packages/fuel-gauge/test/fixtures/index.ts b/packages/fuel-gauge/test/fixtures/index.ts index d52e688247..c150b70816 100644 --- a/packages/fuel-gauge/test/fixtures/index.ts +++ b/packages/fuel-gauge/test/fixtures/index.ts @@ -16,7 +16,6 @@ export enum FuelGaugeProjectsEnum { COLLISION_IN_FN_NAMES = 'collision_in_fn_names', COVERAGE_CONTRACT = 'coverage-contract', GENERIC_TYPES_CONTRACT = 'generic-types-contract', - LIQUIDITY_POOL = 'liquidity-pool', MULTI_TOKEN_CONTRACT = 'multi-token-contract', PAYABLE_ANNOTATION = 'payable-annotation', PREDICATE_ADDRESS = 'predicate-address', diff --git a/packages/fuel-gauge/tsdoc.json b/packages/fuel-gauge/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/fuel-gauge/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/fuels/.gitignore b/packages/fuels/.gitignore index 0cf2b81137..289ea01927 100644 --- a/packages/fuels/.gitignore +++ b/packages/fuels/.gitignore @@ -1,4 +1,2 @@ README.md -test/fixtures/project/.fuels -test/fixtures/generated -test/fixtures/fuels.config.ts +test/__temp__* diff --git a/packages/fuels/package.json b/packages/fuels/package.json index fa004e7f1c..ef401f4e7b 100644 --- a/packages/fuels/package.json +++ b/packages/fuels/package.json @@ -10,7 +10,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -76,7 +76,6 @@ "handlebars": "^4.7.7", "joycon": "^3.1.1", "lodash.camelcase": "^4.3.0", - "npm-which": "^3.0.1", "portfinder": "^1.0.32", "rimraf": "^3.0.2", "toml": "^3.0.0", diff --git a/packages/fuels/src/bin.ts b/packages/fuels/src/bin.ts index 016f2671a2..572e5b8df8 100644 --- a/packages/fuels/src/bin.ts +++ b/packages/fuels/src/bin.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { run } from './cli'; import { error } from './cli/utils/logger'; +import { run } from './run'; try { run(process.argv).catch(process.stderr.write); diff --git a/packages/fuels/src/cli.test.ts b/packages/fuels/src/cli.test.ts index 77694f8246..37bf5bc22d 100644 --- a/packages/fuels/src/cli.test.ts +++ b/packages/fuels/src/cli.test.ts @@ -3,16 +3,24 @@ import { Command } from 'commander'; import * as cliMod from './cli'; import { Commands } from './cli/types'; import * as loggingMod from './cli/utils/logger'; +import { run } from './run'; +/** + * @group node + */ describe('cli.js', () => { - const { configureCli, run, onPreAction } = cliMod; + beforeEach(() => { + vi.restoreAllMocks(); + }); - beforeEach(() => jest.resetAllMocks()); - afterAll(() => jest.resetAllMocks()); + afterEach(() => { + vi.restoreAllMocks(); + }); it('shoud configure cli', () => { - const program = configureCli(); + const program = cliMod.configureCli(); + expect(program).toBeTruthy(); // top level props and opts expect(program.name()).toEqual('fuels'); expect(program.opts()).toEqual({ @@ -50,14 +58,14 @@ describe('cli.js', () => { }); it('preAction should configure logging', () => { - const spy = jest.spyOn(loggingMod, 'configureLogging'); + const spy = vi.spyOn(loggingMod, 'configureLogging'); const command = new Command(); command.option('-D, --debug', 'Enables verbose logging', false); command.option('-S, --silent', 'Omit output messages', false); command.parse([]); - onPreAction(command); + cliMod.onPreAction(command); expect(spy).toBeCalledWith({ isDebugEnabled: false, isLoggingEnabled: true, @@ -66,12 +74,16 @@ describe('cli.js', () => { it('should run cli program', async () => { const command = new Command(); - const parseAsync = jest.spyOn(command, 'parseAsync'); - const $configureCli = jest.spyOn(cliMod, 'configureCli').mockReturnValue(command); + + const parseAsync = vi + .spyOn(Command.prototype, 'parseAsync') + .mockReturnValue(Promise.resolve(command)); + + const configureCli = vi.spyOn(cliMod, 'configureCli').mockImplementation(() => new Command()); await run([]); - expect($configureCli).toHaveBeenCalledTimes(1); + expect(configureCli).toHaveBeenCalledTimes(1); expect(parseAsync).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/fuels/src/cli.ts b/packages/fuels/src/cli.ts index 5c457f5df9..427fbac360 100644 --- a/packages/fuels/src/cli.ts +++ b/packages/fuels/src/cli.ts @@ -1,4 +1,5 @@ import { configureCliOptions as configureTypegenCliOptions } from '@fuel-ts/abi-typegen/cli'; +import { findBinPath } from '@fuel-ts/utils/cli-utils'; import { versions } from '@fuel-ts/versions'; import { runVersions } from '@fuel-ts/versions/cli'; import { Command, Option } from 'commander'; @@ -10,7 +11,6 @@ import { init } from './cli/commands/init'; import { withConfig } from './cli/commands/withConfig'; import { withProgram } from './cli/commands/withProgram'; import { Commands } from './cli/types'; -import { findBinPath } from './cli/utils/findBinPath'; import { configureLogging } from './cli/utils/logger'; export const onPreAction = (command: Command) => { @@ -100,17 +100,12 @@ export const configureCli = () => { */ program.command('core', 'Wrapper around Fuel Core binary', { - executableFile: findBinPath('fuels-core'), + executableFile: findBinPath('fuels-core', __dirname), }); program.command('forc', 'Wrapper around Forc binary', { - executableFile: findBinPath('fuels-forc'), + executableFile: findBinPath('fuels-forc', __dirname), }); return program; }; - -export const run = async (argv: string[]) => { - const program = configureCli(); - return program.parseAsync(argv); -}; diff --git a/packages/fuels/src/cli/commands/build/buildSwayProgram.test.ts b/packages/fuels/src/cli/commands/build/buildSwayProgram.test.ts new file mode 100644 index 0000000000..24cf1be223 --- /dev/null +++ b/packages/fuels/src/cli/commands/build/buildSwayProgram.test.ts @@ -0,0 +1,82 @@ +import * as findBinPathMod from '@fuel-ts/utils/cli-utils'; +import * as childProcessMod from 'child_process'; + +import { fuelsConfig } from '../../../../test/fixtures/fuels.config'; +import { mockLogger } from '../../../../test/utils/mockLogger'; +import { configureLogging } from '../../utils/logger'; + +import { buildSwayProgram } from './buildSwayProgram'; + +vi.mock('child_process', async () => { + const mod = await vi.importActual('child_process'); + return { + __esModule: true, + ...mod, + }; +}); + +/** + * @group node + */ +describe('buildSwayPrograms', () => { + beforeEach(() => { + mockLogger(); + }); + + function mockAll(params: { shouldError: boolean } = { shouldError: false }) { + const findBinPath = vi.spyOn(findBinPathMod, 'findBinPath').mockReturnValue(''); + + const spawnMocks = { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + on: vi.fn((eventName: string, fn: (..._: any) => void) => { + const shouldExit = eventName === 'exit' && !params.shouldError; + const shouldError = eventName === 'error' && params.shouldError; + if (shouldExit || shouldError) { + setTimeout(fn, 10); + } + }), + stderr: { + pipe: vi.fn(), + }, + stdout: { + pipe: vi.fn(), + }, + } as unknown as childProcessMod.ChildProcessWithoutNullStreams; + + const spawn = vi.spyOn(childProcessMod, 'spawn').mockReturnValue(spawnMocks); + + return { + spawn, + spawnMocks, + findBinPath, + }; + } + + test('should pipe stdout', async () => { + const { spawn, spawnMocks } = mockAll(); + + vi.spyOn(process.stdout, 'write').mockReturnValue(true); + configureLogging({ isLoggingEnabled: true, isDebugEnabled: false }); + + await buildSwayProgram(fuelsConfig, '/any/workspace/path'); + + expect(spawn).toHaveBeenCalledTimes(1); + expect(spawnMocks.stderr.pipe).toHaveBeenCalledTimes(1); + expect(spawnMocks.stdout.pipe).toHaveBeenCalledTimes(0); + }); + + test('should pipe stdout and stderr', async () => { + const { spawn, spawnMocks } = mockAll(); + + vi.spyOn(process.stderr, 'write').mockReturnValue(true); + vi.spyOn(process.stdout, 'write').mockReturnValue(true); + configureLogging({ isLoggingEnabled: true, isDebugEnabled: true }); + + await buildSwayProgram(fuelsConfig, '/any/workspace/path'); + + expect(spawn).toHaveBeenCalledTimes(1); + expect(spawnMocks.stderr.pipe).toHaveBeenCalledTimes(1); + expect(spawnMocks.stdout.pipe).toHaveBeenCalledTimes(1); + expect(spawnMocks.on).toHaveBeenCalledTimes(2); + }); +}); diff --git a/packages/fuels/src/cli/commands/build/buildSwayProgram.ts b/packages/fuels/src/cli/commands/build/buildSwayProgram.ts new file mode 100644 index 0000000000..80780a6984 --- /dev/null +++ b/packages/fuels/src/cli/commands/build/buildSwayProgram.ts @@ -0,0 +1,32 @@ +import { findBinPath } from '@fuel-ts/utils/cli-utils'; +import { spawn } from 'child_process'; + +import type { FuelsConfig } from '../../types'; +import { debug, loggingConfig } from '../../utils/logger'; + +import { onForcExit, onForcError } from './forcHandlers'; + +export const buildSwayProgram = async (config: FuelsConfig, path: string) => { + debug('Building Sway program', path); + + return new Promise((resolve, reject) => { + const builtInForcPath = findBinPath('fuels-forc', __dirname); + + const command = config.useBuiltinForc ? builtInForcPath : 'forc'; + const forc = spawn(command, ['build', '-p', path], { stdio: 'pipe' }); + + if (loggingConfig.isLoggingEnabled) { + forc.stderr?.pipe(process.stderr); + } + + if (loggingConfig.isDebugEnabled) { + forc.stdout?.pipe(process.stdout); + } + + const onExit = onForcExit(resolve, reject); + const onError = onForcError(reject); + + forc.on('exit', onExit); + forc.on('error', onError); + }); +}; diff --git a/packages/fuels/src/cli/commands/build/buildSwayPrograms.test.ts b/packages/fuels/src/cli/commands/build/buildSwayPrograms.test.ts index 61dd5f78ab..9b1ca75748 100644 --- a/packages/fuels/src/cli/commands/build/buildSwayPrograms.test.ts +++ b/packages/fuels/src/cli/commands/build/buildSwayPrograms.test.ts @@ -1,57 +1,21 @@ -import * as childProcessMod from 'child_process'; - -import { fuelsConfig } from '../../../../test/fixtures/config/fuels.config'; +import { fuelsConfig } from '../../../../test/fixtures/fuels.config'; import { mockLogger } from '../../../../test/utils/mockLogger'; -import { resetDiskAndMocks } from '../../../../test/utils/resetDiskAndMocks'; -import { workspaceDir } from '../../../../test/utils/runCommands'; -import { configureLogging } from '../../utils/logger'; - -import * as buildSwayProgramsMod from './buildSwayPrograms'; -jest.mock('child_process', () => ({ - __esModule: true, - ...jest.requireActual('child_process'), -})); +import * as buildSwayProgramMod from './buildSwayProgram'; +import { buildSwayPrograms } from './buildSwayPrograms'; +/** + * @group node + */ describe('buildSwayPrograms', () => { - const { onForcExit, onForcError } = buildSwayProgramsMod; - - beforeEach(mockLogger); - afterEach(resetDiskAndMocks); - - function mockSpawn(params: { shouldError: boolean } = { shouldError: false }) { - const spawnMocks = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - on: jest.fn((eventName: string, fn: (..._: any) => void) => { - const shouldExit = eventName === 'exit' && !params.shouldError; - const shouldError = eventName === 'error' && params.shouldError; - if (shouldExit || shouldError) { - setTimeout(fn, 10); - } - }), - stderr: { - pipe: jest.fn(), - }, - stdout: { - pipe: jest.fn(), - }, - }; - - const spawn = jest - .spyOn(childProcessMod, 'spawn') - .mockImplementation( - (..._) => spawnMocks as unknown as childProcessMod.ChildProcessWithoutNullStreams - ); - - return { - spawn, - spawnMocks, - }; - } + beforeEach(() => { + vi.resetAllMocks(); + mockLogger(); + }); function mockBuildSwayProgram() { - const buildSwayProgram = jest - .spyOn(buildSwayProgramsMod, 'buildSwayProgram') + const buildSwayProgram = vi + .spyOn(buildSwayProgramMod, 'buildSwayProgram') .mockReturnValue(Promise.resolve()); return { @@ -59,18 +23,15 @@ describe('buildSwayPrograms', () => { }; } - function customConfig(workspace: undefined | string) { - return { - ...structuredClone(fuelsConfig), - workspace, - }; - } - test('building Sway programs using workspace', async () => { - const config = customConfig(workspaceDir); const { buildSwayProgram } = mockBuildSwayProgram(); - await buildSwayProgramsMod.buildSwayPrograms(config); + const config = { + ...structuredClone(fuelsConfig), + workspace: '/any/workspace/path', + }; + + await buildSwayPrograms(config); expect(buildSwayProgram).toHaveBeenCalledTimes(1); expect(buildSwayProgram).toHaveBeenCalledWith(config, config.workspace); @@ -78,68 +39,13 @@ describe('buildSwayPrograms', () => { test('building Sway programs using individual configs', async () => { const { buildSwayProgram } = mockBuildSwayProgram(); - const config = customConfig(undefined); - await buildSwayProgramsMod.buildSwayPrograms(config); + await buildSwayPrograms(fuelsConfig); expect(buildSwayProgram).toHaveBeenCalledTimes(4); - expect(buildSwayProgram).toHaveBeenCalledWith(config, config.contracts[0]); - expect(buildSwayProgram).toHaveBeenCalledWith(config, config.contracts[1]); - expect(buildSwayProgram).toHaveBeenCalledWith(config, config.scripts[0]); - expect(buildSwayProgram).toHaveBeenCalledWith(config, config.predicates[0]); - }); - - test('should pipe stdout', async () => { - const config = customConfig(workspaceDir); - const { spawn, spawnMocks } = mockSpawn(); - - jest.spyOn(process.stdout, 'write').mockImplementation(); - configureLogging({ isLoggingEnabled: true, isDebugEnabled: false }); - - await buildSwayProgramsMod.buildSwayProgram(config, config.workspace); - - expect(spawn).toHaveBeenCalledTimes(1); - expect(spawnMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(spawnMocks.stdout.pipe).toHaveBeenCalledTimes(0); - }); - - test('should pipe stdout and stderr', async () => { - const config = customConfig(workspaceDir); - const { spawn, spawnMocks } = mockSpawn(); - - jest.spyOn(process.stderr, 'write').mockImplementation(); - jest.spyOn(process.stdout, 'write').mockImplementation(); - configureLogging({ isLoggingEnabled: true, isDebugEnabled: true }); - - await buildSwayProgramsMod.buildSwayProgram(config, config.workspace); - - expect(spawn).toHaveBeenCalledTimes(1); - expect(spawnMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(spawnMocks.stdout.pipe).toHaveBeenCalledTimes(1); - expect(spawnMocks.on).toHaveBeenCalledTimes(2); - }); - - test('should resolve on successful exit', () => { - const resolve = jest.fn(); - const reject = jest.fn((_reason?: number | Error) => {}); - onForcExit(resolve, reject)(null); - expect(reject).toHaveBeenCalledTimes(0); - expect(resolve).toHaveBeenCalledTimes(1); - }); - - test('should reject on failed exit', () => { - const resolve = jest.fn(); - const reject = jest.fn((_reason?: number | Error) => {}); - onForcExit(resolve, reject)(1); - expect(reject).toHaveBeenCalledTimes(1); - expect(resolve).toHaveBeenCalledTimes(0); - }); - - test('should reject on error', () => { - const reject = jest.fn(); - const { error } = mockLogger(); - onForcError(reject)(new Error()); - expect(reject).toHaveBeenCalledTimes(1); - expect(error).toHaveBeenCalledTimes(1); + expect(buildSwayProgram).toHaveBeenCalledWith(fuelsConfig, fuelsConfig.contracts[0]); + expect(buildSwayProgram).toHaveBeenCalledWith(fuelsConfig, fuelsConfig.contracts[1]); + expect(buildSwayProgram).toHaveBeenCalledWith(fuelsConfig, fuelsConfig.scripts[0]); + expect(buildSwayProgram).toHaveBeenCalledWith(fuelsConfig, fuelsConfig.predicates[0]); }); }); diff --git a/packages/fuels/src/cli/commands/build/buildSwayPrograms.ts b/packages/fuels/src/cli/commands/build/buildSwayPrograms.ts index 71270893cf..57cf9957dd 100644 --- a/packages/fuels/src/cli/commands/build/buildSwayPrograms.ts +++ b/packages/fuels/src/cli/commands/build/buildSwayPrograms.ts @@ -1,52 +1,8 @@ -import { spawn } from 'child_process'; - import type { FuelsConfig } from '../../types'; -import { findBinPath } from '../../utils/findBinPath'; import { getBinarySource } from '../../utils/getBinarySource'; -import { debug, error, log, loggingConfig } from '../../utils/logger'; - -type OnResultFn = () => void; -type OnErrorFn = (reason?: number | Error) => void; - -export const onForcExit = - (onResultFn: OnResultFn, onErrorFn: OnErrorFn) => (code: number | null) => { - if (code) { - onErrorFn(code); - // process.exit()? - } else { - onResultFn(); - } - }; - -export const onForcError = (onError: OnErrorFn) => (err: Error) => { - error(err); - onError(err); -}; - -export const buildSwayProgram = async (config: FuelsConfig, path: string) => { - debug('Building Sway program', path); - - return new Promise((resolve, reject) => { - const builtInForcPath = findBinPath('fuels-forc'); - - const command = config.useBuiltinForc ? builtInForcPath : 'forc'; - const forc = spawn(command, ['build', '-p', path], { stdio: 'pipe' }); - - if (loggingConfig.isLoggingEnabled) { - forc.stderr?.pipe(process.stderr); - } - - if (loggingConfig.isDebugEnabled) { - forc.stdout?.pipe(process.stdout); - } - - const onExit = onForcExit(resolve, reject); - const onError = onForcError(reject); +import { log } from '../../utils/logger'; - forc.on('exit', onExit); - forc.on('error', onError); - }); -}; +import { buildSwayProgram } from './buildSwayProgram'; export async function buildSwayPrograms(config: FuelsConfig) { log(`Building Sway programs using ${getBinarySource(config.useBuiltinFuelCore)} 'forc' binary`); diff --git a/packages/fuels/src/cli/commands/build/forcHandlers.test.ts b/packages/fuels/src/cli/commands/build/forcHandlers.test.ts new file mode 100644 index 0000000000..e104cdb26a --- /dev/null +++ b/packages/fuels/src/cli/commands/build/forcHandlers.test.ts @@ -0,0 +1,32 @@ +import { mockLogger } from '../../../../test/utils/mockLogger'; + +import { onForcExit, onForcError } from './forcHandlers'; + +/** + * @group node + */ +describe('buildSwayPrograms', () => { + test('should resolve on successful exit', () => { + const resolve = vi.fn(); + const reject = vi.fn((_reason?: number | Error) => {}); + onForcExit(resolve, reject)(null); + expect(reject).toHaveBeenCalledTimes(0); + expect(resolve).toHaveBeenCalledTimes(1); + }); + + test('should reject on failed exit', () => { + const resolve = vi.fn(); + const reject = vi.fn((_reason?: number | Error) => {}); + onForcExit(resolve, reject)(1); + expect(reject).toHaveBeenCalledTimes(1); + expect(resolve).toHaveBeenCalledTimes(0); + }); + + test('should reject on error', () => { + const reject = vi.fn(); + const { error } = mockLogger(); + onForcError(reject)(new Error()); + expect(reject).toHaveBeenCalledTimes(1); + expect(error).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/fuels/src/cli/commands/build/forcHandlers.ts b/packages/fuels/src/cli/commands/build/forcHandlers.ts new file mode 100644 index 0000000000..295005077a --- /dev/null +++ b/packages/fuels/src/cli/commands/build/forcHandlers.ts @@ -0,0 +1,19 @@ +import { error } from '../../utils/logger'; + +type OnResultFn = () => void; +type OnErrorFn = (reason?: number | Error) => void; + +export const onForcExit = + (onResultFn: OnResultFn, onErrorFn: OnErrorFn) => (code: number | null) => { + if (code) { + onErrorFn(code); + // process.exit()? + } else { + onResultFn(); + } + }; + +export const onForcError = (onError: OnErrorFn) => (err: Error) => { + error(err); + onError(err); +}; diff --git a/packages/fuels/src/cli/commands/build/index.ts b/packages/fuels/src/cli/commands/build/index.ts index 0a35fe65af..48f1738d67 100644 --- a/packages/fuels/src/cli/commands/build/index.ts +++ b/packages/fuels/src/cli/commands/build/index.ts @@ -3,7 +3,7 @@ import { type Command } from 'commander'; import type { FuelsConfig } from '../../types'; import { log } from '../../utils/logger'; import { deploy } from '../deploy'; -import { autoStartFuelCore } from '../dev/startFuelCore'; +import { autoStartFuelCore } from '../dev/autoStartFuelCore'; import { buildSwayPrograms } from './buildSwayPrograms'; import { generateTypes } from './generateTypes'; diff --git a/packages/fuels/src/cli/commands/deploy/createWallet.test.ts b/packages/fuels/src/cli/commands/deploy/createWallet.test.ts index c7650bb83b..4722fa53f9 100644 --- a/packages/fuels/src/cli/commands/deploy/createWallet.test.ts +++ b/packages/fuels/src/cli/commands/deploy/createWallet.test.ts @@ -3,6 +3,9 @@ import { FUEL_NETWORK_URL } from '@fuel-ts/wallet/configs'; import { createWallet } from './createWallet'; +/** + * @group node + */ describe('createWallet', () => { const privateKey = '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298'; diff --git a/packages/fuels/src/cli/commands/deploy/getDeployConfig.test.ts b/packages/fuels/src/cli/commands/deploy/getDeployConfig.test.ts index c2e674b095..35d6407d78 100644 --- a/packages/fuels/src/cli/commands/deploy/getDeployConfig.test.ts +++ b/packages/fuels/src/cli/commands/deploy/getDeployConfig.test.ts @@ -1,5 +1,8 @@ import { getDeployConfig } from './getDeployConfig'; +/** + * @group node + */ describe('getDeployConfig', () => { test('deploy options as object', async () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts new file mode 100644 index 0000000000..35cbbf508d --- /dev/null +++ b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.test.ts @@ -0,0 +1,107 @@ +import * as testUtilsMod from '@fuel-ts/wallet/test-utils'; +import { existsSync, rmSync } from 'fs'; +import { join } from 'path'; + +import { fuelsConfig } from '../../../../test/fixtures/fuels.config'; +import type { FuelsConfig } from '../../types'; + +import type { FuelCoreNode } from './autoStartFuelCore'; +import { autoStartFuelCore } from './autoStartFuelCore'; + +vi.mock('@fuel-ts/wallet/test-utils', async () => { + const mod = await vi.importActual('@fuel-ts/wallet/test-utils'); + return { + __esModule: true, + ...mod, + }; +}); + +/** + * @group node + */ +describe('autoStartFuelCore', () => { + afterEach(() => { + vi.restoreAllMocks(); + + const chainConfig = join(fuelsConfig.basePath, '.fuels', 'chainConfig.json'); + if (existsSync(chainConfig)) { + rmSync(chainConfig); + } + }); + + function mockLaunchNode() { + const launchNode = vi.spyOn(testUtilsMod, 'launchNode').mockReturnValue( + Promise.resolve({ + cleanup: () => {}, + ip: '0.0.0.0', + port: '4000', + chainConfigPath: '/some/path/chainConfig.json', + }) + ); + return { launchNode }; + } + + test('should auto start `fuel-core`', async () => { + const { launchNode } = mockLaunchNode(); + + const config = structuredClone(fuelsConfig); + config.autoStartFuelCore = true; + + await autoStartFuelCore(config); + + expect(launchNode).toHaveBeenCalledTimes(1); + }); + + test('should not start `fuel-core`', async () => { + const { launchNode } = mockLaunchNode(); + + const config = structuredClone(fuelsConfig); + config.autoStartFuelCore = false; + + await autoStartFuelCore(config); + + expect(launchNode).toHaveBeenCalledTimes(0); + }); + + test('should start `fuel-core` node using built-in binary', async () => { + const { launchNode } = mockLaunchNode(); + + const copyConfig: FuelsConfig = structuredClone(fuelsConfig); + copyConfig.useBuiltinFuelCore = true; + + // this will cause it to autofind a free port + copyConfig.fuelCorePort = undefined; + delete copyConfig.fuelCorePort; + + const core = (await autoStartFuelCore(copyConfig)) as FuelCoreNode; + + expect(launchNode).toHaveBeenCalledTimes(1); + + expect(core.bindIp).toEqual('0.0.0.0'); + expect(core.accessIp).toEqual('127.0.0.1'); + expect(core.port).toBeGreaterThanOrEqual(4000); + expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/graphql/); + expect(core.killChildProcess).toBeTruthy(); + + core.killChildProcess(); + }); + + test('should start `fuel-core` node using system binary', async () => { + const { launchNode } = mockLaunchNode(); + + const core = (await autoStartFuelCore({ + ...structuredClone(fuelsConfig), + useBuiltinFuelCore: false, + })) as FuelCoreNode; + + expect(launchNode).toHaveBeenCalledTimes(1); + + expect(core.bindIp).toEqual('0.0.0.0'); + expect(core.accessIp).toEqual('127.0.0.1'); + expect(core.port).toBeGreaterThanOrEqual(4000); + expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/graphql/); + expect(core.killChildProcess).toBeTruthy(); + + core.killChildProcess(); + }); +}); diff --git a/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts new file mode 100644 index 0000000000..9958ca5660 --- /dev/null +++ b/packages/fuels/src/cli/commands/dev/autoStartFuelCore.ts @@ -0,0 +1,69 @@ +import { defaultConsensusKey } from '@fuel-ts/utils'; +import { launchNode } from '@fuel-ts/wallet/test-utils'; +import type { ChildProcessWithoutNullStreams } from 'child_process'; +import { getPortPromise } from 'portfinder'; + +import type { FuelsConfig } from '../../types'; +import { getBinarySource } from '../../utils/getBinarySource'; +import { log, loggingConfig } from '../../utils/logger'; + +export type FuelCoreNode = { + bindIp: string; + accessIp: string; + port: number; + providerUrl: string; + chainConfigPath: string; + killChildProcess: () => void; +}; + +export type KillNodeParams = { + core: ChildProcessWithoutNullStreams; + killFn: (pid: number) => void; + state: { + isDead: boolean; + }; +}; + +export const autoStartFuelCore = async (config: FuelsConfig) => { + let fuelCore: FuelCoreNode | undefined; + + if (config.autoStartFuelCore) { + log(`Starting ${getBinarySource(config.useBuiltinFuelCore)} 'fuel-core' node..`); + + const bindIp = '0.0.0.0'; + const accessIp = '127.0.0.1'; + + const port = config.fuelCorePort ?? (await getPortPromise({ port: 4000 })); + + const providerUrl = `http://${accessIp}:${port}/graphql`; + + const { cleanup, chainConfigPath } = await launchNode({ + args: [ + ['--chain', config.chainConfig], + ['--db-type', 'rocks-db'], + ].flat() as string[], + ip: bindIp, + port: port.toString(), + loggingEnabled: loggingConfig.isLoggingEnabled, + debugEnabled: loggingConfig.isDebugEnabled, + basePath: config.basePath, + useSystemFuelCore: !config.useBuiltinFuelCore, + }); + + fuelCore = { + bindIp, + accessIp, + port, + providerUrl, + chainConfigPath, + killChildProcess: cleanup, + }; + + // eslint-disable-next-line no-param-reassign + config.providerUrl = fuelCore.providerUrl; + // eslint-disable-next-line no-param-reassign + config.privateKey = defaultConsensusKey; + } + + return fuelCore; +}; diff --git a/packages/fuels/src/cli/commands/dev/defaultChainConfig.ts b/packages/fuels/src/cli/commands/dev/defaultChainConfig.ts deleted file mode 100644 index 80f4eb9de6..0000000000 --- a/packages/fuels/src/cli/commands/dev/defaultChainConfig.ts +++ /dev/null @@ -1,522 +0,0 @@ -/** - * This is the `privateKey` of the `consensus.PoA.signing_key` below. - * This key is responsible for validating the transactions. - */ -export const defaultConsensusKey = - '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298'; - -export const defaultChainConfig = { - chain_name: 'local_testnet', - block_gas_limit: 5000000000, - initial_state: { - coins: [ - { - owner: '0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - ], - messages: [ - { - sender: '0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f', - recipient: '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba', - nonce: '0101010101010101010101010101010101010101010101010101010101010101', - amount: '0x000000000000FFFF', - data: '', - da_height: '0x00', - }, - { - sender: '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba', - recipient: '0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f', - nonce: '0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b', - amount: '0xb04f3c08f59b309e', - data: '', - da_height: '0x00', - }, - ], - }, - consensus_parameters: { - tx_params: { - max_inputs: 255, - max_outputs: 255, - max_witnesses: 255, - max_gas_per_tx: 10000000, - max_size: 17825792, - }, - predicate_params: { - max_predicate_length: 1048576, - max_predicate_data_length: 1048576, - max_gas_per_predicate: 10000000, - max_message_data_length: 1048576, - }, - script_params: { - max_script_length: 1048576, - max_script_data_length: 1048576, - }, - contract_params: { - contract_max_size: 16777216, - max_storage_slots: 255, - }, - fee_params: { - gas_price_factor: 92, - gas_per_byte: 4, - }, - }, - gas_costs: { - add: 1, - addi: 1, - aloc: 1, - and: 1, - andi: 1, - bal: 13, - bhei: 1, - bhsh: 1, - burn: 132, - cb: 1, - cfei: 1, - cfsi: 1, - croo: 16, - div: 1, - divi: 1, - ecr1: 3000, - eck1: 951, - ed19: 3000, - eq: 1, - exp: 1, - expi: 1, - flag: 1, - gm: 1, - gt: 1, - gtf: 1, - ji: 1, - jmp: 1, - jne: 1, - jnei: 1, - jnzi: 1, - jmpf: 1, - jmpb: 1, - jnzf: 1, - jnzb: 1, - jnef: 1, - jneb: 1, - lb: 1, - log: 9, - lt: 1, - lw: 1, - mint: 135, - mlog: 1, - modOp: 1, - modi: 1, - moveOp: 1, - movi: 1, - mroo: 2, - mul: 1, - muli: 1, - mldv: 1, - noop: 1, - not: 1, - or: 1, - ori: 1, - poph: 2, - popl: 2, - pshh: 2, - pshl: 2, - ret: 13, - rvrt: 13, - sb: 1, - sll: 1, - slli: 1, - srl: 1, - srli: 1, - srw: 12, - sub: 1, - subi: 1, - sw: 1, - sww: 67, - time: 1, - tr: 105, - tro: 60, - wdcm: 1, - wqcm: 1, - wdop: 1, - wqop: 1, - wdml: 1, - wqml: 1, - wddv: 1, - wqdv: 2, - wdmd: 3, - wqmd: 4, - wdam: 2, - wqam: 3, - wdmm: 3, - wqmm: 3, - xor: 1, - xori: 1, - call: { - LightOperation: { - base: 144, - units_per_gas: 214, - }, - }, - ccp: { - LightOperation: { - base: 15, - units_per_gas: 103, - }, - }, - csiz: { - LightOperation: { - base: 17, - units_per_gas: 790, - }, - }, - k256: { - LightOperation: { - base: 11, - units_per_gas: 214, - }, - }, - ldc: { - LightOperation: { - base: 15, - units_per_gas: 272, - }, - }, - logd: { - LightOperation: { - base: 26, - units_per_gas: 64, - }, - }, - mcl: { - LightOperation: { - base: 1, - units_per_gas: 3333, - }, - }, - mcli: { - LightOperation: { - base: 1, - units_per_gas: 3333, - }, - }, - mcp: { - LightOperation: { - base: 1, - units_per_gas: 2000, - }, - }, - mcpi: { - LightOperation: { - base: 3, - units_per_gas: 2000, - }, - }, - meq: { - LightOperation: { - base: 1, - units_per_gas: 2500, - }, - }, - retd: { - LightOperation: { - base: 29, - units_per_gas: 62, - }, - }, - s256: { - LightOperation: { - base: 2, - units_per_gas: 214, - }, - }, - scwq: { - LightOperation: { - base: 13, - units_per_gas: 5, - }, - }, - smo: { - LightOperation: { - base: 209, - units_per_gas: 55, - }, - }, - srwq: { - LightOperation: { - base: 47, - units_per_gas: 5, - }, - }, - swwq: { - LightOperation: { - base: 44, - units_per_gas: 5, - }, - }, - contract_root: { - LightOperation: { - base: 75, - units_per_gas: 1, - }, - }, - state_root: { - LightOperation: { - base: 412, - units_per_gas: 1, - }, - }, - vm_initialization: { - HeavyOperation: { - base: 2000, - gas_per_unit: 0, - }, - }, - new_storage_per_byte: 1, - }, - consensus: { - PoA: { - signing_key: '0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d', - }, - }, -}; diff --git a/packages/fuels/src/cli/commands/dev/index.test.ts b/packages/fuels/src/cli/commands/dev/index.test.ts index 3c70994e84..48e18a0ae0 100644 --- a/packages/fuels/src/cli/commands/dev/index.test.ts +++ b/packages/fuels/src/cli/commands/dev/index.test.ts @@ -1,39 +1,52 @@ import { safeExec } from '@fuel-ts/errors/test-utils'; +import type { FSWatcher } from 'chokidar'; -import { fuelsConfig } from '../../../../test/fixtures/config/fuels.config'; +import { fuelsConfig } from '../../../../test/fixtures/fuels.config'; +import { mockStartFuelCore } from '../../../../test/utils/mockAutoStartFuelCore'; import { mockLogger } from '../../../../test/utils/mockLogger'; import * as loadConfigMod from '../../config/loadConfig'; import type { FuelsConfig } from '../../types'; +import * as buildMod from '../build'; +import * as deployMod from '../deploy'; import * as withConfigMod from '../withConfig'; -import * as indexMod from '.'; -import type { FuelCoreNode } from './startFuelCore'; - +// import * as indexMod from './index'; +import { + closeAllFileHandlers, + configFileChanged, + dev, + getConfigFilepathsToWatch, + workspaceFileChanged, +} from '.'; + +/** + * @group node + */ describe('dev', () => { - beforeEach(jest.restoreAllMocks); + beforeEach(() => { + vi.restoreAllMocks(); + }); function mockAll() { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const killChildProcess: any = jest.fn(); - const closeAllFileHandlers = jest.spyOn(indexMod, 'closeAllFileHandlers').mockImplementation(); - const fuelCore = { killChildProcess } as FuelCoreNode; - const onFailure = jest.fn(); + const { autoStartFuelCore, fuelCore, killChildProcess } = mockStartFuelCore(); + + const onFailure = vi.fn(); - const withConfigErrorHandler = jest + const withConfigErrorHandler = vi .spyOn(withConfigMod, 'withConfigErrorHandler') - .mockImplementation(); + .mockReturnValue(Promise.resolve()); - const loadConfig = jest + const loadConfig = vi .spyOn(loadConfigMod, 'loadConfig') .mockReturnValue(Promise.resolve(fuelsConfig)); - const dev = jest.spyOn(indexMod, 'dev').mockImplementation(() => { - throw new Error('The sky became purple'); - }); + const build = vi.spyOn(buildMod, 'build').mockResolvedValue(); + const deploy = vi.spyOn(deployMod, 'deploy').mockResolvedValue([]); return { - closeAllFileHandlers, - dev, + autoStartFuelCore, + build, + deploy, fuelCore, killChildProcess, loadConfig, @@ -42,31 +55,28 @@ describe('dev', () => { }; } - const { workspaceFileChanged } = indexMod; - test('workspaceFileChanged should log change and call `buildAndDeploy`', async () => { const { log } = mockLogger(); - - const buildAndDeploy = jest.spyOn(indexMod, 'buildAndDeploy').mockImplementation(); + const { build, deploy } = mockAll(); await workspaceFileChanged({ config: fuelsConfig, watchHandlers: [] })('event', 'some/path'); expect(log).toHaveBeenCalledTimes(1); - expect(buildAndDeploy).toHaveBeenCalledTimes(1); + expect(build).toHaveBeenCalledTimes(1); + expect(deploy).toHaveBeenCalledTimes(1); }); - test('dev should handle and log error from `buildAndDeploy`', async () => { - const err = new Error('something happened'); - + it('dev should handle and log error from `buildAndDeploy`', async () => { const { error } = mockLogger(); - jest.spyOn(indexMod, 'buildAndDeploy').mockImplementation(() => { + const err = new Error('something happened'); + vi.spyOn(buildMod, 'build').mockImplementation(() => { throw err; }); const configCopy: FuelsConfig = { ...fuelsConfig, autoStartFuelCore: false }; - const { result, error: safeError } = await safeExec(() => indexMod.dev(configCopy)); + const { result, error: safeError } = await safeExec(() => dev(configCopy)); expect(result).not.toBeTruthy(); expect(safeError).toEqual(err); @@ -76,35 +86,52 @@ describe('dev', () => { }); test('should call `close` on all file handlers', () => { - const close = jest.fn(); + const close = vi.fn(); // eslint-disable-next-line @typescript-eslint/no-explicit-any const handlers: any = [{ close }, { close }, { close }]; - indexMod.closeAllFileHandlers(handlers); + closeAllFileHandlers(handlers); expect(close).toHaveBeenCalledTimes(3); }); test('should restart everything when config file changes', async () => { - const { closeAllFileHandlers, dev, fuelCore, killChildProcess, loadConfig } = mockAll(); const { log } = mockLogger(); + const { + autoStartFuelCore, + build, + deploy, + fuelCore, + killChildProcess, + loadConfig, + withConfigErrorHandler, + } = mockAll(); const config = structuredClone(fuelsConfig); + const close = vi.fn(); + const watchHandlers = [{ close }, { close }] as unknown as FSWatcher[]; - await indexMod.configFileChanged({ config, fuelCore, watchHandlers: [] })('event', 'some/path'); + await configFileChanged({ config, fuelCore, watchHandlers })('event', 'some/path'); - expect(closeAllFileHandlers).toHaveBeenCalledTimes(1); - expect(killChildProcess).toHaveBeenCalledTimes(1); - expect(dev).toHaveBeenCalledTimes(1); + // configFileChanged() internals expect(log).toHaveBeenCalledTimes(1); + expect(close).toHaveBeenCalledTimes(2); + expect(killChildProcess).toHaveBeenCalledTimes(1); expect(loadConfig).toHaveBeenCalledTimes(1); + + // dev() internals + expect(autoStartFuelCore).toHaveBeenCalledTimes(1); + expect(build).toHaveBeenCalledTimes(1); + expect(deploy).toHaveBeenCalledTimes(1); + expect(withConfigErrorHandler).toHaveBeenCalledTimes(0); // never error }); test('should restart everything and handle errors', async () => { + const { log } = mockLogger(); const { - closeAllFileHandlers, - dev, + autoStartFuelCore, + deploy, fuelCore, killChildProcess, loadConfig, @@ -112,20 +139,27 @@ describe('dev', () => { withConfigErrorHandler, } = mockAll(); - const { log } = mockLogger(); + const err = new Error('something happened'); + const build = vi.spyOn(buildMod, 'build').mockImplementation(() => { + throw err; + }); const config = { onFailure, ...structuredClone(fuelsConfig) }; + const close = vi.fn(); + const watchHandlers = [{ close }, { close }] as unknown as FSWatcher[]; - await indexMod.configFileChanged({ config, fuelCore, watchHandlers: [] })('event', 'some/path'); + await configFileChanged({ config, fuelCore, watchHandlers })('event', 'some/path'); + // configFileChanged() internals expect(log).toHaveBeenCalledTimes(1); - - expect(closeAllFileHandlers).toHaveBeenCalledTimes(1); + expect(close).toHaveBeenCalledTimes(2); expect(killChildProcess).toHaveBeenCalledTimes(1); - expect(loadConfig).toHaveBeenCalledTimes(1); - expect(dev).toHaveBeenCalledTimes(1); + // dev() internals + expect(autoStartFuelCore).toHaveBeenCalledTimes(1); + expect(build).toHaveBeenCalledTimes(1); + expect(deploy).toHaveBeenCalledTimes(0); // never deploy expect(withConfigErrorHandler).toHaveBeenCalledTimes(1); }); @@ -133,9 +167,9 @@ describe('dev', () => { const config = structuredClone(fuelsConfig); config.chainConfig = undefined; - expect(indexMod.getConfigFilepathsToWatch(config)).toHaveLength(1); + expect(getConfigFilepathsToWatch(config)).toHaveLength(1); config.chainConfig = '/some/path/to/chainConfig.json'; - expect(indexMod.getConfigFilepathsToWatch(config)).toHaveLength(2); + expect(getConfigFilepathsToWatch(config)).toHaveLength(2); }); }); diff --git a/packages/fuels/src/cli/commands/dev/index.ts b/packages/fuels/src/cli/commands/dev/index.ts index b062b93d06..5481dfa04e 100644 --- a/packages/fuels/src/cli/commands/dev/index.ts +++ b/packages/fuels/src/cli/commands/dev/index.ts @@ -9,8 +9,8 @@ import { build } from '../build'; import { deploy } from '../deploy'; import { withConfigErrorHandler } from '../withConfig'; -import type { FuelCoreNode } from './startFuelCore'; -import { autoStartFuelCore } from './startFuelCore'; +import type { FuelCoreNode } from './autoStartFuelCore'; +import { autoStartFuelCore } from './autoStartFuelCore'; export const closeAllFileHandlers = (handlers: FSWatcher[]) => { handlers.forEach((h) => h.close()); diff --git a/packages/fuels/src/cli/commands/dev/startFuelCore.test.ts b/packages/fuels/src/cli/commands/dev/startFuelCore.test.ts deleted file mode 100644 index c1188213cd..0000000000 --- a/packages/fuels/src/cli/commands/dev/startFuelCore.test.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { safeExec } from '@fuel-ts/errors/test-utils'; -import * as childProcessMod from 'child_process'; - -import { fuelsConfig } from '../../../../test/fixtures/config/fuels.config'; -import { mockLogger } from '../../../../test/utils/mockLogger'; -import { resetDiskAndMocks } from '../../../../test/utils/resetDiskAndMocks'; -import type { FuelsConfig } from '../../types'; -import { configureLogging, loggingConfig } from '../../utils/logger'; - -import { killNode, startFuelCore } from './startFuelCore'; - -type ChildProcessWithoutNullStreams = childProcessMod.ChildProcessWithoutNullStreams; - -jest.mock('child_process', () => ({ - __esModule: true, - ...jest.requireActual('child_process'), -})); - -describe('startFuelCore', () => { - const loggingConfigBkp = loggingConfig; - - afterEach(() => { - configureLogging(loggingConfigBkp); - resetDiskAndMocks(); - }); - - /** - * This should mimic the stderr.on('data') event, returning both - * success and error messages, as strings. These messages are like - * the ones from `fuel-core` startup log messages. We filter them - * to know fuel-core state. - */ - function mockSpawn(params: { shouldError: boolean } = { shouldError: false }) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const stderrOn = (eventName: string, fn: (data: any) => void) => { - if (eventName === 'data') { - if (params.shouldError) { - // The `IO error` message simulates a possible fuel-core error log message - fn('IO error'); - } else { - // The `Binding GraphQL provider to` message simulates a fuel-core - // successful startup log message, usually meaning that the node - // is up and waiting for connections - fn('Binding GraphQL provider to'); - } - } - }; - - const innerMocks = { - on: jest.fn(), - stderr: { - pipe: jest.fn(), - on: jest.fn(stderrOn), - }, - stdout: { - pipe: jest.fn(), - }, - }; - - const spawn = jest - .spyOn(childProcessMod, 'spawn') - .mockImplementation((..._) => innerMocks as unknown as ChildProcessWithoutNullStreams); - - return { spawn, innerMocks }; - } - - test('should start `fuel-core` node using built-in binary', async () => { - mockSpawn(); - mockLogger(); - - const copyConfig: FuelsConfig = structuredClone(fuelsConfig); - copyConfig.useBuiltinFuelCore = true; - - // this will cause it to autofind a free port - copyConfig.fuelCorePort = undefined; - delete copyConfig.fuelCorePort; - - const core = await startFuelCore(copyConfig); - - expect(core.bindIp).toEqual('0.0.0.0'); - expect(core.accessIp).toEqual('127.0.0.1'); - expect(core.port).toBeGreaterThanOrEqual(4000); - expect(core.providerUrl).toMatch(/http:\/\/127\.0\.0\.1:([0-9]+)\/graphql/); - expect(core.killChildProcess).toBeTruthy(); - - core.killChildProcess(); - }); - - test('should start `fuel-core` node using system binary', async () => { - mockLogger(); - - const { spawn, innerMocks } = mockSpawn(); - - await startFuelCore({ - ...structuredClone(fuelsConfig), - useBuiltinFuelCore: false, - }); - - expect(spawn).toHaveBeenCalledTimes(1); - expect(spawn.mock.calls[0][0]).toMatch(/^fuel-core$/m); - - expect(innerMocks.on).toHaveBeenCalledTimes(1); - expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(0); - }); - - test('should throw on error', async () => { - const { innerMocks } = mockSpawn({ shouldError: true }); - const { error } = mockLogger(); - - const { error: safeError, result } = await safeExec(async () => startFuelCore(fuelsConfig)); - - expect(safeError).toBeTruthy(); - expect(result).not.toBeTruthy(); - - expect(error).toHaveBeenCalledTimes(1); - - expect(innerMocks.on).toHaveBeenCalledTimes(1); - expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(0); - }); - - test('should pipe stdout', async () => { - mockLogger(); - - jest.spyOn(process.stdout, 'write').mockImplementation(); - - configureLogging({ isDebugEnabled: false, isLoggingEnabled: true }); - - const { innerMocks } = mockSpawn(); - - await startFuelCore(fuelsConfig); - - expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(0); - }); - - test('should pipe stdout and stderr', async () => { - mockLogger(); - - jest.spyOn(process.stderr, 'write').mockImplementation(); - jest.spyOn(process.stdout, 'write').mockImplementation(); - - configureLogging({ isDebugEnabled: true, isLoggingEnabled: true }); - - const { innerMocks } = mockSpawn(); - - await startFuelCore(fuelsConfig); - - expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); - expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(1); - }); - - test('should kill process only if PID exists and node is alive', () => { - const killFn = jest.fn(); - const state = { isDead: true }; - - // should not kill - let core = { pid: undefined } as ChildProcessWithoutNullStreams; - killNode({ core, killFn, state })(); - expect(killFn).toHaveBeenCalledTimes(0); - expect(state.isDead).toEqual(true); - - // should not kill - core = { pid: 1 } as ChildProcessWithoutNullStreams; - killNode({ core, killFn, state })(); - expect(killFn).toHaveBeenCalledTimes(0); - expect(state.isDead).toEqual(true); - - // should kill - state.isDead = false; - killNode({ core, killFn, state })(); - expect(killFn).toHaveBeenCalledTimes(1); - expect(state.isDead).toEqual(true); - }); -}); diff --git a/packages/fuels/src/cli/commands/dev/startFuelCore.ts b/packages/fuels/src/cli/commands/dev/startFuelCore.ts deleted file mode 100644 index ac12446876..0000000000 --- a/packages/fuels/src/cli/commands/dev/startFuelCore.ts +++ /dev/null @@ -1,130 +0,0 @@ -import type { ChildProcessWithoutNullStreams } from 'child_process'; -import { spawn } from 'child_process'; -import { mkdirSync, writeFileSync } from 'fs'; -import { dirname, join } from 'path'; -import { getPortPromise } from 'portfinder'; -import treeKill from 'tree-kill'; - -import type { FuelsConfig } from '../../types'; -import { findBinPath } from '../../utils/findBinPath'; -import { getBinarySource } from '../../utils/getBinarySource'; -import { error, log, loggingConfig } from '../../utils/logger'; - -import { defaultChainConfig, defaultConsensusKey } from './defaultChainConfig'; - -export type FuelCoreNode = { - bindIp: string; - accessIp: string; - port: number; - providerUrl: string; - chainConfig: string; - killChildProcess: () => void; -}; - -export type KillNodeParams = { - core: ChildProcessWithoutNullStreams; - killFn: (pid: number) => void; - state: { - isDead: boolean; - }; -}; - -export const killNode = (params: KillNodeParams) => () => { - const { core, state, killFn } = params; - if (core.pid && !state.isDead) { - state.isDead = true; - killFn(Number(core.pid)); - } -}; - -export const createTempChainConfig = (coreDir: string) => { - const chainConfigPath = join(coreDir, 'chainConfig.json'); - const chainConfigJson = JSON.stringify(defaultChainConfig, null, 2); - mkdirSync(dirname(chainConfigPath), { recursive: true }); - writeFileSync(chainConfigPath, chainConfigJson); - return chainConfigPath; -}; - -export const startFuelCore = async (config: FuelsConfig): Promise => { - log(`Starting ${getBinarySource(config.useBuiltinFuelCore)} 'fuel-core' node..`); - - const coreDir = join(config.basePath, '.fuels'); - - const bindIp = '0.0.0.0'; - const accessIp = '127.0.0.1'; - - const chainConfig = config.chainConfig ?? createTempChainConfig(coreDir); - const port = config.fuelCorePort ?? (await getPortPromise({ port: 4000 })); - - const providerUrl = `http://${accessIp}:${port}/graphql`; - - const flags = [ - 'run', - ['--ip', bindIp], - ['--port', port.toString()], - ['--db-path', coreDir], - ['--min-gas-price', '0'], - ['--poa-instant', 'true'], - ['--consensus-key', defaultConsensusKey], - ['--chain', chainConfig], - '--vm-backtrace', - '--utxo-validation', - '--debug', - ].flat(); - - return new Promise((resolve, reject) => { - const builtInFuelsCorePath = findBinPath('fuels-core'); - - const command = config.useBuiltinFuelCore ? builtInFuelsCorePath : 'fuel-core'; - const core = spawn(command, flags, { stdio: 'pipe' }); - - if (loggingConfig.isLoggingEnabled) { - core.stderr.pipe(process.stderr); - } - - if (loggingConfig.isDebugEnabled) { - core.stdout.pipe(process.stdout); - } - - const state = { isDead: false }; - const killChildProcess = killNode({ core, state, killFn: treeKill }); - - process.on('beforeExit', killChildProcess); - process.on('uncaughtException', killChildProcess); - - core.stderr?.on('data', (data) => { - if (/Binding GraphQL provider to/.test(data)) { - resolve({ - bindIp, - accessIp, - port, - providerUrl, - killChildProcess, - chainConfig, - }); - } - if (/error/i.test(data)) { - error( - `Some error occurred. Please, check to see if you have another instance running locally.` - ); - reject(data.toString()); - } - }); - - core.on('error', reject); - }); -}; - -export const autoStartFuelCore = async (config: FuelsConfig) => { - let fuelCore: FuelCoreNode | undefined; - - if (config.autoStartFuelCore) { - fuelCore = await startFuelCore(config); - // eslint-disable-next-line no-param-reassign - config.providerUrl = fuelCore.providerUrl; - // eslint-disable-next-line no-param-reassign - config.privateKey = defaultConsensusKey; - } - - return fuelCore; -}; diff --git a/packages/fuels/src/cli/commands/init/index.ts b/packages/fuels/src/cli/commands/init/index.ts index 33fbb6a502..934f4c1391 100644 --- a/packages/fuels/src/cli/commands/init/index.ts +++ b/packages/fuels/src/cli/commands/init/index.ts @@ -40,26 +40,26 @@ export function init(program: Command) { // mimicking commander property validation process.stdout.write(`error: required option '-w, --workspace ' not specified\r`); process.exit(1); - } - - const fuelsConfigPath = join(path, 'fuels.config.ts'); + } else { + const fuelsConfigPath = join(path, 'fuels.config.ts'); - if (existsSync(fuelsConfigPath)) { - throw new Error(`Config file exists, aborting.\n ${fuelsConfigPath}`); - } + if (existsSync(fuelsConfigPath)) { + throw new Error(`Config file exists, aborting.\n ${fuelsConfigPath}`); + } - const renderedConfig = renderFuelsConfigTemplate({ - workspace, - contracts, - scripts, - predicates, - output, - useBuiltinForc, - useBuiltinFuelCore, - autoStartFuelCore, - }); + const renderedConfig = renderFuelsConfigTemplate({ + workspace, + contracts, + scripts, + predicates, + output, + useBuiltinForc, + useBuiltinFuelCore, + autoStartFuelCore, + }); - writeFileSync(fuelsConfigPath, renderedConfig); + writeFileSync(fuelsConfigPath, renderedConfig); - log(`Config file created at:\n\n ${fuelsConfigPath}\n`); + log(`Config file created at:\n\n ${fuelsConfigPath}\n`); + } } diff --git a/packages/fuels/src/cli/commands/init/shouldUseBuiltinForc.test.ts b/packages/fuels/src/cli/commands/init/shouldUseBuiltinForc.test.ts index 9efc9c8f17..560c559761 100644 --- a/packages/fuels/src/cli/commands/init/shouldUseBuiltinForc.test.ts +++ b/packages/fuels/src/cli/commands/init/shouldUseBuiltinForc.test.ts @@ -4,21 +4,32 @@ import { mockLogger } from '../../../../test/utils/mockLogger'; import { shouldUseBuiltinFuelCore } from './shouldUseBuiltinFuelCore'; -jest.mock('@fuel-ts/versions/cli', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/versions/cli'), -})); +vi.mock('@fuel-ts/versions/cli', async () => { + const mod = await vi.importActual('@fuel-ts/versions/cli'); + return { + __esModule: true, + ...mod, + }; +}); -jest.mock('prompts', () => ({ - __esModule: true, - ...jest.requireActual('prompts'), -})); +vi.mock('prompts', async () => { + const mod = await vi.importActual('prompts'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('shouldUseBuiltinFuelCore', () => { - beforeEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); function mockAll(returns: { getSystemFuelCore: string | null }) { - const getSystemFuelCore = jest + const getSystemFuelCore = vi .spyOn(getSystemFuelCoreMod, 'getSystemFuelCore') .mockReturnValue({ error: null, systemFuelCoreVersion: returns.getSystemFuelCore }); diff --git a/packages/fuels/src/cli/commands/init/shouldUseBuiltinFuelCore.test.ts b/packages/fuels/src/cli/commands/init/shouldUseBuiltinFuelCore.test.ts index 7449a4087a..04d44fe662 100644 --- a/packages/fuels/src/cli/commands/init/shouldUseBuiltinFuelCore.test.ts +++ b/packages/fuels/src/cli/commands/init/shouldUseBuiltinFuelCore.test.ts @@ -4,16 +4,24 @@ import { mockLogger } from '../../../../test/utils/mockLogger'; import { shouldUseBuiltinForc } from './shouldUseBuiltinForc'; -jest.mock('@fuel-ts/versions/cli', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/versions/cli'), -})); +vi.mock('@fuel-ts/versions/cli', async () => { + const mod = await vi.importActual('@fuel-ts/versions/cli'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('shouldUseBuiltinForc', () => { - beforeEach(jest.restoreAllMocks); + beforeEach(() => { + vi.restoreAllMocks(); + }); function mockAll(returns: { getSystemForc: string | null }) { - const getSystemForc = jest + const getSystemForc = vi .spyOn(getSystemForcMod, 'getSystemForc') .mockReturnValue({ error: null, systemForcVersion: returns.getSystemForc }); diff --git a/packages/fuels/src/cli/commands/withConfig.test.ts b/packages/fuels/src/cli/commands/withConfig.test.ts index 87e63a5de0..27f47028ac 100644 --- a/packages/fuels/src/cli/commands/withConfig.test.ts +++ b/packages/fuels/src/cli/commands/withConfig.test.ts @@ -1,21 +1,28 @@ import { program } from 'commander'; -import { fuelsConfig } from '../../../test/fixtures/config/fuels.config'; +import { fuelsConfig } from '../../../test/fixtures/fuels.config'; import { mockLogger } from '../../../test/utils/mockLogger'; -import { resetDiskAndMocks } from '../../../test/utils/resetDiskAndMocks'; import * as loadConfigMod from '../config/loadConfig'; import type { FuelsConfig } from '../types'; import { Commands } from '../types'; import { withConfig } from './withConfig'; +/** + * @group node + */ describe('withConfig', () => { - beforeEach(mockLogger); - afterEach(resetDiskAndMocks); + beforeEach(() => { + mockLogger(); + }); + + beforeEach(() => { + vi.restoreAllMocks(); + }); function mockAll(params?: { shouldErrorOnDeploy?: boolean; shouldErrorOnLoadConfig?: boolean }) { - const onSuccess = jest.fn(); - const onFailure = jest.fn(); + const onSuccess = vi.fn(); + const onFailure = vi.fn(); const copyConfig: FuelsConfig = { ...structuredClone(fuelsConfig), @@ -29,14 +36,14 @@ describe('withConfig', () => { .command(Commands.deploy) .option('-p, --path ', 'Path to project root', configPath); - const loadConfig = jest.spyOn(loadConfigMod, 'loadConfig').mockImplementation((..._) => { + const loadConfig = vi.spyOn(loadConfigMod, 'loadConfig').mockImplementation(() => { if (params?.shouldErrorOnLoadConfig) { throw new Error('Something happened'); } return Promise.resolve(copyConfig); }); - const deploy = jest.fn(() => { + const deploy = vi.fn(() => { if (params?.shouldErrorOnDeploy) { throw new Error('Something happened'); } diff --git a/packages/fuels/src/cli/config/forcUtils.test.ts b/packages/fuels/src/cli/config/forcUtils.test.ts index a35b8d0c5f..1cbc972d94 100644 --- a/packages/fuels/src/cli/config/forcUtils.test.ts +++ b/packages/fuels/src/cli/config/forcUtils.test.ts @@ -2,6 +2,9 @@ import { safeExec } from '@fuel-ts/errors/test-utils'; import { readForcToml } from './forcUtils'; +/** + * @group node + */ describe('forcUtils', () => { test('should throw if Toml file is not found', async () => { const tomlPath = '/non/existent/path'; diff --git a/packages/fuels/src/cli/config/loadConfig.test.ts b/packages/fuels/src/cli/config/loadConfig.test.ts index e7c358b25b..6fbc5dc3e7 100644 --- a/packages/fuels/src/cli/config/loadConfig.test.ts +++ b/packages/fuels/src/cli/config/loadConfig.test.ts @@ -1,14 +1,11 @@ import { safeExec } from '@fuel-ts/errors/test-utils'; import { readFileSync } from 'fs'; -import { resetDiskAndMocks } from '../../../test/utils/resetDiskAndMocks'; import { runInit, - fixturesDir, - fuelsConfigPath, - initFlagsUseBuiltinBinaries, - generatedDir, - initFlagsWorkspace, + bootstrapProject, + resetConfigAndMocks, + resetDiskAndMocks, } from '../../../test/utils/runCommands'; import * as shouldUseBuiltinForcMod from '../commands/init/shouldUseBuiltinForc'; import * as shouldUseBuiltinFuelCoreMod from '../commands/init/shouldUseBuiltinFuelCore'; @@ -16,8 +13,19 @@ import type { FuelsConfig } from '../types'; import { loadConfig } from './loadConfig'; +/** + * @group node + */ describe('loadConfig', () => { - beforeEach(resetDiskAndMocks); + const paths = bootstrapProject(__filename); + + afterEach(() => { + resetConfigAndMocks(paths.fuelsConfigPath); + }); + + afterAll(() => { + resetDiskAndMocks(paths.root); + }); test('should throw if config path is not found', async () => { const cwd = '/non/existent/path'; @@ -28,29 +36,31 @@ describe('loadConfig', () => { }); test(`should auto start fuel core explicitly`, async () => { - await runInit( - [initFlagsWorkspace, initFlagsUseBuiltinBinaries, '--auto-start-fuel-core'].flat() - ); - - const config = await loadConfig(fixturesDir); - const fuelsContents = readFileSync(fuelsConfigPath, 'utf-8'); - - expect(fuelsContents).toMatch(` autoStartFuelCore: true,`); // not comment + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + useBuiltinBinaries: true, + autoStartFuelCore: true, + }); + + const fuelsContents = readFileSync(paths.fuelsConfigPath, 'utf-8'); + const config = await loadConfig(paths.root); + + expect(fuelsContents).toMatch(` autoStartFuelCore: true,`); // not a comment expect(config.autoStartFuelCore).toEqual(true); }); test(`should resolve individual paths when not using workspaces`, async () => { - await runInit( - [ - initFlagsUseBuiltinBinaries, - ['--contracts', 'project/contracts/*'], - ['--scripts', 'project/scripts/*'], - ['--predicates', 'project/predicates/*'], - ['-o', generatedDir], - ].flat() - ); - - const config = await loadConfig(fixturesDir); + await runInit({ + root: paths.root, + output: paths.outputDir, + contracts: 'workspace/contracts/*', + scripts: 'workspace/scripts/*', + predicates: 'workspace/predicates/*', + }); + + const config = await loadConfig(paths.root); expect(config.contracts.length).toEqual(2); expect(config.scripts.length).toEqual(1); @@ -58,15 +68,13 @@ describe('loadConfig', () => { }); test(`should resolve only contracts`, async () => { - await runInit( - [ - initFlagsUseBuiltinBinaries, - ['--contracts', 'project/contracts/*'], - ['-o', generatedDir], - ].flat() - ); + await runInit({ + root: paths.root, + output: paths.outputDir, + contracts: 'workspace/contracts/*', + }); - const config = await loadConfig(fixturesDir); + const config = await loadConfig(paths.root); expect(config.contracts.length).toEqual(2); expect(config.scripts.length).toEqual(0); @@ -74,11 +82,13 @@ describe('loadConfig', () => { }); test(`should resolve only scripts`, async () => { - await runInit( - [initFlagsUseBuiltinBinaries, ['--scripts', 'project/scripts/*'], ['-o', generatedDir]].flat() - ); + await runInit({ + root: paths.root, + output: paths.outputDir, + scripts: 'workspace/scripts/*', + }); - const config = await loadConfig(fixturesDir); + const config = await loadConfig(paths.root); expect(config.contracts.length).toEqual(0); expect(config.scripts.length).toEqual(1); @@ -86,15 +96,13 @@ describe('loadConfig', () => { }); test(`should resolve only predicates`, async () => { - await runInit( - [ - initFlagsUseBuiltinBinaries, - ['--predicates', 'project/predicates/*'], - ['-o', generatedDir], - ].flat() - ); + await runInit({ + root: paths.root, + output: paths.outputDir, + predicates: 'workspace/predicates/*', + }); - const config = await loadConfig(fixturesDir); + const config = await loadConfig(paths.root); expect(config.contracts.length).toEqual(0); expect(config.scripts.length).toEqual(0); @@ -102,16 +110,14 @@ describe('loadConfig', () => { }); test(`should warn about misconfigured workspace`, async () => { - await runInit( - [ - initFlagsUseBuiltinBinaries, - // passing contract path in workspace config option - ['--workspace', 'project/contracts/bar'], - ['--output', generatedDir], - ].flat() - ); + await runInit({ + root: paths.root, + output: paths.outputDir, + // passing contract path in workspace config option + workspace: 'workspace/contracts/bar', + }); - const { error, result } = await safeExec>(() => loadConfig(fixturesDir)); + const { error, result } = await safeExec>(() => loadConfig(paths.root)); expect(result).not.toBeTruthy(); expect(error?.message).toMatch(/forc workspace not detected/i); @@ -119,17 +125,21 @@ describe('loadConfig', () => { }); test(`should smart-set built-in flags`, async () => { - await runInit(initFlagsWorkspace); + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); - const shouldUseBuiltinForc = jest + const shouldUseBuiltinForc = vi .spyOn(shouldUseBuiltinForcMod, 'shouldUseBuiltinForc') .mockReturnValue(false); - const shouldUseBuiltinFuelCore = jest + const shouldUseBuiltinFuelCore = vi .spyOn(shouldUseBuiltinFuelCoreMod, 'shouldUseBuiltinFuelCore') .mockReturnValue(true); - const config = await loadConfig(fixturesDir); + const config = await loadConfig(paths.root); expect(config.useBuiltinForc).toEqual(false); expect(config.useBuiltinFuelCore).toEqual(true); diff --git a/packages/fuels/src/cli/config/loadConfig.ts b/packages/fuels/src/cli/config/loadConfig.ts index d70aa1345b..8715392504 100644 --- a/packages/fuels/src/cli/config/loadConfig.ts +++ b/packages/fuels/src/cli/config/loadConfig.ts @@ -1,10 +1,10 @@ +import { defaultConsensusKey } from '@fuel-ts/utils'; import { FUEL_NETWORK_URL } from '@fuel-ts/wallet/configs'; import { bundleRequire } from 'bundle-require'; import type { BuildOptions } from 'esbuild'; import JoyCon from 'joycon'; import { resolve, parse } from 'path'; -import { defaultConsensusKey } from '../commands/dev/defaultChainConfig'; import { shouldUseBuiltinForc } from '../commands/init/shouldUseBuiltinForc'; import { shouldUseBuiltinFuelCore } from '../commands/init/shouldUseBuiltinFuelCore'; import type { FuelsConfig, UserFuelsConfig } from '../types'; diff --git a/packages/fuels/src/cli/index.test.ts b/packages/fuels/src/cli/index.test.ts index dc6385cca4..ccf317bc55 100644 --- a/packages/fuels/src/cli/index.test.ts +++ b/packages/fuels/src/cli/index.test.ts @@ -1,4 +1,4 @@ -import { fuelsConfig } from '../../test/fixtures/config/fuels.config'; +import { fuelsConfig } from '../../test/fixtures/fuels.config'; import type { CommandEvent, @@ -11,6 +11,9 @@ import type { } from './index'; import { createConfig } from './index'; +/** + * @group node + */ describe('cli/index.ts', () => { test('should create config via cli index', () => { expect(createConfig(fuelsConfig)).toEqual(fuelsConfig); diff --git a/packages/fuels/src/cli/utils/findBinPath.ts b/packages/fuels/src/cli/utils/findBinPath.ts deleted file mode 100644 index e950e34e5f..0000000000 --- a/packages/fuels/src/cli/utils/findBinPath.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { existsSync } from 'fs'; -import { join } from 'path'; - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const npmWhich = require('npm-which')(__dirname); - -export function findBinPath(binCommandName: string) { - let binPath = npmWhich.sync(binCommandName); - - if (!existsSync(binPath)) { - // The user might be using bun, which has a different structure for binaries inside node_modules - binPath = join('node_modules', '.bin', binCommandName); - } - - return binPath; -} diff --git a/packages/fuels/src/cli/utils/logger.test.ts b/packages/fuels/src/cli/utils/logger.test.ts index 35553d587b..e38ae184f9 100644 --- a/packages/fuels/src/cli/utils/logger.test.ts +++ b/packages/fuels/src/cli/utils/logger.test.ts @@ -2,6 +2,9 @@ import { resetDiskAndMocks } from '../../../test/utils/resetDiskAndMocks'; import * as loggerMod from './logger'; +/** + * @group node + */ describe('logger', () => { const { configureLogging, loggingConfig } = loggerMod; @@ -16,8 +19,8 @@ describe('logger', () => { afterAll(reset); function mockStdIO() { - const err = jest.spyOn(process.stderr, 'write').mockImplementation(); - const out = jest.spyOn(process.stdout, 'write').mockImplementation(); + const err = vi.spyOn(process.stderr, 'write').mockReturnValue(true); + const out = vi.spyOn(process.stdout, 'write').mockReturnValue(true); return { err, out }; } diff --git a/packages/fuels/src/index.test.ts b/packages/fuels/src/index.test.ts index 3847f6ca3d..ecde17b927 100644 --- a/packages/fuels/src/index.test.ts +++ b/packages/fuels/src/index.test.ts @@ -1,5 +1,8 @@ import * as fuels from './index'; +/** + * @group node + */ describe('index.js', () => { test('should export everything', () => { expect(fuels.hexlify).toBeTruthy(); diff --git a/packages/fuels/src/run.ts b/packages/fuels/src/run.ts new file mode 100644 index 0000000000..e6bf972037 --- /dev/null +++ b/packages/fuels/src/run.ts @@ -0,0 +1,6 @@ +import { configureCli } from './cli'; + +export const run = async (argv: string[]) => { + const program = configureCli(); + return program.parseAsync(argv); +}; diff --git a/packages/fuels/test/features/build.test.ts b/packages/fuels/test/features/build.test.ts index 5ba49d4ed2..1d45516959 100644 --- a/packages/fuels/test/features/build.test.ts +++ b/packages/fuels/test/features/build.test.ts @@ -2,85 +2,114 @@ import { existsSync } from 'fs'; import { join } from 'path'; import * as deployMod from '../../src/cli/commands/deploy/index'; -import { mockStartFuelCore } from '../utils/mockStartFuelCore'; -import { resetDiskAndMocks } from '../utils/resetDiskAndMocks'; +import { mockStartFuelCore } from '../utils/mockAutoStartFuelCore'; import { - buildFlagsDeploy, - contractsFooDir, - generatedDir, - initFlagsUseBuiltinBinaries, + bootstrapProject, + resetConfigAndMocks, + resetDiskAndMocks, runBuild, runInit, } from '../utils/runCommands'; -describe('build', () => { - beforeEach(resetDiskAndMocks); - afterEach(resetDiskAndMocks); - - function mockAll() { - const { startFuelCore, killChildProcess } = mockStartFuelCore(); - const deploy = jest.spyOn(deployMod, 'deploy').mockImplementation(); - - return { startFuelCore, killChildProcess, deploy }; - } - - it('should run `build` command', async () => { - const { startFuelCore, killChildProcess, deploy } = mockAll(); - - await runInit(); - await runBuild(); - - const files = [ - 'predicates/factories/PredicateTrueAbi__factory.ts', - 'predicates/index.ts', - 'contracts/BarFooAbi.d.ts', - 'contracts/BarFooAbi.hex.ts', - 'contracts/FooBarAbi.hex.ts', - 'contracts/FooBarAbi.d.ts', - 'contracts/factories/FooBarAbi__factory.ts', - 'contracts/factories/BarFooAbi__factory.ts', - 'contracts/index.ts', - 'scripts/factories/ScriptTrueAbi__factory.ts', - 'scripts/index.ts', - 'index.ts', - ].map((f) => join(__dirname, '..', 'fixtures', 'generated', f)); - - files.forEach((file) => expect(existsSync(file)).toBeTruthy()); - - expect(startFuelCore).toHaveBeenCalledTimes(0); - expect(deploy).toHaveBeenCalledTimes(0); - expect(killChildProcess).toHaveBeenCalledTimes(0); - }); - - it('should run `build` command with contracts-only', async () => { - const { startFuelCore, killChildProcess, deploy } = mockAll(); - - await runInit([initFlagsUseBuiltinBinaries, '-c', contractsFooDir, '-o', generatedDir].flat()); - await runBuild(); - - const files = [ - 'contracts/FooBarAbi.hex.ts', - 'contracts/FooBarAbi.d.ts', - 'contracts/factories/FooBarAbi__factory.ts', - 'contracts/index.ts', - 'index.ts', - ].map((f) => join(__dirname, '..', 'fixtures', 'generated', f)); - - files.forEach((file) => expect(existsSync(file)).toBeTruthy()); - - expect(startFuelCore).toHaveBeenCalledTimes(0); - expect(deploy).toHaveBeenCalledTimes(0); - expect(killChildProcess).toHaveBeenCalledTimes(0); - }); - - it('should run `build` command with `--deploy` flag', async () => { - const { startFuelCore, killChildProcess, deploy } = mockAll(); - - await runInit(); - await runBuild([buildFlagsDeploy]); - - expect(startFuelCore).toHaveBeenCalledTimes(1); - expect(deploy).toHaveBeenCalledTimes(1); - expect(killChildProcess).toHaveBeenCalledTimes(1); - }); -}); +/** + * @group node + */ +describe( + 'build', + () => { + const paths = bootstrapProject(__filename); + + afterEach(() => { + resetConfigAndMocks(paths.fuelsConfigPath); + }); + + afterAll(() => { + resetDiskAndMocks(paths.root); + }); + + function mockAll() { + const { autoStartFuelCore, killChildProcess } = mockStartFuelCore(); + const deploy = vi.spyOn(deployMod, 'deploy').mockResolvedValue([]); + + return { autoStartFuelCore, killChildProcess, deploy }; + } + + it('should run `build` command', async () => { + const { autoStartFuelCore, killChildProcess, deploy } = mockAll(); + + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + + await runBuild({ root: paths.root }); + + const files = [ + 'predicates/factories/PredicateTrueAbi__factory.ts', + 'predicates/index.ts', + 'contracts/BarFooAbi.d.ts', + 'contracts/BarFooAbi.hex.ts', + 'contracts/FooBarAbi.hex.ts', + 'contracts/FooBarAbi.d.ts', + 'contracts/factories/FooBarAbi__factory.ts', + 'contracts/factories/BarFooAbi__factory.ts', + 'contracts/index.ts', + 'scripts/factories/ScriptTrueAbi__factory.ts', + 'scripts/index.ts', + 'index.ts', + ].map((f) => join(paths.outputDir, f)); + + files.forEach((file) => { + expect(existsSync(file)).toBeTruthy(); + }); + + expect(autoStartFuelCore).toHaveBeenCalledTimes(0); + expect(deploy).toHaveBeenCalledTimes(0); + expect(killChildProcess).toHaveBeenCalledTimes(0); + }); + + it('should run `build` command with contracts-only', async () => { + const { autoStartFuelCore, killChildProcess, deploy } = mockAll(); + + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + + await runBuild({ root: paths.root }); + + const files = [ + 'contracts/FooBarAbi.hex.ts', + 'contracts/FooBarAbi.d.ts', + 'contracts/factories/FooBarAbi__factory.ts', + 'contracts/index.ts', + 'index.ts', + ].map((f) => join(paths.outputDir, f)); + + files.forEach((file) => expect(existsSync(file)).toBeTruthy()); + + expect(autoStartFuelCore).toHaveBeenCalledTimes(0); + expect(deploy).toHaveBeenCalledTimes(0); + expect(killChildProcess).toHaveBeenCalledTimes(0); + }); + + it('should run `build` command with `--deploy` flag', async () => { + const { autoStartFuelCore, killChildProcess, deploy } = mockAll(); + + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + + await runBuild({ root: paths.root, deploy: true }); + + expect(autoStartFuelCore).toHaveBeenCalledTimes(1); + expect(deploy).toHaveBeenCalledTimes(1); + expect(killChildProcess).toHaveBeenCalledTimes(1); + }); + }, + { timeout: 10000 } +); diff --git a/packages/fuels/test/features/deploy.test.ts b/packages/fuels/test/features/deploy.test.ts index aa739e99f3..4d4bc74af8 100644 --- a/packages/fuels/test/features/deploy.test.ts +++ b/packages/fuels/test/features/deploy.test.ts @@ -1,21 +1,46 @@ import { existsSync, readFileSync } from 'fs'; import { resetDiskAndMocks } from '../utils/resetDiskAndMocks'; -import { contractsJsonPath, runBuild, runDeploy, runInit } from '../utils/runCommands'; +import { + bootstrapProject, + resetConfigAndMocks, + runBuild, + runDeploy, + runInit, +} from '../utils/runCommands'; -describe('deploy', () => { - beforeEach(resetDiskAndMocks); - afterEach(resetDiskAndMocks); +/** + * @group node + */ +describe( + 'deploy', + () => { + const paths = bootstrapProject(__filename); - it('should run `deploy` command', async () => { - await runInit(); - await runBuild(); - await runDeploy(); + afterEach(() => { + resetConfigAndMocks(paths.fuelsConfigPath); + }); - expect(existsSync(contractsJsonPath)).toBeTruthy(); + afterAll(() => { + resetDiskAndMocks(paths.root); + }); - const fuelsContents = JSON.parse(readFileSync(contractsJsonPath, 'utf-8')); - expect(fuelsContents.barFoo).toMatch(/0x/); - expect(fuelsContents.fooBar).toMatch(/0x/); - }); -}); + it('should run `deploy` command', async () => { + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + + await runBuild({ root: paths.root }); + await runDeploy({ root: paths.root }); + + expect(existsSync(paths.contractsJsonPath)).toBeTruthy(); + + const fuelsContents = JSON.parse(readFileSync(paths.contractsJsonPath, 'utf-8')); + expect(fuelsContents.barFoo).toMatch(/0x/); + expect(fuelsContents.fooBar).toMatch(/0x/); + }); + }, + { timeout: 15000 } +); diff --git a/packages/fuels/test/features/dev.test.ts b/packages/fuels/test/features/dev.test.ts index f2a14007fd..bb4daaa47a 100644 --- a/packages/fuels/test/features/dev.test.ts +++ b/packages/fuels/test/features/dev.test.ts @@ -2,43 +2,61 @@ import * as chokidar from 'chokidar'; import * as buildMod from '../../src/cli/commands/build/index'; import * as deployMod from '../../src/cli/commands/deploy/index'; +import { mockStartFuelCore } from '../utils/mockAutoStartFuelCore'; import { mockLogger } from '../utils/mockLogger'; -import { mockStartFuelCore } from '../utils/mockStartFuelCore'; import { resetDiskAndMocks } from '../utils/resetDiskAndMocks'; -import { runInit, runDev } from '../utils/runCommands'; +import { runInit, runDev, bootstrapProject, resetConfigAndMocks } from '../utils/runCommands'; -jest.mock('chokidar', () => ({ - __esModule: true, - ...jest.requireActual('chokidar'), -})); +vi.mock('chokidar', async () => { + const mod = await vi.importActual('chokidar'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('dev', () => { - beforeEach(mockLogger); - afterEach(resetDiskAndMocks); + const paths = bootstrapProject(__filename); + + afterEach(() => { + resetConfigAndMocks(paths.fuelsConfigPath); + }); + + afterAll(() => { + resetDiskAndMocks(paths.root); + }); function mockAll() { mockLogger(); - const { startFuelCore, killChildProcess } = mockStartFuelCore(); + const { autoStartFuelCore, killChildProcess } = mockStartFuelCore(); - const build = jest.spyOn(buildMod, 'build').mockImplementation(); - const deploy = jest.spyOn(deployMod, 'deploy').mockImplementation(); + const build = vi.spyOn(buildMod, 'build').mockReturnValue(Promise.resolve()); + const deploy = vi.spyOn(deployMod, 'deploy').mockReturnValue(Promise.resolve([])); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const on: any = jest.fn(() => ({ on })); + const on: any = vi.fn(() => ({ on })); // eslint-disable-next-line @typescript-eslint/no-explicit-any - const watch = jest.spyOn(chokidar, 'watch').mockReturnValue({ on } as any); + const watch = vi.spyOn(chokidar, 'watch').mockReturnValue({ on } as any); - return { startFuelCore, killChildProcess, build, deploy, on, watch }; + return { autoStartFuelCore, killChildProcess, build, deploy, on, watch }; } it('should run `dev` command', async () => { - const { startFuelCore, killChildProcess, build, deploy, on, watch } = mockAll(); + const { autoStartFuelCore, killChildProcess, build, deploy, on, watch } = mockAll(); + + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); - await runInit(); - await runDev(); + await runDev({ root: paths.root }); - expect(startFuelCore).toHaveBeenCalledTimes(1); + expect(autoStartFuelCore).toHaveBeenCalledTimes(1); expect(killChildProcess).toHaveBeenCalledTimes(0); expect(build).toHaveBeenCalledTimes(1); expect(deploy).toHaveBeenCalledTimes(1); diff --git a/packages/fuels/test/features/init.test.ts b/packages/fuels/test/features/init.test.ts index 1db94d6d7f..3f111cd75d 100644 --- a/packages/fuels/test/features/init.test.ts +++ b/packages/fuels/test/features/init.test.ts @@ -1,36 +1,61 @@ import chalk from 'chalk'; import { existsSync, readFileSync } from 'fs'; +import { Commands } from '../../src'; import { mockLogger } from '../utils/mockLogger'; -import { resetDiskAndMocks } from '../utils/resetDiskAndMocks'; import { - fuelsConfigPath, - generatedDir, - initFlagsAutoStartFuelCore, - initFlagsWorkspace, + bootstrapProject, + runCommand, runInit, + resetDiskAndMocks, + resetConfigAndMocks, } from '../utils/runCommands'; +/** + * @group node + */ describe('init', () => { - beforeEach(mockLogger); - afterEach(resetDiskAndMocks); + const paths = bootstrapProject(__filename); + + beforeEach(() => { + mockLogger(); + }); + + afterEach(() => { + resetConfigAndMocks(paths.fuelsConfigPath); + }); + + afterAll(() => { + resetDiskAndMocks(paths.root); + }); it('should run `init` command', async () => { - await runInit([initFlagsWorkspace, initFlagsAutoStartFuelCore].flat()); - expect(existsSync(fuelsConfigPath)).toBeTruthy(); - const fuelsContents = readFileSync(fuelsConfigPath, 'utf-8'); - expect(fuelsContents).toMatch(`workspace: './project',`); - expect(fuelsContents).toMatch(`output: './generated',`); + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + + expect(existsSync(paths.fuelsConfigPath)).toBeTruthy(); + const fuelsContents = readFileSync(paths.fuelsConfigPath, 'utf-8'); + expect(fuelsContents).toMatch(`workspace: './workspace',`); + expect(fuelsContents).toMatch(`output: './output',`); expect(fuelsContents).not.toMatch(`useBuiltinForc: true,`); expect(fuelsContents).not.toMatch(`useBuiltinFuelCore: true,`); }); it('should run `init` command using built-in flags', async () => { - await runInit(); - expect(existsSync(fuelsConfigPath)).toBeTruthy(); - const fuelsContents = readFileSync(fuelsConfigPath, 'utf-8'); - expect(fuelsContents).toMatch(`workspace: './project',`); - expect(fuelsContents).toMatch(`output: './generated',`); + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + useBuiltinBinaries: true, + }); + + expect(existsSync(paths.fuelsConfigPath)).toBeTruthy(); + const fuelsContents = readFileSync(paths.fuelsConfigPath, 'utf-8'); + expect(fuelsContents).toMatch(`workspace: './workspace',`); + expect(fuelsContents).toMatch(`output: './output',`); expect(fuelsContents).toMatch(`useBuiltinForc: true,`); expect(fuelsContents).toMatch(`useBuiltinFuelCore: true,`); }); @@ -38,20 +63,31 @@ describe('init', () => { it('should run `init` command and throw for existent config file', async () => { const { error } = mockLogger(); - await runInit(); + // first time, all good + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + expect(error).toHaveBeenCalledTimes(0); // second time will trigger error - await runInit(); + await runInit({ + root: paths.root, + workspace: paths.workspaceDir, + output: paths.outputDir, + }); + expect(error).toHaveBeenCalledTimes(1); expect(chalk.reset(error.mock.calls[0][0])).toMatch(/Config file exists, aborting/); }); it('should error if no inputs/workspace is supplied', async () => { - const write = jest.spyOn(process.stdout, 'write').mockImplementation(); - const exit = jest.spyOn(process, 'exit').mockImplementation(); + const write = vi.spyOn(process.stdout, 'write').mockReturnValue(true); + const exit = vi.spyOn(process, 'exit').mockResolvedValue({} as never); - await runInit(['-o', generatedDir].flat()); + await runCommand(Commands.init, ['-p', paths.root, '-o', paths.outputDir]); expect(exit).toHaveBeenCalledTimes(1); expect(exit).toHaveBeenCalledWith(1); diff --git a/packages/fuels/test/fixtures/config/fuels.config.ts b/packages/fuels/test/fixtures/fuels.config.ts similarity index 84% rename from packages/fuels/test/fixtures/config/fuels.config.ts rename to packages/fuels/test/fixtures/fuels.config.ts index b974f2b400..edc85516c4 100644 --- a/packages/fuels/test/fixtures/config/fuels.config.ts +++ b/packages/fuels/test/fixtures/fuels.config.ts @@ -1,9 +1,9 @@ import { FUEL_NETWORK_URL } from '@fuel-ts/wallet/configs'; import { join } from 'path'; -import type { FuelsConfig } from '../../../src'; +import type { FuelsConfig } from '../../src'; -const projectPath = join(__dirname, '..', 'project'); +const projectPath = join(__dirname, 'workspace'); const contractsDir = join(projectPath, 'contracts'); const scriptsDir = join(projectPath, 'scripts'); @@ -15,7 +15,7 @@ export const fuelsConfig: FuelsConfig = { contracts: [join(contractsDir, 'foo'), join(contractsDir, 'bar')], scripts: [join(scriptsDir, 'script')], predicates: [join(predicatesDir, 'predicate')], - output: '/generated-types', + output: '/output', deployConfig: { gasPrice: 5, }, diff --git a/packages/fuels/test/fixtures/project/.fuels/chainConfig.json b/packages/fuels/test/fixtures/project/.fuels/chainConfig.json new file mode 100644 index 0000000000..82345ea163 --- /dev/null +++ b/packages/fuels/test/fixtures/project/.fuels/chainConfig.json @@ -0,0 +1,515 @@ +{ + "chain_name": "local_testnet", + "block_gas_limit": 5000000000, + "initial_state": { + "coins": [ + { + "owner": "0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + } + ], + "messages": [ + { + "sender": "0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f", + "recipient": "0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba", + "nonce": "0101010101010101010101010101010101010101010101010101010101010101", + "amount": "0x000000000000FFFF", + "data": "", + "da_height": "0x00" + }, + { + "sender": "0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba", + "recipient": "0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f", + "nonce": "0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b", + "amount": "0xb04f3c08f59b309e", + "data": "", + "da_height": "0x00" + } + ] + }, + "consensus_parameters": { + "tx_params": { + "max_inputs": 255, + "max_outputs": 255, + "max_witnesses": 255, + "max_gas_per_tx": 10000000, + "max_size": 17825792 + }, + "predicate_params": { + "max_predicate_length": 1048576, + "max_predicate_data_length": 1048576, + "max_gas_per_predicate": 10000000, + "max_message_data_length": 1048576 + }, + "script_params": { + "max_script_length": 1048576, + "max_script_data_length": 1048576 + }, + "contract_params": { + "contract_max_size": 16777216, + "max_storage_slots": 255 + }, + "fee_params": { + "gas_price_factor": 92, + "gas_per_byte": 4 + } + }, + "gas_costs": { + "add": 1, + "addi": 1, + "aloc": 1, + "and": 1, + "andi": 1, + "bal": 13, + "bhei": 1, + "bhsh": 1, + "burn": 132, + "cb": 1, + "cfei": 1, + "cfsi": 1, + "croo": 16, + "div": 1, + "divi": 1, + "ecr1": 3000, + "eck1": 951, + "ed19": 3000, + "eq": 1, + "exp": 1, + "expi": 1, + "flag": 1, + "gm": 1, + "gt": 1, + "gtf": 1, + "ji": 1, + "jmp": 1, + "jne": 1, + "jnei": 1, + "jnzi": 1, + "jmpf": 1, + "jmpb": 1, + "jnzf": 1, + "jnzb": 1, + "jnef": 1, + "jneb": 1, + "lb": 1, + "log": 9, + "lt": 1, + "lw": 1, + "mint": 135, + "mlog": 1, + "modOp": 1, + "modi": 1, + "moveOp": 1, + "movi": 1, + "mroo": 2, + "mul": 1, + "muli": 1, + "mldv": 1, + "noop": 1, + "not": 1, + "or": 1, + "ori": 1, + "poph": 2, + "popl": 2, + "pshh": 2, + "pshl": 2, + "ret": 13, + "rvrt": 13, + "sb": 1, + "sll": 1, + "slli": 1, + "srl": 1, + "srli": 1, + "srw": 12, + "sub": 1, + "subi": 1, + "sw": 1, + "sww": 67, + "time": 1, + "tr": 105, + "tro": 60, + "wdcm": 1, + "wqcm": 1, + "wdop": 1, + "wqop": 1, + "wdml": 1, + "wqml": 1, + "wddv": 1, + "wqdv": 2, + "wdmd": 3, + "wqmd": 4, + "wdam": 2, + "wqam": 3, + "wdmm": 3, + "wqmm": 3, + "xor": 1, + "xori": 1, + "call": { + "LightOperation": { + "base": 144, + "units_per_gas": 214 + } + }, + "ccp": { + "LightOperation": { + "base": 15, + "units_per_gas": 103 + } + }, + "csiz": { + "LightOperation": { + "base": 17, + "units_per_gas": 790 + } + }, + "k256": { + "LightOperation": { + "base": 11, + "units_per_gas": 214 + } + }, + "ldc": { + "LightOperation": { + "base": 15, + "units_per_gas": 272 + } + }, + "logd": { + "LightOperation": { + "base": 26, + "units_per_gas": 64 + } + }, + "mcl": { + "LightOperation": { + "base": 1, + "units_per_gas": 3333 + } + }, + "mcli": { + "LightOperation": { + "base": 1, + "units_per_gas": 3333 + } + }, + "mcp": { + "LightOperation": { + "base": 1, + "units_per_gas": 2000 + } + }, + "mcpi": { + "LightOperation": { + "base": 3, + "units_per_gas": 2000 + } + }, + "meq": { + "LightOperation": { + "base": 1, + "units_per_gas": 2500 + } + }, + "retd": { + "LightOperation": { + "base": 29, + "units_per_gas": 62 + } + }, + "s256": { + "LightOperation": { + "base": 2, + "units_per_gas": 214 + } + }, + "scwq": { + "LightOperation": { + "base": 13, + "units_per_gas": 5 + } + }, + "smo": { + "LightOperation": { + "base": 209, + "units_per_gas": 55 + } + }, + "srwq": { + "LightOperation": { + "base": 47, + "units_per_gas": 5 + } + }, + "swwq": { + "LightOperation": { + "base": 44, + "units_per_gas": 5 + } + }, + "contract_root": { + "LightOperation": { + "base": 75, + "units_per_gas": 1 + } + }, + "state_root": { + "LightOperation": { + "base": 412, + "units_per_gas": 1 + } + }, + "vm_initialization": { + "HeavyOperation": { + "base": 2000, + "gas_per_unit": 0 + } + }, + "new_storage_per_byte": 1 + }, + "consensus": { + "PoA": { + "signing_key": "0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d" + } + } +} \ No newline at end of file diff --git a/packages/fuels/test/fixtures/project/Forc.toml b/packages/fuels/test/fixtures/workspace/Forc.toml similarity index 100% rename from packages/fuels/test/fixtures/project/Forc.toml rename to packages/fuels/test/fixtures/workspace/Forc.toml diff --git a/packages/fuels/test/fixtures/project/contracts/bar/Forc.toml b/packages/fuels/test/fixtures/workspace/contracts/bar/Forc.toml similarity index 100% rename from packages/fuels/test/fixtures/project/contracts/bar/Forc.toml rename to packages/fuels/test/fixtures/workspace/contracts/bar/Forc.toml diff --git a/packages/fuels/test/fixtures/project/contracts/bar/src/main.sw b/packages/fuels/test/fixtures/workspace/contracts/bar/src/main.sw similarity index 100% rename from packages/fuels/test/fixtures/project/contracts/bar/src/main.sw rename to packages/fuels/test/fixtures/workspace/contracts/bar/src/main.sw diff --git a/packages/fuels/test/fixtures/project/contracts/foo/Forc.toml b/packages/fuels/test/fixtures/workspace/contracts/foo/Forc.toml similarity index 100% rename from packages/fuels/test/fixtures/project/contracts/foo/Forc.toml rename to packages/fuels/test/fixtures/workspace/contracts/foo/Forc.toml diff --git a/packages/fuels/test/fixtures/project/contracts/foo/src/main.sw b/packages/fuels/test/fixtures/workspace/contracts/foo/src/main.sw similarity index 100% rename from packages/fuels/test/fixtures/project/contracts/foo/src/main.sw rename to packages/fuels/test/fixtures/workspace/contracts/foo/src/main.sw diff --git a/packages/fuels/test/fixtures/project/predicates/predicate/Forc.toml b/packages/fuels/test/fixtures/workspace/predicates/predicate/Forc.toml similarity index 100% rename from packages/fuels/test/fixtures/project/predicates/predicate/Forc.toml rename to packages/fuels/test/fixtures/workspace/predicates/predicate/Forc.toml diff --git a/packages/fuels/test/fixtures/workspace/predicates/predicate/src/main.sw b/packages/fuels/test/fixtures/workspace/predicates/predicate/src/main.sw new file mode 100644 index 0000000000..084dacab2c --- /dev/null +++ b/packages/fuels/test/fixtures/workspace/predicates/predicate/src/main.sw @@ -0,0 +1,5 @@ +predicate; + +fn main() -> bool { + true +} diff --git a/packages/fuels/test/fixtures/project/scripts/script/Forc.toml b/packages/fuels/test/fixtures/workspace/scripts/script/Forc.toml similarity index 100% rename from packages/fuels/test/fixtures/project/scripts/script/Forc.toml rename to packages/fuels/test/fixtures/workspace/scripts/script/Forc.toml diff --git a/packages/fuels/test/fixtures/project/scripts/script/src/main.sw b/packages/fuels/test/fixtures/workspace/scripts/script/src/main.sw similarity index 100% rename from packages/fuels/test/fixtures/project/scripts/script/src/main.sw rename to packages/fuels/test/fixtures/workspace/scripts/script/src/main.sw diff --git a/packages/fuels/test/utils/mockAutoStartFuelCore.ts b/packages/fuels/test/utils/mockAutoStartFuelCore.ts new file mode 100644 index 0000000000..bbca5f69da --- /dev/null +++ b/packages/fuels/test/utils/mockAutoStartFuelCore.ts @@ -0,0 +1,26 @@ +import type { SpyInstance } from 'vitest'; + +import * as autoStartFuelCoreMod from '../../src/cli/commands/dev/autoStartFuelCore'; + +export const mockStartFuelCore = (): { + killChildProcess: SpyInstance; + autoStartFuelCore: SpyInstance; + fuelCore: autoStartFuelCoreMod.FuelCoreNode; +} => { + const killChildProcess = vi.fn(); + + const fuelCore: autoStartFuelCoreMod.FuelCoreNode = { + bindIp: '0.0.0.0', + accessIp: '127.0.0.1', + port: 4000, + providerUrl: `http://127.0.0.1:4000/graphql`, + killChildProcess, + chainConfigPath: '/some/path/chainConfig.json', + }; + + const autoStartFuelCore = vi + .spyOn(autoStartFuelCoreMod, 'autoStartFuelCore') + .mockResolvedValue(fuelCore); + + return { autoStartFuelCore, killChildProcess, fuelCore }; +}; diff --git a/packages/fuels/test/utils/mockLogger.ts b/packages/fuels/test/utils/mockLogger.ts index 7a995d0ab7..0ff436d0b3 100644 --- a/packages/fuels/test/utils/mockLogger.ts +++ b/packages/fuels/test/utils/mockLogger.ts @@ -1,10 +1,10 @@ import * as logger from '../../src/cli/utils/logger'; export function mockLogger() { - const error = jest.spyOn(logger, 'error').mockImplementation(); - const warn = jest.spyOn(logger, 'warn').mockImplementation(); - const log = jest.spyOn(logger, 'log').mockImplementation(); - const debug = jest.spyOn(logger, 'debug').mockImplementation(); + const error = vi.spyOn(logger, 'error').mockReturnValue(); + const warn = vi.spyOn(logger, 'warn').mockReturnValue(); + const log = vi.spyOn(logger, 'log').mockReturnValue(); + const debug = vi.spyOn(logger, 'debug').mockReturnValue(); return { error, warn, diff --git a/packages/fuels/test/utils/mockStartFuelCore.ts b/packages/fuels/test/utils/mockStartFuelCore.ts deleted file mode 100644 index b713d6c018..0000000000 --- a/packages/fuels/test/utils/mockStartFuelCore.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { FuelsConfig } from '../../src'; -import * as startFuelCoreMod from '../../src/cli/commands/dev/startFuelCore'; - -export const mockStartFuelCore = () => { - const killChildProcess = jest.fn(); - - const startFuelCore = jest - .spyOn(startFuelCoreMod, 'startFuelCore') - .mockImplementation((_config: FuelsConfig) => - Promise.resolve({ - bindIp: '0.0.0.0', - accessIp: '127.0.0.1', - port: 4000, - providerUrl: `http://127.0.0.1:4000/graphql`, - killChildProcess, - chainConfig: '/some/path/chainConfig.json', - }) - ); - - return { startFuelCore, killChildProcess }; -}; diff --git a/packages/fuels/test/utils/resetDiskAndMocks.ts b/packages/fuels/test/utils/resetDiskAndMocks.ts index d46f6d943a..fddd7eabab 100644 --- a/packages/fuels/test/utils/resetDiskAndMocks.ts +++ b/packages/fuels/test/utils/resetDiskAndMocks.ts @@ -1,20 +1,12 @@ import { existsSync, rmSync } from 'fs'; -import { fuelsConfigPath, generatedDir } from './runCommands'; - /** * Cleanup routine */ -export function deleteGeneratedFiles() { - if (existsSync(fuelsConfigPath)) { - rmSync(fuelsConfigPath); - } - if (existsSync(generatedDir)) { - rmSync(generatedDir, { recursive: true }); - } -} -export function resetDiskAndMocks() { - deleteGeneratedFiles(); - jest.restoreAllMocks(); +export function resetDiskAndMocks(dirPath: string) { + if (existsSync(dirPath)) { + rmSync(dirPath, { recursive: true }); + } + vi.restoreAllMocks(); } diff --git a/packages/fuels/test/utils/runCommands.ts b/packages/fuels/test/utils/runCommands.ts index cddc499981..37b3337bd5 100644 --- a/packages/fuels/test/utils/runCommands.ts +++ b/packages/fuels/test/utils/runCommands.ts @@ -1,69 +1,152 @@ -import { join } from 'path'; +import { cpSync, existsSync, mkdirSync, rmSync } from 'fs'; +import { join, basename } from 'path'; import { Commands } from '../../src'; -import { run } from '../../src/cli'; +import { run } from '../../src/run'; /** - * Paths + * Path and Directory utils */ -export const fixturesDir = join(__dirname, '..', 'fixtures'); +export const testDir = join(__dirname, '..'); +export const fixturesDir = join(testDir, 'fixtures'); +export const sampleWorkspaceDir = join(fixturesDir, 'workspace'); +export const sampleConfigPath = join(fixturesDir, 'fuels.config.ts'); -export const workspaceDir = join(fixturesDir, 'project'); +export type Paths = { + root: string; + workspaceDir: string; + contractsDir: string; + contractsFooDir: string; + scriptsDir: string; + predicateDir: string; + fooContractMainPath: string; + fuelsConfigPath: string; + outputDir: string; + contractsJsonPath: string; + fooContractFactoryPath: string; +}; -export const contractsDir = join(workspaceDir, 'contracts'); -export const contractsFooDir = join(contractsDir, 'foo'); -export const scriptsDir = join(workspaceDir, 'scripts'); -export const predicateDir = join(workspaceDir, 'predicate'); +export function bootstrapProject(testFilepath: string) { + const testFilename = basename(testFilepath.replace(/\./g, '-')); + const uniqueName = `__temp__${testFilename}_${new Date().getTime()}`; -export const fooContractMainPath = join(contractsDir, 'foo', 'src', 'main.sw'); + const root = join(testDir, uniqueName); + const workspaceDir = join(root, 'workspace'); + const fuelsConfigPath = join(root, 'fuels.config.ts'); -export const fuelsConfigPath = join(fixturesDir, 'fuels.config.ts'); -export const generatedDir = join(fixturesDir, 'generated'); -export const contractsJsonPath = join(generatedDir, 'contract-ids.json'); -export const fooContractFactoryPath = join( - generatedDir, - 'contracts', - 'factories', - 'FooBarAbi__factory.ts' -); + mkdirSync(workspaceDir, { recursive: true }); + + cpSync(sampleWorkspaceDir, workspaceDir, { recursive: true }); + + const contractsDir = join(workspaceDir, 'contracts'); + const contractsFooDir = join(contractsDir, 'foo'); + const scriptsDir = join(workspaceDir, 'scripts'); + const predicateDir = join(workspaceDir, 'predicate'); + const fooContractMainPath = join(contractsDir, 'foo', 'src', 'main.sw'); + + const outputDir = join(root, 'output'); + const contractsJsonPath = join(outputDir, 'contract-ids.json'); + const fooContractFactoryPath = join(outputDir, 'contracts', 'factories', 'FooBarAbi__factory.ts'); + + return { + root, + workspaceDir, + contractsDir, + contractsFooDir, + scriptsDir, + predicateDir, + fooContractMainPath, + fuelsConfigPath, + outputDir, + contractsJsonPath, + fooContractFactoryPath, + }; +} /** - * Helper + * Command callers */ export async function runCommand(commandName: string, params: string[] = []) { // always `--silent` to avoid polluting tests output - const argv = ['node', 'fuels', '--silent', commandName, '-p', fixturesDir].concat(params); + const argv = ['node', 'fuels', '--silent', commandName].concat(params); return { argv, command: await run(argv) }; } -/** - * Bundled flag combos - */ -export const initFlagsWorkspace = ['-w', workspaceDir, '-o', generatedDir]; -export const initFlagsUseBuiltinBinaries = ['--use-builtin-forc', '--use-builtin-fuel-core']; -export const initFlagsAutoStartFuelCore = '--auto-start-fuel-core'; -export const initFlagsDefault = [ - initFlagsWorkspace, - initFlagsUseBuiltinBinaries, - initFlagsAutoStartFuelCore, -]; -export const buildFlagsDeploy = '--deploy'; +export type BaseParams = { + root: string; +}; + +export type InitParams = BaseParams & { + workspace?: string; + contracts?: string; + scripts?: string; + predicates?: string; + output: string; + useBuiltinBinaries?: boolean; + autoStartFuelCore?: boolean; + build?: boolean; +}; + +export type BuildParams = BaseParams & { + deploy?: boolean; +}; + +export async function runInit(params: InitParams) { + const { + autoStartFuelCore, + contracts, + output, + predicates, + root, + scripts, + useBuiltinBinaries, + workspace, + } = params; + + const flag = (flags: (string | undefined)[], value?: string | boolean): string[] => + value ? (flags as string[]) : []; + + const flags = [ + flag(['-p', root], root), + flag(['-o', output], output), + flag(['-w', workspace], workspace), + flag(['--contracts', contracts], contracts), + flag(['--scripts', scripts], scripts), + flag(['--predicates', predicates], predicates), + flag(['--use-builtin-forc', '--use-builtin-fuel-core'], useBuiltinBinaries), + flag(['--auto-start-fuel-core'], autoStartFuelCore), + ].flat(); -/** - * Command callers - */ -export async function runInit(flags: string[] = initFlagsDefault.flat()) { return runCommand(Commands.init, flags); } -export async function runBuild(flags: string[] = []) { +export async function runBuild(params: BuildParams) { + const { root, deploy } = params; + const flags = [['-p', root], deploy ? ['--deploy'] : []].flat(); return runCommand(Commands.build, flags); } -export async function runDeploy() { - return runCommand(Commands.deploy); +export async function runDeploy(params: BaseParams) { + return runCommand(Commands.deploy, ['-p', params.root]); +} + +export async function runDev(params: BaseParams) { + return runCommand(Commands.dev, ['-p', params.root]); +} + +/** + * Cleanup + */ +export function resetConfigAndMocks(configPath: string) { + if (existsSync(configPath)) { + rmSync(configPath); + } + vi.restoreAllMocks(); } -export async function runDev() { - return runCommand(Commands.dev); +export function resetDiskAndMocks(dirPath: string) { + if (existsSync(dirPath)) { + rmSync(dirPath, { recursive: true }); + } + vi.restoreAllMocks(); } diff --git a/packages/fuels/tsdoc.json b/packages/fuels/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/fuels/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/hasher/README.md b/packages/hasher/README.md index 2a2292a852..a6c920bbde 100644 --- a/packages/hasher/README.md +++ b/packages/hasher/README.md @@ -18,7 +18,7 @@ This module contains several common hashing utilities. -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/hasher/package.json b/packages/hasher/package.json index 7d0d6638c9..52abc4e962 100644 --- a/packages/hasher/package.json +++ b/packages/hasher/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/hasher/src/hasher.test.ts b/packages/hasher/src/hasher.test.ts index 724400a043..44e2143220 100644 --- a/packages/hasher/src/hasher.test.ts +++ b/packages/hasher/src/hasher.test.ts @@ -1,5 +1,9 @@ -import { hashMessage, hash } from './hasher'; +import { hashMessage, hash, uint64ToBytesBE } from './hasher'; +/** + * @group node + * @group browser + */ describe('Hasher', () => { it('Hash message', () => { const message = 'my message'; @@ -12,4 +16,10 @@ describe('Hasher', () => { '0xf5ca38f748a1d6eaf726b8a42fb575c3c71f1864a8143301782de13da2d9202b' ); }); + + it('Convert uint64 to bytes in big-endian order', () => { + const value = 1234567890; + const expectedBytes = new Uint8Array([0, 0, 0, 0, 73, 150, 2, 210]); + expect(uint64ToBytesBE(value)).toEqual(expectedBytes); + }); }); diff --git a/packages/hasher/tsdoc.json b/packages/hasher/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/hasher/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/hdwallet/README.md b/packages/hdwallet/README.md index 31804b1b8f..0069b8004f 100644 --- a/packages/hdwallet/README.md +++ b/packages/hdwallet/README.md @@ -18,7 +18,7 @@ This module is an implementation of the BIP-0044 and BIP-0032, Multi-Account Hie -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/hdwallet/package.json b/packages/hdwallet/package.json index b6141785c2..bc42a7bd69 100644 --- a/packages/hdwallet/package.json +++ b/packages/hdwallet/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/hdwallet/src/hdwallet.test.ts b/packages/hdwallet/src/hdwallet.test.ts index 7f280c1951..51894aeb57 100644 --- a/packages/hdwallet/src/hdwallet.test.ts +++ b/packages/hdwallet/src/hdwallet.test.ts @@ -1,6 +1,10 @@ import HDWallet from './hdwallet'; import HDWalletSpec from './hdwallet-spec'; +/** + * @group node + * @group browser + */ describe('HDWallet', () => { test("Should throw error on invalid extended key's", () => { expect(() => diff --git a/packages/hdwallet/tsdoc.json b/packages/hdwallet/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/hdwallet/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/interfaces/README.md b/packages/interfaces/README.md index 49dd79edce..03d8e85591 100644 --- a/packages/interfaces/README.md +++ b/packages/interfaces/README.md @@ -18,7 +18,7 @@ This module contains utilities to manipulate binary data and can be used to help -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/interfaces/package.json b/packages/interfaces/package.json index 458a7fc9ae..45cd56c2df 100644 --- a/packages/interfaces/package.json +++ b/packages/interfaces/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index 5aed5cd5ea..90765b3442 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -60,7 +60,7 @@ export abstract class AbstractAccount { abstract address: AbstractAddress; abstract provider: unknown; abstract getResourcesToSpend(quantities: any[], options?: any): any; - abstract sendTransaction(transactionRequest: any): any; + abstract sendTransaction(transactionRequest: any, options?: any): any; abstract simulateTransaction(transactionRequest: any): any; abstract fund(transactionRequest: any, quantities: any, fee: any): Promise; } @@ -74,7 +74,7 @@ export abstract class AbstractProgram { }; abstract provider: { - sendTransaction(transactionRequest: any): any; + sendTransaction(transactionRequest: any, options?: any): any; } | null; } diff --git a/packages/math/README.md b/packages/math/README.md index db5d27e4bf..fd2d333c3c 100644 --- a/packages/math/README.md +++ b/packages/math/README.md @@ -20,7 +20,7 @@ Math is based in [bn.js](https://www.npmjs.com/package/bn.js) library, which hel -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/math/package.json b/packages/math/package.json index e196a78d59..7fcfd789aa 100644 --- a/packages/math/package.json +++ b/packages/math/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/math/src/bn.test.ts b/packages/math/src/bn.test.ts index b92b442e83..47103bdd3f 100644 --- a/packages/math/src/bn.test.ts +++ b/packages/math/src/bn.test.ts @@ -2,6 +2,10 @@ import type { BN } from './bn'; import { bn } from './bn'; import type { BigNumberish } from './types'; +/** + * @group node + * @group browser + */ describe('Math - BN', () => { it('can execute operations without losing our BN reference', () => { let test: BN; diff --git a/packages/math/src/functional.test.ts b/packages/math/src/functional.test.ts index 086ebb8477..99acae319d 100644 --- a/packages/math/src/functional.test.ts +++ b/packages/math/src/functional.test.ts @@ -6,6 +6,9 @@ import { format, formatUnits, toBytes, toHex, toNumber } from './functional'; +/** + * @group node + */ describe('Math - Functional shortcuts', () => { it('should toNumber return a number', () => { expect(toNumber('50000')).toEqual(50000); diff --git a/packages/math/tsdoc.json b/packages/math/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/math/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/merkle/README.md b/packages/merkle/README.md index 480010e4a9..2d1975deb6 100644 --- a/packages/merkle/README.md +++ b/packages/merkle/README.md @@ -23,7 +23,7 @@ This module contains: -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/merkle/package.json b/packages/merkle/package.json index 18e583d623..8a3fcb6b2b 100644 --- a/packages/merkle/package.json +++ b/packages/merkle/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/merkle/src/binary/binaryMerkleTree.test.ts b/packages/merkle/src/binary/binaryMerkleTree.test.ts index afefdf2e4f..574af5e14a 100644 --- a/packages/merkle/src/binary/binaryMerkleTree.test.ts +++ b/packages/merkle/src/binary/binaryMerkleTree.test.ts @@ -3,6 +3,9 @@ import { toHex } from '@fuel-ts/math'; import { calcRoot, constructTree, getProof } from './binaryMerkleTree'; import type Node from './types/node'; +/** + * @group node + */ describe('Binary Merkle Tree', () => { const rootAfterLeaves = '0x9e59abcd7c89011ba919f9141624acb32b4cc31c24e76c6d4f64b25093ef366c'; const size = 100; diff --git a/packages/merkle/src/sparse/sparseMerkleTree.test.ts b/packages/merkle/src/sparse/sparseMerkleTree.test.ts index f41f9e0ca9..89f745e40e 100644 --- a/packages/merkle/src/sparse/sparseMerkleTree.test.ts +++ b/packages/merkle/src/sparse/sparseMerkleTree.test.ts @@ -5,6 +5,9 @@ import { hash } from '../common'; import { DeepSparseMerkleSubTree } from './deepSparseMerkleSubTree'; import { SparseMerkleTree } from './sparseMerkleTree'; +/** + * @group node + */ describe('Sparse Merkle Tree', () => { it('Update and delete', () => { const smt = new SparseMerkleTree(); diff --git a/packages/merkle/src/sum/sumMerkleTree.test.ts b/packages/merkle/src/sum/sumMerkleTree.test.ts index 910d37864e..d1d5e062df 100644 --- a/packages/merkle/src/sum/sumMerkleTree.test.ts +++ b/packages/merkle/src/sum/sumMerkleTree.test.ts @@ -3,6 +3,9 @@ import { toHex } from '@fuel-ts/math'; import { calcRoot, constructTree, getProof } from './sumMerkleTree'; import Proof from './types/proof'; +/** + * @group node + */ describe('Sum Merkle Tree', () => { const size = 100; const sumAfterLeaves = toHex(((size - 1) * size) / 2); diff --git a/packages/merkle/tsdoc.json b/packages/merkle/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/merkle/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/mnemonic/README.md b/packages/mnemonic/README.md index 51ccc70777..27338167f3 100644 --- a/packages/mnemonic/README.md +++ b/packages/mnemonic/README.md @@ -18,7 +18,7 @@ This module contains utilities to import and export BIP 39 mnemonic phrases in c -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/mnemonic/package.json b/packages/mnemonic/package.json index 8ad4dd8926..7ee666f6f3 100644 --- a/packages/mnemonic/package.json +++ b/packages/mnemonic/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/mnemonic/src/mnemonic.test.ts b/packages/mnemonic/src/mnemonic.test.ts index ca3af21daf..f07d1c4ccd 100644 --- a/packages/mnemonic/src/mnemonic.test.ts +++ b/packages/mnemonic/src/mnemonic.test.ts @@ -3,6 +3,10 @@ import { randomBytes } from '@fuel-ts/crypto'; import Mnemonic from './mnemonic'; import MnemonicSpec from './mnemonic-specs'; +/** + * @group node + * @group browser + */ describe('Mnemonic', () => { const mnemonic = new Mnemonic(); diff --git a/packages/mnemonic/src/utils.test.ts b/packages/mnemonic/src/utils.test.ts index 9e20212f06..5bcc30bd3f 100644 --- a/packages/mnemonic/src/utils.test.ts +++ b/packages/mnemonic/src/utils.test.ts @@ -1,5 +1,9 @@ import { getWords } from './utils'; +/** + * @group node + * @group browser + */ describe('mnemonic utils', () => { const words = ['a', 'b', 'c']; diff --git a/packages/mnemonic/tsdoc.json b/packages/mnemonic/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/mnemonic/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/predicate/README.md b/packages/predicate/README.md index 4811e836b9..d966e70e06 100644 --- a/packages/predicate/README.md +++ b/packages/predicate/README.md @@ -16,7 +16,7 @@ This module allows for a simple way to serialize calls to an on-chain predicate ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/predicates/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/predicates/) ## Usage diff --git a/packages/predicate/package.json b/packages/predicate/package.json index 173c5a1ffa..64a7115646 100644 --- a/packages/predicate/package.json +++ b/packages/predicate/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/predicate/src/predicate.ts b/packages/predicate/src/predicate.ts index f425290b62..d6fd4c49f3 100644 --- a/packages/predicate/src/predicate.ts +++ b/packages/predicate/src/predicate.ts @@ -14,6 +14,7 @@ import type { BigNumberish } from '@fuel-ts/math'; import type { CallResult, Provider, + ProviderSendTxParams, TransactionRequest, TransactionRequestLike, TransactionResponse, @@ -113,9 +114,12 @@ export class Predicate extends Account implements Abs * @param transactionRequestLike - The transaction request-like object. * @returns A promise that resolves to the transaction response. */ - sendTransaction(transactionRequestLike: TransactionRequestLike): Promise { + sendTransaction( + transactionRequestLike: TransactionRequestLike, + options?: Pick + ): Promise { const transactionRequest = this.populateTransactionPredicateData(transactionRequestLike); - return super.sendTransaction(transactionRequest); + return super.sendTransaction(transactionRequest, options); } /** diff --git a/packages/predicate/src/utils/getPredicateRoot.test.ts b/packages/predicate/src/utils/getPredicateRoot.test.ts index e448adec37..28b2ed9388 100644 --- a/packages/predicate/src/utils/getPredicateRoot.test.ts +++ b/packages/predicate/src/utils/getPredicateRoot.test.ts @@ -2,6 +2,9 @@ import { getBytesCopy } from 'ethers'; import { getPredicateRoot } from './getPredicateRoot'; +/** + * @group node + */ describe('getPredicateRoot', () => { it('should return the correct predicate root', () => { const predicateBytes = getBytesCopy( diff --git a/packages/predicate/test/features/predicate-functions.test.ts b/packages/predicate/test/features/predicate-functions.test.ts index e2c0bf4b0d..ecdba186b4 100644 --- a/packages/predicate/test/features/predicate-functions.test.ts +++ b/packages/predicate/test/features/predicate-functions.test.ts @@ -5,6 +5,10 @@ import { Predicate } from '../../src/predicate'; import { defaultPredicateAbi } from '../fixtures/abi/default'; import { defaultPredicateBytecode } from '../fixtures/bytecode/default'; +/** + * @group node + * @group browser + */ describe('Predicate', () => { describe('Functions', () => { const predicateAddress = '0x6b6ef590390f0a7de75f8275ab5d7877c17236caba2514039c6565ec15f79111'; diff --git a/packages/predicate/test/features/predicate-transactions.test.ts b/packages/predicate/test/features/predicate-transactions.test.ts index 7fcf95d3f1..3be2fa8d3e 100644 --- a/packages/predicate/test/features/predicate-transactions.test.ts +++ b/packages/predicate/test/features/predicate-transactions.test.ts @@ -10,6 +10,10 @@ import { Predicate } from '../../src/predicate'; import { defaultPredicateAbi } from '../fixtures/abi/default'; import { defaultPredicateBytecode } from '../fixtures/bytecode/default'; +/** + * @group node + * @group browser + */ describe('Predicate', () => { describe('Transactions', () => { let predicate: Predicate<[string]>; @@ -36,9 +40,9 @@ describe('Predicate', () => { }); it('includes predicate as input when sending a transaction', async () => { - const sendTransactionMock = jest + const sendTransactionMock = vi .spyOn(Account.prototype, 'sendTransaction') - .mockImplementation(); + .mockImplementation(() => []); await predicate.sendTransaction(request); @@ -49,9 +53,9 @@ describe('Predicate', () => { }); it('includes predicate as input when simulating a transaction', async () => { - const sendTransactionMock = jest + const sendTransactionMock = vi .spyOn(Account.prototype, 'simulateTransaction') - .mockImplementation(); + .mockImplementation(() => []); await predicate.simulateTransaction(request); diff --git a/packages/program/README.md b/packages/program/README.md index b8c7697441..f72b241b48 100644 --- a/packages/program/README.md +++ b/packages/program/README.md @@ -18,7 +18,7 @@ This module allows for a simple way to serialize calls and transactions to Sway -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/program/package.json b/packages/program/package.json index be20a77f9a..c6c67fdb80 100644 --- a/packages/program/package.json +++ b/packages/program/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/program/src/contract.test.ts b/packages/program/src/contract.test.ts index 0a09d291e5..6dac19ba45 100644 --- a/packages/program/src/contract.test.ts +++ b/packages/program/src/contract.test.ts @@ -37,6 +37,9 @@ const ABI: JsonAbi = { configurables: [], }; +/** + * @group node + */ describe('Contract', () => { test('Create contract instance with provider', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); @@ -64,7 +67,7 @@ describe('Contract', () => { // but without reference to the BaseWalletLocked class const BaseWalletLockedCustom = Object.assign(Account); expect(BaseWalletLockedCustom).not.toBeInstanceOf(Account); - const wallet = new BaseWalletLockedCustom(generatedWallet.address); + const wallet = new BaseWalletLockedCustom(generatedWallet.address, generatedWallet.provider); const contract = new Contract(CONTRACT_ID, ABI, wallet); expect(contract.provider).toBe(wallet.provider); expect(contract.account).toBe(wallet); diff --git a/packages/program/src/functions/base-invocation-scope.ts b/packages/program/src/functions/base-invocation-scope.ts index b9857c7b78..f0e1a777bf 100644 --- a/packages/program/src/functions/base-invocation-scope.ts +++ b/packages/program/src/functions/base-invocation-scope.ts @@ -297,7 +297,9 @@ export class BaseInvocationScope { await this.fundWithRequiredCoins(maxFee); - const response = await this.program.account.sendTransaction(transactionRequest); + const response = await this.program.account.sendTransaction(transactionRequest, { + awaitExecution: true, + }); return FunctionInvocationResult.build( this.functionInvocationScopes, diff --git a/packages/providers/README.md b/packages/providers/README.md index 7c4fed3c0c..8e1f0aba61 100644 --- a/packages/providers/README.md +++ b/packages/providers/README.md @@ -16,7 +16,7 @@ This module contains common Provider classes and utility functions for connectin ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/providers/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/providers/) ## Usage diff --git a/packages/providers/codegen.json b/packages/providers/codegen.json index 0f48ea8058..d21c27157c 100644 --- a/packages/providers/codegen.json +++ b/packages/providers/codegen.json @@ -7,7 +7,7 @@ "plugins": [ { "typescript": {} }, { "typescript-operations": {} }, - { "typescript-graphql-request": {} } + { "typescript-generic-sdk": {} } ], "config": { "scalars": { diff --git a/packages/providers/package.json b/packages/providers/package.json index 5805692f7b..86f7432ab6 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -39,7 +39,7 @@ "ethers": "^6.7.1", "@fuel-ts/versions": "workspace:*", "graphql": "^16.6.0", - "graphql-request": "^5.0.0", + "graphql-request": "5.0.0", "graphql-tag": "^2.12.6", "ramda": "^0.29.0", "tai64": "^1.0.0" @@ -48,9 +48,9 @@ "@fuel-ts/utils": "workspace:*", "@graphql-codegen/cli": "^2.13.7", "@graphql-codegen/typescript": "^2.8.0", - "@graphql-codegen/typescript-graphql-request": "^4.5.7", "@graphql-codegen/typescript-operations": "^2.5.5", - "@types/ramda": "^0.29.3", - "get-graphql-schema": "^2.1.2" + "@graphql-codegen/typescript-generic-sdk": "^3.1.0", + "get-graphql-schema": "^2.1.2", + "@types/ramda": "^0.29.3" } } diff --git a/packages/providers/src/coin-quantityfy.test.ts b/packages/providers/src/coin-quantityfy.test.ts index 48c866e95e..90ec540c3c 100644 --- a/packages/providers/src/coin-quantityfy.test.ts +++ b/packages/providers/src/coin-quantityfy.test.ts @@ -1,5 +1,8 @@ import { coinQuantityfy } from './coin-quantity'; +/** + * @group node + */ describe('coinQuantityfy', () => { it('should returns 1 when input is < 1', () => { expect(coinQuantityfy([0]).amount.toNumber()).toEqual(1); diff --git a/packages/providers/src/fuel-graphql-subscriber.ts b/packages/providers/src/fuel-graphql-subscriber.ts new file mode 100644 index 0000000000..fb1f80f9a1 --- /dev/null +++ b/packages/providers/src/fuel-graphql-subscriber.ts @@ -0,0 +1,81 @@ +import { FuelError } from '@fuel-ts/errors'; +import type { DocumentNode } from 'graphql'; +import { print } from 'graphql'; + +type FuelGraphQLSubscriberOptions = { + url: string; + query: DocumentNode; + variables?: Record; + fetchFn: typeof fetch; + abortController?: AbortController; +}; + +class FuelSubscriptionStream implements TransformStream { + readable: ReadableStream>; + writable: WritableStream; + private readableStreamController!: ReadableStreamController>; + private static textDecoder = new TextDecoder(); + + constructor() { + this.readable = new ReadableStream({ + start: (controller) => { + this.readableStreamController = controller; + }, + }); + + this.writable = new WritableStream({ + write: (bytes) => { + const text = FuelSubscriptionStream.textDecoder.decode(bytes); + // the fuel node sends keep-alive messages that should be ignored + if (text.startsWith('data:')) { + const { data, errors } = JSON.parse(text.split('data:')[1]); + if (Array.isArray(errors)) { + this.readableStreamController.enqueue( + new FuelError( + FuelError.CODES.INVALID_REQUEST, + errors.map((err) => err.message).join('\n\n') + ) + ); + } else { + this.readableStreamController.enqueue(data); + } + } + }, + }); + } +} + +export async function* fuelGraphQLSubscriber({ + url, + variables, + query, + fetchFn, +}: FuelGraphQLSubscriberOptions) { + const response = await fetchFn(`${url}-sub`, { + method: 'POST', + body: JSON.stringify({ + query: print(query), + variables, + }), + headers: { + 'Content-Type': 'application/json', + Accept: 'text/event-stream', + }, + }); + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const subscriptionStreamReader = response + .body!.pipeThrough(new FuelSubscriptionStream()) + .getReader(); + + while (true) { + const { value, done } = await subscriptionStreamReader.read(); + if (value instanceof FuelError) { + throw value; + } + yield value; + if (done) { + break; + } + } +} diff --git a/packages/providers/src/operations.graphql b/packages/providers/src/operations.graphql index f154d7fb84..a17615a068 100644 --- a/packages/providers/src/operations.graphql +++ b/packages/providers/src/operations.graphql @@ -4,6 +4,31 @@ # generate `operations.ts` from this file. # Fragments + +fragment transactionStatusFragment on TransactionStatus { + type: __typename + ... on SubmittedStatus { + time + } + ... on SuccessStatus { + block { + id + } + time + programState { + returnType + data + } + } + ... on FailureStatus { + block { + id + } + time + reason + } +} + fragment transactionFragment on Transaction { id rawPayload @@ -12,27 +37,7 @@ fragment transactionFragment on Transaction { ...receiptFragment } status { - type: __typename - ... on SubmittedStatus { - time - } - ... on SuccessStatus { - block { - id - } - time - programState { - returnType - data - } - } - ... on FailureStatus { - block { - id - } - time - reason - } + ...transactionStatusFragment } } @@ -675,3 +680,15 @@ mutation produceBlocks( startTimestamp: $startTimestamp ) } + +subscription submitAndAwait($encodedTransaction: HexString!) { + submitAndAwait(tx: $encodedTransaction) { + ...transactionStatusFragment + } +} + +subscription statusChange($transactionId: TransactionId!) { + statusChange(id: $transactionId) { + ...transactionStatusFragment + } +} diff --git a/packages/providers/src/provider.ts b/packages/providers/src/provider.ts index f85cfe3756..91fef5afca 100644 --- a/packages/providers/src/provider.ts +++ b/packages/providers/src/provider.ts @@ -13,6 +13,7 @@ import { import { checkFuelCoreVersionCompatibility } from '@fuel-ts/versions'; import type { BytesLike } from 'ethers'; import { getBytesCopy, hexlify, Network } from 'ethers'; +import type { DocumentNode } from 'graphql'; import { GraphQLClient } from 'graphql-request'; import { clone } from 'ramda'; @@ -26,6 +27,7 @@ import type { import type { Coin } from './coin'; import type { CoinQuantity, CoinQuantityLike } from './coin-quantity'; import { coinQuantityfy } from './coin-quantity'; +import { fuelGraphQLSubscriber } from './fuel-graphql-subscriber'; import { MemoryCache } from './memory-cache'; import type { Message, MessageCoin, MessageProof, MessageStatus } from './message'; import type { ExcludeResourcesOption, Resource } from './resource'; @@ -45,6 +47,8 @@ import { getGasUsedFromReceipts, getReceiptsWithMissingData, } from './utils'; +import type { RetryOptions } from './utils/auto-retry-fetch'; +import { autoRetryFetch } from './utils/auto-retry-fetch'; import { mergeQuantities } from './utils/merge-quantities'; const MAX_RETRIES = 10; @@ -209,8 +213,14 @@ export type FetchRequestOptions = { * Provider initialization options */ export type ProviderOptions = { - fetch?: (url: string, options: FetchRequestOptions) => Promise; + fetch?: ( + url: string, + options: FetchRequestOptions, + providerOptions: Omit + ) => Promise; + timeout?: number; cacheUtxo?: number; + retryOptions?: RetryOptions; }; /** @@ -241,7 +251,16 @@ export type ProviderCallParams = UTXOValidationParams & EstimateTransactionParam /** * Provider Send transaction params */ -export type ProviderSendTxParams = EstimateTransactionParams; +export type ProviderSendTxParams = EstimateTransactionParams & { + /** + * By default, the promise will resolve immediately after the transaction is submitted. + * + * If set to true, the promise will resolve only when the transaction changes status + * from `SubmittedStatus` to one of `SuccessStatus`, `FailureStatus` or `SqueezedOutStatus`. + * + */ + awaitExecution?: boolean; +}; /** * URL - Consensus Params mapping. @@ -268,6 +287,29 @@ export default class Provider { private static chainInfoCache: ChainInfoCache = {}; private static nodeInfoCache: NodeInfoCache = {}; + options: ProviderOptions = { + timeout: undefined, + cacheUtxo: undefined, + fetch: undefined, + retryOptions: undefined, + }; + + private static getFetchFn(options: ProviderOptions): NonNullable { + const { retryOptions, timeout } = options; + + return autoRetryFetch((...args) => { + if (options.fetch) { + return options.fetch(...args); + } + + const url = args[0]; + const request = args[1]; + const signal = timeout ? AbortSignal.timeout(timeout) : undefined; + + return fetch(url, { ...request, signal }); + }, retryOptions); + } + /** * Constructor to initialize a Provider. * @@ -279,9 +321,12 @@ export default class Provider { protected constructor( /** GraphQL endpoint of the Fuel node */ public url: string, - public options: ProviderOptions = {} + options: ProviderOptions = {} ) { - this.operations = this.createOperations(url, options); + this.options = { ...this.options, ...options }; + this.url = url; + + this.operations = this.createOperations(); this.cache = options.cacheUtxo ? new MemoryCache(options.cacheUtxo) : undefined; } @@ -346,7 +391,8 @@ export default class Provider { */ async connect(url: string, options?: ProviderOptions) { this.url = url; - this.operations = this.createOperations(url, options ?? this.options); + this.options = options ?? this.options; + this.operations = this.createOperations(); await this.fetchChainAndNodeInfo(); } @@ -382,14 +428,35 @@ export default class Provider { /** * Create GraphQL client and set operations. * - * @param url - The URL of the Fuel node - * @param options - Additional options for the provider * @returns The operation SDK object */ - private createOperations(url: string, options: ProviderOptions = {}) { - this.url = url; - const gqlClient = new GraphQLClient(url, options.fetch ? { fetch: options.fetch } : undefined); - return getOperationsSdk(gqlClient); + private createOperations() { + const fetchFn = Provider.getFetchFn(this.options); + const gqlClient = new GraphQLClient(this.url, { + fetch: (url: string, requestInit: FetchRequestOptions) => + fetchFn(url, requestInit, this.options), + }); + + const executeQuery = (query: DocumentNode, vars: Record) => { + const opDefinition = query.definitions.find((x) => x.kind === 'OperationDefinition') as { + operation: string; + }; + const isSubscription = opDefinition?.operation === 'subscription'; + + if (isSubscription) { + return fuelGraphQLSubscriber({ + url: this.url, + query, + fetchFn: (url, requestInit) => + fetchFn(url as string, requestInit as FetchRequestOptions, this.options), + variables: vars, + }); + } + return gqlClient.request(query, vars); + }; + + // @ts-expect-error This is due to this function being generic. Its type is specified when calling a specific operation via provider.operations.xyz. + return getOperationsSdk(executeQuery); } /** @@ -506,7 +573,7 @@ export default class Provider { // #region Provider-sendTransaction async sendTransaction( transactionRequestLike: TransactionRequestLike, - { estimateTxDependencies = true }: ProviderSendTxParams = {} + { estimateTxDependencies = true, awaitExecution = false }: ProviderSendTxParams = {} ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); this.#cacheInputs(transactionRequest.inputs); @@ -515,7 +582,6 @@ export default class Provider { } // #endregion Provider-sendTransaction - const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); const { gasUsed, minGasPrice } = await this.getTransactionCost(transactionRequest, [], { estimateTxDependencies: false, estimatePredicates: false, @@ -537,12 +603,27 @@ export default class Provider { ); } + const encodedTransaction = hexlify(transactionRequest.toTransactionBytes()); + + if (awaitExecution) { + const subscription = this.operations.submitAndAwait({ encodedTransaction }); + for await (const { submitAndAwait } of subscription) { + if (submitAndAwait.type !== 'SubmittedStatus') { + break; + } + } + + const transactionId = transactionRequest.getTransactionId(this.getChainId()); + const response = new TransactionResponse(transactionId, this); + await response.fetch(); + return response; + } + const { submit: { id: transactionId }, } = await this.operations.submit({ encodedTransaction }); - const response = new TransactionResponse(transactionId, this); - return response; + return new TransactionResponse(transactionId, this); } /** @@ -794,16 +875,17 @@ export default class Provider { } async getResourcesForTransaction( - owner: AbstractAddress, + owner: string | AbstractAddress, transactionRequestLike: TransactionRequestLike, forwardingQuantities: CoinQuantity[] = [] ) { + const ownerAddress = Address.fromAddressOrString(owner); const transactionRequest = transactionRequestify(clone(transactionRequestLike)); const transactionCost = await this.getTransactionCost(transactionRequest, forwardingQuantities); // Add the required resources to the transaction from the owner transactionRequest.addResources( - await this.getResourcesToSpend(owner, transactionCost.requiredQuantities) + await this.getResourcesToSpend(ownerAddress, transactionCost.requiredQuantities) ); // Refetch transaction costs with the new resources // TODO: we could find a way to avoid fetch estimatePredicates again, by returning the transaction or @@ -815,7 +897,7 @@ export default class Provider { transactionRequest, forwardingQuantities ); - const resources = await this.getResourcesToSpend(owner, requiredQuantities); + const resources = await this.getResourcesToSpend(ownerAddress, requiredQuantities); return { resources, @@ -829,16 +911,17 @@ export default class Provider { */ async getCoins( /** The address to get coins for */ - owner: AbstractAddress, + owner: string | AbstractAddress, /** The asset ID of coins to get */ assetId?: BytesLike, /** Pagination arguments */ paginationArgs?: CursorPaginationArgs ): Promise { + const ownerAddress = Address.fromAddressOrString(owner); const result = await this.operations.getCoins({ first: 10, ...paginationArgs, - filter: { owner: owner.toB256(), assetId: assetId && hexlify(assetId) }, + filter: { owner: ownerAddress.toB256(), assetId: assetId && hexlify(assetId) }, }); const coins = result.coins.edges.map((edge) => edge.node); @@ -864,12 +947,13 @@ export default class Provider { */ async getResourcesToSpend( /** The address to get coins for */ - owner: AbstractAddress, + owner: string | AbstractAddress, /** The quantities to get */ quantities: CoinQuantityLike[], /** IDs of excluded resources from the selection. */ excludedIds?: ExcludeResourcesOption ): Promise { + const ownerAddress = Address.fromAddressOrString(owner); const excludeInput = { messages: excludedIds?.messages?.map((nonce) => hexlify(nonce)) || [], utxos: excludedIds?.utxos?.map((id) => hexlify(id)) || [], @@ -882,7 +966,7 @@ export default class Provider { excludeInput.utxos = Array.from(uniqueUtxos); } const coinsQuery = { - owner: owner.toB256(), + owner: ownerAddress.toB256(), queryPerAsset: quantities .map(coinQuantityfy) .map(({ assetId, amount, max: maxPerAsset }) => ({ @@ -1059,12 +1143,12 @@ export default class Provider { */ async getContractBalance( /** The contract ID to get the balance for */ - contractId: AbstractAddress, + contractId: string | AbstractAddress, /** The asset ID of coins to get */ assetId: BytesLike ): Promise { const { contractBalance } = await this.operations.getContractBalance({ - contract: contractId.toB256(), + contract: Address.fromAddressOrString(contractId).toB256(), asset: hexlify(assetId), }); return bn(contractBalance.amount, 10); @@ -1079,12 +1163,12 @@ export default class Provider { */ async getBalance( /** The address to get coins for */ - owner: AbstractAddress, + owner: string | AbstractAddress, /** The asset ID of coins to get */ assetId: BytesLike ): Promise { const { balance } = await this.operations.getBalance({ - owner: owner.toB256(), + owner: Address.fromAddressOrString(owner).toB256(), assetId: hexlify(assetId), }); return bn(balance.amount, 10); @@ -1099,14 +1183,14 @@ export default class Provider { */ async getBalances( /** The address to get coins for */ - owner: AbstractAddress, + owner: string | AbstractAddress, /** Pagination arguments */ paginationArgs?: CursorPaginationArgs ): Promise { const result = await this.operations.getBalances({ first: 10, ...paginationArgs, - filter: { owner: owner.toB256() }, + filter: { owner: Address.fromAddressOrString(owner).toB256() }, }); const balances = result.balances.edges.map((edge) => edge.node); @@ -1126,14 +1210,14 @@ export default class Provider { */ async getMessages( /** The address to get message from */ - address: AbstractAddress, + address: string | AbstractAddress, /** Pagination arguments */ paginationArgs?: CursorPaginationArgs ): Promise { const result = await this.operations.getMessages({ first: 10, ...paginationArgs, - owner: address.toB256(), + owner: Address.fromAddressOrString(address).toB256(), }); const messages = result.messages.edges.map((edge) => edge.node); diff --git a/packages/providers/src/transaction-request/hash-transaction.test.ts b/packages/providers/src/transaction-request/hash-transaction.test.ts index 25364dbceb..264abf2319 100644 --- a/packages/providers/src/transaction-request/hash-transaction.test.ts +++ b/packages/providers/src/transaction-request/hash-transaction.test.ts @@ -5,6 +5,9 @@ import { SCRIPT_TX_REQUEST } from '../../test/fixtures/transaction-request'; import { hashTransaction } from './hash-transaction'; +/** + * @group node + */ describe('hashTransaction', () => { it('Hash script transaction request', () => { expect(hashTransaction(SCRIPT_TX_REQUEST, 0)).toEqual( diff --git a/packages/providers/src/transaction-request/transaction-request.test.ts b/packages/providers/src/transaction-request/transaction-request.test.ts index 31e3404cf4..422bf88c10 100644 --- a/packages/providers/src/transaction-request/transaction-request.test.ts +++ b/packages/providers/src/transaction-request/transaction-request.test.ts @@ -10,6 +10,9 @@ import { ScriptTransactionRequest } from './script-transaction-request'; import type { TransactionRequestLike } from './types'; import { transactionRequestify } from './utils'; +/** + * @group node + */ describe('TransactionRequest', () => { const assetIdA = '0x0101010101010101010101010101010101010101010101010101010101010101'; const assetIdB = '0x0202020202020202020202020202020202020202020202020202020202020202'; diff --git a/packages/providers/src/transaction-request/transaction-request.ts b/packages/providers/src/transaction-request/transaction-request.ts index 411814b434..3cc5e083d5 100644 --- a/packages/providers/src/transaction-request/transaction-request.ts +++ b/packages/providers/src/transaction-request/transaction-request.ts @@ -226,8 +226,9 @@ export abstract class BaseTransactionRequest implements BaseTransactionRequestLi * @param address - The address to get the coin input witness index for. * @param signature - The signature to update the witness with. */ - updateWitnessByOwner(address: AbstractAddress, signature: BytesLike) { - const witnessIndex = this.getCoinInputWitnessIndexByOwner(address); + updateWitnessByOwner(address: string | AbstractAddress, signature: BytesLike) { + const ownerAddress = Address.fromAddressOrString(address); + const witnessIndex = this.getCoinInputWitnessIndexByOwner(ownerAddress); if (typeof witnessIndex === 'number') { this.updateWitness(witnessIndex, signature); } diff --git a/packages/providers/src/transaction-response/transaction-response.ts b/packages/providers/src/transaction-response/transaction-response.ts index d356b3e88f..a073188702 100644 --- a/packages/providers/src/transaction-response/transaction-response.ts +++ b/packages/providers/src/transaction-response/transaction-response.ts @@ -29,7 +29,6 @@ import type { GqlTransaction, AbiMap, } from '../transaction-summary/types'; -import { sleep } from '../utils'; /** @hidden */ export type TransactionResultCallReceipt = ReceiptCall; @@ -72,9 +71,6 @@ export type TransactionResultReceipt = | TransactionResultMintReceipt | TransactionResultBurnReceipt; -const STATUS_POLLING_INTERVAL_MAX_MS = 5000; -const STATUS_POLLING_INTERVAL_MIN_MS = 1000; - /** @hidden */ export type TransactionResult = TransactionSummary & { gqlTransaction: GqlTransaction; @@ -90,10 +86,6 @@ export class TransactionResponse { provider: Provider; /** Gas used on the transaction */ gasUsed: BN = bn(0); - /** Number of attempts made to fetch the transaction */ - fetchAttempts: number = 0; - /** Number of attempts made to retrieve a processed transaction. */ - resultAttempts: number = 0; /** The graphql Transaction with receipts object. */ gqlTransaction?: GqlTransaction; @@ -133,7 +125,16 @@ export class TransactionResponse { }); if (!response.transaction) { - await this.sleepBasedOnAttempts(++this.fetchAttempts); + const subscription = this.provider.operations.statusChange({ + transactionId: this.id, + }); + + for await (const { statusChange } of subscription) { + if (statusChange) { + break; + } + } + return this.fetch(); } @@ -196,6 +197,25 @@ export class TransactionResponse { return transactionSummary; } + private async waitForStatusChange() { + const status = this.gqlTransaction?.status?.type; + if (status && status !== 'SubmittedStatus') { + return; + } + + const subscription = this.provider.operations.statusChange({ + transactionId: this.id, + }); + + for await (const { statusChange } of subscription) { + if (statusChange.type !== 'SubmittedStatus') { + break; + } + } + + await this.fetch(); + } + /** * Waits for transaction to complete and returns the result. * @@ -204,13 +224,7 @@ export class TransactionResponse { async waitForResult( contractsAbiMap?: AbiMap ): Promise> { - await this.fetch(); - - if (this.gqlTransaction?.status?.type === 'SubmittedStatus') { - await this.sleepBasedOnAttempts(++this.resultAttempts); - - return this.waitForResult(contractsAbiMap); - } + await this.waitForStatusChange(); const transactionSummary = await this.getTransactionSummary(contractsAbiMap); @@ -241,18 +255,4 @@ export class TransactionResponse { return result; } - - /** - * Introduces a delay based on the number of previous attempts made. - * - * @param attempts - The number of attempts. - */ - private async sleepBasedOnAttempts(attempts: number): Promise { - // TODO: Consider adding `maxTimeout` or `maxAttempts` parameter. - // The aim is to avoid perpetual execution; when the limit - // is reached, we can throw accordingly. - await sleep( - Math.min(STATUS_POLLING_INTERVAL_MIN_MS * attempts, STATUS_POLLING_INTERVAL_MAX_MS) - ); - } } diff --git a/packages/providers/src/transaction-summary/assemble-transaction-summary.test.ts b/packages/providers/src/transaction-summary/assemble-transaction-summary.test.ts index 49a06b5dd7..ca4ea11493 100644 --- a/packages/providers/src/transaction-summary/assemble-transaction-summary.test.ts +++ b/packages/providers/src/transaction-summary/assemble-transaction-summary.test.ts @@ -19,8 +19,12 @@ import Provider from '../provider'; import type { TransactionResultReceipt } from '../transaction-response'; import { assembleTransactionSummary } from './assemble-transaction-summary'; +import * as calculateTransactionFeeMod from './calculate-transaction-fee'; import type { GraphqlTransactionStatus, Operation } from './types'; +/** + * @group node + */ describe('TransactionSummary', () => { let provider: Provider; let gasCosts: GqlGasCosts; @@ -44,7 +48,28 @@ describe('TransactionSummary', () => { gasCosts = provider.getChain().gasCosts; }); + beforeEach(() => { + vi.resetAllMocks(); + }); + + const mockCalculateTransactionFee = () => { + const calculateTransactionFee = vi + .spyOn(calculateTransactionFeeMod, 'calculateTransactionFee') + .mockReturnValue({ + fee: bn(0), + minFee: bn(0), + maxFee: bn(0), + feeFromGasUsed: bn(0), + }); + + return { + calculateTransactionFee, + }; + }; + const runTest = (status: GraphqlTransactionStatus, expected: Record) => { + const { calculateTransactionFee } = mockCalculateTransactionFee(); + const transactionSummary = assembleTransactionSummary({ id, gasPerByte, @@ -59,6 +84,7 @@ describe('TransactionSummary', () => { }); expect(transactionSummary).toMatchObject(expected); + expect(calculateTransactionFee).toHaveBeenCalledTimes(1); }; it('should assemble transaction summary just fine (SUCCESS)', () => { diff --git a/packages/providers/src/transaction-summary/calculate-transaction-fee.test.ts b/packages/providers/src/transaction-summary/calculate-transaction-fee.test.ts index fd3007b838..096ed6b2ea 100644 --- a/packages/providers/src/transaction-summary/calculate-transaction-fee.test.ts +++ b/packages/providers/src/transaction-summary/calculate-transaction-fee.test.ts @@ -9,6 +9,9 @@ import { import { calculateTransactionFee } from './calculate-transaction-fee'; +/** + * @group node + */ describe('calculateTransactionFee', () => { it('should properly calculate the transaction fee (SCRIPT TX)', () => { const transactionRawPayload = MOCK_TX_SCRIPT_RAW_PAYLOAD; diff --git a/packages/providers/src/transaction-summary/date.test.ts b/packages/providers/src/transaction-summary/date.test.ts index dcd29bbb89..549f6809cb 100644 --- a/packages/providers/src/transaction-summary/date.test.ts +++ b/packages/providers/src/transaction-summary/date.test.ts @@ -4,12 +4,17 @@ import * as dateMod from './date'; const { fromTai64ToDate: tai64toDate, fromDateToTai64: dateToTai64 } = dateMod; +/** + * @group node + */ describe('transaction-summary/date', () => { - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); it('should convert TAI64 to Date correctly', () => { - const fromStringSpy = jest.spyOn(tai64Mod.TAI64, 'fromString'); - const toUnixSpy = jest.spyOn(tai64Mod.TAI64.prototype, 'toUnix'); + const fromStringSpy = vi.spyOn(tai64Mod.TAI64, 'fromString'); + const toUnixSpy = vi.spyOn(tai64Mod.TAI64.prototype, 'toUnix'); const tai64Timestamp = '4611686020121838636'; @@ -22,8 +27,8 @@ describe('transaction-summary/date', () => { }); it('should convert Date to TAI64 correctly', () => { - const fromUnixSpy = jest.spyOn(tai64Mod.TAI64, 'fromUnix'); - const toStringSpy = jest.spyOn(tai64Mod.TAI64.prototype, 'toString'); + const fromUnixSpy = vi.spyOn(tai64Mod.TAI64, 'fromUnix'); + const toStringSpy = vi.spyOn(tai64Mod.TAI64.prototype, 'toString'); const date = new Date(); diff --git a/packages/providers/src/transaction-summary/input.test.ts b/packages/providers/src/transaction-summary/input.test.ts index 892c361792..773847c29a 100644 --- a/packages/providers/src/transaction-summary/input.test.ts +++ b/packages/providers/src/transaction-summary/input.test.ts @@ -17,6 +17,9 @@ import { getInputsMessage, } from './input'; +/** + * @group node + */ describe('transaction-summary/input', () => { it('should ensure getInputsCoin return correct inputs', () => { const coinInputs = getInputsCoin([MOCK_INPUT_COIN, MOCK_INPUT_CONTRACT, MOCK_INPUT_MESSAGE]); diff --git a/packages/providers/src/transaction-summary/operations.test.ts b/packages/providers/src/transaction-summary/operations.test.ts index 2b30c56840..c6a3167839 100644 --- a/packages/providers/src/transaction-summary/operations.test.ts +++ b/packages/providers/src/transaction-summary/operations.test.ts @@ -1,3 +1,4 @@ +import { getRandomB256 } from '@fuel-ts/address'; import { bn } from '@fuel-ts/math'; import { ReceiptType, TransactionType } from '@fuel-ts/transactions'; @@ -49,6 +50,9 @@ import { import type { Operation } from './types'; import { AddressType, OperationName, TransactionTypeName, ChainName } from './types'; +/** + * @group node + */ describe('operations', () => { describe('getContractCallOperations', () => { it('should ensure getContractCallOperations return contract call operations', () => { @@ -719,6 +723,9 @@ describe('operations', () => { const fromAddress = getInputAccountAddress(coinInput[0]); + const assetA = '0x0101010101010101010101010101010101010101010101010101010101010101'; + const assetB = '0x0202020202020202020202020202020202020202020202020202020202020202'; + const OPERATION_CONTRACT_CALL = { name: OperationName.contractCall, from: { @@ -746,6 +753,24 @@ describe('operations', () => { ], }; + const OPERATION_TRANSFER = { + name: OperationName.transfer, + from: { + type: 1, + address: getRandomB256(), + }, + to: { + type: 1, + address: getRandomB256(), + }, + assetsSent: [ + { + assetId: '0x0101010101010101010101010101010101010101010101010101010101010101', + amount: bn(100), + }, + ], + }; + it('should just add operation when its the first one', () => { const operations = addOperation([], OPERATION_CONTRACT_CALL); expect(operations.length).toEqual(1); @@ -805,6 +830,7 @@ describe('operations', () => { JSON.parse(JSON.stringify(baseOperations[0].assetsSent)) ); }); + it('should stack when same asset is added', () => { const baseOperations = addOperation([], OPERATION_CONTRACT_CALL); const operationsAddedSameAsset = addOperation(baseOperations, OPERATION_CONTRACT_CALL); @@ -816,7 +842,8 @@ describe('operations', () => { OPERATION_CONTRACT_CALL.assetsSent[0].assetId ); }); - it('should stack when same asset is added together with a different asset', () => { + + it('should stack when same asset is added together with a different asset [CONTRACT-CALL]', () => { const DIF_ASSET_ID = '0x0012300000000000000000000000000000000001'; const operationTwoAssets: Operation = { ...OPERATION_CONTRACT_CALL, @@ -845,6 +872,108 @@ describe('operations', () => { ); expect(operationsAddedSameAsset[0].assetsSent?.[1]?.assetId).toEqual(DIF_ASSET_ID); }); + + it('ensure operation asset transfer stacks multiple assetSents between same addresses', () => { + const operationOne: Operation = { + ...OPERATION_TRANSFER, + assetsSent: [ + { + assetId: assetA, + amount: bn(100), + }, + ], + }; + + const operationTwo: Operation = { + ...OPERATION_TRANSFER, + assetsSent: [ + { + assetId: assetB, + amount: bn(200), + }, + ], + }; + + const baseOperations = addOperation([], operationOne); + const stackedOperation = addOperation(baseOperations, operationTwo); + + expect(stackedOperation.length).toEqual(1); + expect(stackedOperation[0].assetsSent?.length).toEqual(2); + expect(stackedOperation[0].assetsSent?.[0]?.amount.valueOf()).toEqual( + operationOne.assetsSent?.[0]?.amount.valueOf() + ); + expect(stackedOperation[0].assetsSent?.[0]?.assetId).toEqual( + operationOne.assetsSent?.[0].assetId + ); + expect(stackedOperation[0].assetsSent?.[1]?.amount.valueOf()).toEqual( + operationTwo.assetsSent?.[0]?.amount.valueOf() + ); + expect(stackedOperation[0].assetsSent?.[1]?.assetId).toEqual( + operationTwo.assetsSent?.[0].assetId + ); + }); + + it('ensure operation asset transfer does not stack multiple assetSents between different addresses', () => { + const fromOne = getRandomB256(); + const fromTwo = getRandomB256(); + const toAddress2 = getRandomB256(); + + const operationOne: Operation = { + ...OPERATION_TRANSFER, + from: { + address: fromOne, + type: 1, + }, + to: { + address: toAddress2, + type: 1, + }, + assetsSent: [ + { + assetId: assetA, + amount: bn(100), + }, + ], + }; + + const operationTwo: Operation = { + ...OPERATION_TRANSFER, + from: { + address: fromTwo, + type: 1, + }, + to: { + address: toAddress2, + type: 1, + }, + assetsSent: [ + { + assetId: assetB, + amount: bn(200), + }, + ], + }; + + const baseOperation = addOperation([], operationOne); + const multipleOperations = addOperation(baseOperation, operationTwo); + + expect(multipleOperations.length).toEqual(2); + expect(multipleOperations[0].assetsSent?.length).toEqual(1); + expect(multipleOperations[0].assetsSent?.[0]?.amount.valueOf()).toEqual( + operationOne.assetsSent?.[0]?.amount.valueOf() + ); + expect(multipleOperations[0].assetsSent?.[0]?.assetId).toEqual( + operationOne.assetsSent?.[0].assetId + ); + expect(multipleOperations[1].assetsSent?.length).toEqual(1); + expect(multipleOperations[1].assetsSent?.[0]?.amount.valueOf()).toEqual( + operationTwo.assetsSent?.[0]?.amount.valueOf() + ); + expect(multipleOperations[1].assetsSent?.[0]?.assetId).toEqual( + operationTwo.assetsSent?.[0].assetId + ); + }); + it('should always not stack for contract calls', () => { const baseOperations = addOperation([], OPERATION_CONTRACT_CALL); const operationsAddedSameContractCall = addOperation(baseOperations, OPERATION_CONTRACT_CALL); @@ -963,7 +1092,7 @@ describe('operations', () => { }); }); - describe('should ensure getTransactionTypeName works as expected', () => { + it('should ensure getTransactionTypeName works as expected', () => { expect(getTransactionTypeName(TransactionType.Create)).toBe(TransactionTypeName.Create); expect(getTransactionTypeName(TransactionType.Mint)).toBe(TransactionTypeName.Mint); expect(getTransactionTypeName(TransactionType.Script)).toBe(TransactionTypeName.Script); diff --git a/packages/providers/src/transaction-summary/operations.ts b/packages/providers/src/transaction-summary/operations.ts index 23a78efcf0..f921322d75 100644 --- a/packages/providers/src/transaction-summary/operations.ts +++ b/packages/providers/src/transaction-summary/operations.ts @@ -103,16 +103,27 @@ export function getReceiptsMessageOut(receipts: TransactionResultReceipt[]) { const mergeAssets = (op1: Operation, op2: Operation) => { const assets1 = op1.assetsSent || []; const assets2 = op2.assetsSent || []; - const filtered = assets2.filter((c) => !assets1.some(hasSameAssetId(c))); - return assets1 - .map((coin) => { - const asset = assets2.find(hasSameAssetId(coin)); - if (!asset) { - return coin; - } - return { ...coin, amount: bn(coin.amount).add(asset.amount) }; - }) - .concat(filtered); + + // Getting assets from op2 that don't exist in op1 + const filteredAssets = assets2.filter( + (asset2) => !assets1.some((asset1) => asset1.assetId === asset2.assetId) + ); + + // Merge assets that already exist in op1 + const mergedAssets = assets1.map((asset1) => { + // Find matching asset in op2 + const matchingAsset = assets2.find((asset2) => asset2.assetId === asset1.assetId); + if (!matchingAsset) { + // No matching asset found, return asset1 + return asset1; + } + // Matching asset found, merge amounts + const mergedAmount = bn(asset1.amount).add(matchingAsset.amount); + return { ...asset1, amount: mergedAmount }; + }); + + // Return merged assets from op1 with filtered assets from op2 + return mergedAssets.concat(filteredAssets); }; /** @hidden */ @@ -128,43 +139,37 @@ function isSameOperation(a: Operation, b: Operation) { /** @hidden */ export function addOperation(operations: Operation[], toAdd: Operation) { - const ops = operations - .map((op) => { - // if it's not same operation, don't change. we just wanna stack the same operation - if (!isSameOperation(op, toAdd)) { - return null; - } - - let newOp = { ...op }; - - // if it's adding new assets - if (toAdd.assetsSent?.length) { - // if prev op had assets, merge them. Otherwise just add the new assets - newOp = { - ...newOp, - assetsSent: op.assetsSent?.length ? mergeAssets(op, toAdd) : toAdd.assetsSent, - }; - } + const allOperations = [...operations]; + + // Verifying if the operation to add already exists. + const index = allOperations.findIndex((op) => isSameOperation(op, toAdd)); + + if (allOperations[index]) { + // Existent operation, we want to edit it. + const existentOperation = { ...allOperations[index] }; + + if (toAdd.assetsSent?.length) { + /** + * If the assetSent already exists, we call 'mergeAssets' to merge possible + * entries of the same 'assetId', otherwise we just add the new 'assetSent'. + */ + existentOperation.assetsSent = existentOperation.assetsSent?.length + ? mergeAssets(existentOperation, toAdd) + : toAdd.assetsSent; + } - // if it's adding new calls, - if (toAdd.calls?.length) { - /* -[] for calls we don't stack as grouping is not desired. - we wanna show all calls in the same operation - with each respective assets, amounts, functions, arguments. - */ - newOp = { - ...newOp, - calls: [...(op.calls || []), ...(toAdd.calls || [])], - }; - } + if (toAdd.calls?.length) { + // We need to stack the new call(s) with the possible existent ones. + existentOperation.calls = [...(existentOperation.calls || []), ...toAdd.calls]; + } - return newOp; - }) - .filter(Boolean) as Operation[]; + allOperations[index] = existentOperation; + } else { + // New operation, we can simply add it. + allOperations.push(toAdd); + } - // if this operation didn't exist before just add it to the end - return ops.length ? ops : [...operations, toAdd]; + return allOperations; } /** @hidden */ @@ -372,7 +377,8 @@ export function getTransferOperations({ const input = getInputFromAssetId(inputs, output.assetId); if (input) { const inputAddress = getInputAccountAddress(input); - operations = addOperation(operations, { + + const operationToAdd: Operation = { name: OperationName.transfer, from: { type: AddressType.account, @@ -388,7 +394,9 @@ export function getTransferOperations({ amount: output.amount, }, ], - }); + }; + + operations = addOperation(operations, operationToAdd); } }); } diff --git a/packages/providers/src/transaction-summary/output.test.ts b/packages/providers/src/transaction-summary/output.test.ts index f3afd64b33..f4aceb3cfc 100644 --- a/packages/providers/src/transaction-summary/output.test.ts +++ b/packages/providers/src/transaction-summary/output.test.ts @@ -14,6 +14,9 @@ import { getOutputsVariable, } from './output'; +/** + * @group node + */ describe('transaction-summary/output', () => { it('should ensure getOutputsCoin return correct outputs', () => { const coinsOutputs = getOutputsCoin([ diff --git a/packages/providers/src/transaction-summary/receipt.test.ts b/packages/providers/src/transaction-summary/receipt.test.ts index 3f9f532a15..3f71a8f316 100644 --- a/packages/providers/src/transaction-summary/receipt.test.ts +++ b/packages/providers/src/transaction-summary/receipt.test.ts @@ -10,6 +10,9 @@ import type { import { extractBurnedAssetsFromReceipts, extractMintedAssetsFromReceipts } from './receipt'; import type { MintedAsset, BurnedAsset } from './types'; +/** + * @group node + */ describe('extractMintedAssetsFromReceipts and extractBurnedAssetsFromReceipts', () => { it('should extracts minted and burned assets just fine', () => { // Sample input diff --git a/packages/providers/src/transaction-summary/status.test.ts b/packages/providers/src/transaction-summary/status.test.ts index f5194645e2..b3050375c0 100644 --- a/packages/providers/src/transaction-summary/status.test.ts +++ b/packages/providers/src/transaction-summary/status.test.ts @@ -9,6 +9,9 @@ import { getTransactionStatusName, processGraphqlStatus } from './status'; import type { GqlTransactionStatusesNames, GraphqlTransactionStatus } from './types'; import { TransactionStatus } from './types'; +/** + * @group node + */ describe('status', () => { it('should ensure getTransactionStatusName return status name just fine', () => { let status = getTransactionStatusName('FailureStatus'); diff --git a/packages/providers/src/utils/auto-retry-fetch.test.ts b/packages/providers/src/utils/auto-retry-fetch.test.ts new file mode 100644 index 0000000000..db3526fac5 --- /dev/null +++ b/packages/providers/src/utils/auto-retry-fetch.test.ts @@ -0,0 +1,130 @@ +import { safeExec } from '@fuel-ts/errors/test-utils'; + +import type { FetchRequestOptions } from '../provider'; + +import type { RetryOptions } from './auto-retry-fetch'; +import { autoRetryFetch, getWaitDelay } from './auto-retry-fetch'; + +/** + * @group node + * @group browser + */ +describe('getWaitDelay', () => { + const maxRetries = 10; + const baseDelay = 10; + + it('should get wait delay for linear backoff strategy', () => { + const options: RetryOptions = { maxRetries, baseDelay, backoff: 'linear' }; + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = getWaitDelay(options, attempt); + expect(delay).toEqual(baseDelay * attempt); // linear + } + }); + + it('should get wait delay for fixed backoff strategy', () => { + const options: RetryOptions = { maxRetries, baseDelay, backoff: 'fixed' }; + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = getWaitDelay(options, attempt); + expect(delay).toEqual(baseDelay); // fixed + } + }); + + it('should get wait delay for exponential backoff strategy', () => { + const options: RetryOptions = { maxRetries, baseDelay, backoff: 'exponential' }; + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = getWaitDelay(options, attempt); + expect(delay).toEqual(2 ** (attempt - 1) * baseDelay); // exponential + } + }); + + it('default strategy should be exponential', () => { + const options: RetryOptions = { maxRetries, baseDelay }; // omitting `backoff` + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = getWaitDelay(options, attempt); + expect(delay).toEqual(2 ** (attempt - 1) * baseDelay); // exponential + } + }); + + it('default baseDelay should be 150', () => { + const defaultDuration = 150; + const options: RetryOptions = { maxRetries, backoff: 'fixed' }; // omitting `baseDelay` + for (let attempt = 1; attempt <= maxRetries; attempt++) { + const delay = getWaitDelay(options, attempt); + expect(delay).toEqual(defaultDuration); + } + }); +}); + +describe('autoRetryFetch', () => { + const url = 'http://anythibng.com'; + const fetchOptions: FetchRequestOptions = { method: 'POST', headers: {}, body: '' }; + + const maxRetries = 5; + const baseDelay = 1; + const retryOptions: RetryOptions = { maxRetries, baseDelay, backoff: 'fixed' }; + + const econnRefusedError = new Error(); + econnRefusedError.cause = { code: 'ECONNREFUSED' }; + + it('should not wrap function by default', async () => { + const fn = vi.fn(() => { + throw new Error('anything'); + }); + + const autoRetry = autoRetryFetch(fn); + + const { error, result } = await safeExec(async () => autoRetry(url, fetchOptions, {})); + + expect(fn).toHaveBeenCalledTimes(1); + expect(result).toBeFalsy(); + expect(error).toMatch(/anything/); + }); + + it('should retry until maxRetries and fail', async () => { + const fn = vi.fn(() => { + throw econnRefusedError; + }); + + const autoRetry = autoRetryFetch(fn, retryOptions); + + const { error, result } = await safeExec(async () => autoRetry(url, fetchOptions, {})); + + expect(fn).toHaveBeenCalledTimes(1 + maxRetries); // 1st call is not a retry + expect(result).toBeFalsy(); + expect(error).toBe(econnRefusedError); + }); + + it('should retry until maxRetries and succeed', async () => { + let retries = 0; + + const fn = vi.fn(() => { + if (retries < maxRetries) { + retries += 1; + throw econnRefusedError; + } + return Promise.resolve(new Response()); + }); + + const autoRetry = autoRetryFetch(fn, retryOptions); + + const { error, result } = await safeExec(async () => autoRetry(url, fetchOptions, {})); + + expect(fn).toHaveBeenCalledTimes(1 + maxRetries); // 1st call is not a retry + expect(result).toBeInstanceOf(Response); + expect(error).toBeFalsy(); + }); + + it('throws if error is not ECONNREFUSED and it does not retry', async () => { + const fn = vi.fn(() => { + throw new Error('anything'); + }); + + const autoRetry = autoRetryFetch(fn, retryOptions); + + const { error, result } = await safeExec(async () => autoRetry(url, fetchOptions, {})); + + expect(fn).toHaveBeenCalledTimes(1); + expect(result).toBeFalsy(); + expect(error?.message).toMatch(/anything/); + }); +}); diff --git a/packages/providers/src/utils/auto-retry-fetch.ts b/packages/providers/src/utils/auto-retry-fetch.ts new file mode 100644 index 0000000000..a3a7a9ef98 --- /dev/null +++ b/packages/providers/src/utils/auto-retry-fetch.ts @@ -0,0 +1,87 @@ +import type { ProviderOptions } from '../provider'; + +import { sleep } from './sleep'; + +type Backoff = 'linear' | 'exponential' | 'fixed'; + +/** + * Retry options scheme + */ +export type RetryOptions = { + /** + * Amount of attempts to retry before failing the call. + */ + maxRetries: number; + /** + * Backoff strategy to use when retrying. Default is exponential. + */ + backoff?: Backoff; + /** + * Starting delay for backoff strategy. Default is 150ms. + */ + baseDelay?: number; +}; + +/** + * Calculate the delay for the next retry attempt + * @param options - Retry options configuration + * @param retryAttemptNum - 1-based, tells which retry attempt is this + * @returns Next wait delay + */ +export function getWaitDelay(options: RetryOptions, retryAttemptNum: number) { + const duration = options.baseDelay ?? 150; + + switch (options.backoff) { + case 'linear': + return duration * retryAttemptNum; + case 'fixed': + return duration; + case 'exponential': + default: + return 2 ** (retryAttemptNum - 1) * duration; + } +} + +/** + * Returns a wrapped fetch function that will auto-execute itself in case of errors, until it succeeds + * @param fetchFn - Function to be auto-retried + * @param options - Retry options configuration + * @param retryAttemptNum - ZERO=first call, ONE=first retry, TWO=second retry, etc. + * @returns Whatever is the output of the `fetchFn` function + */ +export function autoRetryFetch( + fetchFn: NonNullable, + options?: RetryOptions, + retryAttemptNum: number = 0 +): NonNullable { + if (options === undefined) { + return fetchFn; + } + + return async (...args) => { + try { + return await fetchFn(...args); + } catch (_error: unknown) { + const error = _error as Error & { cause?: { code: string } }; + + /** + * So far, we are auto-retrying only for `ECONNREFUSED` error. + * TODO: Investigate if we should consider more errors. + */ + if (error.cause?.code !== 'ECONNREFUSED') { + throw error; + } + const retryNum = retryAttemptNum + 1; + + if (retryNum > options.maxRetries) { + throw error; + } + + const delay = getWaitDelay(options, retryNum); + + await sleep(delay); + + return autoRetryFetch(fetchFn, options, retryNum)(...args); + } + }; +} diff --git a/packages/providers/src/utils/block-explorer.test.ts b/packages/providers/src/utils/block-explorer.test.ts index 4409ea4ba9..3ce7c990b7 100644 --- a/packages/providers/src/utils/block-explorer.test.ts +++ b/packages/providers/src/utils/block-explorer.test.ts @@ -28,6 +28,9 @@ const testBlockExplorerUrlWithInputs = ({ expect(url).toEqual(expectedUrl); }; +/** + * @group node + */ describe('BlockExplorer Utils', () => { test('buildBlockExplorerUrl - empty/undefined inputs', () => { expect(buildBlockExplorerUrl()).toEqual(`${DEFAULT_BLOCK_EXPLORER_URL}/`); diff --git a/packages/providers/src/utils/gas.test.ts b/packages/providers/src/utils/gas.test.ts index edca491e36..9857395941 100644 --- a/packages/providers/src/utils/gas.test.ts +++ b/packages/providers/src/utils/gas.test.ts @@ -29,6 +29,9 @@ import { resolveGasDependentCosts, } from './gas'; +/** + * @group node + */ describe('gas', () => { describe('resolveGasDependentCosts', () => { it('calculates cost correctly for LightOperation', () => { diff --git a/packages/providers/src/utils/json.test.ts b/packages/providers/src/utils/json.test.ts index 89664630cb..931d1aec05 100644 --- a/packages/providers/src/utils/json.test.ts +++ b/packages/providers/src/utils/json.test.ts @@ -3,6 +3,9 @@ import { BN, bn } from '@fuel-ts/math'; import { normalizeJSON } from './json'; +/** + * @group node + */ describe('JSON parser', () => { test('normalizeJSON object', () => { const bytesValue = Uint8Array.from([1, 2, 3, 4]); diff --git a/packages/providers/src/utils/merge-quantities.test.ts b/packages/providers/src/utils/merge-quantities.test.ts index 6c818d5a31..493658129e 100644 --- a/packages/providers/src/utils/merge-quantities.test.ts +++ b/packages/providers/src/utils/merge-quantities.test.ts @@ -4,6 +4,9 @@ import type { CoinQuantity } from '../coin-quantity'; import { mergeQuantities } from './merge-quantities'; +/** + * @group node + */ describe('mergeQuantities', () => { const assetIdA = '0x0101010101010101010101010101010101010101010101010101010101010101'; const assetIdB = '0x0202020202020202020202020202020202020202020202020202020202020202'; diff --git a/packages/providers/src/utils/receipts.test.ts b/packages/providers/src/utils/receipts.test.ts index 3a8bebc372..1d3bc76b0e 100644 --- a/packages/providers/src/utils/receipts.test.ts +++ b/packages/providers/src/utils/receipts.test.ts @@ -25,6 +25,9 @@ import { GqlReceiptType } from '../__generated__/operations'; import { assembleReceiptByType } from './receipts'; +/** + * @group node + */ describe('assembleReceiptByType', () => { it('should return a ReceiptCall receipt when GqlReceiptType.Call is provided', () => { const receipt = assembleReceiptByType({ diff --git a/packages/providers/src/utils/time.test.ts b/packages/providers/src/utils/time.test.ts index 8f4f3ec84f..182b4c044c 100644 --- a/packages/providers/src/utils/time.test.ts +++ b/packages/providers/src/utils/time.test.ts @@ -1,5 +1,8 @@ import { fromTai64ToUnix, fromUnixToTai64 } from './time'; +/** + * @group node + */ test('fromTai64ToUnix', () => { expect(fromTai64ToUnix('4611686020108779312')).toEqual(1681391398); }); diff --git a/packages/providers/test/__snapshots__/provider.test.ts.snap b/packages/providers/test/__snapshots__/provider.test.ts.snap index e9106af6f4..30aaf5b14e 100644 --- a/packages/providers/test/__snapshots__/provider.test.ts.snap +++ b/packages/providers/test/__snapshots__/provider.test.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Provider can getMessageProof with all data 1`] = ` +exports[`Provider > can getMessageProof with all data 1`] = ` { "amount": "0xa", "blockProof": { @@ -50,7 +50,7 @@ exports[`Provider can getMessageProof with all data 1`] = ` } `; -exports[`Provider can getMessageStatus 1`] = ` +exports[`Provider > can getMessageStatus 1`] = ` { "state": "SPENT", } diff --git a/packages/providers/test/auto-retry-fetch.test.ts b/packages/providers/test/auto-retry-fetch.test.ts new file mode 100644 index 0000000000..cb0d6b7717 --- /dev/null +++ b/packages/providers/test/auto-retry-fetch.test.ts @@ -0,0 +1,33 @@ +import Provider from '../src/provider'; +import type { RetryOptions } from '../src/utils/auto-retry-fetch'; +import * as autoRetryFetchMod from '../src/utils/auto-retry-fetch'; + +// TODO: Figure out a way to import this constant from `@fuel-ts/wallet/configs` +const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; + +/** + * @group node + * TODO: add browser group as well (https://github.com/FuelLabs/fuels-ts/pull/1654#discussion_r1456501593) + */ +describe('Provider correctly', () => { + afterEach(() => { + vi.restoreAllMocks(); + }); + + test('Provider should always wrap `fetchFn`', async () => { + const autoRetryFetchFn = vi.spyOn(autoRetryFetchMod, 'autoRetryFetch'); + + // #region provider-retry-options + const retryOptions: RetryOptions = { + maxRetries: 5, + baseDelay: 100, + backoff: 'exponential', + }; + + const provider = await Provider.create(FUEL_NETWORK_URL, { retryOptions }); + // #endregion provider-retry-options + + expect(provider).toBeTruthy(); + expect(autoRetryFetchFn).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/providers/test/memory-cache.test.ts b/packages/providers/test/memory-cache.test.ts index 0c4c31f22f..d4060528a3 100644 --- a/packages/providers/test/memory-cache.test.ts +++ b/packages/providers/test/memory-cache.test.ts @@ -6,6 +6,10 @@ import { MemoryCache } from '../src/memory-cache'; const CACHE_ITEMS = [hexlify(randomBytes(8)), randomBytes(8), randomBytes(8)]; +/** + * @group node + * @group browser + */ describe('Memory Cache', () => { it('can construct [valid numerical ttl]', () => { const memCache = new MemoryCache(1000); diff --git a/packages/providers/test/provider.test.ts b/packages/providers/test/provider.test.ts index 24e3ac66c0..95cc533939 100644 --- a/packages/providers/test/provider.test.ts +++ b/packages/providers/test/provider.test.ts @@ -10,30 +10,39 @@ import { versions } from '@fuel-ts/versions'; import * as fuelTsVersionsMod from '@fuel-ts/versions'; import { getBytesCopy, hexlify } from 'ethers'; import type { BytesLike } from 'ethers'; -import * as GraphQL from 'graphql-request'; -import type { TransactionCost } from '../src/provider'; +import { fromTai64ToDate } from '../src'; +import type { ChainInfo, NodeInfo, TransactionCost, FetchRequestOptions } from '../src/provider'; import Provider from '../src/provider'; import type { CoinTransactionRequestInput, MessageTransactionRequestInput, } from '../src/transaction-request'; -import { CreateTransactionRequest, ScriptTransactionRequest } from '../src/transaction-request'; -import { fromTai64ToUnix, fromUnixToTai64 } from '../src/utils'; +import { ScriptTransactionRequest, CreateTransactionRequest } from '../src/transaction-request'; +import { TransactionResponse } from '../src/transaction-response'; +import { fromTai64ToUnix, fromUnixToTai64, sleep } from '../src/utils'; import * as gasMod from '../src/utils/gas'; import { messageProofResponse, messageStatusResponse } from './fixtures'; -import { MOCK_CHAIN } from './fixtures/chain'; -import { MOCK_NODE_INFO } from './fixtures/nodeInfo'; -// https://stackoverflow.com/a/72885576 -jest.mock('@fuel-ts/versions', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/versions'), -})); +vi.mock('@fuel-ts/versions', async () => { + const mod = await vi.importActual('@fuel-ts/versions'); + return { + __esModule: true, + ...mod, + }; +}); + +vi.mock('@fuel-ts/math', async () => { + const mod = await vi.importActual('@fuel-ts/math'); + return { + __esModule: true, + ...mod, + }; +}); afterEach(() => { - jest.restoreAllMocks(); + vi.restoreAllMocks(); }); const getCustomFetch = @@ -63,6 +72,9 @@ const getCustomFetch = // TODO: Figure out a way to import this constant from `@fuel-ts/wallet/configs` const FUEL_NETWORK_URL = 'http://127.0.0.1:4000/graphql'; +/** + * @group node + */ describe('Provider', () => { it('can getVersion()', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); @@ -209,32 +221,27 @@ describe('Provider', () => { const providerUrl1 = FUEL_NETWORK_URL; const providerUrl2 = 'http://127.0.0.1:8080/graphql'; - const provider = await Provider.create(providerUrl1); + const provider = await Provider.create(providerUrl1, { + fetch: (url: string, options: FetchRequestOptions) => + getCustomFetch('getVersion', { nodeInfo: { nodeVersion: url } })(url, options), + }); expect(provider.url).toBe(providerUrl1); + expect(await provider.getVersion()).toEqual(providerUrl1); - const spyGraphQLClient = jest.spyOn(GraphQL, 'GraphQLClient').mockImplementation( - () => - ({ - request: () => - Promise.resolve({ - chain: MOCK_CHAIN, - nodeInfo: MOCK_NODE_INFO, - }), - }) as unknown as GraphQL.GraphQLClient - ); - - const spyFetchChainAndNodeInfo = jest.spyOn(Provider.prototype, 'fetchChainAndNodeInfo'); - const spyFetchChain = jest.spyOn(Provider.prototype, 'fetchChain'); - const spyFetchNode = jest.spyOn(Provider.prototype, 'fetchNode'); + const spyFetchChainAndNodeInfo = vi + .spyOn(Provider.prototype, 'fetchChainAndNodeInfo') + .mockResolvedValue({ + chain: {} as ChainInfo, + nodeInfo: {} as NodeInfo, + }); await provider.connect(providerUrl2); expect(provider.url).toBe(providerUrl2); - expect(spyGraphQLClient).toBeCalledWith(providerUrl2, undefined); + + expect(await provider.getVersion()).toEqual(providerUrl2); expect(spyFetchChainAndNodeInfo).toHaveBeenCalledTimes(1); - expect(spyFetchChain).toHaveBeenCalledTimes(1); - expect(spyFetchNode).toHaveBeenCalledTimes(1); }); it('can accept a custom fetch function', async () => { @@ -254,9 +261,12 @@ describe('Provider', () => { * Mocking and initializing Provider with an invalid fetcher just * to ensure it'll be properly overriden in `connect` method below */ - const fetchChainAndNodeInfo = jest + const fetchChainAndNodeInfo = vi .spyOn(Provider.prototype, 'fetchChainAndNodeInfo') - .mockImplementation(); + .mockResolvedValue({ + chain: {} as ChainInfo, + nodeInfo: {} as NodeInfo, + }); const provider = await Provider.create(providerUrl, { fetch: () => { @@ -286,14 +296,19 @@ describe('Provider', () => { if (!block) { throw new Error('No latest block'); } - const { height: latestBlockNumberBeforeProduce } = block; + const { time: timeLastBlockProduced } = block; const amountOfBlocksToProduce = 3; - const latestBlockNumber = await provider.produceBlocks(amountOfBlocksToProduce); + const producedBlockHeigh = await provider.produceBlocks(amountOfBlocksToProduce); - expect(latestBlockNumber.toHex()).toEqual( - latestBlockNumberBeforeProduce.add(amountOfBlocksToProduce).toHex() - ); + const producedBlock = await provider.getBlock(producedBlockHeigh.toNumber()); + + expect(producedBlock).toBeDefined(); + + const oldest = new Date(fromTai64ToDate(timeLastBlockProduced || '')); + const newest = new Date(fromTai64ToDate(producedBlock?.time || '')); + + expect(newest >= oldest).toBeTruthy(); // #endregion Provider-produce-blocks }); @@ -510,8 +525,9 @@ describe('Provider', () => { expect(EXCLUDED.map((value) => hexlify(value))).toStrictEqual(EXPECTED); const owner = Address.fromRandom(); - const resourcesToSpendMock = jest.fn(() => Promise.resolve({ coinsToSpend: [] })); - // @ts-expect-error mock + const resourcesToSpendMock = vi.fn(() => + Promise.resolve({ coinsToSpend: [] }) + ) as unknown as typeof provider.operations.getCoinsToSpend; provider.operations.getCoinsToSpend = resourcesToSpendMock; await provider.getResourcesToSpend(owner, []); @@ -643,8 +659,9 @@ describe('Provider', () => { expect(EXCLUDED.map((value) => hexlify(value))).toStrictEqual(EXPECTED); const owner = Address.fromRandom(); - const resourcesToSpendMock = jest.fn(() => Promise.resolve({ coinsToSpend: [] })); - // @ts-expect-error mock + const resourcesToSpendMock = vi.fn(() => + Promise.resolve({ coinsToSpend: [] }) + ) as unknown as typeof provider.operations.getCoinsToSpend; provider.operations.getCoinsToSpend = resourcesToSpendMock; await provider.getResourcesToSpend(owner, [], { utxos: [ @@ -747,9 +764,9 @@ describe('Provider', () => { it('should ensure getChain and getNode uses the cache and does not fetch new data', async () => { Provider.clearChainAndNodeCaches(); - const spyFetchChainAndNodeInfo = jest.spyOn(Provider.prototype, 'fetchChainAndNodeInfo'); - const spyFetchChain = jest.spyOn(Provider.prototype, 'fetchChain'); - const spyFetchNode = jest.spyOn(Provider.prototype, 'fetchNode'); + const spyFetchChainAndNodeInfo = vi.spyOn(Provider.prototype, 'fetchChainAndNodeInfo'); + const spyFetchChain = vi.spyOn(Provider.prototype, 'fetchChain'); + const spyFetchNode = vi.spyOn(Provider.prototype, 'fetchNode'); const provider = await Provider.create(FUEL_NETWORK_URL); @@ -768,9 +785,9 @@ describe('Provider', () => { it('should ensure fetchChainAndNodeInfo always fetch new data', async () => { Provider.clearChainAndNodeCaches(); - const spyFetchChainAndNodeInfo = jest.spyOn(Provider.prototype, 'fetchChainAndNodeInfo'); - const spyFetchChain = jest.spyOn(Provider.prototype, 'fetchChain'); - const spyFetchNode = jest.spyOn(Provider.prototype, 'fetchNode'); + const spyFetchChainAndNodeInfo = vi.spyOn(Provider.prototype, 'fetchChainAndNodeInfo'); + const spyFetchChain = vi.spyOn(Provider.prototype, 'fetchChain'); + const spyFetchNode = vi.spyOn(Provider.prototype, 'fetchNode'); const provider = await Provider.create(FUEL_NETWORK_URL); @@ -835,7 +852,7 @@ describe('Provider', () => { throw new Error(); } - const spy = jest.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); + const spy = vi.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); spy.mockImplementationOnce(() => mock); await expectToThrowFuelError(() => Provider.create(FUEL_NETWORK_URL), { @@ -860,7 +877,7 @@ describe('Provider', () => { throw new Error(); } - const spy = jest.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); + const spy = vi.spyOn(fuelTsVersionsMod, 'checkFuelCoreVersionCompatibility'); spy.mockImplementationOnce(() => mock); await expectToThrowFuelError(() => Provider.create(FUEL_NETWORK_URL), { @@ -886,9 +903,9 @@ describe('Provider', () => { usedFee: bn(1), }; - const estimateTxSpy = jest.spyOn(provider, 'estimateTxDependencies').mockImplementation(); + const estimateTxSpy = vi.spyOn(provider, 'estimateTxDependencies').mockResolvedValueOnce(); - const txCostSpy = jest + const txCostSpy = vi .spyOn(provider, 'getTransactionCost') .mockReturnValue(Promise.resolve(transactionCost)); @@ -921,9 +938,9 @@ describe('Provider', () => { usedFee: bn(1), }; - const estimateTxSpy = jest.spyOn(provider, 'estimateTxDependencies').mockImplementation(); + const estimateTxSpy = vi.spyOn(provider, 'estimateTxDependencies').mockResolvedValueOnce(); - const txCostSpy = jest + const txCostSpy = vi .spyOn(provider, 'getTransactionCost') .mockReturnValue(Promise.resolve(transactionCost)); @@ -939,6 +956,78 @@ describe('Provider', () => { expect(estimateTxSpy).toHaveBeenCalled(); }); + it('An invalid subscription request throws a FuelError and does not hold the test runner (closes all handles)', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + + await expectToThrowFuelError( + async () => { + for await (const value of provider.operations.statusChange({ + transactionId: 'invalid transaction id', + })) { + // shouldn't be reached and should fail if reached + expect(value).toBeFalsy(); + } + }, + + { code: FuelError.CODES.INVALID_REQUEST } + ); + + const response = new TransactionResponse('invalid transaction id', provider); + + await expectToThrowFuelError(() => response.waitForResult(), { + code: FuelError.CODES.INVALID_REQUEST, + }); + }); + + it('default timeout is undefined', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + expect(provider.options.timeout).toBeUndefined(); + }); + + it('throws TimeoutError on timeout when calling an operation', async () => { + const timeout = 500; + const provider = await Provider.create(FUEL_NETWORK_URL, { timeout }); + vi.spyOn(global, 'fetch').mockImplementationOnce((...args: unknown[]) => + sleep(timeout).then(() => + fetch(args[0] as RequestInfo | URL, args[1] as RequestInit | undefined) + ) + ); + + const { error } = await safeExec(async () => { + await provider.getBlocks({}); + }); + + expect(error).toMatchObject({ + code: 23, + name: 'TimeoutError', + message: 'The operation was aborted due to timeout', + }); + }); + + it('throws TimeoutError on timeout when calling a subscription', async () => { + const timeout = 500; + const provider = await Provider.create(FUEL_NETWORK_URL, { timeout }); + + vi.spyOn(global, 'fetch').mockImplementationOnce((...args: unknown[]) => + sleep(timeout).then(() => + fetch(args[0] as RequestInfo | URL, args[1] as RequestInit | undefined) + ) + ); + + const { error } = await safeExec(async () => { + for await (const iterator of provider.operations.statusChange({ + transactionId: 'doesnt matter, will be aborted', + })) { + // shouldn't be reached and should fail if reached + expect(iterator).toBeFalsy(); + } + }); + expect(error).toMatchObject({ + code: 23, + name: 'TimeoutError', + message: 'The operation was aborted due to timeout', + }); + }); it('should ensure calculateMaxgas considers gasLimit for ScriptTransactionRequest', async () => { const provider = await Provider.create(FUEL_NETWORK_URL); const { gasPerByte } = provider.getGasConfig(); @@ -948,7 +1037,7 @@ describe('Provider', () => { gasLimit, }); - const maxGasSpy = jest.spyOn(gasMod, 'getMaxGas'); + const maxGasSpy = vi.spyOn(gasMod, 'getMaxGas'); const chainInfo = provider.getChain(); const minGas = bn(200); @@ -977,7 +1066,7 @@ describe('Provider', () => { transactionRequest.addContractCreatedOutput(ZeroBytes32, ZeroBytes32); - const maxGasSpy = jest.spyOn(gasMod, 'getMaxGas'); + const maxGasSpy = vi.spyOn(gasMod, 'getMaxGas'); const chainInfo = provider.getChain(); const minGas = bn(700); @@ -1001,21 +1090,38 @@ describe('Provider', () => { const request = new ScriptTransactionRequest(); // forcing calculatePriceWithFactor to return 0 - const calculatePriceWithFactorMock = jest + const calculatePriceWithFactorMock = vi .spyOn(gasMod, 'calculatePriceWithFactor') .mockReturnValue(bn(0)); - const normalizeZeroToOneSpy = jest.spyOn(BN.prototype, 'normalizeZeroToOne'); - const { minFee, maxFee, usedFee } = await provider.getTransactionCost(request); expect(calculatePriceWithFactorMock).toHaveBeenCalledTimes(3); - expect(normalizeZeroToOneSpy).toHaveBeenCalledTimes(3); - expect(normalizeZeroToOneSpy).toHaveReturnedWith(bn(1)); - expect(maxFee.eq(0)).not.toBeTruthy(); expect(usedFee.eq(0)).not.toBeTruthy(); expect(minFee.eq(0)).not.toBeTruthy(); }); + + it('should accept string addresses in methods that require an address', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + + const b256Str = Address.fromRandom().toB256(); + + const methodCalls = [ + () => provider.getBalance(b256Str, BaseAssetId), + () => provider.getCoins(b256Str), + () => provider.getResourcesForTransaction(b256Str, new ScriptTransactionRequest()), + () => provider.getResourcesToSpend(b256Str, []), + () => provider.getContractBalance(b256Str, BaseAssetId), + () => provider.getBalances(b256Str), + () => provider.getMessages(b256Str), + ]; + + const promises = methodCalls.map(async (call) => { + await expect(call()).resolves.toBeTruthy(); + }); + + await Promise.all(promises); + }); }); diff --git a/packages/providers/tsconfig.json b/packages/providers/tsconfig.json index c723e93fb3..b22c89a4b3 100644 --- a/packages/providers/tsconfig.json +++ b/packages/providers/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "outDir": "./dist" }, - "include": ["src/**/*.ts", "src/**/*.json"] + "include": ["src", "test"] } diff --git a/packages/script/package.json b/packages/script/package.json index d19b9d6389..0b781c019a 100644 --- a/packages/script/package.json +++ b/packages/script/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/script/src/script-invocation-scope.ts b/packages/script/src/script-invocation-scope.ts index e4b4ff409a..5caeaa7b7f 100644 --- a/packages/script/src/script-invocation-scope.ts +++ b/packages/script/src/script-invocation-scope.ts @@ -1,13 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { FuelError } from '@fuel-ts/errors'; import type { AbstractScript } from '@fuel-ts/interfaces'; -import { - ScriptRequest, - assert, - FunctionInvocationScope, - FunctionInvocationResult, -} from '@fuel-ts/program'; -import type { InvocationScopeLike } from '@fuel-ts/program'; +import { ScriptRequest, FunctionInvocationScope } from '@fuel-ts/program'; import type { Provider } from '@fuel-ts/providers'; import { ByteArrayCoder } from '@fuel-ts/transactions'; @@ -49,24 +43,4 @@ export class ScriptInvocationScope< () => [] as unknown as TReturn ); } - - /** - * Submits a script transaction to the blockchain. - */ - async call(): Promise> { - assert(this.program.account, 'Provider is required!'); - - const transactionRequest = await this.getTransactionRequest(); - const { maxFee } = await this.getTransactionCost(); - await this.fundWithRequiredCoins(maxFee); - - const response = await this.program.account.sendTransaction(transactionRequest); - - return FunctionInvocationResult.build( - this as unknown as InvocationScopeLike, - response, - false, - this.program - ); - } } diff --git a/packages/script/src/script.test.ts b/packages/script/src/script.test.ts index cc83ec59a3..a11b0c8eeb 100644 --- a/packages/script/src/script.test.ts +++ b/packages/script/src/script.test.ts @@ -76,6 +76,9 @@ type MyStruct = { arg_two: BigNumberish; }; +/** + * @group node + */ describe('Script', () => { let scriptRequest: ScriptRequest; beforeAll(() => { diff --git a/packages/signer/README.md b/packages/signer/README.md index a59eb7d654..e588110d11 100644 --- a/packages/signer/README.md +++ b/packages/signer/README.md @@ -18,7 +18,7 @@ This module contains utilities for secp256-k1 signing, verifying and recovery op -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/signer/package.json b/packages/signer/package.json index b6e678c63c..06f90e09b6 100644 --- a/packages/signer/package.json +++ b/packages/signer/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -29,10 +29,7 @@ "@fuel-ts/crypto": "workspace:*", "@fuel-ts/hasher": "workspace:*", "@fuel-ts/math": "workspace:*", - "elliptic": "^6.5.4", - "ethers": "^6.7.1" - }, - "devDependencies": { - "@types/elliptic": "^6.4.14" + "ethers": "^6.7.1", + "@noble/curves": "^1.3.0" } } diff --git a/packages/signer/src/index.ts b/packages/signer/src/index.ts index 3eface77c7..af5d8964d6 100644 --- a/packages/signer/src/index.ts +++ b/packages/signer/src/index.ts @@ -1,2 +1 @@ -export { default as Signer } from './signer'; export * from './signer'; diff --git a/packages/signer/src/signer.test.ts b/packages/signer/src/signer.test.ts index 954aa3be7a..2d0635135c 100644 --- a/packages/signer/src/signer.test.ts +++ b/packages/signer/src/signer.test.ts @@ -1,7 +1,11 @@ import { getBytesCopy, sha256 } from 'ethers'; -import Signer from './signer'; +import { Signer } from './signer'; +/** + * @group node + * @group browser + */ describe('Signer', () => { const expectedPrivateKey = '0x5f70feeff1f229e4a95e1056e8b4d80d0b24b565674860cc213bdb07127ce1b1'; const expectedPublicKey = diff --git a/packages/signer/src/signer.ts b/packages/signer/src/signer.ts index 364cd10397..0444a4c1ec 100644 --- a/packages/signer/src/signer.ts +++ b/packages/signer/src/signer.ts @@ -2,24 +2,11 @@ import { Address } from '@fuel-ts/address'; import { randomBytes } from '@fuel-ts/crypto'; import { hash } from '@fuel-ts/hasher'; import { toBytes } from '@fuel-ts/math'; -import * as elliptic from 'elliptic'; -import { hexlify, concat, getBytesCopy } from 'ethers'; +import { secp256k1 } from '@noble/curves/secp256k1'; import type { BytesLike } from 'ethers'; +import { hexlify, concat, getBytesCopy } from 'ethers'; -/* Importing `ec` like this to avoid the 'Requested module is a CommonJS module, - * which may not support all module.exports as named exports' error - * @see https://github.com/FuelLabs/fuels-ts/issues/841 - */ -const { ec: EC } = elliptic; - -/** - * Return elliptic instance with curve secp256k1 - */ -export function getCurve() { - return new EC('secp256k1'); -} - -class Signer { +export class Signer { readonly address: Address; readonly publicKey: string; @@ -42,16 +29,15 @@ class Signer { privateKey = `0x${privateKey}`; } } - // Convert to byte array, normalize private key input allowing it to be BytesLike // like remove 0x prefix and accept array of bytes - const privateKeyBytes = getBytesCopy(privateKey); - const keyPair = getCurve().keyFromPrivate(privateKeyBytes, 'hex'); + const privateKeyBytes = toBytes(privateKey, 32); - // Slice(1) removes the encoding scheme from the public key - this.compressedPublicKey = hexlify(Uint8Array.from(keyPair.getPublic(true, 'array'))); - this.publicKey = hexlify(Uint8Array.from(keyPair.getPublic(false, 'array').slice(1))); this.privateKey = hexlify(privateKeyBytes); + + // Slice(1) removes the encoding scheme from the public key + this.publicKey = hexlify(secp256k1.getPublicKey(privateKeyBytes, false).slice(1)); + this.compressedPublicKey = hexlify(secp256k1.getPublicKey(privateKeyBytes, true)); this.address = Address.fromPublicKey(this.publicKey); } @@ -64,15 +50,13 @@ class Signer { * @returns hashed signature */ sign(data: BytesLike) { - const keyPair = getCurve().keyFromPrivate(getBytesCopy(this.privateKey), 'hex'); - const signature = keyPair.sign(getBytesCopy(data), { - canonical: true, - }); - const r = toBytes(signature.r, 32); - const s = toBytes(signature.s, 32); + const signature = secp256k1.sign(getBytesCopy(data), getBytesCopy(this.privateKey)); + + const r = toBytes(`0x${signature.r.toString(16)}`, 32); + const s = toBytes(`0x${signature.s.toString(16)}`, 32); // add recoveryParam to first s byte - s[0] |= (signature.recoveryParam || 0) << 7; + s[0] |= (signature.recovery || 0) << 7; return concat([r, s]); } @@ -84,11 +68,10 @@ class Signer { * @returns compressed point on the curve */ addPoint(point: BytesLike) { - const p0 = getCurve().keyFromPublic(getBytesCopy(this.compressedPublicKey)); - const p1 = getCurve().keyFromPublic(getBytesCopy(point)); - const result = p0.getPublic().add(p1.getPublic()); - - return hexlify(Uint8Array.from(result.encode('array', true))); + const p0 = secp256k1.ProjectivePoint.fromHex(getBytesCopy(this.compressedPublicKey)); + const p1 = secp256k1.ProjectivePoint.fromHex(getBytesCopy(point)); + const result = p0.add(p1); + return `0x${result.toHex(true)}`; } /** @@ -107,12 +90,12 @@ class Signer { // remove recoveryParam from s first byte s[0] &= 0x7f; - const publicKey = getCurve() - .recoverPubKey(getBytesCopy(data), { r, s }, recoveryParam) - .encode('array', false) - .slice(1); + const sig = new secp256k1.Signature(BigInt(hexlify(r)), BigInt(hexlify(s))).addRecoveryBit( + recoveryParam + ); - return hexlify(Uint8Array.from(publicKey)); + const publicKey = sig.recoverPublicKey(getBytesCopy(data)).toRawBytes(false).slice(1); + return hexlify(publicKey); } /** @@ -143,9 +126,7 @@ class Signer { * @returns extended publicKey */ static extendPublicKey(publicKey: BytesLike) { - const keyPair = getCurve().keyFromPublic(getBytesCopy(publicKey)); - return hexlify(Uint8Array.from(keyPair.getPublic(false, 'array').slice(1))); + const point = secp256k1.ProjectivePoint.fromHex(getBytesCopy(publicKey)); + return hexlify(point.toRawBytes(false).slice(1)); } } - -export default Signer; diff --git a/packages/signer/tsdoc.json b/packages/signer/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/signer/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/testcases/tsdoc.json b/packages/testcases/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/testcases/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/transactions/README.md b/packages/transactions/README.md index dea49a86ef..045b842f12 100644 --- a/packages/transactions/README.md +++ b/packages/transactions/README.md @@ -18,7 +18,7 @@ This module contains various constants and functions for encoding and decoding s -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/transactions/package.json b/packages/transactions/package.json index c14eeed601..6c10a97659 100644 --- a/packages/transactions/package.json +++ b/packages/transactions/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/transactions/src/coders/byte-array.test.ts b/packages/transactions/src/coders/byte-array.test.ts index 9bb45ae306..9d141aabb8 100644 --- a/packages/transactions/src/coders/byte-array.test.ts +++ b/packages/transactions/src/coders/byte-array.test.ts @@ -2,6 +2,10 @@ import { getBytesCopy, hexlify } from 'ethers'; import { ByteArrayCoder } from './byte-array'; +/** + * @group node + * @group browser + */ describe('ByteArrayCoder', () => { it('Can encode empty byte[]', () => { const bytes = getBytesCopy('0x'); diff --git a/packages/transactions/src/coders/input.test.ts b/packages/transactions/src/coders/input.test.ts index 54302e2699..b7701fc390 100644 --- a/packages/transactions/src/coders/input.test.ts +++ b/packages/transactions/src/coders/input.test.ts @@ -9,6 +9,10 @@ import { InputMessageCoder, InputCoder, InputType } from './input'; const B256 = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; const MAX_U32 = 2 ** 32 - 1; +/** + * @group node + * @group browser + */ describe('InputCoder', () => { it('Can encode Coin', () => { const input: Input = { diff --git a/packages/transactions/src/coders/output.test.ts b/packages/transactions/src/coders/output.test.ts index 3d33bc461a..d9e17237b3 100644 --- a/packages/transactions/src/coders/output.test.ts +++ b/packages/transactions/src/coders/output.test.ts @@ -6,6 +6,10 @@ import { OutputCoder, OutputType } from './output'; const B256 = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; +/** + * @group node + * @group browser + */ describe('OutputCoder', () => { it('Can encode Coin', () => { const output: Output = { diff --git a/packages/transactions/src/coders/policy.test.ts b/packages/transactions/src/coders/policy.test.ts index ad20b40264..b799745a91 100644 --- a/packages/transactions/src/coders/policy.test.ts +++ b/packages/transactions/src/coders/policy.test.ts @@ -5,6 +5,10 @@ import { bn } from '@fuel-ts/math'; import type { Policy } from './policy'; import { PoliciesCoder, PolicyType } from './policy'; +/** + * @group node + * @group browser + */ describe('PoliciesCoder', () => { describe('encode', () => { it('should encode policy correctly (GasPrice)', () => { diff --git a/packages/transactions/src/coders/receipt.test.ts b/packages/transactions/src/coders/receipt.test.ts index cddcca2775..3b4a711d0b 100644 --- a/packages/transactions/src/coders/receipt.test.ts +++ b/packages/transactions/src/coders/receipt.test.ts @@ -10,6 +10,10 @@ const B256_ALT2 = '0x68b401b682ba0c9018150cca596358a6b98576337ea10b9cfb0d02441b3 const B256_ALT3 = '0xeb03488970d05ea240c788a0ea2e07176cc5317b7c7c89f26ac5282bbcd445bd'; const B256_ALT4 = '0x2f6d40e3ac1a172fb9445f9843440a0fc383bea238a7a35a77a3c73d36902992'; +/** + * @group node + * @group browser + */ describe('ReceiptCoder', () => { it('Can encode Call', () => { const receipt: Receipt = { diff --git a/packages/transactions/src/coders/receipt.ts b/packages/transactions/src/coders/receipt.ts index ba80cc8925..a00a38637e 100644 --- a/packages/transactions/src/coders/receipt.ts +++ b/packages/transactions/src/coders/receipt.ts @@ -767,7 +767,7 @@ export type ReceiptMint = { is: BN; }; -const getAssetIdForMintAndBurnReceipts = (contractId: string, subId: string): string => { +export const getAssetId = (contractId: string, subId: string): string => { const contractIdBytes = getBytesCopy(contractId); const subIdBytes = getBytesCopy(subId); @@ -780,7 +780,7 @@ export class ReceiptMintCoder extends Coder { } static getAssetId(contractId: string, subId: string): string { - return getAssetIdForMintAndBurnReceipts(contractId, subId); + return getAssetId(contractId, subId); } encode(value: ReceiptMint): Uint8Array { @@ -848,7 +848,7 @@ export class ReceiptBurnCoder extends Coder { } static getAssetId(contractId: string, subId: string): string { - return getAssetIdForMintAndBurnReceipts(contractId, subId); + return getAssetId(contractId, subId); } encode(value: ReceiptBurn): Uint8Array { diff --git a/packages/transactions/src/coders/storage-slot.test.ts b/packages/transactions/src/coders/storage-slot.test.ts index 758da11e06..72d0842ac1 100644 --- a/packages/transactions/src/coders/storage-slot.test.ts +++ b/packages/transactions/src/coders/storage-slot.test.ts @@ -4,6 +4,10 @@ import { getBytesCopy, hexlify } from 'ethers'; import type { StorageSlot } from './storage-slot'; import { StorageSlotCoder } from './storage-slot'; +/** + * @group node + * @group browser + */ describe('StorageSlotCoder', () => { it('Can encode and decode', () => { const storageSlot: StorageSlot = { diff --git a/packages/transactions/src/coders/transaction.test.ts b/packages/transactions/src/coders/transaction.test.ts index d9349f9477..3c313736be 100644 --- a/packages/transactions/src/coders/transaction.test.ts +++ b/packages/transactions/src/coders/transaction.test.ts @@ -12,6 +12,10 @@ const U32 = 1000; const U16 = 32; const U8 = 1; +/** + * @group node + * @group browser + */ describe('TransactionCoder', () => { it('Can encode/decode TransactionScript without inputs, outputs and witnesses', () => { const transaction: Transaction = { diff --git a/packages/transactions/src/coders/tx-pointer.test.ts b/packages/transactions/src/coders/tx-pointer.test.ts index afd3237a98..a7d962be81 100644 --- a/packages/transactions/src/coders/tx-pointer.test.ts +++ b/packages/transactions/src/coders/tx-pointer.test.ts @@ -5,6 +5,10 @@ import { TxPointerCoder } from './tx-pointer'; const B256 = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; +/** + * @group node + * @group browser + */ describe('TxPointerCoder', () => { it('can encode TxPointer', () => { const txPointer: TxPointer = { diff --git a/packages/transactions/src/coders/utxo-id.test.ts b/packages/transactions/src/coders/utxo-id.test.ts index 947bc1124f..0e4f9366f9 100644 --- a/packages/transactions/src/coders/utxo-id.test.ts +++ b/packages/transactions/src/coders/utxo-id.test.ts @@ -5,6 +5,10 @@ import { UtxoIdCoder } from './utxo-id'; const B256 = '0xd5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b'; +/** + * @group node + * @group browser + */ describe('UtxoIdCoder', () => { it('can encode UtxoId', () => { const utxoId: UtxoId = { diff --git a/packages/transactions/src/coders/witness.test.ts b/packages/transactions/src/coders/witness.test.ts index 167f6bf01d..206049651e 100644 --- a/packages/transactions/src/coders/witness.test.ts +++ b/packages/transactions/src/coders/witness.test.ts @@ -3,6 +3,10 @@ import { getBytesCopy, hexlify } from 'ethers'; import type { Witness } from './witness'; import { WitnessCoder } from './witness'; +/** + * @group node + * @group browser + */ describe('WitnessCoder', () => { it('Can encode empty Witness', () => { const witness: Witness = { diff --git a/packages/transactions/tsdoc.json b/packages/transactions/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/transactions/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/utils/README.md b/packages/utils/README.md index fb0e694228..8f8a3e9620 100644 --- a/packages/utils/README.md +++ b/packages/utils/README.md @@ -18,7 +18,7 @@ It's a collection of utilities and test utilities that may be useful in other pl -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Installation diff --git a/packages/utils/package.json b/packages/utils/package.json index 94525cde1f..482fc781e1 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -19,12 +19,20 @@ "require": "./dist/test-utils.js", "import": "./dist/test-utils.mjs", "types": "./dist/test-utils.d.ts" + }, + "./cli-utils": { + "require": "./dist/cli-utils.js", + "import": "./dist/cli-utils.mjs", + "types": "./dist/cli-utils.d.ts" } }, "typesVersions": { "*": { "test-utils": [ "./dist/test-utils.d.ts" + ], + "cli-utils": [ + "./dist/cli-utils.d.ts" ] } }, @@ -39,7 +47,7 @@ }, "license": "Apache-2.0", "dependencies": { - "ethers": "^6.7.1", + "@fuel-ts/interfaces": "workspace:*", "ramda": "^0.29.0", "rimraf": "^3.0.2" }, diff --git a/packages/utils/src/cli-utils.ts b/packages/utils/src/cli-utils.ts new file mode 100644 index 0000000000..eaac016729 --- /dev/null +++ b/packages/utils/src/cli-utils.ts @@ -0,0 +1 @@ +export * from './cli-utils/findBinPath'; diff --git a/packages/utils/src/cli-utils/findBinPath.test.ts b/packages/utils/src/cli-utils/findBinPath.test.ts new file mode 100644 index 0000000000..cb1ddde4c9 --- /dev/null +++ b/packages/utils/src/cli-utils/findBinPath.test.ts @@ -0,0 +1,57 @@ +import { safeExec } from '@fuel-ts/errors/test-utils'; +import { mkdirSync, rmSync, writeFileSync } from 'fs'; +import { join } from 'path'; + +import { findBinPath } from './findBinPath'; + +/** + * @group node + */ +describe('findBinPath', () => { + const bootstrap = (dir: string) => { + const cmdName = 'my-cmd'; + const mods = join(dir, 'node_modules'); + const bin = join(mods, '.bin'); + const cmdPath = join(bin, cmdName); + + const resetDisk = () => rmSync(mods, { recursive: true }); + + mkdirSync(bin, { recursive: true }); + writeFileSync(cmdPath, ''); + + return { resetDisk, mods, cmdName, cmdPath }; + }; + + it('should find bin path in current dir', () => { + const base = __dirname; // current dir + const { cmdName, cmdPath, resetDisk } = bootstrap(base); + const binPath = findBinPath(cmdName, base); + + resetDisk(); + expect(binPath).toEqual(cmdPath); + }); + + it('should find bin path one dir up', () => { + const base = join(__dirname, '..'); // one dir up + const { cmdName, cmdPath, resetDisk } = bootstrap(base); + const binPath = findBinPath(cmdName, base); + + resetDisk(); + expect(binPath).toEqual(cmdPath); + }); + + it('should find bin path two dir up', () => { + const base = join(__dirname, '..', '..'); // two dirs up + const { cmdName, cmdPath, resetDisk } = bootstrap(base); + const binPath = findBinPath(cmdName, base); + + resetDisk(); + expect(binPath).toEqual(cmdPath); + }); + + it('should throw for bin path not found', async () => { + const cmdName = 'non-existent'; + const { error } = await safeExec(() => findBinPath(cmdName, __dirname)); + expect(error?.message).toEqual(`Command not found: ${cmdName}`); + }); +}); diff --git a/packages/utils/src/cli-utils/findBinPath.ts b/packages/utils/src/cli-utils/findBinPath.ts new file mode 100644 index 0000000000..7f255e01bd --- /dev/null +++ b/packages/utils/src/cli-utils/findBinPath.ts @@ -0,0 +1,17 @@ +import { existsSync } from 'fs'; +import { join } from 'path'; + +export const findBinPath = (binCommandName: string, startingDir: string): string => { + const cmdPath = join(startingDir, 'node_modules', '.bin', binCommandName); + const parentDir = join(startingDir, '..'); + + if (existsSync(cmdPath)) { + return cmdPath; + } + + if (parentDir === startingDir) { + throw new Error(`Command not found: ${binCommandName}`); + } + + return findBinPath(binCommandName, parentDir); +}; diff --git a/packages/utils/src/index.test.ts b/packages/utils/src/index.test.ts index ecc66d9618..4d28f6ff58 100644 --- a/packages/utils/src/index.test.ts +++ b/packages/utils/src/index.test.ts @@ -1,5 +1,9 @@ import * as indexMod from '.'; +/** + * @group node + * @group browser + */ describe('index.js', () => { test('should export all utilities', () => { expect(indexMod.normalizeString).toBeTruthy(); diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 5278d7f3b0..7004b0e889 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -4,3 +4,4 @@ export * from './utils/concat'; export * from './utils/arrayify'; export * from './utils/hexlify'; export * from './utils/normalizeString'; +export * from './utils/defaultChainConfig'; diff --git a/packages/utils/src/test-util.test.ts b/packages/utils/src/test-util.test.ts index e0cecd3dfe..f2a9a9f00f 100644 --- a/packages/utils/src/test-util.test.ts +++ b/packages/utils/src/test-util.test.ts @@ -1,5 +1,8 @@ import * as indexMod from './test-utils'; +/** + * @group node + */ describe('index.js', () => { test('should export all test utilities', () => { expect(indexMod.getForcProject).toBeTruthy(); diff --git a/packages/utils/src/test-utils/expectToBeInRange.test.ts b/packages/utils/src/test-utils/expectToBeInRange.test.ts index 95404f6590..6ebe61e1e7 100644 --- a/packages/utils/src/test-utils/expectToBeInRange.test.ts +++ b/packages/utils/src/test-utils/expectToBeInRange.test.ts @@ -1,5 +1,9 @@ import { expectToBeInRange } from './expectToBeInRange'; +/** + * @group node + * @group browser + */ describe('expectValueToBeInRange', () => { it('should throw an error when value is less than the minimum', () => { expect(() => diff --git a/packages/utils/src/test-utils/getForcProject.test.ts b/packages/utils/src/test-utils/getForcProject.test.ts index 6af5a15d65..a41e47a5f2 100644 --- a/packages/utils/src/test-utils/getForcProject.test.ts +++ b/packages/utils/src/test-utils/getForcProject.test.ts @@ -1,7 +1,8 @@ -import * as ethers from 'ethers'; import * as fs from 'fs'; import * as path from 'path'; +import * as utilsMod from '../index'; + import { getForcProject, getProjectAbiPath, @@ -13,24 +14,35 @@ import { getProjectTempDir, } from './getForcProject'; -jest.mock('path', () => ({ - __esModule: true, - ...jest.requireActual('path'), -})); +vi.mock('path', async () => { + const mod = await vi.importActual('path'); + return { + __esModule: true, + ...mod, + }; +}); -jest.mock('fs', () => ({ - __esModule: true, - ...jest.requireActual('fs'), -})); +vi.mock('fs', async () => { + const mod = await vi.importActual('fs'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('getForcProject', () => { - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); it('should return the correct temporary directory path on getProjectTempDir', () => { const params = { projectDir: '/path/to/project', projectName: 'myProject' }; const expectedPath = '/path/to/project/out/debug/__temp__'; - jest.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); + vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); const tempDir = getProjectTempDir(params); @@ -41,7 +53,7 @@ describe('getForcProject', () => { const params = { projectDir: '/path/to/project', projectName: 'myProject' }; const expectedPath = '/path/to/project/out/debug/myProject-abi.json'; - jest.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); + vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); const abiPath = getProjectAbiPath(params); @@ -52,7 +64,7 @@ describe('getForcProject', () => { const params = { projectDir: '/path/to/project', projectName: 'myProject' }; const expectedPath = '/path/to/project/out/debug/myProject.bin'; - jest.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); + vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); const binPath = getProjectBinPath(params); @@ -63,7 +75,7 @@ describe('getForcProject', () => { const params = { projectDir: '/path/to/project', projectName: 'myProject' }; const expectedPath = '/path/to/project/out/debug/myProject-storage_slots.json'; - jest.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); + vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); const storageSlotsPath = getProjectStorageSlotsPath(params); @@ -84,9 +96,9 @@ describe('getForcProject', () => { const expectedPath = '/path/to/project/out/debug/myProject-storage_slots.json'; const fakeStorageSlots = [{ key: 'key1', value: 'value1' }]; - jest.spyOn(fs, 'existsSync').mockReturnValue(true); + vi.spyOn(fs, 'existsSync').mockReturnValue(true); - const readFileSyncSpy = jest + const readFileSyncSpy = vi .spyOn(fs, 'readFileSync') .mockReturnValue(JSON.stringify(fakeStorageSlots)); @@ -97,9 +109,7 @@ describe('getForcProject', () => { }); it('should return the correct debug directory path', () => { - const joinSpy = jest - .spyOn(path, 'join') - .mockImplementation((...segments) => segments.join('/')); + const joinSpy = vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); const params = { projectDir: '/path/to/project', projectName: 'myProject' }; const expectedPath = '/path/to/project/out/debug'; @@ -113,8 +123,8 @@ describe('getForcProject', () => { it('should return an empty array if the storage slots file does not exist', () => { const params = { projectDir: '/path/to/project', projectName: 'myProject' }; - jest.spyOn(fs, 'existsSync').mockReturnValue(false); - const readFileSyncSpy = jest.spyOn(fs, 'readFileSync'); + vi.spyOn(fs, 'existsSync').mockReturnValue(false); + const readFileSyncSpy = vi.spyOn(fs, 'readFileSync'); const storageSlots = getProjectStorageSlots(params); @@ -127,9 +137,9 @@ describe('getForcProject', () => { const fakeAbiContent = { contracts: {} }; const fakeStorageSlots = [{ key: 'key1', value: 'value1' }]; - jest.spyOn(ethers, 'hexlify').mockImplementation((param) => param as string); - jest.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); - jest.spyOn(fs, 'readFileSync').mockImplementation((pathParam) => { + vi.spyOn(utilsMod, 'hexlify').mockImplementation((param) => param as string); + vi.spyOn(path, 'join').mockImplementation((...segments) => segments.join('/')); + vi.spyOn(fs, 'readFileSync').mockImplementation((pathParam) => { if ((pathParam).endsWith('.bin')) { return fakeBinContent; } @@ -142,9 +152,9 @@ describe('getForcProject', () => { throw new Error('File not found'); }); - jest - .spyOn(fs, 'existsSync') - .mockImplementation((pathParam) => (pathParam).endsWith('-storage_slots.json')); + vi.spyOn(fs, 'existsSync').mockImplementation((pathParam) => + (pathParam).endsWith('-storage_slots.json') + ); const forcProject = { projectDir: 'fuel_gauge', diff --git a/packages/utils/src/test-utils/getForcProject.ts b/packages/utils/src/test-utils/getForcProject.ts index 877cf068dd..b68fdbe157 100644 --- a/packages/utils/src/test-utils/getForcProject.ts +++ b/packages/utils/src/test-utils/getForcProject.ts @@ -1,7 +1,7 @@ -import { hexlify } from 'ethers'; import { existsSync, readFileSync } from 'fs'; import { join } from 'path'; +import { hexlify } from '../index'; import { normalizeString } from '../utils/normalizeString'; interface IGetForcProjectParams { diff --git a/packages/utils/src/utils/arrayify.test.ts b/packages/utils/src/utils/arrayify.test.ts index 1c5fa8d1c1..970d568261 100644 --- a/packages/utils/src/utils/arrayify.test.ts +++ b/packages/utils/src/utils/arrayify.test.ts @@ -1,5 +1,9 @@ import { arrayify } from './arrayify'; +/** + * @group node + * @group browser + */ describe('arrayify', () => { it('returns Uint8Array from Uint8Array', () => { expect(arrayify(new Uint8Array([0, 1, 2, 3]))).toEqual(new Uint8Array([0, 1, 2, 3])); diff --git a/packages/utils/src/utils/arrayify.ts b/packages/utils/src/utils/arrayify.ts index 4251ed8071..24eeb00c13 100644 --- a/packages/utils/src/utils/arrayify.ts +++ b/packages/utils/src/utils/arrayify.ts @@ -1,5 +1,5 @@ import { FuelError, ErrorCode } from '@fuel-ts/errors'; -import type { BytesLike } from 'ethers'; +import type { BytesLike } from '@fuel-ts/interfaces'; /** * Converts a bytes-like value to a `Uint8Array`. diff --git a/packages/utils/src/utils/capitalizeString.test.ts b/packages/utils/src/utils/capitalizeString.test.ts index 94bcc630a4..9ae643912b 100644 --- a/packages/utils/src/utils/capitalizeString.test.ts +++ b/packages/utils/src/utils/capitalizeString.test.ts @@ -1,5 +1,9 @@ import { capitalizeString } from './capitalizeString'; +/** + * @group node + * @group browser + */ describe('capitalizeString', () => { test('should capitalize string', () => { expect(capitalizeString('test')).toEqual('Test'); diff --git a/packages/utils/src/utils/chainConfig.json b/packages/utils/src/utils/chainConfig.json new file mode 100644 index 0000000000..a89ba09581 --- /dev/null +++ b/packages/utils/src/utils/chainConfig.json @@ -0,0 +1,515 @@ +{ + "chain_name": "local_testnet", + "block_gas_limit": 5000000000, + "initial_state": { + "coins": [ + { + "owner": "0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0101010101010101010101010101010101010101010101010101010101010101" + }, + { + "owner": "0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82", + "amount": "0xFFFFFFFFFFFFFFFF", + "asset_id": "0x0202020202020202020202020202020202020202020202020202020202020202" + } + ], + "messages": [ + { + "sender": "0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f", + "recipient": "0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba", + "nonce": "0101010101010101010101010101010101010101010101010101010101010101", + "amount": "0x000000000000FFFF", + "data": "", + "da_height": "0x00" + }, + { + "sender": "0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba", + "recipient": "0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f", + "nonce": "0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b", + "amount": "0xb04f3c08f59b309e", + "data": "", + "da_height": "0x00" + } + ] + }, + "consensus_parameters": { + "tx_params": { + "max_inputs": 255, + "max_outputs": 255, + "max_witnesses": 255, + "max_gas_per_tx": 10000000, + "max_size": 17825792 + }, + "predicate_params": { + "max_predicate_length": 1048576, + "max_predicate_data_length": 1048576, + "max_gas_per_predicate": 10000000, + "max_message_data_length": 1048576 + }, + "script_params": { + "max_script_length": 1048576, + "max_script_data_length": 1048576 + }, + "contract_params": { + "contract_max_size": 16777216, + "max_storage_slots": 255 + }, + "fee_params": { + "gas_price_factor": 92, + "gas_per_byte": 4 + } + }, + "gas_costs": { + "add": 1, + "addi": 1, + "aloc": 1, + "and": 1, + "andi": 1, + "bal": 13, + "bhei": 1, + "bhsh": 1, + "burn": 132, + "cb": 1, + "cfei": 1, + "cfsi": 1, + "croo": 16, + "div": 1, + "divi": 1, + "ecr1": 3000, + "eck1": 951, + "ed19": 3000, + "eq": 1, + "exp": 1, + "expi": 1, + "flag": 1, + "gm": 1, + "gt": 1, + "gtf": 1, + "ji": 1, + "jmp": 1, + "jne": 1, + "jnei": 1, + "jnzi": 1, + "jmpf": 1, + "jmpb": 1, + "jnzf": 1, + "jnzb": 1, + "jnef": 1, + "jneb": 1, + "lb": 1, + "log": 9, + "lt": 1, + "lw": 1, + "mint": 135, + "mlog": 1, + "modOp": 1, + "modi": 1, + "moveOp": 1, + "movi": 1, + "mroo": 2, + "mul": 1, + "muli": 1, + "mldv": 1, + "noop": 1, + "not": 1, + "or": 1, + "ori": 1, + "poph": 2, + "popl": 2, + "pshh": 2, + "pshl": 2, + "ret": 13, + "rvrt": 13, + "sb": 1, + "sll": 1, + "slli": 1, + "srl": 1, + "srli": 1, + "srw": 12, + "sub": 1, + "subi": 1, + "sw": 1, + "sww": 67, + "time": 1, + "tr": 105, + "tro": 60, + "wdcm": 1, + "wqcm": 1, + "wdop": 1, + "wqop": 1, + "wdml": 1, + "wqml": 1, + "wddv": 1, + "wqdv": 2, + "wdmd": 3, + "wqmd": 4, + "wdam": 2, + "wqam": 3, + "wdmm": 3, + "wqmm": 3, + "xor": 1, + "xori": 1, + "call": { + "LightOperation": { + "base": 144, + "units_per_gas": 214 + } + }, + "ccp": { + "LightOperation": { + "base": 15, + "units_per_gas": 103 + } + }, + "csiz": { + "LightOperation": { + "base": 17, + "units_per_gas": 790 + } + }, + "k256": { + "LightOperation": { + "base": 11, + "units_per_gas": 214 + } + }, + "ldc": { + "LightOperation": { + "base": 15, + "units_per_gas": 272 + } + }, + "logd": { + "LightOperation": { + "base": 26, + "units_per_gas": 64 + } + }, + "mcl": { + "LightOperation": { + "base": 1, + "units_per_gas": 3333 + } + }, + "mcli": { + "LightOperation": { + "base": 1, + "units_per_gas": 3333 + } + }, + "mcp": { + "LightOperation": { + "base": 1, + "units_per_gas": 2000 + } + }, + "mcpi": { + "LightOperation": { + "base": 3, + "units_per_gas": 2000 + } + }, + "meq": { + "LightOperation": { + "base": 1, + "units_per_gas": 2500 + } + }, + "retd": { + "LightOperation": { + "base": 29, + "units_per_gas": 62 + } + }, + "s256": { + "LightOperation": { + "base": 2, + "units_per_gas": 214 + } + }, + "scwq": { + "LightOperation": { + "base": 13, + "units_per_gas": 5 + } + }, + "smo": { + "LightOperation": { + "base": 209, + "units_per_gas": 55 + } + }, + "srwq": { + "LightOperation": { + "base": 47, + "units_per_gas": 5 + } + }, + "swwq": { + "LightOperation": { + "base": 44, + "units_per_gas": 5 + } + }, + "contract_root": { + "LightOperation": { + "base": 75, + "units_per_gas": 1 + } + }, + "state_root": { + "LightOperation": { + "base": 412, + "units_per_gas": 1 + } + }, + "vm_initialization": { + "HeavyOperation": { + "base": 2000, + "gas_per_unit": 0 + } + }, + "new_storage_per_byte": 1 + }, + "consensus": { + "PoA": { + "signing_key": "0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d" + } + } +} diff --git a/packages/utils/src/utils/chunkAndPadBytes.test.ts b/packages/utils/src/utils/chunkAndPadBytes.test.ts index 36ff1aee96..a4587965d6 100644 --- a/packages/utils/src/utils/chunkAndPadBytes.test.ts +++ b/packages/utils/src/utils/chunkAndPadBytes.test.ts @@ -1,10 +1,14 @@ -import { getBytesCopy } from 'ethers'; +import { arrayify } from '../index'; import { chunkAndPadBytes } from './chunkAndPadBytes'; +/** + * @group node + * @group browser + */ describe('chunkAndPadBytes', () => { it('can chunk and pad bytes to 16 KiB', () => { - const bytes = getBytesCopy( + const bytes = arrayify( '0x900000044700000000000000000000345dfcc00110fff3005d4060495d47f000134904407348000c72f0007b36f0000024040000000000002151bd4b' ); const chunkSize = 16 * 1024; diff --git a/packages/utils/src/utils/concat.test.ts b/packages/utils/src/utils/concat.test.ts index d384d918d4..763b4cbf61 100644 --- a/packages/utils/src/utils/concat.test.ts +++ b/packages/utils/src/utils/concat.test.ts @@ -1,7 +1,10 @@ -import { getBytesCopy } from 'ethers'; - +import { arrayify } from './arrayify'; import { concat, concatBytes } from './concat'; +/** + * @group node + * @group browser + */ describe('concat', () => { it('should concatenate multiple BytesLike into a single Uint8Array', () => { const byteslike1 = '0xff61ba809b36351b'; @@ -14,7 +17,7 @@ describe('concat', () => { expect(output).toBeInstanceOf(Uint8Array); expect(output).toStrictEqual( - new Uint8Array([...getBytesCopy(byteslike1), ...byteslike2, ...byteslike3]) + new Uint8Array([...arrayify(byteslike1), ...byteslike2, ...byteslike3]) ); }); }); diff --git a/packages/utils/src/utils/concat.ts b/packages/utils/src/utils/concat.ts index 0ff1421993..699e645278 100644 --- a/packages/utils/src/utils/concat.ts +++ b/packages/utils/src/utils/concat.ts @@ -1,5 +1,6 @@ -import type { BytesLike } from 'ethers'; -import { getBytesCopy } from 'ethers'; +import type { BytesLike } from '@fuel-ts/interfaces'; + +import { arrayify } from './arrayify'; /** * Concatenates multiple Uint8Arrays into a single Uint8Array. @@ -35,7 +36,7 @@ export const concatBytes = ( * @returns - The concatenated array. */ export const concat = (arrays: ReadonlyArray): Uint8Array => { - const bytes = arrays.map((v) => getBytesCopy(v)); + const bytes = arrays.map((v) => arrayify(v)); return concatBytes(bytes); }; diff --git a/packages/utils/src/utils/defaultChainConfig.ts b/packages/utils/src/utils/defaultChainConfig.ts new file mode 100644 index 0000000000..fb4b3da471 --- /dev/null +++ b/packages/utils/src/utils/defaultChainConfig.ts @@ -0,0 +1,6 @@ +import chainConfigJson from './chainConfig.json'; + +export const defaultChainConfig = chainConfigJson; + +export const defaultConsensusKey = + '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298'; diff --git a/packages/utils/src/utils/hexlify.test.ts b/packages/utils/src/utils/hexlify.test.ts index f54ebf1f00..e90d7bcd87 100644 --- a/packages/utils/src/utils/hexlify.test.ts +++ b/packages/utils/src/utils/hexlify.test.ts @@ -1,5 +1,9 @@ import { hexlify } from './hexlify'; +/** + * @group node + * @group browser + */ describe('hexlify', () => { it('returns hex from bytes', () => { expect(hexlify(new Uint8Array([0, 1, 2, 3]))).toEqual('0x00010203'); diff --git a/packages/utils/src/utils/hexlify.ts b/packages/utils/src/utils/hexlify.ts index 3501427408..aca2d19768 100644 --- a/packages/utils/src/utils/hexlify.ts +++ b/packages/utils/src/utils/hexlify.ts @@ -1,5 +1,6 @@ -import type { BytesLike } from 'ethers'; -import { getBytes } from 'ethers'; +import type { BytesLike } from '@fuel-ts/interfaces'; + +import { arrayify } from './arrayify'; const HexCharacters: string = '0123456789abcdef'; @@ -7,7 +8,7 @@ const HexCharacters: string = '0123456789abcdef'; * Returns a hex representation of the inputted bytes. */ export function hexlify(data: BytesLike): string { - const bytes = getBytes(data); + const bytes = arrayify(data); let result = '0x'; for (let i = 0; i < bytes.length; i++) { diff --git a/packages/utils/src/utils/normalizeString.test.ts b/packages/utils/src/utils/normalizeString.test.ts index 3f5ab62def..c8f00c7962 100644 --- a/packages/utils/src/utils/normalizeString.test.ts +++ b/packages/utils/src/utils/normalizeString.test.ts @@ -2,6 +2,10 @@ import { safeExec } from '@fuel-ts/errors/test-utils'; import { normalizeString } from './normalizeString'; +/** + * @group node + * @group browser + */ describe('normalize.ts', () => { test('should normalize strings', () => { expect(normalizeString('DsToken')).toEqual('DsToken'); diff --git a/packages/utils/tsdoc.json b/packages/utils/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/utils/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/utils/tsup.config.ts b/packages/utils/tsup.config.ts index 4972257d81..ce3ba9f9ae 100644 --- a/packages/utils/tsup.config.ts +++ b/packages/utils/tsup.config.ts @@ -6,6 +6,7 @@ const configs: Options = { entry: { index: 'src/index.ts', 'test-utils': 'src/test-utils.ts', + 'cli-utils': 'src/cli-utils.ts', }, }; diff --git a/packages/versions/README.md b/packages/versions/README.md index 3b38dbad3a..5797b70f7f 100644 --- a/packages/versions/README.md +++ b/packages/versions/README.md @@ -26,7 +26,7 @@ Aditionally, the library can be used as a CLI tool to help checking/validating u -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Installation diff --git a/packages/versions/package.json b/packages/versions/package.json index fe3b8f5ae2..c9a8e6303f 100644 --- a/packages/versions/package.json +++ b/packages/versions/package.json @@ -10,7 +10,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -42,11 +42,9 @@ "license": "Apache-2.0", "dependencies": { "chalk": "4", - "cli-table": "^0.3.11", - "semver": "^7.3.8" + "cli-table": "^0.3.11" }, "devDependencies": { - "@types/cli-table": "^0.3.1", - "@types/semver": "^7.3.13" + "@types/cli-table": "^0.3.1" } } diff --git a/packages/versions/scripts/rewriteVersions.test.ts b/packages/versions/scripts/rewriteVersions.test.ts index 0c8937a0c4..dd90dee943 100644 --- a/packages/versions/scripts/rewriteVersions.test.ts +++ b/packages/versions/scripts/rewriteVersions.test.ts @@ -7,12 +7,17 @@ import { rewriteVersions, } from './rewriteVersions'; -// https://stackoverflow.com/a/72885576 -jest.mock('fs', () => ({ - __esModule: true, - ...jest.requireActual('fs'), -})); +vi.mock('fs', async () => { + const mod = await vi.importActual('fs'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('rewriteVersions.js', () => { function modifyEnv() { const envBackup = { ...process.env }; @@ -88,7 +93,7 @@ describe('rewriteVersions.js', () => { test('should rewrite files', () => { // mocking - const writeFileSync = jest.spyOn(fsMod, 'writeFileSync').mockImplementation(); + const writeFileSync = vi.spyOn(fsMod, 'writeFileSync').mockImplementation(() => []); // executing rewriteVersions(); diff --git a/packages/versions/scripts/rewriteVersions.ts b/packages/versions/scripts/rewriteVersions.ts index fd0f4c5275..5f1734bf51 100644 --- a/packages/versions/scripts/rewriteVersions.ts +++ b/packages/versions/scripts/rewriteVersions.ts @@ -63,7 +63,7 @@ export const rewriteVersions = () => { }; /* istanbul ignore next */ -// Do not auto-run script when inside jest runner -if (!/jest\.js$/m.test(process.argv[1])) { +// Do not auto-run script when inside vitest +if (!process.env.VITEST) { rewriteVersions(); } diff --git a/packages/versions/src/cli.test.ts b/packages/versions/src/cli.test.ts index 507479c565..2f972a0a7c 100644 --- a/packages/versions/src/cli.test.ts +++ b/packages/versions/src/cli.test.ts @@ -4,10 +4,18 @@ import * as compareSystemVersionsMod from './lib/compareSystemVersions'; import * as getBuiltinVersionsMod from './lib/getBuiltinVersions'; import * as getSystemVersionsMod from './lib/getSystemVersions'; +/** + * @group node + */ describe('cli.js', () => { // hooks - beforeEach(jest.clearAllMocks); - afterEach(jest.restoreAllMocks); + beforeEach(() => { + vi.resetAllMocks(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); /* Test (mocking) utility @@ -29,27 +37,27 @@ describe('cli.js', () => { systemForcIsEq, } = params; - const error = jest.spyOn(console, 'error').mockImplementation(); - const info = jest.spyOn(console, 'info').mockImplementation(); - const exit = jest.spyOn(process, 'exit').mockImplementation(); + const error = vi.spyOn(console, 'error').mockImplementation(() => []); + const info = vi.spyOn(console, 'info').mockImplementation(() => []); + const exit = vi.spyOn(process, 'exit').mockImplementation(vi.fn()); - jest - .spyOn(colorizeUserVersionMod, 'colorizeUserVersion') - .mockImplementation(({ version }) => version); + vi.spyOn(colorizeUserVersionMod, 'colorizeUserVersion').mockImplementation( + ({ version }) => version + ); - jest.spyOn(compareSystemVersionsMod, 'compareSystemVersions').mockImplementation(() => ({ + vi.spyOn(compareSystemVersionsMod, 'compareSystemVersions').mockImplementation(() => ({ systemForcIsGt, systemFuelCoreIsGt, systemForcIsEq, systemFuelCoreIsEq, })); - jest.spyOn(getSystemVersionsMod, 'getSystemVersions').mockImplementation(() => ({ + vi.spyOn(getSystemVersionsMod, 'getSystemVersions').mockImplementation(() => ({ systemForcVersion, systemFuelCoreVersion, })); - jest.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions').mockImplementation(() => ({ + vi.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions').mockImplementation(() => ({ FORC: '1.0.0', FUEL_CORE: '1.0.0', FUELS: '1.0.0', diff --git a/packages/versions/src/index.test.ts b/packages/versions/src/index.test.ts index 9dea598ecb..cedcafd7ff 100644 --- a/packages/versions/src/index.test.ts +++ b/packages/versions/src/index.test.ts @@ -1,5 +1,8 @@ import * as indexMod from './index'; +/** + * @group node + */ describe('index.js', () => { test('should export versions constant', () => { expect(indexMod.versions).toBeTruthy(); diff --git a/packages/versions/src/lib/checkFuelCoreVersionCompatibility.test.ts b/packages/versions/src/lib/checkFuelCoreVersionCompatibility.test.ts index 262a3ff067..876534d4e4 100644 --- a/packages/versions/src/lib/checkFuelCoreVersionCompatibility.test.ts +++ b/packages/versions/src/lib/checkFuelCoreVersionCompatibility.test.ts @@ -1,13 +1,18 @@ import { checkFuelCoreVersionCompatibility } from './checkFuelCoreVersionCompatibility'; import * as getBuiltinVersionsMod from './getBuiltinVersions'; +/** + * @group node + */ describe('getDifferenceToUserFuelCoreVersion', () => { - afterAll(() => jest.restoreAllMocks()); + afterEach(() => { + vi.restoreAllMocks(); + }); it('should validate all possible version mismatches', () => { const supportedVersion = '0.1.2'; - jest.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions').mockImplementation(() => ({ + vi.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions').mockImplementation(() => ({ FUELS: '1', // not under test FORC: '1', // not under test FUEL_CORE: supportedVersion, diff --git a/packages/versions/src/lib/checkFuelCoreVersionCompatibility.ts b/packages/versions/src/lib/checkFuelCoreVersionCompatibility.ts index 169644436c..b9fa9c4d0c 100644 --- a/packages/versions/src/lib/checkFuelCoreVersionCompatibility.ts +++ b/packages/versions/src/lib/checkFuelCoreVersionCompatibility.ts @@ -1,22 +1,13 @@ -import semver from 'semver'; - import { getBuiltinVersions } from './getBuiltinVersions'; +import { majorEq, minorEq, patchEq } from './semver'; export function checkFuelCoreVersionCompatibility(networkVersion: string) { const { FUEL_CORE: supportedVersion } = getBuiltinVersions(); - const networkMajor = semver.major(networkVersion); - const networkMinor = semver.minor(networkVersion); - const networkPatch = semver.patch(networkVersion); - - const supportedMajor = semver.major(supportedVersion); - const supportedMinor = semver.minor(supportedVersion); - const supportedPatch = semver.patch(supportedVersion); - return { supportedVersion, - isMajorSupported: networkMajor === supportedMajor, - isMinorSupported: networkMinor === supportedMinor, - isPatchSupported: networkPatch === supportedPatch, + isMajorSupported: majorEq(networkVersion, supportedVersion), + isMinorSupported: minorEq(networkVersion, supportedVersion), + isPatchSupported: patchEq(networkVersion, supportedVersion), }; } diff --git a/packages/versions/src/lib/colorizeUserVersion.test.ts b/packages/versions/src/lib/colorizeUserVersion.test.ts index d7ea91b1bf..ba9479353f 100644 --- a/packages/versions/src/lib/colorizeUserVersion.test.ts +++ b/packages/versions/src/lib/colorizeUserVersion.test.ts @@ -2,6 +2,9 @@ import { cyan, red, green } from 'chalk'; import { colorizeUserVersion } from './colorizeUserVersion'; +/** + * @group node + */ describe('colorizeUserVersion.js', () => { test('should colorize user versions just fine', () => { const version = '1.0.0'; diff --git a/packages/versions/src/lib/compareSystemVersions.test.ts b/packages/versions/src/lib/compareSystemVersions.test.ts index 6e634882a1..e4003a7b5d 100644 --- a/packages/versions/src/lib/compareSystemVersions.test.ts +++ b/packages/versions/src/lib/compareSystemVersions.test.ts @@ -1,17 +1,22 @@ import { compareSystemVersions } from './compareSystemVersions'; import * as getBuiltinVersionsMod from './getBuiltinVersions'; +/** + * @group node + */ describe('compareSystemVersions.js', () => { /* Hooks */ beforeEach(() => { const v = '1.0.0'; - const spy = jest.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions'); + const spy = vi.spyOn(getBuiltinVersionsMod, 'getBuiltinVersions'); spy.mockImplementation(() => ({ FUELS: v, FORC: v, FUEL_CORE: v })); }); - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); /* Tests diff --git a/packages/versions/src/lib/compareSystemVersions.ts b/packages/versions/src/lib/compareSystemVersions.ts index 2cc7dd566c..12f4779409 100644 --- a/packages/versions/src/lib/compareSystemVersions.ts +++ b/packages/versions/src/lib/compareSystemVersions.ts @@ -1,6 +1,5 @@ -import semver from 'semver'; - import { getBuiltinVersions } from './getBuiltinVersions'; +import { gt, eq } from './semver'; export interface ICompareVersionsParams { systemForcVersion: string; @@ -13,12 +12,12 @@ export function compareSystemVersions(params: ICompareVersionsParams) { const versions = getBuiltinVersions(); // are user's versions GREATER than the ones supported by the SDK? - const systemForcIsGt = semver.gt(systemForcVersion, versions.FORC); - const systemFuelCoreIsGt = semver.gt(systemFuelCoreVersion, versions.FUEL_CORE); + const systemForcIsGt = gt(systemForcVersion, versions.FORC); + const systemFuelCoreIsGt = gt(systemFuelCoreVersion, versions.FUEL_CORE); // are user's versions EXACTLY the ones supported by the SDK? - const systemForcIsEq = semver.eq(systemForcVersion, versions.FORC); - const systemFuelCoreIsEq = semver.eq(systemFuelCoreVersion, versions.FUEL_CORE); + const systemForcIsEq = eq(systemForcVersion, versions.FORC); + const systemFuelCoreIsEq = eq(systemFuelCoreVersion, versions.FUEL_CORE); return { systemForcIsGt, diff --git a/packages/versions/src/lib/getBuiltinVersions.test.ts b/packages/versions/src/lib/getBuiltinVersions.test.ts index b090636ce1..fc7c09e9fd 100644 --- a/packages/versions/src/lib/getBuiltinVersions.test.ts +++ b/packages/versions/src/lib/getBuiltinVersions.test.ts @@ -2,6 +2,9 @@ import { readVersionsFromFiles } from '../../scripts/rewriteVersions'; import { getBuiltinVersions } from './getBuiltinVersions'; +/** + * @group node + */ describe('getBuiltinVersions.js', () => { test('should return received version of default', () => { const versions = getBuiltinVersions(); diff --git a/packages/versions/src/lib/getSystemVersions.test.ts b/packages/versions/src/lib/getSystemVersions.test.ts index f09f445bdc..e5f8747746 100644 --- a/packages/versions/src/lib/getSystemVersions.test.ts +++ b/packages/versions/src/lib/getSystemVersions.test.ts @@ -2,12 +2,17 @@ import * as childProcessMod from 'child_process'; import { getSystemVersions } from './getSystemVersions'; -// https://stackoverflow.com/a/72885576 -jest.mock('child_process', () => ({ - __esModule: true, - ...jest.requireActual('child_process'), -})); +vi.mock('child_process', async () => { + const mod = await vi.importActual('child_process'); + return { + __esModule: true, + ...mod, + }; +}); +/** + * @group node + */ describe('getSystemVersions.js', () => { /* Test (mocking) utility @@ -19,17 +24,17 @@ describe('getSystemVersions.js', () => { }) { const { systemForcVersion, systemFuelCoreVersion, shouldThrow } = params; - const error = jest.spyOn(console, 'error').mockImplementation(); + const error = vi.spyOn(console, 'error').mockImplementation(() => []); - const mockedExecOk = jest.fn(); + const mockedExecOk = vi.fn(); mockedExecOk.mockReturnValueOnce(systemForcVersion); // first call (forc) mockedExecOk.mockReturnValueOnce(systemFuelCoreVersion); // second call (fuel-core) - const execSyncThrow = jest.fn(() => { + const execSyncThrow = vi.fn(() => { throw new Error(); }); - const execSync = jest + const execSync = vi .spyOn(childProcessMod, 'execSync') .mockImplementation(shouldThrow ? execSyncThrow : mockedExecOk); diff --git a/packages/versions/src/lib/semver.test.ts b/packages/versions/src/lib/semver.test.ts new file mode 100644 index 0000000000..e1ea836b54 --- /dev/null +++ b/packages/versions/src/lib/semver.test.ts @@ -0,0 +1,43 @@ +import { eq, gt, majorEq, minorEq, patchEq } from './semver'; + +/** + * @group node + */ +describe('semver', () => { + test('majorEq', () => { + expect(majorEq('1.2.3', '1.2.3')).toBe(true); + expect(majorEq('1.2.3', '1.2.4')).toBe(true); + expect(majorEq('1.2.3', '1.3.3')).toBe(true); + expect(majorEq('1.2.3', '2.2.3')).toBe(false); + }); + test('minorEq', () => { + expect(minorEq('1.2.3', '1.2.3')).toBe(true); + expect(minorEq('1.2.3', '1.2.4')).toBe(true); + expect(minorEq('1.2.3', '2.2.3')).toBe(true); + expect(minorEq('1.2.3', '1.3.3')).toBe(false); + }); + test('patchEq', () => { + expect(patchEq('1.2.3', '1.2.3')).toBe(true); + expect(patchEq('1.2.3', '1.3.3')).toBe(true); + expect(patchEq('1.2.3', '2.2.3')).toBe(true); + expect(patchEq('1.2.3', '1.2.4')).toBe(false); + }); + test('gt', () => { + expect(gt('1.2.3', '0.2.3')).toBe(true); + expect(gt('1.2.3', '1.1.3')).toBe(true); + expect(gt('1.2.3', '1.2.2')).toBe(true); + expect(gt('1.2.3', '1.2.3')).toBe(false); + expect(gt('1.2.3', '2.2.3')).toBe(false); + expect(gt('1.2.3', '1.3.3')).toBe(false); + expect(gt('1.2.3', '1.2.4')).toBe(false); + }); + test('eq', () => { + expect(eq('1.2.3', '1.2.3')).toBe(true); + expect(eq('1.2.3', '0.2.3')).toBe(false); + expect(eq('1.2.3', '2.2.3')).toBe(false); + expect(eq('1.2.3', '1.1.3')).toBe(false); + expect(eq('1.2.3', '1.3.3')).toBe(false); + expect(eq('1.2.3', '1.2.2')).toBe(false); + expect(eq('1.2.3', '1.2.4')).toBe(false); + }); +}); diff --git a/packages/versions/src/lib/semver.ts b/packages/versions/src/lib/semver.ts new file mode 100644 index 0000000000..a479e2670e --- /dev/null +++ b/packages/versions/src/lib/semver.ts @@ -0,0 +1,46 @@ +function parseVersion(version: string): { major: number; minor: number; patch: number } { + const [major, minor, patch] = version.split('.').map((v) => parseInt(v, 10)); + return { major, minor, patch }; +} + +function versionDiffs( + version1: string, + version2: string +): { major: number; minor: number; patch: number; fullVersionDiff: number } { + const semver1 = parseVersion(version1); + const semver2 = parseVersion(version2); + const major = semver1.major - semver2.major; + const minor = semver1.minor - semver2.minor; + const patch = semver1.patch - semver2.patch; + return { + major, + minor, + patch, + fullVersionDiff: major || minor || patch, + }; +} + +export function gt(version1: string, version2: string): boolean { + const { fullVersionDiff } = versionDiffs(version1, version2); + return fullVersionDiff > 0; +} + +export function eq(version1: string, version2: string): boolean { + const { fullVersionDiff } = versionDiffs(version1, version2); + return fullVersionDiff === 0; +} + +export function majorEq(version1: string, version2: string): boolean { + const { major } = versionDiffs(version1, version2); + return major === 0; +} + +export function minorEq(version1: string, version2: string): boolean { + const { minor } = versionDiffs(version1, version2); + return minor === 0; +} + +export function patchEq(version1: string, version2: string): boolean { + const { patch } = versionDiffs(version1, version2); + return patch === 0; +} diff --git a/packages/versions/tsdoc.json b/packages/versions/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/versions/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/wallet-manager/README.md b/packages/wallet-manager/README.md index d7bd4fa85f..9b443fd0ef 100644 --- a/packages/wallet-manager/README.md +++ b/packages/wallet-manager/README.md @@ -18,7 +18,7 @@ This module is a coordination wrapper to manage multiple wallet `Vaults` and sto -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/wallet-manager/package.json b/packages/wallet-manager/package.json index f5a5c4f487..260016b597 100644 --- a/packages/wallet-manager/package.json +++ b/packages/wallet-manager/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/wallet-manager/src/storages/memory-storage.test.ts b/packages/wallet-manager/src/storages/memory-storage.test.ts index 77e64a640b..bc3a0ca6c8 100644 --- a/packages/wallet-manager/src/storages/memory-storage.test.ts +++ b/packages/wallet-manager/src/storages/memory-storage.test.ts @@ -1,5 +1,9 @@ import MemoryStorage from './memory-storage'; +/** + * @group node + * @group browser + */ describe('MemoryStorage', () => { it('Test storage operations', async () => { const storage = new MemoryStorage(); diff --git a/packages/wallet-manager/src/vaults/mnemonic-vault.test.ts b/packages/wallet-manager/src/vaults/mnemonic-vault.test.ts index 68cbf785c7..0705ae4275 100644 --- a/packages/wallet-manager/src/vaults/mnemonic-vault.test.ts +++ b/packages/wallet-manager/src/vaults/mnemonic-vault.test.ts @@ -6,6 +6,10 @@ import walletManagerSpec from '../wallet-manager-spec'; import { MnemonicVault } from './mnemonic-vault'; +/** + * @group node + * @group browser + */ describe('MnemonicVault', () => { let provider: Provider; @@ -22,7 +26,9 @@ describe('MnemonicVault', () => { vault.addAccount(); - expect(vault.getWallet(wallet.address).publicKey).toBe(walletManagerSpec.account_0.publicKey); + expect(vault.getWallet(wallet.address.toString()).publicKey).toBe( + walletManagerSpec.account_0.publicKey + ); }); it('Check if accounts are been added correctly', async () => { diff --git a/packages/wallet-manager/src/vaults/mnemonic-vault.ts b/packages/wallet-manager/src/vaults/mnemonic-vault.ts index 0047ca5431..2d8bfc8219 100644 --- a/packages/wallet-manager/src/vaults/mnemonic-vault.ts +++ b/packages/wallet-manager/src/vaults/mnemonic-vault.ts @@ -1,3 +1,4 @@ +import { Address } from '@fuel-ts/address'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { AbstractAddress } from '@fuel-ts/interfaces'; import { Mnemonic } from '@fuel-ts/mnemonic'; @@ -82,9 +83,9 @@ export class MnemonicVault implements Vault { }; } - exportAccount(address: AbstractAddress): string { + exportAccount(address: string | AbstractAddress): string { let numberOfAccounts = 0; - + const ownerAddress = Address.fromAddressOrString(address); // Look for the account that has the same address do { const wallet = Wallet.fromMnemonic( @@ -92,7 +93,7 @@ export class MnemonicVault implements Vault { this.provider, this.getDerivePath(numberOfAccounts) ); - if (wallet.address.equals(address)) { + if (wallet.address.equals(ownerAddress)) { return wallet.privateKey; } numberOfAccounts += 1; @@ -104,7 +105,7 @@ export class MnemonicVault implements Vault { ); } - getWallet(address: AbstractAddress): WalletUnlocked { + getWallet(address: string | AbstractAddress): WalletUnlocked { const privateKey = this.exportAccount(address); return Wallet.fromPrivateKey(privateKey, this.provider); } diff --git a/packages/wallet-manager/src/vaults/privatekey-vault.test.ts b/packages/wallet-manager/src/vaults/privatekey-vault.test.ts index db1bc98f6f..b6954c4c0c 100644 --- a/packages/wallet-manager/src/vaults/privatekey-vault.test.ts +++ b/packages/wallet-manager/src/vaults/privatekey-vault.test.ts @@ -6,6 +6,10 @@ import { FUEL_NETWORK_URL } from '@fuel-ts/wallet/configs'; import { PrivateKeyVault } from './privatekey-vault'; +/** + * @group node + * @group browser + */ describe('PrivateKeyVault', () => { let provider: Provider; let walletSpec: WalletUnlocked; diff --git a/packages/wallet-manager/src/vaults/privatekey-vault.ts b/packages/wallet-manager/src/vaults/privatekey-vault.ts index 75698e080e..bf2322c09c 100644 --- a/packages/wallet-manager/src/vaults/privatekey-vault.ts +++ b/packages/wallet-manager/src/vaults/privatekey-vault.ts @@ -1,3 +1,4 @@ +import { Address } from '@fuel-ts/address'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; import type { AbstractAddress } from '@fuel-ts/interfaces'; import type { Provider } from '@fuel-ts/providers'; @@ -64,9 +65,10 @@ export class PrivateKeyVault implements Vault { return this.getPublicAccount(wallet.privateKey); } - exportAccount(address: AbstractAddress): string { + exportAccount(address: string | AbstractAddress): string { + const ownerAddress = Address.fromAddressOrString(address); const privateKey = this.#privateKeys.find((pk) => - Wallet.fromPrivateKey(pk, this.provider).address.equals(address) + Wallet.fromPrivateKey(pk, this.provider).address.equals(ownerAddress) ); if (!privateKey) { @@ -79,7 +81,7 @@ export class PrivateKeyVault implements Vault { return privateKey; } - getWallet(address: AbstractAddress): WalletUnlocked { + getWallet(address: string | AbstractAddress): WalletUnlocked { const privateKey = this.exportAccount(address); return Wallet.fromPrivateKey(privateKey, this.provider); } diff --git a/packages/wallet-manager/src/wallet-manager.test.ts b/packages/wallet-manager/src/wallet-manager.test.ts index 8e64a99719..207a85307b 100644 --- a/packages/wallet-manager/src/wallet-manager.test.ts +++ b/packages/wallet-manager/src/wallet-manager.test.ts @@ -10,6 +10,9 @@ import type { VaultConfig } from './types'; import { WalletManager } from './wallet-manager'; import WalletManagerSpec from './wallet-manager-spec'; +/** + * @group node + */ describe('Wallet Manager', () => { let provider: Provider; @@ -325,16 +328,16 @@ describe('Wallet Manager', () => { provider, }); // Create object with methods to be able to - // use Jest.spyOn + // use vi.spyOn const listeners = { onLock: () => {}, onUnlock: () => {}, onUpdate: () => {}, }; - const apyLock = jest.spyOn(listeners, 'onLock'); - const spyUnlock = jest.spyOn(listeners, 'onUnlock'); - const spyUpdate = jest.spyOn(listeners, 'onUpdate'); + const apyLock = vi.spyOn(listeners, 'onLock'); + const spyUnlock = vi.spyOn(listeners, 'onUnlock'); + const spyUpdate = vi.spyOn(listeners, 'onUpdate'); walletManager.on('update', listeners.onUpdate); walletManager.on('lock', listeners.onLock); diff --git a/packages/wallet-manager/src/wallet-manager.ts b/packages/wallet-manager/src/wallet-manager.ts index 1259d1810a..fd4f710f15 100644 --- a/packages/wallet-manager/src/wallet-manager.ts +++ b/packages/wallet-manager/src/wallet-manager.ts @@ -1,3 +1,4 @@ +import { Address } from '@fuel-ts/address'; import type { Keystore } from '@fuel-ts/crypto'; import { encrypt, decrypt } from '@fuel-ts/crypto'; import { ErrorCode, FuelError } from '@fuel-ts/errors'; @@ -110,26 +111,28 @@ export class WalletManager extends EventEmitter { /** * Create a Wallet instance for the specific account */ - getWallet(address: AbstractAddress): WalletUnlocked { + getWallet(address: string | AbstractAddress): WalletUnlocked { + const ownerAddress = Address.fromAddressOrString(address); const vaultState = this.#vaults.find((vs) => - vs.vault.getAccounts().find((a) => a.address.equals(address)) + vs.vault.getAccounts().find((a) => a.address.equals(ownerAddress)) ); assert(vaultState, ERROR_MESSAGES.address_not_found); - return vaultState.vault.getWallet(address); + return vaultState.vault.getWallet(ownerAddress); } /** * Export specific account privateKey */ - exportPrivateKey(address: AbstractAddress) { + exportPrivateKey(address: string | AbstractAddress) { + const ownerAddress = Address.fromAddressOrString(address); assert(!this.#isLocked, ERROR_MESSAGES.wallet_not_unlocked); const vaultState = this.#vaults.find((vs) => - vs.vault.getAccounts().find((a) => a.address.equals(address)) + vs.vault.getAccounts().find((a) => a.address.equals(ownerAddress)) ); assert(vaultState, ERROR_MESSAGES.address_not_found); - return vaultState.vault.exportAccount(address); + return vaultState.vault.exportAccount(ownerAddress); } /** diff --git a/packages/wallet-manager/tsdoc.json b/packages/wallet-manager/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/wallet-manager/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/packages/wallet/README.md b/packages/wallet/README.md index 4ff975221b..5a8d7f9796 100644 --- a/packages/wallet/README.md +++ b/packages/wallet/README.md @@ -16,7 +16,7 @@ This module contains the class to manage a private key and signing for a standar ## Documentation -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/guide/wallets/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/wallets/) ## Usage diff --git a/packages/wallet/package.json b/packages/wallet/package.json index 4d05feaf57..70153c6cc1 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -7,7 +7,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { @@ -48,6 +48,7 @@ "@fuel-ts/abi-coder": "workspace:*", "@fuel-ts/address": "workspace:*", "@fuel-ts/crypto": "workspace:*", + "@fuel-ts/errors": "workspace:*", "@fuel-ts/fuel-core": "workspace:*", "@fuel-ts/hasher": "workspace:*", "@fuel-ts/hdwallet": "workspace:*", @@ -59,7 +60,6 @@ "@fuel-ts/transactions": "workspace:*", "@fuel-ts/utils": "workspace:*", "@fuels/vm-asm": "0.42.1", - "@fuel-ts/errors": "workspace:*", "ethers": "^6.7.1", "portfinder": "^1.0.32", "tree-kill": "^1.2.2", diff --git a/packages/wallet/src/account.test.ts b/packages/wallet/src/account.test.ts index 95207fb885..e0259eabe5 100644 --- a/packages/wallet/src/account.test.ts +++ b/packages/wallet/src/account.test.ts @@ -16,19 +16,27 @@ import type { TxParamsType } from './account'; import { Account } from './account'; import { FUEL_NETWORK_URL } from './configs'; -jest.mock('@fuel-ts/providers', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/providers'), -})); +vi.mock('@fuel-ts/providers', async () => { + const mod = await vi.importActual('@fuel-ts/providers'); + return { + __esModule: true, + ...mod, + }; +}); let provider: Provider; -afterEach(jest.restoreAllMocks); +afterEach(() => { + vi.restoreAllMocks(); +}); beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); }); +/** + * @group node + */ describe('Account', () => { const assets = [ '0x0101010101010101010101010101010101010101010101010101010101010101', @@ -36,7 +44,7 @@ describe('Account', () => { '0x0000000000000000000000000000000000000000000000000000000000000000', ]; - it('Create wallet using a address', () => { + it('should create account using an address, with a provider', () => { const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', provider @@ -46,6 +54,22 @@ describe('Account', () => { ); }); + it('should create account using an address, without a provider', () => { + const account = new Account( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' + ); + expect(account.address.toB256()).toEqual( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' + ); + }); + + it('should throw an error when using a provider dependent method, without a provider', async () => { + const account = new Account( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db' + ); + await expect(() => account.getBalance()).rejects.toThrow(/Provider not set/); + }); + it('should get coins just fine', async () => { const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', @@ -63,9 +87,9 @@ describe('Account', () => { it('should throw if coins length is higher than 9999', async () => { const dummyCoins: Coin[] = new Array(10000); - const getCoins = async () => Promise.resolve(dummyCoins); - - jest.spyOn(providersMod.Provider.prototype, 'getCoins').mockImplementation(getCoins); + vi.spyOn(Provider.prototype, 'getCoins').mockImplementation(async () => + Promise.resolve(dummyCoins) + ); const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', @@ -127,12 +151,11 @@ describe('Account', () => { }); it('should throw if messages length is higher than 9999', async () => { - // mocking - const messages: Message[] = new Array(10000); - const mockedGetMessages = async () => Promise.resolve(messages); - jest - .spyOn(providersMod.Provider.prototype, 'getMessages') - .mockImplementationOnce(mockedGetMessages); + const dummyMessages: Message[] = new Array(10000); + + vi.spyOn(Provider.prototype, 'getMessages').mockImplementation(async () => + Promise.resolve(dummyMessages) + ); const account = new Account( '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba', @@ -175,13 +198,11 @@ describe('Account', () => { }); it('should throw if balances length is higher than 9999', async () => { - const dummyBalace: CoinQuantity[] = new Array(10000); - - const mockedGetBalances = async () => Promise.resolve(dummyBalace); + const dummyBalances: CoinQuantity[] = new Array(10000); - jest - .spyOn(providersMod.Provider.prototype, 'getBalances') - .mockImplementation(mockedGetBalances); + vi.spyOn(Provider.prototype, 'getBalances').mockImplementation(async () => + Promise.resolve(dummyBalances) + ); const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', @@ -218,6 +239,21 @@ describe('Account', () => { expect(account.provider).not.toBe(provider); }); + it('should be able to set a provider', async () => { + const account = new Account( + '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', + provider + ); + const newProviderInstance = await Provider.create(FUEL_NETWORK_URL); + + expect(account.provider).not.toBe(newProviderInstance); + + account.provider = newProviderInstance; + + expect(account.provider).toBe(newProviderInstance); + expect(account.provider).not.toBe(provider); + }); + it('should execute fund just as fine', async () => { const quantities: CoinQuantity[] = [ { @@ -230,13 +266,13 @@ describe('Account', () => { const request = new ScriptTransactionRequest(); const resourcesToSpend: Resource[] = []; - const getResourcesToSpendSpy = jest + const getResourcesToSpendSpy = vi .spyOn(Account.prototype, 'getResourcesToSpend') .mockImplementationOnce(() => Promise.resolve(resourcesToSpend)); - const addResourcesSpy = jest.spyOn(request, 'addResources'); + const addResourcesSpy = vi.spyOn(request, 'addResources'); - const addAmountToAssetSpy = jest.spyOn(providersMod, 'addAmountToAsset'); + const addAmountToAssetSpy = vi.spyOn(providersMod, 'addAmountToAsset'); const account = new Account( '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', @@ -292,21 +328,19 @@ describe('Account', () => { }; const request = new ScriptTransactionRequest(); - jest.spyOn(providersMod, 'ScriptTransactionRequest').mockImplementation(() => request); + vi.spyOn(providersMod, 'ScriptTransactionRequest').mockImplementation(() => request); const transactionResponse = new TransactionResponse('transactionId', provider); - const addCoinOutputSpy = jest.spyOn(request, 'addCoinOutput'); + const addCoinOutputSpy = vi.spyOn(request, 'addCoinOutput'); - const fundSpy = jest - .spyOn(Account.prototype, 'fund') - .mockImplementation(() => Promise.resolve()); + const fundSpy = vi.spyOn(Account.prototype, 'fund').mockImplementation(() => Promise.resolve()); - const sendTransactionSpy = jest + const sendTransactionSpy = vi .spyOn(Account.prototype, 'sendTransaction') .mockImplementation(() => Promise.resolve(transactionResponse)); - const getTransactionCost = jest + const getTransactionCost = vi .spyOn(Provider.prototype, 'getTransactionCost') .mockImplementation(() => Promise.resolve(transactionCost)); @@ -363,17 +397,17 @@ describe('Account', () => { const transactionResponse = {} as unknown as TransactionResponse; - const scriptTransactionRequest = jest + const scriptTransactionRequest = vi .spyOn(providersMod, 'ScriptTransactionRequest') .mockImplementation(() => request); - const getTransactionCost = jest + const getTransactionCost = vi .spyOn(providersMod.Provider.prototype, 'getTransactionCost') .mockImplementation(() => Promise.resolve(cost)); - const fund = jest.spyOn(Account.prototype, 'fund').mockImplementation(() => Promise.resolve()); + const fund = vi.spyOn(Account.prototype, 'fund').mockImplementation(() => Promise.resolve()); - const sendTransaction = jest + const sendTransaction = vi .spyOn(Account.prototype, 'sendTransaction') .mockImplementation(() => Promise.resolve(transactionResponse)); @@ -412,13 +446,13 @@ describe('Account', () => { const transactionRequest = new ScriptTransactionRequest(); const transactionResponse = 'transactionResponse' as unknown as TransactionResponse; - const transactionRequestify = jest.spyOn(providersMod, 'transactionRequestify'); + const transactionRequestify = vi.spyOn(providersMod, 'transactionRequestify'); - const estimateTxDependencies = jest + const estimateTxDependencies = vi .spyOn(providersMod.Provider.prototype, 'estimateTxDependencies') .mockImplementation(() => Promise.resolve()); - const sendTransaction = jest + const sendTransaction = vi .spyOn(providersMod.Provider.prototype, 'sendTransaction') .mockImplementation(() => Promise.resolve(transactionResponse)); @@ -448,15 +482,15 @@ describe('Account', () => { const transactionRequest = new ScriptTransactionRequest(); const callResult = 'callResult' as unknown as CallResult; - const transactionRequestify = jest + const transactionRequestify = vi .spyOn(providersMod, 'transactionRequestify') .mockImplementation(() => transactionRequest); - const estimateTxDependencies = jest + const estimateTxDependencies = vi .spyOn(providersMod.Provider.prototype, 'estimateTxDependencies') .mockImplementation(() => Promise.resolve()); - const simulate = jest + const simulate = vi .spyOn(providersMod.Provider.prototype, 'simulate') .mockImplementation(() => Promise.resolve(callResult)); diff --git a/packages/wallet/src/account.ts b/packages/wallet/src/account.ts index 5a5f0eebd3..9692c7d1db 100644 --- a/packages/wallet/src/account.ts +++ b/packages/wallet/src/account.ts @@ -18,6 +18,7 @@ import type { TransactionResponse, Provider, ScriptTransactionRequestLike, + ProviderSendTxParams, } from '@fuel-ts/providers'; import { withdrawScript, @@ -50,20 +51,44 @@ export class Account extends AbstractAccount { /** * The provider used to interact with the network. */ - provider: Provider; + protected _provider?: Provider; /** * Creates a new Account instance. * * @param address - The address of the account. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). */ - constructor(address: string | AbstractAddress, provider: Provider) { + constructor(address: string | AbstractAddress, provider?: Provider) { super(); - this.provider = provider; + this._provider = provider; this.address = Address.fromDynamicInput(address); } + /** + * The provider used to interact with the network. + * + * @returns A Provider instance. + * + * @throws `FuelError` if the provider is not set. + */ + get provider(): Provider { + if (!this._provider) { + throw new FuelError(ErrorCode.MISSING_PROVIDER, 'Provider not set'); + } + + return this._provider; + } + + /** + * Sets the provider for the account. + * + * @param provider - A Provider instance. + */ + set provider(provider: Provider) { + this._provider = provider; + } + /** * Changes the provider connection for the account. * @@ -71,7 +96,7 @@ export class Account extends AbstractAccount { * @returns The updated Provider instance. */ connect(provider: Provider): Provider { - this.provider = provider; + this._provider = provider; return this.provider; } @@ -292,7 +317,7 @@ export class Account extends AbstractAccount { */ async createTransfer( /** Address of the destination */ - destination: AbstractAddress, + destination: string | AbstractAddress, /** Amount of coins */ amount: BigNumberish, /** Asset ID of coins */ @@ -303,7 +328,7 @@ export class Account extends AbstractAccount { const { minGasPrice } = this.provider.getGasConfig(); const params = { gasPrice: minGasPrice, ...txParams }; const request = new ScriptTransactionRequest(params); - request.addCoinOutput(destination, amount, assetId); + request.addCoinOutput(Address.fromAddressOrString(destination), amount, assetId); const { maxFee, requiredQuantities } = await this.provider.getTransactionCost(request); await this.fund(request, requiredQuantities, maxFee); return request; @@ -320,7 +345,7 @@ export class Account extends AbstractAccount { */ async transfer( /** Address of the destination */ - destination: AbstractAddress, + destination: string | AbstractAddress, /** Amount of coins */ amount: BigNumberish, /** Asset ID of coins */ @@ -343,7 +368,7 @@ export class Account extends AbstractAccount { */ async transferToContract( /** Contract address */ - contractId: AbstractAddress, + contractId: string | AbstractAddress, /** Amount of coins */ amount: BigNumberish, /** Asset ID of coins */ @@ -351,13 +376,14 @@ export class Account extends AbstractAccount { /** Tx Params */ txParams: TxParamsType = {} ): Promise { + const contractAddress = Address.fromAddressOrString(contractId); const { minGasPrice } = this.provider.getGasConfig(); const params = { gasPrice: minGasPrice, ...txParams }; const script = await composeScriptForTransferringToContract(); const scriptData = formatScriptDataForTransferringToContract( - contractId.toB256(), + contractAddress.toB256(), amount, assetId ); @@ -368,7 +394,7 @@ export class Account extends AbstractAccount { scriptData, }); - request.addContractInputAndOutput(contractId); + request.addContractInputAndOutput(contractAddress); const { maxFee, requiredQuantities } = await this.provider.getTransactionCost(request, [ { amount: bn(amount), assetId: String(assetId) }, @@ -389,15 +415,16 @@ export class Account extends AbstractAccount { */ async withdrawToBaseLayer( /** Address of the recipient on the base chain */ - recipient: AbstractAddress, + recipient: string | AbstractAddress, /** Amount of base asset */ amount: BigNumberish, /** Tx Params */ txParams: TxParamsType = {} ): Promise { + const recipientAddress = Address.fromAddressOrString(recipient); // add recipient and amount to the transaction script code const recipientDataArray = getBytesCopy( - '0x'.concat(recipient.toHexString().substring(2).padStart(64, '0')) + '0x'.concat(recipientAddress.toHexString().substring(2).padStart(64, '0')) ); const amountDataArray = getBytesCopy( '0x'.concat(bn(amount).toHex().substring(2).padStart(16, '0')) @@ -429,11 +456,15 @@ export class Account extends AbstractAccount { * @returns A promise that resolves to the transaction response. */ async sendTransaction( - transactionRequestLike: TransactionRequestLike + transactionRequestLike: TransactionRequestLike, + options?: Pick ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); await this.provider.estimateTxDependencies(transactionRequest); - return this.provider.sendTransaction(transactionRequest, { estimateTxDependencies: false }); + return this.provider.sendTransaction(transactionRequest, { + ...options, + estimateTxDependencies: false, + }); } /** diff --git a/packages/wallet/src/base-unlocked-wallet.ts b/packages/wallet/src/base-unlocked-wallet.ts index d26627465d..69a1912a25 100644 --- a/packages/wallet/src/base-unlocked-wallet.ts +++ b/packages/wallet/src/base-unlocked-wallet.ts @@ -4,6 +4,7 @@ import type { TransactionRequestLike, CallResult, Provider, + ProviderSendTxParams, } from '@fuel-ts/providers'; import { transactionRequestify } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; @@ -21,11 +22,6 @@ export class BaseWalletUnlocked extends Account { */ static defaultPath = "m/44'/1179993420'/0'/0/0"; - /** - * The provider used to interact with the Fuel network. - */ - provider: Provider; - /** * A function that returns the wallet's signer. */ @@ -35,13 +31,12 @@ export class BaseWalletUnlocked extends Account { * Creates a new BaseWalletUnlocked instance. * * @param privateKey - The private key of the wallet. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). */ - constructor(privateKey: BytesLike, provider: Provider) { + constructor(privateKey: BytesLike, provider?: Provider) { const signer = new Signer(privateKey); super(signer.address, provider); this.signer = () => signer; - this.provider = provider; } /** @@ -110,13 +105,14 @@ export class BaseWalletUnlocked extends Account { * @returns A promise that resolves to the TransactionResponse object. */ async sendTransaction( - transactionRequestLike: TransactionRequestLike + transactionRequestLike: TransactionRequestLike, + options?: Pick ): Promise { const transactionRequest = transactionRequestify(transactionRequestLike); await this.provider.estimateTxDependencies(transactionRequest); return this.provider.sendTransaction( await this.populateTransactionWitnessesSignature(transactionRequest), - { estimateTxDependencies: false } + { ...options, estimateTxDependencies: false } ); } diff --git a/packages/wallet/src/configs.test.ts b/packages/wallet/src/configs.test.ts index 1e71827fa9..dd336caf8a 100644 --- a/packages/wallet/src/configs.test.ts +++ b/packages/wallet/src/configs.test.ts @@ -1,3 +1,6 @@ +/** + * @group node + */ describe('Configs', () => { it('exports FUEL_NETWORK_URL', async () => { const configs = await import('./configs'); @@ -9,7 +12,7 @@ describe('Configs - undefined process', () => { const originalProcess = process; beforeEach(() => { - jest.resetModules(); + vi.resetModules(); // @ts-expect-error - test to assert undefined process // eslint-disable-next-line no-global-assign @@ -35,7 +38,7 @@ describe('Configs - overridden env', () => { const originalEnv = process.env; beforeEach(() => { - jest.resetModules(); + vi.resetModules(); process.env = { ...originalEnv, FUEL_NETWORK_URL: 'some-other-network-url' }; }); diff --git a/packages/wallet/src/keystore-wallet.test.ts b/packages/wallet/src/keystore-wallet.test.ts index 5569282f16..c68d6331ac 100644 --- a/packages/wallet/src/keystore-wallet.test.ts +++ b/packages/wallet/src/keystore-wallet.test.ts @@ -3,8 +3,13 @@ import { safeExec } from '@fuel-ts/errors/test-utils'; import { decryptKeystoreWallet, encryptKeystoreWallet, removeHexPrefix } from './keystore-wallet'; +/** + * @group node + */ describe('Keystore Wallet', () => { - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); const privateKey = '0xeac85e732b683119e62fb52ce3b04c0d2f60539cd55af34c731fcdcf802e5ef4'; @@ -15,7 +20,7 @@ describe('Keystore Wallet', () => { it('should return a valid keystore when given correct parameters', async () => { // Act - const keystore = await encryptKeystoreWallet(privateKey, address, password); + const keystore = await encryptKeystoreWallet(privateKey, address.toB256(), password); // Assert expect(keystore).toBeTruthy(); diff --git a/packages/wallet/src/keystore-wallet.ts b/packages/wallet/src/keystore-wallet.ts index 43f90fc203..145c43c9de 100644 --- a/packages/wallet/src/keystore-wallet.ts +++ b/packages/wallet/src/keystore-wallet.ts @@ -1,3 +1,4 @@ +import { Address } from '@fuel-ts/address'; import { bufferFromString, keccak256, @@ -57,12 +58,12 @@ export const removeHexPrefix = (hexString: string) => { export async function encryptKeystoreWallet( privateKey: string, - address: AbstractAddress, + address: string | AbstractAddress, password: string ): Promise { // Convert the hexlified private key string to a Buffer. const privateKeyBuffer = bufferFromString(removeHexPrefix(privateKey), 'hex'); - + const ownerAddress = Address.fromAddressOrString(address); // Generate a random salt. const salt = randomBytes(DEFAULT_KEY_SIZE); @@ -91,7 +92,7 @@ export async function encryptKeystoreWallet( const keystore: KeystoreWallet = { id: uuidv4(), version: 3, - address: removeHexPrefix(address.toHexString()), + address: removeHexPrefix(ownerAddress.toHexString()), crypto: { cipher: 'aes-128-ctr', mac, diff --git a/packages/wallet/src/test-utils/defaultChainConfig.ts b/packages/wallet/src/test-utils/defaultChainConfig.ts deleted file mode 100644 index d4358fca08..0000000000 --- a/packages/wallet/src/test-utils/defaultChainConfig.ts +++ /dev/null @@ -1,515 +0,0 @@ -export const defaultChainConfig = { - chain_name: 'local_testnet', - block_gas_limit: 5000000000, - initial_state: { - coins: [ - { - owner: '0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x09c0b2d1a486c439a87bcba6b46a7a1a23f3897cc83a94521a96da5c23bc58db', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x5d99ee966b42cd8fc7bdd1364b389153a9e78b42b7d4a691470674e817888d4e', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbdaad6a89e073e177895b3e5a9ccd15806749eda134a6438dae32fc5b6601f3f', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x95a7aa6cc32743f8706c40ef49a7423b47da763bb4bbc055b1f07254dc729036', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xcee104acd38b940c8f1c62c6d7ea00a0ad2241d6dee0509a4bf27297508870d3', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x7e3626e306588eba79cafab73f0709e55ab8f4bdfe8c8b75034a430fc56ece89', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x1c31df52b6df56407dd95f83082e8beb9cfc9532ac111d5bd8491651d95ba775', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x09dd7a49174d6fcc9f4c6f7942c18060a935ddd03ee69b594189b8c3581276ea', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x86604282dc604481b809845be49667607c470644f6822fc01eb0d22f167e08cf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbca334a06d19db5041c78fe2f465b07be5bec828f38b7796b2877e7d1542c950', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xbd9a1dc8d3ec3521c43f6c2c01611b4d0204c7610204ff0178488c8738a30bd2', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0xb32197cf75efe05bf453c26178139f09b391582065549c1422bc92555ecffb64', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x3b24509ed4ab3c7959f5c9391c1445c59290cdb5f13d6f780922f376b7029f30', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x77c6f40b7da70d885f68efaad7c661327482a63ea10dcb4271de819438254ae1', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x6a2c4691c547c43924650dbd30620b184b5fe3fb6dbe5c4446110b08f6f405bf', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0000000000000000000000000000000000000000000000000000000000000000', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0101010101010101010101010101010101010101010101010101010101010101', - }, - { - owner: '0x49075a7538e2c88ebe1926ce4d898198a2a4e790d14512943a9864bc536b3c82', - amount: '0xFFFFFFFFFFFFFFFF', - asset_id: '0x0202020202020202020202020202020202020202020202020202020202020202', - }, - ], - messages: [ - { - sender: '0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f', - recipient: '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba', - nonce: '0101010101010101010101010101010101010101010101010101010101010101', - amount: '0x000000000000FFFF', - data: '', - da_height: '0x00', - }, - { - sender: '0x69a2b736b60159b43bb8a4f98c0589f6da5fa3a3d101e8e269c499eb942753ba', - recipient: '0xc43454aa38dd91f88109a4b7aef5efb96ce34e3f24992fe0f81d233ca686f80f', - nonce: '0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b0e1ef2963832068b', - amount: '0xb04f3c08f59b309e', - data: '', - da_height: '0x00', - }, - ], - }, - consensus_parameters: { - tx_params: { - max_inputs: 255, - max_outputs: 255, - max_witnesses: 255, - max_gas_per_tx: 10000000, - max_size: 17825792, - }, - predicate_params: { - max_predicate_length: 1048576, - max_predicate_data_length: 1048576, - max_gas_per_predicate: 10000000, - max_message_data_length: 1048576, - }, - script_params: { - max_script_length: 1048576, - max_script_data_length: 1048576, - }, - contract_params: { - contract_max_size: 16777216, - max_storage_slots: 255, - }, - fee_params: { - gas_price_factor: 92, - gas_per_byte: 4, - }, - }, - gas_costs: { - add: 1, - addi: 1, - aloc: 1, - and: 1, - andi: 1, - bal: 13, - bhei: 1, - bhsh: 1, - burn: 132, - cb: 1, - cfei: 1, - cfsi: 1, - croo: 16, - div: 1, - divi: 1, - ecr1: 3000, - eck1: 951, - ed19: 3000, - eq: 1, - exp: 1, - expi: 1, - flag: 1, - gm: 1, - gt: 1, - gtf: 1, - ji: 1, - jmp: 1, - jne: 1, - jnei: 1, - jnzi: 1, - jmpf: 1, - jmpb: 1, - jnzf: 1, - jnzb: 1, - jnef: 1, - jneb: 1, - lb: 1, - log: 9, - lt: 1, - lw: 1, - mint: 135, - mlog: 1, - modOp: 1, - modi: 1, - moveOp: 1, - movi: 1, - mroo: 2, - mul: 1, - muli: 1, - mldv: 1, - noop: 1, - not: 1, - or: 1, - ori: 1, - poph: 2, - popl: 2, - pshh: 2, - pshl: 2, - ret: 13, - rvrt: 13, - sb: 1, - sll: 1, - slli: 1, - srl: 1, - srli: 1, - srw: 12, - sub: 1, - subi: 1, - sw: 1, - sww: 67, - time: 1, - tr: 105, - tro: 60, - wdcm: 1, - wqcm: 1, - wdop: 1, - wqop: 1, - wdml: 1, - wqml: 1, - wddv: 1, - wqdv: 2, - wdmd: 3, - wqmd: 4, - wdam: 2, - wqam: 3, - wdmm: 3, - wqmm: 3, - xor: 1, - xori: 1, - call: { - LightOperation: { - base: 144, - units_per_gas: 214, - }, - }, - ccp: { - LightOperation: { - base: 15, - units_per_gas: 103, - }, - }, - csiz: { - LightOperation: { - base: 17, - units_per_gas: 790, - }, - }, - k256: { - LightOperation: { - base: 11, - units_per_gas: 214, - }, - }, - ldc: { - LightOperation: { - base: 15, - units_per_gas: 272, - }, - }, - logd: { - LightOperation: { - base: 26, - units_per_gas: 64, - }, - }, - mcl: { - LightOperation: { - base: 1, - units_per_gas: 3333, - }, - }, - mcli: { - LightOperation: { - base: 1, - units_per_gas: 3333, - }, - }, - mcp: { - LightOperation: { - base: 1, - units_per_gas: 2000, - }, - }, - mcpi: { - LightOperation: { - base: 3, - units_per_gas: 2000, - }, - }, - meq: { - LightOperation: { - base: 1, - units_per_gas: 2500, - }, - }, - retd: { - LightOperation: { - base: 29, - units_per_gas: 62, - }, - }, - s256: { - LightOperation: { - base: 2, - units_per_gas: 214, - }, - }, - scwq: { - LightOperation: { - base: 13, - units_per_gas: 5, - }, - }, - smo: { - LightOperation: { - base: 209, - units_per_gas: 55, - }, - }, - srwq: { - LightOperation: { - base: 47, - units_per_gas: 5, - }, - }, - swwq: { - LightOperation: { - base: 44, - units_per_gas: 5, - }, - }, - contract_root: { - LightOperation: { - base: 75, - units_per_gas: 1, - }, - }, - state_root: { - LightOperation: { - base: 412, - units_per_gas: 1, - }, - }, - vm_initialization: { - HeavyOperation: { - base: 2000, - gas_per_unit: 0, - }, - }, - new_storage_per_byte: 1, - }, - consensus: { - PoA: { - signing_key: '0x94ffcc53b892684acefaebc8a3d4a595e528a8cf664eeb3ef36f1020b0809d0d', - }, - }, -}; diff --git a/packages/wallet/src/test-utils/launchNode.test.ts b/packages/wallet/src/test-utils/launchNode.test.ts index eceebb70b6..f49d091349 100644 --- a/packages/wallet/src/test-utils/launchNode.test.ts +++ b/packages/wallet/src/test-utils/launchNode.test.ts @@ -1,78 +1,195 @@ -import { Provider } from '@fuel-ts/providers'; -import path from 'path'; -import { cwd } from 'process'; +import { safeExec } from '@fuel-ts/errors/test-utils'; +import * as childProcessMod from 'child_process'; -import { WalletUnlocked } from '../wallets'; +import type { LaunchNodeOptions } from './launchNode'; +import { killNode, launchNode } from './launchNode'; -import { launchNodeAndGetWallets } from './launchNode'; +type ChildProcessWithoutNullStreams = childProcessMod.ChildProcessWithoutNullStreams; +vi.mock('child_process', async () => { + const mod = await vi.importActual('child_process'); + return { + __esModule: true, + ...mod, + }; +}); + +/** + * This should mimic the stderr.on('data') event, returning both + * success and error messages, as strings. These messages are like + * the ones from `fuel-core` startup log messages. We filter them + * to know fuel-core state. + */ +function mockSpawn(params: { shouldError: boolean } = { shouldError: false }) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const stderrOn = (eventName: string, fn: (data: any) => void) => { + if (eventName === 'data') { + if (params.shouldError) { + // The `IO error` message simulates a possible fuel-core error log message + fn('IO error'); + } else { + // The `Binding GraphQL provider to` message simulates a fuel-core + // successful startup log message, usually meaning that the node + // is up and waiting for connections + fn('Binding GraphQL provider to'); + } + } + }; + + const innerMocks = { + on: vi.fn(), + stderr: { + pipe: vi.fn(), + on: vi.fn(stderrOn), + removeAllListeners: vi.fn(), + }, + stdout: { + pipe: vi.fn(), + removeAllListeners: vi.fn(), + }, + } as unknown as ChildProcessWithoutNullStreams; + + const spawn = vi.spyOn(childProcessMod, 'spawn').mockReturnValue(innerMocks); + + return { spawn, innerMocks }; +} + +const defaultLaunchNodeConfig: Partial = { + ip: '0.0.0.0', + port: '4000', +}; + +/** + * @group node + */ describe('launchNode', () => { - test('launchNodeAndGetWallets - empty config', async () => { - const { stop, provider, wallets } = await launchNodeAndGetWallets(); - expect(provider).toBeInstanceOf(Provider); - expect(wallets.length).toBe(10); - wallets.forEach((wallet) => { - expect(wallet).toBeInstanceOf(WalletUnlocked); + test('should start `fuel-core` node using built-in binary', async () => { + mockSpawn(); + + const { cleanup, ip, port } = await launchNode({ + ...defaultLaunchNodeConfig, + useSystemFuelCore: false, }); - stop(); + + expect(ip).toBe('0.0.0.0'); + expect(port).toBe('4000'); + cleanup(); }); - test('launchNodeAndGetWallets - custom config', async () => { - // #region launchNode-custom-config - const chainConfigPath = path.join(cwd(), '.fuel-core/configs/chainConfig.json'); + test('should start `fuel-core` node using system binary', async () => { + mockSpawn(); - const { stop, provider } = await launchNodeAndGetWallets({ - launchNodeOptions: { - chainConfigPath, - args: ['--poa-instant', 'true'], - }, + const { cleanup, ip, port } = await launchNode({ + ...defaultLaunchNodeConfig, + useSystemFuelCore: true, }); - const { - consensusParameters: { gasPerByte }, - } = provider.getChain(); + expect(ip).toBe('0.0.0.0'); + expect(port).toBe('4000'); + + cleanup(); + }); + + test('should throw on error', async () => { + const { innerMocks } = mockSpawn({ shouldError: true }); - expect(gasPerByte.toNumber()).toEqual(4); + const { error: safeError, result } = await safeExec(async () => + launchNode(defaultLaunchNodeConfig) + ); - stop(); - // #endregion launchNode-custom-config + expect(safeError).toBeTruthy(); + expect(result).not.toBeTruthy(); + + expect(innerMocks.on).toHaveBeenCalledTimes(1); + expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); + expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(0); }); - test('launchNodeAndGetWallets - custom walletCount', async () => { - const { stop, wallets } = await launchNodeAndGetWallets({ - walletCount: 5, - }); - expect(wallets.length).toBe(5); - wallets.forEach((wallet) => { - expect(wallet).toBeInstanceOf(WalletUnlocked); + test('should pipe stdout', async () => { + vi.spyOn(process.stdout, 'write'); + + const { innerMocks } = mockSpawn(); + + const { cleanup } = await launchNode(defaultLaunchNodeConfig); + + expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); + expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(0); + + cleanup(); + }); + + test('should pipe stdout and stderr', async () => { + vi.spyOn(process.stderr, 'write'); + vi.spyOn(process.stdout, 'write'); + + const { innerMocks } = mockSpawn(); + + await launchNode({ + ...defaultLaunchNodeConfig, + debugEnabled: true, }); - stop(); + + expect(innerMocks.stderr.pipe).toHaveBeenCalledTimes(1); + expect(innerMocks.stdout.pipe).toHaveBeenCalledTimes(1); }); - describe('without a GENESIS_SECRET', () => { - let GENESIS_SECRET: string | undefined; + test('should kill process only if PID exists and node is alive', () => { + const killFn = vi.fn(); + const state = { isDead: true }; - beforeAll(() => { - GENESIS_SECRET = process.env.GENESIS_SECRET; - delete process.env.GENESIS_SECRET; + // should not kill + let child = { + pid: undefined, + stdout: { + removeAllListeners: () => {}, + }, + stderr: { + removeAllListeners: () => {}, + }, + } as ChildProcessWithoutNullStreams; + + killNode({ + child, + configPath: '', + killFn, + state, }); - afterAll(() => { - process.env.GENESIS_SECRET = GENESIS_SECRET; + expect(killFn).toHaveBeenCalledTimes(0); + expect(state.isDead).toEqual(true); + + // should not kill + child = { + pid: 1, + stdout: { + removeAllListeners: () => {}, + }, + stderr: { + removeAllListeners: () => {}, + }, + } as ChildProcessWithoutNullStreams; + + killNode({ + child, + configPath: '', + killFn, + state, }); - test('launchNodeAndGetWallets - empty config', async () => { - const { stop, provider, wallets } = await launchNodeAndGetWallets(); - expect(provider).toBeInstanceOf(Provider); - expect(wallets.length).toBe(10); - wallets.forEach((wallet) => { - expect(wallet).toBeInstanceOf(WalletUnlocked); - }); - - expect(process.env.GENESIS_SECRET).toBeDefined(); - expect(process.env.GENESIS_SECRET).not.toEqual(GENESIS_SECRET); - expect(process.env.GENESIS_SECRET).toHaveLength(66); - stop(); + expect(killFn).toHaveBeenCalledTimes(0); + expect(state.isDead).toEqual(true); + + // should kill + state.isDead = false; + + killNode({ + child, + configPath: '', + killFn, + state, }); + + expect(killFn).toHaveBeenCalledTimes(1); + expect(state.isDead).toEqual(true); }); }); diff --git a/packages/wallet/src/test-utils/launchNode.ts b/packages/wallet/src/test-utils/launchNode.ts index c0284ab08f..cfbd1f4684 100644 --- a/packages/wallet/src/test-utils/launchNode.ts +++ b/packages/wallet/src/test-utils/launchNode.ts @@ -2,12 +2,13 @@ import { BaseAssetId } from '@fuel-ts/address/configs'; import { toHex } from '@fuel-ts/math'; import { Provider } from '@fuel-ts/providers'; import { Signer } from '@fuel-ts/signer'; +import { defaultChainConfig, defaultConsensusKey } from '@fuel-ts/utils'; +import { findBinPath } from '@fuel-ts/utils/cli-utils'; import type { ChildProcessWithoutNullStreams } from 'child_process'; import { spawn } from 'child_process'; import { randomUUID } from 'crypto'; import { hexlify } from 'ethers'; -import fsSync from 'fs'; -import fs from 'fs/promises'; +import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs'; import os from 'os'; import path from 'path'; import { getPortPromise } from 'portfinder'; @@ -15,24 +16,42 @@ import treeKill from 'tree-kill'; import type { WalletUnlocked } from '../wallets'; -import { defaultChainConfig } from './defaultChainConfig'; import { generateTestWallet } from './generateTestWallet'; -const defaultFuelCoreArgs = ['--vm-backtrace', '--utxo-validation']; +const getFlagValueFromArgs = (args: string[], flag: string) => { + const flagIndex = args.indexOf(flag); + if (flagIndex === -1) { + return undefined; + } + return args[flagIndex + 1]; +}; -type LaunchNodeOptions = { - chainConfigPath?: string; - consensusKey?: string; +const extractRemainingArgs = (args: string[], flagsToRemove: string[]) => { + const newArgs = [...args]; + flagsToRemove.forEach((flag) => { + const flagIndex = newArgs.indexOf(flag); + if (flagIndex !== -1) { + newArgs.splice(flagIndex, 2); + } + }); + return newArgs; +}; + +export type LaunchNodeOptions = { ip?: string; port?: string; args?: string[]; useSystemFuelCore?: boolean; + loggingEnabled?: boolean; + debugEnabled?: boolean; + basePath?: string; }; export type LaunchNodeResult = Promise<{ cleanup: () => void; ip: string; port: string; + chainConfigPath: string; }>; export type KillNodeParams = { @@ -57,8 +76,8 @@ export const killNode = (params: KillNodeParams) => { child.stderr.removeAllListeners(); // Remove the temporary folder and all its contents. - if (fsSync.existsSync(configPath)) { - fsSync.rmSync(configPath, { recursive: true }); + if (existsSync(configPath)) { + rmSync(configPath, { recursive: true }); } } }; @@ -66,28 +85,49 @@ export const killNode = (params: KillNodeParams) => { // #region launchNode-launchNodeOptions /** * Launches a fuel-core node. - * @param chainConfigPath - path to the chain configuration file. - * @param consensusKey - the consensus key to use. * @param ip - the ip to bind to. (optional, defaults to 0.0.0.0) * @param port - the port to bind to. (optional, defaults to 4000 or the next available port) * @param args - additional arguments to pass to fuel-core. * @param useSystemFuelCore - whether to use the system fuel-core binary or the one provided by the \@fuel-ts/fuel-core package. + * @param loggingEnabled - whether the node should output logs. (optional, defaults to true) + * @param debugEnabled - whether the node should log debug messages. (optional, defaults to false) + * @param basePath - the base path to use for the temporary folder. (optional, defaults to os.tmpdir()) * */ // #endregion launchNode-launchNodeOptions export const launchNode = async ({ - chainConfigPath, - consensusKey = '0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298', ip, port, - args = defaultFuelCoreArgs, + args = [], useSystemFuelCore = false, + loggingEnabled = true, + debugEnabled = false, + basePath, }: LaunchNodeOptions): LaunchNodeResult => // eslint-disable-next-line no-async-promise-executor new Promise(async (resolve, reject) => { + // filter out the flags chain, consensus-key, db-type, and poa-instant. we don't want to pass them twice to fuel-core. see line 214. + const remainingArgs = extractRemainingArgs(args, [ + '--chain', + '--consensus-key', + '--db-type', + '--poa-instant', + ]); + + const chainConfigPath = getFlagValueFromArgs(args, '--chain'); + const consensusKey = getFlagValueFromArgs(args, '--consensus-key') || defaultConsensusKey; + + const dbTypeFlagValue = getFlagValueFromArgs(args, '--db-type'); + const useInMemoryDb = dbTypeFlagValue === 'in-memory' || dbTypeFlagValue === undefined; + + const poaInstantFlagValue = getFlagValueFromArgs(args, '--poa-instant'); + const poaInstant = poaInstantFlagValue === 'true' || poaInstantFlagValue === undefined; + // This string is logged by the client when the node has successfully started. We use it to know when to resolve. const graphQLStartSubstring = 'Binding GraphQL provider to'; - const command = useSystemFuelCore ? 'fuel-core' : './node_modules/.bin/fuels-core'; + const binPath = findBinPath('fuels-core', __dirname); + + const command = useSystemFuelCore ? 'fuel-core' : binPath; const ipToUse = ip || '0.0.0.0'; @@ -100,15 +140,19 @@ export const launchNode = async ({ }) ).toString(); - let chainConfigPathToUse = chainConfigPath; + let chainConfigPathToUse: string; - const tempDirPath = path.join(os.tmpdir(), '.fuels-ts', randomUUID()); + const prefix = basePath || os.tmpdir(); + const suffix = basePath ? '' : randomUUID(); + const tempDirPath = path.join(prefix, '.fuels', suffix); - if (!chainConfigPath) { - if (!fsSync.existsSync(tempDirPath)) { - fsSync.mkdirSync(tempDirPath, { recursive: true }); + if (chainConfigPath) { + chainConfigPathToUse = chainConfigPath; + } else { + if (!existsSync(tempDirPath)) { + mkdirSync(tempDirPath, { recursive: true }); } - const tempChainConfigFilePath = path.join(tempDirPath, '.chainConfig.json'); + const tempChainConfigFilePath = path.join(tempDirPath, 'chainConfig.json'); let chainConfig = defaultChainConfig; @@ -135,25 +179,39 @@ export const launchNode = async ({ } // Write a temporary chain configuration file. - await fs.writeFile(tempChainConfigFilePath, JSON.stringify(chainConfig), 'utf8'); + writeFileSync(tempChainConfigFilePath, JSON.stringify(chainConfig), 'utf8'); chainConfigPathToUse = tempChainConfigFilePath; } - const child = spawn(command, [ - 'run', - '--ip', - ipToUse, - '--port', - portToUse, - '--db-type', - 'in-memory', - '--consensus-key', - consensusKey, - '--chain', - chainConfigPathToUse as string, - ...args, - ]); + const child = spawn( + command, + [ + 'run', + ['--ip', ipToUse], + ['--port', portToUse], + useInMemoryDb ? ['--db-type', 'in-memory'] : ['--db-path', tempDirPath], + ['--min-gas-price', '0'], + poaInstant ? ['--poa-instant', 'true'] : [], + ['--consensus-key', consensusKey], + ['--chain', chainConfigPathToUse as string], + '--vm-backtrace', + '--utxo-validation', + '--debug', + ...remainingArgs, + ].flat(), + { + stdio: 'pipe', + } + ); + + if (loggingEnabled) { + child.stderr.pipe(process.stderr); + } + + if (debugEnabled) { + child.stdout.pipe(process.stdout); + } const cleanupConfig: KillNodeParams = { child, @@ -164,8 +222,6 @@ export const launchNode = async ({ }, }; - child.stderr.setEncoding('utf8'); - // Look for a specific graphql start point in the output. child.stderr.on('data', (chunk: string) => { // Look for the graphql service start. @@ -175,6 +231,7 @@ export const launchNode = async ({ cleanup: () => killNode(cleanupConfig), ip: ipToUse, port: portToUse, + chainConfigPath: chainConfigPathToUse as string, }); } if (/error/i.test(chunk)) { @@ -183,17 +240,18 @@ export const launchNode = async ({ }); // Process exit. - process.on('exit', killNode); + process.on('exit', () => killNode(cleanupConfig)); // Catches ctrl+c event. - process.on('SIGINT', killNode); + process.on('SIGINT', () => killNode(cleanupConfig)); // Catches "kill pid" (for example: nodemon restart). - process.on('SIGUSR1', killNode); - process.on('SIGUSR2', killNode); + process.on('SIGUSR1', () => killNode(cleanupConfig)); + process.on('SIGUSR2', () => killNode(cleanupConfig)); // Catches uncaught exceptions. - process.on('uncaughtException', killNode); + process.on('beforeExit', () => killNode(cleanupConfig)); + process.on('uncaughtException', () => killNode(cleanupConfig)); child.on('error', reject); }); @@ -225,16 +283,7 @@ export const launchNodeAndGetWallets = async ({ launchNodeOptions?: Partial; walletCount?: number; } = {}): LaunchNodeAndGetWalletsResult => { - const defaultNodeOptions: LaunchNodeOptions = { - chainConfigPath: launchNodeOptions?.chainConfigPath, - consensusKey: launchNodeOptions?.consensusKey, - }; - - const { - cleanup: closeNode, - ip, - port, - } = await launchNode({ ...defaultNodeOptions, ...launchNodeOptions }); + const { cleanup: closeNode, ip, port } = await launchNode(launchNodeOptions || {}); const provider = await Provider.create(`http://${ip}:${port}/graphql`); const wallets = await generateWallets(walletCount, provider); diff --git a/packages/wallet/src/test-utils/launchNodeAndGetWallets.test.ts b/packages/wallet/src/test-utils/launchNodeAndGetWallets.test.ts new file mode 100644 index 0000000000..d90d0275ba --- /dev/null +++ b/packages/wallet/src/test-utils/launchNodeAndGetWallets.test.ts @@ -0,0 +1,95 @@ +import { Provider } from '@fuel-ts/providers'; +import path from 'path'; +import { cwd } from 'process'; + +import { WalletUnlocked } from '../wallets'; + +import { launchNodeAndGetWallets } from './launchNode'; + +/** + * @group node + */ +describe('launchNode', () => { + test('launchNodeAndGetWallets - empty config', async () => { + const { stop, provider, wallets } = await launchNodeAndGetWallets({ + launchNodeOptions: { + loggingEnabled: false, + }, + }); + expect(provider).toBeInstanceOf(Provider); + expect(wallets.length).toBe(10); + wallets.forEach((wallet) => { + expect(wallet).toBeInstanceOf(WalletUnlocked); + }); + stop(); + }); + + test('launchNodeAndGetWallets - custom config', async () => { + // #region launchNode-custom-config + const chainConfigPath = path.join(cwd(), '.fuel-core/configs/chainConfig.json'); + + const { stop, provider } = await launchNodeAndGetWallets({ + launchNodeOptions: { + args: ['--chain', chainConfigPath], + loggingEnabled: false, + }, + }); + + const { + consensusParameters: { gasPerByte }, + } = provider.getChain(); + + expect(gasPerByte.toNumber()).toEqual(4); + + stop(); + // #endregion launchNode-custom-config + }); + + test('launchNodeAndGetWallets - custom walletCount', async () => { + const { stop, wallets } = await launchNodeAndGetWallets({ + walletCount: 5, + launchNodeOptions: { + loggingEnabled: false, + }, + }); + expect(wallets.length).toBe(5); + wallets.forEach((wallet) => { + expect(wallet).toBeInstanceOf(WalletUnlocked); + }); + stop(); + }); + + describe('without a GENESIS_SECRET', () => { + let GENESIS_SECRET: string | undefined; + + beforeAll(() => { + GENESIS_SECRET = process.env.GENESIS_SECRET; + delete process.env.GENESIS_SECRET; + }); + + afterAll(() => { + process.env.GENESIS_SECRET = GENESIS_SECRET; + }); + + test('launchNodeAndGetWallets - empty config', async () => { + const { stop, provider, wallets } = await launchNodeAndGetWallets({ + launchNodeOptions: { + loggingEnabled: false, + }, + }); + + expect(provider).toBeInstanceOf(Provider); + expect(wallets.length).toBe(10); + + wallets.forEach((wallet) => { + expect(wallet).toBeInstanceOf(WalletUnlocked); + }); + + expect(process.env.GENESIS_SECRET).toBeDefined(); + expect(process.env.GENESIS_SECRET).not.toEqual(GENESIS_SECRET); + expect(process.env.GENESIS_SECRET).toHaveLength(66); + + stop(); + }); + }); +}); diff --git a/packages/wallet/src/test-utils/seedTestWallet.ts b/packages/wallet/src/test-utils/seedTestWallet.ts index e2cb1d9bdd..4ea14beb95 100644 --- a/packages/wallet/src/test-utils/seedTestWallet.ts +++ b/packages/wallet/src/test-utils/seedTestWallet.ts @@ -27,7 +27,5 @@ export const seedTestWallet = async (wallet: Account, quantities: CoinQuantityLi quantities .map(coinQuantityfy) .forEach(({ amount, assetId }) => request.addCoinOutput(wallet.address, amount, assetId)); - const response = await genesisWallet.sendTransaction(request); - - await response.wait(); + await genesisWallet.sendTransaction(request, { awaitExecution: true }); }; diff --git a/packages/wallet/src/transfer.test.ts b/packages/wallet/src/transfer.test.ts index 9c62e9d0fe..27b652910a 100644 --- a/packages/wallet/src/transfer.test.ts +++ b/packages/wallet/src/transfer.test.ts @@ -9,6 +9,9 @@ import { Wallet } from '.'; import { FUEL_NETWORK_URL } from './configs'; import { generateTestWallet, seedTestWallet } from './test-utils'; +/** + * @group node + */ describe('Wallet', () => { let provider: Provider; let gasPrice: BN; @@ -39,7 +42,7 @@ describe('Wallet', () => { const sender = await generateTestWallet(provider, [[500_000, BaseAssetId]]); const receiver = await generateTestWallet(provider); - const request = await sender.createTransfer(receiver.address, 1, BaseAssetId, { + const request = await sender.createTransfer(receiver.address.toB256(), 1, BaseAssetId, { gasPrice, gasLimit: 10_000, }); @@ -175,7 +178,7 @@ describe('Wallet', () => { const AMOUNT = 10; const recipient = Address.fromB256(RECIPIENT_ID); - const tx = await sender.withdrawToBaseLayer(recipient, AMOUNT, { + const tx = await sender.withdrawToBaseLayer(recipient.toB256(), AMOUNT, { gasPrice, gasLimit: 10_000, }); diff --git a/packages/wallet/src/types/GenerateOptions.ts b/packages/wallet/src/types/GenerateOptions.ts index 8a6ac35583..ef23a3dc50 100644 --- a/packages/wallet/src/types/GenerateOptions.ts +++ b/packages/wallet/src/types/GenerateOptions.ts @@ -4,5 +4,5 @@ import type { BytesLike } from 'ethers'; export interface GenerateOptions { /** Additional entropy for the random bytes */ entropy?: BytesLike; - provider: Provider; + provider?: Provider; } diff --git a/packages/wallet/src/utils.test.ts b/packages/wallet/src/utils.test.ts index 1e93a43bc2..6dc90931c7 100644 --- a/packages/wallet/src/utils.test.ts +++ b/packages/wallet/src/utils.test.ts @@ -9,8 +9,29 @@ import { formatScriptDataForTransferringToContract, } from './utils'; +vi.mock('@fuels/vm-asm', async () => { + const mod = await vi.importActual('@fuels/vm-asm'); + return { + __esModule: true, + ...mod, + }; +}); + +vi.mock('ethers', async () => { + const mod = await vi.importActual('ethers'); + return { + __esModule: true, + ...mod, + }; +}); + +/** + * @group node + */ describe('util', () => { - afterEach(jest.restoreAllMocks); + afterEach(() => { + vi.restoreAllMocks(); + }); it('should ensure "composeScriptForTransferringToContract" returns script just fine', async () => { const script = await composeScriptForTransferringToContract(); @@ -24,9 +45,9 @@ describe('util', () => { it('should ensure "formatScriptDataForTransferringToContract" returns script data just fine', () => { const byte: number[] = [0, 0, 0, 0, 0, 0, 0, 1]; - const encode = jest.spyOn(U64Coder.prototype, 'encode').mockReturnValue(Uint8Array.from(byte)); + const encode = vi.spyOn(U64Coder.prototype, 'encode').mockReturnValue(Uint8Array.from(byte)); - const arrayify = jest + const arrayify = vi .spyOn(getBytesCopyMod, 'getBytesCopy') .mockReturnValue(Uint8Array.from(byte)); diff --git a/packages/wallet/src/wallet-unlocked.test.ts b/packages/wallet/src/wallet-unlocked.test.ts index aaccc84753..e02f3f0a00 100644 --- a/packages/wallet/src/wallet-unlocked.test.ts +++ b/packages/wallet/src/wallet-unlocked.test.ts @@ -14,13 +14,19 @@ import * as keystoreWMod from './keystore-wallet'; import walletSpec from './wallet-spec'; import { WalletLocked, WalletUnlocked } from './wallets'; -jest.mock('@fuel-ts/providers', () => ({ - __esModule: true, - ...jest.requireActual('@fuel-ts/providers'), -})); +vi.mock('@fuel-ts/providers', async () => { + const mod = await vi.importActual('@fuel-ts/providers'); + return { + __esModule: true, + ...mod, + }; +}); const { ScriptTransactionRequest } = providersMod; +/** + * @group node + */ describe('WalletUnlocked', () => { const expectedPrivateKey = '0x5f70feeff1f229e4a95e1056e8b4d80d0b24b565674860cc213bdb07127ce1b1'; const expectedPublicKey = @@ -97,7 +103,7 @@ describe('WalletUnlocked', () => { const wallet = new WalletUnlocked(PRIVATE_KEY, provider); let signature: BytesLike | undefined; // Intercept Provider.sendTransaction to collect signature - const spy = jest + const spy = vi .spyOn(wallet.provider, 'sendTransaction') .mockImplementation(async (transaction: TransactionRequestLike) => { signature = transaction.witnesses?.[0]; @@ -144,48 +150,75 @@ describe('WalletUnlocked', () => { expect(wallet.address).toEqual(recoveredAddress); }); - it('Create wallet from seed', async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - const wallet = WalletUnlocked.fromSeed(walletSpec.seed, provider, walletSpec.account_1.path); + describe('WalletUnlocked.fromSeed', () => { + it('Create wallet from seed', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = WalletUnlocked.fromSeed(walletSpec.seed, provider, walletSpec.account_1.path); - expect(wallet.publicKey).toBe(walletSpec.account_1.publicKey); - expect(wallet.provider.url).toBe(walletSpec.providerUrl); - }); + expect(wallet.publicKey).toBe(walletSpec.account_1.publicKey); + expect(wallet.provider.url).toBe(walletSpec.providerUrl); + }); - it('Create wallet from mnemonic', async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - const wallet = WalletUnlocked.fromMnemonic( - walletSpec.mnemonic, - provider, - walletSpec.account_1.path, - undefined - ); + it('Create wallet from seed with default path', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = WalletUnlocked.fromSeed(walletSpec.seed, provider); - expect(wallet.publicKey).toBe(walletSpec.account_1.publicKey); - expect(wallet.provider.url).toBe(walletSpec.providerUrl); - }); + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(wallet.provider.url).toBe(walletSpec.providerUrl); + }); - it('Create wallet from mnemonic with default path', async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - const wallet = WalletUnlocked.fromMnemonic(walletSpec.mnemonic, provider); + it('Create wallet from seed with default path, without a provider', () => { + const wallet = WalletUnlocked.fromSeed(walletSpec.seed); - expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(() => wallet.provider).toThrowError('Provider not set'); + }); }); - it('Create wallet from extendedKey', async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - const wallet = WalletUnlocked.fromExtendedKey(walletSpec.account_0.xprv, provider); + describe('WalletUnlocked.fromMnemonic', () => { + it('Create wallet from mnemonic', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = WalletUnlocked.fromMnemonic( + walletSpec.mnemonic, + provider, + walletSpec.account_1.path, + undefined + ); + + expect(wallet.publicKey).toBe(walletSpec.account_1.publicKey); + expect(wallet.provider.url).toBe(walletSpec.providerUrl); + }); + + it('Create wallet from mnemonic with default path', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = WalletUnlocked.fromMnemonic(walletSpec.mnemonic, provider); + + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + }); + + it('Create wallet from mnemonic with default path, without a provider', () => { + const wallet = WalletUnlocked.fromMnemonic(walletSpec.mnemonic); - expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); - expect(wallet.provider.url).toBe(walletSpec.providerUrl); + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(() => wallet.provider).toThrowError('Provider not set'); + }); }); - it('Create wallet from seed with default path', async () => { - const provider = await Provider.create(FUEL_NETWORK_URL); - const wallet = WalletUnlocked.fromSeed(walletSpec.seed, provider); + describe('WalletUnlocked.extendedKey', () => { + it('Create wallet from extendedKey', async () => { + const provider = await Provider.create(FUEL_NETWORK_URL); + const wallet = WalletUnlocked.fromExtendedKey(walletSpec.account_0.xprv, provider); + + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(wallet.provider.url).toBe(walletSpec.providerUrl); + }); - expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); - expect(wallet.provider.url).toBe(walletSpec.providerUrl); + it('Create wallet from extendedKey, without provider', () => { + const wallet = WalletUnlocked.fromExtendedKey(walletSpec.account_0.xprv); + + expect(wallet.publicKey).toBe(walletSpec.account_0.publicKey); + expect(() => wallet.provider).toThrowError('Provider not set'); + }); }); it('Create wallet and lock it', async () => { @@ -205,19 +238,19 @@ describe('WalletUnlocked', () => { const transactionReq = new ScriptTransactionRequest(); const callResult = 'callResult' as unknown as CallResult; - const transactionRequestify = jest + const transactionRequestify = vi .spyOn(providersMod, 'transactionRequestify') .mockImplementation(() => transactionReq); - const estimateTxDependencies = jest + const estimateTxDependencies = vi .spyOn(providersMod.Provider.prototype, 'estimateTxDependencies') .mockImplementation(() => Promise.resolve()); - const call = jest + const call = vi .spyOn(providersMod.Provider.prototype, 'call') .mockImplementation(() => Promise.resolve(callResult)); - const populateTransactionWitnessesSignatureSpy = jest + const populateTransactionWitnessesSignatureSpy = vi .spyOn(BaseWalletUnlocked.prototype, 'populateTransactionWitnessesSignature') .mockImplementationOnce(() => Promise.resolve(transactionReq)); @@ -250,7 +283,7 @@ describe('WalletUnlocked', () => { }); const password = 'password'; - const encryptKeystoreWalletSpy = jest.spyOn(keystoreWMod, 'encryptKeystoreWallet'); + const encryptKeystoreWalletSpy = vi.spyOn(keystoreWMod, 'encryptKeystoreWallet'); const keystore = wallet.encrypt(password); diff --git a/packages/wallet/src/wallet.test.ts b/packages/wallet/src/wallet.test.ts index 324b0e15aa..af9617c272 100644 --- a/packages/wallet/src/wallet.test.ts +++ b/packages/wallet/src/wallet.test.ts @@ -8,72 +8,168 @@ import { transactionRequestify, Provider } from '@fuel-ts/providers'; import { FUEL_NETWORK_URL } from './configs'; import { generateTestWallet } from './test-utils/generateTestWallet'; import { Wallet } from './wallet'; -import { WalletUnlocked } from './wallets'; +import { WalletLocked, WalletUnlocked } from './wallets'; +/** + * @group node + */ describe('Wallet', () => { let wallet: WalletUnlocked; let provider: Provider; let gasPrice: BN; beforeAll(async () => { provider = await Provider.create(FUEL_NETWORK_URL); - wallet = Wallet.generate({ - provider, - }); + wallet = Wallet.generate({ provider }); gasPrice = provider.getGasConfig().minGasPrice; }); - it('Instantiate a new wallet', () => { - const lockedWallet = Wallet.fromAddress(wallet.address, provider); - expect(lockedWallet.address).toEqual(wallet.address); + describe('WalletLocked.constructor', () => { + it('should instatiate from a constructor', () => { + const lockedWallet = new WalletLocked(wallet.address, provider); + + expect(lockedWallet.address).toEqual(wallet.address); + }); + + it('should instatiate from a constructor, without a provider', () => { + const lockedWallet = new WalletLocked(wallet.address); + + expect(lockedWallet.address).toStrictEqual(wallet.address); + expect(lockedWallet).toBeInstanceOf(WalletLocked); + }); + }); + + describe('WalletLocked.fromAddress', () => { + it('should instantiate from an address', () => { + const lockedWallet = Wallet.fromAddress(wallet.address, provider); + + expect(lockedWallet.address).toStrictEqual(wallet.address); + expect(lockedWallet).toBeInstanceOf(WalletLocked); + }); + + it('should instantiate from an address, without a provider', () => { + const lockedWallet = Wallet.fromAddress(wallet.address); + + expect(lockedWallet.address).toStrictEqual(wallet.address); + expect(lockedWallet).toBeInstanceOf(WalletLocked); + }); }); - it('Create a locked wallet', () => { - const lockedWallet = Wallet.fromAddress(wallet.address, provider); - expect(lockedWallet.address).toEqual(wallet.address); + describe('WalletLocked.unlock', () => { + it('should be able to unlock a locked wallet', () => { + const lockedWallet = Wallet.fromAddress(wallet.address, provider); + expect(lockedWallet).toBeInstanceOf(WalletLocked); + + const unlockedWallet = lockedWallet.unlock(wallet.privateKey); + + expect(unlockedWallet).toBeInstanceOf(WalletUnlocked); + expect(unlockedWallet.address).toStrictEqual(lockedWallet.address); + expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + }); }); - it('Unlock a locked wallet', () => { - const lockedWallet = Wallet.fromAddress(wallet.address, provider); - const unlockedWallet = lockedWallet.unlock(wallet.privateKey); - expect(unlockedWallet.address).toEqual(lockedWallet.address); - expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + describe('WalletUnlocked.constructor', () => { + it('Should instatiate from a constructor', () => { + const unlockedWallet = new WalletUnlocked(wallet.privateKey, provider); + + expect(unlockedWallet.address).toStrictEqual(wallet.address); + }); + + it('should instatiate from a constructor, without a provider', () => { + const unlockedWallet = new WalletUnlocked(wallet.privateKey); + + expect(unlockedWallet.address).toStrictEqual(wallet.address); + expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + expect(() => unlockedWallet.provider).toThrowError('Provider not set'); + expect(unlockedWallet).toBeInstanceOf(WalletUnlocked); + }); }); - it('Create from privateKey', () => { - const unlockedWallet = Wallet.fromPrivateKey(wallet.privateKey, provider); - expect(unlockedWallet.address).toStrictEqual(wallet.address); - expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + /** + * @see {@link WalletUnlocked.fromPrivateKey} + */ + describe('WalletUnlocked.fromPrivateKey', () => { + it('Should instantiate fromPrivateKey', () => { + const unlockedWallet = Wallet.fromPrivateKey(wallet.privateKey, provider); + + expect(unlockedWallet.address).toStrictEqual(wallet.address); + expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + }); + + it('Should instantiate fromPrivateKey, without a provider', () => { + const unlockedWallet = Wallet.fromPrivateKey(wallet.privateKey); + + expect(unlockedWallet.address).toStrictEqual(wallet.address); + expect(unlockedWallet.privateKey).toEqual(wallet.privateKey); + expect(() => unlockedWallet.provider).toThrowError('Provider not set'); + }); }); - it('encrypts and decrypts a JSON wallet', async () => { - wallet = WalletUnlocked.generate({ - provider, + /** + * @see {@link WalletUnlocked.generate} + */ + describe('WalletUnlocked.generate', () => { + it('Should instantiate from generate', () => { + const unlockedWallet = WalletUnlocked.generate({ provider }); + + expect(unlockedWallet.address).toBeDefined(); + expect(unlockedWallet.privateKey).toBeDefined(); }); - const password = 'password'; - const jsonWallet = await wallet.encrypt(password); - const decryptedWallet = await Wallet.fromEncryptedJson(jsonWallet, password, provider); + it('Should instantiate from generate, without a provider', () => { + const unlockedWallet = WalletUnlocked.generate(); - expect(decryptedWallet.address).toStrictEqual(wallet.address); - expect(decryptedWallet.privateKey).toEqual(wallet.privateKey); - expect(decryptedWallet.address.toB256()).toEqual(wallet.address.toB256()); + expect(unlockedWallet.address).toBeDefined(); + expect(unlockedWallet.privateKey).toBeDefined(); + expect(() => unlockedWallet.provider).toThrowError('Provider not set'); + }); }); - it('Should fail to decrypt JSON wallet for a given wrong password', async () => { - wallet = WalletUnlocked.generate({ - provider, + /** + * @see {@link WalletUnlocked.fromEncryptedJson} + */ + describe('WalletUnlocked.fromEncryptedJson', () => { + it('should encrypt and decrypt a JSON wallet', async () => { + wallet = WalletUnlocked.generate({ + provider, + }); + const password = 'password'; + const jsonWallet = await wallet.encrypt(password); + + const decryptedWallet = await Wallet.fromEncryptedJson(jsonWallet, password, provider); + + expect(decryptedWallet.address).toStrictEqual(wallet.address); + expect(decryptedWallet.privateKey).toEqual(wallet.privateKey); + expect(decryptedWallet.address.toB256()).toEqual(wallet.address.toB256()); }); - const password = 'password'; - const jsonWallet = await wallet.encrypt(password); - const { error, result } = await safeExec(() => - Wallet.fromEncryptedJson(jsonWallet, 'wrong-password', provider) - ); + it('should encrypt and decrypt a JSON wallet, without a provider', async () => { + wallet = WalletUnlocked.generate(); + const password = 'password'; + const jsonWallet = await wallet.encrypt(password); - expect(result).toBeUndefined(); - expect(error?.message).toBe( - 'Failed to decrypt the keystore wallet, the provided password is incorrect.' - ); + const decryptedWallet = await Wallet.fromEncryptedJson(jsonWallet, password); + + expect(decryptedWallet.address).toStrictEqual(wallet.address); + expect(decryptedWallet.privateKey).toEqual(wallet.privateKey); + expect(() => decryptedWallet.provider).toThrowError('Provider not set'); + }); + + it('Should fail to decrypt JSON wallet for a given wrong password', async () => { + wallet = WalletUnlocked.generate({ + provider, + }); + const password = 'password'; + const jsonWallet = await wallet.encrypt(password); + + const { error, result } = await safeExec(() => + Wallet.fromEncryptedJson(jsonWallet, 'wrong-password', provider) + ); + + expect(result).toBeUndefined(); + expect(error?.message).toBe( + 'Failed to decrypt the keystore wallet, the provided password is incorrect.' + ); + }); }); it('Provide a custom provider on a public wallet to the contract instance', async () => { @@ -102,7 +198,7 @@ describe('Wallet', () => { const transactionRequest = transactionRequestify(transactionRequestLike); // Simulate a external request of signature const signedTransaction = await externalWallet.signTransaction(transactionRequest); - transactionRequest.updateWitnessByOwner(externalWallet.address, signedTransaction); + transactionRequest.updateWitnessByOwner(externalWallet.address.toB256(), signedTransaction); return super.sendTransaction(transactionRequestLike); } } diff --git a/packages/wallet/src/wallet.ts b/packages/wallet/src/wallet.ts index 5d4df4422c..13cba2b6ed 100644 --- a/packages/wallet/src/wallet.ts +++ b/packages/wallet/src/wallet.ts @@ -12,10 +12,10 @@ export class Wallet { * Creates a locked wallet instance from an address and a provider. * * @param address - The address of the wallet. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). * @returns A locked wallet instance. */ - static fromAddress(address: string | AbstractAddress, provider: Provider): WalletLocked { + static fromAddress(address: string | AbstractAddress, provider?: Provider): WalletLocked { return new WalletLocked(address, provider); } @@ -23,10 +23,10 @@ export class Wallet { * Creates an unlocked wallet instance from a private key and a provider. * * @param privateKey - The private key of the wallet. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). * @returns An unlocked wallet instance. */ - static fromPrivateKey(privateKey: BytesLike, provider: Provider) { + static fromPrivateKey(privateKey: BytesLike, provider?: Provider) { return new WalletUnlocked(privateKey, provider); } @@ -42,8 +42,8 @@ export class Wallet { * Create a Wallet Unlocked from a seed. * * @param seed - The seed phrase. - * @param path - The derivation path (optional). * @param provider - A Provider instance (optional). + * @param path - The derivation path (optional). * @returns An unlocked wallet instance. */ static fromSeed = WalletUnlocked.fromSeed; @@ -52,9 +52,9 @@ export class Wallet { * Create a Wallet Unlocked from a mnemonic phrase. * * @param mnemonic - The mnemonic phrase. + * @param provider - A Provider instance (optional). * @param path - The derivation path (optional). * @param passphrase - The passphrase for the mnemonic (optional). - * @param provider - A Provider instance (optional). * @returns An unlocked wallet instance. */ static fromMnemonic = WalletUnlocked.fromMnemonic; @@ -67,5 +67,14 @@ export class Wallet { * @returns An unlocked wallet instance. */ static fromExtendedKey = WalletUnlocked.fromExtendedKey; + + /** + * Create a Wallet Unlocked from an encrypted JSON. + * + * @param jsonWallet - The encrypted JSON keystore. + * @param password - The password to decrypt the JSON. + * @param provider - A Provider instance (optional). + * @returns An unlocked wallet instance. + */ static fromEncryptedJson = WalletUnlocked.fromEncryptedJson; } diff --git a/packages/wallet/src/wallets.ts b/packages/wallet/src/wallets.ts index c3969a0799..6d2e6b68e7 100644 --- a/packages/wallet/src/wallets.ts +++ b/packages/wallet/src/wallets.ts @@ -26,7 +26,7 @@ export class WalletLocked extends Account { */ unlock(privateKey: BytesLike): WalletUnlocked { // eslint-disable-next-line @typescript-eslint/no-use-before-define - return new WalletUnlocked(privateKey, this.provider); + return new WalletUnlocked(privateKey, this._provider); } } @@ -41,7 +41,7 @@ export class WalletUnlocked extends BaseWalletUnlocked { */ lock(): WalletLocked { this.signer = () => new Signer('0x00'); - return new WalletLocked(this.address, this.provider); + return new WalletLocked(this.address, this._provider); } /** @@ -50,7 +50,7 @@ export class WalletUnlocked extends BaseWalletUnlocked { * @param generateOptions - Options to customize the generation process (optional). * @returns An instance of WalletUnlocked. */ - static generate(generateOptions: GenerateOptions): WalletUnlocked { + static generate(generateOptions?: GenerateOptions): WalletUnlocked { const privateKey = Signer.generatePrivateKey(generateOptions?.entropy); return new WalletUnlocked(privateKey, generateOptions?.provider); @@ -60,11 +60,11 @@ export class WalletUnlocked extends BaseWalletUnlocked { * Create a Wallet Unlocked from a seed. * * @param seed - The seed phrase. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). * @param path - The derivation path (optional). * @returns An instance of WalletUnlocked. */ - static fromSeed(seed: string, provider: Provider, path?: string): WalletUnlocked { + static fromSeed(seed: string, provider?: Provider, path?: string): WalletUnlocked { const hdWallet = HDWallet.fromSeed(seed); const childWallet = hdWallet.derivePath(path || WalletUnlocked.defaultPath); @@ -75,14 +75,14 @@ export class WalletUnlocked extends BaseWalletUnlocked { * Create a Wallet Unlocked from a mnemonic phrase. * * @param mnemonic - The mnemonic phrase. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). * @param path - The derivation path (optional). * @param passphrase - The passphrase for the mnemonic (optional). * @returns An instance of WalletUnlocked. */ static fromMnemonic( mnemonic: string, - provider: Provider, + provider?: Provider, path?: string, passphrase?: BytesLike ): WalletUnlocked { @@ -97,19 +97,27 @@ export class WalletUnlocked extends BaseWalletUnlocked { * Create a Wallet Unlocked from an extended key. * * @param extendedKey - The extended key. - * @param provider - A Provider instance. + * @param provider - A Provider instance (optional). * @returns An instance of WalletUnlocked. */ - static fromExtendedKey(extendedKey: string, provider: Provider): WalletUnlocked { + static fromExtendedKey(extendedKey: string, provider?: Provider): WalletUnlocked { const hdWallet = HDWallet.fromExtendedKey(extendedKey); return new WalletUnlocked(hdWallet.privateKey, provider); } + /** + * Create a Wallet Unlocked from an encrypted JSON. + * + * @param jsonWallet - The encrypted JSON keystore. + * @param password - The password to decrypt the JSON. + * @param provider - A Provider instance (optional). + * @returns An unlocked wallet instance. + */ static async fromEncryptedJson( jsonWallet: string, password: string, - provider: Provider + provider?: Provider ): Promise { const privateKey = await decryptKeystoreWallet(jsonWallet, password); diff --git a/packages/wordlists/README.md b/packages/wordlists/README.md index 34761cb299..3ffb7b78ad 100644 --- a/packages/wordlists/README.md +++ b/packages/wordlists/README.md @@ -18,7 +18,7 @@ This module contains a wordlist for BIP 39 mnemonic phrases, currently limited t -See [Fuels-ts Documentation](https://fuellabs.github.io/fuels-ts/) +See [Fuels-ts Documentation](https://docs.fuel.network/docs/fuels-ts/) ## Usage diff --git a/packages/wordlists/package.json b/packages/wordlists/package.json index ea57977184..05ee69d070 100644 --- a/packages/wordlists/package.json +++ b/packages/wordlists/package.json @@ -8,7 +8,7 @@ "module": "dist/index.mjs", "types": "dist/index.d.ts", "engines": { - "node": "^18.17.1" + "node": "^18.18.2 || ^20.0.0" }, "exports": { ".": { diff --git a/packages/wordlists/src/wordlists.test.ts b/packages/wordlists/src/wordlists.test.ts index ca98da1529..3d72a3e917 100644 --- a/packages/wordlists/src/wordlists.test.ts +++ b/packages/wordlists/src/wordlists.test.ts @@ -7,6 +7,9 @@ const checksum = (wordlists: string[]) => .update(Buffer.from(`${wordlists.join('\n')}\n`)) .digest('hex'); +/** + * @group node + */ describe('Checksum word lists', () => { test('Checksum english list', () => { expect(checksum(english)).toBe( diff --git a/packages/wordlists/tsdoc.json b/packages/wordlists/tsdoc.json new file mode 100644 index 0000000000..4514b07272 --- /dev/null +++ b/packages/wordlists/tsdoc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "extends": ["../../tsdoc.base.json"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 33d1932629..ccaf958ca6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,18 +23,18 @@ importers: '@fuel-ts/fuel-core': specifier: workspace:* version: link:packages/fuel-core + '@fuel-ts/utils': + specifier: workspace:* + version: link:packages/utils '@fuel-ts/versions': specifier: workspace:^ version: link:packages/versions '@internal/tsup': specifier: workspace:* version: link:internal/tsup - '@jest/types': - specifier: ^29.5.0 - version: 29.5.0 - '@types/jest': - specifier: ^29.5.0 - version: 29.5.0 + '@istanbuljs/nyc-config-typescript': + specifier: ^1.0.2 + version: 1.0.2(nyc@15.1.0) '@types/node': specifier: 18.15.3 version: 18.15.3 @@ -50,12 +50,21 @@ importers: '@typescript-eslint/parser': specifier: ^6.9.0 version: 6.9.1(eslint@8.52.0)(typescript@5.2.2) + '@vitest/browser': + specifier: ^1.1.3 + version: 1.1.3(vitest@1.1.3)(webdriverio@8.27.2) + '@vitest/coverage-istanbul': + specifier: ^1.1.3 + version: 1.1.3(vitest@1.1.3) compare-versions: specifier: ^6.1.0 version: 6.1.0 conventional-changelog-angular: specifier: ^5.0.13 version: 5.0.13 + coverage-diff: + specifier: ^3.2.0 + version: 3.2.0 dotenv: specifier: ^9.0.2 version: 9.0.2 @@ -95,24 +104,21 @@ importers: eslint-plugin-tsdoc: specifier: ^0.2.17 version: 0.2.17 - ethers: - specifier: ^6.7.1 - version: 6.7.1 glob: specifier: ^10.2.6 version: 10.2.6 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@18.15.3) - jest-text-transformer: - specifier: ^1.0.4 - version: 1.0.4 + memfs: + specifier: ^4.6.0 + version: 4.6.0(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.0) nodemon: specifier: ^2.0.22 version: 2.0.22 npm-run-all: specifier: ^4.1.5 version: 4.1.5 + nyc: + specifier: ^15.1.0 + version: 15.1.0 open: specifier: ^8.4.0 version: 8.4.0 @@ -131,21 +137,33 @@ importers: ts-generator: specifier: ^0.1.1 version: 0.1.1 - ts-jest: - specifier: ^29.1.1 - version: 29.1.1(@babel/core@7.23.3)(@jest/types@29.5.0)(esbuild@0.17.19)(jest@29.7.0)(typescript@5.2.2) tsup: specifier: ^6.7.0 version: 6.7.0(typescript@5.2.2) tsx: - specifier: ^3.12.7 - version: 3.12.7 + specifier: ^4.7.0 + version: 4.7.0 turbo: specifier: ^1.8.8 version: 1.8.8 typescript: specifier: ~5.2.2 version: 5.2.2 + vite: + specifier: ^5.0.11 + version: 5.0.11(@types/node@18.15.3) + vite-plugin-node-polyfills: + specifier: ^0.17.0 + version: 0.17.0(vite@5.0.11) + vite-plugin-plain-text: + specifier: ^1.4.2 + version: 1.4.2 + vitest: + specifier: ^1.1.3 + version: 1.1.3(@types/node@18.15.3)(@vitest/browser@1.1.3) + webdriverio: + specifier: ^8.27.0 + version: 8.27.2(typescript@5.2.2) apps/demo-fuels: dependencies: @@ -450,6 +468,8 @@ importers: specifier: workspace:* version: link:../../packages/fuels + internal/check-tests: {} + internal/tsup: {} packages/abi-coder: @@ -764,9 +784,6 @@ importers: lodash.camelcase: specifier: ^4.3.0 version: 4.3.0 - npm-which: - specifier: ^3.0.1 - version: 3.0.1 portfinder: specifier: ^1.0.32 version: 1.0.32 @@ -791,7 +808,7 @@ importers: version: 3.0.2 vite: specifier: ^4.3.9 - version: 4.3.9(@types/node@18.15.3) + version: 4.3.9 packages/hasher: dependencies: @@ -999,7 +1016,7 @@ importers: specifier: ^16.6.0 version: 16.6.0 graphql-request: - specifier: ^5.0.0 + specifier: 5.0.0 version: 5.0.0(graphql@16.6.0) graphql-tag: specifier: ^2.12.6 @@ -1020,9 +1037,9 @@ importers: '@graphql-codegen/typescript': specifier: ^2.8.0 version: 2.8.0(graphql@16.6.0) - '@graphql-codegen/typescript-graphql-request': - specifier: ^4.5.7 - version: 4.5.7(graphql-request@5.0.0)(graphql-tag@2.12.6)(graphql@16.6.0) + '@graphql-codegen/typescript-generic-sdk': + specifier: ^3.1.0 + version: 3.1.0(graphql-tag@2.12.6)(graphql@16.6.0) '@graphql-codegen/typescript-operations': specifier: ^2.5.5 version: 2.5.5(graphql@16.6.0) @@ -1090,16 +1107,12 @@ importers: '@fuel-ts/math': specifier: workspace:* version: link:../math - elliptic: - specifier: ^6.5.4 - version: 6.5.4 + '@noble/curves': + specifier: ^1.3.0 + version: 1.3.0 ethers: specifier: ^6.7.1 version: 6.7.1 - devDependencies: - '@types/elliptic': - specifier: ^6.4.14 - version: 6.4.14 packages/transactions: dependencies: @@ -1124,9 +1137,9 @@ importers: packages/utils: dependencies: - ethers: - specifier: ^6.7.1 - version: 6.7.1 + '@fuel-ts/interfaces': + specifier: workspace:* + version: link:../interfaces ramda: specifier: ^0.29.0 version: 0.29.0 @@ -1146,16 +1159,10 @@ importers: cli-table: specifier: ^0.3.11 version: 0.3.11 - semver: - specifier: ^7.3.8 - version: 7.3.8 devDependencies: '@types/cli-table': specifier: ^0.3.1 version: 0.3.1 - '@types/semver': - specifier: ^7.3.13 - version: 7.3.13 packages/wallet: dependencies: @@ -1318,6 +1325,7 @@ packages: /@adraffy/ens-normalize@1.9.2: resolution: {integrity: sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==} + dev: false /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.20.0)(algoliasearch@4.18.0)(search-insights@2.11.0): resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} @@ -1906,7 +1914,7 @@ packages: '@babel/helper-function-name': 7.22.5 '@babel/template': 7.22.5 '@babel/traverse': 7.22.5 - '@babel/types': 7.22.5 + '@babel/types': 7.23.4 transitivePeerDependencies: - supports-color dev: false @@ -2114,6 +2122,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.3): + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} @@ -2122,6 +2140,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.22.5): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} @@ -2131,6 +2159,15 @@ packages: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.3): + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.22.5): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} @@ -2225,6 +2262,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.3): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} @@ -2233,6 +2280,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==} @@ -2260,6 +2317,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.3): + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} @@ -2268,6 +2335,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.22.5): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} @@ -2276,6 +2353,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.3): + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} @@ -2285,6 +2372,15 @@ packages: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: @@ -2292,6 +2388,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.22.5): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} @@ -2300,6 +2406,16 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.3): + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.22.5): resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} @@ -2319,6 +2435,17 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.3): + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.22.5): resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} @@ -2328,6 +2455,17 @@ packages: dependencies: '@babel/core': 7.22.5 '@babel/helper-plugin-utils': 7.22.5 + dev: false + + /@babel/plugin-syntax-typescript@7.22.5(@babel/core@7.23.3): + resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.3 + '@babel/helper-plugin-utils': 7.22.5 + dev: false /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.22.5): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} @@ -3236,6 +3374,7 @@ packages: /@bcoe/v8-coverage@0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: false /@changesets/apply-release-plan@6.1.4: resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} @@ -3668,26 +3807,14 @@ packages: jsdoc-type-pratt-parser: 4.0.0 dev: true - /@esbuild-kit/cjs-loader@2.4.2: - resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==} - dependencies: - '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.2 - dev: true - - /@esbuild-kit/core-utils@3.1.0: - resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} - dependencies: - esbuild: 0.17.19 - source-map-support: 0.5.21 - dev: true - - /@esbuild-kit/esm-loader@2.5.5: - resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} - dependencies: - '@esbuild-kit/core-utils': 3.1.0 - get-tsconfig: 4.6.2 + /@esbuild/aix-ppc64@0.19.11: + resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true dev: true + optional: true /@esbuild/android-arm64@0.17.19: resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} @@ -3697,6 +3824,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm64@0.19.11: + resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.19.3: resolution: {integrity: sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==} engines: {node: '>=12'} @@ -3714,6 +3850,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm@0.19.11: + resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.19.3: resolution: {integrity: sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==} engines: {node: '>=12'} @@ -3731,6 +3876,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-x64@0.19.11: + resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.19.3: resolution: {integrity: sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==} engines: {node: '>=12'} @@ -3748,6 +3902,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-arm64@0.19.11: + resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.19.3: resolution: {integrity: sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==} engines: {node: '>=12'} @@ -3765,6 +3928,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-x64@0.19.11: + resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.19.3: resolution: {integrity: sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==} engines: {node: '>=12'} @@ -3782,6 +3954,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-arm64@0.19.11: + resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.19.3: resolution: {integrity: sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==} engines: {node: '>=12'} @@ -3799,6 +3980,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-x64@0.19.11: + resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.19.3: resolution: {integrity: sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==} engines: {node: '>=12'} @@ -3816,6 +4006,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm64@0.19.11: + resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.19.3: resolution: {integrity: sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==} engines: {node: '>=12'} @@ -3833,6 +4032,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm@0.19.11: + resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.19.3: resolution: {integrity: sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==} engines: {node: '>=12'} @@ -3850,6 +4058,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ia32@0.19.11: + resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.19.3: resolution: {integrity: sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==} engines: {node: '>=12'} @@ -3867,6 +4084,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-loong64@0.19.11: + resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.19.3: resolution: {integrity: sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==} engines: {node: '>=12'} @@ -3884,6 +4110,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-mips64el@0.19.11: + resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.19.3: resolution: {integrity: sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==} engines: {node: '>=12'} @@ -3901,6 +4136,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ppc64@0.19.11: + resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.19.3: resolution: {integrity: sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==} engines: {node: '>=12'} @@ -3918,21 +4162,39 @@ packages: requiresBuild: true optional: true - /@esbuild/linux-riscv64@0.19.3: - resolution: {integrity: sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==} + /@esbuild/linux-riscv64@0.19.11: + resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true - /@esbuild/linux-s390x@0.17.19: - resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} + /@esbuild/linux-riscv64@0.19.3: + resolution: {integrity: sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-s390x@0.17.19: + resolution: {integrity: sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-s390x@0.19.11: + resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} engines: {node: '>=12'} cpu: [s390x] os: [linux] requiresBuild: true + dev: true optional: true /@esbuild/linux-s390x@0.19.3: @@ -3952,6 +4214,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-x64@0.19.11: + resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.19.3: resolution: {integrity: sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==} engines: {node: '>=12'} @@ -3969,6 +4240,15 @@ packages: requiresBuild: true optional: true + /@esbuild/netbsd-x64@0.19.11: + resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.19.3: resolution: {integrity: sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==} engines: {node: '>=12'} @@ -3986,6 +4266,15 @@ packages: requiresBuild: true optional: true + /@esbuild/openbsd-x64@0.19.11: + resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.19.3: resolution: {integrity: sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==} engines: {node: '>=12'} @@ -4003,6 +4292,15 @@ packages: requiresBuild: true optional: true + /@esbuild/sunos-x64@0.19.11: + resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.19.3: resolution: {integrity: sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==} engines: {node: '>=12'} @@ -4020,6 +4318,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-arm64@0.19.11: + resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.19.3: resolution: {integrity: sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==} engines: {node: '>=12'} @@ -4037,6 +4344,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-ia32@0.19.11: + resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.19.3: resolution: {integrity: sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==} engines: {node: '>=12'} @@ -4054,6 +4370,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-x64@0.19.11: + resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.19.3: resolution: {integrity: sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==} engines: {node: '>=12'} @@ -4415,18 +4740,16 @@ packages: tslib: 2.4.1 dev: true - /@graphql-codegen/typescript-graphql-request@4.5.7(graphql-request@5.0.0)(graphql-tag@2.12.6)(graphql@16.6.0): - resolution: {integrity: sha512-1YPaCO+0q5z0Um6Om+5LMWdB8+WQxda8eXRXwy0dqSGRy9X5HTZz/pxqaTgy76yMtPBxq1UNa7lruBTzszHhJg==} + /@graphql-codegen/typescript-generic-sdk@3.1.0(graphql-tag@2.12.6)(graphql@16.6.0): + resolution: {integrity: sha512-nQZi/YGRI1+qCZZsh0V5nz6+hCHSN4OU9tKyOTDsEPyDFnGEukDuRdCH2IZasGn22a3Iu5TUDkgp5w9wEQwGmg==} peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - graphql-request: ^3.4.0 || ^4.0.0 || ^5.0.0 graphql-tag: ^2.0.0 dependencies: - '@graphql-codegen/plugin-helpers': 2.7.2(graphql@16.6.0) - '@graphql-codegen/visitor-plugin-common': 2.13.0(graphql@16.6.0) + '@graphql-codegen/plugin-helpers': 3.1.2(graphql@16.6.0) + '@graphql-codegen/visitor-plugin-common': 2.13.1(graphql@16.6.0) auto-bind: 4.0.0 graphql: 16.6.0 - graphql-request: 5.0.0(graphql@16.6.0) graphql-tag: 2.12.6(graphql@16.6.0) tslib: 2.4.1 transitivePeerDependencies: @@ -4487,6 +4810,27 @@ packages: - supports-color dev: true + /@graphql-codegen/visitor-plugin-common@2.13.1(graphql@16.6.0): + resolution: {integrity: sha512-mD9ufZhDGhyrSaWQGrU1Q1c5f01TeWtSWy/cDwXYjJcHIj1Y/DG2x0tOflEfCvh5WcnmHNIw4lzDsg1W7iFJEg==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + dependencies: + '@graphql-codegen/plugin-helpers': 2.7.2(graphql@16.6.0) + '@graphql-tools/optimize': 1.4.0(graphql@16.6.0) + '@graphql-tools/relay-operation-optimizer': 6.5.18(graphql@16.6.0) + '@graphql-tools/utils': 8.13.1(graphql@16.6.0) + auto-bind: 4.0.0 + change-case-all: 1.0.14 + dependency-graph: 0.11.0 + graphql: 16.6.0 + graphql-tag: 2.12.6(graphql@16.6.0) + parse-filepath: 1.0.2 + tslib: 2.4.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /@graphql-tools/apollo-engine-loader@7.3.26(graphql@16.6.0): resolution: {integrity: sha512-h1vfhdJFjnCYn9b5EY1Z91JTF0KB3hHVJNQIsiUV2mpQXZdeOXQoaWeYEKaiI5R6kwBw5PP9B0fv3jfUIG8LyQ==} peerDependencies: @@ -4935,6 +5279,16 @@ packages: js-yaml: 3.14.1 resolve-from: 5.0.0 + /@istanbuljs/nyc-config-typescript@1.0.2(nyc@15.1.0): + resolution: {integrity: sha512-iKGIyMoyJuFnJRSVTZ78POIRvNnwZaWIf8vG4ZS3rQq58MMDrqEX2nnzx0R28V2X8JvmKYiqY9FP2hlJsm8A0w==} + engines: {node: '>=8'} + peerDependencies: + nyc: '>=15' + dependencies: + '@istanbuljs/schema': 0.1.3 + nyc: 15.1.0 + dev: true + /@istanbuljs/schema@0.1.3: resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} @@ -4944,7 +5298,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 jest-message-util: 27.5.1 jest-util: 27.5.1 @@ -4956,25 +5310,13 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 jest-message-util: 28.1.3 jest-util: 28.1.3 slash: 3.0.0 dev: false - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - dev: true - /@jest/core@27.5.1: resolution: {integrity: sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -4989,7 +5331,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.8.1 @@ -5020,91 +5362,22 @@ packages: - utf-8-validate dev: false - /@jest/core@29.7.0: - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.8.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@16.18.34) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - dev: true - /@jest/environment@27.5.1: resolution: {integrity: sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 jest-mock: 27.5.1 dev: false - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - jest-mock: 29.7.0 - dev: true - /@jest/expect-utils@29.5.0: resolution: {integrity: sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: jest-get-type: 29.4.3 - - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true - - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true + dev: false /@jest/fake-timers@27.5.1: resolution: {integrity: sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==} @@ -5112,24 +5385,12 @@ packages: dependencies: '@jest/types': 27.5.1 '@sinonjs/fake-timers': 8.1.0 - '@types/node': 16.18.34 + '@types/node': 20.10.5 jest-message-util: 27.5.1 jest-mock: 27.5.1 jest-util: 27.5.1 dev: false - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 16.18.34 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - /@jest/globals@27.5.1: resolution: {integrity: sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5139,18 +5400,6 @@ packages: expect: 27.5.1 dev: false - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - /@jest/reporters@27.5.1: resolution: {integrity: sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5165,17 +5414,17 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 istanbul-lib-instrument: 5.2.1 istanbul-lib-report: 3.0.0 istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 + istanbul-reports: 3.1.6 jest-haste-map: 27.5.1 jest-resolve: 27.5.1 jest-util: 27.5.1 @@ -5189,43 +5438,6 @@ packages: - supports-color dev: false - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.18 - '@types/node': 16.18.34 - chalk: 4.1.2 - collect-v8-coverage: 1.0.1 - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.0 - istanbul-lib-instrument: 6.0.1 - istanbul-lib-report: 3.0.0 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.5 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.1.0 - transitivePeerDependencies: - - supports-color - dev: true - /@jest/schemas@28.1.3: resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -5238,6 +5450,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@sinclair/typebox': 0.25.24 + dev: false /@jest/schemas@29.6.3: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} @@ -5255,15 +5468,6 @@ packages: source-map: 0.6.1 dev: false - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jridgewell/trace-mapping': 0.3.18 - callsites: 3.1.0 - graceful-fs: 4.2.11 - dev: true - /@jest/test-result@27.5.1: resolution: {integrity: sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5284,16 +5488,6 @@ packages: collect-v8-coverage: 1.0.1 dev: false - /@jest/test-result@29.7.0: - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - collect-v8-coverage: 1.0.1 - dev: true - /@jest/test-sequencer@27.5.1: resolution: {integrity: sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5306,16 +5500,6 @@ packages: - supports-color dev: false - /@jest/test-sequencer@29.7.0: - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - slash: 3.0.0 - dev: true - /@jest/transform@27.5.1: resolution: {integrity: sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5339,36 +5523,13 @@ packages: - supports-color dev: false - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.22.5 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.18 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.5 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true - /@jest/types@27.5.1: resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: false @@ -5380,7 +5541,7 @@ packages: '@jest/schemas': 28.1.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 '@types/yargs': 17.0.24 chalk: 4.1.2 dev: false @@ -5395,18 +5556,7 @@ packages: '@types/node': 16.18.34 '@types/yargs': 17.0.24 chalk: 4.1.2 - - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/istanbul-reports': 3.0.1 - '@types/node': 16.18.34 - '@types/yargs': 17.0.24 - chalk: 4.1.2 - dev: true + dev: false /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -5497,13 +5647,149 @@ packages: resolution: {integrity: sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==} dev: true - /@next/env@13.4.4: - resolution: {integrity: sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg==} - dev: false + /@napi-rs/magic-string-android-arm-eabi@0.3.4: + resolution: {integrity: sha512-sszAYxqtzzJ4FDerDNHcqL9NhqPhj8W4DNiOanXYy50mA5oojlRtaAFPiB5ZMrWDBM32v5Q30LrmxQ4eTtu2Dg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true - /@next/env@14.0.1: - resolution: {integrity: sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==} - dev: false + /@napi-rs/magic-string-android-arm64@0.3.4: + resolution: {integrity: sha512-jdQ6HuO0X5rkX4MauTcWR4HWdgjakTOmmzqXg8L26+jOHVVG1LZE+Su5qvV4bP8vMb2h+vPE+JsnwqSmWymu3Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-darwin-arm64@0.3.4: + resolution: {integrity: sha512-6NmMtvURce9/oq09XBZmuIeI6lPLGtEJ2ZPO/QzL3nLZa6wygiCnO/sFACKYNg5/73ET5HMMTeuogE1JI+r2Lw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-darwin-x64@0.3.4: + resolution: {integrity: sha512-f9LmfMiUAKDOtl0meOuLYeVb6OERrgGzrTg1Tn3R3fTAShM2kxRbfAuPE9ljuXxIFzOv/uqRNLSl/LqCJwpREA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-freebsd-x64@0.3.4: + resolution: {integrity: sha512-rqduQ4odiDK4QdM45xHWRTU4wtFIfpp8g8QGpz+3qqg7ivldDqbbNOrBaf6Oeu77uuEvWggnkyuChotfKgJdJQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-linux-arm-gnueabihf@0.3.4: + resolution: {integrity: sha512-pVaJEdEpiPqIfq3M4+yMAATS7Z9muDcWYn8H7GFH1ygh8GwgLgKfy/n/lG2M6zp18Mwd0x7E2E/qg9GgCyUzoQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-linux-arm64-gnu@0.3.4: + resolution: {integrity: sha512-9FwoAih/0tzEZx0BjYYIxWkSRMjonIn91RFM3q3MBs/evmThXUYXUqLNa1PPIkK1JoksswtDi48qWWLt8nGflQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-linux-arm64-musl@0.3.4: + resolution: {integrity: sha512-wCR7R+WPOcAKmVQc1s6h6HwfwW1vL9pM8BjUY9Ljkdb8wt1LmZEmV2Sgfc1SfbRQzbyl+pKeufP6adRRQVzYDA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-linux-x64-gnu@0.3.4: + resolution: {integrity: sha512-sbxFDpYnt5WFbxQ1xozwOvh5A7IftqSI0WnE9O7KsQIOi0ej2dvFbfOW4tmFkvH/YP8KJELo5AhP2+kEq1DpYA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-linux-x64-musl@0.3.4: + resolution: {integrity: sha512-jN4h/7e2Ul8v3UK5IZu38NXLMdzVWhY4uEDlnwuUAhwRh26wBQ1/pLD97Uy/Z3dFNBQPcsv60XS9fOM1YDNT6w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-win32-arm64-msvc@0.3.4: + resolution: {integrity: sha512-gMUyTRHLWpzX2ntJFCbW2Gnla9Y/WUmbkZuW5SBAo/Jo8QojHn76Y4PNgnoXdzcsV9b/45RBxurYKAfFg9WTyg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-win32-ia32-msvc@0.3.4: + resolution: {integrity: sha512-QIMauMOvEHgL00K9np/c9CT/CRtLOz3mRTQqcZ9XGzSoAMrpxH71KSpDJrKl7h7Ro6TZ+hJ0C3T+JVuTCZNv4A==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string-win32-x64-msvc@0.3.4: + resolution: {integrity: sha512-V8FMSf828MzOI3P6/765MR7zHU6CUZqiyPhmAnwYoKFNxfv7oCviN/G6NcENeCdcYOvNgh5fYzaNLB96ndId5A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@napi-rs/magic-string@0.3.4: + resolution: {integrity: sha512-DEWl/B99RQsyMT3F9bvrXuhL01/eIQp/dtNSE3G1jQ4mTGRcP4iHWxoPZ577WrbjUinrNgvRA5+08g8fkPgimQ==} + engines: {node: '>= 10'} + optionalDependencies: + '@napi-rs/magic-string-android-arm-eabi': 0.3.4 + '@napi-rs/magic-string-android-arm64': 0.3.4 + '@napi-rs/magic-string-darwin-arm64': 0.3.4 + '@napi-rs/magic-string-darwin-x64': 0.3.4 + '@napi-rs/magic-string-freebsd-x64': 0.3.4 + '@napi-rs/magic-string-linux-arm-gnueabihf': 0.3.4 + '@napi-rs/magic-string-linux-arm64-gnu': 0.3.4 + '@napi-rs/magic-string-linux-arm64-musl': 0.3.4 + '@napi-rs/magic-string-linux-x64-gnu': 0.3.4 + '@napi-rs/magic-string-linux-x64-musl': 0.3.4 + '@napi-rs/magic-string-win32-arm64-msvc': 0.3.4 + '@napi-rs/magic-string-win32-ia32-msvc': 0.3.4 + '@napi-rs/magic-string-win32-x64-msvc': 0.3.4 + dev: true + + /@next/env@13.4.4: + resolution: {integrity: sha512-q/y7VZj/9YpgzDe64Zi6rY1xPizx80JjlU2BTevlajtaE3w1LqweH1gGgxou2N7hdFosXHjGrI4OUvtFXXhGLg==} + dev: false + + /@next/env@14.0.1: + resolution: {integrity: sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A==} + dev: false /@next/eslint-plugin-next@14.0.1: resolution: {integrity: sha512-bLjJMwXdzvhnQOnxvHoTTUh/+PYk6FF/DCgHi4BXwXCINer+o1ZYfL9aVeezj/oI7wqGJOqwGIXrlBvPbAId3w==} @@ -5685,16 +5971,29 @@ packages: '@noble/hashes': 1.3.1 dev: false + /@noble/curves@1.3.0: + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + dependencies: + '@noble/hashes': 1.3.3 + dev: false + /@noble/hashes@1.1.2: resolution: {integrity: sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==} + dev: false /@noble/hashes@1.3.1: resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==} engines: {node: '>= 16'} dev: false + /@noble/hashes@1.3.3: + resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} + engines: {node: '>= 16'} + dev: false + /@noble/secp256k1@1.7.1: resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + dev: false /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -5798,6 +6097,48 @@ packages: webpack-dev-server: 4.15.1(webpack@5.88.0) dev: false + /@polka/url@1.0.0-next.24: + resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} + dev: true + + /@puppeteer/browsers@1.4.6(typescript@5.2.2): + resolution: {integrity: sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==} + engines: {node: '>=16.3.0'} + hasBin: true + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.0 + tar-fs: 3.0.4 + typescript: 5.2.2 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@puppeteer/browsers@1.9.1: + resolution: {integrity: sha512-PuvK6xZzGhKPvlx3fpfdM2kYY3P/hB1URtK8wA7XUJ6prn6pp22zvJHu48th0SGcHL9SutbPHrFuQgfXTFobWA==} + engines: {node: '>=16.3.0'} + hasBin: true + dependencies: + debug: 4.3.4 + extract-zip: 2.0.1 + progress: 2.0.3 + proxy-agent: 6.3.1 + tar-fs: 3.0.4 + unbzip2-stream: 1.4.3 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + /@radix-ui/colors@2.1.0: resolution: {integrity: sha512-gcBnxjS2u2c6thQz/9K1+Pt2ZYcm5WKU4SLi0emYkRmYbVUw+37rlc5wgLtYOsSsRP9nxVtbJJYj6WVO7UUmZg==} dev: false @@ -7841,6 +8182,20 @@ packages: rollup: 2.79.1 dev: false + /@rollup/plugin-inject@5.0.5: + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0 + estree-walker: 2.0.2 + magic-string: 0.30.5 + dev: true + /@rollup/plugin-node-resolve@11.2.1(rollup@2.79.1): resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==} engines: {node: '>= 10.0.0'} @@ -7878,6 +8233,124 @@ packages: rollup: 2.79.1 dev: false + /@rollup/pluginutils@5.1.0: + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.1 + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: true + + /@rollup/rollup-android-arm-eabi@4.9.4: + resolution: {integrity: sha512-ub/SN3yWqIv5CWiAZPHVS1DloyZsJbtXmX4HxUTIpS0BHm9pW5iYBo2mIZi+hE3AeiTzHz33blwSnhdUo+9NpA==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.9.4: + resolution: {integrity: sha512-ehcBrOR5XTl0W0t2WxfTyHCR/3Cq2jfb+I4W+Ch8Y9b5G+vbAecVv0Fx/J1QKktOrgUYsIKxWAKgIpvw56IFNA==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.9.4: + resolution: {integrity: sha512-1fzh1lWExwSTWy8vJPnNbNM02WZDS8AW3McEOb7wW+nPChLKf3WG2aG7fhaUmfX5FKw9zhsF5+MBwArGyNM7NA==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.9.4: + resolution: {integrity: sha512-Gc6cukkF38RcYQ6uPdiXi70JB0f29CwcQ7+r4QpfNpQFVHXRd0DfWFidoGxjSx1DwOETM97JPz1RXL5ISSB0pA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.9.4: + resolution: {integrity: sha512-g21RTeFzoTl8GxosHbnQZ0/JkuFIB13C3T7Y0HtKzOXmoHhewLbVTFBQZu+z5m9STH6FZ7L/oPgU4Nm5ErN2fw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.9.4: + resolution: {integrity: sha512-TVYVWD/SYwWzGGnbfTkrNpdE4HON46orgMNHCivlXmlsSGQOx/OHHYiQcMIOx38/GWgwr/po2LBn7wypkWw/Mg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.9.4: + resolution: {integrity: sha512-XcKvuendwizYYhFxpvQ3xVpzje2HHImzg33wL9zvxtj77HvPStbSGI9czrdbfrf8DGMcNNReH9pVZv8qejAQ5A==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.9.4: + resolution: {integrity: sha512-LFHS/8Q+I9YA0yVETyjonMJ3UA+DczeBd/MqNEzsGSTdNvSJa1OJZcSH8GiXLvcizgp9AlHs2walqRcqzjOi3A==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.9.4: + resolution: {integrity: sha512-dIYgo+j1+yfy81i0YVU5KnQrIJZE8ERomx17ReU4GREjGtDW4X+nvkBak2xAUpyqLs4eleDSj3RrV72fQos7zw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.9.4: + resolution: {integrity: sha512-RoaYxjdHQ5TPjaPrLsfKqR3pakMr3JGqZ+jZM0zP2IkDtsGa4CqYaWSfQmZVgFUCgLrTnzX+cnHS3nfl+kB6ZQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.9.4: + resolution: {integrity: sha512-T8Q3XHV+Jjf5e49B4EAaLKV74BbX7/qYBRQ8Wop/+TyyU0k+vSjiLVSHNWdVd1goMjZcbhDmYZUYW5RFqkBNHQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.9.4: + resolution: {integrity: sha512-z+JQ7JirDUHAsMecVydnBPWLwJjbppU+7LZjffGf+Jvrxq+dVjIE7By163Sc9DKc3ADSU50qPVw0KonBS+a+HQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.9.4: + resolution: {integrity: sha512-LfdGXCV9rdEify1oxlN9eamvDSjv9md9ZVMAbNHA87xqIfFCxImxan9qZ8+Un54iK2nnqPlbnSi4R54ONtbWBw==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@rushstack/eslint-patch@1.3.2: resolution: {integrity: sha512-V+MvGwaHH03hYhY+k6Ef/xKd6RYlc4q8WBx+2ANmipHJcKuktNcI/NgEsJgdSUF6Lw32njT6OnrRsKYCdgHjYw==} dev: false @@ -7911,29 +8384,23 @@ packages: /@sinclair/typebox@0.25.24: resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + dev: false /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true + /@sindresorhus/is@5.6.0: + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + dev: true + /@sinonjs/commons@1.8.6: resolution: {integrity: sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==} dependencies: type-detect: 4.0.8 dev: false - /@sinonjs/commons@3.0.0: - resolution: {integrity: sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==} - dependencies: - type-detect: 4.0.8 - dev: true - - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - dependencies: - '@sinonjs/commons': 3.0.0 - dev: true - /@sinonjs/fake-timers@8.1.0: resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} dependencies: @@ -8083,6 +8550,13 @@ packages: tslib: 2.6.0 dev: false + /@szmarczak/http-timer@5.0.1: + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + dependencies: + defer-to-connect: 2.0.1 + dev: true + /@tabler/icons@2.44.0: resolution: {integrity: sha512-WPPtihDcAwEm1QZM9MXQw6+r/R2/qx7KMU1eegsi9DsqBLAb0W2kbt6e/syvd6j9c+6XNpRVBW1ziGqSWQAWOg==} dev: false @@ -8326,6 +8800,10 @@ packages: engines: {node: '>= 6'} dev: false + /@tootallnate/quickjs-emscripten@0.23.0: + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -8363,39 +8841,44 @@ packages: '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.20.1 + dev: false /@types/babel__generator@7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: '@babel/types': 7.22.5 + dev: false /@types/babel__template@7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: '@babel/parser': 7.22.5 '@babel/types': 7.22.5 + dev: false /@types/babel__traverse@7.20.1: resolution: {integrity: sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==} dependencies: '@babel/types': 7.22.5 + dev: false /@types/bn.js@5.1.1: resolution: {integrity: sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==} dependencies: '@types/node': 16.18.34 + dev: false /@types/body-parser@1.19.2: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/bonjour@3.5.10: resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/cli-table@0.3.1: @@ -8406,21 +8889,15 @@ packages: resolution: {integrity: sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig==} dependencies: '@types/express-serve-static-core': 4.17.35 - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false - /@types/elliptic@6.4.14: - resolution: {integrity: sha512-z4OBcDAU0GVwDTuwJzQCiL6188QvZMkvoERgcVjq0/mPM8jCfdwZ3x5zQEVoL9WCAru3aG5wl3Z5Ww5wBWn7ZQ==} - dependencies: - '@types/bn.js': 5.1.1 - dev: true - /@types/eslint-scope@3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: @@ -8441,12 +8918,15 @@ packages: /@types/estree@1.0.1: resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} - dev: false + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: true /@types/express-serve-static-core@4.17.35: resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 '@types/send': 0.17.1 @@ -8475,12 +8955,17 @@ packages: /@types/graceful-fs@4.1.6: resolution: {integrity: sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 + dev: false /@types/html-minifier-terser@6.1.0: resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} dev: false + /@types/http-cache-semantics@4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + dev: true + /@types/http-errors@2.0.1: resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==} dev: false @@ -8488,7 +8973,7 @@ packages: /@types/http-proxy@1.17.11: resolution: {integrity: sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/is-ci@3.0.0: @@ -8499,16 +8984,19 @@ packages: /@types/istanbul-lib-coverage@2.0.4: resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + dev: false /@types/istanbul-lib-report@3.0.0: resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} dependencies: '@types/istanbul-lib-coverage': 2.0.4 + dev: false /@types/istanbul-reports@3.0.1: resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} dependencies: '@types/istanbul-lib-report': 3.0.0 + dev: false /@types/jest@27.5.2: resolution: {integrity: sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA==} @@ -8522,6 +9010,7 @@ packages: dependencies: expect: 29.5.0 pretty-format: 29.5.0 + dev: false /@types/js-yaml@4.0.5: resolution: {integrity: sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==} @@ -8619,6 +9108,7 @@ packages: /@types/node@18.15.13: resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} + dev: false /@types/node@18.15.3: resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==} @@ -8627,7 +9117,6 @@ packages: resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==} dependencies: undici-types: 5.26.5 - dev: true /@types/normalize-package-data@2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -8688,7 +9177,7 @@ packages: /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/retry@0.12.0: @@ -8720,7 +9209,7 @@ packages: resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} dependencies: '@types/mime': 1.3.2 - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/serve-index@1.9.1: @@ -8734,17 +9223,18 @@ packages: dependencies: '@types/http-errors': 2.0.1 '@types/mime': 3.0.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/sockjs@0.3.33: resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false /@types/stack-utils@2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + dev: false /@types/testing-library__jest-dom@5.14.6: resolution: {integrity: sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==} @@ -8772,6 +9262,10 @@ packages: resolution: {integrity: sha512-dl7VRSYBhxhOVxHA/ec8e7EzGXSQJrrGvRgLQWxusaJk1oT4I9nLpWiqsxekYI2eAEuet05toEm+rByL0G8x2Q==} dev: true + /@types/which@2.0.2: + resolution: {integrity: sha512-113D3mDkZDjo+EeUEHCFy0qniNc1ZpecGiAU7WSo7YDoSzolZIQKpYFHrPpjkB2nuyahcKfrmLXeQlh7gqJYdw==} + dev: true + /@types/ws@8.5.5: resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} dependencies: @@ -8779,6 +9273,7 @@ packages: /@types/yargs-parser@21.0.0: resolution: {integrity: sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==} + dev: false /@types/yargs@16.0.5: resolution: {integrity: sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==} @@ -8790,6 +9285,15 @@ packages: resolution: {integrity: sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==} dependencies: '@types/yargs-parser': 21.0.0 + dev: false + + /@types/yauzl@2.10.3: + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + requiresBuild: true + dependencies: + '@types/node': 20.10.5 + dev: true + optional: true /@typescript-eslint/eslint-plugin@5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.38.0)(typescript@5.2.2): resolution: {integrity: sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==} @@ -9261,6 +9765,86 @@ packages: vue: 3.2.47 dev: true + /@vitest/browser@1.1.3(vitest@1.1.3)(webdriverio@8.27.2): + resolution: {integrity: sha512-ksI0V8YqonFYfjVYMPTvDR84i7ix7QPL2Sc8G2mHirVGAf4jJS3uC/CsifRLe5/E2r8QUhHbAdZQpvMCqBJV5w==} + peerDependencies: + playwright: '*' + safaridriver: '*' + vitest: ^1.0.0 + webdriverio: '*' + peerDependenciesMeta: + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true + dependencies: + '@vitest/utils': 1.1.3 + magic-string: 0.30.5 + sirv: 2.0.4 + vitest: 1.1.3(@types/node@18.15.3)(@vitest/browser@1.1.3) + webdriverio: 8.27.2(typescript@5.2.2) + dev: true + + /@vitest/coverage-istanbul@1.1.3(vitest@1.1.3): + resolution: {integrity: sha512-pqx/RaLjJ7oxsbi0Vc/CjyXBXd86yQ0lKq1PPnk9BMNLqMTEWwfcTelcNrl41yK+IVRhHlFtwcjDva3VslbMMQ==} + peerDependencies: + vitest: ^1.0.0 + dependencies: + debug: 4.3.4 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.1 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.6 + magicast: 0.3.2 + picocolors: 1.0.0 + test-exclude: 6.0.0 + vitest: 1.1.3(@types/node@18.15.3)(@vitest/browser@1.1.3) + transitivePeerDependencies: + - supports-color + dev: true + + /@vitest/expect@1.1.3: + resolution: {integrity: sha512-MnJqsKc1Ko04lksF9XoRJza0bGGwTtqfbyrsYv5on4rcEkdo+QgUdITenBQBUltKzdxW7K3rWh+nXRULwsdaVg==} + dependencies: + '@vitest/spy': 1.1.3 + '@vitest/utils': 1.1.3 + chai: 4.4.0 + dev: true + + /@vitest/runner@1.1.3: + resolution: {integrity: sha512-Va2XbWMnhSdDEh/OFxyUltgQuuDRxnarK1hW5QNN4URpQrqq6jtt8cfww/pQQ4i0LjoYxh/3bYWvDFlR9tU73g==} + dependencies: + '@vitest/utils': 1.1.3 + p-limit: 5.0.0 + pathe: 1.1.2 + dev: true + + /@vitest/snapshot@1.1.3: + resolution: {integrity: sha512-U0r8pRXsLAdxSVAyGNcqOU2H3Z4Y2dAAGGelL50O0QRMdi1WWeYHdrH/QWpN1e8juWfVKsb8B+pyJwTC+4Gy9w==} + dependencies: + magic-string: 0.30.5 + pathe: 1.1.2 + pretty-format: 29.7.0 + dev: true + + /@vitest/spy@1.1.3: + resolution: {integrity: sha512-Ec0qWyGS5LhATFQtldvChPTAHv08yHIOZfiNcjwRQbFPHpkih0md9KAbs7TfeIfL7OFKoe7B/6ukBTqByubXkQ==} + dependencies: + tinyspy: 2.2.0 + dev: true + + /@vitest/utils@1.1.3: + resolution: {integrity: sha512-Dyt3UMcdElTll2H75vhxfpZu03uFpXRCHxWnzcrFjZxT1kTbq8ALUYIeBgGolo1gldVdI0YSlQRacsqxTwNqwg==} + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + dev: true + /@vue/compiler-core@3.2.47: resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==} dependencies: @@ -9373,6 +9957,70 @@ packages: - vue dev: true + /@wdio/config@8.27.2: + resolution: {integrity: sha512-qR1r7K7/jsQhi9g5NiW40lgbvbzCcwwk8nz07hzTj6m8fQ8TXkQPob2fnrlDaNrXjzbZC4od0uv0a5fimK9YOQ==} + engines: {node: ^16.13 || >=18} + dependencies: + '@wdio/logger': 8.24.12 + '@wdio/types': 8.27.2 + '@wdio/utils': 8.27.2 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + glob: 10.2.6 + import-meta-resolve: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@wdio/logger@8.24.12: + resolution: {integrity: sha512-QisOiVIWKTUCf1H7S+DOtC+gruhlpimQrUXfWMTeeh672PvAJYnTpOJDWA+BtXfsikkUYFAzAaq8SeMJk8rqKg==} + engines: {node: ^16.13 || >=18} + dependencies: + chalk: 5.3.0 + loglevel: 1.8.1 + loglevel-plugin-prefix: 0.8.4 + strip-ansi: 7.1.0 + dev: true + + /@wdio/protocols@8.24.12: + resolution: {integrity: sha512-QnVj3FkapmVD3h2zoZk+ZQ8gevSj9D9MiIQIy8eOnY4FAneYZ9R9GvoW+mgNcCZO8S8++S/jZHetR8n+8Q808g==} + dev: true + + /@wdio/repl@8.24.12: + resolution: {integrity: sha512-321F3sWafnlw93uRTSjEBVuvWCxTkWNDs7ektQS15drrroL3TMeFOynu4rDrIz0jXD9Vas0HCD2Tq/P0uxFLdw==} + engines: {node: ^16.13 || >=18} + dependencies: + '@types/node': 20.10.5 + dev: true + + /@wdio/types@8.27.2: + resolution: {integrity: sha512-z/TtSQysEtAUNh+DooOs22G7xotTsJC2RcIZKaVtHY4Gl6lF+tn8kLRXD79jem2ta1byB1TpW62K366k1vzcLw==} + engines: {node: ^16.13 || >=18} + dependencies: + '@types/node': 20.10.5 + dev: true + + /@wdio/utils@8.27.2: + resolution: {integrity: sha512-jWxUhGjlZ4L3uOsP96oLKWjkITpoH/KPTtKzU7xdoVGhd1LXK4d/Fr8cTFTNkDBXM7yuM7C+EMmQ8HJHR55KTA==} + engines: {node: ^16.13 || >=18} + dependencies: + '@puppeteer/browsers': 1.9.1 + '@wdio/logger': 8.24.12 + '@wdio/types': 8.27.2 + decamelize: 6.0.0 + deepmerge-ts: 5.1.0 + edgedriver: 5.3.9 + geckodriver: 4.3.0 + get-port: 7.0.0 + import-meta-resolve: 4.0.0 + locate-app: 2.2.7 + safaridriver: 0.1.2 + split2: 4.2.0 + wait-port: 1.1.0 + transitivePeerDependencies: + - supports-color + dev: true + /@webassemblyjs/ast@1.11.6: resolution: {integrity: sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==} dependencies: @@ -9602,12 +10250,22 @@ packages: engines: {node: '>=0.4.0'} dev: true + /acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + dev: true + /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true dev: false + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + /acorn@8.9.0: resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==} engines: {node: '>=0.4.0'} @@ -9628,6 +10286,7 @@ packages: /aes-js@4.0.0-beta.5: resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + dev: false /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -9776,6 +10435,42 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /append-transform@2.0.0: + resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} + engines: {node: '>=8'} + dependencies: + default-require-extensions: 3.0.1 + dev: true + + /archiver-utils@4.0.1: + resolution: {integrity: sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==} + engines: {node: '>= 12.0.0'} + dependencies: + glob: 8.1.0 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash: 4.17.21 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + dev: true + + /archiver@6.0.1: + resolution: {integrity: sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==} + engines: {node: '>= 12.0.0'} + dependencies: + archiver-utils: 4.0.1 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 3.1.6 + zip-stream: 5.0.1 + dev: true + + /archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: true + /are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -9956,6 +10651,15 @@ packages: /asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + /asn1.js@5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: true + /asn1js@3.0.5: resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} engines: {node: '>=12.0.0'} @@ -9965,9 +10669,30 @@ packages: tslib: 2.6.0 dev: true + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.5 + is-nan: 1.3.2 + object-is: 1.1.5 + object.assign: 4.1.4 + util: 0.12.5 + dev: true + + /assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /ast-types-flow@0.0.7: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} + /ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + dependencies: + tslib: 2.6.0 + dev: true + /astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -9981,7 +10706,6 @@ packages: /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} - dev: false /asynciterator.prototype@1.0.0: resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} @@ -10035,6 +10759,10 @@ packages: dequal: 2.0.3 dev: true + /b4a@1.6.4: + resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + dev: true + /babel-jest@27.5.1(@babel/core@7.22.5): resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -10054,23 +10782,24 @@ packages: - supports-color dev: false - /babel-jest@29.7.0(@babel/core@7.22.5): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /babel-jest@27.5.1(@babel/core@7.23.3): + resolution: {integrity: sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.22.5 - '@jest/transform': 29.7.0 + '@babel/core': 7.23.3 + '@jest/transform': 27.5.1 + '@jest/types': 27.5.1 '@types/babel__core': 7.20.1 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.22.5) + babel-preset-jest: 27.5.1(@babel/core@7.23.3) chalk: 4.1.2 graceful-fs: 4.2.11 slash: 3.0.0 transitivePeerDependencies: - supports-color - dev: true + dev: false /babel-loader@8.3.0(@babel/core@7.22.5)(webpack@5.88.0): resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} @@ -10098,6 +10827,7 @@ packages: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color + dev: false /babel-plugin-jest-hoist@27.5.1: resolution: {integrity: sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==} @@ -10109,16 +10839,6 @@ packages: '@types/babel__traverse': 7.20.1 dev: false - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/template': 7.22.5 - '@babel/types': 7.22.5 - '@types/babel__core': 7.20.1 - '@types/babel__traverse': 7.20.1 - dev: true - /babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} engines: {node: '>=10', npm: '>=6'} @@ -10198,6 +10918,27 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.22.5) '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.22.5) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.22.5) + dev: false + + /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.3): + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.3 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.3) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.3) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.3) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.3) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.3) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.3) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.3) + dev: false /babel-preset-fbjs@3.4.0(@babel/core@7.22.5): resolution: {integrity: sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==} @@ -10247,16 +10988,16 @@ packages: babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.5) dev: false - /babel-preset-jest@29.6.3(@babel/core@7.22.5): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /babel-preset-jest@27.5.1(@babel/core@7.23.3): + resolution: {integrity: sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.22.5 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.5) - dev: true + '@babel/core': 7.23.3 + babel-plugin-jest-hoist: 27.5.1 + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.3) + dev: false /babel-preset-react-app@10.0.1: resolution: {integrity: sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==} @@ -10293,6 +11034,11 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true + /basic-ftp@5.0.4: + resolution: {integrity: sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==} + engines: {node: '>=10.0.0'} + dev: true + /batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: false @@ -10331,6 +11077,13 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + /binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + dev: true + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: @@ -10339,17 +11092,20 @@ packages: readable-stream: 3.6.2 dev: true + /bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + dev: true + /bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} dev: false /bn.js@4.12.0: resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} - dev: false + dev: true /bn.js@5.2.1: resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - dev: false /body-parser@1.20.1: resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} @@ -10424,12 +11180,74 @@ packages: /brorand@1.1.0: resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - dev: false + dev: true /browser-process-hrtime@1.0.0: resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} dev: false + /browser-resolve@2.0.0: + resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} + dependencies: + resolve: 1.22.8 + dev: true + + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + dev: true + + /browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + + /browserify-rsa@4.1.0: + resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + dev: true + + /browserify-sign@4.2.2: + resolution: {integrity: sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==} + engines: {node: '>= 4'} + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.5.4 + inherits: 2.0.4 + parse-asn1: 5.1.6 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: true + + /browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + dependencies: + pako: 1.0.11 + dev: true + /browserslist@4.21.9: resolution: {integrity: sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -10450,20 +11268,27 @@ packages: node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} - dependencies: - fast-json-stable-stringify: 2.1.0 - dev: true - /bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} dependencies: node-int64: 0.4.0 + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + + /buffer-indexof-polyfill@1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + dev: true + + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + dev: true /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -10472,10 +11297,26 @@ packages: ieee754: 1.2.1 dev: true + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + dev: true + /builtin-modules@3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} + /builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + dev: true + /bundle-name@3.0.0: resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} engines: {node: '>=12'} @@ -10524,11 +11365,39 @@ packages: engines: {node: '>=8'} dev: true - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.2.1 + /cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + dev: true + + /cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.0 + responselike: 3.0.0 + dev: true + + /caching-transform@4.0.0: + resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} + engines: {node: '>=8'} + dependencies: + hasha: 5.2.2 + make-dir: 3.1.0 + package-hash: 4.0.0 + write-file-atomic: 3.0.3 + dev: true + + /call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.2.1 /call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} @@ -10568,6 +11437,7 @@ packages: /camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} + dev: false /caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} @@ -10602,6 +11472,25 @@ packages: resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} dev: true + /chai@4.4.0: + resolution: {integrity: sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + + /chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + dependencies: + traverse: 0.3.9 + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -10633,6 +11522,11 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + /change-case-all@1.0.14: resolution: {integrity: sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA==} dependencies: @@ -10683,6 +11577,7 @@ packages: /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} + dev: false /char-regex@2.0.1: resolution: {integrity: sha512-oSvEeo6ZUD7NepqAat3RqoucZ5SeqLJgOvVIwkafu6IP3V0pO38s/ypdVUmDDK6qIIHNlYHJAKX9E7R7HoKElw==} @@ -10709,6 +11604,12 @@ packages: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} dev: true + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 + dev: true + /check-types@11.2.2: resolution: {integrity: sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==} dev: false @@ -10736,12 +11637,29 @@ packages: engines: {node: '>=6.0'} dev: false + /chromium-bidi@0.4.16(devtools-protocol@0.0.1147663): + resolution: {integrity: sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==} + peerDependencies: + devtools-protocol: '*' + dependencies: + devtools-protocol: 0.0.1147663 + mitt: 3.0.0 + dev: true + /ci-info@3.8.0: resolution: {integrity: sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==} engines: {node: '>=8'} + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + /cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + dev: false /classnames@2.3.2: resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} @@ -10833,6 +11751,7 @@ packages: /co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false /coa@2.0.2: resolution: {integrity: sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==} @@ -10845,6 +11764,7 @@ packages: /collect-v8-coverage@1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} + dev: false /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} @@ -10902,7 +11822,6 @@ packages: /commander@9.4.1: resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} engines: {node: ^12.20.0 || >=14} - dev: false /comment-parser@1.4.0: resolution: {integrity: sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw==} @@ -10919,7 +11838,6 @@ packages: /commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - dev: false /compare-func@2.0.0: resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} @@ -10932,6 +11850,16 @@ packages: resolution: {integrity: sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==} dev: true + /compress-commons@5.0.1: + resolution: {integrity: sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==} + engines: {node: '>= 12.0.0'} + dependencies: + crc-32: 1.2.2 + crc32-stream: 5.0.0 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + dev: true + /compressible@2.0.18: resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} engines: {node: '>= 0.6'} @@ -10965,6 +11893,10 @@ packages: engines: {node: '>=0.8'} dev: false + /console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + dev: true + /constant-case@3.0.4: resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} dependencies: @@ -10973,6 +11905,10 @@ packages: upper-case: 2.0.2 dev: true + /constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + dev: true + /content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -11032,7 +11968,6 @@ packages: /core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - dev: false /cosmiconfig-toml-loader@1.0.0: resolution: {integrity: sha512-H/2gurFWVi7xXvCyvsWRLCMekl4tITJcX0QEsDMpzxtuxDyM59xLatYNg4s/k9AA/HdtCYfj2su8mgA0GSDLDA==} @@ -11102,23 +12037,52 @@ packages: path-type: 4.0.0 yaml: 1.10.2 - /create-jest@29.7.0(@types/node@18.15.3): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + /coverage-diff@3.2.0: + resolution: {integrity: sha512-ZapsZXZZTQAEfWlUoObrpkvRnMYHbi99T96XRJlrbcZkIKpDvSmVxfJ0dPwjI3eTbl122hVMTmEwielS7qvTfg==} + dependencies: + markdown-table: 2.0.0 + dev: true + + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} hasBin: true + dev: true + + /crc32-stream@5.0.0: + resolution: {integrity: sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==} + engines: {node: '>= 12.0.0'} dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.15.3) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node + crc-32: 1.2.2 + readable-stream: 3.6.2 + dev: true + + /create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + dependencies: + bn.js: 4.12.0 + elliptic: 6.5.4 + dev: true + + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + dev: true + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 dev: true /create-require@1.1.1: @@ -11163,6 +12127,22 @@ packages: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} dev: true + /crypto-browserify@3.12.0: + resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.2 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + dev: true + /crypto-random-string@2.0.0: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} @@ -11179,13 +12159,13 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /css-declaration-sorter@6.4.0(postcss@8.4.24): + /css-declaration-sorter@6.4.0(postcss@8.4.31): resolution: {integrity: sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==} engines: {node: ^10 || ^12 || >=14} peerDependencies: postcss: ^8.0.9 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false /css-has-pseudo@3.0.4(postcss@8.4.24): @@ -11205,12 +12185,12 @@ packages: peerDependencies: webpack: ^5.0.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.24) - postcss: 8.4.24 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.24) - postcss-modules-local-by-default: 4.0.3(postcss@8.4.24) - postcss-modules-scope: 3.0.0(postcss@8.4.24) - postcss-modules-values: 4.0.0(postcss@8.4.24) + icss-utils: 5.1.0(postcss@8.4.31) + postcss: 8.4.31 + postcss-modules-extract-imports: 3.0.0(postcss@8.4.31) + postcss-modules-local-by-default: 4.0.3(postcss@8.4.31) + postcss-modules-scope: 3.0.0(postcss@8.4.31) + postcss-modules-values: 4.0.0(postcss@8.4.31) postcss-value-parser: 4.2.0 semver: 7.5.4 webpack: 5.88.0(esbuild@0.17.19) @@ -11235,10 +12215,10 @@ packages: esbuild: optional: true dependencies: - cssnano: 5.1.15(postcss@8.4.24) + cssnano: 5.1.15(postcss@8.4.31) esbuild: 0.17.19 jest-worker: 27.5.1 - postcss: 8.4.24 + postcss: 8.4.31 schema-utils: 4.2.0 serialize-javascript: 6.0.1 source-map: 0.6.1 @@ -11288,6 +12268,10 @@ packages: nth-check: 2.1.1 dev: false + /css-shorthand-properties@1.1.1: + resolution: {integrity: sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A==} + dev: true + /css-tree@1.0.0-alpha.37: resolution: {integrity: sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==} engines: {node: '>=8.0.0'} @@ -11320,6 +12304,10 @@ packages: source-map-js: 1.0.2 dev: false + /css-value@0.0.1: + resolution: {integrity: sha512-FUV3xaJ63buRLgHrLQVlVgQnQdR4yqdLGaDu7g8CQcWjInDfM9plBTPI9FRfpahju1UBSaMckeb2/46ApS/V1Q==} + dev: true + /css-what@3.4.2: resolution: {integrity: sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==} engines: {node: '>= 6'} @@ -11343,62 +12331,62 @@ packages: engines: {node: '>=4'} hasBin: true - /cssnano-preset-default@5.2.14(postcss@8.4.24): + /cssnano-preset-default@5.2.14(postcss@8.4.31): resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - css-declaration-sorter: 6.4.0(postcss@8.4.24) - cssnano-utils: 3.1.0(postcss@8.4.24) - postcss: 8.4.24 - postcss-calc: 8.2.4(postcss@8.4.24) - postcss-colormin: 5.3.1(postcss@8.4.24) - postcss-convert-values: 5.1.3(postcss@8.4.24) - postcss-discard-comments: 5.1.2(postcss@8.4.24) - postcss-discard-duplicates: 5.1.0(postcss@8.4.24) - postcss-discard-empty: 5.1.1(postcss@8.4.24) - postcss-discard-overridden: 5.1.0(postcss@8.4.24) - postcss-merge-longhand: 5.1.7(postcss@8.4.24) - postcss-merge-rules: 5.1.4(postcss@8.4.24) - postcss-minify-font-values: 5.1.0(postcss@8.4.24) - postcss-minify-gradients: 5.1.1(postcss@8.4.24) - postcss-minify-params: 5.1.4(postcss@8.4.24) - postcss-minify-selectors: 5.2.1(postcss@8.4.24) - postcss-normalize-charset: 5.1.0(postcss@8.4.24) - postcss-normalize-display-values: 5.1.0(postcss@8.4.24) - postcss-normalize-positions: 5.1.1(postcss@8.4.24) - postcss-normalize-repeat-style: 5.1.1(postcss@8.4.24) - postcss-normalize-string: 5.1.0(postcss@8.4.24) - postcss-normalize-timing-functions: 5.1.0(postcss@8.4.24) - postcss-normalize-unicode: 5.1.1(postcss@8.4.24) - postcss-normalize-url: 5.1.0(postcss@8.4.24) - postcss-normalize-whitespace: 5.1.1(postcss@8.4.24) - postcss-ordered-values: 5.1.3(postcss@8.4.24) - postcss-reduce-initial: 5.1.2(postcss@8.4.24) - postcss-reduce-transforms: 5.1.0(postcss@8.4.24) - postcss-svgo: 5.1.0(postcss@8.4.24) - postcss-unique-selectors: 5.1.1(postcss@8.4.24) - dev: false - - /cssnano-utils@3.1.0(postcss@8.4.24): + css-declaration-sorter: 6.4.0(postcss@8.4.31) + cssnano-utils: 3.1.0(postcss@8.4.31) + postcss: 8.4.31 + postcss-calc: 8.2.4(postcss@8.4.31) + postcss-colormin: 5.3.1(postcss@8.4.31) + postcss-convert-values: 5.1.3(postcss@8.4.31) + postcss-discard-comments: 5.1.2(postcss@8.4.31) + postcss-discard-duplicates: 5.1.0(postcss@8.4.31) + postcss-discard-empty: 5.1.1(postcss@8.4.31) + postcss-discard-overridden: 5.1.0(postcss@8.4.31) + postcss-merge-longhand: 5.1.7(postcss@8.4.31) + postcss-merge-rules: 5.1.4(postcss@8.4.31) + postcss-minify-font-values: 5.1.0(postcss@8.4.31) + postcss-minify-gradients: 5.1.1(postcss@8.4.31) + postcss-minify-params: 5.1.4(postcss@8.4.31) + postcss-minify-selectors: 5.2.1(postcss@8.4.31) + postcss-normalize-charset: 5.1.0(postcss@8.4.31) + postcss-normalize-display-values: 5.1.0(postcss@8.4.31) + postcss-normalize-positions: 5.1.1(postcss@8.4.31) + postcss-normalize-repeat-style: 5.1.1(postcss@8.4.31) + postcss-normalize-string: 5.1.0(postcss@8.4.31) + postcss-normalize-timing-functions: 5.1.0(postcss@8.4.31) + postcss-normalize-unicode: 5.1.1(postcss@8.4.31) + postcss-normalize-url: 5.1.0(postcss@8.4.31) + postcss-normalize-whitespace: 5.1.1(postcss@8.4.31) + postcss-ordered-values: 5.1.3(postcss@8.4.31) + postcss-reduce-initial: 5.1.2(postcss@8.4.31) + postcss-reduce-transforms: 5.1.0(postcss@8.4.31) + postcss-svgo: 5.1.0(postcss@8.4.31) + postcss-unique-selectors: 5.1.1(postcss@8.4.31) + dev: false + + /cssnano-utils@3.1.0(postcss@8.4.31): resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /cssnano@5.1.15(postcss@8.4.24): + /cssnano@5.1.15(postcss@8.4.31): resolution: {integrity: sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - cssnano-preset-default: 5.2.14(postcss@8.4.24) + cssnano-preset-default: 5.2.14(postcss@8.4.31) lilconfig: 2.1.0 - postcss: 8.4.24 + postcss: 8.4.31 yaml: 1.10.2 dev: false @@ -11463,6 +12451,16 @@ packages: /damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + /data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + dev: true + + /data-uri-to-buffer@6.0.1: + resolution: {integrity: sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==} + engines: {node: '>= 14'} + dev: true + /data-urls@2.0.0: resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} engines: {node: '>=10'} @@ -11495,6 +12493,17 @@ packages: ms: 2.0.0 dev: false + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + /debug@3.2.7(supports-color@5.5.0): resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -11530,21 +12539,31 @@ packages: engines: {node: '>=0.10.0'} dev: true + /decamelize@6.0.0: + resolution: {integrity: sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /decimal.js@10.4.3: resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} dev: false + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: true + /dedent@0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: false - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true + /deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 dev: true /deep-equal@2.2.1: @@ -11578,9 +12597,15 @@ packages: engines: {node: '>=4.0.0'} dev: false + /deepmerge-ts@5.1.0: + resolution: {integrity: sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw==} + engines: {node: '>=16.0.0'} + dev: true + /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + dev: false /default-browser-id@3.0.0: resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} @@ -11607,12 +12632,24 @@ packages: execa: 5.1.1 dev: false + /default-require-extensions@3.0.1: + resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} + engines: {node: '>=8'} + dependencies: + strip-bom: 4.0.0 + dev: true + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 dev: true + /defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: true + /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} engines: {node: '>= 0.4'} @@ -11647,6 +12684,15 @@ packages: object-keys: 1.1.1 dev: true + /degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + dev: true + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -11670,6 +12716,13 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + /des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: true + /destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -11683,6 +12736,7 @@ packages: /detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} + dev: false /detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} @@ -11703,6 +12757,14 @@ packages: - supports-color dev: false + /devtools-protocol@0.0.1147663: + resolution: {integrity: sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ==} + dev: true + + /devtools-protocol@0.0.1239539: + resolution: {integrity: sha512-uS7hZVqZxGyZwR8lX/8wWyNLGEYs1wWWxN7qeRC+wBZ4VM5JXYwCJg8hofEna5yX0W2cavpjHOE4ukHXLHlEaA==} + dev: true + /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -11714,6 +12776,7 @@ packages: /diff-sequences@29.4.3: resolution: {integrity: sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + dev: false /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} @@ -11725,6 +12788,14 @@ packages: engines: {node: '>=0.3.1'} dev: true + /diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + dev: true + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -11790,6 +12861,11 @@ packages: entities: 4.5.0 dev: false + /domain-browser@4.23.0: + resolution: {integrity: sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==} + engines: {node: '>=10'} + dev: true + /domelementtype@1.3.1: resolution: {integrity: sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==} dev: false @@ -11879,6 +12955,12 @@ packages: engines: {node: '>=4'} dev: true + /duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + dependencies: + readable-stream: 2.3.8 + dev: true + /duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} dev: false @@ -11886,6 +12968,27 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + /edge-paths@3.0.5: + resolution: {integrity: sha512-sB7vSrDnFa4ezWQk9nZ/n0FdpdUuC6R1EOrlU3DL+bovcNFK28rqu2emmAUjujYEJTWIgQGqgVVWUZXMnc8iWg==} + engines: {node: '>=14.0.0'} + dependencies: + '@types/which': 2.0.2 + which: 2.0.2 + dev: true + + /edgedriver@5.3.9: + resolution: {integrity: sha512-G0wNgFMFRDnFfKaXG2R6HiyVHqhKwdQ3EgoxW3wPlns2wKqem7F+HgkWBcevN7Vz0nN4AXtskID7/6jsYDXcKw==} + hasBin: true + requiresBuild: true + dependencies: + '@wdio/logger': 8.24.12 + decamelize: 6.0.0 + edge-paths: 3.0.5 + node-fetch: 3.3.2 + unzipper: 0.10.14 + which: 4.0.0 + dev: true + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false @@ -11914,18 +13017,13 @@ packages: inherits: 2.0.4 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false + dev: true /emittery@0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} engines: {node: '>=12'} dev: false - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true - /emittery@0.8.1: resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} engines: {node: '>=10'} @@ -11947,6 +13045,12 @@ packages: engines: {node: '>= 0.8'} dev: false + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + /enhanced-resolve@5.15.0: resolution: {integrity: sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==} engines: {node: '>=10.13.0'} @@ -12132,6 +13236,10 @@ packages: is-date-object: 1.0.5 is-symbol: 1.0.4 + /es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + dev: true + /esbuild@0.17.19: resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} engines: {node: '>=12'} @@ -12161,6 +13269,37 @@ packages: '@esbuild/win32-ia32': 0.17.19 '@esbuild/win32-x64': 0.17.19 + /esbuild@0.19.11: + resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.11 + '@esbuild/android-arm': 0.19.11 + '@esbuild/android-arm64': 0.19.11 + '@esbuild/android-x64': 0.19.11 + '@esbuild/darwin-arm64': 0.19.11 + '@esbuild/darwin-x64': 0.19.11 + '@esbuild/freebsd-arm64': 0.19.11 + '@esbuild/freebsd-x64': 0.19.11 + '@esbuild/linux-arm': 0.19.11 + '@esbuild/linux-arm64': 0.19.11 + '@esbuild/linux-ia32': 0.19.11 + '@esbuild/linux-loong64': 0.19.11 + '@esbuild/linux-mips64el': 0.19.11 + '@esbuild/linux-ppc64': 0.19.11 + '@esbuild/linux-riscv64': 0.19.11 + '@esbuild/linux-s390x': 0.19.11 + '@esbuild/linux-x64': 0.19.11 + '@esbuild/netbsd-x64': 0.19.11 + '@esbuild/openbsd-x64': 0.19.11 + '@esbuild/sunos-x64': 0.19.11 + '@esbuild/win32-arm64': 0.19.11 + '@esbuild/win32-ia32': 0.19.11 + '@esbuild/win32-x64': 0.19.11 + dev: true + /esbuild@0.19.3: resolution: {integrity: sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==} engines: {node: '>=12'} @@ -12206,6 +13345,7 @@ packages: /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} + dev: false /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -12224,6 +13364,18 @@ packages: source-map: 0.6.1 dev: false + /escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.0)(eslint@8.52.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} @@ -13115,6 +14267,12 @@ packages: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.5 + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -13147,6 +14305,7 @@ packages: transitivePeerDependencies: - bufferutil - utf-8-validate + dev: false /event-target-polyfill@0.0.3: resolution: {integrity: sha512-ZMc6UuvmbinrCk4RzGyVmRyIsAyxMRlp4CqSrcQRO8Dy0A9ldbiRy5kdtBj4OtP7EClGdqGfIqo9JmOClMsGLQ==} @@ -13163,7 +14322,13 @@ packages: /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: false + + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + dev: true /execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} @@ -13194,9 +14359,25 @@ packages: strip-final-newline: 3.0.0 dev: true + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: true + /exit@0.1.2: resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} engines: {node: '>= 0.8.0'} + dev: false /expect@27.5.1: resolution: {integrity: sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==} @@ -13217,17 +14398,7 @@ packages: jest-matcher-utils: 29.5.0 jest-message-util: 29.5.0 jest-util: 29.5.0 - - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/expect-utils': 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - dev: true + dev: false /express@4.18.2: resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==} @@ -13293,11 +14464,30 @@ packages: /extract-files@9.0.0: resolution: {integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==} engines: {node: ^10.17.0 || ^12.0.0 || >= 13.7.0} + dev: false + + /extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + dev: true /fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} dev: true + /fast-deep-equal@2.0.1: + resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} + dev: true + /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -13309,6 +14499,10 @@ packages: resolution: {integrity: sha512-G3BSX9cfKttjr+2o1O22tYMLq0DPluZnYtq1rXumE1SpL/F/SLIfHx08WYQoWSIpeMYf8sRbJ8++71+v6Pnxfg==} dev: true + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: true + /fast-glob@3.2.12: resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} engines: {node: '>=8.6.0'} @@ -13388,7 +14582,21 @@ packages: - encoding dev: true - /figures@3.2.0: + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + + /fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.2.1 + dev: true + + /figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} dependencies: @@ -13458,7 +14666,6 @@ packages: commondir: 1.0.1 make-dir: 3.1.0 pkg-dir: 4.2.0 - dev: false /find-up@2.1.0: resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} @@ -13537,6 +14744,14 @@ packages: dependencies: is-callable: 1.2.7 + /foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + dev: true + /foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} @@ -13580,6 +14795,11 @@ packages: resolution: {integrity: sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==} dev: true + /form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + dev: true + /form-data@3.0.1: resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} engines: {node: '>= 6'} @@ -13601,6 +14821,13 @@ packages: web-streams-polyfill: 4.0.0-beta.3 dev: true + /formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + dependencies: + fetch-blob: 3.2.0 + dev: true + /forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} @@ -13632,6 +14859,10 @@ packages: engines: {node: '>= 0.6'} dev: false + /fromentries@1.3.2: + resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} + dev: true + /fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -13683,6 +14914,16 @@ packages: requiresBuild: true optional: true + /fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + dependencies: + graceful-fs: 4.2.11 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.6.3 + dev: true + /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} @@ -13711,6 +14952,24 @@ packages: /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + /geckodriver@4.3.0: + resolution: {integrity: sha512-QfpvxFsMORwKpvnLslkHCr3NTCczHAvkte6+pQGsiUZXKBe6mO4TTb727b+9KMVSK6XZqhR6ZwImKdP+F5vS6A==} + engines: {node: ^16.13 || >=18 || >=20} + hasBin: true + requiresBuild: true + dependencies: + '@wdio/logger': 8.24.12 + decamelize: 6.0.0 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + node-fetch: 3.3.2 + tar-fs: 3.0.4 + unzipper: 0.10.14 + which: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -13719,6 +14978,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true + /get-graphql-schema@2.1.2: resolution: {integrity: sha512-1z5Hw91VrE3GrpCZE6lE8Dy+jz4kXWesLS7rCSjwOxf5BOcIedAZeTUJRIeIzmmR+PA9CKOkPTYFRJbdgUtrxA==} hasBin: true @@ -13761,15 +15024,32 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + /get-port@7.0.0: + resolution: {integrity: sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==} + engines: {node: '>=16'} + dev: true + /get-stdin@5.0.1: resolution: {integrity: sha512-jZV7n6jGE3Gt7fgSTJoz91Ak5MuTLwMwkoYdjxuJ/AmjIsE1UC03y/IWkZCQGEvVNS9qoRNwy5BCqxImv0FVeA==} engines: {node: '>=0.12.0'} dev: true + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: true + /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: true + /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} engines: {node: '>= 0.4'} @@ -13783,6 +15063,24 @@ packages: resolve-pkg-maps: 1.0.0 dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + + /get-uri@6.0.2: + resolution: {integrity: sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==} + engines: {node: '>= 14'} + dependencies: + basic-ftp: 5.0.4 + data-uri-to-buffer: 6.0.1 + debug: 4.3.4 + fs-extra: 8.1.0 + transitivePeerDependencies: + - supports-color + dev: true + /get-url-origin@1.0.1: resolution: {integrity: sha512-MMSKo16gB2+6CjWy55jNdIAqUEaKgw3LzZCb8wVVtFrhoQ78EXyuYXxDdn3COI3A4Xr4ZfM3fZa9RTjO6DOTxw==} dev: true @@ -13845,6 +15143,17 @@ packages: once: 1.4.0 path-is-absolute: 1.0.1 + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: true + /global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -13908,6 +15217,23 @@ packages: dependencies: get-intrinsic: 1.2.1 + /got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: true + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -13959,6 +15285,7 @@ packages: graphql: 16.6.0 transitivePeerDependencies: - encoding + dev: false /graphql-request@6.1.0(graphql@16.6.0): resolution: {integrity: sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==} @@ -14070,12 +15397,29 @@ packages: dependencies: function-bind: 1.1.1 + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: true + /hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - dev: false + dev: true + + /hasha@5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + dev: true /hasown@2.0.0: resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} @@ -14101,7 +15445,7 @@ packages: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - dev: false + dev: true /hoopy@0.1.4: resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==} @@ -14172,6 +15516,10 @@ packages: entities: 2.2.0 dev: false + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: true + /http-deceiver@1.2.7: resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} dev: false @@ -14222,6 +15570,16 @@ packages: - supports-color dev: true + /http-proxy-agent@7.0.0: + resolution: {integrity: sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /http-proxy-middleware@2.0.6(@types/express@4.17.17): resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} engines: {node: '>=12.0.0'} @@ -14252,6 +15610,18 @@ packages: - debug dev: false + /http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: true + + /https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + dev: true + /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} @@ -14272,6 +15642,16 @@ packages: - supports-color dev: true + /https-proxy-agent@7.0.2: + resolution: {integrity: sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /human-id@1.0.2: resolution: {integrity: sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==} dev: true @@ -14285,6 +15665,16 @@ packages: engines: {node: '>=14.18.0'} dev: true + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: true + + /hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} + dev: true + /iconv-lite@0.4.24: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} @@ -14298,13 +15688,13 @@ packages: safer-buffer: 2.1.2 dev: false - /icss-utils@5.1.0(postcss@8.4.24): + /icss-utils@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false /idb@7.1.1: @@ -14362,6 +15752,11 @@ packages: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + dev: false + + /import-meta-resolve@4.0.0: + resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} + dev: true /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -14431,6 +15826,14 @@ packages: dependencies: loose-envify: 1.4.0 + /ip@1.1.8: + resolution: {integrity: sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==} + dev: true + + /ip@2.0.0: + resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==} + dev: true + /ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -14466,7 +15869,6 @@ packages: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: false /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} @@ -14582,6 +15984,7 @@ packages: /is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} + dev: false /is-generator-function@1.0.10: resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} @@ -14626,6 +16029,14 @@ packages: resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} dev: false + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + dev: true + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -14669,6 +16080,11 @@ packages: engines: {node: '>=10'} dev: false + /is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + dev: true + /is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: false @@ -14752,7 +16168,6 @@ packages: /is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - dev: false /is-unc-path@1.0.0: resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==} @@ -14803,7 +16218,6 @@ packages: /isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - dev: false /isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} @@ -14811,6 +16225,16 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + /isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + dev: true + + /isomorphic-timers-promises@1.0.1: + resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} + engines: {node: '>=10'} + dev: true + /isomorphic-ws@5.0.0(ws@8.13.0): resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} peerDependencies: @@ -14823,31 +16247,67 @@ packages: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} + /istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + /istanbul-lib-hook@3.0.0: + resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==} + engines: {node: '>=8'} + dependencies: + append-transform: 2.0.0 + dev: true + + /istanbul-lib-instrument@4.0.3: + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.23.3 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + /istanbul-lib-instrument@5.2.1: resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.22.5 - '@babel/parser': 7.22.5 + '@babel/core': 7.23.3 + '@babel/parser': 7.23.4 '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 - semver: 6.3.0 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 transitivePeerDependencies: - supports-color + dev: false /istanbul-lib-instrument@6.0.1: resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==} engines: {node: '>=10'} dependencies: - '@babel/core': 7.22.5 - '@babel/parser': 7.22.5 + '@babel/core': 7.23.3 + '@babel/parser': 7.23.4 '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 semver: 7.5.4 transitivePeerDependencies: - supports-color dev: true + /istanbul-lib-processinfo@2.0.3: + resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} + engines: {node: '>=8'} + dependencies: + archy: 1.0.0 + cross-spawn: 7.0.3 + istanbul-lib-coverage: 3.2.0 + p-map: 3.0.0 + rimraf: 3.0.2 + uuid: 8.3.2 + dev: true + /istanbul-lib-report@3.0.0: resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} engines: {node: '>=8'} @@ -14856,12 +16316,20 @@ packages: make-dir: 3.1.0 supports-color: 7.2.0 + /istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + /istanbul-lib-source-maps@4.0.1: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: debug: 4.3.4 - istanbul-lib-coverage: 3.2.0 + istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color @@ -14872,6 +16340,14 @@ packages: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.0 + dev: true + + /istanbul-reports@3.1.6: + resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 /iterall@1.3.0: resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} @@ -14915,15 +16391,6 @@ packages: throat: 6.0.2 dev: false - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - execa: 5.1.1 - jest-util: 29.7.0 - p-limit: 3.1.0 - dev: true - /jest-circus@27.5.1: resolution: {integrity: sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -14931,7 +16398,7 @@ packages: '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -14951,35 +16418,6 @@ packages: - supports-color dev: false - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.5.1 - is-generator-fn: 2.1.0 - jest-each: 29.7.0 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - p-limit: 3.1.0 - pretty-format: 29.7.0 - pure-rand: 6.0.2 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - /jest-cli@27.5.1: resolution: {integrity: sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15010,34 +16448,6 @@ packages: - utf-8-validate dev: false - /jest-cli@29.7.0(@types/node@18.15.3): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.15.3) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.15.3) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - /jest-config@27.5.1: resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15047,10 +16457,10 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.23.3 '@jest/test-sequencer': 27.5.1 '@jest/types': 27.5.1 - babel-jest: 27.5.1(@babel/core@7.22.5) + babel-jest: 27.5.1(@babel/core@7.23.3) chalk: 4.1.2 ci-info: 3.8.0 deepmerge: 4.3.1 @@ -15078,89 +16488,9 @@ packages: - utf-8-validate dev: false - /jest-config@29.7.0(@types/node@16.18.34): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.22.5 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - babel-jest: 29.7.0(@babel/core@7.22.5) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-config@29.7.0(@types/node@18.15.3): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true - dependencies: - '@babel/core': 7.22.5 - '@jest/test-sequencer': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.15.3 - babel-jest: 29.7.0(@babel/core@7.22.5) - chalk: 4.1.2 - ci-info: 3.8.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.7.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - - /jest-diff@27.5.1: - resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + /jest-diff@27.5.1: + resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: chalk: 4.1.2 diff-sequences: 27.5.1 @@ -15176,16 +16506,7 @@ packages: diff-sequences: 29.4.3 jest-get-type: 29.4.3 pretty-format: 29.5.0 - - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true + dev: false /jest-docblock@27.5.1: resolution: {integrity: sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==} @@ -15194,13 +16515,6 @@ packages: detect-newline: 3.1.0 dev: false - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true - /jest-each@27.5.1: resolution: {integrity: sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15212,17 +16526,6 @@ packages: pretty-format: 27.5.1 dev: false - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 - dev: true - /jest-environment-jsdom@27.5.1: resolution: {integrity: sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15230,7 +16533,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 jest-mock: 27.5.1 jest-util: 27.5.1 jsdom: 16.7.0 @@ -15248,23 +16551,11 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 jest-mock: 27.5.1 jest-util: 27.5.1 dev: false - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - /jest-get-type@27.5.1: resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15273,11 +16564,7 @@ packages: /jest-get-type@29.4.3: resolution: {integrity: sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + dev: false /jest-haste-map@27.5.1: resolution: {integrity: sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==} @@ -15285,7 +16572,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@types/graceful-fs': 4.1.6 - '@types/node': 16.18.34 + '@types/node': 20.10.5 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -15299,25 +16586,6 @@ packages: fsevents: 2.3.3 dev: false - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.6 - '@types/node': 16.18.34 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.5 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /jest-jasmine2@27.5.1: resolution: {integrity: sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15326,7 +16594,7 @@ packages: '@jest/source-map': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 co: 4.6.0 expect: 27.5.1 @@ -15351,14 +16619,6 @@ packages: pretty-format: 27.5.1 dev: false - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true - /jest-matcher-utils@27.5.1: resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15377,16 +16637,7 @@ packages: jest-diff: 29.5.0 jest-get-type: 29.4.3 pretty-format: 29.5.0 - - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true + dev: false /jest-message-util@27.5.1: resolution: {integrity: sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==} @@ -15431,39 +16682,16 @@ packages: pretty-format: 29.5.0 slash: 3.0.0 stack-utils: 2.0.6 - - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.22.5 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.1 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.5 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true + dev: false /jest-mock@27.5.1: resolution: {integrity: sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 dev: false - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - jest-util: 29.7.0 - dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} @@ -15476,18 +16704,6 @@ packages: jest-resolve: 27.5.1 dev: false - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 29.7.0 - dev: true - /jest-regex-util@27.5.1: resolution: {integrity: sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15498,11 +16714,6 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dev: false - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - /jest-resolve-dependencies@27.5.1: resolution: {integrity: sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15514,16 +16725,6 @@ packages: - supports-color dev: false - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - /jest-resolve@27.5.1: resolution: {integrity: sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15540,21 +16741,6 @@ packages: slash: 3.0.0 dev: false - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.2 - slash: 3.0.0 - dev: true - /jest-runner@27.5.1: resolution: {integrity: sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15564,7 +16750,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 emittery: 0.8.1 graceful-fs: 4.2.11 @@ -15587,35 +16773,6 @@ packages: - utf-8-validate dev: false - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.11 - jest-docblock: 29.7.0 - jest-environment-node: 29.7.0 - jest-haste-map: 29.7.0 - jest-leak-detector: 29.7.0 - jest-message-util: 29.7.0 - jest-resolve: 29.7.0 - jest-runtime: 29.7.0 - jest-util: 29.7.0 - jest-watcher: 29.7.0 - jest-worker: 29.7.0 - p-limit: 3.1.0 - source-map-support: 0.5.13 - transitivePeerDependencies: - - supports-color - dev: true - /jest-runtime@27.5.1: resolution: {integrity: sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15646,41 +16803,11 @@ packages: - supports-color dev: false - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0 - '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - chalk: 4.1.2 - cjs-module-lexer: 1.2.3 - collect-v8-coverage: 1.0.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.7.0 - jest-snapshot: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - strip-bom: 4.0.0 - transitivePeerDependencies: - - supports-color - dev: true - /jest-serializer@27.5.1: resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 graceful-fs: 4.2.11 dev: false @@ -15688,16 +16815,16 @@ packages: resolution: {integrity: sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@babel/core': 7.22.5 + '@babel/core': 7.23.3 '@babel/generator': 7.22.5 - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.5) + '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.23.3) '@babel/traverse': 7.22.5 - '@babel/types': 7.22.5 + '@babel/types': 7.23.4 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 '@types/babel__traverse': 7.20.1 '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.5) + babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.3) chalk: 4.1.2 expect: 27.5.1 graceful-fs: 4.2.11 @@ -15714,47 +16841,12 @@ packages: - supports-color dev: false - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.22.5 - '@babel/generator': 7.22.5 - '@babel/plugin-syntax-jsx': 7.22.5(@babel/core@7.22.5) - '@babel/plugin-syntax-typescript': 7.22.5(@babel/core@7.22.5) - '@babel/types': 7.22.5 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.22.5) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - jest-matcher-utils: 29.7.0 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - natural-compare: 1.4.0 - pretty-format: 29.7.0 - semver: 7.5.4 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-text-transformer@1.0.4: - resolution: {integrity: sha512-Qi3FpWP6EFxZimSD05Zlmd/WER8l/3agVG7e5voHgdnM2vTs45sxS/i8qMWMO/dBkoxajndrGXfJTvhEENnjqw==} - engines: {node: '>=9.5.0', npm: '>=5.8.0'} - dependencies: - uuid: 3.4.0 - dev: true - /jest-util@27.5.1: resolution: {integrity: sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -15766,7 +16858,7 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@jest/types': 28.1.3 - '@types/node': 16.18.34 + '@types/node': 20.10.5 chalk: 4.1.2 ci-info: 3.8.0 graceful-fs: 4.2.11 @@ -15783,18 +16875,7 @@ packages: ci-info: 3.8.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - chalk: 4.1.2 - ci-info: 3.8.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - dev: true + dev: false /jest-validate@27.5.1: resolution: {integrity: sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==} @@ -15808,18 +16889,6 @@ packages: pretty-format: 27.5.1 dev: false - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - dev: true - /jest-watch-typeahead@1.1.0(jest@27.5.1): resolution: {integrity: sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -15842,7 +16911,7 @@ packages: dependencies: '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 16.18.34 + '@types/node': 20.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 27.5.1 @@ -15855,7 +16924,7 @@ packages: dependencies: '@jest/test-result': 28.1.3 '@jest/types': 28.1.3 - '@types/node': 16.18.34 + '@types/node': 20.10.5 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.10.2 @@ -15863,25 +16932,11 @@ packages: string-length: 4.0.2 dev: false - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 16.18.34 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - dev: true - /jest-worker@26.6.2: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 merge-stream: 2.0.0 supports-color: 7.2.0 dev: false @@ -15890,7 +16945,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false @@ -15899,21 +16954,11 @@ packages: resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@types/node': 16.18.34 + '@types/node': 20.10.5 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 16.18.34 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true - /jest@27.5.1: resolution: {integrity: sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -15935,27 +16980,6 @@ packages: - utf-8-validate dev: false - /jest@29.7.0(@types/node@18.15.3): - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - '@jest/core': 29.7.0 - '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.15.3) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - dev: true - /jiti@1.18.2: resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==} hasBin: true @@ -16007,7 +17031,7 @@ packages: optional: true dependencies: abab: 2.0.6 - acorn: 8.9.0 + acorn: 8.11.3 acorn-globals: 6.0.0 cssom: 0.4.4 cssstyle: 2.3.0 @@ -16049,6 +17073,26 @@ packages: engines: {node: '>=4'} hasBin: true + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-joy@9.9.1(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.0): + resolution: {integrity: sha512-/d7th2nbQRBQ/nqTkBe6KjjvDciSwn9UICmndwk3Ed/Bk9AqkTRm4PnLVfXG4DKbT0rEY0nKnwE7NqZlqKE6kg==} + engines: {node: '>=10.0'} + hasBin: true + peerDependencies: + quill-delta: ^5 + rxjs: '7' + tslib: '2' + dependencies: + arg: 5.0.2 + hyperdyperid: 1.2.0 + quill-delta: 5.1.0 + rxjs: 7.8.1 + tslib: 2.6.0 + dev: true + /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} dev: true @@ -16127,6 +17171,12 @@ packages: array-includes: 3.1.6 object.assign: 4.1.4 + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + /kind-of@6.0.3: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} @@ -16145,6 +17195,11 @@ packages: engines: {node: '>= 8'} dev: false + /ky@0.33.3: + resolution: {integrity: sha512-CasD9OCEQSFIam2U8efFK81Yeg8vNMTBUqtMOHlrcWQHqUX3HeCl9Dr31u4toV7emlH8Mymk5+9p0lL6mKb/Xw==} + engines: {node: '>=14.16'} + dev: true + /language-subtag-registry@0.3.22: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} @@ -16167,9 +17222,17 @@ packages: shell-quote: 1.8.1 dev: false + /lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.8 + dev: true + /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + dev: false /levn@0.3.0: resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} @@ -16199,6 +17262,10 @@ packages: uc.micro: 1.0.6 dev: true + /listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + dev: true + /listr2@4.0.5: resolution: {integrity: sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==} engines: {node: '>=12'} @@ -16272,6 +17339,22 @@ packages: engines: {node: '>= 12.13.0'} dev: false + /local-pkg@0.5.0: + resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==} + engines: {node: '>=14'} + dependencies: + mlly: 1.4.2 + pkg-types: 1.0.3 + dev: true + + /locate-app@2.2.7: + resolution: {integrity: sha512-4NR8WidaCRCozDZ0BW0U5wL91EPuuIshFun2//4Kpca4DIi5XPQHAUEbj+MQt7NihZTYs+HKfOuaoqurZ58bUg==} + dependencies: + n12: 1.8.10 + type-fest: 2.13.0 + userhome: 1.0.0 + dev: true + /locate-path@2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} @@ -16308,12 +17391,25 @@ packages: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} dev: false + /lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + dev: true + /lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} dev: false + /lodash.flattendeep@4.4.0: + resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} + dev: true + + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: true + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + dev: false /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -16333,6 +17429,10 @@ packages: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: false + /lodash.zip@4.2.0: + resolution: {integrity: sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -16354,6 +17454,15 @@ packages: wrap-ansi: 6.2.0 dev: true + /loglevel-plugin-prefix@0.8.4: + resolution: {integrity: sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g==} + dev: true + + /loglevel@1.8.1: + resolution: {integrity: sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==} + engines: {node: '>= 0.6.0'} + dev: true + /long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} dev: false @@ -16368,6 +17477,12 @@ packages: dependencies: js-tokens: 4.0.0 + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + dependencies: + get-func-name: 2.0.2 + dev: true + /lower-case-first@2.0.2: resolution: {integrity: sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==} dependencies: @@ -16379,6 +17494,11 @@ packages: dependencies: tslib: 2.6.0 + /lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /lru-cache@10.0.0: resolution: {integrity: sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw==} engines: {node: 14 || >=16.14} @@ -16401,6 +17521,11 @@ packages: dependencies: yallist: 4.0.0 + /lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + dev: true + /lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} @@ -16414,11 +17539,32 @@ packages: dependencies: sourcemap-codec: 1.4.8 + /magic-string@0.30.5: + resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + + /magicast@0.3.2: + resolution: {integrity: sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg==} + dependencies: + '@babel/parser': 7.23.4 + '@babel/types': 7.23.4 + source-map-js: 1.0.2 + dev: true + /make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.3.0 + semver: 6.3.1 + + /make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 /make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} @@ -16428,6 +17574,7 @@ packages: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} dependencies: tmpl: 1.0.5 + dev: false /map-age-cleaner@0.1.3: resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} @@ -16473,6 +17620,14 @@ packages: engines: {node: '>= 12'} hasBin: true + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + /md5@2.3.0: resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} dependencies: @@ -16613,6 +17768,20 @@ packages: fs-monkey: 1.0.4 dev: false + /memfs@4.6.0(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.0): + resolution: {integrity: sha512-I6mhA1//KEZfKRQT9LujyW6lRbX7RkC24xKododIDO3AGShcaFAMKElv1yFGWX8fD4UaSiwasr3NeQ5TdtHY1A==} + engines: {node: '>= 4.0.0'} + peerDependencies: + tslib: '2' + dependencies: + json-joy: 9.9.1(quill-delta@5.1.0)(rxjs@7.8.1)(tslib@2.6.0) + thingies: 1.15.0(tslib@2.6.0) + tslib: 2.6.0 + transitivePeerDependencies: + - quill-delta + - rxjs + dev: true + /memorystream@0.3.1: resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} @@ -16742,6 +17911,14 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + dev: true + /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -16767,6 +17944,16 @@ packages: engines: {node: '>=12'} dev: true + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: true + + /mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} @@ -16783,11 +17970,10 @@ packages: /minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - dev: false /minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - dev: false + dev: true /minimatch@3.0.5: resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==} @@ -16812,7 +17998,13 @@ packages: engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 - dev: false + + /minimatch@6.2.0: + resolution: {integrity: sha512-sauLxniAmvnhhRjFwPNnJKaPFYyddAgbYdeUpHULtCT/GhzdCx/MDNy+Y40lBxTQUrMzDE8e0S43Z5uqfO0REg==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true /minimatch@9.0.2: resolution: {integrity: sha512-PZOT9g5v2ojiTL7r1xF6plNHLtOeTpSlDI007As2NlA2aYBMfVom17yqa6QzhmDP8QOhn7LjHTg7DFCVSSa6yg==} @@ -16842,11 +18034,19 @@ packages: resolution: {integrity: sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==} engines: {node: '>=16 || 14 >=14.17'} + /mitt@3.0.0: + resolution: {integrity: sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==} + dev: true + /mixme@0.5.9: resolution: {integrity: sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==} engines: {node: '>= 8.0.0'} dev: true + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: true + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -16858,6 +18058,20 @@ packages: engines: {node: '>=10'} hasBin: true + /mlly@1.4.2: + resolution: {integrity: sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==} + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.0.3 + ufo: 1.3.2 + dev: true + + /mrmime@2.0.0: + resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} + engines: {node: '>=10'} + dev: true + /ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: false @@ -16887,6 +18101,10 @@ packages: object-assign: 4.1.1 thenify-all: 1.6.0 + /n12@1.8.10: + resolution: {integrity: sha512-/iREutgBDWCLwSqVOTKyAXRfToeY8Y9PmFPk3egwWVf6UYUyL9UXIaVnEkW4mx+g3dBGBywfvWilfKFEkiGK+A==} + dev: true + /nanoclone@0.2.1: resolution: {integrity: sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==} dev: false @@ -16896,6 +18114,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -16911,6 +18135,11 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: false + /netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + dev: true + /next@13.4.4(@babel/core@7.23.3)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-C5S0ysM0Ily9McL4Jb48nOQHT1BukOWI59uC3X/xCMlYIh9rJZCv7nzG92J6e1cOBqQbKovlpgvHWFmz4eKKEA==} engines: {node: '>=16.8.0'} @@ -17030,6 +18259,15 @@ packages: dependencies: whatwg-url: 5.0.0 + /node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + dev: true + /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -17038,12 +18276,52 @@ packages: /node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + /node-preload@0.2.1: + resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} + engines: {node: '>=8'} + dependencies: + process-on-spawn: 1.0.0 + dev: true + /node-releases@2.0.12: resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + /node-stdlib-browser@1.2.0: + resolution: {integrity: sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==} + engines: {node: '>=10'} + dependencies: + assert: 2.1.0 + browser-resolve: 2.0.0 + browserify-zlib: 0.2.0 + buffer: 5.7.1 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + create-require: 1.1.1 + crypto-browserify: 3.12.0 + domain-browser: 4.23.0 + events: 3.3.0 + https-browserify: 1.0.0 + isomorphic-timers-promises: 1.0.1 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + pkg-dir: 5.0.0 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + readable-stream: 3.6.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.3 + util: 0.12.5 + vm-browserify: 1.1.2 + dev: true + /nodemon@2.0.22: resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} engines: {node: '>=8.10.0'} @@ -17097,13 +18375,10 @@ packages: engines: {node: '>=10'} dev: false - /npm-path@2.0.4: - resolution: {integrity: sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==} - engines: {node: '>=0.8'} - hasBin: true - dependencies: - which: 1.3.1 - dev: false + /normalize-url@8.0.0: + resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==} + engines: {node: '>=14.16'} + dev: true /npm-run-all@4.1.5: resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==} @@ -17134,16 +18409,6 @@ packages: path-key: 4.0.0 dev: true - /npm-which@3.0.1: - resolution: {integrity: sha512-CM8vMpeFQ7MAPin0U3wzDhSGV0hMHNwHU0wjo402IVizPDrs45jSfSuoC+wThevY88LQti8VvaAnqYAeVy3I1A==} - engines: {node: '>=4.2.0'} - hasBin: true - dependencies: - commander: 2.20.3 - npm-path: 2.0.4 - which: 1.3.1 - dev: false - /nth-check@1.0.2: resolution: {integrity: sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==} dependencies: @@ -17164,6 +18429,42 @@ packages: resolution: {integrity: sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==} dev: false + /nyc@15.1.0: + resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==} + engines: {node: '>=8.9'} + hasBin: true + dependencies: + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + caching-transform: 4.0.0 + convert-source-map: 1.9.0 + decamelize: 1.2.0 + find-cache-dir: 3.3.2 + find-up: 4.1.0 + foreground-child: 2.0.0 + get-package-type: 0.1.0 + glob: 7.2.3 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-hook: 3.0.0 + istanbul-lib-instrument: 4.0.3 + istanbul-lib-processinfo: 2.0.3 + istanbul-lib-report: 3.0.0 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.5 + make-dir: 3.1.0 + node-preload: 0.2.1 + p-map: 3.0.0 + process-on-spawn: 1.0.0 + resolve-from: 5.0.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + spawn-wrap: 2.0.0 + test-exclude: 6.0.0 + yargs: 15.4.1 + transitivePeerDependencies: + - supports-color + dev: true + /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -17185,7 +18486,6 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 - dev: false /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} @@ -17358,6 +18658,10 @@ packages: wcwidth: 1.0.1 dev: true + /os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + dev: true + /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -17367,6 +18671,11 @@ packages: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} dev: true + /p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + dev: true + /p-defer@1.0.0: resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} engines: {node: '>=4'} @@ -17408,6 +18717,13 @@ packages: dependencies: yocto-queue: 0.1.0 + /p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + dependencies: + yocto-queue: 1.0.0 + dev: true + /p-locate@2.0.0: resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} @@ -17439,6 +18755,13 @@ packages: engines: {node: '>=6'} dev: true + /p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + dependencies: + aggregate-error: 3.1.0 + dev: true + /p-map@4.0.0: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} @@ -17486,6 +18809,45 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + /pac-proxy-agent@7.0.1: + resolution: {integrity: sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==} + engines: {node: '>= 14'} + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.0 + debug: 4.3.4 + get-uri: 6.0.2 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + pac-resolver: 7.0.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /pac-resolver@7.0.0: + resolution: {integrity: sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==} + engines: {node: '>= 14'} + dependencies: + degenerator: 5.0.1 + ip: 1.1.8 + netmask: 2.0.2 + dev: true + + /package-hash@4.0.0: + resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==} + engines: {node: '>=8'} + dependencies: + graceful-fs: 4.2.11 + hasha: 5.2.2 + lodash.flattendeep: 4.4.0 + release-zalgo: 1.0.0 + dev: true + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + /param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: @@ -17498,6 +18860,16 @@ packages: dependencies: callsites: 3.1.0 + /parse-asn1@5.1.6: + resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==} + dependencies: + asn1.js: 5.4.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 + dev: true + /parse-entities@2.0.0: resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} dependencies: @@ -17557,6 +18929,10 @@ packages: no-case: 3.0.4 tslib: 2.6.0 + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + /path-case@3.0.4: resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} dependencies: @@ -17640,6 +19016,29 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true + + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: true + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: false @@ -17697,6 +19096,21 @@ packages: dependencies: find-up: 4.1.0 + /pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + dependencies: + find-up: 5.0.0 + dev: true + + /pkg-types@1.0.3: + resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + dependencies: + jsonc-parser: 3.2.0 + mlly: 1.4.2 + pathe: 1.1.2 + dev: true + /pkg-up@3.1.0: resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} engines: {node: '>=8'} @@ -17713,7 +19127,7 @@ packages: engines: {node: '>= 0.12.0'} dependencies: async: 2.6.4 - debug: 3.2.7(supports-color@5.5.0) + debug: 3.2.7 mkdirp: 0.5.6 transitivePeerDependencies: - supports-color @@ -17740,12 +19154,12 @@ packages: postcss: 8.4.24 dev: false - /postcss-calc@8.2.4(postcss@8.4.24): + /postcss-calc@8.2.4(postcss@8.4.31): resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} peerDependencies: postcss: ^8.2.2 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 dev: false @@ -17790,7 +19204,7 @@ packages: postcss-value-parser: 4.2.0 dev: false - /postcss-colormin@5.3.1(postcss@8.4.24): + /postcss-colormin@5.3.1(postcss@8.4.31): resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -17799,18 +19213,18 @@ packages: browserslist: 4.22.1 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-convert-values@5.1.3(postcss@8.4.24): + /postcss-convert-values@5.1.3(postcss@8.4.31): resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: browserslist: 4.22.1 - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false @@ -17854,40 +19268,40 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /postcss-discard-comments@5.1.2(postcss@8.4.24): + /postcss-discard-comments@5.1.2(postcss@8.4.31): resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-discard-duplicates@5.1.0(postcss@8.4.24): + /postcss-discard-duplicates@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-discard-empty@5.1.1(postcss@8.4.24): + /postcss-discard-empty@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-discard-overridden@5.1.0(postcss@8.4.24): + /postcss-discard-overridden@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false /postcss-double-position-gradients@3.1.2(postcss@8.4.24): @@ -18069,18 +19483,18 @@ packages: postcss: 8.4.24 dev: false - /postcss-merge-longhand@5.1.7(postcss@8.4.24): + /postcss-merge-longhand@5.1.7(postcss@8.4.31): resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 - stylehacks: 5.1.1(postcss@8.4.24) + stylehacks: 5.1.1(postcss@8.4.31) dev: false - /postcss-merge-rules@5.1.4(postcss@8.4.24): + /postcss-merge-rules@5.1.4(postcss@8.4.31): resolution: {integrity: sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -18088,94 +19502,94 @@ packages: dependencies: browserslist: 4.22.1 caniuse-api: 3.0.0 - cssnano-utils: 3.1.0(postcss@8.4.24) - postcss: 8.4.24 + cssnano-utils: 3.1.0(postcss@8.4.31) + postcss: 8.4.31 postcss-selector-parser: 6.0.13 dev: false - /postcss-minify-font-values@5.1.0(postcss@8.4.24): + /postcss-minify-font-values@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-gradients@5.1.1(postcss@8.4.24): + /postcss-minify-gradients@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: colord: 2.9.3 - cssnano-utils: 3.1.0(postcss@8.4.24) - postcss: 8.4.24 + cssnano-utils: 3.1.0(postcss@8.4.31) + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-params@5.1.4(postcss@8.4.24): + /postcss-minify-params@5.1.4(postcss@8.4.31): resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: browserslist: 4.22.1 - cssnano-utils: 3.1.0(postcss@8.4.24) - postcss: 8.4.24 + cssnano-utils: 3.1.0(postcss@8.4.31) + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-minify-selectors@5.2.1(postcss@8.4.24): + /postcss-minify-selectors@5.2.1(postcss@8.4.31): resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-selector-parser: 6.0.13 dev: false - /postcss-modules-extract-imports@3.0.0(postcss@8.4.24): + /postcss-modules-extract-imports@3.0.0(postcss@8.4.31): resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-modules-local-by-default@4.0.3(postcss@8.4.24): + /postcss-modules-local-by-default@4.0.3(postcss@8.4.31): resolution: {integrity: sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.24) - postcss: 8.4.24 + icss-utils: 5.1.0(postcss@8.4.31) + postcss: 8.4.31 postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 dev: false - /postcss-modules-scope@3.0.0(postcss@8.4.24): + /postcss-modules-scope@3.0.0(postcss@8.4.31): resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-selector-parser: 6.0.13 dev: false - /postcss-modules-values@4.0.0(postcss@8.4.24): + /postcss-modules-values@4.0.0(postcss@8.4.31): resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.24) - postcss: 8.4.24 + icss-utils: 5.1.0(postcss@8.4.31) + postcss: 8.4.31 dev: false /postcss-nested@6.0.1(postcss@8.4.24): @@ -18198,94 +19612,94 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /postcss-normalize-charset@5.1.0(postcss@8.4.24): + /postcss-normalize-charset@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-normalize-display-values@5.1.0(postcss@8.4.24): + /postcss-normalize-display-values@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-positions@5.1.1(postcss@8.4.24): + /postcss-normalize-positions@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-repeat-style@5.1.1(postcss@8.4.24): + /postcss-normalize-repeat-style@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-string@5.1.0(postcss@8.4.24): + /postcss-normalize-string@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-timing-functions@5.1.0(postcss@8.4.24): + /postcss-normalize-timing-functions@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-unicode@5.1.1(postcss@8.4.24): + /postcss-normalize-unicode@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: browserslist: 4.22.1 - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-url@5.1.0(postcss@8.4.24): + /postcss-normalize-url@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: normalize-url: 6.1.0 - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false - /postcss-normalize-whitespace@5.1.1(postcss@8.4.24): + /postcss-normalize-whitespace@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false @@ -18312,14 +19726,14 @@ packages: postcss: 8.4.24 dev: false - /postcss-ordered-values@5.1.3(postcss@8.4.24): + /postcss-ordered-values@5.1.3(postcss@8.4.31): resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - cssnano-utils: 3.1.0(postcss@8.4.24) - postcss: 8.4.24 + cssnano-utils: 3.1.0(postcss@8.4.31) + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false @@ -18419,7 +19833,7 @@ packages: postcss-selector-parser: 6.0.13 dev: false - /postcss-reduce-initial@5.1.2(postcss@8.4.24): + /postcss-reduce-initial@5.1.2(postcss@8.4.31): resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: @@ -18427,16 +19841,16 @@ packages: dependencies: browserslist: 4.22.1 caniuse-api: 3.0.0 - postcss: 8.4.24 + postcss: 8.4.31 dev: false - /postcss-reduce-transforms@5.1.0(postcss@8.4.24): + /postcss-reduce-transforms@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 dev: false @@ -18465,24 +19879,24 @@ packages: cssesc: 3.0.0 util-deprecate: 1.0.2 - /postcss-svgo@5.1.0(postcss@8.4.24): + /postcss-svgo@5.1.0(postcss@8.4.31): resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-value-parser: 4.2.0 svgo: 2.8.0 dev: false - /postcss-unique-selectors@5.1.1(postcss@8.4.24): + /postcss-unique-selectors@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.24 + postcss: 8.4.31 postcss-selector-parser: 6.0.13 dev: false @@ -18523,6 +19937,15 @@ packages: source-map-js: 1.0.2 dev: false + /postcss@8.4.33: + resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /preact@10.15.1: resolution: {integrity: sha512-qs2ansoQEwzNiV5eAcRT1p1EC/dmEzaATVDJNiB3g2sRDWdA7b7MurXdJjB2+/WQktGWZwxvDrnuRFbWuIr64g==} dev: true @@ -18602,6 +20025,7 @@ packages: '@jest/schemas': 29.4.3 ansi-styles: 5.2.0 react-is: 18.2.0 + dev: false /pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -18614,7 +20038,23 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - dev: false + + /process-on-spawn@1.0.0: + resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==} + engines: {node: '>=8'} + dependencies: + fromentries: 1.3.2 + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true /promise@7.3.1: resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==} @@ -18634,6 +20074,7 @@ packages: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 + dev: false /prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -18654,6 +20095,42 @@ packages: ipaddr.js: 1.9.1 dev: false + /proxy-agent@6.3.0: + resolution: {integrity: sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /proxy-agent@6.3.1: + resolution: {integrity: sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + http-proxy-agent: 7.0.0 + https-proxy-agent: 7.0.2 + lru-cache: 7.18.3 + pac-proxy-agent: 7.0.1 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.2 + transitivePeerDependencies: + - supports-color + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true + /pseudomap@1.0.2: resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} dev: true @@ -18666,6 +20143,24 @@ packages: resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} dev: true + /public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + parse-asn1: 5.1.6 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + /punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} dev: true @@ -18674,8 +20169,27 @@ packages: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} - /pure-rand@6.0.2: - resolution: {integrity: sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==} + /puppeteer-core@20.9.0(typescript@5.2.2): + resolution: {integrity: sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==} + engines: {node: '>=16.3.0'} + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@puppeteer/browsers': 1.4.6(typescript@5.2.2) + chromium-bidi: 0.4.16(devtools-protocol@0.0.1147663) + cross-fetch: 4.0.0 + debug: 4.3.4 + devtools-protocol: 0.0.1147663 + typescript: 5.2.2 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate dev: true /pvtsutils@1.3.2: @@ -18700,6 +20214,22 @@ packages: side-channel: 1.0.4 dev: false + /qs@6.11.2: + resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + dev: true + + /querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + dev: true + /querystringify@2.2.0: resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} dev: false @@ -18707,11 +20237,29 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: true + /quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} dev: true + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /quill-delta@5.1.0: + resolution: {integrity: sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==} + engines: {node: '>= 12.0.0'} + dependencies: + fast-diff: 1.3.0 + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + dev: true + /raf@3.4.1: resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} dependencies: @@ -18726,7 +20274,13 @@ packages: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 - dev: false + + /randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: true /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} @@ -19179,7 +20733,6 @@ packages: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 - dev: false /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} @@ -19189,6 +20742,12 @@ packages: string_decoder: 1.3.0 util-deprecate: 1.0.2 + /readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + dependencies: + minimatch: 5.1.6 + dev: true + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -19300,6 +20859,13 @@ packages: - encoding dev: true + /release-zalgo@1.0.0: + resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} + engines: {node: '>=4'} + dependencies: + es6-error: 4.1.1 + dev: true + /remark-footnotes@3.0.0: resolution: {integrity: sha512-ZssAvH9FjGYlJ/PBVKdSmfyPc3Cz4rTWgZLI4iE/SX8Nt5l3o3oEjv3wwG5VD7xOjktzdwp5coac+kJV9l4jgg==} dependencies: @@ -19386,11 +20952,16 @@ packages: resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} dev: false + /resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: true + /resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} dependencies: resolve-from: 5.0.0 + dev: false /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} @@ -19428,11 +20999,6 @@ packages: engines: {node: '>=10'} dev: false - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - dev: true - /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: @@ -19464,6 +21030,19 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + dependencies: + lowercase-keys: 3.0.0 + dev: true + + /resq@1.11.0: + resolution: {integrity: sha512-G10EBz+zAAy3zUd/CDoBbXRL6ia9kOo3xRHrMDsHljI0GDkhYlyjwoCx5+3eCC4swi1uCoZQhskuJkj7Gp57Bw==} + dependencies: + fast-deep-equal: 2.0.1 + dev: true + /restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -19485,6 +21064,10 @@ packages: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} dev: true + /rgb2hex@0.2.5: + resolution: {integrity: sha512-22MOP1Rh7sAo1BZpDG6R5RFYzR2lYEgwq7HEmyW2qcsOqR2lQKmn+O//xV3YG/0rrhMC6KVX2hU+ZXuaw9a5bw==} + dev: true + /rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} hasBin: true @@ -19498,6 +21081,13 @@ packages: dependencies: glob: 7.2.3 + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + dev: true + /rollup-plugin-terser@7.0.2(rollup@2.79.1): resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==} deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser @@ -19527,6 +21117,29 @@ packages: fsevents: 2.3.3 dev: true + /rollup@4.9.4: + resolution: {integrity: sha512-2ztU7pY/lrQyXSCnnoU4ICjT/tCG9cdH3/G25ERqE3Lst6vl2BCM5hL2Nw+sslAvAf+ccKsAq1SkKQALyqhR7g==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.9.4 + '@rollup/rollup-android-arm64': 4.9.4 + '@rollup/rollup-darwin-arm64': 4.9.4 + '@rollup/rollup-darwin-x64': 4.9.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.9.4 + '@rollup/rollup-linux-arm64-gnu': 4.9.4 + '@rollup/rollup-linux-arm64-musl': 4.9.4 + '@rollup/rollup-linux-riscv64-gnu': 4.9.4 + '@rollup/rollup-linux-x64-gnu': 4.9.4 + '@rollup/rollup-linux-x64-musl': 4.9.4 + '@rollup/rollup-win32-arm64-msvc': 4.9.4 + '@rollup/rollup-win32-ia32-msvc': 4.9.4 + '@rollup/rollup-win32-x64-msvc': 4.9.4 + fsevents: 2.3.3 + dev: true + /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -19550,6 +21163,10 @@ packages: tslib: 2.6.0 dev: true + /safaridriver@0.1.2: + resolution: {integrity: sha512-4R309+gWflJktzPXBQCobbWEHlzC4aK3a+Ov3tz2Ib2aBxiwd11phkdIBH1l0EO22x24CJMUQkpKFumRriCSRg==} + dev: true + /safe-array-concat@1.0.0: resolution: {integrity: sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==} engines: {node: '>=0.4'} @@ -19572,7 +21189,6 @@ packages: /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - dev: false /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -19757,6 +21373,13 @@ packages: upper-case-first: 2.0.2 dev: true + /serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + dependencies: + type-fest: 2.19.0 + dev: true + /serialize-javascript@4.0.0: resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} dependencies: @@ -19831,6 +21454,14 @@ packages: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: false + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: true + /shebang-command@1.2.0: resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} @@ -19871,6 +21502,10 @@ packages: get-intrinsic: 1.2.1 object-inspect: 1.12.3 + /siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + dev: true + /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -19878,6 +21513,11 @@ packages: resolution: {integrity: sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==} engines: {node: '>=14'} + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + /signedsource@1.0.0: resolution: {integrity: sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==} dev: true @@ -19889,8 +21529,18 @@ packages: semver: 7.0.0 dev: true + /sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.24 + mrmime: 2.0.0 + totalist: 3.0.1 + dev: true + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: false /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} @@ -19919,6 +21569,11 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true + /smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + dev: true + /smartwrap@2.0.2: resolution: {integrity: sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==} engines: {node: '>=6'} @@ -19947,6 +21602,25 @@ packages: websocket-driver: 0.7.4 dev: false + /socks-proxy-agent@8.0.2: + resolution: {integrity: sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.0 + debug: 4.3.4 + socks: 2.7.1 + transitivePeerDependencies: + - supports-color + dev: true + + /socks@2.7.1: + resolution: {integrity: sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==} + engines: {node: '>= 10.13.0', npm: '>= 3.0.0'} + dependencies: + ip: 2.0.0 + smart-buffer: 4.2.0 + dev: true + /source-list-map@2.0.1: resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} dev: false @@ -19967,18 +21641,12 @@ packages: webpack: 5.88.0(esbuild@0.17.19) dev: false - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - /source-map-support@0.5.21: resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + dev: false /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} @@ -19999,6 +21667,18 @@ packages: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead + /spawn-wrap@2.0.0: + resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + engines: {node: '>=8'} + dependencies: + foreground-child: 2.0.0 + is-windows: 1.0.2 + make-dir: 3.1.0 + rimraf: 3.0.2 + signal-exit: 3.0.7 + which: 2.0.2 + dev: true + /spawndamnit@2.0.0: resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} dependencies: @@ -20054,6 +21734,11 @@ packages: - supports-color dev: false + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: true + /sponge-case@1.0.1: resolution: {integrity: sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==} dependencies: @@ -20073,6 +21758,11 @@ packages: engines: {node: '>=10'} dependencies: escape-string-regexp: 2.0.0 + dev: false + + /stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + dev: true /stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -20088,6 +21778,10 @@ packages: engines: {node: '>= 0.8'} dev: false + /std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + dev: true + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -20095,6 +21789,22 @@ packages: internal-slot: 1.0.5 dev: false + /stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: true + + /stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + dev: true + /stream-transform@2.1.3: resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} dependencies: @@ -20105,6 +21815,13 @@ packages: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} + /streamx@2.15.6: + resolution: {integrity: sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + dev: true + /string-env-interpolation@1.0.1: resolution: {integrity: sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==} dev: true @@ -20115,6 +21832,7 @@ packages: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 + dev: false /string-length@5.0.1: resolution: {integrity: sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==} @@ -20216,7 +21934,6 @@ packages: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: safe-buffer: 5.1.2 - dev: false /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -20283,6 +22000,12 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + /strip-literal@1.3.0: + resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==} + dependencies: + acorn: 8.11.3 + dev: true + /structured-source@4.0.0: resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==} dependencies: @@ -20316,14 +22039,14 @@ packages: react: 18.2.0 dev: false - /stylehacks@5.1.1(postcss@8.4.24): + /stylehacks@5.1.1(postcss@8.4.31): resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: browserslist: 4.22.1 - postcss: 8.4.24 + postcss: 8.4.31 postcss-selector-parser: 6.0.13 dev: false @@ -20357,6 +22080,7 @@ packages: engines: {node: '>=10'} dependencies: has-flag: 4.0.0 + dev: false /supports-hyperlinks@2.3.0: resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} @@ -20500,6 +22224,22 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + /tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} + dependencies: + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 3.1.6 + dev: true + + /tar-stream@3.1.6: + resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} + dependencies: + b4a: 1.6.4 + fast-fifo: 1.3.2 + streamx: 2.15.6 + dev: true + /temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} engines: {node: '>=8'} @@ -20651,6 +22391,15 @@ packages: dependencies: any-promise: 1.3.0 + /thingies@1.15.0(tslib@2.6.0): + resolution: {integrity: sha512-ZSJlvEpD8QllYim0VSGlbAoob/iPrTWNlV/m8ltizMvMmzzU2gVJvHfH9ijLstyciWF70ZiQXqz+BCXWJq+ZQw==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + dependencies: + tslib: 2.6.0 + dev: true + /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} dev: false @@ -20663,6 +22412,27 @@ packages: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} dev: false + /timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + dependencies: + setimmediate: 1.0.5 + dev: true + + /tinybench@2.5.1: + resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} + dev: true + + /tinypool@0.8.1: + resolution: {integrity: sha512-zBTCK0cCgRROxvs9c0CGK838sPkeokNGdQVUUwHAbynHFlmyJYj825f/oRs528HaIJ97lo0pLIlDUzwN+IorWg==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy@2.2.0: + resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==} + engines: {node: '>=14.0.0'} + dev: true + /title-case@3.0.3: resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==} dependencies: @@ -20683,6 +22453,7 @@ packages: /tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: false /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} @@ -20711,6 +22482,11 @@ packages: resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} dev: false + /totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + dev: true + /touch@3.1.0: resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} hasBin: true @@ -20743,6 +22519,10 @@ packages: punycode: 2.3.0 dev: false + /traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + dev: true + /traverse@0.6.7: resolution: {integrity: sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==} dev: true @@ -20778,63 +22558,27 @@ packages: dev: true /ts-essentials@1.0.4: - resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} - dev: true - - /ts-generator@0.1.1: - resolution: {integrity: sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ==} - hasBin: true - dependencies: - '@types/mkdirp': 0.5.2 - '@types/prettier': 2.7.3 - '@types/resolve': 0.0.8 - chalk: 2.4.2 - glob: 7.2.3 - mkdirp: 0.5.6 - prettier: 2.8.8 - resolve: 1.22.2 - ts-essentials: 1.0.4 - dev: true - - /ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - - /ts-jest@29.1.1(@babel/core@7.23.3)(@jest/types@29.5.0)(esbuild@0.17.19)(jest@29.7.0)(typescript@5.2.2): - resolution: {integrity: sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true - dependencies: - '@babel/core': 7.23.3 - '@jest/types': 29.5.0 - bs-logger: 0.2.6 - esbuild: 0.17.19 - fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@18.15.3) - jest-util: 29.5.0 - json5: 2.2.3 - lodash.memoize: 4.1.2 - make-error: 1.3.6 - semver: 7.5.4 - typescript: 5.2.2 - yargs-parser: 21.1.1 + resolution: {integrity: sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ==} + dev: true + + /ts-generator@0.1.1: + resolution: {integrity: sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ==} + hasBin: true + dependencies: + '@types/mkdirp': 0.5.2 + '@types/prettier': 2.7.3 + '@types/resolve': 0.0.8 + chalk: 2.4.2 + glob: 7.2.3 + mkdirp: 0.5.6 + prettier: 2.8.8 + resolve: 1.22.2 + ts-essentials: 1.0.4 dev: true + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + /ts-log@2.2.5: resolution: {integrity: sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==} dev: true @@ -20887,6 +22631,7 @@ packages: /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + dev: false /tslib@2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} @@ -20940,17 +22685,21 @@ packages: tslib: 1.14.1 typescript: 5.2.2 - /tsx@3.12.7: - resolution: {integrity: sha512-C2Ip+jPmqKd1GWVQDvz/Eyc6QJbGfE7NrR3fx5BpEHMZsEHoIxHL1j+lKdGobr8ovEyqeNkPLSKp6SCSOt7gmw==} + /tsx@4.7.0: + resolution: {integrity: sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==} + engines: {node: '>=18.0.0'} hasBin: true dependencies: - '@esbuild-kit/cjs-loader': 2.4.2 - '@esbuild-kit/core-utils': 3.1.0 - '@esbuild-kit/esm-loader': 2.5.5 + esbuild: 0.19.11 + get-tsconfig: 4.7.2 optionalDependencies: fsevents: 2.3.3 dev: true + /tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + dev: true + /tty-table@4.2.1: resolution: {integrity: sha512-xz0uKo+KakCQ+Dxj1D/tKn2FSyreSYWzdkL/BYhgN6oMW808g8QRMuh1atAV9fjTPbWBjfbkKQpI/5rEcnAc7g==} engines: {node: '>=8.0.0'} @@ -21071,6 +22820,16 @@ packages: engines: {node: '>=8'} dev: true + /type-fest@2.13.0: + resolution: {integrity: sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw==} + engines: {node: '>=12.20'} + dev: true + + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + /type-fest@3.1.0: resolution: {integrity: sha512-StmrZmK3eD9mDF9Vt7UhqthrDSk66O9iYl5t5a0TSoVkHjl0XZx/xuc/BRz4urAXXGHOY5OLsE0RdJFIApSFmw==} engines: {node: '>=14.16'} @@ -21125,7 +22884,6 @@ packages: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} dependencies: is-typedarray: 1.0.0 - dev: false /typedoc-plugin-markdown@3.15.3(typedoc@0.25.3): resolution: {integrity: sha512-idntFYu3vfaY3eaD+w9DeRd0PmNGqGuNLKihPU9poxFGnATJYGn9dPtEhn2QrTdishFMg7jPXAhos+2T6YCWRQ==} @@ -21176,6 +22934,10 @@ packages: resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} dev: true + /ufo@1.3.2: + resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} + dev: true + /uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} @@ -21192,6 +22954,13 @@ packages: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 + /unbzip2-stream@1.4.3: + resolution: {integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==} + dependencies: + buffer: 5.7.1 + through: 2.3.8 + dev: true + /unc-path-regex@0.1.2: resolution: {integrity: sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==} engines: {node: '>=0.10.0'} @@ -21203,7 +22972,6 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true /undici@5.22.1: resolution: {integrity: sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw==} @@ -21319,6 +23087,21 @@ packages: engines: {node: '>=8'} dev: true + /unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + dependencies: + big-integer: 1.6.51 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + listenercount: 1.0.1 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + dev: true + /upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} @@ -21368,6 +23151,13 @@ packages: requires-port: 1.0.0 dev: false + /url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + dependencies: + punycode: 1.4.1 + qs: 6.11.2 + dev: true + /urlpattern-polyfill@8.0.2: resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} dev: true @@ -21424,6 +23214,11 @@ packages: react: 18.2.0 dev: false + /userhome@1.0.0: + resolution: {integrity: sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig==} + engines: {node: '>= 0.8.0'} + dev: true + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -21436,6 +23231,16 @@ packages: object.getownpropertydescriptors: 2.1.6 dev: false + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.12 + which-typed-array: 1.1.13 + dev: true + /utila@0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} dev: false @@ -21445,16 +23250,9 @@ packages: engines: {node: '>= 0.4.0'} dev: false - /uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true - dev: true - /uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - dev: false /uuid@9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} @@ -21474,15 +23272,6 @@ packages: source-map: 0.7.4 dev: false - /v8-to-istanbul@9.1.0: - resolution: {integrity: sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==} - engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.18 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.9.0 - dev: true - /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -21516,6 +23305,81 @@ packages: vfile-message: 2.0.4 dev: true + /vite-node@1.1.3(@types/node@18.15.3): + resolution: {integrity: sha512-BLSO72YAkIUuNrOx+8uznYICJfTEbvBAmWClY3hpath5+h1mbPS5OMn42lrTxXuyCazVyZoDkSRnju78GiVCqA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.0 + vite: 5.0.11(@types/node@18.15.3) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vite-plugin-node-polyfills@0.17.0(vite@5.0.11): + resolution: {integrity: sha512-iPmPn7376e5u6QvoTSJa16hf5Q0DFwHFXJk2uYpsNlmI3JdPms7hWyh55o+OysJ5jo9J5XPhLC9sMOYifwFd1w==} + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + dependencies: + '@rollup/plugin-inject': 5.0.5 + buffer-polyfill: /buffer@6.0.3 + node-stdlib-browser: 1.2.0 + process: 0.11.10 + vite: 5.0.11(@types/node@18.15.3) + transitivePeerDependencies: + - rollup + dev: true + + /vite-plugin-plain-text@1.4.2: + resolution: {integrity: sha512-nkCWW16lkTidaGZ9kItwMZ5OEkUeXMrY4Okc9IQXrN/p6SAuDYmEiGqMRKl1rnhm6CR1h98uJtn+ODkv0cL7DA==} + dependencies: + '@napi-rs/magic-string': 0.3.4 + fast-glob: 3.3.1 + minimatch: 6.2.0 + dev: true + + /vite@4.3.9: + resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.17.19 + postcss: 8.4.24 + rollup: 3.25.3 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /vite@4.3.9(@types/node@18.15.3): resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} engines: {node: ^14.18.0 || >=16.0.0} @@ -21549,6 +23413,42 @@ packages: fsevents: 2.3.3 dev: true + /vite@5.0.11(@types/node@18.15.3): + resolution: {integrity: sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 18.15.3 + esbuild: 0.19.11 + postcss: 8.4.33 + rollup: 4.9.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /vitepress-plugin-search@1.0.4-alpha.19(flexsearch@0.7.31)(vitepress@1.0.0-alpha.51)(vue@3.2.47): resolution: {integrity: sha512-WFOPn5dStyMINd+rVjNxbEmGa7U+qGHLxLnda56EG+ATil1i0yOauGhJEh5LPMvuCUVIA9tInJnFXklOBb39dA==} engines: {node: ^14.13.1 || ^16.7.0 || >=18} @@ -21593,6 +23493,68 @@ packages: - terser dev: true + /vitest@1.1.3(@types/node@18.15.3)(@vitest/browser@1.1.3): + resolution: {integrity: sha512-2l8om1NOkiA90/Y207PsEvJLYygddsOyr81wLQ20Ra8IlLKbyQncWsGZjnbkyG2KwwuTXLQjEPOJuxGMG8qJBQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': ^1.0.0 + '@vitest/ui': ^1.0.0 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/node': 18.15.3 + '@vitest/browser': 1.1.3(vitest@1.1.3)(webdriverio@8.27.2) + '@vitest/expect': 1.1.3 + '@vitest/runner': 1.1.3 + '@vitest/snapshot': 1.1.3 + '@vitest/spy': 1.1.3 + '@vitest/utils': 1.1.3 + acorn-walk: 8.3.2 + cac: 6.7.14 + chai: 4.4.0 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.5 + pathe: 1.1.2 + picocolors: 1.0.0 + std-env: 3.7.0 + strip-literal: 1.3.0 + tinybench: 2.5.1 + tinypool: 0.8.1 + vite: 5.0.11(@types/node@18.15.3) + vite-node: 1.1.3(@types/node@18.15.3) + why-is-node-running: 2.2.2 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + dev: true + + /vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + dev: true + /vscode-oniguruma@1.7.0: resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} @@ -21638,10 +23600,23 @@ packages: xml-name-validator: 3.0.0 dev: false + /wait-port@1.1.0: + resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} + engines: {node: '>=10'} + hasBin: true + dependencies: + chalk: 4.1.2 + commander: 9.4.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} dependencies: makeerror: 1.0.12 + dev: false /watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} @@ -21687,6 +23662,68 @@ packages: tslib: 2.6.0 dev: true + /webdriver@8.27.2: + resolution: {integrity: sha512-vY2Lr0ZNr83n0v8PjLCXtJwR9E7QGycJVS+ev2G72gI54/rFwLv58HMSbJNn8CtE27VkhtewMUPlDpSkj5wGPQ==} + engines: {node: ^16.13 || >=18} + dependencies: + '@types/node': 20.10.5 + '@types/ws': 8.5.5 + '@wdio/config': 8.27.2 + '@wdio/logger': 8.24.12 + '@wdio/protocols': 8.24.12 + '@wdio/types': 8.27.2 + '@wdio/utils': 8.27.2 + deepmerge-ts: 5.1.0 + got: 12.6.1 + ky: 0.33.3 + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /webdriverio@8.27.2(typescript@5.2.2): + resolution: {integrity: sha512-X6PhKE8e8XsB33Q/KSS1zYKP2Rqkq2Nef0YKOhQO+5OTlTkeqMCjnEtyRcfmdtfAwT0DEFqMnGnUKEbTajFC4Q==} + engines: {node: ^16.13 || >=18} + peerDependencies: + devtools: ^8.14.0 + peerDependenciesMeta: + devtools: + optional: true + dependencies: + '@types/node': 20.10.5 + '@wdio/config': 8.27.2 + '@wdio/logger': 8.24.12 + '@wdio/protocols': 8.24.12 + '@wdio/repl': 8.24.12 + '@wdio/types': 8.27.2 + '@wdio/utils': 8.27.2 + archiver: 6.0.1 + aria-query: 5.3.0 + css-shorthand-properties: 1.1.1 + css-value: 0.0.1 + devtools-protocol: 0.0.1239539 + grapheme-splitter: 1.0.4 + import-meta-resolve: 4.0.0 + is-plain-obj: 4.1.0 + lodash.clonedeep: 4.5.0 + lodash.zip: 4.2.0 + minimatch: 9.0.3 + puppeteer-core: 20.9.0(typescript@5.2.2) + query-selector-shadow-dom: 1.0.1 + resq: 1.11.0 + rgb2hex: 0.2.5 + serialize-error: 11.0.3 + webdriver: 8.27.2 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - typescript + - utf-8-validate + dev: true + /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -21971,6 +24008,23 @@ packages: dependencies: isexe: 2.0.0 + /which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + isexe: 3.1.1 + dev: true + + /why-is-node-running@2.2.2: + resolution: {integrity: sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + dev: true + /word-wrap@1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} @@ -22179,15 +24233,6 @@ packages: is-typedarray: 1.0.0 signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 - dev: false - - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true /write@1.0.3: resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} @@ -22232,6 +24277,7 @@ packages: optional: true utf-8-validate: optional: true + dev: false /xml-name-validator@3.0.0: resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} @@ -22245,6 +24291,11 @@ packages: resolution: {integrity: sha512-SH7nAaaPQx57dx6qvfcIgqKRXIh4L0A1iYEqim4s1u7c9VoCgzZc+63FY90AKU4ZzOC2cfJzTnpO4zK7fCUzzw==} dev: false + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true @@ -22323,6 +24374,19 @@ packages: yargs-parser: 20.2.9 dev: false + /yargs@17.7.1: + resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + /yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -22336,6 +24400,13 @@ packages: yargs-parser: 21.1.1 dev: true + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + /yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -22345,6 +24416,11 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true + /yup@0.32.11: resolution: {integrity: sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==} engines: {node: '>=10'} @@ -22358,6 +24434,15 @@ packages: toposort: 2.0.2 dev: false + /zip-stream@5.0.1: + resolution: {integrity: sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==} + engines: {node: '>= 12.0.0'} + dependencies: + archiver-utils: 4.0.1 + compress-commons: 5.0.1 + readable-stream: 3.6.2 + dev: true + /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false diff --git a/scripts/run-node.sh b/scripts/run-node.sh index 51257639cc..28749fd65d 100755 --- a/scripts/run-node.sh +++ b/scripts/run-node.sh @@ -5,6 +5,8 @@ mkdir -p .fuel-core/db +cp ./packages/utils/src/utils/chainConfig.json .fuel-core/configs/chainConfig.json + pnpm fuels-core run \ --db-path .fuel-core/db \ --consensus-key 0xa449b1ffee0e2205fa924c6740cc48b3b473aa28587df6dab12abc245d1f5298 \ diff --git a/scripts/ci-test.sh b/scripts/tests-ci.sh similarity index 68% rename from scripts/ci-test.sh rename to scripts/tests-ci.sh index d5a42af2d7..1ecfac1a74 100755 --- a/scripts/ci-test.sh +++ b/scripts/tests-ci.sh @@ -8,8 +8,11 @@ pnpm node:run > /dev/null 2>&1 & echo "Started Fuel-Core node in background." -if [[ "$*" == *"--coverage"* ]]; then - pnpm test $@ +if [[ "$*" == *"--browser"* ]]; then + pnpm test:browser + TEST_RESULT=$? +elif [[ "$*" == *"--node"* ]]; then + pnpm test TEST_RESULT=$? else pnpm test diff --git a/scripts/tests-coverage-diff.ts b/scripts/tests-coverage-diff.ts new file mode 100644 index 0000000000..68b0450d53 --- /dev/null +++ b/scripts/tests-coverage-diff.ts @@ -0,0 +1,27 @@ +import { diff as coverageDiff } from 'coverage-diff'; +import { readFileSync, writeFileSync } from 'fs'; + +const getDiff = () => { + const base = JSON.parse(readFileSync('coverage-master/coverage-summary.json').toString()); + const head = JSON.parse(readFileSync('coverage/report/coverage-summary.json').toString()); + return coverageDiff(base, head); +}; + +(() => { + const { results } = getDiff(); + const formattedResults = results.split(`${process.cwd()}/`).join(''); + const resultsSections = formattedResults.split('Total:'); + const report = ` + ***Coverage Report:*** + ${resultsSections[1]} + +
+ + Changed Files: + + ${resultsSections[0]} +
+ `; + + writeFileSync('coverage/report/coverage-diff.txt', report, { flag: 'w' }); +})(); diff --git a/scripts/tests-coverage-merge.ts b/scripts/tests-coverage-merge.ts new file mode 100644 index 0000000000..ce2a74aae8 --- /dev/null +++ b/scripts/tests-coverage-merge.ts @@ -0,0 +1,36 @@ +import { execSync } from 'child_process'; +import { readdirSync, renameSync, rmSync } from 'fs'; +import { join } from 'path'; + +const restructureCoverageDirectory = () => { + const coverageDir = join(__dirname, '../coverage/'); + const environmentsDir = join(coverageDir, '/environments/'); + const validEnvironments = ['node', 'browser']; + + const environments = readdirSync(environmentsDir); + environments.forEach((environment) => { + if (validEnvironments.includes(environment)) { + // Move environment coverage directories to a single file + renameSync( + join(environmentsDir, `${environment}/coverage-final.json`), + join(environmentsDir, `${environment}.json`) + ); + // Remove environment coverage directory + rmSync(join(environmentsDir, environment), { recursive: true, force: true }); + } + }); +}; + +(() => { + // Structure all coverage environment dirs into a single dir + restructureCoverageDirectory(); + + // Merge all coverage files + execSync('nyc merge coverage/environments coverage/merged/coverage.json', { stdio: 'inherit' }); + + // Generate coverage report + execSync( + 'nyc report --temp-dir=coverage/merged --report-dir=coverage/report --exclude-after-remap=false', + { stdio: 'inherit' } + ); +})(); diff --git a/scripts/tests-find.sh b/scripts/tests-find.sh new file mode 100755 index 0000000000..264d459b3c --- /dev/null +++ b/scripts/tests-find.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +ROOT=$(cd "$(dirname "$0")/.."; pwd) + +FILES=$(find $ROOT/{apps,packages,internal} -name '*.test.ts') + +if [[ $* == *--all* ]]; then + grep -lE "@group\s+(node|browser|e2e)" $FILES +elif [[ $* == *--node* ]]; then + grep -lE "@group\s+node" $FILES +elif [[ $* == *--browser* ]]; then + grep -lE "@group\s+browser" $FILES +elif [[ $* == *--e2e* ]]; then + grep -lE "@group\s+e2e" $FILES +fi \ No newline at end of file diff --git a/scripts/tests-validate.sh b/scripts/tests-validate.sh new file mode 100755 index 0000000000..74917d2fb8 --- /dev/null +++ b/scripts/tests-validate.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +ROOT=$(cd "$(dirname "$0")/.."; pwd) + +FILES=$(find $ROOT/{apps,packages,internal} -name '*.test.ts') +INVALID_FILES=$(grep -LE "@group\s+(node|browser|e2e)" $FILES) + +if [ ! -z "$INVALID_FILES" ]; then + echo -e "Test files don't contain a test environment configuration:" + echo -e $INVALID_FILES + exit 1 +fi \ No newline at end of file diff --git a/tsconfig.base.json b/tsconfig.base.json index 5c5915c703..09debdaee9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -11,7 +11,8 @@ "skipLibCheck": true, "strict": true, "target": "ES2022", - "sourceMap": true + "sourceMap": true, + "types": ["vitest/globals", "node", "node-fetch", "web"] }, "exclude": ["**/dist", "**/node_modules"] } diff --git a/vite.base.config.mts b/vite.base.config.mts new file mode 100644 index 0000000000..fd72f14ee8 --- /dev/null +++ b/vite.base.config.mts @@ -0,0 +1,43 @@ +import plainText from "vite-plugin-plain-text"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [ + plainText("**/*.hbs", { + namedExport: false, + }), + ], + test: { + exclude: [ + "**/node_modules/**", + "**/dist/**", + "/apps/demo-nextjs", + "/apps/demo-react-cra", + "/apps/demo-react-vite", + ], + globals: true, + setupFiles: ["./vite.env.ts"], + coverage: { + enabled: true, + provider: "istanbul", + reporter: ["json", "text", "html"], + include: ["packages", "internal", "apps"], + exclude: [ + "**/node_modules/**", + "**/dist/**", + "**/test/**", + "**/*.test.ts", + "**/*.d.ts", + "packages/fuel-gauge/**", + "apps/demo-*", + "apps/docs", + ], + }, + poolOptions: { + threads: { + minThreads: 1, + maxThreads: 16, + }, + } + }, +}); diff --git a/vite.browser.config.mts b/vite.browser.config.mts new file mode 100644 index 0000000000..51b1dbc3bc --- /dev/null +++ b/vite.browser.config.mts @@ -0,0 +1,36 @@ +import { nodePolyfills } from "vite-plugin-node-polyfills"; +import { mergeConfig } from "vitest/config"; +import type { UserConfig } from "vitest/config"; + +import baseConfig from "./vite.base.config.mts"; + +const config: UserConfig = { + plugins: [ + nodePolyfills({ + globals: { + process: true, + Buffer: true, + global: true, + }, + include: ["fs", "crypto", "buffer", "fs"], + overrides: { + fs: "memfs", + }, + }), + ], + optimizeDeps: { + exclude: ["fsevents"], + }, + test: { + coverage: { + reportsDirectory: "coverage/environments/browser", + }, + browser: { + headless: true, + enabled: true, + name: "chrome", + }, + }, +}; + +export default mergeConfig(baseConfig, config); diff --git a/jest.env.ts b/vite.env.ts similarity index 83% rename from jest.env.ts rename to vite.env.ts index e550cae779..689c8aa530 100644 --- a/jest.env.ts +++ b/vite.env.ts @@ -1,9 +1,9 @@ -import { hexlify } from 'ethers'; +import { hexlify } from '@fuel-ts/utils'; import faucets from './.fuel-core/configs/faucets.json'; /** - * Gets the private key for the current Jest worker. + * Gets the private key for the current Vitest worker. * * The PK is basically the current worker's ID. This allows us to * have a unique faucet wallet for each file being tested and prevents @@ -18,11 +18,11 @@ import faucets from './.fuel-core/configs/faucets.json'; * - 0x0101010101010101010101010101010101010101010101010101010101010101 * - 0x0202020202020202020202020202020202020202020202020202020202020202 * - * See: https://jestjs.io/docs/environment-variables#jest_worker_id + * See: https://vitest.dev/config/#setupfiles */ const getPrivateKeyForCurrentWorker = () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const workerId = Number.parseInt(process.env.JEST_WORKER_ID!, 10); + const workerId = Number.parseInt(process.env.VITEST_POOL_ID!, 10) || 1; if (workerId > faucets.length) { throw new Error(`At most ${faucets.length} workers are supported.`); diff --git a/vite.node.config.mts b/vite.node.config.mts new file mode 100644 index 0000000000..57e002b56d --- /dev/null +++ b/vite.node.config.mts @@ -0,0 +1,14 @@ +import type { UserConfig } from "vitest/config"; +import { mergeConfig } from "vitest/config"; + +import baseConfig from "./vite.base.config.mts"; + +const config: UserConfig = { + test: { + coverage: { + reportsDirectory: "coverage/environments/node", + }, + }, +}; + +export default mergeConfig(baseConfig, config);