diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 0000000..e6e5ab1 --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -0,0 +1,24 @@ +name: Build Documentation and Deploy to GitHub Pages +on: + push: + branches: + - master +permissions: + contents: write +jobs: + build-and-deploy: + concurrency: ci-${{ github.ref }} + runs-on: ubuntu-latest + steps: + - name: Checkout 🛎️ + uses: actions/checkout@v3 + + - name: Install and Build 🔧 + run: | + npm ci + npm run doc + + - name: Deploy 🚀 + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: documentation \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..7c7c3fb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,19 @@ +name: Publish to NPM +on: + release: + types: [created] +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + - name: Publish package on NPM 📦 + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2885f93 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,22 @@ +name: Build SDK and Test + +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '20.x' + - run: npm ci + - run: node --test --test-concurrency 1 + env: + TEST_KEY: ${{ secrets.TEST_S3_KEY }} + TEST_SECRET: ${{ secrets.TEST_S3_SECRET }} + TEST_IPFS_GATEWAY: ${{ vars.TEST_IPFS_GATEWAY }} + TEST_IPNS_PRIVATE_KEY: ${{ secrets.TEST_IPNS_PRIVATE_KEY }} + TEST_NAME_CID: ${{ vars.TEST_NAME_CID }} diff --git a/.gitignore b/.gitignore index a9b99ff..c479dda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ dist node_modules +documentation .env \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..4fd0219 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d36d5fb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Filebase, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/jsdoc.json b/jsdoc.json new file mode 100644 index 0000000..981e466 --- /dev/null +++ b/jsdoc.json @@ -0,0 +1,35 @@ +{ + "source": { + "include": ["src"], + "includePattern": ".js$", + "excludePattern": "(node_modules/|docs)" + }, + "plugins": ["plugins/markdown", "plugins/summarize"], + "templates": { + "referenceTitle": "Filebase SDK", + "cleverLinks": true + }, + "opts": { + "template": "node_modules/clean-jsdoc-theme", + "recurse": true, + "tutorials": "./tutorials", + "destination": "./documentation/", + "readme": "./readme.md", + "theme_opts": { + "title": "Filebase SDK", + "homepageTitle": "Filebase SDK", + "favicon": "https://console.filebase.com/favicon.ico", + "default_theme": "fallback-dark", + "sort": false, + "menu": [{ + "title": "Github", + "link": "https://github.com/filebase/filebase-sdk", + "target": "_blank" + },{ + "title": "npm", + "link": "https://www.npmjs.com/package/@filebase/sdk", + "target": "_blank" + }] + } + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2c55b80 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3221 @@ +{ + "name": "@filebase/sdk", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@filebase/sdk", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@aws-sdk/client-s3": "3.478.0", + "@aws-sdk/lib-storage": "3.478.0", + "@helia/car": "1.0.4", + "@helia/unixfs": "1.4.3", + "@ipld/car": "5.2.4", + "axios": "1.6.2", + "blockstore-fs": "1.1.8", + "uuid": "9.0.1" + }, + "devDependencies": { + "clean-jsdoc-theme": "4.2.17", + "jsdoc": "4.0.2", + "prettier": "3.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.9.4.tgz", + "integrity": "sha512-HazVq9zwTVwGmqdwYzu7WyQ6FQVZ7SwET0KKQuKm55jD0IfUpZgN0OPIiZG3zV1iSrVYcN0bdwLRXI/VNCYsUA==" + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", + "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", + "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.478.0.tgz", + "integrity": "sha512-OUpbCCnK71lQQ07BohJOx9ZER0rPqRAGOVIIVhNEkeN0uYFLzB7/o5a7+FEPUQXEd5rZRZgbxN5xEmnNW/0Waw==", + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.478.0", + "@aws-sdk/core": "3.477.0", + "@aws-sdk/credential-provider-node": "3.478.0", + "@aws-sdk/middleware-bucket-endpoint": "3.470.0", + "@aws-sdk/middleware-expect-continue": "3.468.0", + "@aws-sdk/middleware-flexible-checksums": "3.468.0", + "@aws-sdk/middleware-host-header": "3.468.0", + "@aws-sdk/middleware-location-constraint": "3.468.0", + "@aws-sdk/middleware-logger": "3.468.0", + "@aws-sdk/middleware-recursion-detection": "3.468.0", + "@aws-sdk/middleware-sdk-s3": "3.474.0", + "@aws-sdk/middleware-signing": "3.468.0", + "@aws-sdk/middleware-ssec": "3.468.0", + "@aws-sdk/middleware-user-agent": "3.478.0", + "@aws-sdk/region-config-resolver": "3.470.0", + "@aws-sdk/signature-v4-multi-region": "3.474.0", + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-endpoints": "3.478.0", + "@aws-sdk/util-user-agent-browser": "3.468.0", + "@aws-sdk/util-user-agent-node": "3.470.0", + "@aws-sdk/xml-builder": "3.472.0", + "@smithy/config-resolver": "^2.0.21", + "@smithy/core": "^1.2.0", + "@smithy/eventstream-serde-browser": "^2.0.15", + "@smithy/eventstream-serde-config-resolver": "^2.0.15", + "@smithy/eventstream-serde-node": "^2.0.15", + "@smithy/fetch-http-handler": "^2.3.1", + "@smithy/hash-blob-browser": "^2.0.16", + "@smithy/hash-node": "^2.0.17", + "@smithy/hash-stream-node": "^2.0.17", + "@smithy/invalid-dependency": "^2.0.15", + "@smithy/md5-js": "^2.0.17", + "@smithy/middleware-content-length": "^2.0.17", + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/middleware-retry": "^2.0.24", + "@smithy/middleware-serde": "^2.0.15", + "@smithy/middleware-stack": "^2.0.9", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/node-http-handler": "^2.2.1", + "@smithy/protocol-http": "^3.0.11", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.22", + "@smithy/util-defaults-mode-node": "^2.0.29", + "@smithy/util-endpoints": "^1.0.7", + "@smithy/util-retry": "^2.0.8", + "@smithy/util-stream": "^2.0.23", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.15", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.478.0.tgz", + "integrity": "sha512-Jxy9cE1JMkPR0PklCpq3cORHnZq/Z4klhSTNGgZNeBWovMa+plor52kyh8iUNHKl3XEJvTbHM7V+dvrr/x0P1g==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.477.0", + "@aws-sdk/middleware-host-header": "3.468.0", + "@aws-sdk/middleware-logger": "3.468.0", + "@aws-sdk/middleware-recursion-detection": "3.468.0", + "@aws-sdk/middleware-user-agent": "3.478.0", + "@aws-sdk/region-config-resolver": "3.470.0", + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-endpoints": "3.478.0", + "@aws-sdk/util-user-agent-browser": "3.468.0", + "@aws-sdk/util-user-agent-node": "3.470.0", + "@smithy/config-resolver": "^2.0.21", + "@smithy/core": "^1.2.0", + "@smithy/fetch-http-handler": "^2.3.1", + "@smithy/hash-node": "^2.0.17", + "@smithy/invalid-dependency": "^2.0.15", + "@smithy/middleware-content-length": "^2.0.17", + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/middleware-retry": "^2.0.24", + "@smithy/middleware-serde": "^2.0.15", + "@smithy/middleware-stack": "^2.0.9", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/node-http-handler": "^2.2.1", + "@smithy/protocol-http": "^3.0.11", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.22", + "@smithy/util-defaults-mode-node": "^2.0.29", + "@smithy/util-endpoints": "^1.0.7", + "@smithy/util-retry": "^2.0.8", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.478.0.tgz", + "integrity": "sha512-D+QID0dYzmn9dcxgKP3/nMndUqiQbDLsqI0Zf2pG4MW5gPhVNKlDGIV3Ztz8SkMjzGJExNOLW2L569o8jshJVw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.477.0", + "@aws-sdk/credential-provider-node": "3.478.0", + "@aws-sdk/middleware-host-header": "3.468.0", + "@aws-sdk/middleware-logger": "3.468.0", + "@aws-sdk/middleware-recursion-detection": "3.468.0", + "@aws-sdk/middleware-user-agent": "3.478.0", + "@aws-sdk/region-config-resolver": "3.470.0", + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-endpoints": "3.478.0", + "@aws-sdk/util-user-agent-browser": "3.468.0", + "@aws-sdk/util-user-agent-node": "3.470.0", + "@smithy/config-resolver": "^2.0.21", + "@smithy/core": "^1.2.0", + "@smithy/fetch-http-handler": "^2.3.1", + "@smithy/hash-node": "^2.0.17", + "@smithy/invalid-dependency": "^2.0.15", + "@smithy/middleware-content-length": "^2.0.17", + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/middleware-retry": "^2.0.24", + "@smithy/middleware-serde": "^2.0.15", + "@smithy/middleware-stack": "^2.0.9", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/node-http-handler": "^2.2.1", + "@smithy/protocol-http": "^3.0.11", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.22", + "@smithy/util-defaults-mode-node": "^2.0.29", + "@smithy/util-endpoints": "^1.0.7", + "@smithy/util-middleware": "^2.0.8", + "@smithy/util-retry": "^2.0.8", + "@smithy/util-utf8": "^2.0.2", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.477.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.477.0.tgz", + "integrity": "sha512-o0434EH+d1BxHZvgG7z8vph2SYefciQ5RnJw2MgvETGnthgqsnI4nnNJLSw0FVeqCeS18n6vRtzqlGYR2YPCNg==", + "dependencies": { + "@smithy/core": "^1.2.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/signature-v4": "^2.0.0", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.468.0.tgz", + "integrity": "sha512-k/1WHd3KZn0EQYjadooj53FC0z24/e4dUZhbSKTULgmxyO62pwh9v3Brvw4WRa/8o2wTffU/jo54tf4vGuP/ZA==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.478.0.tgz", + "integrity": "sha512-SsrYEYUvTG9ZoPC+zB19AnVoOKID+QIEHJDIi1GCZXW5kTVyr1saTVm4orG2TjYvbHQMddsWtHOvGYXZWAYMbw==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.468.0", + "@aws-sdk/credential-provider-process": "3.468.0", + "@aws-sdk/credential-provider-sso": "3.478.0", + "@aws-sdk/credential-provider-web-identity": "3.468.0", + "@aws-sdk/types": "3.468.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.478.0.tgz", + "integrity": "sha512-nwDutJYeHiIZCQDgKIUrsgwAWTil0mNe+cbd+j8fi+wwxkWUzip+F0+z02molJ8WrUUKNRhqB1V5aVx7IranuA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.468.0", + "@aws-sdk/credential-provider-ini": "3.478.0", + "@aws-sdk/credential-provider-process": "3.468.0", + "@aws-sdk/credential-provider-sso": "3.478.0", + "@aws-sdk/credential-provider-web-identity": "3.468.0", + "@aws-sdk/types": "3.468.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.468.0.tgz", + "integrity": "sha512-OYSn1A/UsyPJ7Z8Q2cNhTf55O36shPmSsvOfND04nSfu1nPaR+VUvvsP7v+brhGpwC/GAKTIdGAo4blH31BS6A==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.478.0.tgz", + "integrity": "sha512-LsDShG51X/q+s5ZFN7kHVqrd8ZHdyEyHqdhoocmRvvw2Dif50M0AqQfvCrW1ndj5CNzXO4x/eH8EK5ZOVlS6Sg==", + "dependencies": { + "@aws-sdk/client-sso": "3.478.0", + "@aws-sdk/token-providers": "3.478.0", + "@aws-sdk/types": "3.468.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.468.0.tgz", + "integrity": "sha512-rexymPmXjtkwCPfhnUq3EjO1rSkf39R4Jz9CqiM7OsqK2qlT5Y/V3gnMKn0ZMXsYaQOMfM3cT5xly5R+OKDHlw==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-storage": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.478.0.tgz", + "integrity": "sha512-R1D+hX8Lea9mBZqj2A4hWkSNGCTv5pCsX/+fmfnFtmKL4gPn2MZ1GtnI6Rnk0zyTrQL94SpVc6CcEvhWsm5oiQ==", + "dependencies": { + "@smithy/abort-controller": "^2.0.1", + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/smithy-client": "^2.1.18", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-s3": "^3.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.470.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.470.0.tgz", + "integrity": "sha512-vLXXNWtsRmEIwzJ9HUQfIuTNAsEzvCv0Icsnkvt2BiBZXnmHdp2vIC3e3+kfy1D7dVQloXqMmnfcLu/BUMu2Jw==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-arn-parser": "3.465.0", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "@smithy/util-config-provider": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.468.0.tgz", + "integrity": "sha512-/wmLjmfgeulxhhmnxX3X3N933TvGsYckVIFjAtDSpLjqkbwzEcNiLq7AdmNJ4BfxG0MCMgcht561DCCD19x8Bg==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.468.0.tgz", + "integrity": "sha512-LQwL/N5MCj3Y5keLLewHTqeAXUIMsHFZyxDXRm/uxrOon9ufLKDvGvzAmfwn1/CuSUo66ZfT8VPSA4BsC90RtA==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.468.0", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.468.0.tgz", + "integrity": "sha512-gwQ+/QhX+lhof304r6zbZ/V5l5cjhGRxLL3CjH1uJPMcOAbw9wUlMdl+ibr8UwBZ5elfKFGiB1cdW/0uMchw0w==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.468.0.tgz", + "integrity": "sha512-0gBX/lDynQr4YIhM9h1dVnkVWqrg+34iOCVIUq8jHxzUzgZWglGkG9lHGGg0r1xkLTmegeoo1OKH8wrQ6n33Cg==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.468.0.tgz", + "integrity": "sha512-X5XHKV7DHRXI3f29SAhJPe/OxWRFgDWDMMCALfzhmJfCi6Jfh0M14cJKoC+nl+dk9lB+36+jKjhjETZaL2bPlA==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.468.0.tgz", + "integrity": "sha512-vch9IQib2Ng9ucSyRW2eKNQXHUPb5jUPCLA5otTW/8nGjcOU37LxQG4WrxO7uaJ9Oe8hjHO+hViE3P0KISUhtA==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.474.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.474.0.tgz", + "integrity": "sha512-62aAo/8u5daIabeJ+gseYeHeShe9eYH6mH+kfWmLsHybXCCv1EaD/ZkdXWNhL0HZ3bUI1z1SF1p8jjTAWALnwA==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-arn-parser": "3.465.0", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/protocol-http": "^3.0.11", + "@smithy/signature-v4": "^2.0.0", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/util-config-provider": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.468.0.tgz", + "integrity": "sha512-s+7fSB1gdnnTj5O0aCCarX3z5Vppop8kazbNSZADdkfHIDWCN80IH4ZNjY3OWqaAz0HmR4LNNrovdR304ojb4Q==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.7.0", + "@smithy/util-middleware": "^2.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.468.0.tgz", + "integrity": "sha512-y1qLW24wRkOGBTK5d6eJXf6d8HYo4rzT4a1mNDN1rd18NSffwQ6Yke5qeUiIaxa0y/l+FvvNYErbhYtij2rJoQ==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.478.0.tgz", + "integrity": "sha512-Rec+nAPIzzwxgHPW+xqY6tooJGFOytpYg/xSRv8/IXl3xKGhmpMGs6gDWzmMBv/qy5nKTvLph/csNWJ98GWXCw==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-endpoints": "3.478.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.470.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.470.0.tgz", + "integrity": "sha512-C1o1J06iIw8cyAAOvHqT4Bbqf+PgQ/RDlSyjt2gFfP2OovDpc2o2S90dE8f8iZdSGpg70N5MikT1DBhW9NbhtQ==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.8", + "@smithy/types": "^2.7.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.474.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.474.0.tgz", + "integrity": "sha512-93OWRQgTJZASXLrlUNX7mmXknNkYxFYldRLARmYQccONmnIqgYQW0lQj8BFwqkHJTzSMik3/UsU0SHKwZ9ynYA==", + "dependencies": { + "@aws-sdk/middleware-sdk-s3": "3.474.0", + "@aws-sdk/types": "3.468.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.478.0.tgz", + "integrity": "sha512-7b5tj1y/wGHZIZ+ckjOUKgKrMuCJMF/G1UKZKIqqdekeEsjcThbvoxAMeY0FEowu2ODVk/ggOmpBFxcu0iYd6A==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.468.0", + "@aws-sdk/middleware-logger": "3.468.0", + "@aws-sdk/middleware-recursion-detection": "3.468.0", + "@aws-sdk/middleware-user-agent": "3.478.0", + "@aws-sdk/region-config-resolver": "3.470.0", + "@aws-sdk/types": "3.468.0", + "@aws-sdk/util-endpoints": "3.478.0", + "@aws-sdk/util-user-agent-browser": "3.468.0", + "@aws-sdk/util-user-agent-node": "3.470.0", + "@smithy/config-resolver": "^2.0.21", + "@smithy/fetch-http-handler": "^2.3.1", + "@smithy/hash-node": "^2.0.17", + "@smithy/invalid-dependency": "^2.0.15", + "@smithy/middleware-content-length": "^2.0.17", + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/middleware-retry": "^2.0.24", + "@smithy/middleware-serde": "^2.0.15", + "@smithy/middleware-stack": "^2.0.9", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/node-http-handler": "^2.2.1", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.11", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.1", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.22", + "@smithy/util-defaults-mode-node": "^2.0.29", + "@smithy/util-endpoints": "^1.0.7", + "@smithy/util-retry": "^2.0.8", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.468.0.tgz", + "integrity": "sha512-rx/9uHI4inRbp2tw3Y4Ih4PNZkVj32h7WneSg3MVgVjAoVD5Zti9KhS5hkvsBxfgmQmg0AQbE+b1sy5WGAgntA==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.465.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.465.0.tgz", + "integrity": "sha512-zOJ82vzDJFqBX9yZBlNeHHrul/kpx/DCoxzW5UBbZeb26kfV53QhMSoEmY8/lEbBqlqargJ/sgRC845GFhHNQw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.478.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.478.0.tgz", + "integrity": "sha512-u9Mcg3euGJGs5clPt9mBuhBjHiEKiD0PnfvArhfq9i+dcY5mbCq/i1Dezp3iv1fZH9xxQt7hPXDfSpt1yUSM6g==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/util-endpoints": "^1.0.7", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.465.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.465.0.tgz", + "integrity": "sha512-f+QNcWGswredzC1ExNAB/QzODlxwaTdXkNT5cvke2RLX8SFU5pYk6h4uCtWC0vWPELzOfMfloBrJefBzlarhsw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.468.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.468.0.tgz", + "integrity": "sha512-OJyhWWsDEizR3L+dCgMXSUmaCywkiZ7HSbnQytbeKGwokIhD69HTiJcibF/sgcM5gk4k3Mq3puUhGnEZ46GIig==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/types": "^2.7.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.470.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.470.0.tgz", + "integrity": "sha512-QxsZ9iVHcBB/XRdYvwfM5AMvNp58HfqkIrH88mY0cmxuvtlIGDfWjczdDrZMJk9y0vIq+cuoCHsGXHu7PyiEAQ==", + "dependencies": { + "@aws-sdk/types": "3.468.0", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.472.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.472.0.tgz", + "integrity": "sha512-PwjVxz1hr9up8QkddabuScPZ/d5aDHgvHYgK4acHYzltXL4wngfvimi5ZqXTzVWF2QANxHmWnHUr45QJX71oJQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@chainsafe/is-ip": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.0.2.tgz", + "integrity": "sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA==" + }, + "node_modules/@chainsafe/netmask": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", + "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1" + } + }, + "node_modules/@helia/car": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@helia/car/-/car-1.0.4.tgz", + "integrity": "sha512-HcHMC/eTRCFt3jrLkMvqKD7Og92PpNoBZTMQ9R+dOvtyIlZ2iG4zYRm2DipPdDi+OvXCqaPNg0oJxDx5fBnjRw==", + "dependencies": { + "@helia/interface": "^2.0.0", + "@ipld/car": "^5.1.1", + "@ipld/dag-pb": "^4.0.0", + "@libp2p/interfaces": "^3.3.1", + "cborg": "^4.0.3", + "interface-blockstore": "^5.0.0", + "it-map": "^3.0.3", + "multiformats": "^12.0.1", + "p-defer": "^4.0.0", + "p-queue": "^7.3.4", + "progress-events": "^1.0.0" + } + }, + "node_modules/@helia/interface": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@helia/interface/-/interface-2.1.0.tgz", + "integrity": "sha512-Z7PwuDIR0BODfSMzYcdzgdTYLsshCawAoPvGuuazvBddWSD9y82/QBmsWp6CTkyM/ziEaWbz5wERmRS+wejDLg==", + "dependencies": { + "@libp2p/interface": "^0.1.1", + "interface-blockstore": "^5.0.0", + "interface-datastore": "^8.0.0", + "interface-store": "^5.0.1", + "ipfs-bitswap": "^19.0.0", + "multiformats": "^12.0.1", + "progress-events": "^1.0.0" + } + }, + "node_modules/@helia/unixfs": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@helia/unixfs/-/unixfs-1.4.3.tgz", + "integrity": "sha512-jS0En8fGhb01XH+nnxo3kQsmc1lwBEdlttAZFvTo7HCjBGPNFuaYdwTqF9S1wMVWV2fWqj7eS2zBZZa0MDsi1Q==", + "dependencies": { + "@helia/interface": "^2.0.0", + "@ipld/dag-pb": "^4.0.0", + "@libp2p/interface": "^0.1.2", + "@libp2p/logger": "^3.0.2", + "@multiformats/murmur3": "^2.1.2", + "hamt-sharding": "^3.0.2", + "interface-blockstore": "^5.0.0", + "ipfs-unixfs": "^11.0.0", + "ipfs-unixfs-exporter": "^13.1.0", + "ipfs-unixfs-importer": "^15.1.0", + "it-glob": "^2.0.4", + "it-last": "^3.0.1", + "it-pipe": "^3.0.1", + "merge-options": "^3.0.4", + "multiformats": "^12.1.1", + "progress-events": "^1.0.0", + "sparse-array": "^1.3.2" + } + }, + "node_modules/@ipld/car": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@ipld/car/-/car-5.2.4.tgz", + "integrity": "sha512-YoVXE/o5HLXKi/Oqh9Nhcn423sdn9brRFKnbUid68/1D332/XINcoyCTvBluFcCw/9IeiTx+sEAV+onXZ/A4eA==", + "dependencies": { + "@ipld/dag-cbor": "^9.0.0", + "cborg": "^4.0.0", + "multiformats": "^12.1.0", + "varint": "^6.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-cbor": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@ipld/dag-cbor/-/dag-cbor-9.0.6.tgz", + "integrity": "sha512-3kNab5xMppgWw6DVYx2BzmFq8t7I56AGWfp5kaU1fIPkwHVpBRglJJTYsGtbVluCi/s/q97HZM3bC+aDW4sxbQ==", + "dependencies": { + "cborg": "^4.0.0", + "multiformats": "^12.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@ipld/dag-pb": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.0.6.tgz", + "integrity": "sha512-wOij3jfDKZsb9yjhQeHp+TQy0pu1vmUkGv324xciFFZ7xGbDfAGTQW03lSA5aJ/7HBBNYgjEE0nvHmNW1Qjfag==", + "dependencies": { + "multiformats": "^12.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdoc/salty": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.7.tgz", + "integrity": "sha512-mh8LbS9d4Jq84KLw8pzho7XC2q2/IJGiJss3xwRoLD1A+EE16SjN4PfaG4jRCzKegTFLlN0Zd8SdUPE6XdoPFg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=v12.0.0" + } + }, + "node_modules/@libp2p/interface": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-0.1.6.tgz", + "integrity": "sha512-Lzc5cS/hXuoXhuAbVIxJIHLCYmfPcbU0vVgrpMoiP1Qb2Q3ETU4A46GB8s8mWXgSU6tr9RcqerUqzFYD6+OAag==", + "dependencies": { + "@multiformats/multiaddr": "^12.1.5", + "abortable-iterator": "^5.0.1", + "it-pushable": "^3.2.0", + "it-stream-types": "^2.0.1", + "multiformats": "^12.0.1", + "p-defer": "^4.0.0", + "race-signal": "^1.0.0", + "uint8arraylist": "^2.4.3" + } + }, + "node_modules/@libp2p/interfaces": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@libp2p/interfaces/-/interfaces-3.3.2.tgz", + "integrity": "sha512-p/M7plbrxLzuQchvNwww1Was7ZeGE2NaOFulMaZBYIihU8z3fhaV+a033OqnC/0NTX/yhfdNOG7znhYq3XoR/g==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/logger": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-3.1.0.tgz", + "integrity": "sha512-qJbJBAhxHVsRBtQSOIkSLi0lskUSFjzE+zm0QvoyxzZKSz+mX41mZLbnofPIVOVauoDQ40dXpe7WDUOq8AbiQQ==", + "dependencies": { + "@libp2p/interface": "^0.1.6", + "@multiformats/multiaddr": "^12.1.5", + "debug": "^4.3.4", + "interface-datastore": "^8.2.0", + "multiformats": "^12.0.1" + } + }, + "node_modules/@multiformats/multiaddr": { + "version": "12.1.11", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.1.11.tgz", + "integrity": "sha512-CWG9kETEGTTMdr1T+/JEuMwFld3r3fHNP8LkLoUcLvHRy6yr8sWdotVGEDNEdDO/vrKhuD7bQBws3xMSMMyylg==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/interface": "^1.0.0", + "dns-over-http-resolver": "3.0.0", + "multiformats": "^12.0.1", + "uint8-varint": "^2.0.1", + "uint8arrays": "^4.0.2" + } + }, + "node_modules/@multiformats/multiaddr/node_modules/@libp2p/interface": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.0.2.tgz", + "integrity": "sha512-z/3Yyg+7cVyzRXwzdrDkJd7YmNaLE9iZjQaixo5luI/n9uk5OFFjb9ulAsNqpq8V1xylCo2DXIC7f94KClwzVw==", + "dependencies": { + "@multiformats/multiaddr": "^12.1.10", + "it-pushable": "^3.2.1", + "it-stream-types": "^2.0.1", + "multiformats": "^12.1.3", + "uint8arraylist": "^2.4.3" + } + }, + "node_modules/@multiformats/murmur3": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@multiformats/murmur3/-/murmur3-2.1.7.tgz", + "integrity": "sha512-Yf0UpAaONjed+8PTt5NM/GG4Z4Ai4m1qfT7bqevjnkwRQ12K+0jxtRomirz+VJx4PokpA2St1ZSD1iMkZTqPRQ==", + "dependencies": { + "multiformats": "^12.0.1", + "murmurhash3js-revisited": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.15.tgz", + "integrity": "sha512-JkS36PIS3/UCbq/MaozzV7jECeL+BTt4R75bwY8i+4RASys4xOyUS1HsRyUNSqUXFP4QyCz5aNnh3ltuaxv+pw==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz", + "integrity": "sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.1.tgz", + "integrity": "sha512-N2oCZRglhWKm7iMBu7S6wDzXirjAofi7tAd26cxmgibRYOBS4D3hGfmkwCpHdASZzwZDD8rluh0Rcqw1JeZDRw==", + "dependencies": { + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.21.tgz", + "integrity": "sha512-rlLIGT+BeqjnA6C2FWumPRJS1UW07iU5ZxDHtFuyam4W65gIaOFMjkB90ofKCIh+0mLVQrQFrl/VLtQT/6FWTA==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.8", + "@smithy/types": "^2.7.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.2.0.tgz", + "integrity": "sha512-l8R89X7+hlt2FEFg+OrNq29LP3h9DfGPmO6ObwT9IXWHD6V7ycpj5u2rVQyIis26ovrgOYakl6nfgmPMm8m1IQ==", + "dependencies": { + "@smithy/middleware-endpoint": "^2.2.3", + "@smithy/middleware-retry": "^2.0.24", + "@smithy/middleware-serde": "^2.0.15", + "@smithy/protocol-http": "^3.0.11", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/util-middleware": "^2.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.1.4.tgz", + "integrity": "sha512-cwPJN1fa1YOQzhBlTXRavABEYRRchci1X79QRwzaNLySnIMJfztyv1Zkst0iZPLMnpn8+CnHu3wOHS11J5Dr3A==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.8", + "@smithy/property-provider": "^2.0.16", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.15.tgz", + "integrity": "sha512-crjvz3j1gGPwA0us6cwS7+5gAn35CTmqu/oIxVbYJo2Qm/sGAye6zGJnMDk3BKhWZw5kcU1G4MxciTkuBpOZPg==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.7.0", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.15.tgz", + "integrity": "sha512-WiFG5N9j3jmS5P0z5Xev6dO0c3lf7EJYC2Ncb0xDnWFvShwXNn741AF71ABr5EcZw8F4rQma0362MMjAwJeZog==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.15.tgz", + "integrity": "sha512-o65d2LRjgCbWYH+VVNlWXtmsI231SO99ZTOL4UuIPa6WTjbSHWtlXvUcJG9libhEKWmEV9DIUiH2IqyPWi7ubA==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.15.tgz", + "integrity": "sha512-9OOXiIhHq1VeOG6xdHkn2ZayfMYM3vzdUTV3zhcCnt+tMqA3BJK3XXTJFRR2BV28rtRM778DzqbBTf+hqwQPTg==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.15.tgz", + "integrity": "sha512-dP8AQp/pXlWBjvL0TaPBJC3rM0GoYv7O0Uim8d/7UKZ2Wo13bFI3/BhQfY/1DeiP1m23iCHFNFtOQxfQNBB8rQ==", + "dependencies": { + "@smithy/eventstream-codec": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.3.1.tgz", + "integrity": "sha512-6MNk16fqb8EwcYY8O8WxB3ArFkLZ2XppsSNo1h7SQcFdDDwIumiJeO6wRzm7iB68xvsOQzsdQKbdtTieS3hfSQ==", + "dependencies": { + "@smithy/protocol-http": "^3.0.11", + "@smithy/querystring-builder": "^2.0.15", + "@smithy/types": "^2.7.0", + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.16.tgz", + "integrity": "sha512-cSYRi05LA7DZDwjB1HL0BP8B56eUNNeLglVH147QTXFyuXJq/7erAIiLRfsyXB8+GfFHkSS5BHbc76a7k/AYPA==", + "dependencies": { + "@smithy/chunked-blob-reader": "^2.0.0", + "@smithy/chunked-blob-reader-native": "^2.0.1", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.17.tgz", + "integrity": "sha512-Il6WuBcI1nD+e2DM7tTADMf01wEPGK8PAhz4D+YmDUVaoBqlA+CaH2uDJhiySifmuKBZj748IfygXty81znKhw==", + "dependencies": { + "@smithy/types": "^2.7.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.17.tgz", + "integrity": "sha512-ey8DtnATzp1mOXgS7rqMwSmAki6iJA+jgNucKcxRkhMB1rrICfHg+rhmIF50iLPDHUhTcS5pBMOrLzzpZftvNQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.15.tgz", + "integrity": "sha512-dlEKBFFwVfzA5QroHlBS94NpgYjXhwN/bFfun+7w3rgxNvVy79SK0w05iGc7UAeC5t+D7gBxrzdnD6hreZnDVQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.17.tgz", + "integrity": "sha512-jmISTCnEkOnm2oCNx/rMkvBT/eQh3aA6nktevkzbmn/VYqYEuc5Z2n5sTTqsciMSO01Lvf56wG1A4twDqovYeQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.17.tgz", + "integrity": "sha512-OyadvMcKC7lFXTNBa8/foEv7jOaqshQZkjWS9coEXPRZnNnihU/Ls+8ZuJwGNCOrN2WxXZFmDWhegbnM4vak8w==", + "dependencies": { + "@smithy/protocol-http": "^3.0.11", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.2.3.tgz", + "integrity": "sha512-nYfxuq0S/xoAjdLbyn1ixeVB6cyH9wYCMtbbOCpcCRYR5u2mMtqUtVjjPAZ/DIdlK3qe0tpB0Q76szFGNuz+kQ==", + "dependencies": { + "@smithy/middleware-serde": "^2.0.15", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/shared-ini-file-loader": "^2.2.7", + "@smithy/types": "^2.7.0", + "@smithy/url-parser": "^2.0.15", + "@smithy/util-middleware": "^2.0.8", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.24", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.24.tgz", + "integrity": "sha512-q2SvHTYu96N7lYrn3VSuX3vRpxXHR/Cig6MJpGWxd0BWodUQUWlKvXpWQZA+lTaFJU7tUvpKhRd4p4MU3PbeJg==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.8", + "@smithy/protocol-http": "^3.0.11", + "@smithy/service-error-classification": "^2.0.8", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "@smithy/util-middleware": "^2.0.8", + "@smithy/util-retry": "^2.0.8", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.15.tgz", + "integrity": "sha512-FOZRFk/zN4AT4wzGuBY+39XWe+ZnCFd0gZtyw3f9Okn2CJPixl9GyWe98TIaljeZdqWkgrzGyPre20AcW2UMHQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.9.tgz", + "integrity": "sha512-bCB5dUtGQ5wh7QNL2ELxmDc6g7ih7jWU3Kx6MYH1h4mZbv9xL3WyhKHojRltThCB1arLPyTUFDi+x6fB/oabtA==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.8.tgz", + "integrity": "sha512-+w26OKakaBUGp+UG+dxYZtFb5fs3tgHg3/QrRrmUZj+rl3cIuw840vFUXX35cVPTUCQIiTqmz7CpVF7+hdINdQ==", + "dependencies": { + "@smithy/property-provider": "^2.0.16", + "@smithy/shared-ini-file-loader": "^2.2.7", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.2.1.tgz", + "integrity": "sha512-8iAKQrC8+VFHPAT8pg4/j6hlsTQh+NKOWlctJBrYtQa4ExcxX7aSg3vdQ2XLoYwJotFUurg/NLqFCmZaPRrogw==", + "dependencies": { + "@smithy/abort-controller": "^2.0.15", + "@smithy/protocol-http": "^3.0.11", + "@smithy/querystring-builder": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.16.tgz", + "integrity": "sha512-28Ky0LlOqtEjwg5CdHmwwaDRHcTWfPRzkT6HrhwOSRS2RryAvuDfJrZpM+BMcrdeCyEg1mbcgIMoqTla+rdL8Q==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.11.tgz", + "integrity": "sha512-3ziB8fHuXIRamV/akp/sqiWmNPR6X+9SB8Xxnozzj+Nq7hSpyKdFHd1FLpBkgfGFUTzzcBJQlDZPSyxzmdcx5A==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.15.tgz", + "integrity": "sha512-e1q85aT6HutvouOdN+dMsN0jcdshp50PSCvxDvo6aIM57LqeXimjfONUEgfqQ4IFpYWAtVixptyIRE5frMp/2A==", + "dependencies": { + "@smithy/types": "^2.7.0", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.15.tgz", + "integrity": "sha512-jbBvoK3cc81Cj1c1TH1qMYxNQKHrYQ2DoTntN9FBbtUWcGhc+T4FP6kCKYwRLXyU4AajwGIZstvNAmIEgUUNTQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.8.tgz", + "integrity": "sha512-jCw9+005im8tsfYvwwSc4TTvd29kXRFkH9peQBg5R/4DD03ieGm6v6Hpv9nIAh98GwgYg1KrztcINC1s4o7/hg==", + "dependencies": { + "@smithy/types": "^2.7.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.7.tgz", + "integrity": "sha512-0Qt5CuiogIuvQIfK+be7oVHcPsayLgfLJGkPlbgdbl0lD28nUKu4p11L+UG3SAEsqc9UsazO+nErPXw7+IgDpQ==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.18.tgz", + "integrity": "sha512-SJRAj9jT/l9ocm8D0GojMbnA1sp7I4JeStOQ4lEXI8A5eHE73vbjlzlqIFB7cLvIgau0oUl4cGVpF9IGCrvjlw==", + "dependencies": { + "@smithy/eventstream-codec": "^2.0.15", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.7.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.8", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.18.tgz", + "integrity": "sha512-7FqdbaJiVaHJDD9IfDhmzhSDbpjyx+ZsfdYuOpDJF09rl8qlIAIlZNoSaflKrQ3cEXZN2YxGPaNWGhbYimyIRQ==", + "dependencies": { + "@smithy/middleware-stack": "^2.0.9", + "@smithy/types": "^2.7.0", + "@smithy/util-stream": "^2.0.23", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.7.0.tgz", + "integrity": "sha512-1OIFyhK+vOkMbu4aN2HZz/MomREkrAC/HqY5mlJMUJfGrPRwijJDTeiN8Rnj9zUaB8ogXAfIOtZrrgqZ4w7Wnw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.15.tgz", + "integrity": "sha512-sADUncUj9rNbOTrdDGm4EXlUs0eQ9dyEo+V74PJoULY4jSQxS+9gwEgsPYyiu8PUOv16JC/MpHonOgqP/IEDZA==", + "dependencies": { + "@smithy/querystring-parser": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.1.tgz", + "integrity": "sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.1.tgz", + "integrity": "sha512-NXYp3ttgUlwkaug4bjBzJ5+yIbUbUx8VsSLuHZROQpoik+gRkIBeEG9MPVYfvPNpuXb/puqodeeUXcKFe7BLOQ==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.22.tgz", + "integrity": "sha512-qcF20IHHH96FlktvBRICDXDhLPtpVmtksHmqNGtotb9B0DYWXsC6jWXrkhrrwF7tH26nj+npVTqh9isiFV1gdA==", + "dependencies": { + "@smithy/property-provider": "^2.0.16", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.29", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.29.tgz", + "integrity": "sha512-+uG/15VoUh6JV2fdY9CM++vnSuMQ1VKZ6BdnkUM7R++C/vLjnlg+ToiSR1FqKZbMmKBXmsr8c/TsDWMAYvxbxQ==", + "dependencies": { + "@smithy/config-resolver": "^2.0.21", + "@smithy/credential-provider-imds": "^2.1.4", + "@smithy/node-config-provider": "^2.1.8", + "@smithy/property-provider": "^2.0.16", + "@smithy/smithy-client": "^2.1.18", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.0.7.tgz", + "integrity": "sha512-Q2gEind3jxoLk6hdKWyESMU7LnXz8aamVwM+VeVjOYzYT1PalGlY/ETa48hv2YpV4+YV604y93YngyzzzQ4IIA==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.8", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.8.tgz", + "integrity": "sha512-qkvqQjM8fRGGA8P2ydWylMhenCDP8VlkPn8kiNuFEaFz9xnUKC2irfqsBSJrfrOB9Qt6pQsI58r3zvvumhFMkw==", + "dependencies": { + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.8.tgz", + "integrity": "sha512-cQTPnVaVFMjjS6cb44WV2yXtHVyXDC5icKyIbejMarJEApYeJWpBU3LINTxHqp/tyLI+MZOUdosr2mZ3sdziNg==", + "dependencies": { + "@smithy/service-error-classification": "^2.0.8", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.23.tgz", + "integrity": "sha512-OJMWq99LAZJUzUwTk+00plyxX3ESktBaGPhqNIEVab+53gLULiWN9B/8bRABLg0K6R6Xg4t80uRdhk3B/LZqMQ==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.3.1", + "@smithy/node-http-handler": "^2.2.1", + "@smithy/types": "^2.7.0", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.2.tgz", + "integrity": "sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.15.tgz", + "integrity": "sha512-9Y+btzzB7MhLADW7xgD6SjvmoYaRkrb/9SCbNGmNdfO47v38rxb90IGXyDtAK0Shl9bMthTmLgjlfYc+vtz2Qw==", + "dependencies": { + "@smithy/abort-controller": "^2.0.15", + "@smithy/types": "^2.7.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/linkify-it": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "12.2.3", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", + "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "dev": true, + "dependencies": { + "@types/linkify-it": "*", + "@types/mdurl": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==", + "dev": true + }, + "node_modules/@vascosantos/moving-average": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vascosantos/moving-average/-/moving-average-1.1.0.tgz", + "integrity": "sha512-MVEJ4vWAPNbrGLjz7ITnHYg+YXZ6ijAqtH5/cHwSoCpbvuJ98aLXwFfPKAUfZpJMQR5uXB58UJajbY130IRF/w==" + }, + "node_modules/abortable-iterator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/abortable-iterator/-/abortable-iterator-5.0.1.tgz", + "integrity": "sha512-hlZ5Z8UwqrKsJcelVPEqDduZowJPBQJ9ZhBC2FXpja3lXy8X6MoI5uMzIgmrA8+3jcVnp8TF/tx+IBBqYJNUrg==", + "dependencies": { + "get-iterator": "^2.0.0", + "it-stream-types": "^2.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/any-signal": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/any-signal/-/any-signal-4.1.1.tgz", + "integrity": "sha512-iADenERppdC+A2YKbOXXB2WUeABLaM6qnpZ70kZbPZ1cZMMJ7eF+3CaYm+/PhBizgkzlvssC7QuHS30oOiQYWA==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/blockstore-core": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/blockstore-core/-/blockstore-core-4.3.8.tgz", + "integrity": "sha512-Agunhjw9w0I1OoJn012OpzJwBRm3Nf+v64N2FaZSsF3UGhoQAu4RePLuIBsZrPh4XRqT5Yg1rHoBYJGDhDmkWQ==", + "dependencies": { + "@libp2p/logger": "^4.0.1", + "err-code": "^3.0.1", + "interface-blockstore": "^5.0.0", + "interface-store": "^5.0.0", + "it-drain": "^3.0.1", + "it-filter": "^3.0.0", + "it-merge": "^3.0.1", + "it-pushable": "^3.0.0", + "multiformats": "^12.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/blockstore-core/node_modules/@libp2p/interface": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-1.0.2.tgz", + "integrity": "sha512-z/3Yyg+7cVyzRXwzdrDkJd7YmNaLE9iZjQaixo5luI/n9uk5OFFjb9ulAsNqpq8V1xylCo2DXIC7f94KClwzVw==", + "dependencies": { + "@multiformats/multiaddr": "^12.1.10", + "it-pushable": "^3.2.1", + "it-stream-types": "^2.0.1", + "multiformats": "^12.1.3", + "uint8arraylist": "^2.4.3" + } + }, + "node_modules/blockstore-core/node_modules/@libp2p/logger": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-4.0.2.tgz", + "integrity": "sha512-J9UMtMU9BKXNp+3c5kcI7HyWOPYg2B2E6sn1gEQckiSexTaz0wKJSlgTZ89f9F8bkC3AaC8ybXYuHbFQhwpTIg==", + "dependencies": { + "@libp2p/interface": "^1.0.2", + "@multiformats/multiaddr": "^12.1.10", + "debug": "^4.3.4", + "interface-datastore": "^8.2.0", + "multiformats": "^12.1.3" + } + }, + "node_modules/blockstore-core/node_modules/uint8arrays": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.0.tgz", + "integrity": "sha512-RWO7gR4x6syxnKDfZO8mDCsaaYs1/BqZCxlHgrcRge50E9GTnLmtoA4kwFSGIL4s3dQkryeTkvtG6oEFEya3yg==", + "dependencies": { + "multiformats": "^12.0.1" + } + }, + "node_modules/blockstore-fs": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/blockstore-fs/-/blockstore-fs-1.1.8.tgz", + "integrity": "sha512-1KD1+yEkxszZ3GWQdJbGgXAOs12LJC/Pit7JCPueJT/Pjt9GWtGZ4+8mgoaR3bjXVBgBIdhNlUxxw2NS787noA==", + "dependencies": { + "blockstore-core": "^4.0.0", + "fast-write-atomic": "^0.2.0", + "interface-blockstore": "^5.0.0", + "interface-store": "^5.0.0", + "it-glob": "^2.0.1", + "it-map": "^3.0.1", + "it-parallel-batch": "^3.0.0", + "multiformats": "^12.0.1" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/catharsis": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cborg": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/cborg/-/cborg-4.0.5.tgz", + "integrity": "sha512-q8TAjprr8pn9Fp53rOIGp/UFDdFY6os2Nq62YogPSIzczJD9M6g2b6igxMkpCiZZKJ0kn/KzDLDvG+EqBIEeCg==", + "bin": { + "cborg": "lib/bin.js" + } + }, + "node_modules/clean-css": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-jsdoc-theme": { + "version": "4.2.17", + "resolved": "https://registry.npmjs.org/clean-jsdoc-theme/-/clean-jsdoc-theme-4.2.17.tgz", + "integrity": "sha512-5SbJNXcQHUXd7N13g+3OpGFiBQdxz36xwEP3p1r1vbo/apLcDRtugaFdUZ56H6Rvlb68Q33EChoBkajSlnD11w==", + "dev": true, + "dependencies": { + "@jsdoc/salty": "^0.2.4", + "fs-extra": "^10.1.0", + "html-minifier-terser": "^7.2.0", + "klaw-sync": "^6.0.0", + "lodash": "^4.17.21", + "showdown": "^2.1.0" + }, + "peerDependencies": { + "jsdoc": ">=3.x <=4.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dns-over-http-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dns-over-http-resolver/-/dns-over-http-resolver-3.0.0.tgz", + "integrity": "sha512-5+BI+B7n8LKhNaEZBYErr+CBd9t5nYtjunByLhrLGtZ+i3TRgiU8yE87pCjEBu2KOwNsD9ljpSXEbZ4S8xih5g==", + "dependencies": { + "debug": "^4.3.4", + "receptacle": "^1.3.2" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-write-atomic": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fast-write-atomic/-/fast-write-atomic-0.2.1.tgz", + "integrity": "sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw==" + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/get-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-iterator/-/get-iterator-2.0.1.tgz", + "integrity": "sha512-7HuY/hebu4gryTDT7O/XY/fvY9wRByEGdK6QOa4of8npTcv0+NS6frFKABcf6S9EBAsveTuKTsZQQBFMMNILIg==" + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/hamt-sharding": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/hamt-sharding/-/hamt-sharding-3.0.2.tgz", + "integrity": "sha512-f0DzBD2tSmLFdFsLAvOflIBqFPjerbA7BfmwO8mVho/5hXwgyyYhv+ijIzidQf/DpDX3bRjAQvhGoBFj+DBvPw==", + "dependencies": { + "sparse-array": "^1.3.1", + "uint8arrays": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/html-minifier-terser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.15.1" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": "^14.13.1 || >=16.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/interface-blockstore": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/interface-blockstore/-/interface-blockstore-5.2.7.tgz", + "integrity": "sha512-B9UplmgUdQg15f/6xDJEbQYcjMm568cnqJsxSZYbDD0s6eQX5gKh58sd9H3aJEMosIy8T4vz9MwWWZuAOc3hQQ==", + "dependencies": { + "interface-store": "^5.0.0", + "multiformats": "^12.0.1" + } + }, + "node_modules/interface-datastore": { + "version": "8.2.9", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.2.9.tgz", + "integrity": "sha512-J/8PN8TnB5xxCRtgu9Vx3zExdOzcTU5/DBF2dlU41deX1GW6/SPpbJo5DRNSnvzfjmwJ7YhUOIFXyccUp8nuAA==", + "dependencies": { + "interface-store": "^5.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/interface-datastore/node_modules/uint8arrays": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.0.0.tgz", + "integrity": "sha512-RWO7gR4x6syxnKDfZO8mDCsaaYs1/BqZCxlHgrcRge50E9GTnLmtoA4kwFSGIL4s3dQkryeTkvtG6oEFEya3yg==", + "dependencies": { + "multiformats": "^12.0.1" + } + }, + "node_modules/interface-store": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-5.1.5.tgz", + "integrity": "sha512-X0KnJBk3o+YL13MxZBMwa88/b3Mdrpm0yPzkSTKDDVn9BSPH7UK6W+ZtIPO2bxKOQVmq7zqOwAnYnpfqWjb6/g==" + }, + "node_modules/ipfs-bitswap": { + "version": "19.0.2", + "resolved": "https://registry.npmjs.org/ipfs-bitswap/-/ipfs-bitswap-19.0.2.tgz", + "integrity": "sha512-pm0EcnTAwMMkCmdXHw/a7uPXzQ4I/pxVFiQZ6Ebg/R64XxAky/bCOJRzmqsgqH0+prH2bXAOgzS0mOZdL+zFSw==", + "dependencies": { + "@libp2p/interface": "^0.1.1", + "@libp2p/logger": "^3.0.1", + "@multiformats/multiaddr": "^12.1.0", + "@vascosantos/moving-average": "^1.1.0", + "any-signal": "^4.1.1", + "blockstore-core": "^4.0.0", + "events": "^3.3.0", + "interface-blockstore": "^5.0.0", + "interface-store": "^5.1.0", + "it-foreach": "^2.0.2", + "it-length-prefixed": "^9.0.0", + "it-map": "^3.0.2", + "it-pipe": "^3.0.1", + "it-take": "^3.0.1", + "just-debounce-it": "^3.0.1", + "multiformats": "^12.0.1", + "progress-events": "^1.0.0", + "protons-runtime": "^5.0.0", + "timeout-abort-controller": "^3.0.0", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^4.0.2", + "varint": "^6.0.0", + "varint-decoder": "^1.0.0" + } + }, + "node_modules/ipfs-unixfs": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/ipfs-unixfs/-/ipfs-unixfs-11.1.0.tgz", + "integrity": "sha512-Lq37nKLJOpRFjx3rcg3y+ZwUxBX7jluKfIt5UPp6wb1L3dP0sj1yaLR0Yg2CdGYvHWyUpZD1iTnT8upL0ToDOw==", + "dependencies": { + "err-code": "^3.0.1", + "protons-runtime": "^5.0.0", + "uint8arraylist": "^2.4.3" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/ipfs-unixfs-exporter": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/ipfs-unixfs-exporter/-/ipfs-unixfs-exporter-13.2.2.tgz", + "integrity": "sha512-poCxSte+SdQzuPc/Sm+gx/86VJu+IEsW6/Cfkq29yEUZDG8QuCvTkvuqAysKAYuN40aR9SjYqwYFRW/hsvspSw==", + "dependencies": { + "@ipld/dag-cbor": "^9.0.0", + "@ipld/dag-pb": "^4.0.0", + "@multiformats/murmur3": "^2.0.0", + "err-code": "^3.0.1", + "hamt-sharding": "^3.0.0", + "interface-blockstore": "^5.0.0", + "ipfs-unixfs": "^11.0.0", + "it-filter": "^3.0.2", + "it-last": "^3.0.2", + "it-map": "^3.0.3", + "it-parallel": "^3.0.0", + "it-pipe": "^3.0.1", + "it-pushable": "^3.1.0", + "multiformats": "^12.0.1", + "p-queue": "^7.3.0", + "progress-events": "^1.0.0", + "uint8arrays": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/ipfs-unixfs-importer": { + "version": "15.2.1", + "resolved": "https://registry.npmjs.org/ipfs-unixfs-importer/-/ipfs-unixfs-importer-15.2.1.tgz", + "integrity": "sha512-9ArBh7Xfz8gUSe8pq9c9ilBOXd1bbT3L+4xnI6w/usWLwnNT14p8WbFZjDD0MO1/PrD0PTUZuHNDS2l4EO+wPg==", + "dependencies": { + "@ipld/dag-pb": "^4.0.0", + "@multiformats/murmur3": "^2.0.0", + "err-code": "^3.0.1", + "hamt-sharding": "^3.0.0", + "interface-blockstore": "^5.0.0", + "interface-store": "^5.0.1", + "ipfs-unixfs": "^11.0.0", + "it-all": "^3.0.2", + "it-batch": "^3.0.2", + "it-first": "^3.0.2", + "it-parallel-batch": "^3.0.1", + "multiformats": "^12.0.1", + "progress-events": "^1.0.0", + "rabin-wasm": "^0.1.4", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/it-all": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-all/-/it-all-3.0.4.tgz", + "integrity": "sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ==" + }, + "node_modules/it-batch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-batch/-/it-batch-3.0.4.tgz", + "integrity": "sha512-WRu2mqOYIs+T9k7+yxSK9VJdk0UE4R0jKQsWQcti5c6vhb1FhjC2+yCB5XBrctQ9edNfCMU/wVzdDj8qSwimbA==" + }, + "node_modules/it-drain": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/it-drain/-/it-drain-3.0.5.tgz", + "integrity": "sha512-qYFe4SWdvs9oJGUY5bSjvmiLUMLzFEODNOQUdYdCIkuIgQF+AUB2INhM4yQ09buJ2rhHKDFxvTD/+yUq6qg0XA==" + }, + "node_modules/it-filter": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-filter/-/it-filter-3.0.4.tgz", + "integrity": "sha512-e0sz+st4sudK/zH6GZ/gRTRP8A/ADuJFCYDmRgMbZvR79y5+v4ZXav850bBZk5wL9zXaYZFxS1v/6Qi+Vjwh5g==", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-first": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-first/-/it-first-3.0.4.tgz", + "integrity": "sha512-FtQl84iTNxN5EItP/JgL28V2rzNMkCzTUlNoj41eVdfix2z1DBuLnBqZ0hzYhGGa1rMpbQf0M7CQSA2adlrLJg==" + }, + "node_modules/it-foreach": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/it-foreach/-/it-foreach-2.0.6.tgz", + "integrity": "sha512-OVosBHJsdXpAyeFlCbe3IGZia+65UykyAznakNsKXK+b99dbhuu/mOnXxTadDEo1GWhKx+WA8RNanKkMf07zQw==", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-glob": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/it-glob/-/it-glob-2.0.6.tgz", + "integrity": "sha512-4C6ccz4nhqrq7yZMzBr3MsKhyL+rlnLXIPceyGG6ogl3Lx3eeWMv1RtlySJwFi6q+jVcPyTpeYt/xftwI2JEQQ==", + "dependencies": { + "minimatch": "^9.0.0" + } + }, + "node_modules/it-last": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-last/-/it-last-3.0.4.tgz", + "integrity": "sha512-Ns+KTsQWhs0KCvfv5X3Ck3lpoYxHcp4zUp4d+AOdmC8cXXqDuoZqAjfWhgCbxJubXyIYWdfE2nRcfWqgvZHP8Q==" + }, + "node_modules/it-length-prefixed": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-9.0.3.tgz", + "integrity": "sha512-YAu424ceYpXctxtjcLOqn7vJq082CaoP8J646ZusYISfQc3bpzQErgTUqMFj81V262KG2W9/YMBHsy6A/4yvmg==", + "dependencies": { + "err-code": "^3.0.1", + "it-reader": "^6.0.1", + "it-stream-types": "^2.0.1", + "uint8-varint": "^2.0.1", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-map": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/it-map/-/it-map-3.0.5.tgz", + "integrity": "sha512-hB0TDXo/h4KSJJDSRLgAPmDroiXP6Fx1ck4Bzl3US9hHfZweTKsuiP0y4gXuTMcJlS6vj0bb+f70rhkD47ZA3w==", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-merge": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-3.0.3.tgz", + "integrity": "sha512-FYVU15KC5pb/GQX1Ims+lee8d4pdqGVCpWr0lkNj8o4xuNo7jY71k6GuEiWdP+T7W1bJqewSxX5yoTy5yZpRVA==", + "dependencies": { + "it-pushable": "^3.2.0" + } + }, + "node_modules/it-parallel": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/it-parallel/-/it-parallel-3.0.6.tgz", + "integrity": "sha512-i7UM7I9LTkDJw3YIqXHFAPZX6CWYzGc+X3irdNrVExI4vPazrJdI7t5OqrSVN8CONXLAunCiqaSV/zZRbQR56A==", + "dependencies": { + "p-defer": "^4.0.0" + } + }, + "node_modules/it-parallel-batch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-parallel-batch/-/it-parallel-batch-3.0.4.tgz", + "integrity": "sha512-O1omh8ss8+UtXiMjE+8kM5C20DT0Ma4VtKVfrSHOJU0UHZ+iWBXarabzPYEp+WiuQmrv+klDPPlTZ9KaLN9xOA==", + "dependencies": { + "it-batch": "^3.0.0" + } + }, + "node_modules/it-peekable": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/it-peekable/-/it-peekable-3.0.3.tgz", + "integrity": "sha512-Wx21JX/rMzTEl9flx3DGHuPV1KQFGOl8uoKfQtmZHgPQtGb89eQ6RyVd82h3HuP9Ghpt0WgBDlmmdWeHXqyx7w==" + }, + "node_modules/it-pipe": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-3.0.1.tgz", + "integrity": "sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA==", + "dependencies": { + "it-merge": "^3.0.0", + "it-pushable": "^3.1.2", + "it-stream-types": "^2.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pushable": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.2.3.tgz", + "integrity": "sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg==", + "dependencies": { + "p-defer": "^4.0.0" + } + }, + "node_modules/it-reader": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.4.tgz", + "integrity": "sha512-XCWifEcNFFjjBHtor4Sfaj8rcpt+FkY0L6WdhD578SCDhV4VUm7fCkF3dv5a+fTcfQqvN9BsxBTvWbYO6iCjTg==", + "dependencies": { + "it-stream-types": "^2.0.1", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-stream-types": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.1.tgz", + "integrity": "sha512-6DmOs5r7ERDbvS4q8yLKENcj6Yecr7QQTqWApbZdfAUTEC947d+PEha7PCqhm//9oxaLYL7TWRekwhoXl2s6fg==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-take": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/it-take/-/it-take-3.0.4.tgz", + "integrity": "sha512-RG8HDjAZlvkzz5Nav4xq6gK5zNT+Ff1UTIf+CrSJW8nIl6N1FpBH5e7clUshiCn+MmmMoSdIEpw4UaTolszxhA==" + }, + "node_modules/js2xmlparser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", + "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", + "dev": true, + "dependencies": { + "xmlcreate": "^2.0.4" + } + }, + "node_modules/jsdoc": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", + "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.15", + "@jsdoc/salty": "^0.2.1", + "@types/markdown-it": "^12.2.3", + "bluebird": "^3.7.2", + "catharsis": "^0.9.0", + "escape-string-regexp": "^2.0.0", + "js2xmlparser": "^4.0.2", + "klaw": "^3.0.0", + "markdown-it": "^12.3.2", + "markdown-it-anchor": "^8.4.1", + "marked": "^4.0.10", + "mkdirp": "^1.0.4", + "requizzle": "^0.2.3", + "strip-json-comments": "^3.1.0", + "underscore": "~1.13.2" + }, + "bin": { + "jsdoc": "jsdoc.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/just-debounce-it": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/just-debounce-it/-/just-debounce-it-3.2.0.tgz", + "integrity": "sha512-WXzwLL0745uNuedrCsCs3rpmfD6DBaf7uuVwaq98/8dafURfgQaBsSpjiPp5+CW6Vjltwy9cOGI6qE71b3T8iQ==" + }, + "node_modules/klaw": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", + "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it-anchor": { + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", + "dev": true, + "peerDependencies": { + "@types/markdown-it": "*", + "markdown-it": "*" + } + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multiformats": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-12.1.3.tgz", + "integrity": "sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/murmurhash3js-revisited": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz", + "integrity": "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/p-defer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", + "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-7.4.1.tgz", + "integrity": "sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA==", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^5.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz", + "integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/progress-events": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.0.tgz", + "integrity": "sha512-zIB6QDrSbPfRg+33FZalluFIowkbV5Xh1xSuetjG+rlC5he6u2dc6VQJ0TbMdlN3R1RHdpOqxEFMKTnQ+itUwA==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/protons-runtime": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.2.0.tgz", + "integrity": "sha512-jL3VSbXllgm17zurKQ/z+Ath0w+4BknJ+l/NLocfjAB8hbeASOZTNtb7zK3nDsKq2pHK9YFumNQvpkZ6gFfWhA==", + "dependencies": { + "uint8arraylist": "^2.4.3", + "uint8arrays": "^4.0.6" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/rabin-wasm": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/rabin-wasm/-/rabin-wasm-0.1.5.tgz", + "integrity": "sha512-uWgQTo7pim1Rnj5TuWcCewRDTf0PEFTSlaUjWP4eY9EbLV9em08v89oCz/WO+wRxpYuO36XEHp4wgYQnAgOHzA==", + "dependencies": { + "@assemblyscript/loader": "^0.9.4", + "bl": "^5.0.0", + "debug": "^4.3.1", + "minimist": "^1.2.5", + "node-fetch": "^2.6.1", + "readable-stream": "^3.6.0" + }, + "bin": { + "rabin-wasm": "cli/bin.js" + } + }, + "node_modules/race-signal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/race-signal/-/race-signal-1.0.2.tgz", + "integrity": "sha512-o3xNv0iTcIDQCXFlF6fPAMEBRjFxssgGoRqLbg06m+AdzEXXLUmoNOoUHTVz2NoBI8hHwKFKoC6IqyNtWr2bww==" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/receptacle": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/receptacle/-/receptacle-1.3.2.tgz", + "integrity": "sha512-HrsFvqZZheusncQRiEE7GatOAETrARKV/lnfYicIm8lbvp/JQOdADOfhjBd2DajvoszEyxSM6RlAAIZgEoeu/A==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/requizzle": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", + "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/retimer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/retimer/-/retimer-3.0.0.tgz", + "integrity": "sha512-WKE0j11Pa0ZJI5YIk0nflGI7SQsfl2ljihVy7ogh7DeQSeYAUi0ubZ/yEueGtDfUPk6GH5LRw1hBdLq4IwUBWA==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/showdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", + "dev": true, + "dependencies": { + "commander": "^9.0.0" + }, + "bin": { + "showdown": "bin/showdown.js" + }, + "funding": { + "type": "individual", + "url": "https://www.paypal.me/tiviesantos" + } + }, + "node_modules/showdown/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sparse-array": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/sparse-array/-/sparse-array-1.3.2.tgz", + "integrity": "sha512-ZT711fePGn3+kQyLuv1fpd3rNSkNF8vd5Kv2D+qnOANeyKs3fx6bUMGWRPvgTTcYV64QMqZKZwcuaQSP3AZ0tg==" + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/terser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/timeout-abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/timeout-abort-controller/-/timeout-abort-controller-3.0.0.tgz", + "integrity": "sha512-O3e+2B8BKrQxU2YRyEjC/2yFdb33slI22WRdUaDx6rvysfi9anloNZyR2q0l6LnePo5qH7gSM7uZtvvwZbc2yA==", + "dependencies": { + "retimer": "^3.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/uint8-varint": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.2.tgz", + "integrity": "sha512-LZXmBT0jiHR7J4oKM1GUhtdLFW1yPauzI8NjJlotXn92TprO9u8VMvEVR4QMk8xhUVUd+2fqfU2/kGbVHYSSWw==", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^4.0.2" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.7.tgz", + "integrity": "sha512-ohRElqR6C5dd60vRFLq40MCiSnUe1AzkpHvbCEMCGGP6zMoFYECsjdhL6bR1kTK37ONNRDuHQ3RIpScRYcYYIg==", + "dependencies": { + "uint8arrays": "^4.0.2" + } + }, + "node_modules/uint8arrays": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-4.0.10.tgz", + "integrity": "sha512-AnJNUGGDJAgFw/eWu/Xb9zrVKEGlwJJCaeInlf3BkecE/zcTobk5YXYIPNQJO1q5Hh1QZrQQHf0JvcHqz2hqoA==", + "dependencies": { + "multiformats": "^12.0.1" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/varint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", + "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==" + }, + "node_modules/varint-decoder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/varint-decoder/-/varint-decoder-1.0.0.tgz", + "integrity": "sha512-JkOvdztASWGUAsXshCFHrB9f6AgR2Q8W08CEyJ+43b1qtFocmI8Sp1R/M0E/hDOY2FzVIqk63tOYLgDYWuJ7IQ==", + "dependencies": { + "varint": "^5.0.0" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/varint-decoder/node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/xmlcreate": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", + "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..822f91e --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "@filebase/sdk", + "version": "1.0.0", + "description": "SDK for Interacting with Filebase Services [S3(Buckets, Objects), IPFS(Gateways, Pins) IPNS(Names)]", + "repository": "https://github.com/filebase/filebase-sdk", + "license": "MIT", + "type": "module", + "main": "src/index.js", + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "scripts": { + "test": "node --test", + "doc": "jsdoc -c jsdoc.json" + }, + "keywords": ["filebase", "filebase-sdk", "s3", "ipfs", "ipns", "sdk", "web3", "distributed"], + "devDependencies": { + "clean-jsdoc-theme": "4.2.17", + "jsdoc": "4.0.2", + "prettier": "3.1.0" + }, + "dependencies": { + "@aws-sdk/client-s3": "3.478.0", + "@aws-sdk/lib-storage": "3.478.0", + "@helia/car": "1.0.4", + "@helia/unixfs": "1.4.3", + "@ipld/car": "5.2.4", + "axios": "1.6.2", + "blockstore-fs": "1.1.8", + "uuid": "9.0.1" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..a8774c3 --- /dev/null +++ b/readme.md @@ -0,0 +1,99 @@ +

• Filebase SDK •

+

Developer Friendly [ IPFS | IPNS | S3 ]

+ +## About + +The Filebase SDK provides a hybrid data management solution, blending S3-compatible cloud storage with IPFS +(InterPlanetary File System) pinning services. It features robust S3 bucket management, object handling for uploads and +downloads, and seamless integration with IPFS and IPNS (InterPlanetary Naming System) for decentralized storage +operations. The SDK supports advanced data tasks like compiling files into CAR (Content Addressable aRchive) formats and +ensures secure transactions through strong authentication. Designed for varied applications, the Filebase SDK is ideal +for scenarios demanding the dependability of cloud storage combined with the advantages of decentralized, peer-to-peer +storage, catering to diverse needs such as content distribution, data backup, and archival. Developing InterPlanetary +Applications has never been easier. + +### JS Client + +Install the package using npm + +```shell +npm install @filebase/sdk +``` + +or yarn: + +```shell +yarn add @filebase/sdk +``` + +### Getting started + +The snippet below shows how to create a new bucket with `BucketManager`, upload a new object to IPFS +with `ObjectManager`, publish the object to IPNS with `NameManager`, delete the object with `ObjectManager` and finally +delete the bucket with `BucketManager`. + +To use the library in your project, use npm or yarn to install the [`@filebase/sdk`](https://www.npmjs.com/package/@filebase/sdk) module. Requires node.js 16+. + +**node.js** +````js +// Import Classes +import { + BucketManager, + ObjectManager, + NameManager, + GatewayManager, + PinManager +} from 'filebase-sdk' + +// Initialize BucketManager +const bucketManager = new BucketManager(S3_KEY, S3_SECRET); +// Create bucket +const bucketName = `create-bucket-[random string]`; +await bucketManager.create(bucketName); + +// Initialize ObjectManager +const objectManager = new ObjectManager(S3_KEY, S3_SECRET, { + bucket: bucketName +}); +// Upload Object +const objectName = `new-object`; +const uploadedObject = await objectManager.upload(objectName, body); +// Download Object +await uploadedObject.download(); +// Copy Object to a New Bucket +const bucketCopyDestinationName = `copy-dest-bucket` +await bucketManager.create(bucketCopyDestinationName); +await objectManager.copy(`new-object`, bucketCopyDestinationName); + +// Initialize NameManager +const nameManager = new NameManager(S3_KEY, S3_SECRET); +// Create New IPNS Name with Broadcast Disabled +const ipnsLabel = `myFirstIpnsKey`; +const ipnsName = await nameManager.create(ipnsLabel, uploadedObject.cid, { + enabled: true +}); + +// Initialize GatewayManager +const gatewayManager = new GatewayManager(S3_KEY, S3_SECRET); +// Create New Gateway +const gatewayName = "myRandomGatewayName"; +const myGateway = await gatewayManager.create(gatewayName); + +// Initialize PinManager +const pinManager = new PinManager(S3_KEY, S3_SECRET, { + bucket: bucketName, + gateway: { + endpoint: "https://myRandomGatewayName.myfilebase.com" + } +}); +// Create New Pin with Metadata +const myNewPin = await pinManager.create("my-pin", "QmTJkc7crTuPG7xRmCQSz1yioBpCW3juFBtJPXhQfdCqGF", { + "application": "my-custom-app-on-filebase" +}); +```` + +Full API reference doc for the JS client are available at https://filebase.github.io/filebase-sdk + +### Testing + +Test are found in the `test` directory and are built to be run with the Node.js v20+ test runner. \ No newline at end of file diff --git a/src/bucketManager.js b/src/bucketManager.js new file mode 100644 index 0000000..e248ca3 --- /dev/null +++ b/src/bucketManager.js @@ -0,0 +1,135 @@ +import { + CreateBucketCommand, + DeleteBucketCommand, + GetBucketAclCommand, + ListBucketsCommand, + PutBucketAclCommand, + S3Client, +} from "@aws-sdk/client-s3"; + +/** Provides methods for managing buckets in an S3 endpoint. */ +class BucketManager { + #DEFAULT_ENDPOINT = "https://s3.filebase.com"; + #DEFAULT_REGION = "us-east-1"; + + #client; + + /** + * @summary Creates a new instance of the constructor. + * @param {string} clientKey - The access key ID for authentication. + * @param {string} clientSecret - The secret access key for authentication. + * @tutorial quickstart-bucket + * @example + * import { BucketManager } from "@filebase/sdk"; + * const bucketManager = new BucketManager("KEY_FROM_DASHBOARD", "SECRET_FROM_DASHBOARD"); + */ + constructor(clientKey, clientSecret) { + const clientEndpoint = + process.env.NODE_ENV === "test" + ? process.env.TEST_S3_ENDPOINT || this.#DEFAULT_ENDPOINT + : this.#DEFAULT_ENDPOINT, + clientConfiguration = { + credentials: { + accessKeyId: clientKey, + secretAccessKey: clientSecret, + }, + endpoint: clientEndpoint, + region: this.#DEFAULT_REGION, + forcePathStyle: true, + }; + this.#client = new S3Client(clientConfiguration); + } + + /** + * @typedef {Object} bucket + * @property {string} Name The name of the bucket + * @property {date} Date the bucket was created + */ + + /** + * @summary Creates a new bucket with the specified name. + * @param {string} name - The name of the bucket to create. + * @returns {Promise} - A promise that resolves when the bucket is created. + * @example + * // Create bucket with name of `create-bucket-example` + * await bucketManager.create(`create-bucket-example`); + */ + async create(name) { + const command = new CreateBucketCommand({ + Bucket: name, + }); + + return await this.#client.send(command); + } + + /** + * @summary Lists the buckets in the client. + * @returns {Promise>} - A promise that resolves with an array of objects representing the buckets in the client. + * @example + * // List all buckets + * await bucketManager.list(); + */ + async list() { + const command = new ListBucketsCommand({}), + { Buckets } = await this.#client.send(command); + + return Buckets; + } + + /** + * @summary Deletes the specified bucket. + * @param {string} name - The name of the bucket to delete. + * @returns {Promise} - A promise that resolves when the bucket is deleted. + * @example + * // Delete bucket with name of `bucket-name-to-delete` + * await bucketManager.delete(`bucket-name-to-delete`); + */ + async delete(name) { + const command = new DeleteBucketCommand({ + Bucket: name, + }); + + await this.#client.send(command); + return true; + } + + /** + * @summary Sets the privacy of a given bucket. + * @param {string} name - The name of the bucket to toggle. + * @param {boolean} targetState - The new target state. [true=private,false=public] + * @returns {Promise} A promise that resolves to true if the bucket was successfully toggled. + * @example + * // Toggle bucket with label of `toggle-bucket-example` + * await bucketManager.setPrivacy(`toggle-bucket-example`, true); // Enabled + * await bucketManager.setPrivacy(`toggle-bucket-example`, false); // Disabled + */ + + async setPrivacy(name, targetState) { + const command = new PutBucketAclCommand({ + Bucket: name, + ACL: targetState ? "private" : "public-read", + }); + + await this.#client.send(command); + return true; + } + + /** + * @summary Gets the privacy of a given bucket + * @param {string} name - The name of the bucket to query. + * @returns {Promise} A promise that resolves to true if the bucket is private. + */ + async getPrivacy(name) { + const command = new GetBucketAclCommand({ + Bucket: name, + }); + + const response = await this.#client.send(command), + readPermission = response.Grants.find((grant) => { + return grant.Grantee.Type === "Group" && grant.Permission === "READ"; + }); + return !(typeof readPermission !== "undefined"); + } +} + +export default BucketManager; diff --git a/src/gatewayManager.js b/src/gatewayManager.js new file mode 100644 index 0000000..b87dd29 --- /dev/null +++ b/src/gatewayManager.js @@ -0,0 +1,221 @@ +import axios from "axios"; +import { apiErrorHandler } from "./helpers.js"; + +class GatewayManager { + #DEFAULT_ENDPOINT = "https://api.filebase.io"; + #DEFAULT_TIMEOUT = 60000; + + #client; + + /** + * @summary Creates a new instance of the constructor. + * @param {string} clientKey - The access key ID for authentication. + * @param {string} clientSecret - The secret access key for authentication. + * @tutorial quickstart-gateway + * @example + * import { GatewayManager } from "@filebase/sdk"; + * const gatewayManager = new GatewayManager("KEY_FROM_DASHBOARD", "SECRET_FROM_DASHBOARD"); + */ + constructor(clientKey, clientSecret) { + const clientEndpoint = + process.env.NODE_ENV === "test" + ? process.env.TEST_GW_ENDPOINT || this.#DEFAULT_ENDPOINT + : this.#DEFAULT_ENDPOINT, + encodedToken = Buffer.from(`${clientKey}:${clientSecret}`).toString( + "base64", + ), + baseURL = `${clientEndpoint}/v1/gateways`; + this.#client = axios.create({ + baseURL: baseURL, + timeout: this.#DEFAULT_TIMEOUT, + headers: { Authorization: `Bearer ${encodedToken}` }, + }); + } + + /** + * @typedef {Object} gateway + * @property {string} name Name for the gateway + * @property {string} domain Custom Domain for the gateway + * @property {boolean} enabled Whether the gateway is enabled or not + * @property {string} private Whether the gateway is scoped to users content + * @property {date} created_at Date the gateway was created + * @property {date} updated_at Date the gateway was last updated + */ + + /** + * @typedef {Object} gatewayOptions + * @property {boolean} [domain] Optional Domain to allow for using a Custom Domain + * @property {string} [enabled] Optional Toggle to use for enabling the gateway + * @property {boolean} [private] Optional Boolean determining if gateway is Public or Private + */ + + /** + * @summary Creates a gateway with the given name and options + * @param {string} name Unique name across entire platform for the gateway. Must be a valid subdomain name. + * @param {gatewayOptions} [options] + * @returns {Promise} - A promise that resolves to the value of a gateway. + * @example + * // Create gateway with name of `create-gateway-example` and a custom domain of `cname.mycustomdomain.com`. + * // The custom domain must already exist and have a CNAME record pointed at `create-gateway-example.myfilebase.com`. + * await gatewayManager.create(`create-gateway-example`, { + * domain: `cname.mycustomdomain.com` + * }); + */ + async create(name, options = {}) { + try { + let createOptions = { + name, + }; + if (typeof options.domain === "string") { + createOptions.domain = options.domain; + } + if (typeof options.enabled === "boolean") { + createOptions.enabled = options.enabled; + } + if (typeof options.private === "boolean") { + createOptions.private = options.private; + } + const createResponse = await this.#client.request({ + method: "POST", + data: createOptions, + }); + return createResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Deletes a gateway with the given name. + * @param {string} name - The name of the gateway to delete. + * @returns {Promise} - A promise that resolves to true if the gateway was successfully deleted. + * @example + * // Delete gateway with name of `delete-gateway-example` + * await gatewayManager.delete(`delete-name-example`); + */ + async delete(name) { + try { + await this.#client.request({ + method: "DELETE", + url: `/${name}`, + validateStatus: (status) => { + return status === 204; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Returns the value of a gateway + * @param {string} name - Parameter representing the name to get. + * @returns {Promise} - A promise that resolves to the value of a gateway. + * @example + * // Get gateway with name of `gateway-get-example` + * await gatewayManager.get(`gateway-get-example`); + */ + async get(name) { + try { + const getResponse = await this.#client.request({ + method: "GET", + url: `/${name}`, + validateStatus: (status) => { + return status === 200 || status === 404; + }, + }); + return getResponse.status === 200 ? getResponse.data : false; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Returns a list of gateways + * @returns {Promise>} - A promise that resolves to an array of gateways. + * @example + * // List all gateways + * await gatewayManager.list(); + */ + async list() { + try { + const getResponse = await this.#client.request({ + method: "GET", + }); + return getResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Updates the specified gateway. + * @param {string} name - The name of the gateway to update. + * @param {gatewayOptions} options - The options for the update operation. + * + * @returns {Promise} - A Promise that resolves to true if the gateway was updated. + * @example + * // Update gateway with name of `update-gateway-example` and set the gateway to only serve CIDs pinned by user. + * await gatewayManager.update(`update-gateway-example`, { + * private: true + * }); + */ + async update(name, options) { + try { + const updateOptions = { + name, + }; + if (options?.domain) { + updateOptions.domain = String(options.private); + } + if (options?.enabled) { + updateOptions.enabled = Boolean(options.enabled); + } + if (options?.private) { + updateOptions.private = Boolean(options.private); + } + await this.#client.request({ + method: "PUT", + url: `/${name}`, + data: updateOptions, + validateStatus: (status) => { + return status === 200; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Toggles the enabled state of a given gateway. + * @param {string} name - The name of the gateway to toggle. + * @param {boolean} targetState - The new target state. + * @returns {Promise} A promise that resolves to true if the gateway was successfully toggled. + * @example + * // Toggle gateway with label of `toggle-gateway-example` + * await gatewayManager.toggle(`toggle-gateway-example`, true); // Enabled + * await gatewayManager.toggle(`toggle-gateway-example`, false); // Disabled + */ + async toggle(name, targetState) { + try { + await this.#client.request({ + method: "PUT", + url: `/${name}`, + data: { + enabled: Boolean(targetState), + }, + validateStatus: (status) => { + return status === 200; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } +} + +export default GatewayManager; diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..9f604b2 --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,42 @@ +import axios from "axios"; + +const GATEWAY_DEFAULT_TIMEOUT = 60000; + +async function downloadFromGateway(cid, options) { + if (typeof options.endpoint !== "string") { + throw new Error(`Default Gateway must be set`); + } + + const downloadHeaders = {}; + if (options.token) { + downloadHeaders["x-filebase-gateway-token"] = options.token; + } + + const downloadResponse = await axios.request({ + method: "GET", + baseURL: options.endpoint, + url: `/ipfs/${cid}`, + headers: downloadHeaders, + type: "stream", + timeout: options?.timeout || GATEWAY_DEFAULT_TIMEOUT, + }); + return downloadResponse.data; +} + +function apiErrorHandler(err) { + if ( + err?.response && + err?.response?.status && + (err.response.status.toString()[0] === "4" || + err.response.status.toString()[0] === "5") + ) { + throw new Error( + err.response.data.error?.details || + err.response.data.error?.reason || + err, + ); + } + throw err; +} + +export { downloadFromGateway, apiErrorHandler }; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..8687af6 --- /dev/null +++ b/src/index.js @@ -0,0 +1,13 @@ +import BucketManager from "./bucketManager.js"; +import GatewayManager from "./gatewayManager.js"; +import NameManager from "./nameManager.js"; +import ObjectManager from "./objectManager.js"; +import PinManager from "./pinManager.js"; + +export { + BucketManager, + GatewayManager, + NameManager, + ObjectManager, + PinManager, +}; diff --git a/src/nameManager.js b/src/nameManager.js new file mode 100644 index 0000000..54a02df --- /dev/null +++ b/src/nameManager.js @@ -0,0 +1,251 @@ +import axios from "axios"; +import { apiErrorHandler } from "./helpers.js"; + +/** Provides methods for managing names in an REST endpoint. */ +class NameManager { + #DEFAULT_ENDPOINT = "https://api.filebase.io"; + #DEFAULT_TIMEOUT = 60000; + + #client; + + /** + * @summary Creates a new instance of the constructor. + * @param {string} clientKey - The access key ID for authentication. + * @param {string} clientSecret - The secret access key for authentication. + * @tutorial quickstart-name + * @example + * import { NameManager } from "@filebase/sdk"; + * const nameManager = new NameManager("KEY_FROM_DASHBOARD", "SECRET_FROM_DASHBOARD"); + */ + constructor(clientKey, clientSecret) { + const clientEndpoint = + process.env.NODE_ENV === "test" + ? process.env.TEST_NAME_ENDPOINT || this.#DEFAULT_ENDPOINT + : this.#DEFAULT_ENDPOINT, + encodedToken = Buffer.from(`${clientKey}:${clientSecret}`).toString( + "base64", + ), + baseURL = `${clientEndpoint}/v1/names`; + this.#client = axios.create({ + baseURL: baseURL, + timeout: this.#DEFAULT_TIMEOUT, + headers: { Authorization: `Bearer ${encodedToken}` }, + }); + } + + /** + * @typedef {Object} name + * @property {string} label Descriptive label for the Key + * @property {string} network_key IPNS Key CID + * @property {string} cid Value that name Publishes + * @property {number} sequence Version Number for the name + * @property {boolean} enabled Whether the name is being Published or not + * @property {date} published_at Date the name was last published to the DHT + * @property {date} created_at Date the name was created + * @property {date} updated_at Date the name was last updated + */ + + /** + * @typedef {Object} nameOptions + * @property {boolean} [enabled] Whether the name is enabled or not. + */ + + /** + * @summary Creates a new IPNS name with the given name as the label and CID. + * @param {string} label - The label of the new IPNS name. + * @param {string} cid - The CID of the IPNS name. + * @param {nameOptions} [options] - Additional options for the IPNS name. + * @returns {Promise} - A Promise that resolves with the response JSON. + * @example + * // Create IPNS name with label of `create-name-example` and CID of `QmdmQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7RgQm` + * await nameManager.create(`create-name-example`, `QmdmQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7RgQm`); + */ + async create( + label, + cid, + options = { + enabled: true, + }, + ) { + try { + const createResponse = await this.#client.request({ + method: "POST", + data: { + label, + cid, + enabled: options?.enabled !== false, + }, + }); + return createResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Imports a user's IPNS private key. + * @param {string} label - The label for the IPNS name. + * @param {string} cid - The CID (Content Identifier) of the data. + * @param {string} privateKey - The existing private key encoded in Base64. + * @param {nameOptions} [options] - Additional options for the IPNS name. + * @returns {Promise} - A Promise that resolves to the server response. + * @example + * // Import IPNS private key with label of `create-name-example`, CID of `QmdmQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7RgQm` + * // and a private key encoded with base64 + * await nameManager.import( + * `create-name-example`, + * `QmdmQXB2mzChmMeKY47C43LxUdg1NDJ5MWcKMKxDu7RgQm` + * `BASE64_ENCODED_PRIVATEKEY` + * ); + */ + async import( + label, + cid, + privateKey, + options = { + enabled: true, + }, + ) { + try { + const importResponse = await this.#client.request({ + method: "POST", + data: { + label, + cid, + network_private_key: privateKey, + enabled: options?.enabled !== false, + }, + }); + return importResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Updates the specified name with the given CID. + * @param {string} label - The label of the name to update. + * @param {string} cid - The cid to associate with the name. + * @param {nameOptions} options - The options for the set operation. + * + * @returns {Promise} - A Promise that resolves to true if the IPNS name was updated. + * @example + * // Update name with label of `update-name-example` and set the value of the IPNS name. + * await nameManager.update(`update-name-example`, `bafybeidt4nmaci476lyon2mvgfmwyzysdazienhxs2bqnfpdainzjuwjom`); + */ + async update(label, cid, options = {}) { + try { + const updateOptions = { + cid, + }; + if (options?.enabled) { + updateOptions.enabled = Boolean(options.enabled); + } + await this.#client.request({ + method: "PUT", + url: `/${label}`, + data: updateOptions, + validateStatus: (status) => { + return status === 200; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Returns the value of an IPNS name + * @param {string} label - Parameter representing the label of the name to resolve. + * @returns {Promise} - A promise that resolves to the value of a name. + * @example + * // Get IPNS name with label of `list-name-example` + * await nameManager.get(`list-name-example`); + */ + async get(label) { + try { + const getResponse = await this.#client.request({ + method: "GET", + url: `/${label}`, + validateStatus: (status) => { + return status === 200 || status === 404; + }, + }); + return getResponse.status === 200 ? getResponse.data : false; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Returns a list of IPNS names + * @returns {Promise>} - A promise that resolves to an array of names. + * @example + * // List all IPNS names + * await nameManager.list(); + */ + async list() { + try { + const listResponse = await this.#client.request({ + method: "GET", + }); + return listResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Deletes an IPNS name with the given label. + * @param {string} label - The label of the IPNS name to delete. + * @returns {Promise} - A promise that resolves to true if the IPNS name was successfully deleted. + * @example + * // List IPNS name with label of `delete-name-example` + * await nameManager.delete(`delete-name-example`); + */ + async delete(label) { + try { + await this.#client.request({ + method: "DELETE", + url: `/${label}`, + validateStatus: (status) => { + return status === 204; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Toggles the enabled state of a given IPNS name. + * @param {string} label - The label of the IPNS name to toggle. + * @param {boolean} targetState - The new target state. + * @returns {Promise} A promise that resolves to true if the IPNS name was successfully toggled. + * @example + * // Toggle IPNS name with label of `toggle-name-example` + * await nameManager.toggle(`toggle-name-example`, true); // Enabled + * await nameManager.toggle(`toggle-name-example`, false); // Disabled + */ + async toggle(label, targetState) { + try { + await this.#client.request({ + method: "PUT", + url: `/${label}`, + data: { + enabled: targetState, + }, + validateStatus: (status) => { + return status === 200; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } +} + +export default NameManager; diff --git a/src/objectManager.js b/src/objectManager.js new file mode 100644 index 0000000..ab00cd4 --- /dev/null +++ b/src/objectManager.js @@ -0,0 +1,440 @@ +// S3 Imports +import { + CopyObjectCommand, + DeleteObjectCommand, + GetObjectCommand, + HeadObjectCommand, + ListObjectsV2Command, + S3Client, +} from "@aws-sdk/client-s3"; +import { Upload } from "@aws-sdk/lib-storage"; +// Helia Imports +import { CarWriter } from "@ipld/car"; +import { car } from "@helia/car"; +import { unixfs } from "@helia/unixfs"; +import { FsBlockstore } from "blockstore-fs"; +// Utility Imports +import { createReadStream, createWriteStream } from "node:fs"; +import { mkdir, rm } from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { Readable } from "node:stream"; +import { v4 as uuidv4 } from "uuid"; +import { downloadFromGateway } from "./helpers.js"; + +/** Interacts with an S3 client to perform various operations on objects in a bucket. */ +class ObjectManager { + #DEFAULT_ENDPOINT = "https://s3.filebase.com"; + #DEFAULT_REGION = "us-east-1"; + #DEFAULT_MAX_CONCURRENT_UPLOADS = 4; + + #client; + #credentials; + #defaultBucket; + #gatewayConfiguration; + #maxConcurrentUploads; + + /** + * @typedef {Object} objectManagerOptions Optional settings for the constructor. + * @property {string} [bucket] Default bucket to use. + * @property {objectDownloadOptions} [gateway] Default gateway to use. + * @property {number} [maxConcurrentUploads] The maximum number of concurrent uploads. + */ + + /** + * @typedef {Object} objectDownloadOptions Optional settings for downloading objects + * @property {string} endpoint Default gateway to use. + * @property {string} [token] Token for the default gateway. + * @property {number} [timeout=60000] Timeout for the default gateway + */ + + /** + * @summary Creates a new instance of the constructor. + * @param {string} clientKey - The access key ID for authentication. + * @param {string} clientSecret - The secret access key for authentication. + * @param {objectManagerOptions} options - Optional settings for the constructor. + * @tutorial quickstart-object + * @example + * import { ObjectManager } from "@filebase/sdk"; + * const objectManager = new ObjectManager("KEY_FROM_DASHBOARD", "SECRET_FROM_DASHBOARD", { + * bucket: "my-default-bucket", + * maxConcurrentUploads: 4, + * gateway: { + * endpoint: "https://my-default-gateway.mydomain.com + * token: SUPER_SECRET_GATEWAY_TOKEN + * } + * }); + */ + constructor(clientKey, clientSecret, options) { + const clientEndpoint = + process.env.NODE_ENV === "test" + ? process.env.TEST_S3_ENDPOINT || this.#DEFAULT_ENDPOINT + : this.#DEFAULT_ENDPOINT, + clientConfiguration = { + credentials: { + accessKeyId: clientKey, + secretAccessKey: clientSecret, + }, + endpoint: clientEndpoint, + region: this.#DEFAULT_REGION, + forcePathStyle: true, + }; + this.#defaultBucket = options?.bucket; + this.#maxConcurrentUploads = + options?.maxConcurrentUploads || this.#DEFAULT_MAX_CONCURRENT_UPLOADS; + this.#credentials = { + key: clientKey, + secret: clientSecret, + }; + this.#client = new S3Client(clientConfiguration); + + this.#gatewayConfiguration = { + endpoint: options?.gateway?.endpoint, + token: options?.gateway?.token, + timeout: options?.gateway?.timeout, + }; + } + + /** + * @typedef {Object} objectOptions + * @property {string} [bucket] - The bucket to pin the IPFS CID into. + */ + + /** + * @typedef {Object} objectHeadResult + * @property {string} cid The CID of the uploaded object + * @property {function} download Convenience function to download the object via S3 or the selected gateway + * @property {array} [entries] If a directory then returns an array of the containing objects + * @property {string} entries.cid The CID of the uploaded object + * @property {string} entries.path The path of the object + */ + + /** + * If the source parameter is an array of objects, it will pack multiple files into a CAR file for upload. + * The method returns a Promise that resolves to an object containing the CID (Content Identifier) of the uploaded file + * and an optional entries object when uploading a CAR file. + * + * @summary Uploads a file or a CAR file to the specified bucket. + * @param {string} key - The key or path of the file in the bucket. + * @param {Buffer|ReadableStream|Array} source - The content of the object to be uploaded. + * If an array of files is provided, each file should have a 'path' property specifying the path of the file + * and a 'content' property specifying the content of the file. The SDK will then construct a CAR file locally + * and use that as the content of the object to be uploaded. + * @param {Object} [metadata] Optional metadata for pin object + * @param {objectOptions} [options] - The options for uploading the object. + * @returns {Promise} + * @example + * // Upload Object + * await objectManager.upload("my-object", Buffer.from("Hello World!")); + * // Upload Object with Metadata + * await objectManager.upload("my-custom-object", Buffer.from("Hello Big World!"), { + * "application": "my-filebase-app" + * }); + * // Upload Directory + * await objectManager.upload("my-first-directory", [ + * { + * path: "/testObjects/1.txt", + * content: Buffer.from("upload test object", "utf-8"), + * }, + * { + * path: "/testObjects/deep/1.txt", + * content: Buffer.from("upload deep test object", "utf-8"), + * }, + * { + * path: "/topLevel.txt", + * content: Buffer.from("upload top level test object", "utf-8"), + * }, + * ]); + */ + async upload(key, source, metadata, options) { + // Generate Upload UUID + const uploadUUID = uuidv4(); + + // Setup Upload Options + const bucket = options?.bucket || this.#defaultBucket, + uploadOptions = { + client: this.#client, + params: { + Bucket: bucket, + Key: key, + Body: source, + Metadata: metadata || {}, + }, + queueSize: this.#maxConcurrentUploads, + partSize: 26843546, //25.6Mb || 250Gb Max File Size + }; + + // Pack Multiple Files into CAR file for upload + let parsedEntries = {}; + if (Array.isArray(source)) { + // Mark Upload as a CAR file import + uploadOptions.params.Metadata = { + ...uploadOptions.params.Metadata, + import: "car", + }; + + let temporaryCarFilePath, temporaryBlockstoreDir; + try { + // Setup Blockstore + temporaryBlockstoreDir = path.resolve( + os.tmpdir(), + "filebase-sdk", + "uploads", + uploadUUID, + ); + temporaryCarFilePath = `${temporaryBlockstoreDir}/main.car`; + await mkdir(temporaryBlockstoreDir, { recursive: true }); + const temporaryBlockstore = new FsBlockstore(temporaryBlockstoreDir); + + const heliaFs = unixfs({ + blockstore: temporaryBlockstore, + }); + + for (let sourceEntry of source) { + sourceEntry.path = + sourceEntry.path[0] === "/" + ? `/${uploadUUID}${sourceEntry.path}` + : `/${uploadUUID}/${sourceEntry.path}`; + } + for await (const entry of heliaFs.addAll(source)) { + parsedEntries[entry.path] = entry; + } + const rootEntry = parsedEntries[uploadUUID]; + + // Get carFile stream here + const carExporter = car({ blockstore: temporaryBlockstore }), + { writer, out } = CarWriter.create([rootEntry.cid]); + + // Put carFile stream to disk + const output = createWriteStream(temporaryCarFilePath); + Readable.from(out).pipe(output); + await carExporter.export(rootEntry.cid, writer); + + // Set Uploader to Read from carFile on disk + uploadOptions.params.Body = createReadStream(temporaryCarFilePath); + + // Upload carFile via S3 + const parallelUploads3 = new Upload(uploadOptions); + await parallelUploads3.done(); + await temporaryBlockstore.close(); + } finally { + if (typeof temporaryBlockstoreDir !== "undefined") { + // Delete Temporary Blockstore + await rm(temporaryBlockstoreDir, { recursive: true, force: true }); + } + } + } else { + // Upload file via S3 + const parallelUploads3 = new Upload(uploadOptions); + await parallelUploads3.done(); + } + + // Get CID from Platform + const command = new HeadObjectCommand({ + Bucket: bucket, + Key: key, + Body: source, + }), + headResult = await this.#client.send(command), + responseCid = headResult.Metadata.cid; + + if (Object.keys(parsedEntries).length === 0) { + return { + cid: responseCid, + download: () => { + return this.#routeDownload(responseCid, key, options); + }, + }; + } + return { + cid: responseCid, + download: () => { + return this.#routeDownload(responseCid, key, options); + }, + entries: parsedEntries, + }; + } + + async #routeDownload(cid, key, options) { + return typeof this.#gatewayConfiguration.endpoint !== "undefined" + ? downloadFromGateway(cid, this.#gatewayConfiguration) + : this.download(key, options); + } + + /** + * @summary Gets an objects info and metadata using the S3 API. + * @param {string} key - The key of the object to be inspected. + * @param {objectOptions} [options] - The options for inspecting the object. + * @returns {Promise} + */ + async get(key, options) { + const bucket = options?.bucket || this.#defaultBucket; + try { + const command = new HeadObjectCommand({ + Bucket: bucket, + Key: key, + }), + response = await this.#client.send(command); + + response.download = () => { + return this.#routeDownload(response.Metadata.cid, key, options); + }; + + return response; + } catch (err) { + if (err.name === "NotFound") { + return false; + } + throw err; + } + } + + /** + * @summary Downloads an object from the specified bucket using the provided key. + * @param {string} key - The key of the object to be downloaded. + * @param {objectOptions} [options] - The options for downloading the object.. + * @returns {Promise} - A promise that resolves with the contents of the downloaded object as a Stream. + * @example + * // Download object with name of `download-object-example` + * await objectManager.download(`download-object-example`); + */ + async download(key, options) { + // Download via IPFS Gateway if Setup or S3 by Default + if (typeof this.#gatewayConfiguration.endpoint === "string") { + const objectToFetch = await this.get(key, options); + return objectToFetch.download(); + } else { + const command = new GetObjectCommand({ + Bucket: options?.bucket || this.#defaultBucket, + Key: key, + }), + response = await this.#client.send(command); + + return response.Body; + } + } + + /** + * @typedef {Object} listObjectsResult + * @property {boolean} IsTruncated Indicates if more results exist on the server + * @property {string} NextContinuationToken ContinuationToken used to paginate list requests + * @property {Array} Contents List of Keys stored in the S3 Bucket + * @property {string} Contents.Key Key of the Object + * @property {string} Contents.LastModified Date Last Modified of the Object + * @property {string} Contents.CID CID of the Object + * @property {string} Contents.ETag ETag of the Object + * @property {number} Contents.Size Size in Bytes of the Object + * @property {string} Contents.StorageClass Class of Storage of the Object + * @property {function} Contents.download Convenience function to download the item using the S3 gateway + */ + + /** + * @typedef {Object} listObjectOptions + * @property {string} [Bucket] The name of the bucket. If not provided, the default bucket will be used. + * @property {string} [ContinuationToken=null] Continues listing from this objects name. + * @property {string} [Delimiter=null] Character used to group keys + * @property {number} [MaxKeys=1000] The maximum number of objects to retrieve. Defaults to 1000. + */ + + /** + * Retrieves a list of objects from a specified bucket. + * + * @param {listObjectOptions} options - The options for listing objects. + * @returns {Promise} - A promise that resolves to an array of objects. + * @example + * // List objects in bucket with a limit of 1000 + * await objectManager.list({ + * MaxKeys: 1000 + * }); + */ + async list( + options = { + Bucket: this.#defaultBucket, + ContinuationToken: null, + Delimiter: null, + MaxKeys: 1000, + }, + ) { + if (options?.MaxKeys && options.MaxKeys > 100000) { + throw new Error(`MaxKeys Maximum value is 100000`); + } + const bucket = options?.Bucket || this.#defaultBucket, + limit = options?.MaxKeys || 1000, + commandOptions = { + Bucket: bucket, + MaxKeys: limit, + }, + command = new ListObjectsV2Command({ + ...options, + ...commandOptions, + }); + + const { Contents, IsTruncated, NextContinuationToken } = + await this.#client.send(command); + return { Contents, IsTruncated, NextContinuationToken }; + } + + /** + * @summary Deletes an object from the specified bucket using the provided key. + * @param {string} key - The key of the object to be deleted. + * @param {objectOptions} [options] - The options for deleting the file. + * @returns {Promise} - A Promise that resolves with the result of the delete operation. + * @example + * // Delete object with name of `delete-object-example` + * await objectManager.delete(`delete-object-example`); + */ + async delete(key, options) { + const command = new DeleteObjectCommand({ + Bucket: options?.bucket || this.#defaultBucket, + Key: key, + }); + + await this.#client.send(command); + return true; + } + + /** + * @typedef {Object} copyObjectOptions + * @property {string} [sourceBucket] The source bucket from where the object is to be copied. + * @property {string} [destinationKey] The key of the object in the destination bucket. By default, it is the same as the sourceKey. + */ + + /** + * If the destinationKey is not provided, the object will be copied with the same key as the sourceKey. + * + * @summary Copy the object from sourceKey in the sourceBucket to destinationKey in the destinationBucket. + * @param {string} sourceKey - The key of the object to be copied from the sourceBucket. + * @param {string} destinationBucket - The bucket where the object will be copied to. + * @param {copyObjectOptions} [options] - Additional options for the copy operation. + * + * @returns {Promise} - A Promise that resolves with the result of the copy operation. + * @example + * // Copy object `copy-object-test` from `copy-object-test-pass-src` to `copy-object-test-pass-dest` + * // TIP: Set bucket on constructor and it will be used as the default source for copying objects. + * await objectManager.copy(`copy-object-test`, `copy-object-dest`, { + * sourceBucket: `copy-object-src` + * }); + */ + async copy( + sourceKey, + destinationBucket, + options = { + sourceBucket: this.#defaultBucket, + destinationKey: undefined, + }, + ) { + const copySource = `${ + options?.sourceBucket || this.#defaultBucket + }/${sourceKey}`, + command = new CopyObjectCommand({ + CopySource: copySource, + Bucket: destinationBucket, + Key: options?.destinationKey || sourceKey, + }); + + await this.#client.send(command); + return true; + } +} + +export default ObjectManager; diff --git a/src/pinManager.js b/src/pinManager.js new file mode 100644 index 0000000..6255020 --- /dev/null +++ b/src/pinManager.js @@ -0,0 +1,298 @@ +import axios from "axios"; +import { apiErrorHandler, downloadFromGateway } from "./helpers.js"; + +/** Provides methods for managing pins in an REST endpoint. */ +class PinManager { + #DEFAULT_ENDPOINT = "https://api.filebase.io"; + #DEFAULT_TIMEOUT = 60000; + + #client; + #credentials; + #gatewayConfiguration; + #defaultBucket; + + /** + * @typedef {Object} pinManagerOptions Optional settings for the constructor. + * @property {string} [bucket] Default bucket to use. + * @property {pinDownloadOptions} [gateway] Default gateway to use. + */ + + /** + * @typedef {Object} pinDownloadOptions Optional settings for downloading pins + * @property {string} endpoint Default gateway to use. + * @property {string} [token] Token for the default gateway. + * @property {number} [timeout=60000] Timeout for the default gateway + */ + + /** + * @summary Creates a new instance of the constructor. + * @param {string} clientKey - The access key ID for authentication. + * @param {string} clientSecret - The secret access key for authentication. + * @param {pinManagerOptions} [options] - Optional settings for the constructor. + * @tutorial quickstart-pin + * @example + * import { PinManager } from "@filebase/sdk"; + * const pinManager = new PinManager("KEY_FROM_DASHBOARD", "SECRET_FROM_DASHBOARD", { + * bucket: "my-default-bucket", + * gateway: { + * endpoint: "https://my-default-gateway.mydomain.com + * token: SUPER_SECRET_GATEWAY_TOKEN + * } + * }); + */ + constructor(clientKey, clientSecret, options) { + this.#defaultBucket = options?.bucket; + const PSAClientEndpoint = + process.env.NODE_ENV === "test" + ? process.env.TEST_NAME_ENDPOINT || this.#DEFAULT_ENDPOINT + : this.#DEFAULT_ENDPOINT, + baseURL = `${PSAClientEndpoint}/v1/ipfs/pins`; + this.#credentials = { + key: clientKey, + secret: clientSecret, + }; + this.#client = axios.create({ + baseURL: baseURL, + timeout: this.#DEFAULT_TIMEOUT, + }); + + this.#gatewayConfiguration = { + endpoint: options?.gateway?.endpoint, + token: options?.gateway?.token, + timeout: options?.gateway?.timeout || this.#DEFAULT_TIMEOUT, + }; + } + + /** + * @typedef {Object} pinStatus + * @property {string} requestid Globally unique identifier of the pin request; can be used to check the status of ongoing pinning, or pin removal + * @property {string} status Status a pin object can have at a pinning service. ("queued","pinning","pinned","failed") + * @property {string} created Immutable timestamp indicating when a pin request entered a pinning service; can be used for filtering results and pagination + * @property {Object} pin Pin object + * @property {string} pin.cid Content Identifier (CID) pinned recursively + * @property {string} pin.name Name for pinned data; can be used for lookups later + * @property {Array} pin.origins Optional list of multiaddrs known to provide the data + * @property {Object} pin.meta Optional metadata for pin object + * @property {Array} delegates List of multiaddrs designated by pinning service that will receive the pin data + * @property {object} [info] Optional info for PinStatus response + * @property {function} download Convenience function to download pin + */ + + /** + * @typedef {Object} pinOptions + * @property {string} [bucket] - The bucket to pin the IPFS CID into. + */ + + /** + * @typedef {Object} listPinOptions + * @property {Array} [cid] Return pin objects responsible for pinning the specified CID(s); be aware that using longer hash functions introduces further constraints on the number of CIDs that will fit under the limit of 2000 characters per URL in browser contexts + * @property {string} [name] Return pin objects with specified name (by default a case-sensitive, exact match) + * @property {string} [match] Customize the text matching strategy applied when the name filter is present; exact (the default) is a case-sensitive exact match, partial matches anywhere in the name, iexact and ipartial are case-insensitive versions of the exact and partial strategies + * @property {Array} [status] Return pin objects for pins with the specified status (when missing, service defaults to pinned only) + * @property {string} [before] Return results created (queued) before provided timestamp + * @property {string} [after] Return results created (queued) after provided timestamp + * @property {number} [limit] Max records to return + * @property {Object} [meta] Return pin objects that match specified metadata keys passed as a string representation of a JSON object; when implementing a client library, make sure the parameter is URL-encoded to ensure safe transport + */ + + /** + * @typedef {Object} listPinResults + * @property {number} count Total number of pin objects that exist for passed query filters + * @property {Array} Array of PinStatus results + */ + + /** + * @summary List the pins in a given bucket + * @param {listPinOptions} [listOptions] + * @param {pinOptions} [options] + * @returns {Promise} + * @example + * // List pins in bucket with a limit of 1000 + * await pinManager.list({ + * limit: 1000 + * }); + */ + async list(listOptions, options) { + try { + const encodedToken = this.#getEncodedToken(options?.bucket), + getResponse = await this.#client.request({ + method: "GET", + params: listOptions, + headers: { Authorization: `Bearer ${encodedToken}` }, + }); + for (let pinStatus of getResponse.data.results) { + pinStatus.download = () => { + return this.download(pinStatus.pin.cid); + }; + } + return getResponse.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Create a pin in the selected bucket + * @param {string} key Key or path of the file in the bucket + * @param {string} cid Content Identifier (CID) to be pinned recursively + * @param {Object} [metadata] Optional metadata for pin object + * @param {pinOptions} [options] Options for pinning the object + * @returns {Promise} + * @example + * // Create Pin with Metadata + * await pinManager.create("my-pin", "QmTJkc7crTuPG7xRmCQSz1yioBpCW3juFBtJPXhQfdCqGF", { + * "application": "my-custom-app-on-filebase" + * }); + */ + async create(key, cid, metadata, options) { + try { + const encodedToken = this.#getEncodedToken(options?.bucket), + pinStatus = await this.#client.request({ + method: "POST", + data: { + cid, + name: key, + meta: metadata, + }, + headers: { Authorization: `Bearer ${encodedToken}` }, + }); + pinStatus.data.download = () => { + return this.download(pinStatus.data.pin.cid); + }; + return pinStatus.data; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @typedef {Object} replacePinOptions + * @augments pinOptions + * @property {Object} [metadata] Optional metadata to set on pin during replacement + * @property {string} [name] Optional name for pin to set during replacement + */ + + /** + * @summary Replace a pinned object in the selected bucket + * @param {string} requestid Unique ID for the pinned object + * @param {string} cid Content Identifier (CID) to be pinned recursively + * @param {replacePinOptions} [options] Options for pinning the object + * @returns {Promise} + * @example + * // Replace Pin with Metadata + * await pinManager.create("qr4231213", "QmTJkc7crTuPG7xRmCQSz1yioBpCW3juFBtJPXhQfdCqGF", { + * "revision": Date.now() + * } + */ + async replace(requestid, cid, options) { + try { + let replaceData = { + cid, + meta: options?.metadata || {}, + }; + if (options?.name) { + replaceData.name = options.name; + } + + const encodedToken = this.#getEncodedToken(options?.bucket), + pinStatusResult = await this.#client.request({ + method: "POST", + url: `/${requestid}`, + data: replaceData, + validateStatus: (status) => { + return status === 200; + }, + headers: { Authorization: `Bearer ${encodedToken}` }, + }); + const pinStatus = pinStatusResult.data; + pinStatus.download = () => { + return this.download(pinStatus.pin.cid); + }; + return pinStatus; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Download a pin from the selected IPFS gateway + * @param {string} cid + * @param {pinDownloadOptions} [options] + * @returns {Promise} + * @example + * // Download Pin by CID + * await pinManager.download("QmTJkc7crTuPG7xRmCQSz1yioBpCW3juFBtJPXhQfdCqGF"); + */ + async download(cid, options) { + const downloadOptions = Object.assign(this.#gatewayConfiguration, options); + return downloadFromGateway(cid, downloadOptions); + } + + /** + * @summary Get details about a pinned object + * @param {string} requestid Globally unique identifier of the pin request + * @param {pinOptions} [options] Options for getting the pin + * @returns {Promise} + * @example + * // Get Pin Info by RequestId + * await pinManager.get("qr4231214"); + */ + async get(requestid, options) { + try { + const encodedToken = this.#getEncodedToken(options?.bucket), + getResponseResult = await this.#client.request({ + method: "GET", + url: `/${requestid}`, + headers: { Authorization: `Bearer ${encodedToken}` }, + validateStatus: (status) => { + return status === 200 || status === 404; + }, + }); + if (getResponseResult.status === 404) { + return false; + } + const pinStatus = getResponseResult.data; + pinStatus.download = () => { + return this.download(pinStatus.pin.cid); + }; + return pinStatus; + } catch (err) { + apiErrorHandler(err); + } + } + + /** + * @summary Delete a pinned object from the selected bucket + * @param requestid Globally unique identifier of the pin request + * @param {pinOptions} [options] Options for deleting the pin + * @returns {Promise} + * @example + * // Delete Pin by RequestId + * await pinManager.delete("qr4231213"); + */ + async delete(requestid, options) { + try { + const encodedToken = this.#getEncodedToken(options?.bucket); + await this.#client.request({ + method: "DELETE", + url: `/${requestid}`, + headers: { Authorization: `Bearer ${encodedToken}` }, + validateStatus: (status) => { + return status === 202; + }, + }); + return true; + } catch (err) { + apiErrorHandler(err); + } + } + + #getEncodedToken(bucket) { + bucket = bucket || this.#defaultBucket; + return Buffer.from( + `${this.#credentials.key}:${this.#credentials.secret}:${bucket}`, + ).toString("base64"); + } +} + +export default PinManager; diff --git a/test/bucketManager.spec.js b/test/bucketManager.spec.js new file mode 100644 index 0000000..71e2d6f --- /dev/null +++ b/test/bucketManager.spec.js @@ -0,0 +1,125 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import BucketManager from "../src/bucketManager.js"; +import GatewayManager from "../src/gatewayManager.js"; + +const TEST_PREFIX = Date.now(); + +test("create bucket", async (t) => { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Create bucket `create-bucket-test-pass` + const bucketNameToCreate = `${TEST_PREFIX}-create-bucket-test-pass`; + await bucketManager.create(bucketNameToCreate); + + try { + // List buckets + const currentBuckets = await bucketManager.list(), + createdBucket = currentBuckets.find((currentBucket) => { + return currentBucket.Name === bucketNameToCreate; + }); + + // Assert new bucket exists + assert.equal(createdBucket.Name, bucketNameToCreate); + } finally { + // Delete new bucket + await bucketManager.delete(bucketNameToCreate); + } +}); + +test("list buckets", async () => { + const testBucketName = `${TEST_PREFIX}-list-bucket-test-pass`, + bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ), + initialBucketsList = await bucketManager.list(), + countToCreate = 3; + for (let i = 0; i < countToCreate; i++) { + await bucketManager.create(`${testBucketName}-${i}`); + } + const bucketsList = await bucketManager.list(); + for (let i = 0; i < countToCreate; i++) { + await bucketManager.delete(`${testBucketName}-${i}`); + } + assert.strictEqual( + bucketsList.length, + initialBucketsList.length + countToCreate, + ); +}); + +test("delete bucket", async (t) => { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Create bucket `delete-bucket-test-pass` + const bucketNameToCreate = `${TEST_PREFIX}-delete-bucket-test-pass`; + await bucketManager.create(bucketNameToCreate); + + // List buckets and assert new bucket exists + const currentBuckets = await bucketManager.list(), + createdBucket = currentBuckets.find((currentBucket) => { + return currentBucket.Name === bucketNameToCreate; + }); + if (typeof createdBucket === "undefined") { + throw new Error(`Unable to create test bucket [delete-bucket-test-pass]`); + } + + // Delete new bucket + await bucketManager.delete(bucketNameToCreate); + + // List buckets and assert new bucket does not exist + const updatedBuckets = await bucketManager.list(), + deletedBucket = updatedBuckets.find((updatedBucket) => { + return updatedBucket.Name === bucketNameToCreate; + }); + assert.equal(typeof deletedBucket, "undefined"); +}); + +test("set bucket privacy to public", async (t) => { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Create bucket `toggle-bucket-test-pass` + const bucketNameToCreate = `${TEST_PREFIX}-toggle-bucket-test-pass`; + await bucketManager.create(bucketNameToCreate); + + try { + // List buckets + const currentBuckets = await bucketManager.list(), + createdBucket = currentBuckets.find((currentBucket) => { + return currentBucket.Name === bucketNameToCreate; + }); + + // Check Privacy + const initialPrivacy = await bucketManager.getPrivacy(bucketNameToCreate); + if (initialPrivacy === false) { + throw new Error(`Unexpected Privacy State on Bucket`); + } + + // Toggle Privacy + await bucketManager.setPrivacy(bucketNameToCreate, false); + + // Check Privacy + const updatedPrivacy = await bucketManager.getPrivacy(bucketNameToCreate); + if (updatedPrivacy === true) { + throw new Error(`Unexpected Privacy State on Bucket`); + } + + // Assert new bucket exists + assert.equal(createdBucket.Name, bucketNameToCreate); + } finally { + // Delete new bucket + await bucketManager.delete(bucketNameToCreate); + } +}); diff --git a/test/gatewayManager.spec.js b/test/gatewayManager.spec.js new file mode 100644 index 0000000..73840bd --- /dev/null +++ b/test/gatewayManager.spec.js @@ -0,0 +1,125 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import GatewayManager from "../src/gatewayManager.js"; + +const TEST_PREFIX = Date.now(); + +test("delete gateway", async () => { + const testGatewayName = `${TEST_PREFIX}-delete-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ); + await gatewayManager.create(testGatewayName); + await gatewayManager.delete(testGatewayName); + const deletedName = await gatewayManager.get(testGatewayName); + assert.strictEqual(deletedName, false); +}); +test("create gateway", async () => { + const testGatewayName = `${TEST_PREFIX}-create-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ), + createdName = await gatewayManager.create(testGatewayName); + await gatewayManager.delete(testGatewayName); + assert.strictEqual(createdName.name, testGatewayName); +}); + +test("update gateway", async () => { + const testGatewayName = `${TEST_PREFIX}-update-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ), + createdName = await gatewayManager.create(testGatewayName); + try { + const updatedName = await gatewayManager.update(createdName.name, { + private: true, + enabled: false, + }); + assert.strictEqual(updatedName, true); + } finally { + await gatewayManager.delete(testGatewayName); + } +}); + +test("get gateway", async () => { + const testGatewayName = `${TEST_PREFIX}-get-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ), + createdName = await gatewayManager.create(testGatewayName, {}); + try { + const testName = await gatewayManager.get(createdName.name); + assert.strictEqual(testName.name, testGatewayName); + } finally { + await gatewayManager.delete(testGatewayName); + } +}); + +test("list gateways", async () => { + const testGatewayName = `${TEST_PREFIX}-list-names-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ), + initialGatewaysList = await gatewayManager.list(), + countToCreate = 3; + for (let i = 0; i < countToCreate; i++) { + await gatewayManager.create(`${testGatewayName}-${i}`); + } + const gatewaysList = await gatewayManager.list(); + for (let i = 0; i < countToCreate; i++) { + await gatewayManager.delete(`${testGatewayName}-${i}`); + } + assert.strictEqual( + gatewaysList.length, + initialGatewaysList.length + countToCreate, + ); +}); + +test("toggle gateway off", async () => { + const testGatewayName = `${TEST_PREFIX}-toggle-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ); + await gatewayManager.create(testGatewayName); + try { + const resolvedName = await gatewayManager.get(testGatewayName); + if (resolvedName?.enabled === false) { + throw new Error(`Incorrect State on Resolved Name`); + } + await gatewayManager.toggle(testGatewayName, false); + const updatedName = await gatewayManager.get(testGatewayName); + assert.strictEqual(updatedName.name, testGatewayName); + assert.strictEqual(updatedName.enabled, false); + } finally { + await gatewayManager.delete(testGatewayName); + } +}); + +test("toggle gateway on", async () => { + const testGatewayName = `${TEST_PREFIX}-toggle-gateway-test-pass`, + gatewayManager = new GatewayManager( + process.env.TEST_GW_KEY || process.env.TEST_KEY, + process.env.TEST_GW_SECRET || process.env.TEST_SECRET, + ); + await gatewayManager.create(testGatewayName, { + enabled: false, + }); + try { + const resolvedName = await gatewayManager.get(testGatewayName); + if (resolvedName?.enabled === true) { + throw new Error(`Incorrect State on Resolved Name`); + } + await gatewayManager.toggle(testGatewayName, true); + const updatedName = await gatewayManager.get(testGatewayName); + assert.strictEqual(updatedName.name, testGatewayName); + assert.strictEqual(updatedName.enabled, true); + } finally { + await gatewayManager.delete(testGatewayName); + } +}); diff --git a/test/nameManager.spec.js b/test/nameManager.spec.js new file mode 100644 index 0000000..0b77658 --- /dev/null +++ b/test/nameManager.spec.js @@ -0,0 +1,141 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import NameManager from "../src/nameManager.js"; + +const TEST_CID = process.env.TEST_NAME_CID, + TEST_PRIVATE_KEY = process.env.TEST_NAME_PRIVATE_KEY, + TEST_PREFIX = Date.now(); + +test("delete name", async () => { + const testNameLabel = `${TEST_PREFIX}-delete-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ); + await nameManager.create(testNameLabel, TEST_CID); + await nameManager.delete(testNameLabel); + const deletedName = await nameManager.get(testNameLabel); + assert.strictEqual(deletedName, false); +}); +test("create name", async () => { + const testNameLabel = `${TEST_PREFIX}-create-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ), + createdName = await nameManager.create(testNameLabel, TEST_CID); + await nameManager.delete(testNameLabel); + assert.strictEqual(createdName.label, testNameLabel); + assert.strictEqual(createdName.cid, TEST_CID); +}); + +test("import name", async () => { + const testNameLabel = `${TEST_PREFIX}-import-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ), + importedName = await nameManager.import( + testNameLabel, + TEST_CID, + TEST_PRIVATE_KEY, + ); + await nameManager.delete(testNameLabel); + assert.strictEqual(importedName.label, testNameLabel); + assert.strictEqual(importedName.cid, TEST_CID); +}); + +test("update name", async () => { + const testNameLabel = `${TEST_PREFIX}-update-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ), + createdName = await nameManager.create(testNameLabel, TEST_CID); + try { + const updatedName = await nameManager.update(createdName.label, TEST_CID); + assert.strictEqual(updatedName, true); + } finally { + await nameManager.delete(testNameLabel); + } +}); + +test("get name", async () => { + const testNameLabel = `${TEST_PREFIX}-get-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ), + createdName = await nameManager.create(testNameLabel, TEST_CID); + try { + const testName = await nameManager.get(createdName.label); + assert.strictEqual(testName.label, testNameLabel); + assert.strictEqual(testName.cid, TEST_CID); + } finally { + await nameManager.delete(testNameLabel); + } +}); + +test("list names", async () => { + const testNameLabel = `${TEST_PREFIX}-list-names-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ), + initialNamesList = await nameManager.list(), + countToCreate = 3; + for (let i = 0; i < countToCreate; i++) { + await nameManager.create(`${testNameLabel}-${i}`, TEST_CID); + } + const namesList = await nameManager.list(); + for (let i = 0; i < countToCreate; i++) { + await nameManager.delete(`${testNameLabel}-${i}`); + } + assert.strictEqual(namesList.length, initialNamesList.length + countToCreate); +}); + +test("toggle name on", async () => { + const testNameLabel = `${TEST_PREFIX}-toggle-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ); + await nameManager.create(testNameLabel, TEST_CID, { + enabled: false, + }); + try { + const resolvedName = await nameManager.get(testNameLabel); + if (resolvedName?.enabled === true) { + throw new Error(`Incorrect State on Resolved Name`); + } + await nameManager.toggle(testNameLabel, true); + const updatedName = await nameManager.get(testNameLabel); + assert.strictEqual(updatedName.label, testNameLabel); + assert.strictEqual(updatedName.cid, TEST_CID); + assert.strictEqual(updatedName.enabled, true); + } finally { + await nameManager.delete(testNameLabel); + } +}); + +test("toggle name off", async () => { + const testNameLabel = `${TEST_PREFIX}-toggle-name-test-pass`, + nameManager = new NameManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ); + await nameManager.create(testNameLabel, TEST_CID); + try { + const resolvedName = await nameManager.get(testNameLabel); + if (resolvedName?.enabled === false) { + throw new Error(`Incorrect State on Resolved Name`); + } + await nameManager.toggle(testNameLabel, false); + const updatedName = await nameManager.get(testNameLabel); + assert.strictEqual(updatedName.label, testNameLabel); + assert.strictEqual(updatedName.cid, TEST_CID); + assert.strictEqual(updatedName.enabled, false); + } finally { + await nameManager.delete(testNameLabel); + } +}); diff --git a/test/objectManager.spec.js b/test/objectManager.spec.js new file mode 100644 index 0000000..abb487b --- /dev/null +++ b/test/objectManager.spec.js @@ -0,0 +1,326 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import ObjectManager from "../src/objectManager.js"; +import BucketManager from "../src/bucketManager.js"; +import * as Path from "node:path"; +import { writeFile } from "node:fs/promises"; +import { v4 as uuidv4 } from "uuid"; +import os from "node:os"; + +const TEST_PREFIX = Date.now(); + +async function createBucket(name) { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Create bucket with name + const bucketNameToCreate = name; + await bucketManager.create(bucketNameToCreate); + + // List buckets and assert new bucket exists + const currentBuckets = await bucketManager.list(), + createdBucket = currentBuckets.find((currentBucket) => { + return currentBucket.Name === bucketNameToCreate; + }); + + return typeof createdBucket !== "undefined"; +} + +async function uploadObject(bucket, key, body) { + // Initialize ObjectManager + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket }, + ); + + // Upload Object + await objectManager.upload(key, body); + + // Confirm Object Uploaded + const uploadedObject = await objectManager.get(key); + + return typeof uploadedObject !== "undefined"; +} + +async function deleteObject(bucket, key) { + // Initialize ObjectManager + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket }, + ); + + // Delete Object + await objectManager.delete(key); + return true; +} + +async function deleteBucket(bucket) { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Delete Bucket + await bucketManager.delete(bucket); + return true; +} + +test("delete object", async () => { + // Create bucket `delete-object-test-pass` + const deleteTestBucket = `${TEST_PREFIX}-delete-object-test-pass`; + await createBucket(deleteTestBucket); + + try { + // Upload object `delete-object-test` + const objectNameToCreate = `delete-object-test`; + const uploaded = await uploadObject( + deleteTestBucket, + objectNameToCreate, + Buffer.from("delete object", "utf-8"), + ); + if (uploaded === false) { + throw Error(`Failed to create object [delete-object-test]`); + } + + // Initialize ObjectManager + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket: deleteTestBucket }, + ); + + // Delete object `delete-object-test` + await objectManager.delete(objectNameToCreate); + + // List bucket and assert new object doesn't exist + const uploadedObject = await objectManager.get(objectNameToCreate); + assert.equal(uploadedObject, false); + } finally { + await deleteBucket(deleteTestBucket); + } +}); + +test("upload object", async () => { + // Create Bucket `create-object-test-pass + const uploadTestBucket = `${TEST_PREFIX}-create-object-test-pass`; + await createBucket(uploadTestBucket); + + try { + // Upload object `create-object-test` + const uploaded = await uploadObject( + uploadTestBucket, + `create-object-test`, + Buffer.from("upload object", "utf-8"), + ); + + assert.strictEqual(uploaded, true); + await deleteObject(uploadTestBucket, `create-object-test`); + } finally { + await deleteBucket(uploadTestBucket); + } +}); + +test("upload directory", async () => { + // Create Bucket `create-object-test-pass + const uploadDirectoryTestBucket = `${TEST_PREFIX}-create-directory-test-pass`; + await createBucket(uploadDirectoryTestBucket); + + try { + // Upload object `create-object-test` + const uploaded = await uploadObject( + uploadDirectoryTestBucket, + `create-directory-test`, + [ + { + path: "/testObjects/1.txt", + content: Buffer.from("upload test object", "utf-8"), + }, + { + path: "/testObjects/deep/1.txt", + content: Buffer.from("upload deep test object", "utf-8"), + }, + { + path: "/topLevel.txt", + content: Buffer.from("upload top level test object", "utf-8"), + }, + ], + ); + assert.strictEqual(uploaded, true); + await deleteObject(uploadDirectoryTestBucket, `create-directory-test`); + } finally { + await deleteBucket(uploadDirectoryTestBucket); + } +}); + +test("download object", async () => { + // Create bucket `download-object-test-pass` + const downloadTestBucket = `${TEST_PREFIX}-download-object-test-pass`; + await createBucket(downloadTestBucket); + + try { + // Upload object `download-object-test` + const objectNameToCreate = `download-object-test`; + const uploaded = await uploadObject( + downloadTestBucket, + objectNameToCreate, + Buffer.from("download object", "utf-8"), + ); + if (uploaded === false) { + throw Error(`Failed to create object [download-object-test]`); + } + + try { + // Download object `download-object-test` and assert it completes + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket: downloadTestBucket }, + ); + const downloadStream = await objectManager.download(objectNameToCreate), + downloadFilename = uuidv4(), + downloadPath = Path.resolve(os.tmpdir(), downloadFilename), + writeFileResult = await writeFile(downloadPath, downloadStream); + assert.strictEqual(typeof writeFileResult, "undefined"); + } finally { + await deleteObject(downloadTestBucket, objectNameToCreate); + } + } finally { + await deleteBucket(downloadTestBucket); + } +}); + +test("download object using gateway", async () => { + // Create bucket `download-object-test-pass` + const downloadTestBucket = `${TEST_PREFIX}-download-object-test-pass`; + await createBucket(downloadTestBucket); + + try { + // Upload object `download-object-test` + const objectNameToCreate = `download-object-test`; + const uploaded = await uploadObject( + downloadTestBucket, + objectNameToCreate, + Buffer.from("download object", "utf-8"), + ); + if (uploaded === false) { + throw Error(`Failed to create object [download-object-test]`); + } + + try { + // Download object `download-object-test` and assert it completes + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { + bucket: downloadTestBucket, + gateway: { endpoint: process.env.TEST_IPFS_GATEWAY }, + }, + ); + const downloadStream = await objectManager.download(objectNameToCreate), + downloadFilename = uuidv4(), + downloadPath = Path.resolve(os.tmpdir(), downloadFilename), + writeFileResult = await writeFile(downloadPath, downloadStream); + assert.strictEqual(typeof writeFileResult, "undefined"); + } finally { + await deleteObject(downloadTestBucket, objectNameToCreate); + } + } finally { + await deleteBucket(downloadTestBucket); + } +}); + +test("list objects", async () => { + // Create bucket `list-objects-test-pass` + const listTestBucket = `${TEST_PREFIX}-list-objects-test-pass`; + await createBucket(listTestBucket); + + try { + let createdObjectCount = 0; + while (createdObjectCount < 26) { + // Upload objects `list-object-test-[x]` + const objectNameToCreate = `list-object-test-${createdObjectCount}`; + await uploadObject( + listTestBucket, + objectNameToCreate, + Buffer.from(`list objects ${createdObjectCount}`, "utf-8"), + ); + createdObjectCount++; + } + + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket: listTestBucket }, + ); + + const objectList = await objectManager.list({ + MaxKeys: 50, + Prefix: `list-object-test-`, + }); + assert.equal(objectList.Contents.length, 26); + + let deletedObjectCount = 0; + while (deletedObjectCount < 26) { + // Delete objects `list-object-test-[x]` + const objectNameToDelete = `list-object-test-${deletedObjectCount}`; + await deleteObject(listTestBucket, objectNameToDelete); + deletedObjectCount++; + } + } finally { + await deleteBucket(listTestBucket); + } +}); + +test("copy object", async () => { + // Create bucket `copy-object-test-pass-src` + const bucketSrc = `${TEST_PREFIX}-copy-object-test-pass-src`; + await createBucket(bucketSrc); + + try { + // Upload object `copy-object-test` + const objectNameToCreateSrc = `copy-object-test`; + const uploaded = await uploadObject( + bucketSrc, + objectNameToCreateSrc, + Buffer.from("copy object", "utf-8"), + ); + try { + assert.equal(uploaded, true); + + // Create bucket `copy-object-test-pass-dest` + const bucketDest = `${TEST_PREFIX}-copy-object-test-pass-dest`; + await createBucket(bucketDest); + + try { + // Initialize ObjectManager + const objectManager = new ObjectManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + { bucket: bucketSrc }, + ); + + // Copy object `copy-object-test` from `copy-object-test-pass-src` to `copy-object-test-pass-dest` + await objectManager.copy(objectNameToCreateSrc, bucketDest); + try { + // List bucket and assert new object exists + const copiedObject = await objectManager.get(objectNameToCreateSrc); + assert.equal(copiedObject.ETag, '"8605273d870f50fde0d8fbcad4a8f702"'); + } finally { + await deleteObject(bucketDest, objectNameToCreateSrc); + } + } finally { + await deleteBucket(bucketDest); + } + } finally { + await deleteObject(bucketSrc, objectNameToCreateSrc); + } + } finally { + await deleteBucket(bucketSrc); + } +}); diff --git a/test/pinManager.spec.js b/test/pinManager.spec.js new file mode 100644 index 0000000..e7358c0 --- /dev/null +++ b/test/pinManager.spec.js @@ -0,0 +1,263 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { PinManager } from "../src/index.js"; +import { v4 as uuidv4 } from "uuid"; +import Path from "node:path"; +import os from "node:os"; +import { writeFile } from "node:fs/promises"; +import BucketManager from "../src/bucketManager.js"; + +const TEST_CID_1 = "QmSEu6zGwKgkQA3ZKaDnvkrwre1kkQa7eRFCbQi7waNwTT", + TEST_CID_2 = "QmNXcMdXadLRTxLpHJMsGnaeKz26d2F6NgUDVWScp54EfC", + TEST_PREFIX = Date.now(); + +async function createBucket(name) { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + ); + + // Create bucket with name + const bucketNameToCreate = name; + await bucketManager.create(bucketNameToCreate); + + // List buckets and assert new bucket exists + const currentBuckets = await bucketManager.list(), + createdBucket = currentBuckets.find((currentBucket) => { + return currentBucket.Name === bucketNameToCreate; + }); + + return typeof createdBucket !== "undefined"; +} + +async function deleteBucket(bucket) { + // Initialize BucketManager + const bucketManager = new BucketManager( + process.env.TEST_S3_KEY || process.env.TEST_KEY, + process.env.TEST_S3_SECRET || process.env.TEST_SECRET, + ); + + // Delete Bucket + await bucketManager.delete(bucket); + return true; +} + +test("create pin", async () => { + const testBucketName = `${TEST_PREFIX}-create-pin-test-pass`, + testPinName = `${TEST_PREFIX}-create-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + await pinManager.delete(createdPin.requestid); + } finally { + await deleteBucket(testBucketName); + } +}); + +test("replace pin with name", async () => { + const testBucketName = `${TEST_PREFIX}-replname-pin-test-pass`, + testPinName = `${TEST_PREFIX}-replace-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + const replacedPin = await pinManager.replace( + createdPin.requestid, + TEST_CID_2, + { + name: `${testPinName}-replaced`, + }, + ); + assert.strictEqual(replacedPin.pin.cid, TEST_CID_2); + assert.strictEqual(replacedPin.pin.name, `${testPinName}-replaced`); + await pinManager.delete(replacedPin.requestid); + } finally { + await deleteBucket(testBucketName); + } +}); + +test("replace pin without name", async () => { + const testBucketName = `${TEST_PREFIX}-replace-pin-test-pass`, + testPinName = `${TEST_PREFIX}-replace-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + const replacedPin = await pinManager.replace( + createdPin.requestid, + TEST_CID_2, + ); + assert.strictEqual(replacedPin.pin.name, testPinName); + assert.strictEqual(replacedPin.pin.cid, TEST_CID_2); + await pinManager.delete(replacedPin.requestid); + } finally { + await deleteBucket(testBucketName); + } +}); + +test("get pin", async () => { + const testBucketName = `${TEST_PREFIX}-get-pin-test-pass`, + testPinName = `${TEST_PREFIX}-get-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + try { + const queriedPin = await pinManager.get(createdPin.requestid); + assert.strictEqual(queriedPin.requestid, createdPin.requestid); + assert.strictEqual(queriedPin.pin.cid, TEST_CID_1); + } finally { + await pinManager.delete(createdPin.requestid); + } + } finally { + await deleteBucket(testBucketName); + } +}); + +test("download pin", async () => { + const testBucketName = `${TEST_PREFIX}-download-pin-test-pass`, + testPinName = `${TEST_PREFIX}-download-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + gateway: { + endpoint: process.env.TEST_IPFS_GATEWAY, + }, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + try { + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + const downloadStream = await pinManager.download(createdPin.pin.cid), + downloadFilename = uuidv4(), + downloadPath = Path.resolve(os.tmpdir(), downloadFilename), + writeFileResult = await writeFile(downloadPath, downloadStream); + assert.strictEqual(typeof writeFileResult, "undefined"); + } finally { + await pinManager.delete(createdPin.requestid); + } + } finally { + await deleteBucket(testBucketName); + } +}); + +test("download pin by reference", async () => { + const testBucketName = `${TEST_PREFIX}-download-ref-test-pass`, + testPinName = `${TEST_PREFIX}-download-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + gateway: { + endpoint: process.env.TEST_IPFS_GATEWAY, + }, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + try { + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + const pinToDownload = await pinManager.get(createdPin.requestid), + downloadStream = await pinToDownload.download(), + downloadFilename = uuidv4(), + downloadPath = Path.resolve(os.tmpdir(), downloadFilename), + writeFileResult = await writeFile(downloadPath, downloadStream); + assert.strictEqual(typeof writeFileResult, "undefined"); + } finally { + await pinManager.delete(createdPin.requestid); + } + } finally { + await deleteBucket(testBucketName); + } +}); + +test("list pins", async () => { + const testBucketName = `${TEST_PREFIX}-list-pin-test-pass`, + testPinName = `${TEST_PREFIX}-list-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const existingPinList = await pinManager.list(), + countToCreate = 25; + let createdPins = []; + for (let i = 0; i < countToCreate; i++) { + createdPins.push( + await pinManager.create(`${testPinName}_${i}`, TEST_CID_1), + ); + } + try { + const pinList = await pinManager.list(); + assert.strictEqual(pinList.count, existingPinList.count + countToCreate); + } finally { + for (const createdPin of createdPins) { + await pinManager.delete(createdPin.requestid); + } + } + } finally { + await deleteBucket(testBucketName); + } +}); + +test("delete pin", async () => { + const testBucketName = `${TEST_PREFIX}-delete-pin-test-pass`, + testPinName = `${TEST_PREFIX}-delete-pin-test-pass`, + pinManager = new PinManager( + process.env.TEST_NAME_KEY || process.env.TEST_KEY, + process.env.TEST_NAME_SECRET || process.env.TEST_SECRET, + { + bucket: testBucketName, + }, + ); + await createBucket(testBucketName); + try { + const createdPin = await pinManager.create(testPinName, TEST_CID_1); + assert.strictEqual(createdPin.pin.cid, TEST_CID_1); + await pinManager.delete(createdPin.requestid); + const deletedPin = await pinManager.get(createdPin.requestid); + assert.strictEqual(deletedPin, false); + } finally { + await deleteBucket(testBucketName); + } +}); diff --git a/tutorials/quickstart-bucket.json b/tutorials/quickstart-bucket.json new file mode 100644 index 0000000..28c9622 --- /dev/null +++ b/tutorials/quickstart-bucket.json @@ -0,0 +1,3 @@ +{ + "title": "Buckets" +} \ No newline at end of file diff --git a/tutorials/quickstart-bucket.md b/tutorials/quickstart-bucket.md new file mode 100644 index 0000000..b93bd22 --- /dev/null +++ b/tutorials/quickstart-bucket.md @@ -0,0 +1,21 @@ +**node.js** +````js +// Import Classes +import {BucketManager} from 'filebase-sdk'; + +// Initialize BucketManager +const bucketManager = new BucketManager(S3_KEY, S3_SECRET); + +// Create bucket +const bucketName = `create-bucket-[random string]`; +await bucketManager.create(bucketName); + +// List buckets +const bucketsList = await bucketManager.list(); + +// Toggle bucket privacy off +await bucketManager.setPrivacy(bucketName, false); +console.dir(bucketsList); + +// Delete Bucket +await bucketManager.delete(bucketName); \ No newline at end of file diff --git a/tutorials/quickstart-gateway.json b/tutorials/quickstart-gateway.json new file mode 100644 index 0000000..bcccf6c --- /dev/null +++ b/tutorials/quickstart-gateway.json @@ -0,0 +1,3 @@ +{ + "title": "Gateways" +} \ No newline at end of file diff --git a/tutorials/quickstart-gateway.md b/tutorials/quickstart-gateway.md new file mode 100644 index 0000000..34816d0 --- /dev/null +++ b/tutorials/quickstart-gateway.md @@ -0,0 +1,32 @@ +**node.js** +````js +// Import Classes +import {GatewayManager} from 'filebase-sdk'; + +// Initialize GatewayManager +const gatewayManager = new GatewayManager(S3_KEY, S3_SECRET); + +// Create New Gateway with a custom domain of `cname.mycustomdomain.com`. +// The custom domain must already exist and have a CNAME record pointed at `myRandomGatewayName.myfilebase.com`. +const gatewayName = "myRandomGatewayName"; +const myGateway = await gatewayManager.create(gatewayName); +await gatewayManager.create(gatewayname, { + domain: `cname.mycustomdomain.com` +}); + +// Get Gateway Setup +const gatewayConfig = await gatewayManager.get(gatewayName); + +// List IPFS Gateways +const myGateways = await gatewayManager.list(); + +// Update Gateway +const myUpdatedGateway = await gatewayManager.update(gatewayName, { + enabled: false +}); + +// Toggle Gateway State +await gatewayManager.toggle(gatewayName, true) + +// Delete Gateway +await gatewayManager.delete(gatewayName); \ No newline at end of file diff --git a/tutorials/quickstart-name.json b/tutorials/quickstart-name.json new file mode 100644 index 0000000..13711de --- /dev/null +++ b/tutorials/quickstart-name.json @@ -0,0 +1,3 @@ +{ + "title": "Names" +} \ No newline at end of file diff --git a/tutorials/quickstart-name.md b/tutorials/quickstart-name.md new file mode 100644 index 0000000..0decf63 --- /dev/null +++ b/tutorials/quickstart-name.md @@ -0,0 +1,36 @@ +**node.js** +````js +// Import Classes +import {NameManager} from 'filebase-sdk'; + +// Initialize NameManager +const nameManager = new NameManager(S3_KEY, S3_SECRET); + +// Create New IPNS Name with Broadcast Disabled +const ipnsCid = "QmZqkuqX1qTspb1GgmnzyRFetf1uMyA3CemvvgPZD39sPo"; +const ipnsName = await nameManager.create(`myFirstIpnsKey`, ipnsCid, { + enabled: true +}); + +// Update IPNS Value and Optionally Enable the Broadcast +const ipnsLabel = `myFirstIpnsKey`; +await nameManager.set(ipnsLabel, ipnsCid, { + enabled: true, +}); + +// Enable IPNS Broadcast without updating the IPNS Record +await nameManager.toggle(ipnsLabel, true); + +// List IPNS Names +const myIpnsNames = await nameManager.list(); + +// List Specific IPNS Name +const myIpnsName = await nameManager.list(ipnsLabel); + +// Import IPNS Name +const myImportedIpnsName = await nameManager.import(ipnsLabel, ipnsCid, Base64EncodedPrivateKey, { + enabled: false, +}); + +// Delete Name +await nameManager.delete(ipnsLabel); \ No newline at end of file diff --git a/tutorials/quickstart-object.json b/tutorials/quickstart-object.json new file mode 100644 index 0000000..7088f34 --- /dev/null +++ b/tutorials/quickstart-object.json @@ -0,0 +1,3 @@ +{ + "title": "Objects" +} \ No newline at end of file diff --git a/tutorials/quickstart-object.md b/tutorials/quickstart-object.md new file mode 100644 index 0000000..0b4df4a --- /dev/null +++ b/tutorials/quickstart-object.md @@ -0,0 +1,22 @@ +**node.js** +````js +// Import Classes +import {ObjectManager} from 'filebase-sdk'; + +// Initialize ObjectManager +const bucketName = `create-object-[random string]`; +const objectManager = new ObjectManager(S3_KEY, S3_SECRET, bucketName); + +// Upload Object +const objectName = `new-object`; +const uploadedObject = await objectManager.upload(objectName, body); + +// Confirm Object Uploaded +const objectsList = await objectManager.list({ + Prefix: key, + MaxKeys: 1, +}); +console.dir(objectsList) + +// Delete Object +await objectManager.delete(objectName); \ No newline at end of file diff --git a/tutorials/quickstart-pin.json b/tutorials/quickstart-pin.json new file mode 100644 index 0000000..b0363b1 --- /dev/null +++ b/tutorials/quickstart-pin.json @@ -0,0 +1,3 @@ +{ + "title": "Pins" +} \ No newline at end of file diff --git a/tutorials/quickstart-pin.md b/tutorials/quickstart-pin.md new file mode 100644 index 0000000..fc91a8d --- /dev/null +++ b/tutorials/quickstart-pin.md @@ -0,0 +1,16 @@ +**node.js** +````js +// Import Classes +import {PinManager} from 'filebase-sdk'; + +// Initialize PinManager +const pinManager = new PinManager(S3_KEY, S3_SECRET, { + bucket: bucketName, + gateway: { + endpoint: "https://myRandomGatewayName.myfilebase.com" + } +}); +// Create New Pin with Metadata +const myNewPin = await pinManager.create("my-pin", "QmTJkc7crTuPG7xRmCQSz1yioBpCW3juFBtJPXhQfdCqGF", { + "application": "my-custom-app-on-filebase" +}); \ No newline at end of file