diff --git a/.husky/pre-commit b/.husky/pre-commit index 1039a04c..c3afc39c 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,10 @@ #!/bin/sh +# Exit if a merge is in progress +if [ -f .git/MERGE_HEAD ]; then + exit 0 +fi + set +e # Stash un-staged changes diff --git a/Cargo.lock b/Cargo.lock index 4a3f364a..739491ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2281,7 +2281,7 @@ dependencies = [ [[package]] name = "mpl-core" -version = "0.7.2" +version = "0.8.0-beta.1" dependencies = [ "anchor-lang", "assert_matches", diff --git a/clients/js/package.json b/clients/js/package.json index 64595e97..6cfc288a 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@metaplex-foundation/mpl-core", - "version": "1.0.2", + "version": "1.1.0-alpha.1", "description": "Digital Assets", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -29,6 +29,9 @@ "@metaplex-foundation/umi": ">=0.8.2 < 1", "@noble/hashes": "^1.3.1" }, + "dependencies": { + "@msgpack/msgpack": "^3.0.0-beta2" + }, "devDependencies": { "@ava/typescript": "^5.0.0", "@metaplex-foundation/mpl-core-oracle-example": "^0.0.2", @@ -64,4 +67,4 @@ } }, "packageManager": "pnpm@8.2.0" -} +} \ No newline at end of file diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index 5a66d381..7ebde4b4 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -5,9 +5,12 @@ settings: excludeLinksFromLockfile: false dependencies: + '@msgpack/msgpack': + specifier: ^3.0.0-beta2 + version: 3.0.0-beta2 '@noble/hashes': specifier: ^1.3.1 - version: 1.3.1 + version: 1.4.0 devDependencies: '@ava/typescript': @@ -15,25 +18,25 @@ devDependencies: version: 5.0.0 '@metaplex-foundation/mpl-core-oracle-example': specifier: ^0.0.2 - version: 0.0.2(@metaplex-foundation/umi@0.8.10)(@noble/hashes@1.3.1) + version: 0.0.2(@metaplex-foundation/umi@0.8.10)(@noble/hashes@1.4.0) '@metaplex-foundation/mpl-toolbox': specifier: ^0.8.0 - version: 0.8.0(@metaplex-foundation/umi@0.8.10) + version: 0.8.1(@metaplex-foundation/umi@0.8.10) '@metaplex-foundation/umi': specifier: ^0.8.10 version: 0.8.10 '@metaplex-foundation/umi-bundle-tests': specifier: ^0.8.10 - version: 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) + version: 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) '@solana/web3.js': specifier: ^1.73.0 - version: 1.73.0 + version: 1.93.0 '@typescript-eslint/eslint-plugin': specifier: ^5.0.0 - version: 5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4) + version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@4.9.5) '@typescript-eslint/parser': specifier: ^5.46.1 - version: 5.46.1(eslint@8.0.1)(typescript@4.9.4) + version: 5.62.0(eslint@8.57.0)(typescript@4.9.5) ava: specifier: ^6.1.3 version: 6.1.3(@ava/typescript@5.0.0) @@ -42,48 +45,43 @@ devDependencies: version: 5.0.0 eslint: specifier: ^8.0.1 - version: 8.0.1 + version: 8.57.0 eslint-config-airbnb-typescript: specifier: ^17.0.0 - version: 17.0.0(@typescript-eslint/eslint-plugin@5.0.0)(@typescript-eslint/parser@5.46.1)(eslint-plugin-import@2.26.0)(eslint@8.0.1) + version: 17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0) eslint-config-prettier: specifier: ^8.5.0 - version: 8.5.0(eslint@8.0.1) + version: 8.10.0(eslint@8.57.0) eslint-plugin-import: specifier: ^2.26.0 - version: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + version: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) eslint-plugin-prettier: specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.0.1)(prettier@3.2.5) + version: 4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.3.2) prettier: specifier: ^3.2.5 - version: 3.2.5 + version: 3.3.2 rimraf: specifier: ^3.0.2 version: 3.0.2 typedoc: specifier: ^0.23.16 - version: 0.23.16(typescript@4.9.4) + version: 0.23.28(typescript@4.9.5) typedoc-plugin-expand-object-like-types: specifier: ^0.1.1 - version: 0.1.1(typedoc@0.23.16) + version: 0.1.2(typedoc@0.23.28) typedoc-plugin-missing-exports: specifier: ^1.0.0 - version: 1.0.0(typedoc@0.23.16) + version: 1.0.0(typedoc@0.23.28) typescript: specifier: ^4.9.4 - version: 4.9.4 + version: 4.9.5 vercel: specifier: ^28.16.0 - version: 28.16.0(@types/node@14.18.33) + version: 28.20.0(@types/node@14.18.33) packages: - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - /@ampproject/remapping@2.3.0: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -100,35 +98,35 @@ packages: execa: 8.0.1 dev: true - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 dev: true - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + /@babel/compat-data@7.24.7: + resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.24.0: - resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==} + /@babel/core@7.24.7: + resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helpers': 7.24.0 - '@babel/parser': 7.24.0 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helpers': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.3.4 + debug: 4.3.5 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -136,1148 +134,1208 @@ packages: - supports-color dev: true - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + /@babel/generator@7.24.7: + resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 dev: true - /@babel/helper-annotate-as-pure@7.22.5: - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + /@babel/helper-annotate-as-pure@7.24.7: + resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 dev: true - /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: - resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + /@babel/helper-builder-binary-assignment-operator-visitor@7.24.7: + resolution: {integrity: sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + /@babel/helper-compilation-targets@7.24.7: + resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.23.0 + '@babel/compat-data': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + browserslist: 4.23.1 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.24.0(@babel/core@7.24.0): - resolution: {integrity: sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==} + /@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 semver: 6.3.1 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.0): - resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} + /@babel/helper-create-regexp-features-plugin@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 regexpu-core: 5.3.2 semver: 6.3.1 dev: true - /@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.24.0): - resolution: {integrity: sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4 - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.24.0): - resolution: {integrity: sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==} + /@babel/helper-define-polyfill-provider@0.6.2(@babel/core@7.24.7): + resolution: {integrity: sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4 + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + debug: 4.3.5 lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + /@babel/helper-environment-visitor@7.24.7: + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.7 dev: true - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + /@babel/helper-function-name@7.24.7: + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + /@babel/helper-hoist-variables@7.24.7: + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 dev: true - /@babel/helper-member-expression-to-functions@7.23.0: - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + /@babel/helper-member-expression-to-functions@7.24.7: + resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + /@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-optimise-call-expression@7.22.5: - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 dev: true - /@babel/helper-plugin-utils@7.24.0: - resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + /@babel/helper-plugin-utils@7.24.7: + resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.0): - resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} + /@babel/helper-remap-async-to-generator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-wrap-function': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-replace-supers@7.22.20(@babel/core@7.24.0): - resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} + /@babel/helper-replace-supers@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.7 + '@babel/helper-optimise-call-expression': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.22.5: - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + /@babel/helper-split-export-declaration@7.24.7: + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 dev: true - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + /@babel/helper-string-parser@7.24.7: + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + /@babel/helper-validator-option@7.24.7: + resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-wrap-function@7.22.20: - resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + /@babel/helper-wrap-function@7.24.7: + resolution: {integrity: sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-function-name': 7.23.0 - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/helper-function-name': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/helpers@7.24.0: - resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==} + /@babel/helpers@7.24.7: + resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 - transitivePeerDependencies: - - supports-color + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 dev: true - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 + picocolors: 1.0.1 dev: true - /@babel/parser@7.24.0: - resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} + /@babel/parser@7.24.7: + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.24.7 + dev: true + + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.24.0): - resolution: {integrity: sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0): + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7): resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.0): + /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.0): + /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.7): resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.0): + /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.24.7): resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} + /@babel/plugin-syntax-import-assertions@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} + /@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.0): + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.7): resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.0): + /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.7): resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.0): + /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.7): resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.0): + /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.7): resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.0): + /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.24.7): resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.0): + /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.7): resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + /@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.0): + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.24.7): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} + /@babel/plugin-transform-arrow-functions@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.24.0): - resolution: {integrity: sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==} + /@babel/plugin-transform-async-generator-functions@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} + /@babel/plugin-transform-async-to-generator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-remap-async-to-generator': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + /@babel/plugin-transform-block-scoped-functions@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + /@babel/plugin-transform-block-scoping@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + /@babel/plugin-transform-class-properties@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + /@babel/plugin-transform-class-static-block@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-classes@7.23.8(@babel/core@7.24.0): - resolution: {integrity: sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==} + /@babel/plugin-transform-classes@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + '@babel/helper-split-export-declaration': 7.24.7 globals: 11.12.0 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} + /@babel/plugin-transform-computed-properties@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/template': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/template': 7.24.7 dev: true - /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} + /@babel/plugin-transform-destructuring@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} + /@babel/plugin-transform-dotall-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} + /@babel/plugin-transform-duplicate-keys@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} + /@babel/plugin-transform-dynamic-import@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} + /@babel/plugin-transform-exponentiation-operator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-builder-binary-assignment-operator-visitor': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} + /@babel/plugin-transform-export-namespace-from@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-for-of@7.23.6(@babel/core@7.24.0): - resolution: {integrity: sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==} + /@babel/plugin-transform-for-of@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} + /@babel/plugin-transform-function-name@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} + /@babel/plugin-transform-json-strings@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-literals@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} + /@babel/plugin-transform-literals@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} + /@babel/plugin-transform-logical-assignment-operators@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} + /@babel/plugin-transform-member-expression-literals@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} + /@babel/plugin-transform-modules-amd@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} + /@babel/plugin-transform-modules-commonjs@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-simple-access': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.24.0): - resolution: {integrity: sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==} + /@babel/plugin-transform-modules-systemjs@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/core': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} + /@babel/plugin-transform-modules-umd@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.24.0): - resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + /@babel/plugin-transform-named-capturing-groups-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} + /@babel/plugin-transform-new-target@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} + /@babel/plugin-transform-nullish-coalescing-operator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} + /@babel/plugin-transform-numeric-separator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-object-rest-spread@7.24.0(@babel/core@7.24.0): - resolution: {integrity: sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==} + /@babel/plugin-transform-object-rest-spread@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} + /@babel/plugin-transform-object-super@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} + /@babel/plugin-transform-optional-catch-binding@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) dev: true - /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} + /@babel/plugin-transform-optional-chaining@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} + /@babel/plugin-transform-parameters@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} + /@babel/plugin-transform-private-methods@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.24.0): - resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} + /@babel/plugin-transform-private-property-in-object@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} + /@babel/plugin-transform-property-literals@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} + /@babel/plugin-transform-regenerator@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 regenerator-transform: 0.15.2 dev: true - /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + /@babel/plugin-transform-reserved-words@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} + /@babel/plugin-transform-shorthand-properties@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-spread@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} + /@babel/plugin-transform-spread@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} + /@babel/plugin-transform-sticky-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} + /@babel/plugin-transform-template-literals@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} + /@babel/plugin-transform-typeof-symbol@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-typescript@7.23.6(@babel/core@7.24.0): - resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==} + /@babel/plugin-transform-typescript@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-iLD3UNkgx2n/HrjBesVbYX6j0yqn/sJktvbtKKgcaLIQ4bTTQ8obAypc1VpyHPD2y4Phh9zHOaAt8e/L14wCpw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} + /@babel/plugin-transform-unicode-escapes@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} + /@babel/plugin-transform-unicode-property-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} + /@babel/plugin-transform-unicode-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + /@babel/plugin-transform-unicode-sets-regex@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.24.0) - '@babel/helper-plugin-utils': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-create-regexp-features-plugin': 7.24.7(@babel/core@7.24.7) + '@babel/helper-plugin-utils': 7.24.7 dev: true - /@babel/preset-env@7.24.0(@babel/core@7.24.0): - resolution: {integrity: sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==} + /@babel/preset-env@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.24.0) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.0) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.0) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.0) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.24.0) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.24.0) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.24.0) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.24.0) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.24.0) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-object-rest-spread': 7.24.0(@babel/core@7.24.0) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.24.0) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.24.0) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.0) - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.24.0) - babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.24.0) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.24.0) - core-js-compat: 3.36.0 + '@babel/compat-data': 7.24.7 + '@babel/core': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.24.7) + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.24.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-import-assertions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.24.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.7) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.24.7) + '@babel/plugin-transform-arrow-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-async-generator-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-async-to-generator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-block-scoped-functions': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-block-scoping': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-class-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-class-static-block': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-classes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-computed-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-destructuring': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-dotall-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-duplicate-keys': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-dynamic-import': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-exponentiation-operator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-export-namespace-from': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-for-of': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-function-name': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-json-strings': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-logical-assignment-operators': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-member-expression-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-amd': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-systemjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-umd': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-named-capturing-groups-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-new-target': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-nullish-coalescing-operator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-numeric-separator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-object-rest-spread': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-object-super': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-optional-catch-binding': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-optional-chaining': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-parameters': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-private-methods': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-private-property-in-object': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-property-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-regenerator': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-reserved-words': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-shorthand-properties': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-spread': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-sticky-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-template-literals': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-typeof-symbol': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-escapes': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-property-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-regex': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-unicode-sets-regex': 7.24.7(@babel/core@7.24.7) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.24.7) + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.7) + babel-plugin-polyfill-corejs3: 0.10.4(@babel/core@7.24.7) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.7) + core-js-compat: 3.37.1 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.0): + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.24.7): resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/types': 7.24.0 + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/types': 7.24.7 esutils: 2.0.3 dev: true - /@babel/preset-typescript@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} + /@babel/preset-typescript@7.24.7(@babel/core@7.24.7): + resolution: {integrity: sha512-SyXRe3OdWwIwalxDg5UtJnJQO+YPcTfwiIY2B0Xlddh9o7jpWLvv8X1RthIeDOxQ+O1ML5BLPCONToObyVQVuQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-plugin-utils': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-modules-commonjs': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-transform-typescript': 7.24.7(@babel/core@7.24.7) + transitivePeerDependencies: + - supports-color dev: true /@babel/regjsgen@0.8.0: @@ -1290,46 +1348,46 @@ packages: regenerator-runtime: 0.13.11 dev: true - /@babel/runtime@7.24.0: - resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} + /@babel/runtime@7.24.7: + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 dev: true - /@babel/template@7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + /@babel/template@7.24.7: + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 dev: true - /@babel/traverse@7.24.0: - resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} + /@babel/traverse@7.24.7: + resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - debug: 4.3.4 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + debug: 4.3.5 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + /@babel/types@7.24.7: + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 dev: true @@ -1340,20 +1398,33 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@edge-runtime/format@1.1.0: - resolution: {integrity: sha512-MkLDDtPhXZIMx83NykdFmOpF7gVWIdd6GBHYb8V/E+PKWvD2pK/qWx9B30oN1iDJ2XBm0SGDjz02S8nDHI9lMQ==} + /@edge-runtime/format@2.0.1: + resolution: {integrity: sha512-aE+9DtBvQyg349srixtXEUNauWtIv5HTKPy8Q9dvG1NvpldVIvvhcDBI+SuvDVM8kQl8phbYnp2NTNloBCn/Yg==} + engines: {node: '>=14'} dev: true /@edge-runtime/primitives@2.0.0: resolution: {integrity: sha512-AXqUq1zruTJAICrllUvZcgciIcEGHdF6KJ3r6FM0n4k8LpFxZ62tPWVIJ9HKm+xt+ncTBUZxwgUaQ73QMUQEKw==} dev: true + /@edge-runtime/primitives@2.1.2: + resolution: {integrity: sha512-SR04SMDybALlhIYIi0hiuEUwIl0b7Sn+RKwQkX6hydg4+AKMzBNDFhj2nqHDD1+xkHArV9EhmJIb6iGjShwSzg==} + engines: {node: '>=14'} + dev: true + /@edge-runtime/vm@2.0.0: resolution: {integrity: sha512-BOLrAX8IWHRXu1siZocwLguKJPEUv7cr+rG8tI4hvHgMdIsBWHJlLeB8EjuUVnIURFrUiM49lVKn8DRrECmngw==} dependencies: '@edge-runtime/primitives': 2.0.0 dev: true + /@edge-runtime/vm@2.1.2: + resolution: {integrity: sha512-j4H5S26NJhYOyjVMN8T/YJuwwslfnEX1P0j6N2Rq1FaubgNowdYunA9nlO7lg8Rgjv6dqJ2zKuM7GD1HFtNSGw==} + engines: {node: '>=14'} + dependencies: + '@edge-runtime/primitives': 2.1.2 + dev: true + /@emotion/hash@0.9.1: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: true @@ -1377,6 +1448,15 @@ packages: dev: true optional: true + /@esbuild/aix-ppc64@0.21.5: + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm64@0.16.3: resolution: {integrity: sha512-RolFVeinkeraDvN/OoRf1F/lP0KUfGNb5jxy/vkIMeRRChkrX/HTYN6TYZosRJs3a1+8wqpxAo5PI5hFmxyPRg==} engines: {node: '>=12'} @@ -1395,6 +1475,15 @@ packages: dev: true optional: true + /@esbuild/android-arm64@0.21.5: + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-arm@0.16.3: resolution: {integrity: sha512-mueuEoh+s1eRbSJqq9KNBQwI4QhQV6sRXIfTyLXSHGMpyew61rOK4qY21uKbXl1iBoMb0AdL1deWFCQVlN2qHA==} engines: {node: '>=12'} @@ -1413,6 +1502,15 @@ packages: dev: true optional: true + /@esbuild/android-arm@0.21.5: + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/android-x64@0.16.3: resolution: {integrity: sha512-SFpTUcIT1bIJuCCBMCQWq1bL2gPTjWoLZdjmIhjdcQHaUfV41OQfho6Ici5uvvkMmZRXIUGpM3GxysP/EU7ifQ==} engines: {node: '>=12'} @@ -1431,6 +1529,15 @@ packages: dev: true optional: true + /@esbuild/android-x64@0.21.5: + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-arm64@0.16.3: resolution: {integrity: sha512-DO8WykMyB+N9mIDfI/Hug70Dk1KipavlGAecxS3jDUwAbTpDXj0Lcwzw9svkhxfpCagDmpaTMgxWK8/C/XcXvw==} engines: {node: '>=12'} @@ -1449,6 +1556,15 @@ packages: dev: true optional: true + /@esbuild/darwin-arm64@0.21.5: + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/darwin-x64@0.16.3: resolution: {integrity: sha512-uEqZQ2omc6BvWqdCiyZ5+XmxuHEi1SPzpVxXCSSV2+Sh7sbXbpeNhHIeFrIpRjAs0lI1FmA1iIOxFozKBhKgRQ==} engines: {node: '>=12'} @@ -1467,6 +1583,15 @@ packages: dev: true optional: true + /@esbuild/darwin-x64@0.21.5: + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-arm64@0.16.3: resolution: {integrity: sha512-nJansp3sSXakNkOD5i5mIz2Is/HjzIhFs49b1tjrPrpCmwgBmH9SSzhC/Z1UqlkivqMYkhfPwMw1dGFUuwmXhw==} engines: {node: '>=12'} @@ -1485,6 +1610,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-arm64@0.21.5: + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/freebsd-x64@0.16.3: resolution: {integrity: sha512-TfoDzLw+QHfc4a8aKtGSQ96Wa+6eimljjkq9HKR0rHlU83vw8aldMOUSJTUDxbcUdcgnJzPaX8/vGWm7vyV7ug==} engines: {node: '>=12'} @@ -1503,6 +1637,15 @@ packages: dev: true optional: true + /@esbuild/freebsd-x64@0.21.5: + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm64@0.16.3: resolution: {integrity: sha512-7I3RlsnxEFCHVZNBLb2w7unamgZ5sVwO0/ikE2GaYvYuUQs9Qte/w7TqWcXHtCwxvZx/2+F97ndiUQAWs47ZfQ==} engines: {node: '>=12'} @@ -1521,6 +1664,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm64@0.21.5: + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-arm@0.16.3: resolution: {integrity: sha512-VwswmSYwVAAq6LysV59Fyqk3UIjbhuc6wb3vEcJ7HEJUtFuLK9uXWuFoH1lulEbE4+5GjtHi3MHX+w1gNHdOWQ==} engines: {node: '>=12'} @@ -1539,6 +1691,15 @@ packages: dev: true optional: true + /@esbuild/linux-arm@0.21.5: + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ia32@0.16.3: resolution: {integrity: sha512-X8FDDxM9cqda2rJE+iblQhIMYY49LfvW4kaEjoFbTTQ4Go8G96Smj2w3BRTwA8IHGoi9dPOPGAX63dhuv19UqA==} engines: {node: '>=12'} @@ -1557,6 +1718,15 @@ packages: dev: true optional: true + /@esbuild/linux-ia32@0.21.5: + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-loong64@0.16.3: resolution: {integrity: sha512-hIbeejCOyO0X9ujfIIOKjBjNAs9XD/YdJ9JXAy1lHA+8UXuOqbFe4ErMCqMr8dhlMGBuvcQYGF7+kO7waj2KHw==} engines: {node: '>=12'} @@ -1575,6 +1745,15 @@ packages: dev: true optional: true + /@esbuild/linux-loong64@0.21.5: + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-mips64el@0.16.3: resolution: {integrity: sha512-znFRzICT/V8VZQMt6rjb21MtAVJv/3dmKRMlohlShrbVXdBuOdDrGb+C2cZGQAR8RFyRe7HS6klmHq103WpmVw==} engines: {node: '>=12'} @@ -1593,6 +1772,15 @@ packages: dev: true optional: true + /@esbuild/linux-mips64el@0.21.5: + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-ppc64@0.16.3: resolution: {integrity: sha512-EV7LuEybxhXrVTDpbqWF2yehYRNz5e5p+u3oQUS2+ZFpknyi1NXxr8URk4ykR8Efm7iu04//4sBg249yNOwy5Q==} engines: {node: '>=12'} @@ -1611,6 +1799,15 @@ packages: dev: true optional: true + /@esbuild/linux-ppc64@0.21.5: + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-riscv64@0.16.3: resolution: {integrity: sha512-uDxqFOcLzFIJ+r/pkTTSE9lsCEaV/Y6rMlQjUI9BkzASEChYL/aSQjZjchtEmdnVxDKETnUAmsaZ4pqK1eE5BQ==} engines: {node: '>=12'} @@ -1629,6 +1826,15 @@ packages: dev: true optional: true + /@esbuild/linux-riscv64@0.21.5: + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-s390x@0.16.3: resolution: {integrity: sha512-NbeREhzSxYwFhnCAQOQZmajsPYtX71Ufej3IQ8W2Gxskfz9DK58ENEju4SbpIj48VenktRASC52N5Fhyf/aliQ==} engines: {node: '>=12'} @@ -1647,6 +1853,15 @@ packages: dev: true optional: true + /@esbuild/linux-s390x@0.21.5: + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/linux-x64@0.16.3: resolution: {integrity: sha512-SDiG0nCixYO9JgpehoKgScwic7vXXndfasjnD5DLbp1xltANzqZ425l7LSdHynt19UWOcDjG9wJJzSElsPvk0w==} engines: {node: '>=12'} @@ -1665,6 +1880,15 @@ packages: dev: true optional: true + /@esbuild/linux-x64@0.21.5: + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@esbuild/netbsd-x64@0.16.3: resolution: {integrity: sha512-AzbsJqiHEq1I/tUvOfAzCY15h4/7Ivp3ff/o1GpP16n48JMNAtbW0qui2WCgoIZArEHD0SUQ95gvR0oSO7ZbdA==} engines: {node: '>=12'} @@ -1683,6 +1907,15 @@ packages: dev: true optional: true + /@esbuild/netbsd-x64@0.21.5: + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/openbsd-x64@0.16.3: resolution: {integrity: sha512-gSABi8qHl8k3Cbi/4toAzHiykuBuWLZs43JomTcXkjMZVkp0gj3gg9mO+9HJW/8GB5H89RX/V0QP4JGL7YEEVg==} engines: {node: '>=12'} @@ -1701,6 +1934,15 @@ packages: dev: true optional: true + /@esbuild/openbsd-x64@0.21.5: + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + /@esbuild/sunos-x64@0.16.3: resolution: {integrity: sha512-SF9Kch5Ete4reovvRO6yNjMxrvlfT0F0Flm+NPoUw5Z4Q3r1d23LFTgaLwm3Cp0iGbrU/MoUI+ZqwCv5XJijCw==} engines: {node: '>=12'} @@ -1719,6 +1961,15 @@ packages: dev: true optional: true + /@esbuild/sunos-x64@0.21.5: + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-arm64@0.16.3: resolution: {integrity: sha512-u5aBonZIyGopAZyOnoPAA6fGsDeHByZ9CnEzyML9NqntK6D/xl5jteZUKm/p6nD09+v3pTM6TuUIqSPcChk5gg==} engines: {node: '>=12'} @@ -1737,6 +1988,15 @@ packages: dev: true optional: true + /@esbuild/win32-arm64@0.21.5: + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-ia32@0.16.3: resolution: {integrity: sha512-GlgVq1WpvOEhNioh74TKelwla9KDuAaLZrdxuuUgsP2vayxeLgVc+rbpIv0IYF4+tlIzq2vRhofV+KGLD+37EQ==} engines: {node: '>=12'} @@ -1755,6 +2015,15 @@ packages: dev: true optional: true + /@esbuild/win32-ia32@0.21.5: + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + /@esbuild/win32-x64@0.16.3: resolution: {integrity: sha512-5/JuTd8OWW8UzEtyf19fbrtMJENza+C9JoPIkvItgTBQ1FO2ZLvjbPO6Xs54vk0s5JB5QsfieUEshRQfu7ZHow==} engines: {node: '>=12'} @@ -1773,12 +2042,36 @@ packages: dev: true optional: true - /@eslint/eslintrc@1.4.1: - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + /@esbuild/win32-x64@0.21.5: + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.10.1: + resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4 + debug: 4.3.5 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -1790,23 +2083,35 @@ packages: - supports-color dev: true + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true - /@humanwhocodes/config-array@0.6.0: - resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.5 minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead dev: true /@jridgewell/gen-mapping@0.3.5: @@ -1850,67 +2155,67 @@ packages: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0 nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.6.0 - tar: 6.2.0 + semver: 7.6.2 + tar: 6.2.1 transitivePeerDependencies: - encoding - supports-color dev: true - /@metaplex-foundation/mpl-core-oracle-example@0.0.2(@metaplex-foundation/umi@0.8.10)(@noble/hashes@1.3.1): + /@metaplex-foundation/mpl-core-oracle-example@0.0.2(@metaplex-foundation/umi@0.8.10)(@noble/hashes@1.4.0): resolution: {integrity: sha512-DxHKLaM04YGMv/EGgIzzxSJnBPv+OTBKeekL7mm7Pcu/DqH+xIuy4K7h9mMhI3E1gSbWIaxtzlbitbvwXvYRcw==} peerDependencies: '@metaplex-foundation/umi': '>=0.8.2 < 1' '@noble/hashes': ^1.3.1 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@noble/hashes': 1.3.1 + '@noble/hashes': 1.4.0 dev: true - /@metaplex-foundation/mpl-toolbox@0.8.0(@metaplex-foundation/umi@0.8.10): - resolution: {integrity: sha512-SK1VUPU4hCaL3sozgtoVjjbZxqx2gWiRt0YTFbwEt5LAHWOlCb7J7rcrrA5XwymX4iV2bIWygYs0yz7hYyx2rg==} + /@metaplex-foundation/mpl-toolbox@0.8.1(@metaplex-foundation/umi@0.8.10): + resolution: {integrity: sha512-PYU+qU6hg+h6V42z+MDnBTiWZXTTzWhIn5ieyRZYyszTru/LiJKHdsHGKe1VBfuXEuRdfRhAzivMjquZVaqO4A==} peerDependencies: '@metaplex-foundation/umi': ^0.8.2 dependencies: '@metaplex-foundation/umi': 0.8.10 dev: true - /@metaplex-foundation/umi-bundle-tests@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-bundle-tests@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0): resolution: {integrity: sha512-12BLhBF5lXLG7K1m4J8mEArcc/l4a4iRCmZt2VKSD0tA+i+b3ou1RA+e+262nhrEZ/uhYx0ChUzrJlBk0a1aXQ==} peerDependencies: '@metaplex-foundation/umi': ^0.8.10 '@solana/web3.js': ^1.72.0 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@metaplex-foundation/umi-eddsa-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) + '@metaplex-foundation/umi-eddsa-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) '@metaplex-foundation/umi-http-fetch': 0.8.10(@metaplex-foundation/umi@0.8.10) '@metaplex-foundation/umi-program-repository': 0.8.10(@metaplex-foundation/umi@0.8.10) - '@metaplex-foundation/umi-rpc-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) + '@metaplex-foundation/umi-rpc-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) '@metaplex-foundation/umi-serializer-data-view': 0.8.10(@metaplex-foundation/umi@0.8.10) '@metaplex-foundation/umi-storage-mock': 0.8.10(@metaplex-foundation/umi@0.8.10) - '@metaplex-foundation/umi-transaction-factory-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi-transaction-factory-web3js': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) + '@solana/web3.js': 1.93.0 transitivePeerDependencies: - encoding dev: true - /@metaplex-foundation/umi-eddsa-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-eddsa-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0): resolution: {integrity: sha512-2CLsuQ67oPKczB7RuG07/Ro1rrW25vGZArren20/zBTgHubGIuFW7V8e9qZDqkHDt1nFecxrX55g0fNtQaU40g==} peerDependencies: '@metaplex-foundation/umi': ^0.8.10 '@solana/web3.js': ^1.72.0 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) + '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) '@noble/curves': 1.4.0 - '@solana/web3.js': 1.73.0 + '@solana/web3.js': 1.93.0 dev: true /@metaplex-foundation/umi-http-fetch@0.8.10(@metaplex-foundation/umi@0.8.10): @@ -1942,15 +2247,15 @@ packages: '@metaplex-foundation/umi-serializers-encodings': 0.8.9 dev: true - /@metaplex-foundation/umi-rpc-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-rpc-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0): resolution: {integrity: sha512-+60uxlX1OcThL2UIW9dbcy0Ihr011ggxkQYSxc1qh4qitgD9wrZZ/v9nX4tzEN88a52UJGhH5G3SF6CNmqy4aw==} peerDependencies: '@metaplex-foundation/umi': ^0.8.10 '@solana/web3.js': ^1.72.0 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) + '@solana/web3.js': 1.93.0 dev: true /@metaplex-foundation/umi-serializer-data-view@0.8.10(@metaplex-foundation/umi@0.8.10): @@ -1995,25 +2300,25 @@ packages: '@metaplex-foundation/umi': 0.8.10 dev: true - /@metaplex-foundation/umi-transaction-factory-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-transaction-factory-web3js@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0): resolution: {integrity: sha512-hnkDKdtuZgY6DKH6aSEd6UrZGi5/WvfYqJUWeM8SVl1/8GhNypNKWvuppvFHpU9X2tLXuF4JSG4TVxAuIs9LBQ==} peerDependencies: '@metaplex-foundation/umi': ^0.8.10 '@solana/web3.js': ^1.72.0 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi-web3js-adapters': 0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0) + '@solana/web3.js': 1.93.0 dev: true - /@metaplex-foundation/umi-web3js-adapters@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-web3js-adapters@0.8.10(@metaplex-foundation/umi@0.8.10)(@solana/web3.js@1.93.0): resolution: {integrity: sha512-TGF+vzO/v0HMRM8sz1M1yh+wfZ5l4RCFm1Kkcy5MC9FrNDookPP6y9aYZ3R0QkEVVV3u+8QLptrTUrxr3EGmyQ==} peerDependencies: '@metaplex-foundation/umi': ^0.8.10 '@solana/web3.js': ^1.72.0 dependencies: '@metaplex-foundation/umi': 0.8.10 - '@solana/web3.js': 1.73.0 + '@solana/web3.js': 1.93.0 buffer: 6.0.3 dev: true @@ -2025,28 +2330,20 @@ packages: '@metaplex-foundation/umi-serializers': 0.8.9 dev: true + /@msgpack/msgpack@3.0.0-beta2: + resolution: {integrity: sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==} + engines: {node: '>= 14'} + dev: false + /@noble/curves@1.4.0: resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} dependencies: '@noble/hashes': 1.4.0 dev: true - /@noble/ed25519@1.7.3: - resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} - dev: true - - /@noble/hashes@1.3.1: - resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==} - engines: {node: '>= 16'} - /@noble/hashes@1.4.0: resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} - dev: true - - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - dev: true /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -2073,7 +2370,7 @@ packages: resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} dependencies: '@gar/promisify': 1.1.3 - semver: 7.6.0 + semver: 7.6.2 dev: true /@npmcli/move-file@1.1.2: @@ -2092,93 +2389,18 @@ packages: json-parse-even-better-errors: 2.3.1 dev: true - /@remix-run/dev@1.12.0(@types/node@14.18.33): - resolution: {integrity: sha512-lBiA2FlDi+DjpOAE/vn93zFTSxudKag/FGpmbV6O+LQItDCpFARfbBMhTck/uKcc95nyhRd1GGhQ4ZDgQnyjaQ==} + /@remix-run/router@1.5.0: + resolution: {integrity: sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==} engines: {node: '>=14'} - hasBin: true - peerDependencies: - '@remix-run/serve': ^1.12.0 - peerDependenciesMeta: - '@remix-run/serve': - optional: true - dependencies: - '@babel/core': 7.24.0 - '@babel/generator': 7.23.6 - '@babel/parser': 7.24.0 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.24.0) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) - '@babel/preset-env': 7.24.0(@babel/core@7.24.0) - '@babel/preset-typescript': 7.23.3(@babel/core@7.24.0) - '@babel/traverse': 7.24.0 - '@babel/types': 7.24.0 - '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) - '@npmcli/package-json': 2.0.0 - '@remix-run/server-runtime': 1.12.0 - '@vanilla-extract/integration': 6.5.0(@types/node@14.18.33) - arg: 5.0.2 - cacache: 15.3.0 - chalk: 4.1.2 - chokidar: 3.6.0 - dotenv: 16.4.5 - esbuild: 0.16.3 - execa: 5.1.1 - exit-hook: 2.2.1 - express: 4.18.3 - fast-glob: 3.2.11 - fs-extra: 10.1.0 - get-port: 5.1.1 - gunzip-maybe: 1.4.2 - inquirer: 8.2.6 - jsesc: 3.0.2 - json5: 2.2.3 - lodash: 4.17.21 - lodash.debounce: 4.0.8 - lru-cache: 7.18.3 - minimatch: 3.1.2 - node-fetch: 2.7.0 - ora: 5.4.1 - postcss: 8.4.36 - postcss-discard-duplicates: 5.1.0(postcss@8.4.36) - postcss-modules: 6.0.0(postcss@8.4.36) - prettier: 2.7.1 - pretty-ms: 7.0.1 - proxy-agent: 5.0.0 - recast: 0.21.5 - remark-frontmatter: 4.0.1 - remark-mdx-frontmatter: 1.1.1 - semver: 7.6.0 - sort-package-json: 1.57.0 - tar-fs: 2.1.1 - tsconfig-paths: 4.2.0 - ws: 7.5.9 - xdm: 2.1.0 - transitivePeerDependencies: - - '@types/node' - - bluebird - - bufferutil - - encoding - - less - - lightningcss - - sass - - stylus - - sugarss - - supports-color - - terser - - utf-8-validate dev: true - /@remix-run/router@1.3.1: - resolution: {integrity: sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw==} - engines: {node: '>=14'} - dev: true - - /@remix-run/server-runtime@1.12.0: - resolution: {integrity: sha512-7I0165Ns/ffPfCEfuiqD58lMderTn2s/sew1xJ34ONa21mG/7+5T7diHIgxKST8rS3816JPmlwSqUaHgwbmO6Q==} + /@remix-run/server-runtime@1.15.0: + resolution: {integrity: sha512-DL9xjHfYYrEcOq5VbhYtrjJUWo/nFQAT7Y+Np/oC55HokyU6cb2jGhl52nx96aAxKwaFCse5N90GeodFsRzX7w==} engines: {node: '>=14'} dependencies: - '@remix-run/router': 1.3.1 + '@remix-run/router': 1.5.0 '@types/cookie': 0.4.1 - '@types/react': 18.2.67 + '@types/react': 18.3.3 '@web3-storage/multipart-parser': 1.0.0 cookie: 0.4.2 set-cookie-parser: 2.6.0 @@ -2193,110 +2415,138 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.13.0: - resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==} + /@rollup/rollup-android-arm-eabi@4.18.0: + resolution: {integrity: sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==} cpu: [arm] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.13.0: - resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==} + /@rollup/rollup-android-arm64@4.18.0: + resolution: {integrity: sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.13.0: - resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==} + /@rollup/rollup-darwin-arm64@4.18.0: + resolution: {integrity: sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.13.0: - resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==} + /@rollup/rollup-darwin-x64@4.18.0: + resolution: {integrity: sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.13.0: - resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==} + /@rollup/rollup-linux-arm-gnueabihf@4.18.0: + resolution: {integrity: sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.13.0: - resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==} + /@rollup/rollup-linux-arm-musleabihf@4.18.0: + resolution: {integrity: sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.18.0: + resolution: {integrity: sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.13.0: - resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==} + /@rollup/rollup-linux-arm64-musl@4.18.0: + resolution: {integrity: sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.13.0: - resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==} + /@rollup/rollup-linux-powerpc64le-gnu@4.18.0: + resolution: {integrity: sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.18.0: + resolution: {integrity: sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==} cpu: [riscv64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.13.0: - resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==} + /@rollup/rollup-linux-s390x-gnu@4.18.0: + resolution: {integrity: sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.18.0: + resolution: {integrity: sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.13.0: - resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==} + /@rollup/rollup-linux-x64-musl@4.18.0: + resolution: {integrity: sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.13.0: - resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==} + /@rollup/rollup-win32-arm64-msvc@4.18.0: + resolution: {integrity: sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.13.0: - resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==} + /@rollup/rollup-win32-ia32-msvc@4.18.0: + resolution: {integrity: sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.13.0: - resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==} + /@rollup/rollup-win32-x64-msvc@4.18.0: + resolution: {integrity: sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true + /@sinclair/typebox@0.25.24: + resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + dev: true + /@sindresorhus/is@4.6.0: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -2314,32 +2564,36 @@ packages: buffer: 6.0.3 dev: true - /@solana/web3.js@1.73.0: - resolution: {integrity: sha512-YrgX3Py7ylh8NYkbanoINUPCj//bWUjYZ5/WPy9nQ9SK3Cl7QWCR+NmbDjmC/fTspZGR+VO9LTQslM++jr5PRw==} - engines: {node: '>=12.20.0'} + /@solana/web3.js@1.93.0: + resolution: {integrity: sha512-suf4VYwWxERz4tKoPpXCRHFRNst7jmcFUaD65kII+zg9urpy5PeeqgLV6G5eWGzcVzA9tZeXOju1A1Y+0ojEVw==} dependencies: - '@babel/runtime': 7.24.0 - '@noble/ed25519': 1.7.3 - '@noble/hashes': 1.3.1 - '@noble/secp256k1': 1.7.1 + '@babel/runtime': 7.24.7 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 '@solana/buffer-layout': 4.0.1 agentkeepalive: 4.5.0 bigint-buffer: 1.1.5 bn.js: 5.2.1 borsh: 0.7.0 bs58: 4.0.1 - buffer: 6.0.1 + buffer: 6.0.3 fast-stable-stringify: 1.0.0 - jayson: 3.7.0 + jayson: 4.1.0 node-fetch: 2.7.0 - rpc-websockets: 7.9.0 - superstruct: 0.14.2 + rpc-websockets: 9.0.1 + superstruct: 1.0.4 transitivePeerDependencies: - bufferutil - encoding - utf-8-validate dev: true + /@swc/helpers@0.5.11: + resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} + dependencies: + tslib: 2.6.3 + dev: true + /@szmarczak/http-timer@4.0.6: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -2361,8 +2615,8 @@ packages: path-browserify: 1.0.1 dev: true - /@tsconfig/node10@1.0.9: - resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} + /@tsconfig/node10@1.0.11: + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} dev: true /@tsconfig/node12@1.0.11: @@ -2388,7 +2642,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.11.28 + '@types/node': 20.14.2 '@types/responselike': 1.0.3 dev: true @@ -2428,7 +2682,7 @@ packages: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.2 - '@types/node': 20.11.28 + '@types/node': 20.14.2 dev: true /@types/hast@2.3.10: @@ -2452,7 +2706,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 20.11.28 + '@types/node': 20.14.2 dev: true /@types/mdast@3.0.15: @@ -2481,46 +2735,55 @@ packages: resolution: {integrity: sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==} dev: true - /@types/node@20.11.28: - resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==} + /@types/node@20.14.2: + resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} dependencies: undici-types: 5.26.5 dev: true - /@types/prop-types@15.7.11: - resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + /@types/prop-types@15.7.12: + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} dev: true - /@types/react@18.2.67: - resolution: {integrity: sha512-vkIE2vTIMHQ/xL0rgmuoECBCkZFZeHr49HeWSc24AptMbNRo7pwSBvj73rlJJs9fGKj0koS+V7kQB1jHS0uCgw==} + /@types/react@18.3.3: + resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} dependencies: - '@types/prop-types': 15.7.11 - '@types/scheduler': 0.16.8 + '@types/prop-types': 15.7.12 csstype: 3.1.3 dev: true /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 20.11.28 + '@types/node': 20.14.2 dev: true - /@types/scheduler@0.16.8: - resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + /@types/semver@7.5.8: + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} dev: true + /@types/uuid@8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + /@types/ws@7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: '@types/node': 12.20.55 dev: true - /@typescript-eslint/eslint-plugin@5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg==} + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 20.14.2 + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -2530,41 +2793,25 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.0.0(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/scope-manager': 5.0.0 - debug: 4.3.4 - eslint: 8.0.1 - functional-red-black-tree: 1.0.1 + '@eslint-community/regexpp': 4.10.1 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + debug: 4.3.5 + eslint: 8.57.0 + graphemer: 1.4.0 ignore: 5.3.1 - regexpp: 3.2.0 - semver: 7.6.0 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 + natural-compare-lite: 1.4.0 + semver: 7.6.2 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@5.0.0(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - dependencies: - '@types/json-schema': 7.0.15 - '@typescript-eslint/scope-manager': 5.0.0 - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/typescript-estree': 5.0.0(typescript@4.9.4) - eslint: 8.0.1 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.0.1) - transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/parser@5.46.1(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==} + /@typescript-eslint/parser@5.62.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2573,44 +2820,51 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.46.1 - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/typescript-estree': 5.46.1(typescript@4.9.4) - debug: 4.3.4 - eslint: 8.0.1 - typescript: 4.9.4 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + debug: 4.3.5 + eslint: 8.57.0 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.0.0: - resolution: {integrity: sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ==} + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@5.46.1: - resolution: {integrity: sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==} + /@typescript-eslint/type-utils@5.62.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/visitor-keys': 5.46.1 - dev: true - - /@typescript-eslint/types@5.0.0: - resolution: {integrity: sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + debug: 4.3.5 + eslint: 8.57.0 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color dev: true - /@typescript-eslint/types@5.46.1: - resolution: {integrity: sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==} + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.0.0(typescript@4.9.4): - resolution: {integrity: sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q==} + /@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -2618,97 +2872,95 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 - debug: 4.3.4 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.0 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 + semver: 7.6.2 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.46.1(typescript@4.9.4): - resolution: {integrity: sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==} + /@typescript-eslint/utils@5.62.0(eslint@8.57.0)(typescript@4.9.5): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/visitor-keys': 5.46.1 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.6.0 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@types/json-schema': 7.0.15 + '@types/semver': 7.5.8 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + eslint: 8.57.0 + eslint-scope: 5.1.1 + semver: 7.6.2 transitivePeerDependencies: - supports-color + - typescript dev: true - /@typescript-eslint/visitor-keys@5.0.0: - resolution: {integrity: sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw==} + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.0.0 + '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@5.46.1: - resolution: {integrity: sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.46.1 - eslint-visitor-keys: 3.4.3 + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} dev: true - /@vanilla-extract/babel-plugin-debug-ids@1.0.5: - resolution: {integrity: sha512-Rc9A6ylsw7EBErmpgqCMvc/Z/eEZxI5k1xfLQHw7f5HHh3oc5YfzsAsYU/PdmSNjF1dp3sGEViBdDltvwnfVaA==} + /@vanilla-extract/babel-plugin-debug-ids@1.0.6: + resolution: {integrity: sha512-C188vUEYmw41yxg3QooTs8r1IdbDQQ2mH7L5RkORBnHx74QlmsNfqVmKwAVTgrlYt8JoRaWMtPfGm/Ql0BNQrA==} dependencies: - '@babel/core': 7.24.0 + '@babel/core': 7.24.7 transitivePeerDependencies: - supports-color dev: true - /@vanilla-extract/css@1.14.1: - resolution: {integrity: sha512-V4JUuHNjZgl64NGfkDJePqizkNgiSpphODtZEs4cCPuxLAzwOUJYATGpejwimJr1n529kq4DEKWexW22LMBokw==} + /@vanilla-extract/css@1.15.3: + resolution: {integrity: sha512-mxoskDAxdQAspbkmQRxBvolUi1u1jnyy9WZGm+GeH8V2wwhEvndzl1QoK7w8JfA0WFevTxbev5d+i+xACZlPhA==} dependencies: '@emotion/hash': 0.9.1 - '@vanilla-extract/private': 1.0.3 - chalk: 4.1.2 + '@vanilla-extract/private': 1.0.5 css-what: 6.1.0 cssesc: 3.0.0 csstype: 3.1.3 + dedent: 1.5.3 deep-object-diff: 1.1.9 deepmerge: 4.3.1 media-query-parser: 2.0.2 modern-ahocorasick: 1.0.1 - outdent: 0.8.0 + picocolors: 1.0.1 + transitivePeerDependencies: + - babel-plugin-macros dev: true /@vanilla-extract/integration@6.5.0(@types/node@14.18.33): resolution: {integrity: sha512-E2YcfO8vA+vs+ua+gpvy1HRqvgWbI+MTlUpxA8FvatOvybuNcWAY0CKwQ/Gpj7rswYKtC6C7+xw33emM6/ImdQ==} dependencies: - '@babel/core': 7.24.0 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.0) - '@vanilla-extract/babel-plugin-debug-ids': 1.0.5 - '@vanilla-extract/css': 1.14.1 + '@babel/core': 7.24.7 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) + '@vanilla-extract/babel-plugin-debug-ids': 1.0.6 + '@vanilla-extract/css': 1.15.3 esbuild: 0.19.12 eval: 0.1.8 find-up: 5.0.0 javascript-stringify: 2.1.0 lodash: 4.17.21 - mlly: 1.6.1 + mlly: 1.7.1 outdent: 0.8.0 - vite: 5.1.6(@types/node@14.18.33) - vite-node: 1.4.0(@types/node@14.18.33) + vite: 5.3.1(@types/node@14.18.33) + vite-node: 1.6.0(@types/node@14.18.33) transitivePeerDependencies: - '@types/node' + - babel-plugin-macros - less - lightningcss - sass @@ -2718,28 +2970,32 @@ packages: - terser dev: true - /@vanilla-extract/private@1.0.3: - resolution: {integrity: sha512-17kVyLq3ePTKOkveHxXuIJZtGYs+cSoev7BlP+Lf4916qfDhk/HBjvlYDe8egrea7LNPHKwSZJK/bzZC+Q6AwQ==} + /@vanilla-extract/private@1.0.5: + resolution: {integrity: sha512-6YXeOEKYTA3UV+RC8DeAjFk+/okoNz/h88R+McnzA2zpaVqTR/Ep+vszkWYlGBcMNO7vEkqbq5nT/JMMvhi+tw==} + dev: true + + /@vercel/build-utils@6.7.1: + resolution: {integrity: sha512-Ecc9oQBSVwk1suENcRcj1L6gQrUt4+0XA9oPFxrUpoFEk04lP/ZV3qAQPk+ex08N+vfUulYdqb+cmVTnwqsmqw==} dev: true - /@vercel/build-utils@6.3.0: - resolution: {integrity: sha512-Nbu/CIsv8HMp1+KPZ0n2YlHTKPfGRDrwhMgKW9Dx4z2S5sQWkXpe9WQ5ajePgwZVd7V1XiJYx1CCRaupIVgUwA==} + /@vercel/error-utils@1.0.8: + resolution: {integrity: sha512-s+f7jP2oH1koICbQ8e3K9hOpOeUct7rbCnF9qsNwXemq850wAh2e90tp9R6oYBM0BNpiLRRm+oG5zD2sCIm3HQ==} dev: true - /@vercel/gatsby-plugin-vercel-analytics@1.0.7: - resolution: {integrity: sha512-j4DsneQ+oOF0Zurvisj+H2ds8s8ZEqfI4iD6xgFY9mB2UdGixhzFRjvDBH6g4pfUQXfO76K5GiA1afumGlJbwA==} + /@vercel/gatsby-plugin-vercel-analytics@1.0.10: + resolution: {integrity: sha512-v329WHdtIce+y7oAmaWRvEx59Xfo0FxlQqK4BJG0u6VWYoKWPaflohDAiehIZf/YHCRVb59ZxnzmMOcm/LR8YQ==} dependencies: '@babel/runtime': 7.12.1 web-vitals: 0.2.4 dev: true - /@vercel/gatsby-plugin-vercel-builder@1.1.7: - resolution: {integrity: sha512-XSGT/EOk2BgZ0qRQCn+qGoJmFZHRJ0t9SF+cOtyQ79CtYx0JWDWDlbYEx2r6hDSPsUAsiRnaUmxL5qLzDg4sQg==} + /@vercel/gatsby-plugin-vercel-builder@1.2.10: + resolution: {integrity: sha512-7iSCCOe5XyU8lJVcWd9dDxXq8qF91nEKkO6McxOOVRgiPsJU4T/x48o/+gIbUa35zIv7XltZojRQDRq3jzyfWQ==} dependencies: - '@vercel/build-utils': 6.3.0 - '@vercel/node': 2.9.6 - '@vercel/routing-utils': 2.1.9 - ajv: 8.12.0 + '@sinclair/typebox': 0.25.24 + '@vercel/build-utils': 6.7.1 + '@vercel/node': 2.12.0 + '@vercel/routing-utils': 2.2.0 esbuild: 0.14.47 etag: 1.8.1 fs-extra: 11.1.0 @@ -2749,16 +3005,16 @@ packages: - encoding dev: true - /@vercel/go@2.3.7: - resolution: {integrity: sha512-ffmvGJzalWeOUQ8FfQ4pfqcd4YcQ4y52pTVS5fZXrjCwPYduIdKOowLDXRq08Kv8Llpl42reDaSGWuusFLKF7A==} + /@vercel/go@2.5.0: + resolution: {integrity: sha512-KUUuFpl65oxyCbc7gDWkhbRUg2ZcAa5bpUrhnqYW4ohDicPGe7F7mo/v4GCp/zsFGFNJf9msbmycJA1f9Sk9Ug==} dev: true - /@vercel/hydrogen@0.0.53: - resolution: {integrity: sha512-gJvAL0SbAOR1gS6MMr0EHnKlD3Ri1F0eniIfDpV5qgSNqjzVSSVI3tT8ag4KCS70H1tawj16XMR7oPRcKmyebQ==} + /@vercel/hydrogen@0.0.63: + resolution: {integrity: sha512-FxBjgX0Mt22eqvHGrMKDcfxt/81y9QrHM6md+hGIflkQ9DvrtyYmmFze588yXWAv/I04eCgVoE+/KsgETkRi3w==} dev: true - /@vercel/next@3.4.7: - resolution: {integrity: sha512-C57Uhckij/X9Fx1BaYLWugUiUKrI1ZpmwYIttZgYIM0XdnBArZ14hc+p4shhjWDy7+sG0Fq2IMfANEMLxaJq3A==} + /@vercel/next@3.7.5: + resolution: {integrity: sha512-NonL8rt49EnwooMnAXYUDpz2B+e+yoQRdEZoekZlnFzP6VF1F1r14N2X9zUqxeRH7rY6X53MgiRNSHeZKqTXPA==} dev: true /@vercel/nft@0.22.5: @@ -2768,14 +3024,14 @@ packages: dependencies: '@mapbox/node-pre-gyp': 1.0.11 '@rollup/pluginutils': 4.2.1 - acorn: 8.11.3 + acorn: 8.12.0 async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 glob: 7.2.3 graceful-fs: 4.2.11 - micromatch: 4.0.5 - node-gyp-build: 4.8.0 + micromatch: 4.0.7 + node-gyp-build: 4.8.1 resolve-from: 5.0.0 transitivePeerDependencies: - encoding @@ -2789,14 +3045,14 @@ packages: dependencies: '@mapbox/node-pre-gyp': 1.0.11 '@rollup/pluginutils': 4.2.1 - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) + acorn: 8.12.0 + acorn-import-attributes: 1.9.5(acorn@8.12.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 glob: 7.2.3 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.7 node-gyp-build: 4.8.1 resolve-from: 5.0.0 transitivePeerDependencies: @@ -2804,22 +3060,26 @@ packages: - supports-color dev: true - /@vercel/node-bridge@3.1.11: - resolution: {integrity: sha512-LGbj+kPGgRnIlKo3949z01mLbHVi4BnRE7V5R6+J4E3f7xpQ12I9Wek10V7ivLB+LyS1+ATdjasdXAF4HOhqQw==} + /@vercel/node-bridge@4.0.1: + resolution: {integrity: sha512-XEfKfnLGzlIBpad7eGNPql1HnMhoSTv9q3uDNC4axdaAC/kI5yvl8kXjuCPAXYvpbJnVQPpcSUC5/r5ap8F3jA==} dev: true - /@vercel/node@2.9.6: - resolution: {integrity: sha512-A1/1LucW54jUH8YspTTQYeGdhOPK8Z17bt5vrnB4PW5PGnq5Dn2DaC1mly0/Lo4Qlz44xDIiknwGvAitLAs2gQ==} + /@vercel/node@2.12.0: + resolution: {integrity: sha512-QItQ4DjKrHqTMk/hmtX64V5RfDdp+fDoFzbSbPUICkIOHK3EBCJ5c/392Iv05AwSv+mJIALZUGRQz5o4HKvs6A==} dependencies: '@edge-runtime/vm': 2.0.0 '@types/node': 14.18.33 - '@vercel/build-utils': 6.3.0 - '@vercel/node-bridge': 3.1.11 - '@vercel/static-config': 2.0.13 - edge-runtime: 2.0.0 + '@vercel/build-utils': 6.7.1 + '@vercel/error-utils': 1.0.8 + '@vercel/node-bridge': 4.0.1 + '@vercel/static-config': 2.0.16 + async-listen: 1.2.0 + edge-runtime: 2.1.4 esbuild: 0.14.47 exit-hook: 2.2.1 node-fetch: 2.6.7 + path-to-regexp: 6.2.1 + ts-morph: 12.0.0 ts-node: 10.9.1(@types/node@14.18.33)(typescript@4.3.4) typescript: 4.3.4 transitivePeerDependencies: @@ -2828,32 +3088,115 @@ packages: - encoding dev: true - /@vercel/python@3.1.49: - resolution: {integrity: sha512-0HfFoaU2k+9+Q3oAmUihkpfNonswQq99smhjntBOJfpUTHGbBu/6IXAJJFBYWnRF6sObyaNNoE61NKe84drAtQ==} + /@vercel/python@3.1.59: + resolution: {integrity: sha512-38/KM33nJK5Jk+FiNhi3MTB7arWGGoCF8blejAexpw+NTL70nNy+4O7TN+y7qqx7Az4nygEgBBTgQVfkgIj0Yg==} dev: true - /@vercel/redwood@1.1.5: - resolution: {integrity: sha512-JLgzxhE/g4KgXLoQb7OXTkVFdOkpr/cnY3MAYJa8xw+TD0Nxo9hisXRjoIOQlmpRy4P7HYVruqs9JgCNJ7GRxQ==} + /@vercel/redwood@1.1.14: + resolution: {integrity: sha512-QFIhLegvfVp2OLdv96krTyz6C5/cUncUg4CEEfx3U48+l31hWaWcnjI6+MhgN4PZC4YN+s21vKZNz/UWnGnTiA==} dependencies: '@vercel/nft': 0.22.5 - '@vercel/routing-utils': 2.1.9 + '@vercel/routing-utils': 2.2.0 semver: 6.1.1 transitivePeerDependencies: - encoding - supports-color dev: true - /@vercel/remix@1.3.3(@types/node@14.18.33): - resolution: {integrity: sha512-adUiEJJNG7Ca89go3mf6X0e6yXx971aTLnT1DhZG5IFAAyc82Gqq+0TZb4m2LYmfvXp6HMJZNv1K57psYJxIiw==} + /@vercel/remix-builder@1.8.5(@types/node@14.18.33): + resolution: {integrity: sha512-nXUNsW6+gfHRqnZdXNm9Myx8G8nihbfRe/myAbvUHAXaym+9Bz+WHC3hXXr6YqAOVhjWvCfxAlA9eYqHbhlvKA==} + dependencies: + '@remix-run/dev': /@vercel/remix-run-dev@1.15.0(@types/node@14.18.33) + '@vercel/build-utils': 6.7.1 + '@vercel/nft': 0.22.5 + '@vercel/static-config': 2.0.16 + path-to-regexp: 6.2.1 + semver: 7.3.8 + ts-morph: 12.0.0 + transitivePeerDependencies: + - '@remix-run/serve' + - '@types/node' + - babel-plugin-macros + - bluebird + - bufferutil + - encoding + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + - ts-node + - utf-8-validate + dev: true + + /@vercel/remix-run-dev@1.15.0(@types/node@14.18.33): + resolution: {integrity: sha512-pQTM5WmOzrvhpPSHFDShwqX71YnLaTUxffhnly4MxVNKJ2WKV9zqx8bGQ/7cLfpEu9JfY2c+pVjYYb3wAMBt+Q==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + '@remix-run/serve': ^1.15.0 + peerDependenciesMeta: + '@remix-run/serve': + optional: true dependencies: - '@remix-run/dev': 1.12.0(@types/node@14.18.33) - '@vercel/nft': 0.22.5 - '@vercel/static-config': 2.0.13 - path-to-regexp: 6.2.1 - ts-morph: 12.0.0 + '@babel/core': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.7) + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) + '@babel/preset-env': 7.24.7(@babel/core@7.24.7) + '@babel/preset-typescript': 7.24.7(@babel/core@7.24.7) + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) + '@npmcli/package-json': 2.0.0 + '@remix-run/server-runtime': 1.15.0 + '@vanilla-extract/integration': 6.5.0(@types/node@14.18.33) + arg: 5.0.2 + cacache: 15.3.0 + chalk: 4.1.2 + chokidar: 3.6.0 + dotenv: 16.4.5 + esbuild: 0.16.3 + execa: 5.1.1 + exit-hook: 2.2.1 + express: 4.19.2 + fast-glob: 3.2.11 + fs-extra: 10.1.0 + get-port: 5.1.1 + glob-to-regexp: 0.4.1 + gunzip-maybe: 1.4.2 + inquirer: 8.2.6 + jsesc: 3.0.2 + json5: 2.2.3 + lodash: 4.17.21 + lodash.debounce: 4.0.8 + lru-cache: 7.18.3 + minimatch: 3.1.2 + node-fetch: 2.7.0 + ora: 5.4.1 + postcss: 8.4.38 + postcss-discard-duplicates: 5.1.0(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-modules: 6.0.0(postcss@8.4.38) + prettier: 2.7.1 + pretty-ms: 7.0.1 + proxy-agent: 5.0.0 + react-refresh: 0.14.2 + recast: 0.21.5 + remark-frontmatter: 4.0.1 + remark-mdx-frontmatter: 1.1.1 + semver: 7.6.2 + sort-package-json: 1.57.0 + tar-fs: 2.1.1 + tsconfig-paths: 4.2.0 + ws: 7.5.9 + xdm: 2.1.0 transitivePeerDependencies: - - '@remix-run/serve' - '@types/node' + - babel-plugin-macros - bluebird - bufferutil - encoding @@ -2864,34 +3207,35 @@ packages: - sugarss - supports-color - terser + - ts-node - utf-8-validate dev: true - /@vercel/routing-utils@2.1.9: - resolution: {integrity: sha512-DVE9coIpicZQBKWL0DgIe5wnZsi4SRPbD51XxFCvvnRyYxG34DY09R0aMz4ZQQdPK2asJF57i5rbcplXYaEOkg==} + /@vercel/routing-utils@2.2.0: + resolution: {integrity: sha512-Ro90s1mStpbgu2HV8I4LFEKNG8GVxkWm238ebD/23BCO9/DxIJ3+wCzga8j8BMmG57x4etVlaHNV25bbzW5r2g==} dependencies: path-to-regexp: 6.1.0 optionalDependencies: ajv: 6.12.6 dev: true - /@vercel/ruby@1.3.65: - resolution: {integrity: sha512-MXQ6WlzxVh6ibvVlotRBP/oi27M7QnX0BWPBI4DakNJ7sGPbWbO1bOd66A1GaAK27MFvdKETIXcgvabfhIaSYQ==} + /@vercel/ruby@1.3.75: + resolution: {integrity: sha512-sUmzJnd9O1N7StFEpKG9JvHJvHmJjgfrmhgQsQLEQ7OOQJkO9DYoLomlrIDW9qNdu7dNOeyj7gQY5B8y8RMntw==} dev: true - /@vercel/static-build@1.3.9: - resolution: {integrity: sha512-3cZuQol7nIe2yxfTOq2JGbUIryaQ+W6XEN/PPLZ5nDHdjzCBeFIIHbjxlX4NtyDcPIrfoCZG+UdsCl6fEGpwAA==} + /@vercel/static-build@1.3.25: + resolution: {integrity: sha512-yBb37pPGLlQEF/QPUezENo4Eu9gq7Ctzl56Dff/Kv6pApzYZ6Zj88OvRoNBTXhxDi0g4EGSYnP0uYtB7lBQcHA==} dependencies: - '@vercel/gatsby-plugin-vercel-analytics': 1.0.7 - '@vercel/gatsby-plugin-vercel-builder': 1.1.7 + '@vercel/gatsby-plugin-vercel-analytics': 1.0.10 + '@vercel/gatsby-plugin-vercel-builder': 1.2.10 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' - encoding dev: true - /@vercel/static-config@2.0.13: - resolution: {integrity: sha512-09bVISGyhRMoL6gQTfM7n89SeUmyOlIzVMo2oNOj3thy4AIKGuN0SzEp0qNRw8d9j07rifp9JPD4rOuDRx4+eA==} + /@vercel/static-config@2.0.16: + resolution: {integrity: sha512-lULo+NWBMpTJb9kR4AwYYK/2e7wknTJO2iFxgYYOkG5i12WHgPhMnXDKrEOcotxctd0yPKx3TsWVGEXniNm63g==} dependencies: ajv: 8.6.3 json-schema-to-ts: 1.6.4 @@ -2922,29 +3266,31 @@ packages: negotiator: 0.6.3 dev: true - /acorn-import-attributes@1.9.5(acorn@8.11.3): + /acorn-import-attributes@1.9.5(acorn@8.12.0): resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.3 + acorn: 8.12.0 dev: true - /acorn-jsx@5.3.2(acorn@8.11.3): + /acorn-jsx@5.3.2(acorn@8.12.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.3 + acorn: 8.12.0 dev: true - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + /acorn-walk@8.3.3: + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} engines: {node: '>=0.4.0'} + dependencies: + acorn: 8.12.0 dev: true - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + /acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -2953,7 +3299,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true @@ -2982,15 +3328,6 @@ packages: uri-js: 4.4.1 dev: true - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - /ajv@8.6.3: resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} dependencies: @@ -3000,11 +3337,6 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true - /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -3022,6 +3354,10 @@ packages: engines: {node: '>=12'} dev: true + /ansi-sequence-parser@1.1.1: + resolution: {integrity: sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==} + dev: true + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} @@ -3056,6 +3392,7 @@ packages: /are-we-there-yet@2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} + deprecated: This package is no longer supported. dependencies: delegates: 1.0.0 readable-stream: 3.6.2 @@ -3096,13 +3433,14 @@ packages: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} dev: true - /array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 get-intrinsic: 1.2.4 is-string: 1.0.7 dev: true @@ -3112,13 +3450,35 @@ packages: engines: {node: '>=8'} dev: true + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: true + /array.prototype.flat@1.3.2: resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 es-shim-unscopables: 1.0.2 dev: true @@ -3129,7 +3489,7 @@ packages: array-buffer-byte-length: 1.0.1 call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-abstract: 1.23.3 es-errors: 1.3.0 get-intrinsic: 1.2.4 is-array-buffer: 3.0.4 @@ -3150,14 +3510,14 @@ packages: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} dependencies: - tslib: 2.6.2 + tslib: 2.6.3 dev: true /ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} dependencies: - tslib: 2.6.2 + tslib: 2.6.3 dev: true /astring@1.8.6: @@ -3165,6 +3525,15 @@ packages: hasBin: true dev: true + /async-listen@1.2.0: + resolution: {integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==} + dev: true + + /async-listen@2.0.3: + resolution: {integrity: sha512-WVLi/FGIQaXyfYyNvmkwKT1RZbkzszLLnmW/gFCc5lbVvN/0QQCWpBwRBk2OWSdkkmKRBc8yD6BrKsjA3XKaSw==} + engines: {node: '>= 14'} + dev: true + /async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} dev: true @@ -3181,8 +3550,8 @@ packages: dependencies: '@ava/typescript': 5.0.0 '@vercel/nft': 0.26.5 - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.12.0 + acorn-walk: 8.3.3 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 @@ -3197,7 +3566,7 @@ packages: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.3.4 + debug: 4.3.5 emittery: 1.0.3 figures: 6.1.0 globby: 14.0.1 @@ -3232,38 +3601,38 @@ packages: possible-typed-array-names: 1.0.0 dev: true - /babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.24.0): - resolution: {integrity: sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==} + /babel-plugin-polyfill-corejs2@0.4.11(@babel/core@7.24.7): + resolution: {integrity: sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.24.0) + '@babel/compat-data': 7.24.7 + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.24.0): - resolution: {integrity: sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==} + /babel-plugin-polyfill-corejs3@0.10.4(@babel/core@7.24.7): + resolution: {integrity: sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.24.0) - core-js-compat: 3.36.0 + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) + core-js-compat: 3.37.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.24.0): - resolution: {integrity: sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==} + /babel-plugin-polyfill-regenerator@0.6.2(@babel/core@7.24.7): + resolution: {integrity: sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.24.0 - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.24.0) + '@babel/core': 7.24.7 + '@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.24.7) transitivePeerDependencies: - supports-color dev: true @@ -3370,11 +3739,11 @@ packages: balanced-match: 1.0.2 dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 dev: true /browserify-zlib@0.1.4: @@ -3383,15 +3752,15 @@ packages: pako: 0.2.9 dev: true - /browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + /browserslist@4.23.1: + resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001599 - electron-to-chromium: 1.4.709 + caniuse-lite: 1.0.30001634 + electron-to-chromium: 1.4.803 node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.23.0) + update-browserslist-db: 1.0.16(browserslist@4.23.1) dev: true /bs58@4.0.1: @@ -3417,13 +3786,6 @@ packages: ieee754: 1.2.1 dev: true - /buffer@6.0.1: - resolution: {integrity: sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - /buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: @@ -3436,7 +3798,7 @@ packages: engines: {node: '>=6.14.2'} requiresBuild: true dependencies: - node-gyp-build: 4.8.0 + node-gyp-build: 4.8.1 dev: true /bytes@3.1.2: @@ -3469,7 +3831,7 @@ packages: promise-inflight: 1.0.1 rimraf: 3.0.2 ssri: 8.0.1 - tar: 6.2.0 + tar: 6.2.1 unique-filename: 1.1.1 transitivePeerDependencies: - bluebird @@ -3514,8 +3876,8 @@ packages: engines: {node: '>=12.20'} dev: true - /caniuse-lite@1.0.30001599: - resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==} + /caniuse-lite@1.0.30001634: + resolution: {integrity: sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==} dev: true /cbor@9.0.2: @@ -3572,7 +3934,7 @@ packages: engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -3717,10 +4079,14 @@ packages: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.6.1 + semver: 7.6.2 well-known-symbols: 2.0.0 dev: true + /confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + dev: true + /confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} dev: true @@ -3764,15 +4130,15 @@ packages: engines: {node: '>= 0.6'} dev: true - /cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} dev: true - /core-js-compat@3.36.0: - resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} + /core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} dependencies: - browserslist: 4.23.0 + browserslist: 4.23.1 dev: true /core-util-is@1.0.3: @@ -3853,8 +4219,8 @@ packages: time-zone: 1.0.0 dev: true - /deasync@0.1.29: - resolution: {integrity: sha512-EBtfUhVX23CE9GR6m+F8WPeImEE4hR/FW9RkK0PMl9V1t283s0elqsTD8EZjaKX28SY1BW2rYfCgNsAYdpamUw==} + /deasync@0.1.30: + resolution: {integrity: sha512-OaAjvEQuQ9tJsKG4oHO9nV1UHTwb2Qc2+fadB0VeVtD0Z9wiG1XPGLJ4W3aLhAoQSYTaLROFRbd5X20Dkzf7MQ==} engines: {node: '>=0.11.0'} requiresBuild: true dependencies: @@ -3885,8 +4251,8 @@ packages: ms: 2.1.3 dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + /debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -3910,6 +4276,15 @@ packages: mimic-response: 3.1.0 dev: true + /dedent@1.5.3: + resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + dev: true + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -3991,8 +4366,8 @@ packages: engines: {node: '>=8'} dev: true - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + /detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} engines: {node: '>=8'} dev: true @@ -4046,14 +4421,15 @@ packages: stream-shift: 1.0.3 dev: true - /edge-runtime@2.0.0: - resolution: {integrity: sha512-TmRJhKi4mlM1e+zgF4CSzVU5gJ1sWj7ia+XhVgZ8PYyYUxk4PPjJU8qScpSLsAbdSxoBghLxdMuwuCzdYLd1sQ==} + /edge-runtime@2.1.4: + resolution: {integrity: sha512-SertKByzAmjm+MkLbFl1q0ko+/90V24dhZgQM8fcdguQaDYVEVtb6okEBGeg8IQgL1/JUP8oSlUIxSI/bvsVRQ==} + engines: {node: '>=14'} hasBin: true dependencies: - '@edge-runtime/format': 1.1.0 - '@edge-runtime/vm': 2.0.0 + '@edge-runtime/format': 2.0.1 + '@edge-runtime/vm': 2.1.2 + async-listen: 2.0.3 exit-hook: 2.2.1 - http-status: 1.5.3 mri: 1.2.0 picocolors: 1.0.0 pretty-bytes: 5.6.0 @@ -4065,8 +4441,8 @@ packages: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true - /electron-to-chromium@1.4.709: - resolution: {integrity: sha512-ixj1cyHrKqmdXF5CeHDSLbO0KRuOE1BHdCYKbcRA04dPLaKu8Vi7JDK5KLnGrfD6WxKcSEGm9gtHR4MqBq8gmg==} + /electron-to-chromium@1.4.803: + resolution: {integrity: sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==} dev: true /emittery@1.0.3: @@ -4098,63 +4474,8 @@ packages: once: 1.4.0 dev: true - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - dev: true - - /es-abstract@1.22.5: - resolution: {integrity: sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==} - engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - es-define-property: 1.0.0 - es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.3 - gopd: 1.0.1 - has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 - is-callable: 1.2.7 - is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.1 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.5 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 - dev: true - - /es-abstract@1.23.2: - resolution: {integrity: sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==} + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.1 @@ -4172,7 +4493,7 @@ packages: function.prototype.name: 1.1.6 get-intrinsic: 1.2.4 get-symbol-description: 1.0.2 - globalthis: 1.0.3 + globalthis: 1.0.4 gopd: 1.0.1 has-property-descriptors: 1.0.2 has-proto: 1.0.3 @@ -4196,11 +4517,11 @@ packages: safe-regex-test: 1.0.3 string.prototype.trim: 1.2.9 string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.7 + string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.2 typed-array-byte-length: 1.0.1 typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.5 + typed-array-length: 1.0.6 unbox-primitive: 1.0.2 which-typed-array: 1.1.15 dev: true @@ -4527,6 +4848,37 @@ packages: '@esbuild/win32-x64': 0.19.12 dev: true + /esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + dev: true + /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} @@ -4569,7 +4921,7 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.26.0)(eslint@8.0.1): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -4577,35 +4929,35 @@ packages: eslint-plugin-import: ^2.25.2 dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.0.1 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + eslint: 8.57.0 + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) object.assign: 4.1.5 - object.entries: 1.1.7 + object.entries: 1.1.8 semver: 6.3.1 dev: true - /eslint-config-airbnb-typescript@17.0.0(@typescript-eslint/eslint-plugin@5.0.0)(@typescript-eslint/parser@5.46.1)(eslint-plugin-import@2.26.0)(eslint@8.0.1): - resolution: {integrity: sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==} + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.29.1)(eslint@8.57.0): + resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.13.0 - '@typescript-eslint/parser': ^5.0.0 + '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 + '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - eslint: 8.0.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.0.1) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.0)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + eslint: 8.57.0 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1)(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0) dev: true - /eslint-config-prettier@8.5.0(eslint@8.0.1): - resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + /eslint-config-prettier@8.10.0(eslint@8.57.0): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.0.1 + eslint: 8.57.0 dev: true /eslint-import-resolver-node@0.3.9: @@ -4618,7 +4970,7 @@ packages: - supports-color dev: true - /eslint-module-utils@2.8.1(@typescript-eslint/parser@5.46.1)(eslint-import-resolver-node@0.3.9)(eslint@8.0.1): + /eslint-module-utils@2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} engines: {node: '>=4'} peerDependencies: @@ -4639,16 +4991,16 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.5) debug: 3.2.7 - eslint: 8.0.1 + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1): - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.62.0)(eslint@8.57.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4657,20 +5009,24 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - array-includes: 3.1.7 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.0)(typescript@4.9.5) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 - debug: 2.6.9 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.0.1 + eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.46.1)(eslint-import-resolver-node@0.3.9)(eslint@8.0.1) - has: 1.0.4 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 object.values: 1.2.0 - resolve: 1.22.8 + semver: 6.3.1 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -4678,7 +5034,7 @@ packages: - supports-color dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.5.0)(eslint@8.0.1)(prettier@3.2.5): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.0)(prettier@3.3.2): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -4689,9 +5045,9 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.0.1 - eslint-config-prettier: 8.5.0(eslint@8.0.1) - prettier: 3.2.5 + eslint: 8.57.0 + eslint-config-prettier: 8.10.0(eslint@8.57.0) + prettier: 3.3.2 prettier-linter-helpers: 1.0.0 dev: true @@ -4703,77 +5059,62 @@ packages: estraverse: 4.3.0 dev: true - /eslint-scope@6.0.0: - resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.0.1): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.0.1 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.0.1: - resolution: {integrity: sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA==} + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.4.1 - '@humanwhocodes/config-array': 0.6.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.10.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4 + debug: 4.3.5 doctrine: 3.0.0 - enquirer: 2.4.1 escape-string-regexp: 4.0.0 - eslint-scope: 6.0.0 - eslint-utils: 3.0.0(eslint@8.0.1) + eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 + find-up: 5.0.0 glob-parent: 6.0.2 globals: 13.24.0 - ignore: 4.0.6 - import-fresh: 3.3.0 + graphemer: 1.4.0 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 + is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 minimatch: 3.1.2 natural-compare: 1.4.0 - optionator: 0.9.3 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.6.0 + optionator: 0.9.4 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color dev: true @@ -4782,8 +5123,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 3.4.3 dev: true @@ -4881,12 +5222,12 @@ packages: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} engines: {node: '>= 0.8'} dependencies: - '@types/node': 20.11.28 + '@types/node': 20.14.2 require-like: 0.1.2 dev: true - /eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} dev: true /execa@5.1.1: @@ -4924,8 +5265,8 @@ packages: engines: {node: '>=6'} dev: true - /express@4.18.3: - resolution: {integrity: sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==} + /express@4.19.2: + resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} dependencies: accepts: 1.3.8 @@ -4933,7 +5274,7 @@ packages: body-parser: 1.20.2 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.5.0 + cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 @@ -4997,7 +5338,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 dev: true /fast-glob@3.3.2: @@ -5008,7 +5349,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 dev: true /fast-json-stable-stringify@2.1.0: @@ -5065,8 +5406,8 @@ packages: engines: {node: '>= 6'} dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 @@ -5202,14 +5543,10 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-abstract: 1.23.3 functions-have-names: 1.2.3 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true @@ -5217,6 +5554,7 @@ packages: /gauge@3.0.2: resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} engines: {node: '>=10'} + deprecated: This package is no longer supported. dependencies: aproba: 2.0.0 color-support: 1.1.3 @@ -5232,7 +5570,7 @@ packages: /generic-names@4.0.0: resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} dependencies: - loader-utils: 3.2.1 + loader-utils: 3.3.1 dev: true /gensync@1.0.0-beta.2: @@ -5298,7 +5636,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 data-uri-to-buffer: 3.0.1 - debug: 4.3.4 + debug: 4.3.5 file-uri-to-path: 2.0.0 fs-extra: 8.1.0 ftp: 0.3.10 @@ -5324,8 +5662,13 @@ packages: is-glob: 4.0.3 dev: true + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -5347,11 +5690,12 @@ packages: type-fest: 0.20.2 dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} dependencies: define-properties: 1.2.1 + gopd: 1.0.1 dev: true /globby@10.0.0: @@ -5361,7 +5705,7 @@ packages: '@types/glob': 7.2.0 array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.11 + fast-glob: 3.3.2 glob: 7.2.3 ignore: 5.3.1 merge2: 1.4.1 @@ -5419,6 +5763,10 @@ packages: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -5472,11 +5820,6 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: true - /has@1.0.4: - resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} - engines: {node: '>= 0.4.0'} - dev: true - /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -5497,7 +5840,7 @@ packages: hast-util-whitespace: 2.0.1 mdast-util-mdx-expression: 1.3.2 mdast-util-mdxjs-esm: 1.3.1 - property-information: 6.4.1 + property-information: 6.5.0 space-separated-tokens: 2.0.2 style-to-object: 0.4.4 unist-util-position: 4.0.4 @@ -5531,16 +5874,11 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true - /http-status@1.5.3: - resolution: {integrity: sha512-jCClqdnnwigYslmtfb28vPplOgoiZ0siP2Z8C5Ua+3UKbx410v+c+jT+jh1bbI4TvcEySuX0vd/CfFZFbDkJeQ==} - engines: {node: '>= 0.4.0'} - dev: true - /http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} @@ -5554,7 +5892,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true @@ -5582,13 +5920,13 @@ packages: safer-buffer: 2.1.2 dev: true - /icss-utils@5.1.0(postcss@8.4.36): + /icss-utils@5.1.0(postcss@8.4.38): resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.36 + postcss: 8.4.38 dev: true /ieee754@1.2.1: @@ -5600,11 +5938,6 @@ packages: engines: {node: '>=10 <11 || >=12 <13 || >=14'} dev: true - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true - /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -5639,6 +5972,7 @@ packages: /inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. dependencies: once: 1.4.0 wrappy: 1.0.2 @@ -5835,6 +6169,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -5955,8 +6294,8 @@ packages: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} dev: true - /jayson@3.7.0: - resolution: {integrity: sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ==} + /jayson@4.1.0: + resolution: {integrity: sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==} engines: {node: '>=8'} hasBin: true dependencies: @@ -5970,7 +6309,6 @@ packages: eyes: 0.1.8 isomorphic-ws: 4.0.1(ws@7.5.9) json-stringify-safe: 5.0.1 - lodash: 4.17.21 uuid: 8.3.2 ws: 7.5.9 transitivePeerDependencies: @@ -6117,6 +6455,11 @@ packages: type-check: 0.4.0 dev: true + /lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + dev: true + /load-json-file@7.0.1: resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6131,8 +6474,8 @@ packages: json5: 2.2.3 dev: true - /loader-utils@3.2.1: - resolution: {integrity: sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==} + /loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} engines: {node: '>= 12.13.0'} dev: true @@ -6208,7 +6551,7 @@ packages: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.1.1 + semver: 6.3.1 dev: true /make-error@1.3.6: @@ -6294,7 +6637,7 @@ packages: '@types/mdast': 3.0.15 mdast-util-to-markdown: 1.5.0 parse-entities: 4.0.1 - stringify-entities: 4.0.3 + stringify-entities: 4.0.4 unist-util-remove-position: 4.0.2 unist-util-stringify-position: 3.0.3 vfile-message: 3.1.4 @@ -6369,7 +6712,7 @@ packages: /media-query-parser@2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.7 dev: true /media-typer@0.3.0: @@ -6483,8 +6826,8 @@ packages: /micromark-extension-mdxjs@1.0.1: resolution: {integrity: sha512-7YA7hF6i5eKOfFUzZ+0z6avRG52GpWR8DL+kN47y3f2KhxbBZMhmxe7auOeaTBrW2DenbbZTf1ea9tA2hDpC2Q==} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) micromark-extension-mdx-expression: 1.0.8 micromark-extension-mdx-jsx: 1.0.5 micromark-extension-mdx-md: 1.0.1 @@ -6653,7 +6996,7 @@ packages: resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} dependencies: '@types/debug': 4.1.12 - debug: 4.3.4 + debug: 4.3.5 decode-named-character-reference: 1.0.2 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -6673,11 +7016,11 @@ packages: - supports-color dev: true - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + /micromatch@4.0.7: + resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 dev: true @@ -6730,8 +7073,8 @@ packages: brace-expansion: 1.1.11 dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 @@ -6792,13 +7135,13 @@ packages: hasBin: true dev: true - /mlly@1.6.1: - resolution: {integrity: sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA==} + /mlly@1.7.1: + resolution: {integrity: sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==} dependencies: - acorn: 8.11.3 + acorn: 8.12.0 pathe: 1.1.2 - pkg-types: 1.0.3 - ufo: 1.5.2 + pkg-types: 1.1.1 + ufo: 1.5.3 dev: true /modern-ahocorasick@1.0.1: @@ -6832,6 +7175,10 @@ packages: hasBin: true dev: true + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -6876,11 +7223,6 @@ packages: whatwg-url: 5.0.0 dev: true - /node-gyp-build@4.8.0: - resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} - hasBin: true - dev: true - /node-gyp-build@4.8.1: resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} hasBin: true @@ -6929,6 +7271,7 @@ packages: /npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + deprecated: This package is no longer supported. dependencies: are-we-there-yet: 2.0.0 console-control-strings: 1.1.0 @@ -6960,13 +7303,32 @@ packages: object-keys: 1.1.1 dev: true - /object.entries@1.1.7: - resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: true + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: true + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-abstract: 1.23.3 dev: true /object.values@1.2.0: @@ -7017,16 +7379,16 @@ packages: word-wrap: 1.2.5 dev: true - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} + /optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 dev: true /ora@5.4.1: @@ -7090,7 +7452,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.5 get-uri: 3.0.2 http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 @@ -7231,6 +7593,10 @@ packages: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} dev: true + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: true + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} @@ -7241,11 +7607,11 @@ packages: engines: {node: '>=10'} dev: true - /pkg-types@1.0.3: - resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} + /pkg-types@1.1.1: + resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} dependencies: - jsonc-parser: 3.2.1 - mlly: 1.6.1 + confbox: 0.1.7 + mlly: 1.7.1 pathe: 1.1.2 dev: true @@ -7261,74 +7627,91 @@ packages: engines: {node: '>= 0.4'} dev: true - /postcss-discard-duplicates@5.1.0(postcss@8.4.36): + /postcss-discard-duplicates@5.1.0(postcss@8.4.38): resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.4.36 + postcss: 8.4.38 + dev: true + + /postcss-load-config@4.0.2(postcss@8.4.38): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.2 + postcss: 8.4.38 + yaml: 2.4.5 dev: true - /postcss-modules-extract-imports@3.0.0(postcss@8.4.36): - resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} + /postcss-modules-extract-imports@3.1.0(postcss@8.4.38): + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.36 + postcss: 8.4.38 dev: true - /postcss-modules-local-by-default@4.0.4(postcss@8.4.36): - resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==} + /postcss-modules-local-by-default@4.0.5(postcss@8.4.38): + resolution: {integrity: sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.36) - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 postcss-value-parser: 4.2.0 dev: true - /postcss-modules-scope@3.1.1(postcss@8.4.36): - resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==} + /postcss-modules-scope@3.2.0(postcss@8.4.38): + resolution: {integrity: sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 dev: true - /postcss-modules-values@4.0.0(postcss@8.4.36): + /postcss-modules-values@4.0.0(postcss@8.4.38): resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.4.36) - postcss: 8.4.36 + icss-utils: 5.1.0(postcss@8.4.38) + postcss: 8.4.38 dev: true - /postcss-modules@6.0.0(postcss@8.4.36): + /postcss-modules@6.0.0(postcss@8.4.38): resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==} peerDependencies: postcss: ^8.0.0 dependencies: generic-names: 4.0.0 - icss-utils: 5.1.0(postcss@8.4.36) + icss-utils: 5.1.0(postcss@8.4.38) lodash.camelcase: 4.3.0 - postcss: 8.4.36 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.36) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.36) - postcss-modules-scope: 3.1.1(postcss@8.4.36) - postcss-modules-values: 4.0.0(postcss@8.4.36) + postcss: 8.4.38 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.38) + postcss-modules-local-by-default: 4.0.5(postcss@8.4.38) + postcss-modules-scope: 3.2.0(postcss@8.4.38) + postcss-modules-values: 4.0.0(postcss@8.4.38) string-hash: 1.1.3 dev: true - /postcss-selector-parser@6.0.16: - resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} + /postcss-selector-parser@6.1.0: + resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} engines: {node: '>=4'} dependencies: cssesc: 3.0.0 @@ -7339,13 +7722,13 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.4.36: - resolution: {integrity: sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==} + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.1.0 + picocolors: 1.0.1 + source-map-js: 1.2.0 dev: true /prelude-ls@1.1.2: @@ -7371,8 +7754,8 @@ packages: hasBin: true dev: true - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + /prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true dev: true @@ -7400,11 +7783,6 @@ packages: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: true - /promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: @@ -7414,8 +7792,8 @@ packages: optional: true dev: true - /property-information@6.4.1: - resolution: {integrity: sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w==} + /property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} dev: true /proxy-addr@2.0.7: @@ -7431,7 +7809,7 @@ packages: engines: {node: '>= 8'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 + debug: 4.3.5 http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 lru-cache: 5.1.1 @@ -7504,6 +7882,11 @@ packages: unpipe: 1.0.0 dev: true + /react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + dev: true + /readable-stream@1.1.14: resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} dependencies: @@ -7548,7 +7931,7 @@ packages: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.6.2 + tslib: 2.6.3 dev: true /regenerate-unicode-properties@10.1.1: @@ -7573,7 +7956,7 @@ packages: /regenerator-transform@0.15.2: resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.7 dev: true /regexp.prototype.flags@1.5.2: @@ -7586,11 +7969,6 @@ packages: set-function-name: 2.0.2 dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true - /regexpu-core@5.3.2: resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} engines: {node: '>=4'} @@ -7713,6 +8091,7 @@ packages: /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true dependencies: glob: 7.2.3 @@ -7739,36 +8118,42 @@ packages: estree-walker: 0.6.1 dev: true - /rollup@4.13.0: - resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==} + /rollup@4.18.0: + resolution: {integrity: sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.13.0 - '@rollup/rollup-android-arm64': 4.13.0 - '@rollup/rollup-darwin-arm64': 4.13.0 - '@rollup/rollup-darwin-x64': 4.13.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.13.0 - '@rollup/rollup-linux-arm64-gnu': 4.13.0 - '@rollup/rollup-linux-arm64-musl': 4.13.0 - '@rollup/rollup-linux-riscv64-gnu': 4.13.0 - '@rollup/rollup-linux-x64-gnu': 4.13.0 - '@rollup/rollup-linux-x64-musl': 4.13.0 - '@rollup/rollup-win32-arm64-msvc': 4.13.0 - '@rollup/rollup-win32-ia32-msvc': 4.13.0 - '@rollup/rollup-win32-x64-msvc': 4.13.0 + '@rollup/rollup-android-arm-eabi': 4.18.0 + '@rollup/rollup-android-arm64': 4.18.0 + '@rollup/rollup-darwin-arm64': 4.18.0 + '@rollup/rollup-darwin-x64': 4.18.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.0 + '@rollup/rollup-linux-arm-musleabihf': 4.18.0 + '@rollup/rollup-linux-arm64-gnu': 4.18.0 + '@rollup/rollup-linux-arm64-musl': 4.18.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.0 + '@rollup/rollup-linux-riscv64-gnu': 4.18.0 + '@rollup/rollup-linux-s390x-gnu': 4.18.0 + '@rollup/rollup-linux-x64-gnu': 4.18.0 + '@rollup/rollup-linux-x64-musl': 4.18.0 + '@rollup/rollup-win32-arm64-msvc': 4.18.0 + '@rollup/rollup-win32-ia32-msvc': 4.18.0 + '@rollup/rollup-win32-x64-msvc': 4.18.0 fsevents: 2.3.3 dev: true - /rpc-websockets@7.9.0: - resolution: {integrity: sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw==} + /rpc-websockets@9.0.1: + resolution: {integrity: sha512-JCkdc/TfJBGRfmjIFK7cmqX79nwPWUd9xCM0DAydRbdLShsW3j/GV2gmPlaFa8V1+2u4V/O47fm4ZR5+F6HyDw==} dependencies: - '@babel/runtime': 7.24.0 - eventemitter3: 4.0.7 + '@swc/helpers': 0.5.11 + '@types/uuid': 8.3.4 + '@types/ws': 8.5.10 + buffer: 6.0.3 + eventemitter3: 5.0.1 uuid: 8.3.2 - ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 @@ -7788,7 +8173,7 @@ packages: /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.6.2 + tslib: 2.6.3 dev: true /sade@1.8.1: @@ -7839,16 +8224,16 @@ packages: hasBin: true dev: true - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + /semver@7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} hasBin: true dependencies: lru-cache: 6.0.0 dev: true - /semver@7.6.1: - resolution: {integrity: sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==} + /semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true dev: true @@ -7939,12 +8324,13 @@ packages: engines: {node: '>=8'} dev: true - /shiki@0.11.1: - resolution: {integrity: sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==} + /shiki@0.14.7: + resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==} dependencies: + ansi-sequence-parser: 1.1.1 jsonc-parser: 3.2.1 vscode-oniguruma: 1.7.0 - vscode-textmate: 6.0.0 + vscode-textmate: 8.0.0 dev: true /side-channel@1.0.6: @@ -7994,14 +8380,14 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4 - socks: 2.8.1 + debug: 4.3.5 + socks: 2.8.3 transitivePeerDependencies: - supports-color dev: true - /socks@2.8.1: - resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} + /socks@2.8.3: + resolution: {integrity: sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} dependencies: ip-address: 9.0.5 @@ -8024,8 +8410,8 @@ packages: sort-object-keys: 1.1.3 dev: true - /source-map-js@1.1.0: - resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==} + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} dev: true @@ -8107,7 +8493,7 @@ packages: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.23.3 es-object-atoms: 1.0.0 dev: true @@ -8119,12 +8505,13 @@ packages: es-object-atoms: 1.0.0 dev: true - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.22.5 + es-object-atoms: 1.0.0 dev: true /string_decoder@0.10.31: @@ -8143,8 +8530,8 @@ packages: safe-buffer: 5.2.1 dev: true - /stringify-entities@4.0.3: - resolution: {integrity: sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==} + /stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} dependencies: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 @@ -8190,8 +8577,9 @@ packages: inline-style-parser: 0.1.1 dev: true - /superstruct@0.14.2: - resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} + /superstruct@1.0.4: + resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} + engines: {node: '>=14.0.0'} dev: true /supertap@3.0.1: @@ -8243,8 +8631,8 @@ packages: readable-stream: 3.6.2 dev: true - /tar@6.2.0: - resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + /tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} dependencies: chownr: 2.0.0 @@ -8349,13 +8737,13 @@ packages: optional: true dependencies: '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 + '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 14.18.33 - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.12.0 + acorn-walk: 8.3.3 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 @@ -8391,18 +8779,18 @@ packages: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} dev: true - /tsutils@3.21.0(typescript@4.9.4): + /tsutils@3.21.0(typescript@4.9.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.4 + typescript: 4.9.5 dev: true /type-check@0.3.2: @@ -8474,8 +8862,8 @@ packages: is-typed-array: 1.1.13 dev: true - /typed-array-length@1.0.5: - resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.7 @@ -8486,34 +8874,34 @@ packages: possible-typed-array-names: 1.0.0 dev: true - /typedoc-plugin-expand-object-like-types@0.1.1(typedoc@0.23.16): - resolution: {integrity: sha512-h7iw2qugVqEevlqMK4VeAPHMegg63v6zRjvGMoRfsc4ygoCttFYDs05PyLQNwxjEbXZLvGK9TTzig/oHiXUOJg==} + /typedoc-plugin-expand-object-like-types@0.1.2(typedoc@0.23.28): + resolution: {integrity: sha512-RRMOCWMElQHBOVraWMWrh/0tDqCdS5oxYwaWMZBB3KlUUUUCxKllpvJPsRH/uFLO1nOuy28CbJxGVU1umv7LOQ==} peerDependencies: typedoc: 0.22.x || 0.23.x dependencies: - typedoc: 0.23.16(typescript@4.9.4) + typedoc: 0.23.28(typescript@4.9.5) dev: true - /typedoc-plugin-missing-exports@1.0.0(typedoc@0.23.16): + /typedoc-plugin-missing-exports@1.0.0(typedoc@0.23.28): resolution: {integrity: sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA==} peerDependencies: typedoc: 0.22.x || 0.23.x dependencies: - typedoc: 0.23.16(typescript@4.9.4) + typedoc: 0.23.28(typescript@4.9.5) dev: true - /typedoc@0.23.16(typescript@4.9.4): - resolution: {integrity: sha512-rumYsCeNRXlyuZVzefD7050n7ptL2uudsCJg50dY0v/stKniqIlRpvx/F/6expC0/Q6Dbab+g/JpZuB7Sw90FA==} + /typedoc@0.23.28(typescript@4.9.5): + resolution: {integrity: sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==} engines: {node: '>= 14.14'} hasBin: true peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x dependencies: lunr: 2.3.9 marked: 4.3.0 - minimatch: 5.1.6 - shiki: 0.11.1 - typescript: 4.9.4 + minimatch: 7.4.6 + shiki: 0.14.7 + typescript: 4.9.5 dev: true /typescript@4.3.4: @@ -8522,14 +8910,14 @@ packages: hasBin: true dev: true - /typescript@4.9.4: - resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /ufo@1.5.2: - resolution: {integrity: sha512-eiutMaL0J2MKdhcOM1tUy13pIrYnyR87fEd8STJQFrrAwImwvlXkxlZEjaKah8r2viPohld08lt73QfLG1NxMg==} + /ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} dev: true /unbox-primitive@1.0.2: @@ -8668,15 +9056,15 @@ packages: engines: {node: '>= 0.8'} dev: true - /update-browserslist-db@1.0.13(browserslist@4.23.0): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + /update-browserslist-db@1.0.16(browserslist@4.23.1): + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.23.0 + browserslist: 4.23.1 escalade: 3.1.2 - picocolors: 1.0.0 + picocolors: 1.0.1 dev: true /uri-js@4.4.1: @@ -8690,7 +9078,7 @@ packages: engines: {node: '>=6.14.2'} requiresBuild: true dependencies: - node-gyp-build: 4.8.0 + node-gyp-build: 4.8.1 dev: true /util-deprecate@1.0.2: @@ -8722,36 +9110,33 @@ packages: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - dev: true - /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} dev: true - /vercel@28.16.0(@types/node@14.18.33): - resolution: {integrity: sha512-+YaWIhdShkEz6o36CPmMP0+vYUd+cBJi4rhYCYC6nm86uOCEK1eJDoW1bkCFxTIFDSTSuzbbSmI69jsYIkN3bg==} + /vercel@28.20.0(@types/node@14.18.33): + resolution: {integrity: sha512-U+ZDKVVgxJyUJ26l/B7o53EeocP4PnbCt7D6Qyt/bI/eJ9BXpBtsWtMJf1CvgH3Iv/QRXFYlCvjHQJLs1BC7qw==} engines: {node: '>= 14'} hasBin: true requiresBuild: true dependencies: - '@vercel/build-utils': 6.3.0 - '@vercel/go': 2.3.7 - '@vercel/hydrogen': 0.0.53 - '@vercel/next': 3.4.7 - '@vercel/node': 2.9.6 - '@vercel/python': 3.1.49 - '@vercel/redwood': 1.1.5 - '@vercel/remix': 1.3.3(@types/node@14.18.33) - '@vercel/ruby': 1.3.65 - '@vercel/static-build': 1.3.9 + '@vercel/build-utils': 6.7.1 + '@vercel/go': 2.5.0 + '@vercel/hydrogen': 0.0.63 + '@vercel/next': 3.7.5 + '@vercel/node': 2.12.0 + '@vercel/python': 3.1.59 + '@vercel/redwood': 1.1.14 + '@vercel/remix-builder': 1.8.5(@types/node@14.18.33) + '@vercel/ruby': 1.3.75 + '@vercel/static-build': 1.3.25 transitivePeerDependencies: - '@remix-run/serve' - '@swc/core' - '@swc/wasm' - '@types/node' + - babel-plugin-macros - bluebird - bufferutil - encoding @@ -8762,6 +9147,7 @@ packages: - sugarss - supports-color - terser + - ts-node - utf-8-validate dev: true @@ -8781,16 +9167,16 @@ packages: vfile-message: 3.1.4 dev: true - /vite-node@1.4.0(@types/node@14.18.33): - resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} + /vite-node@1.6.0(@types/node@14.18.33): + resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.4 + debug: 4.3.5 pathe: 1.1.2 - picocolors: 1.0.0 - vite: 5.1.6(@types/node@14.18.33) + picocolors: 1.0.1 + vite: 5.3.1(@types/node@14.18.33) transitivePeerDependencies: - '@types/node' - less @@ -8802,8 +9188,8 @@ packages: - terser dev: true - /vite@5.1.6(@types/node@14.18.33): - resolution: {integrity: sha512-yYIAZs9nVfRJ/AiOLCA91zzhjsHUgMjB+EigzFb6W2XTLO8JixBCKCjvhKZaye+NKYHCrkv3Oh50dH9EdLU2RA==} + /vite@5.3.1(@types/node@14.18.33): + resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -8831,9 +9217,9 @@ packages: optional: true dependencies: '@types/node': 14.18.33 - esbuild: 0.19.12 - postcss: 8.4.36 - rollup: 4.13.0 + esbuild: 0.21.5 + postcss: 8.4.38 + rollup: 4.18.0 optionalDependencies: fsevents: 2.3.3 dev: true @@ -8844,16 +9230,16 @@ packages: deprecated: The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm. hasBin: true dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.12.0 + acorn-walk: 8.3.3 dev: true /vscode-oniguruma@1.7.0: resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} dev: true - /vscode-textmate@6.0.0: - resolution: {integrity: sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==} + /vscode-textmate@8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} dev: true /wcwidth@1.0.1: @@ -8965,8 +9351,8 @@ packages: optional: true dev: true - /ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + /ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9006,7 +9392,7 @@ packages: unist-util-visit: 4.1.2 vfile: 5.3.7 optionalDependencies: - deasync: 0.1.29 + deasync: 0.1.30 transitivePeerDependencies: - supports-color dev: true @@ -9033,6 +9419,12 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true + /yaml@2.4.5: + resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} diff --git a/clients/js/src/generated/errors/mplCore.ts b/clients/js/src/generated/errors/mplCore.ts index f830af2e..0c7414a4 100644 --- a/clients/js/src/generated/errors/mplCore.ts +++ b/clients/js/src/generated/errors/mplCore.ts @@ -433,14 +433,14 @@ export class InvalidLogWrapperProgramError extends ProgramError { codeToErrorMap.set(0x1e, InvalidLogWrapperProgramError); nameToErrorMap.set('InvalidLogWrapperProgram', InvalidLogWrapperProgramError); -/** ExternalPluginAdapterNotFound: External PluginExternalPluginAdapter not found */ +/** ExternalPluginAdapterNotFound: External Plugin Adapter not found */ export class ExternalPluginAdapterNotFoundError extends ProgramError { override readonly name: string = 'ExternalPluginAdapterNotFound'; readonly code: number = 0x1f; // 31 constructor(program: Program, cause?: Error) { - super('External PluginExternalPluginAdapter not found', program, cause); + super('External Plugin Adapter not found', program, cause); } } codeToErrorMap.set(0x1f, ExternalPluginAdapterNotFoundError); @@ -449,18 +449,14 @@ nameToErrorMap.set( ExternalPluginAdapterNotFoundError ); -/** ExternalPluginAdapterAlreadyExists: External PluginExternalPluginAdapter already exists */ +/** ExternalPluginAdapterAlreadyExists: External Plugin Adapter already exists */ export class ExternalPluginAdapterAlreadyExistsError extends ProgramError { override readonly name: string = 'ExternalPluginAdapterAlreadyExists'; readonly code: number = 0x20; // 32 constructor(program: Program, cause?: Error) { - super( - 'External PluginExternalPluginAdapter already exists', - program, - cause - ); + super('External Plugin Adapter already exists', program, cause); } } codeToErrorMap.set(0x20, ExternalPluginAdapterAlreadyExistsError); @@ -621,6 +617,78 @@ export class CollectionMustBeEmptyError extends ProgramError { codeToErrorMap.set(0x2a, CollectionMustBeEmptyError); nameToErrorMap.set('CollectionMustBeEmpty', CollectionMustBeEmptyError); +/** TwoDataSources: Two data sources provided, only one is allowed */ +export class TwoDataSourcesError extends ProgramError { + override readonly name: string = 'TwoDataSources'; + + readonly code: number = 0x2b; // 43 + + constructor(program: Program, cause?: Error) { + super('Two data sources provided, only one is allowed', program, cause); + } +} +codeToErrorMap.set(0x2b, TwoDataSourcesError); +nameToErrorMap.set('TwoDataSources', TwoDataSourcesError); + +/** UnsupportedOperation: External Plugin does not support this operation */ +export class UnsupportedOperationError extends ProgramError { + override readonly name: string = 'UnsupportedOperation'; + + readonly code: number = 0x2c; // 44 + + constructor(program: Program, cause?: Error) { + super('External Plugin does not support this operation', program, cause); + } +} +codeToErrorMap.set(0x2c, UnsupportedOperationError); +nameToErrorMap.set('UnsupportedOperation', UnsupportedOperationError); + +/** NoDataSources: No data sources provided, one is required */ +export class NoDataSourcesError extends ProgramError { + override readonly name: string = 'NoDataSources'; + + readonly code: number = 0x2d; // 45 + + constructor(program: Program, cause?: Error) { + super('No data sources provided, one is required', program, cause); + } +} +codeToErrorMap.set(0x2d, NoDataSourcesError); +nameToErrorMap.set('NoDataSources', NoDataSourcesError); + +/** InvalidPluginAdapterTarget: This plugin adapter cannot be added to an Asset */ +export class InvalidPluginAdapterTargetError extends ProgramError { + override readonly name: string = 'InvalidPluginAdapterTarget'; + + readonly code: number = 0x2e; // 46 + + constructor(program: Program, cause?: Error) { + super('This plugin adapter cannot be added to an Asset', program, cause); + } +} +codeToErrorMap.set(0x2e, InvalidPluginAdapterTargetError); +nameToErrorMap.set( + 'InvalidPluginAdapterTarget', + InvalidPluginAdapterTargetError +); + +/** CannotAddDataSection: Cannot add a Data Section without a linked external plugin */ +export class CannotAddDataSectionError extends ProgramError { + override readonly name: string = 'CannotAddDataSection'; + + readonly code: number = 0x2f; // 47 + + constructor(program: Program, cause?: Error) { + super( + 'Cannot add a Data Section without a linked external plugin', + program, + cause + ); + } +} +codeToErrorMap.set(0x2f, CannotAddDataSectionError); +nameToErrorMap.set('CannotAddDataSection', CannotAddDataSectionError); + /** * Attempts to resolve a custom program error from the provided error code. * @category Errors diff --git a/clients/js/src/generated/instructions/index.ts b/clients/js/src/generated/instructions/index.ts index 6b62997e..f52941cd 100644 --- a/clients/js/src/generated/instructions/index.ts +++ b/clients/js/src/generated/instructions/index.ts @@ -34,5 +34,6 @@ export * from './updateCollectionV1'; export * from './updateExternalPluginAdapterV1'; export * from './updatePluginV1'; export * from './updateV1'; +export * from './updateV2'; export * from './writeCollectionExternalPluginAdapterDataV1'; export * from './writeExternalPluginAdapterDataV1'; diff --git a/clients/js/src/generated/instructions/updateV2.ts b/clients/js/src/generated/instructions/updateV2.ts new file mode 100644 index 00000000..cf28a63c --- /dev/null +++ b/clients/js/src/generated/instructions/updateV2.ts @@ -0,0 +1,190 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Option, + OptionOrNullable, + Pda, + PublicKey, + Signer, + TransactionBuilder, + none, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + option, + string, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; +import { + BaseUpdateAuthority, + BaseUpdateAuthorityArgs, + getBaseUpdateAuthoritySerializer, +} from '../types'; + +// Accounts. +export type UpdateV2InstructionAccounts = { + /** The address of the asset */ + asset: PublicKey | Pda; + /** The collection to which the asset belongs */ + collection?: PublicKey | Pda; + /** The account paying for the storage fees */ + payer?: Signer; + /** The update authority or update authority delegate of the asset */ + authority?: Signer; + /** A new collection to which to move the asset */ + newCollection?: PublicKey | Pda; + /** The system program */ + systemProgram?: PublicKey | Pda; + /** The SPL Noop Program */ + logWrapper?: PublicKey | Pda; +}; + +// Data. +export type UpdateV2InstructionData = { + discriminator: number; + newName: Option; + newUri: Option; + newUpdateAuthority: Option; +}; + +export type UpdateV2InstructionDataArgs = { + newName?: OptionOrNullable; + newUri?: OptionOrNullable; + newUpdateAuthority?: OptionOrNullable; +}; + +export function getUpdateV2InstructionDataSerializer(): Serializer< + UpdateV2InstructionDataArgs, + UpdateV2InstructionData +> { + return mapSerializer< + UpdateV2InstructionDataArgs, + any, + UpdateV2InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['newName', option(string())], + ['newUri', option(string())], + ['newUpdateAuthority', option(getBaseUpdateAuthoritySerializer())], + ], + { description: 'UpdateV2InstructionData' } + ), + (value) => ({ + ...value, + discriminator: 30, + newName: value.newName ?? none(), + newUri: value.newUri ?? none(), + newUpdateAuthority: value.newUpdateAuthority ?? none(), + }) + ) as Serializer; +} + +// Args. +export type UpdateV2InstructionArgs = UpdateV2InstructionDataArgs; + +// Instruction. +export function updateV2( + context: Pick, + input: UpdateV2InstructionAccounts & UpdateV2InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + asset: { + index: 0, + isWritable: true as boolean, + value: input.asset ?? null, + }, + collection: { + index: 1, + isWritable: true as boolean, + value: input.collection ?? null, + }, + payer: { + index: 2, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 3, + isWritable: false as boolean, + value: input.authority ?? null, + }, + newCollection: { + index: 4, + isWritable: true as boolean, + value: input.newCollection ?? null, + }, + systemProgram: { + index: 5, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + logWrapper: { + index: 6, + isWritable: false as boolean, + value: input.logWrapper ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: UpdateV2InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getUpdateV2InstructionDataSerializer().serialize( + resolvedArgs as UpdateV2InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/writeCollectionExternalPluginAdapterDataV1.ts b/clients/js/src/generated/instructions/writeCollectionExternalPluginAdapterDataV1.ts index 1397b69a..589d28a1 100644 --- a/clients/js/src/generated/instructions/writeCollectionExternalPluginAdapterDataV1.ts +++ b/clients/js/src/generated/instructions/writeCollectionExternalPluginAdapterDataV1.ts @@ -8,6 +8,8 @@ import { Context, + Option, + OptionOrNullable, Pda, PublicKey, Signer, @@ -18,6 +20,7 @@ import { Serializer, bytes, mapSerializer, + option, struct, u32, u8, @@ -39,8 +42,10 @@ export type WriteCollectionExternalPluginAdapterDataV1InstructionAccounts = { collection: PublicKey | Pda; /** The account paying for the storage fees */ payer?: Signer; - /** The Data Authority of the External PluginExternalPluginAdapter */ + /** The Data Authority of the External Plugin Adapter */ authority?: Signer; + /** The buffer to write to the external plugin */ + buffer?: PublicKey | Pda; /** The system program */ systemProgram?: PublicKey | Pda; /** The SPL Noop Program */ @@ -51,12 +56,12 @@ export type WriteCollectionExternalPluginAdapterDataV1InstructionAccounts = { export type WriteCollectionExternalPluginAdapterDataV1InstructionData = { discriminator: number; key: BaseExternalPluginAdapterKey; - data: Uint8Array; + data: Option; }; export type WriteCollectionExternalPluginAdapterDataV1InstructionDataArgs = { key: BaseExternalPluginAdapterKeyArgs; - data: Uint8Array; + data: OptionOrNullable; }; export function getWriteCollectionExternalPluginAdapterDataV1InstructionDataSerializer(): Serializer< @@ -72,7 +77,7 @@ export function getWriteCollectionExternalPluginAdapterDataV1InstructionDataSeri [ ['discriminator', u8()], ['key', getBaseExternalPluginAdapterKeySerializer()], - ['data', bytes({ size: u32() })], + ['data', option(bytes({ size: u32() }))], ], { description: @@ -119,13 +124,18 @@ export function writeCollectionExternalPluginAdapterDataV1( isWritable: false as boolean, value: input.authority ?? null, }, - systemProgram: { + buffer: { index: 3, isWritable: false as boolean, + value: input.buffer ?? null, + }, + systemProgram: { + index: 4, + isWritable: false as boolean, value: input.systemProgram ?? null, }, logWrapper: { - index: 4, + index: 5, isWritable: false as boolean, value: input.logWrapper ?? null, }, diff --git a/clients/js/src/generated/instructions/writeExternalPluginAdapterDataV1.ts b/clients/js/src/generated/instructions/writeExternalPluginAdapterDataV1.ts index 78e639ba..226ba20f 100644 --- a/clients/js/src/generated/instructions/writeExternalPluginAdapterDataV1.ts +++ b/clients/js/src/generated/instructions/writeExternalPluginAdapterDataV1.ts @@ -8,6 +8,8 @@ import { Context, + Option, + OptionOrNullable, Pda, PublicKey, Signer, @@ -18,6 +20,7 @@ import { Serializer, bytes, mapSerializer, + option, struct, u32, u8, @@ -41,8 +44,10 @@ export type WriteExternalPluginAdapterDataV1InstructionAccounts = { collection?: PublicKey | Pda; /** The account paying for the storage fees */ payer?: Signer; - /** The Data Authority of the External PluginExternalPluginAdapter */ + /** The Data Authority of the External Plugin Adapter */ authority?: Signer; + /** The buffer to write to the external plugin */ + buffer?: PublicKey | Pda; /** The system program */ systemProgram?: PublicKey | Pda; /** The SPL Noop Program */ @@ -53,12 +58,12 @@ export type WriteExternalPluginAdapterDataV1InstructionAccounts = { export type WriteExternalPluginAdapterDataV1InstructionData = { discriminator: number; key: BaseExternalPluginAdapterKey; - data: Uint8Array; + data: Option; }; export type WriteExternalPluginAdapterDataV1InstructionDataArgs = { key: BaseExternalPluginAdapterKeyArgs; - data: Uint8Array; + data: OptionOrNullable; }; export function getWriteExternalPluginAdapterDataV1InstructionDataSerializer(): Serializer< @@ -74,7 +79,7 @@ export function getWriteExternalPluginAdapterDataV1InstructionDataSerializer(): [ ['discriminator', u8()], ['key', getBaseExternalPluginAdapterKeySerializer()], - ['data', bytes({ size: u32() })], + ['data', option(bytes({ size: u32() }))], ], { description: 'WriteExternalPluginAdapterDataV1InstructionData' } ), @@ -123,13 +128,18 @@ export function writeExternalPluginAdapterDataV1( isWritable: false as boolean, value: input.authority ?? null, }, - systemProgram: { + buffer: { index: 4, isWritable: false as boolean, + value: input.buffer ?? null, + }, + systemProgram: { + index: 5, + isWritable: false as boolean, value: input.systemProgram ?? null, }, logWrapper: { - index: 5, + index: 6, isWritable: false as boolean, value: input.logWrapper ?? null, }, diff --git a/clients/js/src/generated/types/baseDataStore.ts b/clients/js/src/generated/types/baseAppData.ts similarity index 74% rename from clients/js/src/generated/types/baseDataStore.ts rename to clients/js/src/generated/types/baseAppData.ts index e83eff4d..5d80d6b0 100644 --- a/clients/js/src/generated/types/baseDataStore.ts +++ b/clients/js/src/generated/types/baseAppData.ts @@ -16,25 +16,25 @@ import { getExternalPluginAdapterSchemaSerializer, } from '.'; -export type BaseDataStore = { +export type BaseAppData = { dataAuthority: BasePluginAuthority; schema: ExternalPluginAdapterSchema; }; -export type BaseDataStoreArgs = { +export type BaseAppDataArgs = { dataAuthority: BasePluginAuthorityArgs; schema: ExternalPluginAdapterSchemaArgs; }; -export function getBaseDataStoreSerializer(): Serializer< - BaseDataStoreArgs, - BaseDataStore +export function getBaseAppDataSerializer(): Serializer< + BaseAppDataArgs, + BaseAppData > { - return struct( + return struct( [ ['dataAuthority', getBasePluginAuthoritySerializer()], ['schema', getExternalPluginAdapterSchemaSerializer()], ], - { description: 'BaseDataStore' } - ) as Serializer; + { description: 'BaseAppData' } + ) as Serializer; } diff --git a/clients/js/src/generated/types/baseDataStoreInitInfo.ts b/clients/js/src/generated/types/baseAppDataInitInfo.ts similarity index 76% rename from clients/js/src/generated/types/baseDataStoreInitInfo.ts rename to clients/js/src/generated/types/baseAppDataInitInfo.ts index b23c72f6..30374e1f 100644 --- a/clients/js/src/generated/types/baseDataStoreInitInfo.ts +++ b/clients/js/src/generated/types/baseAppDataInitInfo.ts @@ -21,28 +21,28 @@ import { getExternalPluginAdapterSchemaSerializer, } from '.'; -export type BaseDataStoreInitInfo = { +export type BaseAppDataInitInfo = { dataAuthority: BasePluginAuthority; initPluginAuthority: Option; schema: Option; }; -export type BaseDataStoreInitInfoArgs = { +export type BaseAppDataInitInfoArgs = { dataAuthority: BasePluginAuthorityArgs; initPluginAuthority: OptionOrNullable; schema: OptionOrNullable; }; -export function getBaseDataStoreInitInfoSerializer(): Serializer< - BaseDataStoreInitInfoArgs, - BaseDataStoreInitInfo +export function getBaseAppDataInitInfoSerializer(): Serializer< + BaseAppDataInitInfoArgs, + BaseAppDataInitInfo > { - return struct( + return struct( [ ['dataAuthority', getBasePluginAuthoritySerializer()], ['initPluginAuthority', option(getBasePluginAuthoritySerializer())], ['schema', option(getExternalPluginAdapterSchemaSerializer())], ], - { description: 'BaseDataStoreInitInfo' } - ) as Serializer; + { description: 'BaseAppDataInitInfo' } + ) as Serializer; } diff --git a/clients/js/src/generated/types/baseDataStoreUpdateInfo.ts b/clients/js/src/generated/types/baseAppDataUpdateInfo.ts similarity index 65% rename from clients/js/src/generated/types/baseDataStoreUpdateInfo.ts rename to clients/js/src/generated/types/baseAppDataUpdateInfo.ts index 53b65c4c..9d42e1f7 100644 --- a/clients/js/src/generated/types/baseDataStoreUpdateInfo.ts +++ b/clients/js/src/generated/types/baseAppDataUpdateInfo.ts @@ -18,20 +18,20 @@ import { getExternalPluginAdapterSchemaSerializer, } from '.'; -export type BaseDataStoreUpdateInfo = { +export type BaseAppDataUpdateInfo = { schema: Option; }; -export type BaseDataStoreUpdateInfoArgs = { +export type BaseAppDataUpdateInfoArgs = { schema: OptionOrNullable; }; -export function getBaseDataStoreUpdateInfoSerializer(): Serializer< - BaseDataStoreUpdateInfoArgs, - BaseDataStoreUpdateInfo +export function getBaseAppDataUpdateInfoSerializer(): Serializer< + BaseAppDataUpdateInfoArgs, + BaseAppDataUpdateInfo > { - return struct( + return struct( [['schema', option(getExternalPluginAdapterSchemaSerializer())]], - { description: 'BaseDataStoreUpdateInfo' } - ) as Serializer; + { description: 'BaseAppDataUpdateInfo' } + ) as Serializer; } diff --git a/clients/js/src/generated/types/baseDataSection.ts b/clients/js/src/generated/types/baseDataSection.ts new file mode 100644 index 00000000..59cdfbbd --- /dev/null +++ b/clients/js/src/generated/types/baseDataSection.ts @@ -0,0 +1,40 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, struct } from '@metaplex-foundation/umi/serializers'; +import { + BaseLinkedDataKey, + BaseLinkedDataKeyArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getBaseLinkedDataKeySerializer, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseDataSection = { + parentKey: BaseLinkedDataKey; + schema: ExternalPluginAdapterSchema; +}; + +export type BaseDataSectionArgs = { + parentKey: BaseLinkedDataKeyArgs; + schema: ExternalPluginAdapterSchemaArgs; +}; + +export function getBaseDataSectionSerializer(): Serializer< + BaseDataSectionArgs, + BaseDataSection +> { + return struct( + [ + ['parentKey', getBaseLinkedDataKeySerializer()], + ['schema', getExternalPluginAdapterSchemaSerializer()], + ], + { description: 'BaseDataSection' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseDataSectionInitInfo.ts b/clients/js/src/generated/types/baseDataSectionInitInfo.ts new file mode 100644 index 00000000..ed1d30d3 --- /dev/null +++ b/clients/js/src/generated/types/baseDataSectionInitInfo.ts @@ -0,0 +1,40 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, struct } from '@metaplex-foundation/umi/serializers'; +import { + BaseLinkedDataKey, + BaseLinkedDataKeyArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getBaseLinkedDataKeySerializer, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseDataSectionInitInfo = { + parentKey: BaseLinkedDataKey; + schema: ExternalPluginAdapterSchema; +}; + +export type BaseDataSectionInitInfoArgs = { + parentKey: BaseLinkedDataKeyArgs; + schema: ExternalPluginAdapterSchemaArgs; +}; + +export function getBaseDataSectionInitInfoSerializer(): Serializer< + BaseDataSectionInitInfoArgs, + BaseDataSectionInitInfo +> { + return struct( + [ + ['parentKey', getBaseLinkedDataKeySerializer()], + ['schema', getExternalPluginAdapterSchemaSerializer()], + ], + { description: 'BaseDataSectionInitInfo' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseDataSectionUpdateInfo.ts b/clients/js/src/generated/types/baseDataSectionUpdateInfo.ts new file mode 100644 index 00000000..b1abd23e --- /dev/null +++ b/clients/js/src/generated/types/baseDataSectionUpdateInfo.ts @@ -0,0 +1,22 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, struct } from '@metaplex-foundation/umi/serializers'; + +export type BaseDataSectionUpdateInfo = {}; + +export type BaseDataSectionUpdateInfoArgs = BaseDataSectionUpdateInfo; + +export function getBaseDataSectionUpdateInfoSerializer(): Serializer< + BaseDataSectionUpdateInfoArgs, + BaseDataSectionUpdateInfo +> { + return struct([], { + description: 'BaseDataSectionUpdateInfo', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts b/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts index 2649b73a..c65b82af 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts @@ -15,26 +15,44 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { - BaseDataStoreInitInfo, - BaseDataStoreInitInfoArgs, + BaseAppDataInitInfo, + BaseAppDataInitInfoArgs, + BaseDataSectionInitInfo, + BaseDataSectionInitInfoArgs, BaseLifecycleHookInitInfo, BaseLifecycleHookInitInfoArgs, + BaseLinkedAppDataInitInfo, + BaseLinkedAppDataInitInfoArgs, + BaseLinkedLifecycleHookInitInfo, + BaseLinkedLifecycleHookInitInfoArgs, BaseOracleInitInfo, BaseOracleInitInfoArgs, - getBaseDataStoreInitInfoSerializer, + getBaseAppDataInitInfoSerializer, + getBaseDataSectionInitInfoSerializer, getBaseLifecycleHookInitInfoSerializer, + getBaseLinkedAppDataInitInfoSerializer, + getBaseLinkedLifecycleHookInitInfoSerializer, getBaseOracleInitInfoSerializer, } from '.'; export type BaseExternalPluginAdapterInitInfo = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookInitInfo] } | { __kind: 'Oracle'; fields: [BaseOracleInitInfo] } - | { __kind: 'DataStore'; fields: [BaseDataStoreInitInfo] }; + | { __kind: 'AppData'; fields: [BaseAppDataInitInfo] } + | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookInitInfo] } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataInitInfo] } + | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfo] }; export type BaseExternalPluginAdapterInitInfoArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookInitInfoArgs] } | { __kind: 'Oracle'; fields: [BaseOracleInitInfoArgs] } - | { __kind: 'DataStore'; fields: [BaseDataStoreInitInfoArgs] }; + | { __kind: 'AppData'; fields: [BaseAppDataInitInfoArgs] } + | { + __kind: 'LinkedLifecycleHook'; + fields: [BaseLinkedLifecycleHookInitInfoArgs]; + } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataInitInfoArgs] } + | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfoArgs] }; export function getBaseExternalPluginAdapterInitInfoSerializer(): Serializer< BaseExternalPluginAdapterInitInfoArgs, @@ -58,10 +76,39 @@ export function getBaseExternalPluginAdapterInitInfoSerializer(): Serializer< >([['fields', tuple([getBaseOracleInitInfoSerializer()])]]), ], [ - 'DataStore', + 'AppData', struct< - GetDataEnumKindContent - >([['fields', tuple([getBaseDataStoreInitInfoSerializer()])]]), + GetDataEnumKindContent + >([['fields', tuple([getBaseAppDataInitInfoSerializer()])]]), + ], + [ + 'LinkedLifecycleHook', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfo, + 'LinkedLifecycleHook' + > + >([ + ['fields', tuple([getBaseLinkedLifecycleHookInitInfoSerializer()])], + ]), + ], + [ + 'LinkedAppData', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfo, + 'LinkedAppData' + > + >([['fields', tuple([getBaseLinkedAppDataInitInfoSerializer()])]]), + ], + [ + 'DataSection', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfo, + 'DataSection' + > + >([['fields', tuple([getBaseDataSectionInitInfoSerializer()])]]), ], ], { description: 'BaseExternalPluginAdapterInitInfo' } @@ -87,12 +134,36 @@ export function baseExternalPluginAdapterInitInfo( >['fields'] ): GetDataEnumKind; export function baseExternalPluginAdapterInitInfo( - kind: 'DataStore', + kind: 'AppData', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfoArgs, + 'AppData' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterInitInfo( + kind: 'LinkedLifecycleHook', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfoArgs, + 'LinkedLifecycleHook' + >['fields'] +): GetDataEnumKind< + BaseExternalPluginAdapterInitInfoArgs, + 'LinkedLifecycleHook' +>; +export function baseExternalPluginAdapterInitInfo( + kind: 'LinkedAppData', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfoArgs, + 'LinkedAppData' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterInitInfo( + kind: 'DataSection', data: GetDataEnumKindContent< BaseExternalPluginAdapterInitInfoArgs, - 'DataStore' + 'DataSection' >['fields'] -): GetDataEnumKind; +): GetDataEnumKind; export function baseExternalPluginAdapterInitInfo< K extends BaseExternalPluginAdapterInitInfoArgs['__kind'], >( diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts b/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts index 1a57e653..9aedf063 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts @@ -17,20 +17,29 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { + BaseLinkedDataKey, + BaseLinkedDataKeyArgs, BasePluginAuthority, BasePluginAuthorityArgs, + getBaseLinkedDataKeySerializer, getBasePluginAuthoritySerializer, } from '.'; export type BaseExternalPluginAdapterKey = | { __kind: 'LifecycleHook'; fields: [PublicKey] } | { __kind: 'Oracle'; fields: [PublicKey] } - | { __kind: 'DataStore'; fields: [BasePluginAuthority] }; + | { __kind: 'AppData'; fields: [BasePluginAuthority] } + | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } + | { __kind: 'LinkedAppData'; fields: [BasePluginAuthority] } + | { __kind: 'DataSection'; fields: [BaseLinkedDataKey] }; export type BaseExternalPluginAdapterKeyArgs = | { __kind: 'LifecycleHook'; fields: [PublicKey] } | { __kind: 'Oracle'; fields: [PublicKey] } - | { __kind: 'DataStore'; fields: [BasePluginAuthorityArgs] }; + | { __kind: 'AppData'; fields: [BasePluginAuthorityArgs] } + | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } + | { __kind: 'LinkedAppData'; fields: [BasePluginAuthorityArgs] } + | { __kind: 'DataSection'; fields: [BaseLinkedDataKeyArgs] }; export function getBaseExternalPluginAdapterKeySerializer(): Serializer< BaseExternalPluginAdapterKeyArgs, @@ -51,11 +60,32 @@ export function getBaseExternalPluginAdapterKeySerializer(): Serializer< ]), ], [ - 'DataStore', + 'AppData', + struct>( + [['fields', tuple([getBasePluginAuthoritySerializer()])]] + ), + ], + [ + 'LinkedLifecycleHook', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterKey, + 'LinkedLifecycleHook' + > + >([['fields', tuple([publicKeySerializer()])]]), + ], + [ + 'LinkedAppData', struct< - GetDataEnumKindContent + GetDataEnumKindContent >([['fields', tuple([getBasePluginAuthoritySerializer()])]]), ], + [ + 'DataSection', + struct< + GetDataEnumKindContent + >([['fields', tuple([getBaseLinkedDataKeySerializer()])]]), + ], ], { description: 'BaseExternalPluginAdapterKey' } ) as Serializer< @@ -80,12 +110,33 @@ export function baseExternalPluginAdapterKey( >['fields'] ): GetDataEnumKind; export function baseExternalPluginAdapterKey( - kind: 'DataStore', + kind: 'AppData', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterKeyArgs, + 'AppData' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterKey( + kind: 'LinkedLifecycleHook', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterKeyArgs, + 'LinkedLifecycleHook' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterKey( + kind: 'LinkedAppData', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterKeyArgs, + 'LinkedAppData' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterKey( + kind: 'DataSection', data: GetDataEnumKindContent< BaseExternalPluginAdapterKeyArgs, - 'DataStore' + 'DataSection' >['fields'] -): GetDataEnumKind; +): GetDataEnumKind; export function baseExternalPluginAdapterKey< K extends BaseExternalPluginAdapterKeyArgs['__kind'], >( diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts b/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts index 4fc19360..99ee7553 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts @@ -15,26 +15,42 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { - BaseDataStoreUpdateInfo, - BaseDataStoreUpdateInfoArgs, + BaseAppDataUpdateInfo, + BaseAppDataUpdateInfoArgs, BaseLifecycleHookUpdateInfo, BaseLifecycleHookUpdateInfoArgs, + BaseLinkedAppDataUpdateInfo, + BaseLinkedAppDataUpdateInfoArgs, + BaseLinkedLifecycleHookUpdateInfo, + BaseLinkedLifecycleHookUpdateInfoArgs, BaseOracleUpdateInfo, BaseOracleUpdateInfoArgs, - getBaseDataStoreUpdateInfoSerializer, + getBaseAppDataUpdateInfoSerializer, getBaseLifecycleHookUpdateInfoSerializer, + getBaseLinkedAppDataUpdateInfoSerializer, + getBaseLinkedLifecycleHookUpdateInfoSerializer, getBaseOracleUpdateInfoSerializer, } from '.'; export type BaseExternalPluginAdapterUpdateInfo = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookUpdateInfo] } | { __kind: 'Oracle'; fields: [BaseOracleUpdateInfo] } - | { __kind: 'DataStore'; fields: [BaseDataStoreUpdateInfo] }; + | { __kind: 'AppData'; fields: [BaseAppDataUpdateInfo] } + | { + __kind: 'LinkedLifecycleHook'; + fields: [BaseLinkedLifecycleHookUpdateInfo]; + } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfo] }; export type BaseExternalPluginAdapterUpdateInfoArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookUpdateInfoArgs] } | { __kind: 'Oracle'; fields: [BaseOracleUpdateInfoArgs] } - | { __kind: 'DataStore'; fields: [BaseDataStoreUpdateInfoArgs] }; + | { __kind: 'AppData'; fields: [BaseAppDataUpdateInfoArgs] } + | { + __kind: 'LinkedLifecycleHook'; + fields: [BaseLinkedLifecycleHookUpdateInfoArgs]; + } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfoArgs] }; export function getBaseExternalPluginAdapterUpdateInfoSerializer(): Serializer< BaseExternalPluginAdapterUpdateInfoArgs, @@ -58,13 +74,30 @@ export function getBaseExternalPluginAdapterUpdateInfoSerializer(): Serializer< >([['fields', tuple([getBaseOracleUpdateInfoSerializer()])]]), ], [ - 'DataStore', + 'AppData', + struct< + GetDataEnumKindContent + >([['fields', tuple([getBaseAppDataUpdateInfoSerializer()])]]), + ], + [ + 'LinkedLifecycleHook', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterUpdateInfo, + 'LinkedLifecycleHook' + > + >([ + ['fields', tuple([getBaseLinkedLifecycleHookUpdateInfoSerializer()])], + ]), + ], + [ + 'LinkedAppData', struct< GetDataEnumKindContent< BaseExternalPluginAdapterUpdateInfo, - 'DataStore' + 'LinkedAppData' > - >([['fields', tuple([getBaseDataStoreUpdateInfoSerializer()])]]), + >([['fields', tuple([getBaseLinkedAppDataUpdateInfoSerializer()])]]), ], ], { description: 'BaseExternalPluginAdapterUpdateInfo' } @@ -90,12 +123,29 @@ export function baseExternalPluginAdapterUpdateInfo( >['fields'] ): GetDataEnumKind; export function baseExternalPluginAdapterUpdateInfo( - kind: 'DataStore', + kind: 'AppData', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterUpdateInfoArgs, + 'AppData' + >['fields'] +): GetDataEnumKind; +export function baseExternalPluginAdapterUpdateInfo( + kind: 'LinkedLifecycleHook', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterUpdateInfoArgs, + 'LinkedLifecycleHook' + >['fields'] +): GetDataEnumKind< + BaseExternalPluginAdapterUpdateInfoArgs, + 'LinkedLifecycleHook' +>; +export function baseExternalPluginAdapterUpdateInfo( + kind: 'LinkedAppData', data: GetDataEnumKindContent< BaseExternalPluginAdapterUpdateInfoArgs, - 'DataStore' + 'LinkedAppData' >['fields'] -): GetDataEnumKind; +): GetDataEnumKind; export function baseExternalPluginAdapterUpdateInfo< K extends BaseExternalPluginAdapterUpdateInfoArgs['__kind'], >( diff --git a/clients/js/src/generated/types/baseLinkedAppData.ts b/clients/js/src/generated/types/baseLinkedAppData.ts new file mode 100644 index 00000000..22c78b25 --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedAppData.ts @@ -0,0 +1,40 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, struct } from '@metaplex-foundation/umi/serializers'; +import { + BasePluginAuthority, + BasePluginAuthorityArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getBasePluginAuthoritySerializer, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseLinkedAppData = { + dataAuthority: BasePluginAuthority; + schema: ExternalPluginAdapterSchema; +}; + +export type BaseLinkedAppDataArgs = { + dataAuthority: BasePluginAuthorityArgs; + schema: ExternalPluginAdapterSchemaArgs; +}; + +export function getBaseLinkedAppDataSerializer(): Serializer< + BaseLinkedAppDataArgs, + BaseLinkedAppData +> { + return struct( + [ + ['dataAuthority', getBasePluginAuthoritySerializer()], + ['schema', getExternalPluginAdapterSchemaSerializer()], + ], + { description: 'BaseLinkedAppData' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseLinkedAppDataInitInfo.ts b/clients/js/src/generated/types/baseLinkedAppDataInitInfo.ts new file mode 100644 index 00000000..42993060 --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedAppDataInitInfo.ts @@ -0,0 +1,48 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable } from '@metaplex-foundation/umi'; +import { + Serializer, + option, + struct, +} from '@metaplex-foundation/umi/serializers'; +import { + BasePluginAuthority, + BasePluginAuthorityArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getBasePluginAuthoritySerializer, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseLinkedAppDataInitInfo = { + dataAuthority: BasePluginAuthority; + initPluginAuthority: Option; + schema: Option; +}; + +export type BaseLinkedAppDataInitInfoArgs = { + dataAuthority: BasePluginAuthorityArgs; + initPluginAuthority: OptionOrNullable; + schema: OptionOrNullable; +}; + +export function getBaseLinkedAppDataInitInfoSerializer(): Serializer< + BaseLinkedAppDataInitInfoArgs, + BaseLinkedAppDataInitInfo +> { + return struct( + [ + ['dataAuthority', getBasePluginAuthoritySerializer()], + ['initPluginAuthority', option(getBasePluginAuthoritySerializer())], + ['schema', option(getExternalPluginAdapterSchemaSerializer())], + ], + { description: 'BaseLinkedAppDataInitInfo' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseLinkedAppDataUpdateInfo.ts b/clients/js/src/generated/types/baseLinkedAppDataUpdateInfo.ts new file mode 100644 index 00000000..cf987f8e --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedAppDataUpdateInfo.ts @@ -0,0 +1,37 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable } from '@metaplex-foundation/umi'; +import { + Serializer, + option, + struct, +} from '@metaplex-foundation/umi/serializers'; +import { + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseLinkedAppDataUpdateInfo = { + schema: Option; +}; + +export type BaseLinkedAppDataUpdateInfoArgs = { + schema: OptionOrNullable; +}; + +export function getBaseLinkedAppDataUpdateInfoSerializer(): Serializer< + BaseLinkedAppDataUpdateInfoArgs, + BaseLinkedAppDataUpdateInfo +> { + return struct( + [['schema', option(getExternalPluginAdapterSchemaSerializer())]], + { description: 'BaseLinkedAppDataUpdateInfo' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseLinkedDataKey.ts b/clients/js/src/generated/types/baseLinkedDataKey.ts new file mode 100644 index 00000000..80217cb1 --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedDataKey.ts @@ -0,0 +1,81 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { PublicKey } from '@metaplex-foundation/umi'; +import { + GetDataEnumKind, + GetDataEnumKindContent, + Serializer, + dataEnum, + publicKey as publicKeySerializer, + struct, + tuple, +} from '@metaplex-foundation/umi/serializers'; +import { + BasePluginAuthority, + BasePluginAuthorityArgs, + getBasePluginAuthoritySerializer, +} from '.'; + +export type BaseLinkedDataKey = + | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } + | { __kind: 'LinkedAppData'; fields: [BasePluginAuthority] }; + +export type BaseLinkedDataKeyArgs = + | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } + | { __kind: 'LinkedAppData'; fields: [BasePluginAuthorityArgs] }; + +export function getBaseLinkedDataKeySerializer(): Serializer< + BaseLinkedDataKeyArgs, + BaseLinkedDataKey +> { + return dataEnum( + [ + [ + 'LinkedLifecycleHook', + struct< + GetDataEnumKindContent + >([['fields', tuple([publicKeySerializer()])]]), + ], + [ + 'LinkedAppData', + struct>([ + ['fields', tuple([getBasePluginAuthoritySerializer()])], + ]), + ], + ], + { description: 'BaseLinkedDataKey' } + ) as Serializer; +} + +// Data Enum Helpers. +export function baseLinkedDataKey( + kind: 'LinkedLifecycleHook', + data: GetDataEnumKindContent< + BaseLinkedDataKeyArgs, + 'LinkedLifecycleHook' + >['fields'] +): GetDataEnumKind; +export function baseLinkedDataKey( + kind: 'LinkedAppData', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; +export function baseLinkedDataKey( + kind: K, + data?: any +): Extract { + return Array.isArray(data) + ? { __kind: kind, fields: data } + : { __kind: kind, ...(data ?? {}) }; +} +export function isBaseLinkedDataKey( + kind: K, + value: BaseLinkedDataKey +): value is BaseLinkedDataKey & { __kind: K } { + return value.__kind === kind; +} diff --git a/clients/js/src/generated/types/baseLinkedLifecycleHook.ts b/clients/js/src/generated/types/baseLinkedLifecycleHook.ts new file mode 100644 index 00000000..b84a133f --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedLifecycleHook.ts @@ -0,0 +1,56 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable, PublicKey } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + option, + publicKey as publicKeySerializer, + struct, +} from '@metaplex-foundation/umi/serializers'; +import { + BaseExtraAccount, + BaseExtraAccountArgs, + BasePluginAuthority, + BasePluginAuthorityArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + getBaseExtraAccountSerializer, + getBasePluginAuthoritySerializer, + getExternalPluginAdapterSchemaSerializer, +} from '.'; + +export type BaseLinkedLifecycleHook = { + hookedProgram: PublicKey; + extraAccounts: Option>; + dataAuthority: Option; + schema: ExternalPluginAdapterSchema; +}; + +export type BaseLinkedLifecycleHookArgs = { + hookedProgram: PublicKey; + extraAccounts: OptionOrNullable>; + dataAuthority: OptionOrNullable; + schema: ExternalPluginAdapterSchemaArgs; +}; + +export function getBaseLinkedLifecycleHookSerializer(): Serializer< + BaseLinkedLifecycleHookArgs, + BaseLinkedLifecycleHook +> { + return struct( + [ + ['hookedProgram', publicKeySerializer()], + ['extraAccounts', option(array(getBaseExtraAccountSerializer()))], + ['dataAuthority', option(getBasePluginAuthoritySerializer())], + ['schema', getExternalPluginAdapterSchemaSerializer()], + ], + { description: 'BaseLinkedLifecycleHook' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseLinkedLifecycleHookInitInfo.ts b/clients/js/src/generated/types/baseLinkedLifecycleHookInitInfo.ts new file mode 100644 index 00000000..9b3ae621 --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedLifecycleHookInitInfo.ts @@ -0,0 +1,80 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable, PublicKey } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + option, + publicKey as publicKeySerializer, + struct, + tuple, +} from '@metaplex-foundation/umi/serializers'; +import { + BaseExtraAccount, + BaseExtraAccountArgs, + BasePluginAuthority, + BasePluginAuthorityArgs, + ExternalCheckResult, + ExternalCheckResultArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + HookableLifecycleEvent, + HookableLifecycleEventArgs, + getBaseExtraAccountSerializer, + getBasePluginAuthoritySerializer, + getExternalCheckResultSerializer, + getExternalPluginAdapterSchemaSerializer, + getHookableLifecycleEventSerializer, +} from '.'; + +export type BaseLinkedLifecycleHookInitInfo = { + hookedProgram: PublicKey; + initPluginAuthority: Option; + lifecycleChecks: Array<[HookableLifecycleEvent, ExternalCheckResult]>; + extraAccounts: Option>; + dataAuthority: Option; + schema: Option; +}; + +export type BaseLinkedLifecycleHookInitInfoArgs = { + hookedProgram: PublicKey; + initPluginAuthority: OptionOrNullable; + lifecycleChecks: Array<[HookableLifecycleEventArgs, ExternalCheckResultArgs]>; + extraAccounts: OptionOrNullable>; + dataAuthority: OptionOrNullable; + schema: OptionOrNullable; +}; + +export function getBaseLinkedLifecycleHookInitInfoSerializer(): Serializer< + BaseLinkedLifecycleHookInitInfoArgs, + BaseLinkedLifecycleHookInitInfo +> { + return struct( + [ + ['hookedProgram', publicKeySerializer()], + ['initPluginAuthority', option(getBasePluginAuthoritySerializer())], + [ + 'lifecycleChecks', + array( + tuple([ + getHookableLifecycleEventSerializer(), + getExternalCheckResultSerializer(), + ]) + ), + ], + ['extraAccounts', option(array(getBaseExtraAccountSerializer()))], + ['dataAuthority', option(getBasePluginAuthoritySerializer())], + ['schema', option(getExternalPluginAdapterSchemaSerializer())], + ], + { description: 'BaseLinkedLifecycleHookInitInfo' } + ) as Serializer< + BaseLinkedLifecycleHookInitInfoArgs, + BaseLinkedLifecycleHookInitInfo + >; +} diff --git a/clients/js/src/generated/types/baseLinkedLifecycleHookUpdateInfo.ts b/clients/js/src/generated/types/baseLinkedLifecycleHookUpdateInfo.ts new file mode 100644 index 00000000..2abd14d3 --- /dev/null +++ b/clients/js/src/generated/types/baseLinkedLifecycleHookUpdateInfo.ts @@ -0,0 +1,71 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + option, + struct, + tuple, +} from '@metaplex-foundation/umi/serializers'; +import { + BaseExtraAccount, + BaseExtraAccountArgs, + ExternalCheckResult, + ExternalCheckResultArgs, + ExternalPluginAdapterSchema, + ExternalPluginAdapterSchemaArgs, + HookableLifecycleEvent, + HookableLifecycleEventArgs, + getBaseExtraAccountSerializer, + getExternalCheckResultSerializer, + getExternalPluginAdapterSchemaSerializer, + getHookableLifecycleEventSerializer, +} from '.'; + +export type BaseLinkedLifecycleHookUpdateInfo = { + lifecycleChecks: Option>; + extraAccounts: Option>; + schema: Option; +}; + +export type BaseLinkedLifecycleHookUpdateInfoArgs = { + lifecycleChecks: OptionOrNullable< + Array<[HookableLifecycleEventArgs, ExternalCheckResultArgs]> + >; + extraAccounts: OptionOrNullable>; + schema: OptionOrNullable; +}; + +export function getBaseLinkedLifecycleHookUpdateInfoSerializer(): Serializer< + BaseLinkedLifecycleHookUpdateInfoArgs, + BaseLinkedLifecycleHookUpdateInfo +> { + return struct( + [ + [ + 'lifecycleChecks', + option( + array( + tuple([ + getHookableLifecycleEventSerializer(), + getExternalCheckResultSerializer(), + ]) + ) + ), + ], + ['extraAccounts', option(array(getBaseExtraAccountSerializer()))], + ['schema', option(getExternalPluginAdapterSchemaSerializer())], + ], + { description: 'BaseLinkedLifecycleHookUpdateInfo' } + ) as Serializer< + BaseLinkedLifecycleHookUpdateInfoArgs, + BaseLinkedLifecycleHookUpdateInfo + >; +} diff --git a/clients/js/src/generated/types/externalPluginAdapter.ts b/clients/js/src/generated/types/externalPluginAdapter.ts index b50617df..260f2e09 100644 --- a/clients/js/src/generated/types/externalPluginAdapter.ts +++ b/clients/js/src/generated/types/externalPluginAdapter.ts @@ -15,26 +15,41 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { - BaseDataStore, - BaseDataStoreArgs, + BaseAppData, + BaseAppDataArgs, + BaseDataSection, + BaseDataSectionArgs, BaseLifecycleHook, BaseLifecycleHookArgs, + BaseLinkedAppData, + BaseLinkedAppDataArgs, + BaseLinkedLifecycleHook, + BaseLinkedLifecycleHookArgs, BaseOracle, BaseOracleArgs, - getBaseDataStoreSerializer, + getBaseAppDataSerializer, + getBaseDataSectionSerializer, getBaseLifecycleHookSerializer, + getBaseLinkedAppDataSerializer, + getBaseLinkedLifecycleHookSerializer, getBaseOracleSerializer, } from '.'; export type ExternalPluginAdapter = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHook] } | { __kind: 'Oracle'; fields: [BaseOracle] } - | { __kind: 'DataStore'; fields: [BaseDataStore] }; + | { __kind: 'AppData'; fields: [BaseAppData] } + | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHook] } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppData] } + | { __kind: 'DataSection'; fields: [BaseDataSection] }; export type ExternalPluginAdapterArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookArgs] } | { __kind: 'Oracle'; fields: [BaseOracleArgs] } - | { __kind: 'DataStore'; fields: [BaseDataStoreArgs] }; + | { __kind: 'AppData'; fields: [BaseAppDataArgs] } + | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookArgs] } + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataArgs] } + | { __kind: 'DataSection'; fields: [BaseDataSectionArgs] }; export function getExternalPluginAdapterSerializer(): Serializer< ExternalPluginAdapterArgs, @@ -55,9 +70,27 @@ export function getExternalPluginAdapterSerializer(): Serializer< ]), ], [ - 'DataStore', - struct>([ - ['fields', tuple([getBaseDataStoreSerializer()])], + 'AppData', + struct>([ + ['fields', tuple([getBaseAppDataSerializer()])], + ]), + ], + [ + 'LinkedLifecycleHook', + struct< + GetDataEnumKindContent + >([['fields', tuple([getBaseLinkedLifecycleHookSerializer()])]]), + ], + [ + 'LinkedAppData', + struct>([ + ['fields', tuple([getBaseLinkedAppDataSerializer()])], + ]), + ], + [ + 'DataSection', + struct>([ + ['fields', tuple([getBaseDataSectionSerializer()])], ]), ], ], @@ -78,9 +111,30 @@ export function externalPluginAdapter( data: GetDataEnumKindContent['fields'] ): GetDataEnumKind; export function externalPluginAdapter( - kind: 'DataStore', - data: GetDataEnumKindContent['fields'] -): GetDataEnumKind; + kind: 'AppData', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; +export function externalPluginAdapter( + kind: 'LinkedLifecycleHook', + data: GetDataEnumKindContent< + ExternalPluginAdapterArgs, + 'LinkedLifecycleHook' + >['fields'] +): GetDataEnumKind; +export function externalPluginAdapter( + kind: 'LinkedAppData', + data: GetDataEnumKindContent< + ExternalPluginAdapterArgs, + 'LinkedAppData' + >['fields'] +): GetDataEnumKind; +export function externalPluginAdapter( + kind: 'DataSection', + data: GetDataEnumKindContent< + ExternalPluginAdapterArgs, + 'DataSection' + >['fields'] +): GetDataEnumKind; export function externalPluginAdapter< K extends ExternalPluginAdapterArgs['__kind'], >(kind: K, data?: any): Extract { diff --git a/clients/js/src/generated/types/externalPluginAdapterType.ts b/clients/js/src/generated/types/externalPluginAdapterType.ts index a0141f37..dd992d55 100644 --- a/clients/js/src/generated/types/externalPluginAdapterType.ts +++ b/clients/js/src/generated/types/externalPluginAdapterType.ts @@ -11,7 +11,10 @@ import { Serializer, scalarEnum } from '@metaplex-foundation/umi/serializers'; export enum ExternalPluginAdapterType { LifecycleHook, Oracle, - DataStore, + AppData, + LinkedLifecycleHook, + LinkedAppData, + DataSection, } export type ExternalPluginAdapterTypeArgs = ExternalPluginAdapterType; diff --git a/clients/js/src/generated/types/index.ts b/clients/js/src/generated/types/index.ts index c744b4f0..86c9b374 100644 --- a/clients/js/src/generated/types/index.ts +++ b/clients/js/src/generated/types/index.ts @@ -11,9 +11,12 @@ export * from './attribute'; export * from './attributes'; export * from './autograph'; export * from './autographSignature'; -export * from './baseDataStore'; -export * from './baseDataStoreInitInfo'; -export * from './baseDataStoreUpdateInfo'; +export * from './baseAppData'; +export * from './baseAppDataInitInfo'; +export * from './baseAppDataUpdateInfo'; +export * from './baseDataSection'; +export * from './baseDataSectionInitInfo'; +export * from './baseDataSectionUpdateInfo'; export * from './baseExternalPluginAdapterInitInfo'; export * from './baseExternalPluginAdapterKey'; export * from './baseExternalPluginAdapterUpdateInfo'; @@ -21,6 +24,13 @@ export * from './baseExtraAccount'; export * from './baseLifecycleHook'; export * from './baseLifecycleHookInitInfo'; export * from './baseLifecycleHookUpdateInfo'; +export * from './baseLinkedAppData'; +export * from './baseLinkedAppDataInitInfo'; +export * from './baseLinkedAppDataUpdateInfo'; +export * from './baseLinkedDataKey'; +export * from './baseLinkedLifecycleHook'; +export * from './baseLinkedLifecycleHookInitInfo'; +export * from './baseLinkedLifecycleHookUpdateInfo'; export * from './baseMasterEdition'; export * from './baseOracle'; export * from './baseOracleInitInfo'; diff --git a/clients/js/src/helpers/state.ts b/clients/js/src/helpers/state.ts index 43069bd8..fce68fe5 100644 --- a/clients/js/src/helpers/state.ts +++ b/clients/js/src/helpers/state.ts @@ -1,12 +1,17 @@ import { PublicKey, publicKey } from '@metaplex-foundation/umi'; +import { LinkedLifecycleHookPlugin } from '../plugins/linkedLifecycleHook'; import { AssetV1, CollectionV1 } from '../generated'; -import { ExternalPluginAdaptersList } from '../plugins'; -import { OracleInitInfoArgs, OraclePlugin } from '../plugins/oracle'; -import { DataStoreInitInfoArgs, DataStorePlugin } from '../plugins/dataStore'; import { - LifecycleHookInitInfoArgs, - LifecycleHookPlugin, -} from '../plugins/lifecycleHook'; + comparePluginAuthorities, + ExternalPluginAdapters, + ExternalPluginAdaptersList, + PluginAuthority, +} from '../plugins'; +import { OraclePlugin } from '../plugins/oracle'; +import { AppDataPlugin } from '../plugins/appData'; +import { LifecycleHookPlugin } from '../plugins/lifecycleHook'; +import { DataSectionPlugin } from '../plugins/dataSection'; +import { LinkedAppDataPlugin } from '../plugins/linkedAppData'; /** * Find the collection address for the given asset if it is part of a collection. @@ -23,28 +28,37 @@ export function collectionAddress(asset: AssetV1): PublicKey | undefined { const externalPluginAdapterKeys: (keyof ExternalPluginAdaptersList)[] = [ 'oracles', - 'dataStores', + 'appDatas', 'lifecycleHooks', + 'dataSections', + 'linkedAppDatas', ]; export const getExternalPluginAdapterKeyAsString = ( plugin: - | OraclePlugin - | DataStorePlugin - | LifecycleHookPlugin - | OracleInitInfoArgs - | LifecycleHookInitInfoArgs - | DataStoreInitInfoArgs -) => { + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick +): string => { switch (plugin.type) { case 'Oracle': return `${plugin.type}-${plugin.baseAddress}`; - case 'DataStore': + case 'AppData': return `${plugin.type}-${plugin.dataAuthority.type}${ plugin.dataAuthority.address ? `-${plugin.dataAuthority.address}` : '' }`; case 'LifecycleHook': - default: return `${plugin.type}-${plugin.hookedProgram}`; + case 'LinkedAppData': + return `${plugin.type}-${plugin.dataAuthority.type}${ + plugin.dataAuthority.address ? `-${plugin.dataAuthority.address}` : '' + }`; + case 'DataSection': + return `${plugin.type}-${getExternalPluginAdapterKeyAsString(plugin.parentKey)}`; + default: + throw new Error('Unknown ExternalPluginAdapter type'); } }; @@ -61,20 +75,16 @@ export const deriveExternalPluginAdapters = ( if (asset[key] || collection[key]) { externalPluginAdapters[key] = []; } - asset[key]?.forEach( - (plugin: OraclePlugin | DataStorePlugin | LifecycleHookPlugin) => { - set.add(getExternalPluginAdapterKeyAsString(plugin)); - externalPluginAdapters[key]?.push(plugin as any); - } - ); + asset[key]?.forEach((plugin: ExternalPluginAdapters) => { + set.add(getExternalPluginAdapterKeyAsString(plugin)); + externalPluginAdapters[key]?.push(plugin as any); + }); - collection[key]?.forEach( - (plugin: OraclePlugin | DataStorePlugin | LifecycleHookPlugin) => { - if (!set.has(getExternalPluginAdapterKeyAsString(plugin))) { - externalPluginAdapters[key]?.push(plugin as any); - } + collection[key]?.forEach((plugin: ExternalPluginAdapters) => { + if (!set.has(getExternalPluginAdapterKeyAsString(plugin))) { + externalPluginAdapters[key]?.push(plugin as any); } - ); + }); }); return externalPluginAdapters; @@ -97,6 +107,26 @@ export function deriveAssetPlugins( collection ); + // for every data section, find a matching linked plugin and inject the data for convenience + externalPluginAdapters.dataSections?.forEach((dataSection) => { + let appData; + let dataAuth: PluginAuthority; + switch (dataSection.parentKey.type) { + case 'LinkedAppData': + dataAuth = dataSection.parentKey.dataAuthority; + appData = externalPluginAdapters.linkedAppDatas?.find((plugin) => + comparePluginAuthorities(dataAuth, plugin.dataAuthority) + ); + if (appData) { + appData.data = dataSection.data; + } + break; + case 'LinkedLifecycleHook': + default: + throw new Error('LinkedLifecycleHook currently unsupported'); + } + }); + const { numMinted, currentSize, masterEdition, ...colRest } = collection; // remove collection only fields return { diff --git a/clients/js/src/hooked/pluginRegistryV1Data.ts b/clients/js/src/hooked/pluginRegistryV1Data.ts index 00ee11e1..fc57926b 100644 --- a/clients/js/src/hooked/pluginRegistryV1Data.ts +++ b/clients/js/src/hooked/pluginRegistryV1Data.ts @@ -103,7 +103,7 @@ export function getAdapterRegistryRecordSerializer(): Serializer< offset = 0 ): [ExternalRegistryRecordWithUnknown, number] => { let [pluginType, pluginTypeOffset, isUnknown] = [ - ExternalPluginAdapterType.DataStore, + ExternalPluginAdapterType.AppData, offset + 1, true, ]; diff --git a/clients/js/src/instructions/create.ts b/clients/js/src/instructions/create.ts index e3099ac3..80204483 100644 --- a/clients/js/src/instructions/create.ts +++ b/clients/js/src/instructions/create.ts @@ -59,8 +59,8 @@ export const create = ( type: 'Oracle', }); break; - case 'DataStore': - // Do nothing, datastore has no extra accounts + case 'AppData': + // Do nothing, App Data has no extra accounts break; case 'LifecycleHook': assetExternalPluginAdapters.lifecycleHooks?.push({ diff --git a/clients/js/src/instructions/index.ts b/clients/js/src/instructions/index.ts index 49825646..d1d747ba 100644 --- a/clients/js/src/instructions/index.ts +++ b/clients/js/src/instructions/index.ts @@ -11,3 +11,4 @@ export * from './updatePlugin'; export * from './approvePluginAuthority'; export * from './revokePluginAuthority'; export * from './collection'; +export * from './writeData'; diff --git a/clients/js/src/instructions/update.ts b/clients/js/src/instructions/update.ts index a7b949e4..c3bbd233 100644 --- a/clients/js/src/instructions/update.ts +++ b/clients/js/src/instructions/update.ts @@ -1,21 +1,21 @@ import { Context } from '@metaplex-foundation/umi'; import { CollectionV1, - updateV1, AssetV1, - UpdateV1InstructionDataArgs, + UpdateV2InstructionDataArgs, + updateV2, } from '../generated'; import { findExtraAccounts } from '../plugins'; import { deriveExternalPluginAdapters } from '../helpers'; export type UpdateArgs = Omit< - Parameters[1], + Parameters[1], 'asset' | 'collection' | 'newName' | 'newUri' > & { asset: Pick; collection?: Pick; - name?: UpdateV1InstructionDataArgs['newName']; - uri?: UpdateV1InstructionDataArgs['newUri']; + name?: UpdateV2InstructionDataArgs['newName']; + uri?: UpdateV2InstructionDataArgs['newUri']; }; export const update = ( @@ -38,7 +38,7 @@ export const update = ( } ); - return updateV1(context, { + return updateV2(context, { ...args, asset: asset.publicKey, collection: collection?.publicKey, diff --git a/clients/js/src/instructions/writeData.ts b/clients/js/src/instructions/writeData.ts new file mode 100644 index 00000000..9793d189 --- /dev/null +++ b/clients/js/src/instructions/writeData.ts @@ -0,0 +1,28 @@ +import { Context } from '@metaplex-foundation/umi'; +import { + writeExternalPluginAdapterDataV1, + WriteExternalPluginAdapterDataV1InstructionArgs, + WriteExternalPluginAdapterDataV1InstructionAccounts, +} from '../generated'; +import { + ExternalPluginAdapterKey, + externalPluginAdapterKeyToBase, +} from '../plugins'; + +export type WriteDataArgs = Omit< + WriteExternalPluginAdapterDataV1InstructionArgs, + 'key' +> & { + key: ExternalPluginAdapterKey; +}; + +export const writeData = ( + context: Pick, + args: WriteDataArgs & WriteExternalPluginAdapterDataV1InstructionAccounts +) => { + const { key, ...rest } = args; + return writeExternalPluginAdapterDataV1(context, { + ...rest, + key: externalPluginAdapterKeyToBase(key), + }); +}; diff --git a/clients/js/src/plugins/dataStore.ts b/clients/js/src/plugins/appData.ts similarity index 54% rename from clients/js/src/plugins/dataStore.ts rename to clients/js/src/plugins/appData.ts index 04aa1ca0..fb244517 100644 --- a/clients/js/src/plugins/dataStore.ts +++ b/clients/js/src/plugins/appData.ts @@ -1,7 +1,7 @@ import { - BaseDataStore, - BaseDataStoreInitInfoArgs, - BaseDataStoreUpdateInfoArgs, + BaseAppData, + BaseAppDataInitInfoArgs, + BaseAppDataUpdateInfoArgs, ExternalPluginAdapterSchema, ExternalRegistryRecord, } from '../generated'; @@ -16,61 +16,61 @@ import { pluginAuthorityToBase, } from './pluginAuthority'; -export type DataStore = Omit & { +export type AppData = Omit & { dataAuthority: PluginAuthority; data?: any; }; -export type DataStorePlugin = BaseExternalPluginAdapter & - DataStore & { - type: 'DataStore'; +export type AppDataPlugin = BaseExternalPluginAdapter & + AppData & { + type: 'AppData'; dataAuthority: PluginAuthority; }; -export type DataStoreInitInfoArgs = Omit< - BaseDataStoreInitInfoArgs, +export type AppDataInitInfoArgs = Omit< + BaseAppDataInitInfoArgs, 'initPluginAuthority' | 'lifecycleChecks' | 'dataAuthority' > & { - type: 'DataStore'; + type: 'AppData'; initPluginAuthority?: PluginAuthority; lifecycleChecks?: LifecycleChecks; schema?: ExternalPluginAdapterSchema; dataAuthority: PluginAuthority; }; -export type DataStoreUpdateInfoArgs = Omit< - BaseDataStoreUpdateInfoArgs, +export type AppDataUpdateInfoArgs = Omit< + BaseAppDataUpdateInfoArgs, 'schema' > & { key: ExternalPluginAdapterKey; schema?: ExternalPluginAdapterSchema; }; -export function dataStoreInitInfoArgsToBase( - d: DataStoreInitInfoArgs -): BaseDataStoreInitInfoArgs { +export function appDataInitInfoArgsToBase( + d: AppDataInitInfoArgs +): BaseAppDataInitInfoArgs { return { dataAuthority: pluginAuthorityToBase(d.dataAuthority), initPluginAuthority: d.initPluginAuthority ? pluginAuthorityToBase(d.initPluginAuthority) : null, - schema: d.schema ? d.schema : null, + schema: d.schema ?? null, }; } -export function dataStoreUpdateInfoArgsToBase( - d: DataStoreUpdateInfoArgs -): BaseDataStoreUpdateInfoArgs { +export function appDataUpdateInfoArgsToBase( + d: AppDataUpdateInfoArgs +): BaseAppDataUpdateInfoArgs { return { - schema: d.schema ? d.schema : null, + schema: d.schema ?? null, }; } -export function dataStoreFromBase( - s: BaseDataStore, +export function appDataFromBase( + s: BaseAppData, r: ExternalRegistryRecord, account: Uint8Array -): DataStore { +): AppData { return { ...s, dataAuthority: pluginAuthorityFromBase(s.dataAuthority), @@ -78,16 +78,16 @@ export function dataStoreFromBase( }; } -export const dataStoreManifest: ExternalPluginAdapterManifest< - DataStore, - BaseDataStore, - DataStoreInitInfoArgs, - BaseDataStoreInitInfoArgs, - DataStoreUpdateInfoArgs, - BaseDataStoreUpdateInfoArgs +export const appDataManifest: ExternalPluginAdapterManifest< + AppData, + BaseAppData, + AppDataInitInfoArgs, + BaseAppDataInitInfoArgs, + AppDataUpdateInfoArgs, + BaseAppDataUpdateInfoArgs > = { - type: 'DataStore', - fromBase: dataStoreFromBase, - initToBase: dataStoreInitInfoArgsToBase, - updateToBase: dataStoreUpdateInfoArgsToBase, + type: 'AppData', + fromBase: appDataFromBase, + initToBase: appDataInitInfoArgsToBase, + updateToBase: appDataUpdateInfoArgsToBase, }; diff --git a/clients/js/src/plugins/dataSection.ts b/clients/js/src/plugins/dataSection.ts new file mode 100644 index 00000000..327b4055 --- /dev/null +++ b/clients/js/src/plugins/dataSection.ts @@ -0,0 +1,88 @@ +import { + BaseDataSection, + BaseDataSectionInitInfoArgs, + BaseDataSectionUpdateInfoArgs, + ExternalRegistryRecord, +} from '../generated'; +import { ExternalPluginAdapterKey } from './externalPluginAdapterKey'; +import { ExternalPluginAdapterManifest } from './externalPluginAdapterManifest'; +import { BaseExternalPluginAdapter } from './externalPluginAdapters'; +import { parseExternalPluginAdapterData } from './lib'; +import { + LinkedDataKey, + linkedDataKeyFromBase, + linkedDataKeyToBase, +} from './linkedDataKey'; +import { PluginAuthority, pluginAuthorityFromBase } from './pluginAuthority'; + +export type DataSection = Omit< + BaseDataSection, + 'dataAuthority' | 'parentKey' +> & { + dataAuthority?: PluginAuthority; + parentKey: LinkedDataKey; + data?: any; +}; + +export type DataSectionPlugin = BaseExternalPluginAdapter & + DataSection & { + type: 'DataSection'; + }; + +export type DataSectionInitInfoArgs = Omit< + BaseDataSectionInitInfoArgs, + 'parentKey' +> & { + type: 'DataSection'; + parentKey: LinkedDataKey; +}; + +export type DataSectionUpdateInfoArgs = BaseDataSectionUpdateInfoArgs & { + key: ExternalPluginAdapterKey; +}; + +export function dataSectionInitInfoArgsToBase( + d: DataSectionInitInfoArgs +): BaseDataSectionInitInfoArgs { + return { + parentKey: linkedDataKeyToBase(d.parentKey), + schema: d.schema, + }; +} + +export function dataSectionUpdateInfoArgsToBase( + d: DataSectionUpdateInfoArgs +): BaseDataSectionUpdateInfoArgs { + // You can't update the data section directly + return {}; +} + +export function dataSectionFromBase( + s: BaseDataSection, + r: ExternalRegistryRecord, + account: Uint8Array +): DataSection { + return { + ...s, + parentKey: linkedDataKeyFromBase(s.parentKey), + dataAuthority: + s.parentKey.__kind !== 'LinkedLifecycleHook' + ? pluginAuthorityFromBase(s.parentKey.fields[0]) + : undefined, + data: parseExternalPluginAdapterData(s, r, account), + }; +} + +export const dataSectionManifest: ExternalPluginAdapterManifest< + DataSection, + BaseDataSection, + DataSectionInitInfoArgs, + BaseDataSectionInitInfoArgs, + DataSectionUpdateInfoArgs, + BaseDataSectionUpdateInfoArgs +> = { + type: 'DataSection', + fromBase: dataSectionFromBase, + initToBase: dataSectionInitInfoArgsToBase, + updateToBase: dataSectionUpdateInfoArgsToBase, +}; diff --git a/clients/js/src/plugins/externalPluginAdapterKey.ts b/clients/js/src/plugins/externalPluginAdapterKey.ts index e86610b0..8b89113b 100644 --- a/clients/js/src/plugins/externalPluginAdapterKey.ts +++ b/clients/js/src/plugins/externalPluginAdapterKey.ts @@ -1,38 +1,57 @@ import { PublicKey } from '@metaplex-foundation/umi'; import { BaseExternalPluginAdapterKey } from '../generated'; import { PluginAuthority, pluginAuthorityToBase } from './pluginAuthority'; +import { LinkedDataKey, linkedDataKeyToBase } from './linkedDataKey'; export type ExternalPluginAdapterKey = + | { + type: 'LifecycleHook'; + hookedProgram: PublicKey; + } | { type: 'Oracle'; baseAddress: PublicKey; } | { - type: 'DataStore'; + type: 'AppData'; dataAuthority: PluginAuthority; } | { - type: 'LifecycleHook'; - hookedProgram: PublicKey; - }; + type: 'LinkedLifecycleHook'; + dataAuthority: PublicKey; + } + | { + type: 'LinkedAppData'; + dataAuthority: PluginAuthority; + } + | { type: 'DataSection'; parentKey: LinkedDataKey }; export function externalPluginAdapterKeyToBase( e: ExternalPluginAdapterKey ): BaseExternalPluginAdapterKey { - if (e.type === 'Oracle') { - return { - __kind: 'Oracle', - fields: [e.baseAddress], - }; - } - if (e.type === 'DataStore') { - return { - __kind: 'DataStore', - fields: [pluginAuthorityToBase(e.dataAuthority)], - }; + switch (e.type) { + case 'Oracle': + return { + __kind: e.type, + fields: [e.baseAddress], + }; + case 'AppData': + case 'LinkedAppData': + return { + __kind: e.type, + fields: [pluginAuthorityToBase(e.dataAuthority)], + }; + case 'LifecycleHook': + return { + __kind: e.type, + fields: [e.hookedProgram], + }; + case 'DataSection': + return { + __kind: e.type, + fields: [linkedDataKeyToBase(e.parentKey)], + }; + default: + throw new Error('Unknown ExternalPluginAdapterKey type'); } - return { - __kind: 'LifecycleHook', - fields: [e.hookedProgram], - }; } diff --git a/clients/js/src/plugins/externalPluginAdapters.ts b/clients/js/src/plugins/externalPluginAdapters.ts index d5dcaef0..b276055d 100644 --- a/clients/js/src/plugins/externalPluginAdapters.ts +++ b/clients/js/src/plugins/externalPluginAdapters.ts @@ -16,12 +16,12 @@ import { } from '../generated'; import { - dataStoreFromBase, - DataStoreInitInfoArgs, - dataStoreManifest, - DataStorePlugin, - DataStoreUpdateInfoArgs, -} from './dataStore'; + appDataFromBase, + AppDataInitInfoArgs, + appDataManifest, + AppDataPlugin, + AppDataUpdateInfoArgs, +} from './appData'; import { LifecycleChecksContainer, lifecycleChecksFromBase, @@ -36,44 +36,92 @@ import { } from './oracle'; import { BasePlugin } from './types'; import { extraAccountToAccountMeta } from './extraAccount'; +import { + linkedAppDataFromBase, + LinkedAppDataInitInfoArgs, + linkedAppDataManifest, + LinkedAppDataPlugin, + LinkedAppDataUpdateInfoArgs, +} from './linkedAppData'; +import { + dataSectionFromBase, + dataSectionManifest, + DataSectionPlugin, +} from './dataSection'; +import { + LinkedLifecycleHookInitInfoArgs, + LinkedLifecycleHookPlugin, + LinkedLifecycleHookUpdateInfoArgs, + linkedLifecycleHookFromBase, + linkedLifecycleHookManifest, +} from './linkedLifecycleHook'; export type ExternalPluginAdapterTypeString = BaseExternalPluginAdapterKey['__kind']; export type BaseExternalPluginAdapter = BasePlugin & LifecycleChecksContainer; +export type ExternalPluginAdapters = + | LifecycleHookPlugin + | OraclePlugin + | AppDataPlugin + | LinkedLifecycleHookPlugin + | LinkedAppDataPlugin + | DataSectionPlugin; + export type ExternalPluginAdaptersList = { - oracles?: OraclePlugin[]; - dataStores?: DataStorePlugin[]; lifecycleHooks?: LifecycleHookPlugin[]; + oracles?: OraclePlugin[]; + appDatas?: AppDataPlugin[]; + linkedLifecycleHooks?: LinkedLifecycleHookPlugin[]; + linkedAppDatas?: LinkedAppDataPlugin[]; + dataSections?: DataSectionPlugin[]; }; export type ExternalPluginAdapterInitInfoArgs = + | ({ + type: 'LifecycleHook'; + } & LifecycleHookInitInfoArgs) | ({ type: 'Oracle'; } & OracleInitInfoArgs) | ({ - type: 'LifecycleHook'; - } & LifecycleHookInitInfoArgs) + type: 'AppData'; + } & AppDataInitInfoArgs) + | ({ + type: 'LinkedLifecycleHook'; + } & LinkedLifecycleHookInitInfoArgs) | ({ - type: 'DataStore'; - } & DataStoreInitInfoArgs); + type: 'LinkedAppData'; + } & LinkedAppDataInitInfoArgs) + | ({ + type: 'DataSection'; + } & AppDataInitInfoArgs); export type ExternalPluginAdapterUpdateInfoArgs = + | ({ + type: 'LifecycleHook'; + } & LifecycleHookUpdateInfoArgs) | ({ type: 'Oracle'; } & OracleUpdateInfoArgs) | ({ - type: 'LifecycleHook'; - } & LifecycleHookUpdateInfoArgs) + type: 'AppData'; + } & AppDataUpdateInfoArgs) | ({ - type: 'DataStore'; - } & DataStoreUpdateInfoArgs); + type: 'LinkedLifecycleHook'; + } & LinkedLifecycleHookUpdateInfoArgs) + | ({ + type: 'LinkedAppData'; + } & LinkedAppDataUpdateInfoArgs); export const externalPluginAdapterManifests = { - Oracle: oracleManifest, - DataStore: dataStoreManifest, LifecycleHook: lifecycleHookManifest, + Oracle: oracleManifest, + AppData: appDataManifest, + LinkedLifecycleHook: linkedLifecycleHookManifest, + LinkedAppData: linkedAppDataManifest, + DataSection: dataSectionManifest, }; export type ExternalPluginAdapterData = { @@ -102,7 +150,29 @@ export function externalRegistryRecordsToExternalPluginAdapterList( offset: record.offset, }; - if (deserializedPlugin.__kind === 'Oracle') { + if (deserializedPlugin.__kind === 'LifecycleHook') { + if (!result.lifecycleHooks) { + result.lifecycleHooks = []; + } + result.lifecycleHooks.push({ + type: 'LifecycleHook', + ...mappedPlugin, + ...lifecycleHookFromBase( + deserializedPlugin.fields[0], + record, + accountData + ), + }); + } else if (deserializedPlugin.__kind === 'AppData') { + if (!result.appDatas) { + result.appDatas = []; + } + result.appDatas.push({ + type: 'AppData', + ...mappedPlugin, + ...appDataFromBase(deserializedPlugin.fields[0], record, accountData), + }); + } else if (deserializedPlugin.__kind === 'Oracle') { if (!result.oracles) { result.oracles = []; } @@ -112,23 +182,40 @@ export function externalRegistryRecordsToExternalPluginAdapterList( ...mappedPlugin, ...oracleFromBase(deserializedPlugin.fields[0], record, accountData), }); - } else if (deserializedPlugin.__kind === 'DataStore') { - if (!result.dataStores) { - result.dataStores = []; + } else if (deserializedPlugin.__kind === 'LinkedLifecycleHook') { + if (!result.linkedLifecycleHooks) { + result.linkedLifecycleHooks = []; } - result.dataStores.push({ - type: 'DataStore', + result.linkedLifecycleHooks.push({ + type: 'LinkedLifecycleHook', ...mappedPlugin, - ...dataStoreFromBase(deserializedPlugin.fields[0], record, accountData), + ...linkedLifecycleHookFromBase( + deserializedPlugin.fields[0], + record, + accountData + ), }); - } else if (deserializedPlugin.__kind === 'LifecycleHook') { - if (!result.lifecycleHooks) { - result.lifecycleHooks = []; + } else if (deserializedPlugin.__kind === 'LinkedAppData') { + if (!result.linkedAppDatas) { + result.linkedAppDatas = []; } - result.lifecycleHooks.push({ - type: 'LifecycleHook', + result.linkedAppDatas.push({ + type: 'LinkedAppData', ...mappedPlugin, - ...lifecycleHookFromBase( + ...linkedAppDataFromBase( + deserializedPlugin.fields[0], + record, + accountData + ), + }); + } else if (deserializedPlugin.__kind === 'DataSection') { + if (!result.dataSections) { + result.dataSections = []; + } + result.dataSections.push({ + type: 'DataSection', + ...mappedPlugin, + ...dataSectionFromBase( deserializedPlugin.fields[0], record, accountData @@ -142,9 +229,12 @@ export function externalRegistryRecordsToExternalPluginAdapterList( export const isExternalPluginAdapterType = (plugin: { type: string }) => { if ( - plugin.type === 'Oracle' || plugin.type === 'LifecycleHook' || - plugin.type === 'DataStore' + plugin.type === 'Oracle' || + plugin.type === 'AppData' || + plugin.type === 'LinkedLifecycleHook' || + plugin.type === 'DataSection' || + plugin.type === 'LinkedAppData' ) { return true; } @@ -224,5 +314,24 @@ export const findExtraAccounts = ( } }); + externalPluginAdapters.linkedLifecycleHooks?.forEach((hook) => { + if (hook.lifecycleChecks?.[lifecycle]) { + accounts.push({ + pubkey: hook.hookedProgram, + isSigner: false, + isWritable: false, + }); + + hook.extraAccounts?.forEach((extra) => { + accounts.push( + extraAccountToAccountMeta(context, extra, { + ...inputs, + program: hook.hookedProgram, + }) + ); + }); + } + }); + return accounts; }; diff --git a/clients/js/src/plugins/index.ts b/clients/js/src/plugins/index.ts index 9bff9abb..29777a81 100644 --- a/clients/js/src/plugins/index.ts +++ b/clients/js/src/plugins/index.ts @@ -1,6 +1,6 @@ export * from './royalties'; export * from './lib'; -export * from './dataStore'; +export * from './appData'; export * from './lifecycleChecks'; export * from './lifecycleHook'; export * from './oracle'; @@ -13,4 +13,8 @@ export * from './updateAuthority'; export * from './seed'; export * from './extraAccount'; export * from './validationResultsOffset'; +export * from './linkedLifecycleHook'; +export * from './linkedAppData'; +export * from './dataSection'; +export * from './linkedDataKey'; export * from './masterEdition'; diff --git a/clients/js/src/plugins/lib.ts b/clients/js/src/plugins/lib.ts index 14dd4798..b91e9541 100644 --- a/clients/js/src/plugins/lib.ts +++ b/clients/js/src/plugins/lib.ts @@ -1,5 +1,6 @@ -import { none, Option, some } from '@metaplex-foundation/umi'; +import { isSome, none, Option, some } from '@metaplex-foundation/umi'; +import { decode } from '@msgpack/msgpack'; import { Key, PluginHeaderV1, @@ -215,21 +216,32 @@ export function parseExternalPluginAdapterData( account: Uint8Array ): any { let data; - const dataSlice = account.slice( - Number(record.dataOffset), - Number(record.dataOffset) + Number(record.dataLen) - ); - - if (plugin.schema === ExternalPluginAdapterSchema.Binary) { - data = dataSlice; - } else if (plugin.schema === ExternalPluginAdapterSchema.Json) { - data = JSON.parse(new TextDecoder().decode(dataSlice)); - } else if (plugin.schema === ExternalPluginAdapterSchema.MsgPack) { - // eslint-disable-next-line no-console - console.warn( - 'MsgPack schema currently not supported, falling back to binary' + if (isSome(record.dataOffset) && isSome(record.dataLen)) { + const dataSlice = account.slice( + Number(record.dataOffset.value), + Number(record.dataOffset.value) + Number(record.dataLen.value) ); - data = dataSlice; + + if (plugin.schema === ExternalPluginAdapterSchema.Binary) { + data = dataSlice; + } else if (plugin.schema === ExternalPluginAdapterSchema.Json) { + // if data is empty, the data slice is uninitialized and should be ignored + if (dataSlice.length !== 0) { + try { + data = JSON.parse(new TextDecoder().decode(dataSlice)); + } catch (e) { + // eslint-disable-next-line no-console + console.warn('Invalid JSON in external plugin data', e.message); + } + } + } else if (plugin.schema === ExternalPluginAdapterSchema.MsgPack) { + if (dataSlice.length === 0) { + data = null; + } else { + data = decode(dataSlice); + } + } + return data; } - return data; + throw new Error('Invalid DataStore, missing dataOffset or dataLen'); } diff --git a/clients/js/src/plugins/lifecycleHook.ts b/clients/js/src/plugins/lifecycleHook.ts index f3de62c1..55601b50 100644 --- a/clients/js/src/plugins/lifecycleHook.ts +++ b/clients/js/src/plugins/lifecycleHook.ts @@ -75,7 +75,7 @@ export function lifecycleHookInitInfoArgsToBase( ? pluginAuthorityToBase(l.initPluginAuthority) : null, lifecycleChecks: lifecycleChecksToBase(l.lifecycleChecks), - schema: l.schema ? l.schema : null, + schema: l.schema ?? null, dataAuthority: l.dataAuthority ? pluginAuthorityToBase(l.dataAuthority) : null, @@ -92,7 +92,7 @@ export function lifecycleHookUpdateInfoArgsToBase( extraAccounts: l.extraAccounts ? l.extraAccounts.map(extraAccountToBase) : null, - schema: l.schema ? l.schema : null, + schema: l.schema ?? null, // TODO update dataAuthority? }; } diff --git a/clients/js/src/plugins/linkedAppData.ts b/clients/js/src/plugins/linkedAppData.ts new file mode 100644 index 00000000..8993c7d6 --- /dev/null +++ b/clients/js/src/plugins/linkedAppData.ts @@ -0,0 +1,92 @@ +import { + BaseLinkedAppData, + BaseLinkedAppDataInitInfoArgs, + BaseLinkedAppDataUpdateInfoArgs, + ExternalPluginAdapterSchema, + ExternalRegistryRecord, +} from '../generated'; +import { ExternalPluginAdapterKey } from './externalPluginAdapterKey'; +import { ExternalPluginAdapterManifest } from './externalPluginAdapterManifest'; +import { BaseExternalPluginAdapter } from './externalPluginAdapters'; +import { LifecycleChecks } from './lifecycleChecks'; +import { + PluginAuthority, + pluginAuthorityFromBase, + pluginAuthorityToBase, +} from './pluginAuthority'; + +export type LinkedAppData = Omit & { + dataAuthority: PluginAuthority; + data?: any; +}; + +export type LinkedAppDataPlugin = BaseExternalPluginAdapter & + LinkedAppData & { + type: 'LinkedAppData'; + dataAuthority: PluginAuthority; + }; + +export type LinkedAppDataInitInfoArgs = Omit< + BaseLinkedAppDataInitInfoArgs, + 'initPluginAuthority' | 'lifecycleChecks' | 'dataAuthority' +> & { + type: 'LinkedAppData'; + initPluginAuthority?: PluginAuthority; + lifecycleChecks?: LifecycleChecks; + schema?: ExternalPluginAdapterSchema; + dataAuthority: PluginAuthority; +}; + +export type LinkedAppDataUpdateInfoArgs = Omit< + BaseLinkedAppDataUpdateInfoArgs, + 'schema' +> & { + key: ExternalPluginAdapterKey; + schema?: ExternalPluginAdapterSchema; +}; + +export function linkedAppDataInitInfoArgsToBase( + d: LinkedAppDataInitInfoArgs +): BaseLinkedAppDataInitInfoArgs { + return { + dataAuthority: pluginAuthorityToBase(d.dataAuthority), + initPluginAuthority: d.initPluginAuthority + ? pluginAuthorityToBase(d.initPluginAuthority) + : null, + schema: d.schema ?? null, + }; +} + +export function linkedAppDataUpdateInfoArgsToBase( + d: LinkedAppDataUpdateInfoArgs +): BaseLinkedAppDataUpdateInfoArgs { + return { + schema: d.schema ?? null, + }; +} + +export function linkedAppDataFromBase( + s: BaseLinkedAppData, + r: ExternalRegistryRecord, + account: Uint8Array +): LinkedAppData { + return { + ...s, + dataAuthority: pluginAuthorityFromBase(s.dataAuthority), + // plugin has no data but injected in the derivation of the asset + }; +} + +export const linkedAppDataManifest: ExternalPluginAdapterManifest< + LinkedAppData, + BaseLinkedAppData, + LinkedAppDataInitInfoArgs, + BaseLinkedAppDataInitInfoArgs, + LinkedAppDataUpdateInfoArgs, + BaseLinkedAppDataUpdateInfoArgs +> = { + type: 'LinkedAppData', + fromBase: linkedAppDataFromBase, + initToBase: linkedAppDataInitInfoArgsToBase, + updateToBase: linkedAppDataUpdateInfoArgsToBase, +}; diff --git a/clients/js/src/plugins/linkedDataKey.ts b/clients/js/src/plugins/linkedDataKey.ts new file mode 100644 index 00000000..5cafe496 --- /dev/null +++ b/clients/js/src/plugins/linkedDataKey.ts @@ -0,0 +1,52 @@ +import { PublicKey } from '@metaplex-foundation/umi'; + +import { + PluginAuthority, + pluginAuthorityFromBase, + pluginAuthorityToBase, +} from './pluginAuthority'; +import { BaseLinkedDataKey } from '../generated'; + +export type LinkedDataKey = + | { + type: 'LinkedLifecycleHook'; + hookedProgram: PublicKey; + } + | { + type: 'LinkedAppData'; + dataAuthority: PluginAuthority; + }; + +export function linkedDataKeyToBase(e: LinkedDataKey): BaseLinkedDataKey { + switch (e.type) { + case 'LinkedLifecycleHook': + return { + __kind: e.type, + fields: [e.hookedProgram], + }; + case 'LinkedAppData': + return { + __kind: e.type, + fields: [pluginAuthorityToBase(e.dataAuthority)], + }; + default: + throw new Error('Unknown LinkedDataKey type'); + } +} + +export function linkedDataKeyFromBase(e: BaseLinkedDataKey): LinkedDataKey { + switch (e.__kind) { + case 'LinkedLifecycleHook': + return { + type: e.__kind, + hookedProgram: e.fields[0], + }; + case 'LinkedAppData': + return { + type: e.__kind, + dataAuthority: pluginAuthorityFromBase(e.fields[0]), + }; + default: + throw new Error('Unknown LinkedDataKey type'); + } +} diff --git a/clients/js/src/plugins/linkedLifecycleHook.ts b/clients/js/src/plugins/linkedLifecycleHook.ts new file mode 100644 index 00000000..cacb6b3c --- /dev/null +++ b/clients/js/src/plugins/linkedLifecycleHook.ts @@ -0,0 +1,129 @@ +import { PublicKey } from '@metaplex-foundation/umi'; +import { + ExtraAccount, + extraAccountFromBase, + extraAccountToBase, +} from './extraAccount'; +import { + BaseLinkedLifecycleHook, + BaseLinkedLifecycleHookInitInfoArgs, + BaseLinkedLifecycleHookUpdateInfoArgs, + ExternalPluginAdapterSchema, + ExternalRegistryRecord, +} from '../generated'; +import { LifecycleChecks, lifecycleChecksToBase } from './lifecycleChecks'; +import { + PluginAuthority, + pluginAuthorityFromBase, + pluginAuthorityToBase, +} from './pluginAuthority'; +import { BaseExternalPluginAdapter } from './externalPluginAdapters'; +import { ExternalPluginAdapterManifest } from './externalPluginAdapterManifest'; +import { ExternalPluginAdapterKey } from './externalPluginAdapterKey'; +// import { parseExternalPluginAdapterData } from './lib'; + +export type LinkedLifecycleHook = Omit< + BaseLinkedLifecycleHook, + 'extraAccounts' | 'dataAuthority' +> & { + extraAccounts?: Array; + dataAuthority?: PluginAuthority; + data?: any; +}; + +export type LinkedLifecycleHookPlugin = BaseExternalPluginAdapter & + LinkedLifecycleHook & { + type: 'LinkedLifecycleHook'; + hookedProgram: PublicKey; + }; + +export type LinkedLifecycleHookInitInfoArgs = Omit< + BaseLinkedLifecycleHookInitInfoArgs, + | 'initPluginAuthority' + | 'lifecycleChecks' + | 'schema' + | 'extraAccounts' + | 'dataAuthority' +> & { + type: 'LinkedLifecycleHook'; + initPluginAuthority?: PluginAuthority; + lifecycleChecks: LifecycleChecks; + schema?: ExternalPluginAdapterSchema; + extraAccounts?: Array; + dataAuthority?: PluginAuthority; +}; + +export type LinkedLifecycleHookUpdateInfoArgs = Omit< + BaseLinkedLifecycleHookUpdateInfoArgs, + 'lifecycleChecks' | 'extraAccounts' | 'schema' +> & { + key: ExternalPluginAdapterKey; + lifecycleChecks?: LifecycleChecks; + extraAccounts?: Array; + schema?: ExternalPluginAdapterSchema; +}; + +export function linkedLifecycleHookInitInfoArgsToBase( + l: LinkedLifecycleHookInitInfoArgs +): BaseLinkedLifecycleHookInitInfoArgs { + return { + extraAccounts: l.extraAccounts + ? l.extraAccounts.map(extraAccountToBase) + : null, + hookedProgram: l.hookedProgram, + initPluginAuthority: l.initPluginAuthority + ? pluginAuthorityToBase(l.initPluginAuthority) + : null, + lifecycleChecks: lifecycleChecksToBase(l.lifecycleChecks), + schema: l.schema ? l.schema : null, + dataAuthority: l.dataAuthority + ? pluginAuthorityToBase(l.dataAuthority) + : null, + }; +} + +export function linkedLifecycleHookUpdateInfoArgsToBase( + l: LinkedLifecycleHookUpdateInfoArgs +): BaseLinkedLifecycleHookUpdateInfoArgs { + return { + lifecycleChecks: l.lifecycleChecks + ? lifecycleChecksToBase(l.lifecycleChecks) + : null, + extraAccounts: l.extraAccounts + ? l.extraAccounts.map(extraAccountToBase) + : null, + schema: l.schema ?? null, + }; +} + +export function linkedLifecycleHookFromBase( + s: BaseLinkedLifecycleHook, + r: ExternalRegistryRecord, + account: Uint8Array +): LinkedLifecycleHook { + return { + ...s, + extraAccounts: + s.extraAccounts.__option === 'Some' + ? s.extraAccounts.value.map(extraAccountFromBase) + : undefined, + dataAuthority: + s.dataAuthority.__option === 'Some' + ? pluginAuthorityFromBase(s.dataAuthority.value) + : undefined, + }; +} + +export const linkedLifecycleHookManifest: ExternalPluginAdapterManifest< + LinkedLifecycleHook, + BaseLinkedLifecycleHook, + LinkedLifecycleHookInitInfoArgs, + BaseLinkedLifecycleHookInitInfoArgs, + LinkedLifecycleHookUpdateInfoArgs, + BaseLinkedLifecycleHookUpdateInfoArgs +> = { + type: 'LinkedLifecycleHook', + fromBase: linkedLifecycleHookFromBase, + initToBase: linkedLifecycleHookInitInfoArgsToBase, + updateToBase: linkedLifecycleHookUpdateInfoArgsToBase, +}; diff --git a/clients/js/src/plugins/pluginAuthority.ts b/clients/js/src/plugins/pluginAuthority.ts index b0a4f0b3..e75e2365 100644 --- a/clients/js/src/plugins/pluginAuthority.ts +++ b/clients/js/src/plugins/pluginAuthority.ts @@ -28,3 +28,13 @@ export function pluginAuthorityFromBase( address: (authority as any).address, }; } +export function comparePluginAuthorities( + a: PluginAuthority, + b: PluginAuthority +): boolean { + if (a.type !== b.type) { + return false; + } + + return a.address === b.address; +} diff --git a/clients/js/test/_setupRaw.ts b/clients/js/test/_setupRaw.ts index 685ba375..bc2f696e 100644 --- a/clients/js/test/_setupRaw.ts +++ b/clients/js/test/_setupRaw.ts @@ -24,6 +24,7 @@ import { ExternalPluginAdaptersList, AssetPluginsList, CollectionPluginsList, + fetchAsset, } from '../src'; export const createUmi = async () => (await basecreateUmi()).use(mplCore()); @@ -38,7 +39,6 @@ export type CreateAssetHelperArgs = { authority?: Signer; updateAuthority?: PublicKey | Signer; collection?: PublicKey; - // TODO use PluginList type here plugins?: PluginAuthorityPairArgs[]; }; @@ -76,8 +76,6 @@ export const createAsset = async ( authority: input.authority, }).sendAndConfirm(umi); - // console.log("Creating with:", input.plugins, "cost", (await umi.rpc.getTransaction(tx.signature))?.meta.computeUnitsConsumed); - return fetchAssetV1(umi, publicKey(asset)); }; @@ -87,7 +85,6 @@ export type CreateCollectionHelperArgs = { name?: string; uri?: string; updateAuthority?: PublicKey | Signer; - // TODO use CollectionPluginList type here plugins?: PluginAuthorityPairArgs[]; }; @@ -147,11 +144,16 @@ export const assertAsset = async ( name?: string | RegExp; uri?: string | RegExp; } & AssetPluginsList & - ExternalPluginAdaptersList + ExternalPluginAdaptersList, + options: { derivePlugins: boolean } = { + derivePlugins: false, + } ) => { const { asset, owner, name, uri, ...rest } = input; const assetAddress = publicKey(input.asset); - const assetWithPlugins = await fetchAssetV1(umi, assetAddress); + const assetWithPlugins = options.derivePlugins + ? await fetchAsset(umi, assetAddress) + : await fetchAssetV1(umi, assetAddress); // Name. if (typeof name === 'string') t.is(assetWithPlugins.name, name); diff --git a/clients/js/test/externalPlugins/appData.test.ts b/clients/js/test/externalPlugins/appData.test.ts new file mode 100644 index 00000000..2d59c4e5 --- /dev/null +++ b/clients/js/test/externalPlugins/appData.test.ts @@ -0,0 +1,834 @@ +import test from 'ava'; +import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; +import { Signer, Umi, generateSigner } from '@metaplex-foundation/umi'; +import * as msgpack from '@msgpack/msgpack'; +import { + assertAsset, + createUmi, + DEFAULT_ASSET, + assertCollection, +} from '../_setupRaw'; +import { createAsset } from '../_setupSdk'; +import { + ExternalPluginAdapterSchema, + PluginAuthority, + PluginAuthorityType, + updatePlugin, + writeData, + create, + createCollection, + updateCollectionPlugin, +} from '../../src'; + +const DATA_AUTHORITIES: PluginAuthorityType[] = [ + 'Owner', + 'UpdateAuthority', + 'Address', +]; +const SCHEMAS: ExternalPluginAdapterSchema[] = [ + ExternalPluginAdapterSchema.Binary, + ExternalPluginAdapterSchema.Json, + ExternalPluginAdapterSchema.MsgPack, +]; + +type TestContext = { + umi: Umi; + owner: Signer; + dataAuthoritySigner: Signer; + dataAuthority: PluginAuthority; + wrongDataAuthoritySigner?: Signer; + wrongDataAuthority?: PluginAuthority; + data: Uint8Array; + otherData: Uint8Array; +}; + +async function generateTestContext( + dataAuthorityType: PluginAuthorityType, + schema: ExternalPluginAdapterSchema, + wrongDataAuthorityType?: PluginAuthorityType +): Promise { + const umi = await createUmi(); + + const owner = await generateSignerWithSol(umi); + let dataAuthoritySigner = null; + let dataAuthority = null; + if (dataAuthorityType === 'Address') { + dataAuthoritySigner = await generateSignerWithSol(umi); + dataAuthority = { + type: dataAuthorityType, + address: dataAuthoritySigner.publicKey, + }; + } else if (dataAuthorityType === 'UpdateAuthority') { + dataAuthoritySigner = umi.identity; + dataAuthority = { type: dataAuthorityType }; + } else if (dataAuthorityType === 'Owner') { + dataAuthoritySigner = owner; + dataAuthority = { type: dataAuthorityType }; + } + + let wrongDataAuthoritySigner; + let wrongDataAuthority; + if (wrongDataAuthorityType) { + if (wrongDataAuthorityType === 'Address') { + wrongDataAuthoritySigner = await generateSignerWithSol(umi); + wrongDataAuthority = { + type: wrongDataAuthorityType, + address: wrongDataAuthoritySigner.publicKey, + }; + } else if (wrongDataAuthorityType === 'UpdateAuthority') { + wrongDataAuthoritySigner = umi.identity; + wrongDataAuthority = { type: wrongDataAuthorityType }; + } else if (wrongDataAuthorityType === 'Owner') { + wrongDataAuthoritySigner = owner; + wrongDataAuthority = { type: wrongDataAuthorityType }; + } + } + + let data = new Uint8Array(); + let otherData = new Uint8Array(); + + if (schema === ExternalPluginAdapterSchema.Binary) { + const binaryData = 'Hello, world!'; + const binaryOtherData = 'Hello, world! Hello, world!'; + data = Uint8Array.from(Buffer.from(binaryData)); + otherData = Uint8Array.from(Buffer.from(binaryOtherData)); + } else if (schema === ExternalPluginAdapterSchema.Json) { + const dataJson = { message: 'Hello', target: 'world' }; + const otherDataJson = { message: 'Hello hello', target: 'big wide world' }; + data = Uint8Array.from(Buffer.from(JSON.stringify(dataJson))); + otherData = Uint8Array.from(Buffer.from(JSON.stringify(otherDataJson))); + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + data = msgpack.encode({ message: 'Hello', target: 'msgpack' }); + otherData = msgpack.encode({ message: 'Hello hello', target: 'msgpack' }); + } + + if (!dataAuthoritySigner) { + throw new Error('Data authority signer not set'); + } + if (!dataAuthority) { + throw new Error('Data authority not set'); + } + + return { + umi, + owner, + dataAuthoritySigner, + dataAuthority, + wrongDataAuthoritySigner, + wrongDataAuthority, + data, + otherData, + }; +} + +DATA_AUTHORITIES.forEach((dataAuthorityType) => { + SCHEMAS.forEach((schema) => { + test(`it can create a secure app data with ${dataAuthorityType} as data authority and ${ExternalPluginAdapterSchema[schema]} as schema`, async (t) => { + const { umi, dataAuthority, owner } = await generateTestContext( + dataAuthorityType, + schema + ); + + // create asset referencing the oracle account + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'AppData', + dataAuthority, + schema, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + }); + + test(`it can write ${ExternalPluginAdapterSchema[schema]} data to a secure app data as ${dataAuthorityType} data authority`, async (t) => { + const { umi, owner, dataAuthoritySigner, dataAuthority, data } = + await generateTestContext(dataAuthorityType, schema); + + // create asset with the Secure App Data + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'AppData', + dataAuthority, + schema, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'AppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + data, + asset: asset.publicKey, + }).sendAndConfirm(umi); + + let assertData = null; + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = data; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(data); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(data).toString()); + } + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + }); + }); + + test(`it can write ${ExternalPluginAdapterSchema[schema]} data to a secure app data as ${dataAuthorityType} data authority multiple times`, async (t) => { + const { + umi, + owner, + dataAuthoritySigner, + dataAuthority, + data, + otherData, + } = await generateTestContext(dataAuthorityType, schema); + + // create asset with the Secure App Data + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'AppData', + dataAuthority, + schema, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'AppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + let assertData = null; + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = data; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(data); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(data).toString()); + } + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'AppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(otherData)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = otherData; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(otherData); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(otherData).toString()); + } + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + }); + }); + }); + + DATA_AUTHORITIES.filter( + (da) => da === 'Address' || da !== dataAuthorityType + ).forEach((otherDataAuthorityType) => { + test(`it cannot write data to a secure app data with ${dataAuthorityType} data authority using ${otherDataAuthorityType} data authority`, async (t) => { + const { umi, owner, dataAuthority, wrongDataAuthoritySigner, data } = + await generateTestContext( + dataAuthorityType, + ExternalPluginAdapterSchema.Binary, + otherDataAuthorityType + ); + // create asset with the Secure App Data + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'AppData', + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + const res = writeData(umi, { + key: { + type: 'AppData', + dataAuthority, + }, + authority: wrongDataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(res, { name: 'InvalidAuthority' }); + }); + }); + + test(`it cannot write data to a secure app data as ${dataAuthorityType} data authority if the data authority is None`, async (t) => { + const { umi, owner, dataAuthoritySigner, data } = await generateTestContext( + dataAuthorityType, + ExternalPluginAdapterSchema.Binary + ); + + // create asset with the Secure App Data + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'AppData', + dataAuthority: { type: 'None' }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority: { type: 'None' }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + const res = writeData(umi, { + key: { + type: 'AppData', + dataAuthority: { type: 'None' }, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(res, { name: 'InvalidAuthority' }); + }); +}); + +test(`updating a plugin before a secure app data does not corrupt the data`, async (t) => { + const { umi, owner, dataAuthoritySigner, dataAuthority, data } = + await generateTestContext( + 'UpdateAuthority', + ExternalPluginAdapterSchema.Json + ); + + // create asset with the Secure App Data + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'Attributes', + attributeList: [ + { + key: 'Test', + value: 'Test', + }, + ], + }, + { + type: 'AppData', + dataAuthority, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'AppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + const assertData = JSON.parse(Buffer.from(data).toString()); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: 'Test', value: 'Test' }], + }, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Json, + data: assertData, + }, + ], + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + attributeList: [{ key: 'Updated Test', value: 'Updated Test' }], + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: 'Updated Test', value: 'Updated Test' }], + }, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Json, + data: assertData, + }, + ], + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { type: 'Attributes', attributeList: [{ key: '', value: '' }] }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: '', value: '' }], + }, + appDatas: [ + { + type: 'AppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Json, + data: assertData, + }, + ], + }); +}); + +test('it can update app data with external plugin authority different than asset update authority', async (t) => { + const umi = await createUmi(); + const asset = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + authority: appDataUpdateAuthority, + plugin: { + key: { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'AppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); +}); + +test('it cannot update app data using update authority when different from external plugin authority', async (t) => { + const umi = await createUmi(); + const asset = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + const result = updatePlugin(umi, { + asset: asset.publicKey, + authority: umi.identity, + plugin: { + key: { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'AppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); +}); + +test('it can update app data on collection with external plugin authority different than asset update authority', async (t) => { + const umi = await createUmi(); + const collection = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await createCollection(umi, { + collection, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + await updateCollectionPlugin(umi, { + collection: collection.publicKey, + authority: appDataUpdateAuthority, + plugin: { + key: { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'AppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); +}); + +test('it cannot update app data on collection using update authority when different from external plugin authority', async (t) => { + const umi = await createUmi(); + const collection = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await createCollection(umi, { + collection, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + const result = updateCollectionPlugin(umi, { + collection: collection.publicKey, + authority: umi.identity, + plugin: { + key: { + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'AppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + appDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'AppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); +}); diff --git a/clients/js/test/externalPlugins/dataSection.test.ts b/clients/js/test/externalPlugins/dataSection.test.ts new file mode 100644 index 00000000..c581f67b --- /dev/null +++ b/clients/js/test/externalPlugins/dataSection.test.ts @@ -0,0 +1,112 @@ +import { SPL_SYSTEM_PROGRAM_ID } from '@metaplex-foundation/mpl-toolbox'; +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { createCollection, createAsset } from '../_setupSdk'; +import { createUmi, DEFAULT_ASSET } from '../_setupRaw'; +import { + addCollectionExternalPluginAdapterV1, + addExternalPluginAdapterV1, + createCollectionV2, + createV2, + ExternalPluginAdapterSchema, +} from '../../src'; + +test('it cannot create an asset with a DataSection', async (t) => { + const umi = await createUmi(); + const asset = await generateSigner(umi); + + const result = createV2(umi, { + asset, + ...DEFAULT_ASSET, + externalPluginAdapters: [ + { + __kind: 'DataSection', + fields: [ + { + parentKey: { + __kind: 'LinkedLifecycleHook', + fields: [SPL_SYSTEM_PROGRAM_ID], + }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + ], + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'CannotAddDataSection' }); +}); + +test('it cannot create a collection with a DataSection', async (t) => { + const umi = await createUmi(); + const collection = await generateSigner(umi); + + const result = createCollectionV2(umi, { + collection, + ...DEFAULT_ASSET, + externalPluginAdapters: [ + { + __kind: 'DataSection', + fields: [ + { + parentKey: { + __kind: 'LinkedLifecycleHook', + fields: [SPL_SYSTEM_PROGRAM_ID], + }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + ], + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'CannotAddDataSection' }); +}); + +test('it cannot add a DataSection to an asset', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi); + + const result = addExternalPluginAdapterV1(umi, { + asset: asset.publicKey, + initInfo: { + __kind: 'DataSection', + fields: [ + { + parentKey: { + __kind: 'LinkedLifecycleHook', + fields: [SPL_SYSTEM_PROGRAM_ID], + }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'CannotAddDataSection' }); +}); + +test('it cannot add a DataSection to a collection', async (t) => { + const umi = await createUmi(); + + const collection = await createCollection(umi); + + const result = addCollectionExternalPluginAdapterV1(umi, { + collection: collection.publicKey, + initInfo: { + __kind: 'DataSection', + fields: [ + { + parentKey: { + __kind: 'LinkedLifecycleHook', + fields: [SPL_SYSTEM_PROGRAM_ID], + }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'CannotAddDataSection' }); +}); diff --git a/clients/js/test/externalPlugins/linkedAppData.test.ts b/clients/js/test/externalPlugins/linkedAppData.test.ts new file mode 100644 index 00000000..6caa942a --- /dev/null +++ b/clients/js/test/externalPlugins/linkedAppData.test.ts @@ -0,0 +1,926 @@ +import test from 'ava'; +import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; +import { Signer, Umi, generateSigner } from '@metaplex-foundation/umi'; +import * as msgpack from '@msgpack/msgpack'; +import { + assertAsset, + assertCollection, + createUmi, + DEFAULT_ASSET, + DEFAULT_COLLECTION, +} from '../_setupRaw'; +import { createAssetWithCollection } from '../_setupSdk'; +import { + ExternalPluginAdapterSchema, + PluginAuthority, + PluginAuthorityType, + updatePlugin, + writeData, + create, + createCollection, + updateCollectionPlugin, + addPlugin, +} from '../../src'; + +const DATA_AUTHORITIES: PluginAuthorityType[] = [ + 'Owner', + 'UpdateAuthority', + 'Address', +]; +const SCHEMAS: ExternalPluginAdapterSchema[] = [ + ExternalPluginAdapterSchema.Binary, + ExternalPluginAdapterSchema.Json, + ExternalPluginAdapterSchema.MsgPack, +]; + +type TestContext = { + umi: Umi; + owner: Signer; + dataAuthoritySigner: Signer; + dataAuthority: PluginAuthority; + wrongDataAuthoritySigner?: Signer; + wrongDataAuthority?: PluginAuthority; + data: Uint8Array; + otherData: Uint8Array; +}; + +async function generateTestContext( + dataAuthorityType: PluginAuthorityType, + schema: ExternalPluginAdapterSchema, + wrongDataAuthorityType?: PluginAuthorityType +): Promise { + const umi = await createUmi(); + + const owner = await generateSignerWithSol(umi); + let dataAuthoritySigner = null; + let dataAuthority = null; + if (dataAuthorityType === 'Address') { + dataAuthoritySigner = await generateSignerWithSol(umi); + dataAuthority = { + type: dataAuthorityType, + address: dataAuthoritySigner.publicKey, + }; + } else if (dataAuthorityType === 'UpdateAuthority') { + dataAuthoritySigner = umi.identity; + dataAuthority = { type: dataAuthorityType }; + } else if (dataAuthorityType === 'Owner') { + dataAuthoritySigner = owner; + dataAuthority = { type: dataAuthorityType }; + } + + let wrongDataAuthoritySigner; + let wrongDataAuthority; + if (wrongDataAuthorityType) { + if (wrongDataAuthorityType === 'Address') { + wrongDataAuthoritySigner = await generateSignerWithSol(umi); + wrongDataAuthority = { + type: wrongDataAuthorityType, + address: wrongDataAuthoritySigner.publicKey, + }; + } else if (wrongDataAuthorityType === 'UpdateAuthority') { + wrongDataAuthoritySigner = umi.identity; + wrongDataAuthority = { type: wrongDataAuthorityType }; + } else if (wrongDataAuthorityType === 'Owner') { + wrongDataAuthoritySigner = owner; + wrongDataAuthority = { type: wrongDataAuthorityType }; + } + } + + let data = new Uint8Array(); + let otherData = new Uint8Array(); + + if (schema === ExternalPluginAdapterSchema.Binary) { + const binaryData = 'Hello, world!'; + const binaryOtherData = 'Hello, world! Hello, world!'; + data = Uint8Array.from(Buffer.from(binaryData)); + otherData = Uint8Array.from(Buffer.from(binaryOtherData)); + } else if (schema === ExternalPluginAdapterSchema.Json) { + const dataJson = { message: 'Hello', target: 'world' }; + const otherDataJson = { message: 'Hello hello', target: 'big wide world' }; + data = Uint8Array.from(Buffer.from(JSON.stringify(dataJson))); + otherData = Uint8Array.from(Buffer.from(JSON.stringify(otherDataJson))); + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + data = msgpack.encode({ message: 'Hello', target: 'msgpack' }); + otherData = msgpack.encode({ message: 'Hello hello', target: 'msgpack' }); + } + + if (!dataAuthoritySigner) { + throw new Error('Data authority signer not set'); + } + if (!dataAuthority) { + throw new Error('Data authority not set'); + } + + return { + umi, + owner, + dataAuthoritySigner, + dataAuthority, + wrongDataAuthoritySigner, + wrongDataAuthority, + data, + otherData, + }; +} + +DATA_AUTHORITIES.forEach((dataAuthorityType) => { + SCHEMAS.forEach((schema) => { + test(`it can create an linked secure app data with ${dataAuthorityType} as data authority and ${ExternalPluginAdapterSchema[schema]} as schema`, async (t) => { + const { umi, dataAuthority, owner } = await generateTestContext( + dataAuthorityType, + schema + ); + + // create collection with linked secure app data + const { collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority, + schema, + }, + ], + } + ); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + }); + + test(`it can write ${ExternalPluginAdapterSchema[schema]} data to an linked secure app data as ${dataAuthorityType} data authority`, async (t) => { + const { umi, owner, dataAuthoritySigner, dataAuthority, data } = + await generateTestContext(dataAuthorityType, schema); + + // create collection with linked secure app data + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority, + schema, + }, + ], + } + ); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + collection: collection.publicKey, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + let assertData = null; + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = data; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(data); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(data).toString()); + } + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema, + }, + ], + }, + { + derivePlugins: true, + } + ); + }); + + test(`it can write ${ExternalPluginAdapterSchema[schema]} data to an linked secure app data as ${dataAuthorityType} data authority multiple times`, async (t) => { + const { + umi, + owner, + dataAuthoritySigner, + dataAuthority, + data, + otherData, + } = await generateTestContext(dataAuthorityType, schema); + + // create collection with linked secure app data + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority, + schema, + }, + ], + } + ); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + }, + ], + }); + + await writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + collection: collection.publicKey, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + let assertData = null; + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = data; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(data); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(data).toString()); + } + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema, + }, + ], + }, + { + derivePlugins: true, + } + ); + + await writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + collection: collection.publicKey, + data: Uint8Array.from(Buffer.from(otherData)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + if (schema === ExternalPluginAdapterSchema.Binary) { + assertData = otherData; + } else if (schema === ExternalPluginAdapterSchema.MsgPack) { + assertData = msgpack.decode(otherData); + } else if (schema === ExternalPluginAdapterSchema.Json) { + assertData = JSON.parse(Buffer.from(otherData).toString()); + } + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema, + }, + ], + }, + { + derivePlugins: true, + } + ); + }); + }); + + DATA_AUTHORITIES.filter( + (da) => da === 'Address' || da !== dataAuthorityType + ).forEach((otherDataAuthorityType) => { + test(`it cannot write data to an linked secure app data with ${dataAuthorityType} data authority using ${otherDataAuthorityType} data authority`, async (t) => { + const { umi, owner, dataAuthority, wrongDataAuthoritySigner, data } = + await generateTestContext( + dataAuthorityType, + ExternalPluginAdapterSchema.Binary, + otherDataAuthorityType + ); + + // create collection with linked secure app data + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + } + ); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + const res = writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: wrongDataAuthoritySigner, + collection: collection.publicKey, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(res, { name: 'InvalidAuthority' }); + }); + }); + + test(`it cannot write data to an linked secure app data as ${dataAuthorityType} data authority if the data authority is None`, async (t) => { + const { umi, owner, dataAuthoritySigner, data } = await generateTestContext( + dataAuthorityType, + ExternalPluginAdapterSchema.Binary + ); + + // create collection with linked secure app data + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority: { type: 'None' }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + } + ); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority: { type: 'None' }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + const res = writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority: { type: 'None' }, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + collection: collection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(res, { name: 'InvalidAuthority' }); + }); +}); + +test(`updating a plugin before a secure app data does not corrupt the data`, async (t) => { + const { umi, owner, dataAuthoritySigner, dataAuthority, data } = + await generateTestContext( + 'UpdateAuthority', + ExternalPluginAdapterSchema.Binary + ); + + // create collection with linked secure app data + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + plugins: [ + { + type: 'Attributes', + attributeList: [ + { + key: 'Test', + value: 'Test', + }, + ], + }, + ], + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + } + ); + + await writeData(umi, { + key: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: dataAuthoritySigner, + data: Uint8Array.from(Buffer.from(data)), + asset: asset.publicKey, + collection: collection.publicKey, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); + + const assertData = data; + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: 'Test', value: 'Test' }], + }, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + { + derivePlugins: true, + } + ); + + await updatePlugin(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: { + type: 'Attributes', + attributeList: [{ key: 'Updated Test', value: 'Updated Test' }], + }, + }).sendAndConfirm(umi); + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: 'Updated Test', value: 'Updated Test' }], + }, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + { + derivePlugins: true, + } + ); + + await updatePlugin(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: { type: 'Attributes', attributeList: [{ key: '', value: '' }] }, + }).sendAndConfirm(umi); + + // check the derived asset sdk correctly injects the data + await assertAsset( + t, + umi, + { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + attributes: { + authority: { type: 'UpdateAuthority' }, + attributeList: [{ key: '', value: '' }], + }, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { type: 'UpdateAuthority' }, + dataAuthority, + schema: ExternalPluginAdapterSchema.Binary, + data: assertData, + }, + ], + dataSections: [ + { + type: 'DataSection', + parentKey: { + type: 'LinkedAppData', + dataAuthority, + }, + authority: { type: 'None' }, + data: assertData, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }, + { + derivePlugins: true, + } + ); +}); + +test('it cannot create an asset with linked app data', async (t) => { + const umi = await createUmi(); + const asset = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + const result = create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidPluginAdapterTarget' }); +}); + +test('it cannot add linked app data to an asset', async (t) => { + const umi = await createUmi(); + const asset = generateSigner(umi); + + await create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + linkedAppDatas: undefined, + }); + + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + const result = addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidPluginAdapterTarget' }); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + linkedAppDatas: undefined, + }); +}); + +test('it can update linked app data on collection with external plugin authority different than asset update authority', async (t) => { + const umi = await createUmi(); + const collection = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await createCollection(umi, { + collection, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + linkedAppDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + await updateCollectionPlugin(umi, { + collection: collection.publicKey, + authority: appDataUpdateAuthority, + plugin: { + key: { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'LinkedAppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + linkedAppDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Binary, + }, + ], + }); +}); + +test('it cannot update linked app data on collection using update authority when different from external plugin authority', async (t) => { + const umi = await createUmi(); + const collection = generateSigner(umi); + const dataAuthority = generateSigner(umi); + const appDataUpdateAuthority = generateSigner(umi); + + await createCollection(umi, { + collection, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + initPluginAuthority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + }, + ], + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + linkedAppDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + const result = updateCollectionPlugin(umi, { + collection: collection.publicKey, + authority: umi.identity, + plugin: { + key: { + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + }, + type: 'LinkedAppData', + schema: ExternalPluginAdapterSchema.Binary, + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertCollection(t, umi, { + uri: 'https://example.com', + name: 'Test name', + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + linkedAppDatas: [ + { + authority: { + type: 'Address', + address: appDataUpdateAuthority.publicKey, + }, + type: 'LinkedAppData', + dataAuthority: { type: 'Address', address: dataAuthority.publicKey }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); +}); diff --git a/clients/js/test/plugins/asset/burnDelegate.test.ts b/clients/js/test/plugins/asset/burnDelegate.test.ts new file mode 100644 index 00000000..adf3dc28 --- /dev/null +++ b/clients/js/test/plugins/asset/burnDelegate.test.ts @@ -0,0 +1,252 @@ +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { addPlugin, revokePluginAuthority, burn } from '../../../src'; +import { + DEFAULT_ASSET, + assertAsset, + createUmi, + assertBurned, +} from '../../_setupRaw'; +import { createAsset, createCollection } from '../../_setupSdk'; + +test('it can create an asset with burnDelegate', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'BurnDelegate', + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Owner', + }, + }, + }); +}); + +test('it can add burnDelegate to an asset', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi, {}); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: undefined, + }); + + const burnDelegate = generateSigner(umi); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'BurnDelegate', + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }); +}); + +test('a burnDelegate can burn an asset', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi, {}); + const burnDelegate = generateSigner(umi); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'BurnDelegate', + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }); + + await burn(umi, { + asset, + authority: burnDelegate, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); + +test('an burnDelegate cannot burn an asset after delegate authority revoked', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi, {}); + const burnDelegate = generateSigner(umi); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'BurnDelegate', + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Address', + address: burnDelegate.publicKey, + }, + }, + }); + + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'BurnDelegate', + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Owner', + }, + }, + }); + + const result = burn(umi, { + asset, + authority: burnDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + burnDelegate: { + authority: { + type: 'Owner', + }, + }, + }); +}); + +test('a burnDelegate can burn using delegated update authority', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + updateAuthority: updateAuthority.publicKey, + owner: owner.publicKey, + plugins: [ + { + type: 'BurnDelegate', + authority: { + type: 'UpdateAuthority', + }, + }, + ], + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + burnDelegate: { + authority: { + type: 'UpdateAuthority', + }, + }, + }); + + await burn(umi, { + asset, + authority: updateAuthority, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); + +test('a burnDelegate can burn using delegated update authority from collection', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const collection = await createCollection(umi, { + updateAuthority: updateAuthority.publicKey, + }); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + collection: collection.publicKey, + plugins: [ + { + type: 'BurnDelegate', + authority: { + type: 'UpdateAuthority', + }, + }, + ], + authority: updateAuthority, + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + burnDelegate: { + authority: { + type: 'UpdateAuthority', + }, + }, + }); + + await burn(umi, { + asset, + collection, + authority: updateAuthority, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); diff --git a/clients/js/test/plugins/asset/delegateTransfer.test.ts b/clients/js/test/plugins/asset/delegateTransfer.test.ts index ab3cfdc7..9804a561 100644 --- a/clients/js/test/plugins/asset/delegateTransfer.test.ts +++ b/clients/js/test/plugins/asset/delegateTransfer.test.ts @@ -163,6 +163,58 @@ test('it cannot transfer after delegate authority has been revoked', async (t) = }); }); +test('it can transfer using delegated update authority', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const newOwner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'TransferDelegate', + authority: { + type: 'UpdateAuthority', + }, + }, + ], + authority: updateAuthority, + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + transferDelegate: { + authority: { + type: 'UpdateAuthority', + }, + }, + }); + + await transfer(umi, { + asset, + newOwner: newOwner.publicKey, + authority: updateAuthority, + }).sendAndConfirm(umi); + + // Resets to `Owner` after the transfer. + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + transferDelegate: { + authority: { + type: 'Owner', + }, + }, + }); +}); + test('it can transfer using delegated update authority from collection', async (t) => { const umi = await createUmi(); const owner = generateSigner(umi); @@ -187,6 +239,18 @@ test('it can transfer using delegated update authority from collection', async ( authority: updateAuthority, }); + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection' }, + transferDelegate: { + authority: { + type: 'UpdateAuthority', + }, + }, + }); + await transfer(umi, { asset, collection, @@ -194,6 +258,7 @@ test('it can transfer using delegated update authority from collection', async ( authority: updateAuthority, }).sendAndConfirm(umi); + // Resets to `Owner` after the transfer. await assertAsset(t, umi, { ...DEFAULT_ASSET, asset: asset.publicKey, diff --git a/clients/js/test/plugins/asset/freeze.test.ts b/clients/js/test/plugins/asset/freeze.test.ts index fa6f0f7e..a6df6d91 100644 --- a/clients/js/test/plugins/asset/freeze.test.ts +++ b/clients/js/test/plugins/asset/freeze.test.ts @@ -11,11 +11,13 @@ import { createPlugin, ownerPluginAuthority, removePluginV1, + updatePluginAuthority, } from '../../../src'; import { DEFAULT_ASSET, assertAsset, createAsset, + createCollection, createUmi, } from '../../_setupRaw'; @@ -346,3 +348,105 @@ test('it update authority cannot unfreeze frozen asset', async (t) => { }, }); }); + +test('a freezeDelegate can freeze using delegated update authority', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + updateAuthority: updateAuthority.publicKey, + owner: owner.publicKey, + plugins: [ + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: false }, + authority: updatePluginAuthority(), + }), + ], + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + freezeDelegate: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ type: 'FreezeDelegate', data: { frozen: true } }), + authority: updateAuthority, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + freezeDelegate: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); +}); + +test('a freezeDelegate can freeze using delegated update authority from collection', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const collection = await createCollection(umi, { + updateAuthority: updateAuthority.publicKey, + }); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + collection: collection.publicKey, + plugins: [ + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: false }, + authority: updatePluginAuthority(), + }), + ], + authority: updateAuthority, + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + freezeDelegate: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + await updatePluginV1(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: createPlugin({ type: 'FreezeDelegate', data: { frozen: true } }), + authority: updateAuthority, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + freezeDelegate: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); +}); diff --git a/clients/js/test/plugins/asset/updateDelegate.test.ts b/clients/js/test/plugins/asset/updateDelegate.test.ts index 15a72822..9598851a 100644 --- a/clients/js/test/plugins/asset/updateDelegate.test.ts +++ b/clients/js/test/plugins/asset/updateDelegate.test.ts @@ -1,30 +1,26 @@ import { generateSigner } from '@metaplex-foundation/umi'; import test from 'ava'; import { - createPlugin, - pluginAuthorityPair, - addPluginV1, - updatePluginV1, - updateV1, - addressPluginAuthority, - revokePluginAuthorityV1, - PluginType, + addPlugin, + approvePluginAuthority, + removePlugin, + revokePluginAuthority, + update, + updateAuthority, + updatePlugin, } from '../../../src'; -import { - DEFAULT_ASSET, - assertAsset, - createAsset, - createUmi, -} from '../../_setupRaw'; +import { DEFAULT_ASSET, assertAsset, createUmi } from '../../_setupRaw'; +import { createAsset } from '../../_setupSdk'; test('it can create an asset with updateDelegate', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, ], }); @@ -42,53 +38,71 @@ test('it can create an asset with updateDelegate', async (t) => { }); }); -test('it cannot create an asset with updateDelegate with additional delegates', async (t) => { +test('it can create an asset with updateDelegate with additional delegates', async (t) => { const umi = await createUmi(); + const updateDelegate = generateSigner(umi); - const result = createAsset(umi, { + const asset = await createAsset(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, ], }); - await t.throwsAsync(result, { name: 'NotAvailable' }); + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + }); }); -test('it cannot add updateDelegate to asset with additional delegates', async (t) => { +test('it can add updateDelegate to asset with additional delegates', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi); + const updateDelegate = generateSigner(umi); - const result = addPluginV1(umi, { + await addPlugin(umi, { asset: asset.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, }).sendAndConfirm(umi); - await t.throwsAsync(result, { name: 'NotAvailable' }); - await assertAsset(t, umi, { ...DEFAULT_ASSET, asset: asset.publicKey, owner: umi.identity.publicKey, updateAuthority: { type: 'Address', address: umi.identity.publicKey }, - updateDelegate: undefined, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, }); }); -test('it cannot update updateDelegate on asset with additional delegates', async (t) => { +test('it can update updateDelegate on asset with additional delegates', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi); + const updateDelegate = generateSigner(umi); - await addPluginV1(umi, { + await addPlugin(umi, { asset: asset.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, }).sendAndConfirm(umi); await assertAsset(t, umi, { @@ -104,16 +118,14 @@ test('it cannot update updateDelegate on asset with additional delegates', async }, }); - const result = updatePluginV1(umi, { + await updatePlugin(umi, { asset: asset.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, }).sendAndConfirm(umi); - await t.throwsAsync(result, { name: 'NotAvailable' }); - await assertAsset(t, umi, { ...DEFAULT_ASSET, asset: asset.publicKey, @@ -123,12 +135,12 @@ test('it cannot update updateDelegate on asset with additional delegates', async authority: { type: 'UpdateAuthority', }, - additionalDelegates: [], + additionalDelegates: [updateDelegate.publicKey], }, }); }); -test('it updateDelegate can update an asset', async (t) => { +test('an updateDelegate can update an asset', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi, { name: 'short', @@ -136,12 +148,16 @@ test('it updateDelegate can update an asset', async (t) => { }); const updateDelegate = generateSigner(umi); - await addPluginV1(umi, { + await addPlugin(umi, { asset: asset.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - }), - initAuthority: addressPluginAuthority(updateDelegate.publicKey), + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, }).sendAndConfirm(umi); await assertAsset(t, umi, { @@ -159,15 +175,14 @@ test('it updateDelegate can update an asset', async (t) => { uri: 'https://short.com', }); - await updateV1(umi, { - asset: asset.publicKey, - newName: 'Test Bread 2', - newUri: 'https://example.com/bread2', + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', authority: updateDelegate, }).sendAndConfirm(umi); await assertAsset(t, umi, { - ...DEFAULT_ASSET, asset: asset.publicKey, owner: umi.identity.publicKey, updateAuthority: { type: 'Address', address: umi.identity.publicKey }, @@ -183,7 +198,60 @@ test('it updateDelegate can update an asset', async (t) => { }); }); -test('it updateDelegate cannot update an asset after delegate authority revoked', async (t) => { +test('an updateDelegate additionalDelegate can update an asset', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi, { + name: 'short', + uri: 'https://short.com', + }); + const updateDelegate = generateSigner(umi); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + name: 'short', + uri: 'https://short.com', + }); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); +}); + +test('an updateDelegate cannot update an asset after delegate authority revoked', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi, { name: 'short', @@ -191,12 +259,16 @@ test('it updateDelegate cannot update an asset after delegate authority revoked' }); const updateDelegate = generateSigner(umi); - await addPluginV1(umi, { + await addPlugin(umi, { asset: asset.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - }), - initAuthority: addressPluginAuthority(updateDelegate.publicKey), + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, }).sendAndConfirm(umi); await assertAsset(t, umi, { @@ -214,11 +286,36 @@ test('it updateDelegate cannot update an asset after delegate authority revoked' uri: 'https://short.com', }); - await revokePluginAuthorityV1(umi, { + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { asset: asset.publicKey, - pluginType: PluginType.UpdateDelegate, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [], + }, + name: 'short', + uri: 'https://short.com', + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: updateDelegate, }).sendAndConfirm(umi); + await t.throwsAsync(result, { name: 'NoApprovals' }); + await assertAsset(t, umi, { asset: asset.publicKey, owner: umi.identity.publicKey, @@ -232,11 +329,66 @@ test('it updateDelegate cannot update an asset after delegate authority revoked' name: 'short', uri: 'https://short.com', }); +}); + +test('an updateDelegate additionalDelegate cannot update an asset after delegate authority revoked', async (t) => { + const umi = await createUmi(); + const { identity } = umi; + const asset = await createAsset(umi, { + name: 'short', + uri: 'https://short.com', + }); + const updateDelegate = generateSigner(umi); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + name: 'short', + uri: 'https://short.com', + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + authority: identity, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + }).sendAndConfirm(umi); - const result = updateV1(umi, { + await assertAsset(t, umi, { asset: asset.publicKey, - newName: 'Test Bread 2', - newUri: 'https://example.com/bread2', + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [], + }, + name: 'short', + uri: 'https://short.com', + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', authority: updateDelegate, }).sendAndConfirm(umi); @@ -256,3 +408,1066 @@ test('it updateDelegate cannot update an asset after delegate authority revoked' uri: 'https://short.com', }); }); + +test('it cannot add additional delegate as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + const result = updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [ + updateDelegate.publicKey, + updateDelegate2.publicKey, + ], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it can remove additional delegate as additional delegate if self', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [ + updateDelegate.publicKey, + updateDelegate2.publicKey, + ], + }, + ], + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate2.publicKey], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate2.publicKey], + }, + }); +}); + +test('it cannot remove another additional delegate as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [ + updateDelegate.publicKey, + updateDelegate2.publicKey, + ], + }, + ], + }); + + const result = updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot approve the update delegate plugin authority as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + const result = approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { + type: 'Address', + address: updateDelegate2.publicKey, + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot revoke the update delegate plugin authority as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + authority: { + type: 'Address', + address: updateDelegate2.publicKey, + }, + }, + ], + }); + + const result = revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it can approve/revoke the plugin authority of non-updateDelegate plugins as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + { + type: 'Edition', + number: 1, + }, + ], + }); + + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + newAuthority: { + type: 'Address', + address: updateDelegate2.publicKey, + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + edition: { + authority: { + type: 'Address', + address: updateDelegate2.publicKey, + }, + number: 1, + }, + }); + + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 1, + }, + }); +}); + +test('it can update a non-updateDelegate plugin as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const asset = await createAsset(umi, { + plugins: [ + { + type: 'Edition', + number: 1, + }, + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + number: 2, + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 2, + }, + }); +}); + +test('it cannot add updateDelegate plugin with additional delegate as additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const asset = await createAsset(umi); + + const result = addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot update the update authority of the asset as an updateDelegate additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + const result = update(umi, { + asset, + authority: updateDelegate, + newUpdateAuthority: updateAuthority('Address', [updateDelegate2.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot update the update authority of the asset as an updateDelegate root authority', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + authority: { type: 'Address', address: updateDelegate.publicKey }, + additionalDelegates: [], + }, + ], + }); + + const result = update(umi, { + asset, + authority: updateDelegate, + newUpdateAuthority: updateAuthority('Address', [updateDelegate2.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('an updateDelegate can add a plugin to an asset', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + }); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); +}); + +test('an updateDelegate can add a plugin to an asset using delegated owner', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Owner', + }, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + }); + + await addPlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); +}); + +test('an updateDelegate can remove a plugin from an asset', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); + + await removePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + }); +}); + +test('an updateDelegate can remove a plugin from an asset using delegated owner', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Owner', + }, + }, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); + + await removePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + }, + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + }); +}); + +test('it can approve/revoke the plugin authority of other plugins', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, + { + type: 'Edition', + number: 1, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 1, + }, + }); + + const editionAuthority = generateSigner(umi); + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + newAuthority: { + type: 'Address', + address: editionAuthority.publicKey, + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'Address', + address: editionAuthority.publicKey, + }, + number: 1, + }, + }); + + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 1, + }, + }); +}); + +test('it can approve/revoke the plugin authority of other plugins as delegated owner', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Owner', + }, + }, + { + type: 'Edition', + number: 1, + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 1, + }, + }); + + const editionAuthority = generateSigner(umi); + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + newAuthority: { + type: 'Address', + address: editionAuthority.publicKey, + }, + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'Address', + address: editionAuthority.publicKey, + }, + number: 1, + }, + }); + + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { + type: 'Edition', + }, + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + edition: { + authority: { + type: 'UpdateAuthority', + }, + number: 1, + }, + }); +}); + +test('it can update an asset as delegated owner', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Owner', + }, + }, + ], + name: 'short', + uri: 'https://short.com', + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + name: 'short', + uri: 'https://short.com', + }); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); +}); + +test('an updateDelegate can update a plugin on an asset', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + }, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + attributeList: [ + { + key: '789', + value: '012', + }, + ], + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '789', + value: '012', + }, + ], + }, + }); +}); + +test('an updateDelegate can update a plugin on an asset using delegated owner', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const updateAuthority = generateSigner(umi); + + const asset = await createAsset(umi, { + owner: owner.publicKey, + updateAuthority: updateAuthority.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Owner', + }, + }, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + ], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '123', + value: '456', + }, + ], + }, + }); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + type: 'Attributes', + attributeList: [ + { + key: '789', + value: '012', + }, + ], + }, + authority: owner, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuthority.publicKey }, + updateDelegate: { + authority: { + type: 'Owner', + }, + additionalDelegates: [], + }, + attributes: { + authority: { + type: 'UpdateAuthority', + }, + attributeList: [ + { + key: '789', + value: '012', + }, + ], + }, + }); +}); diff --git a/clients/js/test/plugins/collection/updateDelegate.test.ts b/clients/js/test/plugins/collection/updateDelegate.test.ts index a4044136..8c27330f 100644 --- a/clients/js/test/plugins/collection/updateDelegate.test.ts +++ b/clients/js/test/plugins/collection/updateDelegate.test.ts @@ -2,44 +2,49 @@ import { generateSigner } from '@metaplex-foundation/umi'; import test from 'ava'; import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; import { - PluginType, - addCollectionPluginV1, - approveCollectionPluginAuthorityV1, - createPlugin, - pluginAuthorityPair, - addressPluginAuthority, - updateV1, - updateCollectionPluginV1, - revokeCollectionPluginAuthorityV1, + addCollectionPlugin, + approveCollectionPluginAuthority, + approvePluginAuthority, + revokeCollectionPluginAuthority, + revokePluginAuthority, + update, + updateCollection, + updateCollectionPlugin, + updatePlugin, } from '../../../src'; import { DEFAULT_ASSET, DEFAULT_COLLECTION, assertAsset, assertCollection, - createAsset, - createCollection, createUmi, } from '../../_setupRaw'; +import { + createAsset, + createAssetWithCollection, + createCollection, +} from '../../_setupSdk'; test('it can create a new asset with a collection if it is the collection updateDelegate', async (t) => { - // Given a Umi instance and a new signer. const umi = await createUmi(); const updateDelegate = await generateSignerWithSol(umi); - // When we create a new account. const collection = await createCollection(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, ], }); - await approveCollectionPluginAuthorityV1(umi, { + await approveCollectionPluginAuthority(umi, { collection: collection.publicKey, - pluginType: PluginType.UpdateDelegate, - newAuthority: addressPluginAuthority(updateDelegate.publicKey), + plugin: { + type: 'UpdateDelegate', + }, + + newAuthority: { type: 'Address', address: updateDelegate.publicKey }, }).sendAndConfirm(umi); await assertCollection(t, umi, { @@ -58,7 +63,50 @@ test('it can create a new asset with a collection if it is the collection update umi.identity = updateDelegate; umi.payer = updateDelegate; const owner = generateSigner(umi); - // When we create a new account. + + const asset = await createAsset(umi, { + collection: collection.publicKey, + owner, + authority: updateDelegate, + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('it can create a new asset with a collection if it is a collection updateDelegate additionalDelegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = await generateSignerWithSol(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + }); + + umi.identity = updateDelegate; + umi.payer = updateDelegate; + const owner = generateSigner(umi); + const asset = await createAsset(umi, { collection: collection.publicKey, owner, @@ -74,22 +122,24 @@ test('it can create a new asset with a collection if it is the collection update }); test('it can add updateDelegate to collection and then approve', async (t) => { - // Given a Umi instance and a new signer. const umi = await createUmi(); const updateDelegate = generateSigner(umi); const collection = await createCollection(umi); - await addCollectionPluginV1(umi, { + await addCollectionPlugin(umi, { collection: collection.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, }).sendAndConfirm(umi); - await approveCollectionPluginAuthorityV1(umi, { + await approveCollectionPluginAuthority(umi, { collection: collection.publicKey, - pluginType: PluginType.UpdateDelegate, - newAuthority: addressPluginAuthority(updateDelegate.publicKey), + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { type: 'Address', address: updateDelegate.publicKey }, }).sendAndConfirm(umi); await assertCollection(t, umi, { @@ -106,52 +156,65 @@ test('it can add updateDelegate to collection and then approve', async (t) => { }); }); -test('it cannot create a collection with updateDelegate with additional delegates', async (t) => { +test('it can create a collection with updateDelegate with additional delegates', async (t) => { const umi = await createUmi(); + const updateDelegate = generateSigner(umi); - const result = createCollection(umi, { + const collection = await createCollection(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, ], }); - await t.throwsAsync(result, { name: 'NotAvailable' }); + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [updateDelegate.publicKey], + }, + }); }); -test('it cannot add updateDelegate to collection with additional delegates', async (t) => { +test('it can add updateDelegate to collection with additional delegates', async (t) => { const umi = await createUmi(); const collection = await createCollection(umi); + const updateDelegate = generateSigner(umi); - const result = addCollectionPluginV1(umi, { + await addCollectionPlugin(umi, { collection: collection.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, }).sendAndConfirm(umi); - await t.throwsAsync(result, { name: 'NotAvailable' }); - await assertCollection(t, umi, { ...DEFAULT_COLLECTION, collection: collection.publicKey, updateAuthority: umi.identity.publicKey, - updateDelegate: undefined, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [updateDelegate.publicKey], + }, }); }); -test('it cannot update updateDelegate on collection with additional delegates', async (t) => { +test('it can update updateDelegate on collection with additional delegates', async (t) => { const umi = await createUmi(); const collection = await createCollection(umi); + const updateDelegate = generateSigner(umi); - await addCollectionPluginV1(umi, { + await addCollectionPlugin(umi, { collection: collection.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, }).sendAndConfirm(umi); await assertCollection(t, umi, { @@ -166,16 +229,14 @@ test('it cannot update updateDelegate on collection with additional delegates', }, }); - const result = updateCollectionPluginV1(umi, { + await updateCollectionPlugin(umi, { collection: collection.publicKey, - plugin: createPlugin({ + plugin: { type: 'UpdateDelegate', - data: { additionalDelegates: [generateSigner(umi).publicKey] }, - }), + additionalDelegates: [updateDelegate.publicKey], + }, }).sendAndConfirm(umi); - await t.throwsAsync(result, { name: 'NotAvailable' }); - await assertCollection(t, umi, { ...DEFAULT_COLLECTION, collection: collection.publicKey, @@ -184,29 +245,30 @@ test('it cannot update updateDelegate on collection with additional delegates', authority: { type: 'UpdateAuthority', }, - additionalDelegates: [], + additionalDelegates: [updateDelegate.publicKey], }, }); }); -test('it updateDelegate on collection can update an asset', async (t) => { - // Given a Umi instance and a new signer. +test('an updateDelegate on collection can update an asset', async (t) => { const umi = await createUmi(); const updateDelegate = await generateSignerWithSol(umi); - // When we create a new account. const collection = await createCollection(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, ], }); - await approveCollectionPluginAuthorityV1(umi, { + await approveCollectionPluginAuthority(umi, { collection: collection.publicKey, - pluginType: PluginType.UpdateDelegate, - newAuthority: addressPluginAuthority(updateDelegate.publicKey), + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { type: 'Address', address: updateDelegate.publicKey }, }).sendAndConfirm(umi); await assertCollection(t, umi, { @@ -242,11 +304,74 @@ test('it updateDelegate on collection can update an asset', async (t) => { uri: 'https://short.com', }); - await updateV1(umi, { + await update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); +}); + +test('an updateDelegate additionalDelegate on collection can update an asset', async (t) => { + const umi = await createUmi(); + const updateDelegate = await generateSignerWithSol(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, collection: collection.publicKey, - newName: 'Test Bread 2', - newUri: 'https://example.com/bread2', + updateAuthority: umi.identity.publicKey, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + }); + + umi.identity = updateDelegate; + umi.payer = updateDelegate; + const owner = generateSigner(umi); + const asset = await createAsset(umi, { + collection: collection.publicKey, + owner, + authority: updateDelegate, + name: 'short', + uri: 'https://short.com', + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + name: 'short', + uri: 'https://short.com', + }); + + await update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', authority: updateDelegate, }).sendAndConfirm(umi); @@ -260,24 +385,25 @@ test('it updateDelegate on collection can update an asset', async (t) => { }); }); -test('it updateDelegate on collection cannot update an asset after delegate authority revoked', async (t) => { - // Given a Umi instance and a new signer. +test('an updateDelegate on collection cannot update an asset after delegate authority revoked', async (t) => { const umi = await createUmi(); const updateDelegate = await generateSignerWithSol(umi); - // When we create a new account. const collection = await createCollection(umi, { plugins: [ - pluginAuthorityPair({ + { type: 'UpdateDelegate', - }), + additionalDelegates: [], + }, ], }); - await approveCollectionPluginAuthorityV1(umi, { + await approveCollectionPluginAuthority(umi, { collection: collection.publicKey, - pluginType: PluginType.UpdateDelegate, - newAuthority: addressPluginAuthority(updateDelegate.publicKey), + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { type: 'Address', address: updateDelegate.publicKey }, }).sendAndConfirm(umi); await assertCollection(t, umi, { @@ -313,16 +439,93 @@ test('it updateDelegate on collection cannot update an asset after delegate auth uri: 'https://short.com', }); - await revokeCollectionPluginAuthorityV1(umi, { + await revokeCollectionPluginAuthority(umi, { collection: collection.publicKey, - pluginType: PluginType.UpdateDelegate, + plugin: { + type: 'UpdateDelegate', + }, + }).sendAndConfirm(umi); + + const result = update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: updateDelegate, }).sendAndConfirm(umi); - let result = updateV1(umi, { + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + name: 'short', + uri: 'https://short.com', + }); +}); + +test('an updateDelegate additionalDelegate on collection cannot update an asset after delegate authority revoked', async (t) => { + const umi = await createUmi(); + const { identity } = umi; + const updateDelegate = await generateSignerWithSol(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [updateDelegate.publicKey], + }, + }); + + umi.identity = updateDelegate; + umi.payer = updateDelegate; + const owner = generateSigner(umi); + const asset = await createAsset(umi, { + collection: collection.publicKey, + owner, + authority: updateDelegate, + name: 'short', + uri: 'https://short.com', + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + name: 'short', + uri: 'https://short.com', + }); + + await updateCollectionPlugin(umi, { collection: collection.publicKey, - newName: 'Test Bread 2', - newUri: 'https://example.com/bread2', + authority: identity, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + }).sendAndConfirm(umi); + + const result = update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', authority: updateDelegate, }).sendAndConfirm(umi); @@ -337,3 +540,191 @@ test('it updateDelegate on collection cannot update an asset after delegate auth uri: 'https://short.com', }); }); + +test('it can update a non-updateDelegate plugin on an asset as collection update additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = await generateSignerWithSol(umi); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + plugins: [ + { + type: 'Edition', + number: 1, + }, + ], + }, + { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + } + ); + + await updatePlugin(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: { + type: 'Edition', + number: 2, + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + edition: { + authority: { type: 'UpdateAuthority' }, + number: 2, + }, + }); +}); + +test('it can approve/revoke non-updateDelegate plugin on an asset as collection update additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = await generateSignerWithSol(umi); + const updateDelegate2 = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + plugins: [ + { + type: 'Edition', + number: 1, + }, + ], + }, + { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + } + ); + + await approvePluginAuthority(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: { + type: 'Edition', + }, + newAuthority: { type: 'Address', address: updateDelegate2.publicKey }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + edition: { + authority: { type: 'Address', address: updateDelegate2.publicKey }, + number: 1, + }, + }); + + await revokePluginAuthority(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + plugin: { + type: 'Edition', + }, + authority: updateDelegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + edition: { + authority: { type: 'UpdateAuthority' }, + number: 1, + }, + }); +}); + +test('it cannot update the update authority of the collection as an updateDelegate additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + const result = updateCollection(umi, { + collection: collection.publicKey, + authority: updateDelegate, + newUpdateAuthority: updateDelegate2.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('it cannot update the update authority of the collection as an updateDelegate root authority', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + const updateDelegate2 = generateSigner(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + authority: { type: 'Address', address: updateDelegate.publicKey }, + additionalDelegates: [], + }, + ], + }); + + const result = updateCollection(umi, { + collection: collection.publicKey, + authority: updateDelegate, + newUpdateAuthority: updateDelegate2.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('it can update collection details as an updateDelegate additional delegate', async (t) => { + const umi = await createUmi(); + const updateDelegate = generateSigner(umi); + + const collection = await createCollection(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [updateDelegate.publicKey], + }, + ], + }); + + await updateCollection(umi, { + collection: collection.publicKey, + authority: updateDelegate, + name: 'new name', + uri: 'new uri', + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + name: 'new name', + uri: 'new uri', + }); +}); diff --git a/clients/js/test/sdkv1.test.ts b/clients/js/test/sdkv1.test.ts index 33764222..b9c50e19 100644 --- a/clients/js/test/sdkv1.test.ts +++ b/clients/js/test/sdkv1.test.ts @@ -16,6 +16,7 @@ import { CollectionAddablePluginAuthorityPairArgsV2, addCollectionPlugin, removeCollectionPlugin, + ExternalPluginAdapterSchema, } from '../src'; import { createAsset, @@ -1031,3 +1032,80 @@ test('it can burn asset in collection', async (t) => { t.is(afterAsset.data.length, 1); t.is(afterAsset.data[0], Key.Uninitialized); }); + +test('it can fetch asset which correctly derived plugins', async (t) => { + const umi = await createUmi(); + const dataAuth = generateSigner(umi); + const { asset, collection } = await createAssetWithCollection( + umi, + { + plugins: [ + { + type: 'Edition', + number: 1, + }, + { + type: 'PermanentFreezeDelegate', + frozen: false, + }, + ], + }, + { + plugins: [ + { + type: 'LinkedAppData', + dataAuthority: { + type: 'Address', + address: dataAuth.publicKey, + }, + schema: ExternalPluginAdapterSchema.Json, + }, + { + type: 'PermanentFreezeDelegate', + frozen: true, + }, + ], + } + ); + + await assertAsset( + t, + umi, + { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: collection.publicKey, + }, + edition: { + number: 1, + authority: { + type: 'UpdateAuthority', + }, + }, + permanentFreezeDelegate: { + frozen: false, + authority: { + type: 'UpdateAuthority', + }, + }, + linkedAppDatas: [ + { + type: 'LinkedAppData', + authority: { + type: 'UpdateAuthority', + }, + dataAuthority: { + type: 'Address', + address: dataAuth.publicKey, + }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }, + { + derivePlugins: true, + } + ); +}); diff --git a/clients/js/test/update.test.ts b/clients/js/test/update.test.ts index 506d823b..d773f4b8 100644 --- a/clients/js/test/update.test.ts +++ b/clients/js/test/update.test.ts @@ -181,7 +181,7 @@ test('it can update an asset update authority', async (t) => { }); }); -test('it cannot update an asset update authority to be part of a collection (right now)', async (t) => { +test('it cannot update an asset update authority to be part of a collection using updateV1', async (t) => { // Given a Umi instance and a new signer. const umi = await createUmi(); const asset = await createAsset(umi); @@ -199,7 +199,7 @@ test('it cannot update an asset update authority to be part of a collection (rig await t.throwsAsync(result, { name: 'NotAvailable' }); }); -test('it cannot remove an asset from a collection (right now)', async (t) => { +test('it cannot remove an asset from a collection using updateV1', async (t) => { // Given a Umi instance and a new signer. const umi = await createUmi(); const { asset, collection } = await createAssetWithCollection(umi, {}, {}); diff --git a/clients/js/test/updateV2.test.ts b/clients/js/test/updateV2.test.ts new file mode 100644 index 00000000..c22a267c --- /dev/null +++ b/clients/js/test/updateV2.test.ts @@ -0,0 +1,1217 @@ +import test from 'ava'; + +import { generateSigner } from '@metaplex-foundation/umi'; +import { + update, + updateAuthority, + updateCollection, + addCollectionPlugin, + approveCollectionPluginAuthority, +} from '../src'; +import { + assertAsset, + assertCollection, + createUmi, + DEFAULT_ASSET, + DEFAULT_COLLECTION, +} from './_setupRaw'; + +import { + createAsset, + createAssetWithCollection, + createCollection, +} from './_setupSdk'; + +test('it can update an asset to be larger', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); +}); + +test('it cannot update an asset using asset as authority', async (t) => { + const umi = await createUmi(); + const myAsset = generateSigner(umi); + + const asset = await createAsset(umi, { + asset: myAsset, + name: 'short', + uri: 'https://short.com', + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + authority: myAsset, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: 'short', + uri: 'https://short.com', + }); +}); + +test('it can update an asset to be smaller', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi); + + await update(umi, { + asset, + name: '', + uri: '', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: '', + uri: '', + }); +}); + +test('it can update an asset with plugins to be larger', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi, { + name: 'short', + uri: 'https://short.com', + plugins: [ + { + type: 'FreezeDelegate', + frozen: false, + }, + ], + }); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + freezeDelegate: { + authority: { + type: 'Owner', + }, + frozen: false, + }, + }); +}); + +test('it can update an asset with plugins to be smaller', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi, { + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + plugins: [ + { + type: 'FreezeDelegate', + frozen: false, + }, + ], + }); + + await update(umi, { + asset, + name: '', + uri: '', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: '', + uri: '', + freezeDelegate: { + authority: { + type: 'Owner', + }, + frozen: false, + }, + }); +}); + +test('it can update an asset update authority', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi); + const newUpdateAuthority = generateSigner(umi); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [ + newUpdateAuthority.publicKey, + ]), + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: newUpdateAuthority.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); +}); + +test('it cannot update an asset using wrong authority', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const updateAuth = generateSigner(umi); + const asset = await createAsset(umi, { + updateAuthority: updateAuth, + }); + + const newUpdateAuthority = generateSigner(umi); + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [ + newUpdateAuthority.publicKey, + ]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + }); +}); + +test('it cannot use an invalid system program for assets', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi); + const fakeSystemProgram = generateSigner(umi); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + systemProgram: fakeSystemProgram.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidSystemProgram' }); +}); + +test('it cannot use an invalid noop program for assets', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const asset = await createAsset(umi); + const fakeLogWrapper = generateSigner(umi); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + logWrapper: fakeLogWrapper.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidLogWrapperProgram' }); +}); + +test('it cannot use an invalid system program for collections', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const collection = await createCollection(umi); + const fakeSystemProgram = generateSigner(umi); + + const result = updateCollection(umi, { + collection: collection.publicKey, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + systemProgram: fakeSystemProgram.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidSystemProgram' }); +}); + +test('it cannot use an invalid noop program for collections', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const collection = await createCollection(umi); + const fakeLogWrapper = generateSigner(umi); + + const result = updateCollection(umi, { + collection: collection.publicKey, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + logWrapper: fakeLogWrapper.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidLogWrapperProgram' }); +}); + +test('it can remove an asset from a collection using update', async (t) => { + const umi = await createUmi(); + const { asset, collection } = await createAssetWithCollection(umi, {}, {}); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 1, + numMinted: 1, + }); + + await update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 1, + }); +}); + +test('it cannot remove an asset from a collection if not collection update auth', async (t) => { + const umi = await createUmi(); + const collectionAuthority = generateSigner(umi); + const { asset, collection } = await createAssetWithCollection( + umi, + { authority: collectionAuthority }, + { updateAuthority: collectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const result = update(umi, { + asset, + collection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); +}); + +test('it cannot remove an asset from a collection when missing collection account', async (t) => { + const umi = await createUmi(); + const { asset, collection } = await createAssetWithCollection(umi, {}, {}); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'MissingCollection' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 1, + numMinted: 1, + }); +}); + +test('it cannot remove an asset from a collection when using incorrect collection account', async (t) => { + const umi = await createUmi(); + const { asset, collection } = await createAssetWithCollection(umi, {}, {}); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + const randomCollection = await createCollection(umi); + + const result = update(umi, { + asset, + collection: randomCollection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); +}); + +test('it can add asset to collection using update', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + const collection = await createCollection(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + }); + + await update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: collection.publicKey, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 1, + numMinted: 0, + }); +}); + +test('it cannot add asset to collection when missing collection account', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + const collection = await createCollection(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'MissingCollection' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + }); +}); + +test('it cannot add asset to collection when using incorrect collection account', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + const collection = await createCollection(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: generateSigner(umi).publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); +}); + +test('it cannot add asset to collection using only new collection authority', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + const newCollectionAuthority = generateSigner(umi); + const collection = await createCollection(umi, { + updateAuthority: newCollectionAuthority, + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + const result = update(umi, { + asset, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: collection.publicKey, + authority: newCollectionAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot add asset to collection if not both asset and collection auth', async (t) => { + const umi = await createUmi(); + + const assetAuthority = generateSigner(umi); + const asset = await createAsset(umi, { updateAuthority: assetAuthority }); + + const collectionAuthority = generateSigner(umi); + const collection = await createCollection(umi, { + updateAuthority: collectionAuthority, + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: assetAuthority.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + // Attempt to update using asset authority. + const result = update(umi, { + asset, + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: collection.publicKey, + authority: assetAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: assetAuthority.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + // Attempt to update using collection authority. + const result2 = update(umi, { + asset, + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: collection.publicKey, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result2, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: assetAuthority.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); +}); + +test('it can change an asset collection using same update authority', async (t) => { + const umi = await createUmi(); + const collectionAuthority = generateSigner(umi); + const { asset, collection: originalCollection } = + await createAssetWithCollection( + umi, + { authority: collectionAuthority }, + { updateAuthority: collectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: originalCollection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const newCollection = await createCollection(umi, { + updateAuthority: collectionAuthority, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + await update(umi, { + asset, + collection: originalCollection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [ + newCollection.publicKey, + ]), + newCollection: newCollection.publicKey, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: newCollection.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: originalCollection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 1, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 0, + }); +}); + +test('it cannot change an asset collection if not both asset and collection auth', async (t) => { + const umi = await createUmi(); + const originalCollectionAuthority = generateSigner(umi); + const { asset, collection: originalCollection } = + await createAssetWithCollection( + umi, + { authority: originalCollectionAuthority }, + { updateAuthority: originalCollectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: originalCollection.publicKey, + updateAuthority: originalCollectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const newCollectionAuthority = generateSigner(umi); + const newCollection = await createCollection(umi, { + updateAuthority: newCollectionAuthority, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateAuthority: newCollectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + // Attempt to update using original collection authority. + const result = update(umi, { + asset, + collection: originalCollection, + newUpdateAuthority: updateAuthority('Collection', [ + newCollection.publicKey, + ]), + newCollection: newCollection.publicKey, + authority: originalCollectionAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: originalCollection.publicKey, + updateAuthority: originalCollectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateAuthority: newCollectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + // Attempt to update using new collection authority. + const result2 = update(umi, { + asset, + collection: originalCollection, + newUpdateAuthority: updateAuthority('Collection', [ + newCollection.publicKey, + ]), + newCollection: newCollection.publicKey, + authority: newCollectionAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result2, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: originalCollection.publicKey, + updateAuthority: originalCollectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateAuthority: newCollectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); +}); + +test('it can change an asset collection using delegate', async (t) => { + const umi = await createUmi(); + const originalCollectionAuthority = generateSigner(umi); + const { asset, collection: originalCollection } = + await createAssetWithCollection( + umi, + { authority: originalCollectionAuthority }, + { updateAuthority: originalCollectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + const newCollectionAuthority = generateSigner(umi); + const newCollection = await createCollection(umi, { + updateAuthority: newCollectionAuthority, + }); + + await addCollectionPlugin(umi, { + collection: newCollection.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + authority: newCollectionAuthority, + }).sendAndConfirm(umi); + + await approveCollectionPluginAuthority(umi, { + collection: newCollection.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { + type: 'Address', + address: originalCollectionAuthority.publicKey, + }, + authority: newCollectionAuthority, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateDelegate: { + authority: { + type: 'Address', + address: originalCollectionAuthority.publicKey, + }, + additionalDelegates: [], + }, + updateAuthority: newCollectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + await update(umi, { + asset, + collection: originalCollection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [ + newCollection.publicKey, + ]), + newCollection: newCollection.publicKey, + authority: originalCollectionAuthority, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: newCollection.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateDelegate: { + authority: { + type: 'Address', + address: originalCollectionAuthority.publicKey, + }, + additionalDelegates: [], + }, + updateAuthority: newCollectionAuthority.publicKey, + currentSize: 1, + numMinted: 0, + }); +}); + +test('it can change an asset collection using same update authority (delegate exists but not used)', async (t) => { + const umi = await createUmi(); + const collectionAuthority = generateSigner(umi); + const { asset, collection: originalCollection } = + await createAssetWithCollection( + umi, + { authority: collectionAuthority }, + { updateAuthority: collectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: originalCollection.publicKey, + }, + }); + + const newCollection = await createCollection(umi, { + updateAuthority: collectionAuthority, + }); + + await addCollectionPlugin(umi, { + collection: newCollection.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + const updateDelegate = generateSigner(umi); + await approveCollectionPluginAuthority(umi, { + collection: newCollection.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + await update(umi, { + asset, + collection: originalCollection, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + newUpdateAuthority: updateAuthority('Collection', [ + newCollection.publicKey, + ]), + newCollection: newCollection.publicKey, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: newCollection.publicKey }, + name: 'Test Bread 2', + uri: 'https://example.com/bread2', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: newCollection.publicKey, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 0, + }); +}); + +test('it cannot remove an asset from collection using update delegate', async (t) => { + const umi = await createUmi(); + const collectionAuthority = generateSigner(umi); + const { asset, collection } = await createAssetWithCollection( + umi, + { authority: collectionAuthority }, + { updateAuthority: collectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + await addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + const updateDelegate = generateSigner(umi); + await approveCollectionPluginAuthority(umi, { + collection: collection.publicKey, + plugin: { + type: 'UpdateDelegate', + }, + newAuthority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegate.publicKey, + }, + additionalDelegates: [], + }, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const result = update(umi, { + asset, + collection, + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + authority: updateDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot remove an asset from collection using additional update delegate', async (t) => { + const umi = await createUmi(); + const collectionAuthority = generateSigner(umi); + const { asset, collection } = await createAssetWithCollection( + umi, + { authority: collectionAuthority }, + { updateAuthority: collectionAuthority } + ); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); + + const additionalDelegate = generateSigner(umi); + await addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [additionalDelegate.publicKey], + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [additionalDelegate.publicKey], + }, + updateAuthority: collectionAuthority.publicKey, + currentSize: 1, + numMinted: 1, + }); + + const result = update(umi, { + asset, + collection, + newUpdateAuthority: updateAuthority('Address', [umi.identity.publicKey]), + authority: additionalDelegate, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +test('it cannot add asset to collection using additional update delegate on new collection', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + const collectionAuthority = generateSigner(umi); + const collection = await createCollection(umi, { + updateAuthority: collectionAuthority, + }); + + await addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'UpdateDelegate', + additionalDelegates: [umi.identity.publicKey], + }, + authority: collectionAuthority, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [umi.identity.publicKey], + }, + updateAuthority: collectionAuthority.publicKey, + currentSize: 0, + numMinted: 0, + }); + + const result = update(umi, { + asset, + newUpdateAuthority: updateAuthority('Collection', [collection.publicKey]), + newCollection: collection.publicKey, + authority: umi.identity, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); diff --git a/clients/rust/Cargo.toml b/clients/rust/Cargo.toml index 9333750d..139206ec 100644 --- a/clients/rust/Cargo.toml +++ b/clients/rust/Cargo.toml @@ -2,7 +2,7 @@ name = "mpl-core" description = "A flexible digital asset standard for Solana" repository = "https://github.com/metaplex-foundation/mpl-core" -version = "0.7.2" +version = "0.8.0-beta.1" edition = "2021" readme = "README.md" license-file = "../../LICENSE" diff --git a/clients/rust/src/generated/errors/mpl_core.rs b/clients/rust/src/generated/errors/mpl_core.rs index 232dd7f1..93e72b13 100644 --- a/clients/rust/src/generated/errors/mpl_core.rs +++ b/clients/rust/src/generated/errors/mpl_core.rs @@ -103,11 +103,11 @@ pub enum MplCoreError { /// 30 (0x1E) - Invalid Log Wrapper Program #[error("Invalid Log Wrapper Program")] InvalidLogWrapperProgram, - /// 31 (0x1F) - External PluginExternalPluginAdapter not found - #[error("External PluginExternalPluginAdapter not found")] + /// 31 (0x1F) - External Plugin Adapter not found + #[error("External Plugin Adapter not found")] ExternalPluginAdapterNotFound, - /// 32 (0x20) - External PluginExternalPluginAdapter already exists - #[error("External PluginExternalPluginAdapter already exists")] + /// 32 (0x20) - External Plugin Adapter already exists + #[error("External Plugin Adapter already exists")] ExternalPluginAdapterAlreadyExists, /// 33 (0x21) - Missing asset needed for extra account PDA derivation #[error("Missing asset needed for extra account PDA derivation")] @@ -139,6 +139,21 @@ pub enum MplCoreError { /// 42 (0x2A) - Collection must be empty to be burned #[error("Collection must be empty to be burned")] CollectionMustBeEmpty, + /// 43 (0x2B) - Two data sources provided, only one is allowed + #[error("Two data sources provided, only one is allowed")] + TwoDataSources, + /// 44 (0x2C) - External Plugin does not support this operation + #[error("External Plugin does not support this operation")] + UnsupportedOperation, + /// 45 (0x2D) - No data sources provided, one is required + #[error("No data sources provided, one is required")] + NoDataSources, + /// 46 (0x2E) - This plugin adapter cannot be added to an Asset + #[error("This plugin adapter cannot be added to an Asset")] + InvalidPluginAdapterTarget, + /// 47 (0x2F) - Cannot add a Data Section without a linked external plugin + #[error("Cannot add a Data Section without a linked external plugin")] + CannotAddDataSection, } impl solana_program::program_error::PrintProgramError for MplCoreError { diff --git a/clients/rust/src/generated/instructions/mod.rs b/clients/rust/src/generated/instructions/mod.rs index 116673db..b42e06ac 100644 --- a/clients/rust/src/generated/instructions/mod.rs +++ b/clients/rust/src/generated/instructions/mod.rs @@ -33,6 +33,7 @@ pub(crate) mod r#update_collection_v1; pub(crate) mod r#update_external_plugin_adapter_v1; pub(crate) mod r#update_plugin_v1; pub(crate) mod r#update_v1; +pub(crate) mod r#update_v2; pub(crate) mod r#write_collection_external_plugin_adapter_data_v1; pub(crate) mod r#write_external_plugin_adapter_data_v1; @@ -64,5 +65,6 @@ pub use self::r#update_collection_v1::*; pub use self::r#update_external_plugin_adapter_v1::*; pub use self::r#update_plugin_v1::*; pub use self::r#update_v1::*; +pub use self::r#update_v2::*; pub use self::r#write_collection_external_plugin_adapter_data_v1::*; pub use self::r#write_external_plugin_adapter_data_v1::*; diff --git a/clients/rust/src/generated/instructions/update_v2.rs b/clients/rust/src/generated/instructions/update_v2.rs new file mode 100644 index 00000000..925e4a7b --- /dev/null +++ b/clients/rust/src/generated/instructions/update_v2.rs @@ -0,0 +1,672 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::UpdateAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct UpdateV2 { + /// The address of the asset + pub asset: solana_program::pubkey::Pubkey, + /// The collection to which the asset belongs + pub collection: Option, + /// The account paying for the storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The update authority or update authority delegate of the asset + pub authority: Option, + /// A new collection to which to move the asset + pub new_collection: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, + /// The SPL Noop Program + pub log_wrapper: Option, +} + +impl UpdateV2 { + pub fn instruction( + &self, + args: UpdateV2InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: UpdateV2InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.asset, false, + )); + if let Some(collection) = self.collection { + accounts.push(solana_program::instruction::AccountMeta::new( + collection, false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + if let Some(new_collection) = self.new_collection { + accounts.push(solana_program::instruction::AccountMeta::new( + new_collection, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + if let Some(log_wrapper) = self.log_wrapper { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + log_wrapper, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let mut data = UpdateV2InstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct UpdateV2InstructionData { + discriminator: u8, +} + +impl UpdateV2InstructionData { + pub fn new() -> Self { + Self { discriminator: 30 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UpdateV2InstructionArgs { + pub new_name: Option, + pub new_uri: Option, + pub new_update_authority: Option, +} + +/// Instruction builder for `UpdateV2`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` asset +/// 1. `[writable, optional]` collection +/// 2. `[writable, signer]` payer +/// 3. `[signer, optional]` authority +/// 4. `[writable, optional]` new_collection +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 6. `[optional]` log_wrapper +#[derive(Default)] +pub struct UpdateV2Builder { + asset: Option, + collection: Option, + payer: Option, + authority: Option, + new_collection: Option, + system_program: Option, + log_wrapper: Option, + new_name: Option, + new_uri: Option, + new_update_authority: Option, + __remaining_accounts: Vec, +} + +impl UpdateV2Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the asset + #[inline(always)] + pub fn asset(&mut self, asset: solana_program::pubkey::Pubkey) -> &mut Self { + self.asset = Some(asset); + self + } + /// `[optional account]` + /// The collection to which the asset belongs + #[inline(always)] + pub fn collection(&mut self, collection: Option) -> &mut Self { + self.collection = collection; + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority or update authority delegate of the asset + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account]` + /// A new collection to which to move the asset + #[inline(always)] + pub fn new_collection( + &mut self, + new_collection: Option, + ) -> &mut Self { + self.new_collection = new_collection; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional account]` + /// The SPL Noop Program + #[inline(always)] + pub fn log_wrapper( + &mut self, + log_wrapper: Option, + ) -> &mut Self { + self.log_wrapper = log_wrapper; + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_name(&mut self, new_name: String) -> &mut Self { + self.new_name = Some(new_name); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_uri(&mut self, new_uri: String) -> &mut Self { + self.new_uri = Some(new_uri); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_update_authority(&mut self, new_update_authority: UpdateAuthority) -> &mut Self { + self.new_update_authority = Some(new_update_authority); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = UpdateV2 { + asset: self.asset.expect("asset is not set"), + collection: self.collection, + payer: self.payer.expect("payer is not set"), + authority: self.authority, + new_collection: self.new_collection, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + log_wrapper: self.log_wrapper, + }; + let args = UpdateV2InstructionArgs { + new_name: self.new_name.clone(), + new_uri: self.new_uri.clone(), + new_update_authority: self.new_update_authority.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_v2` CPI accounts. +pub struct UpdateV2CpiAccounts<'a, 'b> { + /// The address of the asset + pub asset: &'b solana_program::account_info::AccountInfo<'a>, + /// The collection to which the asset belongs + pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority or update authority delegate of the asset + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// A new collection to which to move the asset + pub new_collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The SPL Noop Program + pub log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, +} + +/// `update_v2` CPI instruction. +pub struct UpdateV2Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the asset + pub asset: &'b solana_program::account_info::AccountInfo<'a>, + /// The collection to which the asset belongs + pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority or update authority delegate of the asset + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// A new collection to which to move the asset + pub new_collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The SPL Noop Program + pub log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The arguments for the instruction. + pub __args: UpdateV2InstructionArgs, +} + +impl<'a, 'b> UpdateV2Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: UpdateV2CpiAccounts<'a, 'b>, + args: UpdateV2InstructionArgs, + ) -> Self { + Self { + __program: program, + asset: accounts.asset, + collection: accounts.collection, + payer: accounts.payer, + authority: accounts.authority, + new_collection: accounts.new_collection, + system_program: accounts.system_program, + log_wrapper: accounts.log_wrapper, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.asset.key, + false, + )); + if let Some(collection) = self.collection { + accounts.push(solana_program::instruction::AccountMeta::new( + *collection.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + if let Some(new_collection) = self.new_collection { + accounts.push(solana_program::instruction::AccountMeta::new( + *new_collection.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + if let Some(log_wrapper) = self.log_wrapper { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *log_wrapper.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = UpdateV2InstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(7 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.asset.clone()); + if let Some(collection) = self.collection { + account_infos.push(collection.clone()); + } + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + if let Some(new_collection) = self.new_collection { + account_infos.push(new_collection.clone()); + } + account_infos.push(self.system_program.clone()); + if let Some(log_wrapper) = self.log_wrapper { + account_infos.push(log_wrapper.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `UpdateV2` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` asset +/// 1. `[writable, optional]` collection +/// 2. `[writable, signer]` payer +/// 3. `[signer, optional]` authority +/// 4. `[writable, optional]` new_collection +/// 5. `[]` system_program +/// 6. `[optional]` log_wrapper +pub struct UpdateV2CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateV2CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(UpdateV2CpiBuilderInstruction { + __program: program, + asset: None, + collection: None, + payer: None, + authority: None, + new_collection: None, + system_program: None, + log_wrapper: None, + new_name: None, + new_uri: None, + new_update_authority: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the asset + #[inline(always)] + pub fn asset(&mut self, asset: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.asset = Some(asset); + self + } + /// `[optional account]` + /// The collection to which the asset belongs + #[inline(always)] + pub fn collection( + &mut self, + collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.collection = collection; + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority or update authority delegate of the asset + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// `[optional account]` + /// A new collection to which to move the asset + #[inline(always)] + pub fn new_collection( + &mut self, + new_collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.new_collection = new_collection; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// `[optional account]` + /// The SPL Noop Program + #[inline(always)] + pub fn log_wrapper( + &mut self, + log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.log_wrapper = log_wrapper; + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_name(&mut self, new_name: String) -> &mut Self { + self.instruction.new_name = Some(new_name); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_uri(&mut self, new_uri: String) -> &mut Self { + self.instruction.new_uri = Some(new_uri); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_update_authority(&mut self, new_update_authority: UpdateAuthority) -> &mut Self { + self.instruction.new_update_authority = Some(new_update_authority); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = UpdateV2InstructionArgs { + new_name: self.instruction.new_name.clone(), + new_uri: self.instruction.new_uri.clone(), + new_update_authority: self.instruction.new_update_authority.clone(), + }; + let instruction = UpdateV2Cpi { + __program: self.instruction.__program, + + asset: self.instruction.asset.expect("asset is not set"), + + collection: self.instruction.collection, + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + new_collection: self.instruction.new_collection, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + + log_wrapper: self.instruction.log_wrapper, + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct UpdateV2CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + asset: Option<&'b solana_program::account_info::AccountInfo<'a>>, + collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + new_collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, + new_name: Option, + new_uri: Option, + new_update_authority: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs b/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs index 16bf3b74..9f4e9692 100644 --- a/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs +++ b/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs @@ -17,8 +17,10 @@ pub struct WriteCollectionExternalPluginAdapterDataV1 { pub collection: solana_program::pubkey::Pubkey, /// The account paying for the storage fees pub payer: solana_program::pubkey::Pubkey, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option, + /// The buffer to write to the external plugin + pub buffer: Option, /// The system program pub system_program: solana_program::pubkey::Pubkey, /// The SPL Noop Program @@ -38,7 +40,7 @@ impl WriteCollectionExternalPluginAdapterDataV1 { args: WriteCollectionExternalPluginAdapterDataV1InstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { - let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new( self.collection, false, @@ -56,6 +58,16 @@ impl WriteCollectionExternalPluginAdapterDataV1 { false, )); } + if let Some(buffer) = self.buffer { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + buffer, false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.system_program, false, @@ -104,7 +116,7 @@ impl WriteCollectionExternalPluginAdapterDataV1InstructionData { #[derive(Clone, Debug, Eq, PartialEq)] pub struct WriteCollectionExternalPluginAdapterDataV1InstructionArgs { pub key: ExternalPluginAdapterKey, - pub data: Vec, + pub data: Option>, } /// Instruction builder for `WriteCollectionExternalPluginAdapterDataV1`. @@ -114,13 +126,15 @@ pub struct WriteCollectionExternalPluginAdapterDataV1InstructionArgs { /// 0. `[writable]` collection /// 1. `[writable, signer]` payer /// 2. `[signer, optional]` authority -/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) -/// 4. `[optional]` log_wrapper +/// 3. `[optional]` buffer +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 5. `[optional]` log_wrapper #[derive(Default)] pub struct WriteCollectionExternalPluginAdapterDataV1Builder { collection: Option, payer: Option, authority: Option, + buffer: Option, system_program: Option, log_wrapper: Option, key: Option, @@ -145,12 +159,19 @@ impl WriteCollectionExternalPluginAdapterDataV1Builder { self } /// `[optional account]` - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter #[inline(always)] pub fn authority(&mut self, authority: Option) -> &mut Self { self.authority = authority; self } + /// `[optional account]` + /// The buffer to write to the external plugin + #[inline(always)] + pub fn buffer(&mut self, buffer: Option) -> &mut Self { + self.buffer = buffer; + self + } /// `[optional account, default to '11111111111111111111111111111111']` /// The system program #[inline(always)] @@ -173,6 +194,7 @@ impl WriteCollectionExternalPluginAdapterDataV1Builder { self.key = Some(key); self } + /// `[optional argument]` #[inline(always)] pub fn data(&mut self, data: Vec) -> &mut Self { self.data = Some(data); @@ -202,6 +224,7 @@ impl WriteCollectionExternalPluginAdapterDataV1Builder { collection: self.collection.expect("collection is not set"), payer: self.payer.expect("payer is not set"), authority: self.authority, + buffer: self.buffer, system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -209,7 +232,7 @@ impl WriteCollectionExternalPluginAdapterDataV1Builder { }; let args = WriteCollectionExternalPluginAdapterDataV1InstructionArgs { key: self.key.clone().expect("key is not set"), - data: self.data.clone().expect("data is not set"), + data: self.data.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -222,8 +245,10 @@ pub struct WriteCollectionExternalPluginAdapterDataV1CpiAccounts<'a, 'b> { pub collection: &'b solana_program::account_info::AccountInfo<'a>, /// The account paying for the storage fees pub payer: &'b solana_program::account_info::AccountInfo<'a>, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The buffer to write to the external plugin + pub buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The SPL Noop Program @@ -238,8 +263,10 @@ pub struct WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { pub collection: &'b solana_program::account_info::AccountInfo<'a>, /// The account paying for the storage fees pub payer: &'b solana_program::account_info::AccountInfo<'a>, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The buffer to write to the external plugin + pub buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The SPL Noop Program @@ -259,6 +286,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { collection: accounts.collection, payer: accounts.payer, authority: accounts.authority, + buffer: accounts.buffer, system_program: accounts.system_program, log_wrapper: accounts.log_wrapper, __args: args, @@ -297,7 +325,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { bool, )], ) -> solana_program::entrypoint::ProgramResult { - let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new( *self.collection.key, false, @@ -317,6 +345,17 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { false, )); } + if let Some(buffer) = self.buffer { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *buffer.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.system_program.key, false, @@ -350,13 +389,16 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { accounts, data, }; - let mut account_infos = Vec::with_capacity(5 + 1 + remaining_accounts.len()); + let mut account_infos = Vec::with_capacity(6 + 1 + remaining_accounts.len()); account_infos.push(self.__program.clone()); account_infos.push(self.collection.clone()); account_infos.push(self.payer.clone()); if let Some(authority) = self.authority { account_infos.push(authority.clone()); } + if let Some(buffer) = self.buffer { + account_infos.push(buffer.clone()); + } account_infos.push(self.system_program.clone()); if let Some(log_wrapper) = self.log_wrapper { account_infos.push(log_wrapper.clone()); @@ -380,8 +422,9 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { /// 0. `[writable]` collection /// 1. `[writable, signer]` payer /// 2. `[signer, optional]` authority -/// 3. `[]` system_program -/// 4. `[optional]` log_wrapper +/// 3. `[optional]` buffer +/// 4. `[]` system_program +/// 5. `[optional]` log_wrapper pub struct WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { instruction: Box>, } @@ -394,6 +437,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { collection: None, payer: None, authority: None, + buffer: None, system_program: None, log_wrapper: None, key: None, @@ -419,7 +463,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self } /// `[optional account]` - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter #[inline(always)] pub fn authority( &mut self, @@ -428,6 +472,16 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self.instruction.authority = authority; self } + /// `[optional account]` + /// The buffer to write to the external plugin + #[inline(always)] + pub fn buffer( + &mut self, + buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.buffer = buffer; + self + } /// The system program #[inline(always)] pub fn system_program( @@ -452,6 +506,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self.instruction.key = Some(key); self } + /// `[optional argument]` #[inline(always)] pub fn data(&mut self, data: Vec) -> &mut Self { self.instruction.data = Some(data); @@ -500,7 +555,7 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { ) -> solana_program::entrypoint::ProgramResult { let args = WriteCollectionExternalPluginAdapterDataV1InstructionArgs { key: self.instruction.key.clone().expect("key is not set"), - data: self.instruction.data.clone().expect("data is not set"), + data: self.instruction.data.clone(), }; let instruction = WriteCollectionExternalPluginAdapterDataV1Cpi { __program: self.instruction.__program, @@ -511,6 +566,8 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { authority: self.instruction.authority, + buffer: self.instruction.buffer, + system_program: self .instruction .system_program @@ -531,6 +588,7 @@ struct WriteCollectionExternalPluginAdapterDataV1CpiBuilderInstruction<'a, 'b> { collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, key: Option, diff --git a/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs b/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs index 0e0123e0..d5c51750 100644 --- a/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs +++ b/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs @@ -19,8 +19,10 @@ pub struct WriteExternalPluginAdapterDataV1 { pub collection: Option, /// The account paying for the storage fees pub payer: solana_program::pubkey::Pubkey, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option, + /// The buffer to write to the external plugin + pub buffer: Option, /// The system program pub system_program: solana_program::pubkey::Pubkey, /// The SPL Noop Program @@ -40,7 +42,7 @@ impl WriteExternalPluginAdapterDataV1 { args: WriteExternalPluginAdapterDataV1InstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { - let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new( self.asset, false, )); @@ -67,6 +69,16 @@ impl WriteExternalPluginAdapterDataV1 { false, )); } + if let Some(buffer) = self.buffer { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + buffer, false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.system_program, false, @@ -115,7 +127,7 @@ impl WriteExternalPluginAdapterDataV1InstructionData { #[derive(Clone, Debug, Eq, PartialEq)] pub struct WriteExternalPluginAdapterDataV1InstructionArgs { pub key: ExternalPluginAdapterKey, - pub data: Vec, + pub data: Option>, } /// Instruction builder for `WriteExternalPluginAdapterDataV1`. @@ -126,14 +138,16 @@ pub struct WriteExternalPluginAdapterDataV1InstructionArgs { /// 1. `[writable, optional]` collection /// 2. `[writable, signer]` payer /// 3. `[signer, optional]` authority -/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) -/// 5. `[optional]` log_wrapper +/// 4. `[optional]` buffer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 6. `[optional]` log_wrapper #[derive(Default)] pub struct WriteExternalPluginAdapterDataV1Builder { asset: Option, collection: Option, payer: Option, authority: Option, + buffer: Option, system_program: Option, log_wrapper: Option, key: Option, @@ -165,12 +179,19 @@ impl WriteExternalPluginAdapterDataV1Builder { self } /// `[optional account]` - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter #[inline(always)] pub fn authority(&mut self, authority: Option) -> &mut Self { self.authority = authority; self } + /// `[optional account]` + /// The buffer to write to the external plugin + #[inline(always)] + pub fn buffer(&mut self, buffer: Option) -> &mut Self { + self.buffer = buffer; + self + } /// `[optional account, default to '11111111111111111111111111111111']` /// The system program #[inline(always)] @@ -193,6 +214,7 @@ impl WriteExternalPluginAdapterDataV1Builder { self.key = Some(key); self } + /// `[optional argument]` #[inline(always)] pub fn data(&mut self, data: Vec) -> &mut Self { self.data = Some(data); @@ -223,6 +245,7 @@ impl WriteExternalPluginAdapterDataV1Builder { collection: self.collection, payer: self.payer.expect("payer is not set"), authority: self.authority, + buffer: self.buffer, system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -230,7 +253,7 @@ impl WriteExternalPluginAdapterDataV1Builder { }; let args = WriteExternalPluginAdapterDataV1InstructionArgs { key: self.key.clone().expect("key is not set"), - data: self.data.clone().expect("data is not set"), + data: self.data.clone(), }; accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) @@ -245,8 +268,10 @@ pub struct WriteExternalPluginAdapterDataV1CpiAccounts<'a, 'b> { pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The account paying for the storage fees pub payer: &'b solana_program::account_info::AccountInfo<'a>, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The buffer to write to the external plugin + pub buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The SPL Noop Program @@ -263,8 +288,10 @@ pub struct WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { pub collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The account paying for the storage fees pub payer: &'b solana_program::account_info::AccountInfo<'a>, - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The buffer to write to the external plugin + pub buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The SPL Noop Program @@ -285,6 +312,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { collection: accounts.collection, payer: accounts.payer, authority: accounts.authority, + buffer: accounts.buffer, system_program: accounts.system_program, log_wrapper: accounts.log_wrapper, __args: args, @@ -323,7 +351,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { bool, )], ) -> solana_program::entrypoint::ProgramResult { - let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(7 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new( *self.asset.key, false, @@ -354,6 +382,17 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { false, )); } + if let Some(buffer) = self.buffer { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *buffer.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.system_program.key, false, @@ -387,7 +426,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { accounts, data, }; - let mut account_infos = Vec::with_capacity(6 + 1 + remaining_accounts.len()); + let mut account_infos = Vec::with_capacity(7 + 1 + remaining_accounts.len()); account_infos.push(self.__program.clone()); account_infos.push(self.asset.clone()); if let Some(collection) = self.collection { @@ -397,6 +436,9 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { if let Some(authority) = self.authority { account_infos.push(authority.clone()); } + if let Some(buffer) = self.buffer { + account_infos.push(buffer.clone()); + } account_infos.push(self.system_program.clone()); if let Some(log_wrapper) = self.log_wrapper { account_infos.push(log_wrapper.clone()); @@ -421,8 +463,9 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { /// 1. `[writable, optional]` collection /// 2. `[writable, signer]` payer /// 3. `[signer, optional]` authority -/// 4. `[]` system_program -/// 5. `[optional]` log_wrapper +/// 4. `[optional]` buffer +/// 5. `[]` system_program +/// 6. `[optional]` log_wrapper pub struct WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { instruction: Box>, } @@ -435,6 +478,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { collection: None, payer: None, authority: None, + buffer: None, system_program: None, log_wrapper: None, key: None, @@ -466,7 +510,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self } /// `[optional account]` - /// The Data Authority of the External PluginExternalPluginAdapter + /// The Data Authority of the External Plugin Adapter #[inline(always)] pub fn authority( &mut self, @@ -475,6 +519,16 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self.instruction.authority = authority; self } + /// `[optional account]` + /// The buffer to write to the external plugin + #[inline(always)] + pub fn buffer( + &mut self, + buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.buffer = buffer; + self + } /// The system program #[inline(always)] pub fn system_program( @@ -499,6 +553,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { self.instruction.key = Some(key); self } + /// `[optional argument]` #[inline(always)] pub fn data(&mut self, data: Vec) -> &mut Self { self.instruction.data = Some(data); @@ -547,7 +602,7 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { ) -> solana_program::entrypoint::ProgramResult { let args = WriteExternalPluginAdapterDataV1InstructionArgs { key: self.instruction.key.clone().expect("key is not set"), - data: self.instruction.data.clone().expect("data is not set"), + data: self.instruction.data.clone(), }; let instruction = WriteExternalPluginAdapterDataV1Cpi { __program: self.instruction.__program, @@ -560,6 +615,8 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1CpiBuilder<'a, 'b> { authority: self.instruction.authority, + buffer: self.instruction.buffer, + system_program: self .instruction .system_program @@ -581,6 +638,7 @@ struct WriteExternalPluginAdapterDataV1CpiBuilderInstruction<'a, 'b> { collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + buffer: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, log_wrapper: Option<&'b solana_program::account_info::AccountInfo<'a>>, key: Option, diff --git a/clients/rust/src/generated/types/data_store.rs b/clients/rust/src/generated/types/app_data.rs similarity index 97% rename from clients/rust/src/generated/types/data_store.rs rename to clients/rust/src/generated/types/app_data.rs index 7d7f5577..1c6c7603 100644 --- a/clients/rust/src/generated/types/data_store.rs +++ b/clients/rust/src/generated/types/app_data.rs @@ -16,7 +16,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; #[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct DataStore { +pub struct AppData { pub data_authority: PluginAuthority, pub schema: ExternalPluginAdapterSchema, } diff --git a/clients/rust/src/generated/types/data_store_init_info.rs b/clients/rust/src/generated/types/app_data_init_info.rs similarity index 96% rename from clients/rust/src/generated/types/data_store_init_info.rs rename to clients/rust/src/generated/types/app_data_init_info.rs index bdcf7213..408f13b7 100644 --- a/clients/rust/src/generated/types/data_store_init_info.rs +++ b/clients/rust/src/generated/types/app_data_init_info.rs @@ -16,7 +16,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; #[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct DataStoreInitInfo { +pub struct AppDataInitInfo { pub data_authority: PluginAuthority, pub init_plugin_authority: Option, pub schema: Option, diff --git a/clients/rust/src/generated/types/data_store_update_info.rs b/clients/rust/src/generated/types/app_data_update_info.rs similarity index 95% rename from clients/rust/src/generated/types/data_store_update_info.rs rename to clients/rust/src/generated/types/app_data_update_info.rs index c9fe1584..2cc4cf6f 100644 --- a/clients/rust/src/generated/types/data_store_update_info.rs +++ b/clients/rust/src/generated/types/app_data_update_info.rs @@ -15,6 +15,6 @@ use borsh::{BorshDeserialize, BorshSerialize}; #[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] #[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] #[derive(Clone, Debug, Eq, PartialEq)] -pub struct DataStoreUpdateInfo { +pub struct AppDataUpdateInfo { pub schema: Option, } diff --git a/clients/rust/src/generated/types/data_section.rs b/clients/rust/src/generated/types/data_section.rs new file mode 100644 index 00000000..ac1090bf --- /dev/null +++ b/clients/rust/src/generated/types/data_section.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::LinkedDataKey; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DataSection { + pub parent_key: LinkedDataKey, + pub schema: ExternalPluginAdapterSchema, +} diff --git a/clients/rust/src/generated/types/data_section_init_info.rs b/clients/rust/src/generated/types/data_section_init_info.rs new file mode 100644 index 00000000..bdca4113 --- /dev/null +++ b/clients/rust/src/generated/types/data_section_init_info.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::LinkedDataKey; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DataSectionInitInfo { + pub parent_key: LinkedDataKey, + pub schema: ExternalPluginAdapterSchema, +} diff --git a/clients/rust/src/generated/types/data_section_update_info.rs b/clients/rust/src/generated/types/data_section_update_info.rs new file mode 100644 index 00000000..06b84f15 --- /dev/null +++ b/clients/rust/src/generated/types/data_section_update_info.rs @@ -0,0 +1,17 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DataSectionUpdateInfo {} diff --git a/clients/rust/src/generated/types/external_plugin_adapter.rs b/clients/rust/src/generated/types/external_plugin_adapter.rs index 00e02d0a..d691df27 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter.rs @@ -5,8 +5,11 @@ //! [https://github.com/metaplex-foundation/kinobi] //! -use crate::generated::types::DataStore; +use crate::generated::types::AppData; +use crate::generated::types::DataSection; use crate::generated::types::LifecycleHook; +use crate::generated::types::LinkedAppData; +use crate::generated::types::LinkedLifecycleHook; use crate::generated::types::Oracle; #[cfg(feature = "anchor")] use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; @@ -20,5 +23,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub enum ExternalPluginAdapter { LifecycleHook(LifecycleHook), Oracle(Oracle), - DataStore(DataStore), + AppData(AppData), + LinkedLifecycleHook(LinkedLifecycleHook), + LinkedAppData(LinkedAppData), + DataSection(DataSection), } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs b/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs index 2168a069..5992c9f7 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs @@ -5,8 +5,11 @@ //! [https://github.com/metaplex-foundation/kinobi] //! -use crate::generated::types::DataStoreInitInfo; +use crate::generated::types::AppDataInitInfo; +use crate::generated::types::DataSectionInitInfo; use crate::generated::types::LifecycleHookInitInfo; +use crate::generated::types::LinkedAppDataInitInfo; +use crate::generated::types::LinkedLifecycleHookInitInfo; use crate::generated::types::OracleInitInfo; #[cfg(feature = "anchor")] use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; @@ -20,5 +23,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub enum ExternalPluginAdapterInitInfo { LifecycleHook(LifecycleHookInitInfo), Oracle(OracleInitInfo), - DataStore(DataStoreInitInfo), + AppData(AppDataInitInfo), + LinkedLifecycleHook(LinkedLifecycleHookInitInfo), + LinkedAppData(LinkedAppDataInitInfo), + DataSection(DataSectionInitInfo), } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_key.rs b/clients/rust/src/generated/types/external_plugin_adapter_key.rs index b8d3b68d..6defc9f7 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_key.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_key.rs @@ -5,6 +5,7 @@ //! [https://github.com/metaplex-foundation/kinobi] //! +use crate::generated::types::LinkedDataKey; use crate::generated::types::PluginAuthority; #[cfg(feature = "anchor")] use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; @@ -27,5 +28,12 @@ pub enum ExternalPluginAdapterKey { serde(with = "serde_with::As::") )] Oracle(Pubkey), - DataStore(PluginAuthority), + AppData(PluginAuthority), + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + LinkedLifecycleHook(Pubkey), + LinkedAppData(PluginAuthority), + DataSection(LinkedDataKey), } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_type.rs b/clients/rust/src/generated/types/external_plugin_adapter_type.rs index 0a7c025e..4a3e299d 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_type.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_type.rs @@ -18,5 +18,8 @@ use num_derive::FromPrimitive; pub enum ExternalPluginAdapterType { LifecycleHook, Oracle, - DataStore, + AppData, + LinkedLifecycleHook, + LinkedAppData, + DataSection, } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs b/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs index cd709990..3b4840e2 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs @@ -5,8 +5,10 @@ //! [https://github.com/metaplex-foundation/kinobi] //! -use crate::generated::types::DataStoreUpdateInfo; +use crate::generated::types::AppDataUpdateInfo; use crate::generated::types::LifecycleHookUpdateInfo; +use crate::generated::types::LinkedAppDataUpdateInfo; +use crate::generated::types::LinkedLifecycleHookUpdateInfo; use crate::generated::types::OracleUpdateInfo; #[cfg(feature = "anchor")] use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; @@ -20,5 +22,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub enum ExternalPluginAdapterUpdateInfo { LifecycleHook(LifecycleHookUpdateInfo), Oracle(OracleUpdateInfo), - DataStore(DataStoreUpdateInfo), + AppData(AppDataUpdateInfo), + LinkedLifecycleHook(LinkedLifecycleHookUpdateInfo), + LinkedAppData(LinkedAppDataUpdateInfo), } diff --git a/clients/rust/src/generated/types/linked_app_data.rs b/clients/rust/src/generated/types/linked_app_data.rs new file mode 100644 index 00000000..71ba8094 --- /dev/null +++ b/clients/rust/src/generated/types/linked_app_data.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedAppData { + pub data_authority: PluginAuthority, + pub schema: ExternalPluginAdapterSchema, +} diff --git a/clients/rust/src/generated/types/linked_app_data_init_info.rs b/clients/rust/src/generated/types/linked_app_data_init_info.rs new file mode 100644 index 00000000..2ecbbacd --- /dev/null +++ b/clients/rust/src/generated/types/linked_app_data_init_info.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedAppDataInitInfo { + pub data_authority: PluginAuthority, + pub init_plugin_authority: Option, + pub schema: Option, +} diff --git a/clients/rust/src/generated/types/linked_app_data_update_info.rs b/clients/rust/src/generated/types/linked_app_data_update_info.rs new file mode 100644 index 00000000..9eabc134 --- /dev/null +++ b/clients/rust/src/generated/types/linked_app_data_update_info.rs @@ -0,0 +1,20 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedAppDataUpdateInfo { + pub schema: Option, +} diff --git a/clients/rust/src/generated/types/linked_data_key.rs b/clients/rust/src/generated/types/linked_data_key.rs new file mode 100644 index 00000000..3dca4754 --- /dev/null +++ b/clients/rust/src/generated/types/linked_data_key.rs @@ -0,0 +1,26 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LinkedDataKey { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + LinkedLifecycleHook(Pubkey), + LinkedAppData(PluginAuthority), +} diff --git a/clients/rust/src/generated/types/linked_lifecycle_hook.rs b/clients/rust/src/generated/types/linked_lifecycle_hook.rs new file mode 100644 index 00000000..8359ec49 --- /dev/null +++ b/clients/rust/src/generated/types/linked_lifecycle_hook.rs @@ -0,0 +1,30 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::ExtraAccount; +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedLifecycleHook { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub hooked_program: Pubkey, + pub extra_accounts: Option>, + pub data_authority: Option, + pub schema: ExternalPluginAdapterSchema, +} diff --git a/clients/rust/src/generated/types/linked_lifecycle_hook_init_info.rs b/clients/rust/src/generated/types/linked_lifecycle_hook_init_info.rs new file mode 100644 index 00000000..e2952707 --- /dev/null +++ b/clients/rust/src/generated/types/linked_lifecycle_hook_init_info.rs @@ -0,0 +1,34 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalCheckResult; +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::ExtraAccount; +use crate::generated::types::HookableLifecycleEvent; +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedLifecycleHookInitInfo { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub hooked_program: Pubkey, + pub init_plugin_authority: Option, + pub lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, + pub extra_accounts: Option>, + pub data_authority: Option, + pub schema: Option, +} diff --git a/clients/rust/src/generated/types/linked_lifecycle_hook_update_info.rs b/clients/rust/src/generated/types/linked_lifecycle_hook_update_info.rs new file mode 100644 index 00000000..ec583ba4 --- /dev/null +++ b/clients/rust/src/generated/types/linked_lifecycle_hook_update_info.rs @@ -0,0 +1,25 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalCheckResult; +use crate::generated::types::ExternalPluginAdapterSchema; +use crate::generated::types::ExtraAccount; +use crate::generated::types::HookableLifecycleEvent; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LinkedLifecycleHookUpdateInfo { + pub lifecycle_checks: Option>, + pub extra_accounts: Option>, + pub schema: Option, +} diff --git a/clients/rust/src/generated/types/mod.rs b/clients/rust/src/generated/types/mod.rs index 1a02a50a..755acf21 100644 --- a/clients/rust/src/generated/types/mod.rs +++ b/clients/rust/src/generated/types/mod.rs @@ -6,6 +6,9 @@ //! pub(crate) mod r#add_blocker; +pub(crate) mod r#app_data; +pub(crate) mod r#app_data_init_info; +pub(crate) mod r#app_data_update_info; pub(crate) mod r#attribute; pub(crate) mod r#attributes; pub(crate) mod r#autograph; @@ -13,10 +16,10 @@ pub(crate) mod r#autograph_signature; pub(crate) mod r#burn_delegate; pub(crate) mod r#compression_proof; pub(crate) mod r#creator; +pub(crate) mod r#data_section; +pub(crate) mod r#data_section_init_info; +pub(crate) mod r#data_section_update_info; pub(crate) mod r#data_state; -pub(crate) mod r#data_store; -pub(crate) mod r#data_store_init_info; -pub(crate) mod r#data_store_update_info; pub(crate) mod r#edition; pub(crate) mod r#external_check_result; pub(crate) mod r#external_plugin_adapter; @@ -37,6 +40,13 @@ pub(crate) mod r#key; pub(crate) mod r#lifecycle_hook; pub(crate) mod r#lifecycle_hook_init_info; pub(crate) mod r#lifecycle_hook_update_info; +pub(crate) mod r#linked_app_data; +pub(crate) mod r#linked_app_data_init_info; +pub(crate) mod r#linked_app_data_update_info; +pub(crate) mod r#linked_data_key; +pub(crate) mod r#linked_lifecycle_hook; +pub(crate) mod r#linked_lifecycle_hook_init_info; +pub(crate) mod r#linked_lifecycle_hook_update_info; pub(crate) mod r#master_edition; pub(crate) mod r#oracle; pub(crate) mod r#oracle_init_info; @@ -62,6 +72,9 @@ pub(crate) mod r#verified_creators; pub(crate) mod r#verified_creators_signature; pub use self::r#add_blocker::*; +pub use self::r#app_data::*; +pub use self::r#app_data_init_info::*; +pub use self::r#app_data_update_info::*; pub use self::r#attribute::*; pub use self::r#attributes::*; pub use self::r#autograph::*; @@ -69,10 +82,10 @@ pub use self::r#autograph_signature::*; pub use self::r#burn_delegate::*; pub use self::r#compression_proof::*; pub use self::r#creator::*; +pub use self::r#data_section::*; +pub use self::r#data_section_init_info::*; +pub use self::r#data_section_update_info::*; pub use self::r#data_state::*; -pub use self::r#data_store::*; -pub use self::r#data_store_init_info::*; -pub use self::r#data_store_update_info::*; pub use self::r#edition::*; pub use self::r#external_check_result::*; pub use self::r#external_plugin_adapter::*; @@ -93,6 +106,13 @@ pub use self::r#key::*; pub use self::r#lifecycle_hook::*; pub use self::r#lifecycle_hook_init_info::*; pub use self::r#lifecycle_hook_update_info::*; +pub use self::r#linked_app_data::*; +pub use self::r#linked_app_data_init_info::*; +pub use self::r#linked_app_data_update_info::*; +pub use self::r#linked_data_key::*; +pub use self::r#linked_lifecycle_hook::*; +pub use self::r#linked_lifecycle_hook_init_info::*; +pub use self::r#linked_lifecycle_hook_update_info::*; pub use self::r#master_edition::*; pub use self::r#oracle::*; pub use self::r#oracle_init_info::*; diff --git a/clients/rust/src/hooked/advanced_types.rs b/clients/rust/src/hooked/advanced_types.rs index b4149623..5dc81285 100644 --- a/clients/rust/src/hooked/advanced_types.rs +++ b/clients/rust/src/hooked/advanced_types.rs @@ -8,11 +8,11 @@ use std::{cmp::Ordering, io::ErrorKind}; use crate::{ accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1}, types::{ - AddBlocker, Attributes, Autograph, BurnDelegate, DataStore, Edition, ExternalCheckResult, - ExternalPluginAdapter, ExternalPluginAdapterKey, FreezeDelegate, ImmutableMetadata, Key, - LifecycleHook, MasterEdition, Oracle, PermanentBurnDelegate, PermanentFreezeDelegate, - PermanentTransferDelegate, PluginAuthority, Royalties, TransferDelegate, UpdateDelegate, - VerifiedCreators, + AddBlocker, AppData, Attributes, Autograph, BurnDelegate, DataSection, Edition, + ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterKey, FreezeDelegate, + ImmutableMetadata, Key, LifecycleHook, LinkedAppData, LinkedLifecycleHook, MasterEdition, + Oracle, PermanentBurnDelegate, PermanentFreezeDelegate, PermanentTransferDelegate, + PluginAuthority, Royalties, TransferDelegate, UpdateDelegate, VerifiedCreators, }, }; @@ -181,9 +181,33 @@ pub struct PluginsList { #[derive(Debug, Default)] pub struct ExternalPluginAdaptersList { - pub lifecycle_hooks: Vec, + pub lifecycle_hooks: Vec, + pub linked_lifecycle_hooks: Vec, pub oracles: Vec, - pub data_stores: Vec, + pub app_data: Vec, + pub linked_app_data: Vec, + pub data_sections: Vec, +} + +#[derive(Debug)] +pub struct LifecycleHookWithData { + pub base: LifecycleHook, + pub data_offset: usize, + pub data_len: usize, +} + +#[derive(Debug)] +pub struct AppDataWithData { + pub base: AppData, + pub data_offset: usize, + pub data_len: usize, +} + +#[derive(Debug)] +pub struct DataSectionWithData { + pub base: DataSection, + pub data_offset: usize, + pub data_len: usize, } #[derive(Debug)] @@ -219,6 +243,7 @@ impl RegistryRecordSafe { ///ExternalPluginAdapter Registry record that can be used when the plugin type is not known (i.e. a `ExternalPluginAdapterType` that /// is too new for this client to know about). +#[derive(Clone, Debug, Eq, PartialEq)] pub struct ExternalRegistryRecordSafe { pub plugin_type: u8, pub authority: PluginAuthority, @@ -304,15 +329,22 @@ impl PluginRegistryV1Safe { impl From<&ExternalPluginAdapter> for ExternalPluginAdapterKey { fn from(plugin: &ExternalPluginAdapter) -> Self { match plugin { - ExternalPluginAdapter::DataStore(data_store) => { - ExternalPluginAdapterKey::DataStore(data_store.data_authority.clone()) + ExternalPluginAdapter::LinkedAppData(app_data) => { + ExternalPluginAdapterKey::AppData(app_data.data_authority.clone()) + } + ExternalPluginAdapter::AppData(app_data) => { + ExternalPluginAdapterKey::AppData(app_data.data_authority.clone()) } ExternalPluginAdapter::Oracle(oracle) => { ExternalPluginAdapterKey::Oracle(oracle.base_address) } + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + ExternalPluginAdapterKey::LifecycleHook(lifecycle_hook.hooked_program) + } ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { ExternalPluginAdapterKey::LifecycleHook(lifecycle_hook.hooked_program) } + ExternalPluginAdapter::DataSection(_) => todo!(), } } } diff --git a/clients/rust/src/hooked/mod.rs b/clients/rust/src/hooked/mod.rs index bbae32c7..481dbbc4 100644 --- a/clients/rust/src/hooked/mod.rs +++ b/clients/rust/src/hooked/mod.rs @@ -14,6 +14,7 @@ pub use collection::*; use anchor_lang::prelude::{ AnchorDeserialize as CrateDeserialize, AnchorSerialize as CrateSerialize, }; +use base64::prelude::*; #[cfg(not(feature = "anchor"))] use borsh::{BorshDeserialize as CrateDeserialize, BorshSerialize as CrateSerialize}; use modular_bitfield::{bitfield, specifiers::B29}; @@ -23,7 +24,10 @@ use std::{cmp::Ordering, mem::size_of}; use crate::{ accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1, PluginRegistryV1}, errors::MplCoreError, - types::{ExternalCheckResult, Key, Plugin, PluginType, RegistryRecord}, + types::{ + ExternalCheckResult, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + ExternalPluginAdapterType, Key, Plugin, PluginType, RegistryRecord, + }, }; use solana_program::account_info::AccountInfo; @@ -215,7 +219,7 @@ impl RegistryRecord { /// Bitfield representation of lifecycle permissions for external plugin adapter, third party plugins. #[bitfield(bits = 32)] -#[derive(Eq, PartialEq, Copy, Clone, Debug)] +#[derive(Eq, PartialEq, Copy, Clone, Debug, Default)] pub struct ExternalCheckResultBits { pub can_listen: bool, pub can_approve: bool, @@ -236,3 +240,47 @@ impl From for ExternalCheckResult { } } } + +impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType { + fn from(key: &ExternalPluginAdapterKey) -> Self { + match key { + ExternalPluginAdapterKey::LifecycleHook(_) => ExternalPluginAdapterType::LifecycleHook, + ExternalPluginAdapterKey::LinkedLifecycleHook(_) => { + ExternalPluginAdapterType::LinkedLifecycleHook + } + ExternalPluginAdapterKey::Oracle(_) => ExternalPluginAdapterType::Oracle, + ExternalPluginAdapterKey::AppData(_) => ExternalPluginAdapterType::AppData, + ExternalPluginAdapterKey::LinkedAppData(_) => ExternalPluginAdapterType::LinkedAppData, + ExternalPluginAdapterKey::DataSection(_) => ExternalPluginAdapterType::DataSection, + } + } +} + +/// Use `ExternalPluginAdapterSchema` to convert data to string. If schema is binary or there is +/// an error, then use Base64 encoding. +pub fn convert_external_plugin_adapter_data_to_string( + schema: &ExternalPluginAdapterSchema, + data_slice: &[u8], +) -> String { + match schema { + ExternalPluginAdapterSchema::Binary => { + // Encode the binary data as a base64 string. + BASE64_STANDARD.encode(data_slice) + } + ExternalPluginAdapterSchema::Json => { + // Convert the byte slice to a UTF-8 string, replacing invalid characterse. + String::from_utf8_lossy(data_slice).to_string() + } + ExternalPluginAdapterSchema::MsgPack => { + // Attempt to decode `MsgPack` to serde_json::Value and serialize to JSON string. + match rmp_serde::decode::from_slice::(data_slice) { + Ok(json_val) => serde_json::to_string(&json_val) + .unwrap_or_else(|_| BASE64_STANDARD.encode(data_slice)), + Err(_) => { + // Failed to decode `MsgPack`, fallback to base64. + BASE64_STANDARD.encode(data_slice) + } + } + } + } +} diff --git a/clients/rust/src/hooked/plugin.rs b/clients/rust/src/hooked/plugin.rs index cd1f71c4..9f815451 100644 --- a/clients/rust/src/hooked/plugin.rs +++ b/clients/rust/src/hooked/plugin.rs @@ -3,18 +3,19 @@ use anchor_lang::prelude::AnchorDeserialize as CrateDeserialize; #[cfg(not(feature = "anchor"))] use borsh::BorshDeserialize as CrateDeserialize; use num_traits::FromPrimitive; -use solana_program::account_info::AccountInfo; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::{ accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1}, errors::MplCoreError, types::{ - ExternalPluginAdapter, ExternalPluginAdapterType, Plugin, PluginAuthority, PluginType, - RegistryRecord, + ExternalPluginAdapter, ExternalPluginAdapterKey, ExternalPluginAdapterType, LinkedDataKey, + Plugin, PluginAuthority, PluginType, RegistryRecord, }, - AddBlockerPlugin, AttributesPlugin, AutographPlugin, BaseAuthority, BasePlugin, - BurnDelegatePlugin, DataBlob, EditionPlugin, ExternalPluginAdaptersList, - ExternalRegistryRecordSafe, FreezeDelegatePlugin, ImmutableMetadataPlugin, MasterEditionPlugin, + AddBlockerPlugin, AppDataWithData, AttributesPlugin, AutographPlugin, BaseAuthority, + BasePlugin, BurnDelegatePlugin, DataBlob, DataSectionWithData, EditionPlugin, + ExternalPluginAdaptersList, ExternalRegistryRecordSafe, FreezeDelegatePlugin, + ImmutableMetadataPlugin, LifecycleHookWithData, MasterEditionPlugin, PermanentBurnDelegatePlugin, PermanentFreezeDelegatePlugin, PermanentTransferDelegatePlugin, PluginRegistryV1Safe, PluginsList, RegistryRecordSafe, RoyaltiesPlugin, SolanaAccount, TransferDelegatePlugin, UpdateDelegatePlugin, VerifiedCreatorsPlugin, @@ -124,6 +125,118 @@ pub fn fetch_plugins(account_data: &[u8]) -> Result, std::io Ok(filtered_plugin_registry) } +/// Fetch the external plugin adapter from the registry. +pub fn fetch_external_plugin_adapter( + account: &AccountInfo, + core: Option<&T>, + plugin_key: &ExternalPluginAdapterKey, +) -> Result<(PluginAuthority, U, usize), std::io::Error> { + let registry_record = fetch_external_registry_record(account, core, plugin_key)?; + + let inner = U::deserialize( + &mut &(*account.data).borrow()[registry_record.offset.checked_add(1).ok_or( + std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::NumericalOverflow.to_string(), + ), + )? as usize..], + )?; + + // Return the plugin and its authority. + Ok(( + registry_record.authority.clone(), + inner, + registry_record.offset as usize, + )) +} + +/// Fetch the external plugin adapter from the registry. +pub fn fetch_wrapped_external_plugin_adapter( + account: &AccountInfo, + core: Option<&T>, + plugin_key: &ExternalPluginAdapterKey, +) -> Result<(ExternalRegistryRecordSafe, ExternalPluginAdapter), std::io::Error> { + let registry_record = fetch_external_registry_record(account, core, plugin_key)?; + + // Deserialize the plugin. + let plugin = ExternalPluginAdapter::deserialize( + &mut &(*account.data).borrow()[registry_record.offset as usize..], + )?; + + // Return the plugin and its authority. + Ok((registry_record, plugin)) +} + +// Helper to unwrap optional data offset and data length. +fn unwrap_data_offset_and_data_len( + data_offset: Option, + data_len: Option, +) -> Result<(usize, usize), std::io::Error> { + let data_offset = data_offset.ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::InvalidPlugin.to_string(), + ))?; + + let data_len = data_len.ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::InvalidPlugin.to_string(), + ))?; + + Ok((data_offset as usize, data_len as usize)) +} + +/// Fetch the external plugin adapter data offset and length. These can be used to +/// directly slice the account data for use of the external plugin adapter data. +pub fn fetch_external_plugin_adapter_data_info( + account: &AccountInfo, + core: Option<&T>, + plugin_key: &ExternalPluginAdapterKey, +) -> Result<(usize, usize), std::io::Error> { + let registry_record = fetch_external_registry_record(account, core, plugin_key)?; + let (data_offset, data_len) = + unwrap_data_offset_and_data_len(registry_record.data_offset, registry_record.data_len)?; + + // Return the data offset and length. + Ok((data_offset, data_len)) +} + +// Internal helper to fetch just the external registry record for the external plugin key. +fn fetch_external_registry_record( + account: &AccountInfo, + core: Option<&T>, + plugin_key: &ExternalPluginAdapterKey, +) -> Result { + let size = match core { + Some(core) => core.get_size(), + None => { + let asset = T::load(account, 0)?; + + if asset.get_size() == account.data_len() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::ExternalPluginAdapterNotFound.to_string(), + )); + } + + asset.get_size() + } + }; + + let header = PluginHeaderV1::from_bytes(&(*account.data).borrow()[size..])?; + let plugin_registry = PluginRegistryV1Safe::from_bytes( + &(*account.data).borrow()[header.plugin_registry_offset as usize..], + )?; + + // Find and return the registry record. + let result = find_external_plugin_adapter(&plugin_registry, plugin_key, account)?; + result.1.cloned().ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::ExternalPluginAdapterNotFound.to_string(), + ) + }) +} + /// List all plugins in an account, dropping any unknown plugins (i.e. `PluginType`s that are too /// new for this client to know about). Note this also does not support external plugin adapters for now, /// and will be updated when those are defined. @@ -256,11 +369,41 @@ pub(crate) fn registry_records_to_external_plugin_adapter_list( match plugin { ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { - acc.lifecycle_hooks.push(lifecycle_hook) + let (data_offset, data_len) = + unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?; + + acc.lifecycle_hooks.push(LifecycleHookWithData { + base: lifecycle_hook, + data_offset, + data_len, + }) + } + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + acc.linked_lifecycle_hooks.push(lifecycle_hook) } ExternalPluginAdapter::Oracle(oracle) => acc.oracles.push(oracle), - ExternalPluginAdapter::DataStore(data_store) => { - acc.data_stores.push(data_store) + ExternalPluginAdapter::AppData(app_data) => { + let (data_offset, data_len) = + unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?; + + acc.app_data.push(AppDataWithData { + base: app_data, + data_offset, + data_len, + }) + } + ExternalPluginAdapter::LinkedAppData(app_data) => { + acc.linked_app_data.push(app_data) + } + ExternalPluginAdapter::DataSection(data_section) => { + let (data_offset, data_len) = + unwrap_data_offset_and_data_len(record.data_offset, record.data_len)?; + + acc.data_sections.push(DataSectionWithData { + base: data_section, + data_offset, + data_len, + }) } } } @@ -270,3 +413,107 @@ pub(crate) fn registry_records_to_external_plugin_adapter_list( result } + +pub(crate) fn find_external_plugin_adapter<'b>( + plugin_registry: &'b PluginRegistryV1Safe, + plugin_key: &ExternalPluginAdapterKey, + account: &AccountInfo<'_>, +) -> Result<(Option, Option<&'b ExternalRegistryRecordSafe>), std::io::Error> { + let mut result = (None, None); + for (i, record) in plugin_registry.external_registry.iter().enumerate() { + if record.plugin_type == ExternalPluginAdapterType::from(plugin_key) as u8 + && (match plugin_key { + ExternalPluginAdapterKey::LifecycleHook(address) + | ExternalPluginAdapterKey::Oracle(address) + | ExternalPluginAdapterKey::LinkedLifecycleHook(address) => { + let pubkey_offset = record.offset.checked_add(1).ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::NumericalOverflow, + ))?; + address + == &match Pubkey::deserialize( + &mut &account.data.borrow()[pubkey_offset as usize..], + ) { + Ok(address) => address, + Err(_) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + Box::::from( + MplCoreError::DeserializationError, + ), + )) + } + } + } + ExternalPluginAdapterKey::AppData(authority) => { + let authority_offset = + record.offset.checked_add(1).ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::NumericalOverflow, + ))?; + authority + == &match PluginAuthority::deserialize( + &mut &account.data.borrow()[authority_offset as usize..], + ) { + Ok(authority) => authority, + Err(_) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + Box::::from( + MplCoreError::DeserializationError, + ), + )) + } + } + } + ExternalPluginAdapterKey::LinkedAppData(authority) => { + let authority_offset = + record.offset.checked_add(1).ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::NumericalOverflow, + ))?; + authority + == &match PluginAuthority::deserialize( + &mut &account.data.borrow()[authority_offset as usize..], + ) { + Ok(authority) => authority, + Err(_) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + Box::::from( + MplCoreError::DeserializationError, + ), + )) + } + } + } + ExternalPluginAdapterKey::DataSection(linked_data_key) => { + let linked_data_key_offset = + record.offset.checked_add(1).ok_or(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::NumericalOverflow, + ))?; + linked_data_key + == &match LinkedDataKey::deserialize( + &mut &account.data.borrow()[linked_data_key_offset as usize..], + ) { + Ok(linked_data_key) => linked_data_key, + Err(_) => { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + Box::::from( + MplCoreError::DeserializationError, + ), + )) + } + } + } + }) + { + result = (Some(i), Some(record)); + break; + } + } + + Ok(result) +} diff --git a/clients/rust/src/indexable_asset.rs b/clients/rust/src/indexable_asset.rs index 7ce31887..5686ebd8 100644 --- a/clients/rust/src/indexable_asset.rs +++ b/clients/rust/src/indexable_asset.rs @@ -9,6 +9,7 @@ use std::{cmp::Ordering, collections::HashMap, io::ErrorKind}; use crate::{ accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1}, + convert_external_plugin_adapter_data_to_string, types::{ ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterSchema, ExternalPluginAdapterType, HookableLifecycleEvent, Key, Plugin, PluginAuthority, @@ -39,6 +40,40 @@ pub struct IndexableUnknownPluginSchemaV1 { pub data: String, } +#[cfg(feature = "serde")] +mod custom_serde { + use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; + use serde_json::Value as JsonValue; + + pub fn serialize(data: &Option, serializer: S) -> Result + where + S: Serializer, + { + match data { + Some(s) => { + if let Ok(json_value) = serde_json::from_str::(s) { + json_value.serialize(serializer) + } else { + serializer.serialize_str(s) + } + } + None => serializer.serialize_none(), + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let json_value: Option = Option::deserialize(deserializer)?; + match json_value { + Some(JsonValue::String(s)) => Ok(Some(s)), + Some(json_value) => Ok(Some(json_value.to_string())), + None => Ok(None), + } + } +} + /// Schema used for indexing known external plugin types. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Clone, Debug, Eq, PartialEq)] @@ -56,7 +91,10 @@ pub struct IndexableExternalPluginSchemaV1 { pub data_offset: Option, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] pub data_len: Option, - #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))] + #[cfg_attr( + feature = "serde", + serde(skip_serializing_if = "Option::is_none", with = "custom_serde") + )] pub data: Option, } @@ -227,17 +265,22 @@ impl ProcessedExternalPlugin { let (data_offset, data_len, data) = match external_plugin_data_info { Some(data_info) => { let schema = match &adapter_config { - ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { - &lifecycle_hook.schema - } - ExternalPluginAdapter::DataStore(data_store) => &data_store.schema, - _ => &ExternalPluginAdapterSchema::Binary, // is this possible + ExternalPluginAdapter::LifecycleHook(lc_hook) => &lc_hook.schema, + ExternalPluginAdapter::AppData(app_data) => &app_data.schema, + ExternalPluginAdapter::LinkedLifecycleHook(l_lc_hook) => &l_lc_hook.schema, + ExternalPluginAdapter::LinkedAppData(l_app_data) => &l_app_data.schema, + ExternalPluginAdapter::DataSection(data_section) => &data_section.schema, + // Assume binary for `Oracle`, but this should never happen. + ExternalPluginAdapter::Oracle(_) => &ExternalPluginAdapterSchema::Binary, }; ( Some(data_info.data_offset), Some(data_info.data_len), - Some(Self::convert_data_to_string(schema, data_info.data_slice)), + Some(convert_external_plugin_adapter_data_to_string( + schema, + data_info.data_slice, + )), ) } None => (None, None, None), @@ -285,30 +328,6 @@ impl ProcessedExternalPlugin { Ok(processed_plugin) } - - fn convert_data_to_string(schema: &ExternalPluginAdapterSchema, data_slice: &[u8]) -> String { - match schema { - ExternalPluginAdapterSchema::Binary => { - // Encode the binary data as a base64 string. - BASE64_STANDARD.encode(data_slice) - } - ExternalPluginAdapterSchema::Json => { - // Convert the byte slice to a UTF-8 string, replacing invalid characterse. - String::from_utf8_lossy(data_slice).to_string() - } - ExternalPluginAdapterSchema::MsgPack => { - // Attempt to decode `MsgPack` to serde_json::Value and serialize to JSON string. - match rmp_serde::decode::from_slice::(data_slice) { - Ok(json_val) => serde_json::to_string(&json_val) - .unwrap_or_else(|_| BASE64_STANDARD.encode(data_slice)), - Err(_) => { - // Failed to decode `MsgPack`, fallback to base64. - BASE64_STANDARD.encode(data_slice) - } - } - } - } - } } /// A type used to store both Core Assets and Core Collections for indexing. diff --git a/clients/rust/tests/add_external_plugins.rs b/clients/rust/tests/add_external_plugins.rs index f08935dc..485388e1 100644 --- a/clients/rust/tests/add_external_plugins.rs +++ b/clients/rust/tests/add_external_plugins.rs @@ -6,7 +6,7 @@ use mpl_core::{ AddCollectionExternalPluginAdapterV1Builder, AddExternalPluginAdapterV1Builder, }, types::{ - DataStore, DataStoreInitInfo, ExternalCheckResult, ExternalPluginAdapter, + AppData, AppDataInitInfo, ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterInitInfo, ExternalPluginAdapterSchema, HookableLifecycleEvent, LifecycleHook, LifecycleHookInitInfo, Oracle, OracleInitInfo, PluginAuthority, UpdateAuthority, ValidationResultsOffset, @@ -320,6 +320,7 @@ async fn test_temporarily_cannot_add_lifecycle_hook_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![], }, ) .await; @@ -535,8 +536,7 @@ async fn test_cannot_add_oracle_with_duplicate_lifecycle_checks() { } #[tokio::test] -#[ignore] -async fn test_add_data_store() { +async fn test_add_app_data() { let mut context = program_test().start_with_context().await; let asset = Keypair::new(); @@ -578,13 +578,11 @@ async fn test_add_data_store() { let add_external_plugin_adapter_ix = AddExternalPluginAdapterV1Builder::new() .asset(asset.pubkey()) .payer(context.payer.pubkey()) - .init_info(ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { - init_plugin_authority: Some(PluginAuthority::UpdateAuthority), - data_authority: PluginAuthority::UpdateAuthority, - schema: None, - }, - )) + .init_info(ExternalPluginAdapterInitInfo::AppData(AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: None, + })) .instruction(); let tx = Transaction::new_signed_with_payer( @@ -605,7 +603,7 @@ async fn test_add_data_store() { name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapter::DataStore(DataStore { + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { data_authority: PluginAuthority::UpdateAuthority, schema: ExternalPluginAdapterSchema::Binary, })], @@ -614,153 +612,6 @@ async fn test_add_data_store() { .await; } -#[tokio::test] -async fn test_temporarily_cannot_add_data_store() { - let mut context = program_test().start_with_context().await; - - let asset = Keypair::new(); - create_asset( - &mut context, - CreateAssetHelperArgs { - owner: None, - payer: None, - asset: &asset, - data_state: None, - name: None, - uri: None, - authority: None, - update_authority: None, - collection: None, - plugins: vec![], - external_plugin_adapters: vec![], - }, - ) - .await - .unwrap(); - - let owner = context.payer.pubkey(); - let update_authority = context.payer.pubkey(); - assert_asset( - &mut context, - AssertAssetHelperArgs { - asset: asset.pubkey(), - owner, - update_authority: Some(UpdateAuthority::Address(update_authority)), - name: None, - uri: None, - plugins: vec![], - external_plugin_adapters: vec![], - }, - ) - .await; - - let add_external_plugin_adapter_ix = AddExternalPluginAdapterV1Builder::new() - .asset(asset.pubkey()) - .payer(context.payer.pubkey()) - .init_info(ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { - init_plugin_authority: Some(PluginAuthority::UpdateAuthority), - data_authority: PluginAuthority::UpdateAuthority, - schema: None, - }, - )) - .instruction(); - - let tx = Transaction::new_signed_with_payer( - &[add_external_plugin_adapter_ix], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(tx) - .await - .unwrap_err(); - - assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); - - assert_asset( - &mut context, - AssertAssetHelperArgs { - asset: asset.pubkey(), - owner, - update_authority: Some(UpdateAuthority::Address(update_authority)), - name: None, - uri: None, - plugins: vec![], - external_plugin_adapters: vec![], - }, - ) - .await; -} - -#[tokio::test] -async fn test_temporarily_cannot_add_data_store_on_collection() { - let mut context = program_test().start_with_context().await; - - let collection = Keypair::new(); - create_collection( - &mut context, - CreateCollectionHelperArgs { - collection: &collection, - update_authority: None, - payer: None, - name: None, - uri: None, - plugins: vec![], - external_plugin_adapters: vec![], - }, - ) - .await - .unwrap(); - - let update_authority = context.payer.pubkey(); - assert_collection( - &mut context, - AssertCollectionHelperArgs { - collection: collection.pubkey(), - update_authority, - name: None, - uri: None, - num_minted: 0, - current_size: 0, - plugins: vec![], - }, - ) - .await; - - let add_external_plugin_adapter_ix = AddCollectionExternalPluginAdapterV1Builder::new() - .collection(collection.pubkey()) - .payer(context.payer.pubkey()) - .init_info(ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { - init_plugin_authority: Some(PluginAuthority::UpdateAuthority), - data_authority: PluginAuthority::UpdateAuthority, - schema: None, - }, - )) - .instruction(); - - let tx = Transaction::new_signed_with_payer( - &[add_external_plugin_adapter_ix], - Some(&context.payer.pubkey()), - &[&context.payer], - context.last_blockhash, - ); - - let error = context - .banks_client - .process_transaction(tx) - .await - .unwrap_err(); - - assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); - - // TODO: add collection assert. -} - #[tokio::test] async fn test_cannot_add_duplicate_external_plugin_adapter() { let mut context = program_test().start_with_context().await; diff --git a/clients/rust/tests/create_collection.rs b/clients/rust/tests/create_collection.rs index 84ff4ddf..7ddc728a 100644 --- a/clients/rust/tests/create_collection.rs +++ b/clients/rust/tests/create_collection.rs @@ -37,6 +37,7 @@ async fn test_create_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![], }, ) .await; @@ -76,6 +77,7 @@ async fn create_collection_with_different_payer() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![], }, ) .await; @@ -132,6 +134,7 @@ async fn create_collection_with_plugins() { rule_set: RuleSet::ProgramDenyList(vec![]), }), }], + external_plugin_adapters: vec![], }, ) .await; @@ -172,6 +175,7 @@ async fn create_collection_with_different_update_authority() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![], }, ) .await; @@ -233,6 +237,7 @@ async fn create_collection_with_plugins_with_different_plugin_authority() { rule_set: RuleSet::ProgramDenyList(vec![]), }), }], + external_plugin_adapters: vec![], }, ) .await; diff --git a/clients/rust/tests/create_collection_with_external_plugins.rs b/clients/rust/tests/create_collection_with_external_plugins.rs index 517e566c..79568e3f 100644 --- a/clients/rust/tests/create_collection_with_external_plugins.rs +++ b/clients/rust/tests/create_collection_with_external_plugins.rs @@ -1,18 +1,46 @@ #![cfg(feature = "test-sbf")] pub mod setup; +use serde_json::json; +use std::borrow::BorrowMut; + use mpl_core::{ + accounts::BaseCollectionV1, + convert_external_plugin_adapter_data_to_string, errors::MplCoreError, + fetch_external_plugin_adapter, fetch_external_plugin_adapter_data_info, + fetch_wrapped_external_plugin_adapter, + instructions::WriteCollectionExternalPluginAdapterDataV1Builder, types::{ - ExternalCheckResult, ExternalPluginAdapterInitInfo, HookableLifecycleEvent, - LifecycleHookInitInfo, OracleInitInfo, PluginAuthority, + AppData, AppDataInitInfo, ExternalCheckResult, ExternalPluginAdapter, + ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + HookableLifecycleEvent, LifecycleHookInitInfo, Oracle, OracleInitInfo, PluginAuthority, + ValidationResultsOffset, }, + Collection, }; pub use setup::*; use solana_program::pubkey; use solana_program_test::tokio; -use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer}; +use solana_sdk::{ + account_info::AccountInfo, pubkey::Pubkey, signature::Keypair, signer::Signer, + transaction::Transaction, +}; + +#[tokio::test] +#[ignore] +async fn test_create_lifecycle_hook_on_collection() { + // Note we can reference the asset version of this test when ready to implement. + todo!() +} + +#[tokio::test] +#[ignore] +async fn test_cannot_create_lifecycle_hook_with_duplicate_lifecycle_checks_on_collection() { + // Note we can reference the asset version of this test when ready to implement. + todo!() +} #[tokio::test] async fn test_temporarily_cannot_create_lifecycle_hook_on_collection() { @@ -89,6 +117,11 @@ async fn test_create_oracle_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::Oracle(Oracle { + base_address: Pubkey::default(), + base_address_config: None, + results_offset: ValidationResultsOffset::NoOffset, + })], }, ) .await; @@ -131,3 +164,208 @@ async fn test_cannot_create_oracle_with_duplicate_lifecycle_checks_on_collection assert_custom_instruction_error!(0, error, MplCoreError::DuplicateLifecycleChecks); } + +#[tokio::test] +async fn test_create_app_data_on_collection() { + let mut context = program_test().start_with_context().await; + + let collection = Keypair::new(); + create_collection( + &mut context, + CreateCollectionHelperArgs { + collection: &collection, + update_authority: None, + payer: None, + name: None, + uri: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: None, + }, + )], + }, + ) + .await + .unwrap(); + + let update_authority = context.payer.pubkey(); + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Binary, + })], + }, + ) + .await; +} + +#[tokio::test] +async fn test_create_and_fetch_app_data_on_collection() { + let mut context = program_test().start_with_context().await; + + let collection = Keypair::new(); + create_collection( + &mut context, + CreateCollectionHelperArgs { + collection: &collection, + update_authority: None, + payer: None, + name: None, + uri: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: Some(ExternalPluginAdapterSchema::Json), + }, + )], + }, + ) + .await + .unwrap(); + + let update_authority = context.payer.pubkey(); + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Json, + })], + }, + ) + .await; + + // Test JSON. + let test_json_obj = json!({ + "message": "Hello", + "target": "world" + }); + let test_json_str = serde_json::to_string(&test_json_obj).unwrap(); + let test_json_vec = test_json_str.as_bytes().to_vec(); + + // Write data. + let ix = WriteCollectionExternalPluginAdapterDataV1Builder::new() + .collection(collection.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(test_json_vec) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + // Get account. + let mut account = context + .banks_client + .get_account(collection.pubkey()) + .await + .unwrap() + .unwrap(); + + let binding = collection.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account.lamports, + account.data.borrow_mut(), + &account.owner, + false, + 0, + ); + + // Fetch external plugin adapter two ways. + // First, get the external plugin adapter in its enum. + let (registry_record, external_plugin) = + fetch_wrapped_external_plugin_adapter::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + let inner_app_data = match external_plugin { + ExternalPluginAdapter::AppData(app_data) => app_data, + _ => panic!("Unexpected external plugin adapter"), + }; + + // Second, get the inner `AppData` object directly. + let (auth, app_data, offset) = fetch_external_plugin_adapter::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + // Validate the data matches between the two fetches. + assert_eq!(registry_record.authority, auth); + assert_eq!(inner_app_data, app_data); + + println!("App data: {:#?}", app_data); + println!("Auth: {:#?}", auth); + println!("Offset: {:#?}", offset); + + // Fetch the actual app data. Validate multiple methods. + + // First, get app data data offset and length directly. + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + // Second, get app data offset and length from a full `Collection` deserialization. + let full_collection = Collection::from_bytes(&account.data).unwrap(); + let app_data_with_data = full_collection + .external_plugin_adapter_list + .app_data + .first() + .unwrap(); + + // Validate data matches between two methods. + assert_eq!(data_offset, app_data_with_data.data_offset); + assert_eq!(data_len, app_data_with_data.data_len); + + // Convert data to string. + let data_end = data_offset.checked_add(data_len).unwrap(); + let data_slice = &account.data[data_offset..data_end]; + let data_string = convert_external_plugin_adapter_data_to_string(&app_data.schema, data_slice); + + // Validate app data. + assert_eq!(data_string, test_json_str); + assert_eq!(data_len, 36); + + println!("Data string: {:#?}", data_string); + println!("Data offset: {:#?}", data_offset); + println!("Data len: {:#?}", data_len); +} diff --git a/clients/rust/tests/create_with_external_plugins.rs b/clients/rust/tests/create_with_external_plugins.rs index 411e48ee..484b81e7 100644 --- a/clients/rust/tests/create_with_external_plugins.rs +++ b/clients/rust/tests/create_with_external_plugins.rs @@ -1,19 +1,32 @@ #![cfg(feature = "test-sbf")] pub mod setup; +use serde_json::json; +use std::borrow::BorrowMut; + use mpl_core::{ + accounts::BaseAssetV1, + convert_external_plugin_adapter_data_to_string, errors::MplCoreError, + fetch_external_plugin_adapter, fetch_external_plugin_adapter_data_info, + fetch_wrapped_external_plugin_adapter, + instructions::WriteExternalPluginAdapterDataV1Builder, types::{ - DataStore, DataStoreInitInfo, ExternalCheckResult, ExternalPluginAdapter, - ExternalPluginAdapterInitInfo, ExternalPluginAdapterSchema, HookableLifecycleEvent, - LifecycleHook, LifecycleHookInitInfo, Oracle, OracleInitInfo, PluginAuthority, - UpdateAuthority, ValidationResultsOffset, + AppData, AppDataInitInfo, ExternalCheckResult, ExternalPluginAdapter, + ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + HookableLifecycleEvent, LifecycleHook, LifecycleHookInitInfo, Oracle, OracleInitInfo, + PluginAuthority, UpdateAuthority, ValidationResultsOffset, }, + Asset, }; + pub use setup::*; use solana_program::pubkey; use solana_program_test::tokio; -use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer}; +use solana_sdk::{ + account_info::AccountInfo, pubkey::Pubkey, signature::Keypair, signer::Signer, + transaction::Transaction, +}; #[tokio::test] #[ignore] @@ -159,41 +172,6 @@ async fn test_temporarily_cannot_create_lifecycle_hook() { assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); } -#[tokio::test] -async fn test_temporarily_cannot_create_lifecycle_hook_on_collection() { - let mut context = program_test().start_with_context().await; - - let collection = Keypair::new(); - let error = create_collection( - &mut context, - CreateCollectionHelperArgs { - collection: &collection, - update_authority: None, - payer: None, - name: None, - uri: None, - plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::LifecycleHook( - LifecycleHookInitInfo { - hooked_program: pubkey!("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), - init_plugin_authority: Some(PluginAuthority::UpdateAuthority), - lifecycle_checks: vec![( - HookableLifecycleEvent::Transfer, - ExternalCheckResult { flags: 1 }, - )], - extra_accounts: None, - data_authority: Some(PluginAuthority::UpdateAuthority), - schema: None, - }, - )], - }, - ) - .await - .unwrap_err(); - - assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); -} - #[tokio::test] async fn test_create_oracle() { let mut context = program_test().start_with_context().await; @@ -291,8 +269,7 @@ async fn test_cannot_create_oracle_with_duplicate_lifecycle_checks() { } #[tokio::test] -#[ignore] -async fn test_create_data_store() { +async fn test_create_app_data() { let mut context = program_test().start_with_context().await; let asset = Keypair::new(); @@ -309,8 +286,8 @@ async fn test_create_data_store() { update_authority: None, collection: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { init_plugin_authority: Some(PluginAuthority::UpdateAuthority), data_authority: PluginAuthority::UpdateAuthority, schema: None, @@ -332,7 +309,7 @@ async fn test_create_data_store() { name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapter::DataStore(DataStore { + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { data_authority: PluginAuthority::UpdateAuthority, schema: ExternalPluginAdapterSchema::Binary, })], @@ -342,11 +319,11 @@ async fn test_create_data_store() { } #[tokio::test] -async fn test_temporarily_cannot_create_data_store() { +async fn test_create_and_fetch_app_data() { let mut context = program_test().start_with_context().await; let asset = Keypair::new(); - let error = create_asset( + create_asset( &mut context, CreateAssetHelperArgs { owner: None, @@ -359,46 +336,146 @@ async fn test_temporarily_cannot_create_data_store() { update_authority: None, collection: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { init_plugin_authority: Some(PluginAuthority::UpdateAuthority), data_authority: PluginAuthority::UpdateAuthority, - schema: None, + schema: Some(ExternalPluginAdapterSchema::Json), }, )], }, ) .await - .unwrap_err(); - - assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); -} - -#[tokio::test] -async fn test_temporarily_cannot_create_data_store_on_collection() { - let mut context = program_test().start_with_context().await; + .unwrap(); - let collection = Keypair::new(); - let error = create_collection( + let owner = context.payer.pubkey(); + let update_authority = context.payer.pubkey(); + assert_asset( &mut context, - CreateCollectionHelperArgs { - collection: &collection, - update_authority: None, - payer: None, + AssertAssetHelperArgs { + asset: asset.pubkey(), + owner, + update_authority: Some(UpdateAuthority::Address(update_authority)), name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { - init_plugin_authority: Some(PluginAuthority::UpdateAuthority), - data_authority: PluginAuthority::UpdateAuthority, - schema: None, - }, - )], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Json, + })], }, ) - .await - .unwrap_err(); + .await; - assert_custom_instruction_error!(0, error, MplCoreError::NotAvailable); + // Test JSON. + let test_json_obj = json!({ + "message": "Hello", + "target": "world" + }); + let test_json_str = serde_json::to_string(&test_json_obj).unwrap(); + let test_json_vec = test_json_str.as_bytes().to_vec(); + + // Write data. + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(test_json_vec) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + // Get account. + let mut account = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account.lamports, + account.data.borrow_mut(), + &account.owner, + false, + 0, + ); + + // Fetch external plugin adapter two ways. + // First, get the external plugin adapter in its enum. + let (registry_record, external_plugin) = fetch_wrapped_external_plugin_adapter::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + let inner_app_data = match external_plugin { + ExternalPluginAdapter::AppData(app_data) => app_data, + _ => panic!("Unexpected external plugin adapter"), + }; + + // Second, get the inner `AppData` object directly. + let (auth, app_data, offset) = fetch_external_plugin_adapter::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + // Validate the data matches between the two fetches. + assert_eq!(registry_record.authority, auth); + assert_eq!(inner_app_data, app_data); + + println!("App data: {:#?}", app_data); + println!("Auth: {:#?}", auth); + println!("Offset: {:#?}", offset); + + // Fetch the actual app data. Validate multiple methods. + + // First, get app data data offset and length directly. + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .unwrap(); + + // Second, get app data offset and length from a full `Asset` deserialization. + let full_asset = Asset::from_bytes(&account.data).unwrap(); + let app_data_with_data = full_asset + .external_plugin_adapter_list + .app_data + .first() + .unwrap(); + + // Validate data matches between two methods. + assert_eq!(data_offset, app_data_with_data.data_offset); + assert_eq!(data_len, app_data_with_data.data_len); + + // Convert data to string. + let data_end = data_offset.checked_add(data_len).unwrap(); + let data_slice = &account.data[data_offset..data_end]; + let data_string = convert_external_plugin_adapter_data_to_string(&app_data.schema, data_slice); + + // Validate app data. + assert_eq!(data_string, test_json_str); + assert_eq!(data_len, 36); + + println!("Data string: {:#?}", data_string); + println!("Data offset: {:#?}", data_offset); + println!("Data len: {:#?}", data_len); } diff --git a/clients/rust/tests/remove_external_plugins.rs b/clients/rust/tests/remove_external_plugins.rs index 6e1a99ca..17e4634c 100644 --- a/clients/rust/tests/remove_external_plugins.rs +++ b/clients/rust/tests/remove_external_plugins.rs @@ -3,7 +3,7 @@ pub mod setup; use mpl_core::{ instructions::RemoveExternalPluginAdapterV1Builder, types::{ - DataStore, DataStoreInitInfo, ExternalCheckResult, ExternalPluginAdapter, + AppData, AppDataInitInfo, ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, HookableLifecycleEvent, LifecycleHook, LifecycleHookInitInfo, Oracle, OracleInitInfo, PluginAuthority, UpdateAuthority, ValidationResultsOffset, @@ -189,8 +189,7 @@ async fn test_remove_oracle() { } #[tokio::test] -#[ignore] -async fn test_remove_data_store() { +async fn test_remove_app_data() { let mut context = program_test().start_with_context().await; let asset = Keypair::new(); @@ -207,8 +206,8 @@ async fn test_remove_data_store() { update_authority: None, collection: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { init_plugin_authority: Some(PluginAuthority::UpdateAuthority), data_authority: PluginAuthority::UpdateAuthority, schema: None, @@ -230,7 +229,7 @@ async fn test_remove_data_store() { name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapter::DataStore(DataStore { + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { data_authority: PluginAuthority::UpdateAuthority, schema: ExternalPluginAdapterSchema::Binary, })], @@ -241,7 +240,7 @@ async fn test_remove_data_store() { let ix = RemoveExternalPluginAdapterV1Builder::new() .asset(asset.pubkey()) .payer(context.payer.pubkey()) - .key(ExternalPluginAdapterKey::DataStore( + .key(ExternalPluginAdapterKey::AppData( PluginAuthority::UpdateAuthority, )) .instruction(); diff --git a/clients/rust/tests/remove_external_plugins_on_collection.rs b/clients/rust/tests/remove_external_plugins_on_collection.rs index 3cbc5c18..ef19e125 100644 --- a/clients/rust/tests/remove_external_plugins_on_collection.rs +++ b/clients/rust/tests/remove_external_plugins_on_collection.rs @@ -3,8 +3,9 @@ pub mod setup; use mpl_core::{ instructions::RemoveCollectionExternalPluginAdapterV1Builder, types::{ - ExternalCheckResult, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, - HookableLifecycleEvent, OracleInitInfo, PluginAuthority, + AppData, AppDataInitInfo, ExternalCheckResult, ExternalPluginAdapter, + ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + HookableLifecycleEvent, Oracle, OracleInitInfo, PluginAuthority, ValidationResultsOffset, }, }; pub use setup::*; @@ -12,6 +13,13 @@ pub use setup::*; use solana_program_test::tokio; use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction}; +#[tokio::test] +#[ignore] +async fn test_remove_lifecycle_hook_on_collection() { + // Note we can reference the asset version of this test when ready to implement. + todo!() +} + #[tokio::test] async fn test_remove_oracle_on_collection() { let mut context = program_test().start_with_context().await; @@ -52,6 +60,11 @@ async fn test_remove_oracle_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::Oracle(Oracle { + base_address: Pubkey::default(), + base_address_config: None, + results_offset: ValidationResultsOffset::NoOffset, + })], }, ) .await; @@ -81,6 +94,85 @@ async fn test_remove_oracle_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![], + }, + ) + .await; +} + +#[tokio::test] +async fn test_remove_app_data_on_collection() { + let mut context = program_test().start_with_context().await; + + let collection = Keypair::new(); + create_collection( + &mut context, + CreateCollectionHelperArgs { + collection: &collection, + update_authority: None, + payer: None, + name: None, + uri: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: None, + }, + )], + }, + ) + .await + .unwrap(); + + let update_authority = context.payer.pubkey(); + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Binary, + })], + }, + ) + .await; + + let ix = RemoveCollectionExternalPluginAdapterV1Builder::new() + .collection(collection.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![], }, ) .await; diff --git a/clients/rust/tests/setup/mod.rs b/clients/rust/tests/setup/mod.rs index 6a7c402e..18dbe9e8 100644 --- a/clients/rust/tests/setup/mod.rs +++ b/clients/rust/tests/setup/mod.rs @@ -136,7 +136,7 @@ pub async fn assert_asset(context: &mut ProgramTestContext, input: AssertAssetHe input.external_plugin_adapters.len(), asset.external_plugin_adapter_list.lifecycle_hooks.len() + asset.external_plugin_adapter_list.oracles.len() - + asset.external_plugin_adapter_list.data_stores.len() + + asset.external_plugin_adapter_list.app_data.len() ); for plugin in input.external_plugin_adapters { match plugin { @@ -144,16 +144,37 @@ pub async fn assert_asset(context: &mut ProgramTestContext, input: AssertAssetHe assert!(asset .external_plugin_adapter_list .lifecycle_hooks - .contains(&hook)) + .iter() + .any(|lifecyle_hook_with_data| lifecyle_hook_with_data.base == hook)) } ExternalPluginAdapter::Oracle(oracle) => { assert!(asset.external_plugin_adapter_list.oracles.contains(&oracle)) } - ExternalPluginAdapter::DataStore(data_store) => { + ExternalPluginAdapter::AppData(app_data) => { + assert!(asset + .external_plugin_adapter_list + .app_data + .iter() + .any(|app_data_with_data| app_data_with_data.base == app_data)) + } + ExternalPluginAdapter::LinkedLifecycleHook(hook) => { + assert!(asset + .external_plugin_adapter_list + .linked_lifecycle_hooks + .contains(&hook)) + } + ExternalPluginAdapter::LinkedAppData(app_data) => { + assert!(asset + .external_plugin_adapter_list + .linked_app_data + .contains(&app_data)) + } + ExternalPluginAdapter::DataSection(data) => { assert!(asset .external_plugin_adapter_list - .data_stores - .contains(&data_store)) + .data_sections + .iter() + .any(|data_sections_with_data| data_sections_with_data.base == data)) } } } @@ -211,6 +232,7 @@ pub struct AssertCollectionHelperArgs { pub current_size: u32, // TODO use PluginList type here pub plugins: Vec, + pub external_plugin_adapters: Vec, } pub async fn assert_collection( @@ -264,7 +286,58 @@ pub async fn assert_collection( } } - // TODO validate external plugin adapters here. + assert_eq!( + input.external_plugin_adapters.len(), + collection + .external_plugin_adapter_list + .lifecycle_hooks + .len() + + collection.external_plugin_adapter_list.oracles.len() + + collection.external_plugin_adapter_list.app_data.len() + ); + for plugin in input.external_plugin_adapters { + match plugin { + ExternalPluginAdapter::LifecycleHook(hook) => { + assert!(collection + .external_plugin_adapter_list + .lifecycle_hooks + .iter() + .any(|lifecyle_hook_with_data| lifecyle_hook_with_data.base == hook)) + } + ExternalPluginAdapter::Oracle(oracle) => { + assert!(collection + .external_plugin_adapter_list + .oracles + .contains(&oracle)) + } + ExternalPluginAdapter::AppData(app_data) => { + assert!(collection + .external_plugin_adapter_list + .app_data + .iter() + .any(|app_data_with_data| app_data_with_data.base == app_data)) + } + ExternalPluginAdapter::LinkedLifecycleHook(hook) => { + assert!(collection + .external_plugin_adapter_list + .linked_lifecycle_hooks + .contains(&hook)) + } + ExternalPluginAdapter::LinkedAppData(app_data) => { + assert!(collection + .external_plugin_adapter_list + .linked_app_data + .contains(&app_data)) + } + ExternalPluginAdapter::DataSection(data) => { + assert!(collection + .external_plugin_adapter_list + .data_sections + .iter() + .any(|data_sections_with_data| data_sections_with_data.base == data)) + } + } + } } pub async fn airdrop( diff --git a/clients/rust/tests/update_external_plugins.rs b/clients/rust/tests/update_external_plugins.rs index 22972f9e..d4397509 100644 --- a/clients/rust/tests/update_external_plugins.rs +++ b/clients/rust/tests/update_external_plugins.rs @@ -4,11 +4,11 @@ use mpl_core::{ errors::MplCoreError, instructions::UpdateExternalPluginAdapterV1Builder, types::{ - DataStore, DataStoreInitInfo, DataStoreUpdateInfo, ExternalCheckResult, - ExternalPluginAdapter, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, - ExternalPluginAdapterSchema, ExternalPluginAdapterUpdateInfo, HookableLifecycleEvent, - LifecycleHook, LifecycleHookInitInfo, LifecycleHookUpdateInfo, Oracle, OracleInitInfo, - OracleUpdateInfo, PluginAuthority, UpdateAuthority, ValidationResultsOffset, + AppData, AppDataInitInfo, AppDataUpdateInfo, ExternalCheckResult, ExternalPluginAdapter, + ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + ExternalPluginAdapterUpdateInfo, HookableLifecycleEvent, LifecycleHook, + LifecycleHookInitInfo, LifecycleHookUpdateInfo, Oracle, OracleInitInfo, OracleUpdateInfo, + PluginAuthority, UpdateAuthority, ValidationResultsOffset, }, }; pub use setup::*; @@ -403,8 +403,7 @@ async fn test_cannot_update_oracle_to_have_duplicate_lifecycle_checks() { } #[tokio::test] -#[ignore] -async fn test_update_data_store() { +async fn test_update_app_data() { let mut context = program_test().start_with_context().await; let asset = Keypair::new(); @@ -421,8 +420,8 @@ async fn test_update_data_store() { update_authority: None, collection: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::DataStore( - DataStoreInitInfo { + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { init_plugin_authority: Some(PluginAuthority::UpdateAuthority), data_authority: PluginAuthority::UpdateAuthority, schema: None, @@ -444,7 +443,7 @@ async fn test_update_data_store() { name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapter::DataStore(DataStore { + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { data_authority: PluginAuthority::UpdateAuthority, schema: ExternalPluginAdapterSchema::Binary, })], @@ -455,11 +454,11 @@ async fn test_update_data_store() { let ix = UpdateExternalPluginAdapterV1Builder::new() .asset(asset.pubkey()) .payer(context.payer.pubkey()) - .key(ExternalPluginAdapterKey::DataStore( + .key(ExternalPluginAdapterKey::AppData( PluginAuthority::UpdateAuthority, )) - .update_info(ExternalPluginAdapterUpdateInfo::DataStore( - DataStoreUpdateInfo { + .update_info(ExternalPluginAdapterUpdateInfo::AppData( + AppDataUpdateInfo { schema: Some(ExternalPluginAdapterSchema::Json), }, )) @@ -483,7 +482,7 @@ async fn test_update_data_store() { name: None, uri: None, plugins: vec![], - external_plugin_adapters: vec![ExternalPluginAdapter::DataStore(DataStore { + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { data_authority: PluginAuthority::UpdateAuthority, schema: ExternalPluginAdapterSchema::Json, })], diff --git a/clients/rust/tests/update_external_plugins_on_collection.rs b/clients/rust/tests/update_external_plugins_on_collection.rs index bb7e89f7..bf7cbc04 100644 --- a/clients/rust/tests/update_external_plugins_on_collection.rs +++ b/clients/rust/tests/update_external_plugins_on_collection.rs @@ -4,9 +4,10 @@ use mpl_core::{ errors::MplCoreError, instructions::UpdateCollectionExternalPluginAdapterV1Builder, types::{ - ExternalCheckResult, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, - ExternalPluginAdapterUpdateInfo, HookableLifecycleEvent, OracleInitInfo, OracleUpdateInfo, - PluginAuthority, ValidationResultsOffset, + AppData, AppDataInitInfo, AppDataUpdateInfo, ExternalCheckResult, ExternalPluginAdapter, + ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, ExternalPluginAdapterSchema, + ExternalPluginAdapterUpdateInfo, HookableLifecycleEvent, Oracle, OracleInitInfo, + OracleUpdateInfo, PluginAuthority, ValidationResultsOffset, }, }; pub use setup::*; @@ -14,6 +15,20 @@ pub use setup::*; use solana_program_test::tokio; use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction}; +#[tokio::test] +#[ignore] +async fn test_update_lifecycle_hook_on_collection() { + // Note we can reference the asset version of this test when ready to implement. + todo!() +} + +#[tokio::test] +#[ignore] +async fn test_cannot_update_lifecycle_hook_to_have_duplicate_lifecycle_checks_on_collection() { + // Note we can reference the asset version of this test when ready to implement. + todo!() +} + #[tokio::test] async fn test_update_oracle_on_collection() { let mut context = program_test().start_with_context().await; @@ -54,6 +69,11 @@ async fn test_update_oracle_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::Oracle(Oracle { + base_address: Pubkey::default(), + base_address_config: None, + results_offset: ValidationResultsOffset::NoOffset, + })], }, ) .await; @@ -88,6 +108,11 @@ async fn test_update_oracle_on_collection() { num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::Oracle(Oracle { + base_address: Pubkey::default(), + base_address_config: None, + results_offset: ValidationResultsOffset::Custom(10), + })], }, ) .await; @@ -133,6 +158,11 @@ async fn test_cannot_update_oracle_to_have_duplicate_lifecycle_checks_on_collect num_minted: 0, current_size: 0, plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::Oracle(Oracle { + base_address: Pubkey::default(), + base_address_config: None, + results_offset: ValidationResultsOffset::NoOffset, + })], }, ) .await; @@ -174,3 +204,89 @@ async fn test_cannot_update_oracle_to_have_duplicate_lifecycle_checks_on_collect // TODO: Check that registry record did not get updated. } + +#[tokio::test] +async fn test_update_app_data_on_collection() { + let mut context = program_test().start_with_context().await; + + let collection = Keypair::new(); + create_collection( + &mut context, + CreateCollectionHelperArgs { + collection: &collection, + update_authority: None, + payer: None, + name: None, + uri: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: None, + }, + )], + }, + ) + .await + .unwrap(); + + let update_authority = context.payer.pubkey(); + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Binary, + })], + }, + ) + .await; + + let ix = UpdateCollectionExternalPluginAdapterV1Builder::new() + .collection(collection.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .update_info(ExternalPluginAdapterUpdateInfo::AppData( + AppDataUpdateInfo { + schema: Some(ExternalPluginAdapterSchema::Json), + }, + )) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapter::AppData(AppData { + data_authority: PluginAuthority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Json, + })], + }, + ) + .await; +} diff --git a/configs/kinobi.cjs b/configs/kinobi.cjs index c6aaf750..e5bd5f64 100755 --- a/configs/kinobi.cjs +++ b/configs/kinobi.cjs @@ -130,6 +130,19 @@ kinobi.update( }, } }, + updateV2: { + arguments: { + newUpdateAuthority: { + defaultValue: k.noneValueNode() + }, + newName: { + defaultValue: k.noneValueNode() + }, + newUri: { + defaultValue: k.noneValueNode() + }, + } + }, updateCollectionV1: { arguments: { newName: { @@ -198,6 +211,9 @@ kinobi.update( externalPluginAdapterKey: { name: "baseExternalPluginAdapterKey" }, + linkedDataKey: { + name: 'baseLinkedDataKey' + }, externalPluginAdapterInitInfo: { name: "baseExternalPluginAdapterInitInfo" }, @@ -222,14 +238,41 @@ kinobi.update( lifecycleHookUpdateInfo: { name: "baseLifecycleHookUpdateInfo" }, - dataStore: { - name: "baseDataStore" + linkedLifecycleHook: { + name: "baseLinkedLifecycleHook" + }, + linkedLifecycleHookInitInfo: { + name: "baseLinkedLifecycleHookInitInfo" + }, + linkedLifecycleHookUpdateInfo: { + name: "baseLinkedLifecycleHookUpdateInfo" + }, + appData: { + name: "baseAppData" + }, + appDataInitInfo: { + name: "baseAppDataInitInfo" + }, + appDataUpdateInfo: { + name: "baseAppDataUpdateInfo" + }, + linkedAppData: { + name: "baseLinkedAppData" + }, + linkedAppDataInitInfo: { + name: "baseLinkedAppDataInitInfo" + }, + linkedAppDataUpdateInfo: { + name: "baseLinkedAppDataUpdateInfo" + }, + dataSection: { + name: "baseDataSection" }, - dataStoreInitInfo: { - name: "baseDataStoreInitInfo" + dataSectionInitInfo: { + name: "baseDataSectionInitInfo" }, - dataStoreUpdateInfo: { - name: "baseDataStoreUpdateInfo" + dataSectionUpdateInfo: { + name: "baseDataSectionUpdateInfo" }, validationResultsOffset: { name: "baseValidationResultsOffset" diff --git a/configs/scripts/client/test-rust.sh b/configs/scripts/client/test-rust.sh index a5609c56..f22236cc 100755 --- a/configs/scripts/client/test-rust.sh +++ b/configs/scripts/client/test-rust.sh @@ -16,7 +16,7 @@ export SBF_OUT_DIR="${WORKING_DIR}/${PROGRAMS_OUTPUT}" cd ${WORKING_DIR}/clients/rust if [ ! "$(command -v $SOLFMT)" = "" ]; then - CARGO_TERM_COLOR=always cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} 2>&1 | ${SOLFMT} + CARGO_TERM_COLOR=always cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} 2>&1 | ${SOLFMT} -- --nocapture else - cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} + cargo test-sbf --sbf-out-dir ${WORKING_DIR}/${PROGRAMS_OUTPUT} ${ARGS} -- --nocapture fi \ No newline at end of file diff --git a/idls/mpl_core.json b/idls/mpl_core.json index ea9a1e4d..85960483 100644 --- a/idls/mpl_core.json +++ b/idls/mpl_core.json @@ -1819,7 +1819,16 @@ "isSigner": true, "isOptional": true, "docs": [ - "The Data Authority of the External PluginExternalPluginAdapter" + "The Data Authority of the External Plugin Adapter" + ] + }, + { + "name": "buffer", + "isMut": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "The buffer to write to the external plugin" ] }, { @@ -1878,7 +1887,16 @@ "isSigner": true, "isOptional": true, "docs": [ - "The Data Authority of the External PluginExternalPluginAdapter" + "The Data Authority of the External Plugin Adapter" + ] + }, + { + "name": "buffer", + "isMut": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "The buffer to write to the external plugin" ] }, { @@ -1911,6 +1929,83 @@ "type": "u8", "value": 29 } + }, + { + "name": "UpdateV2", + "accounts": [ + { + "name": "asset", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the asset" + ] + }, + { + "name": "collection", + "isMut": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "The collection to which the asset belongs" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for the storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The update authority or update authority delegate of the asset" + ] + }, + { + "name": "newCollection", + "isMut": true, + "isSigner": false, + "isOptional": true, + "docs": [ + "A new collection to which to move the asset" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + }, + { + "name": "logWrapper", + "isMut": false, + "isSigner": false, + "isOptional": true, + "docs": [ + "The SPL Noop Program" + ] + } + ], + "args": [ + { + "name": "updateV2Args", + "type": { + "defined": "UpdateV2Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 30 + } } ], "accounts": [ @@ -2088,6 +2183,72 @@ "fields": [] } }, + { + "name": "AppData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "dataAuthority", + "type": { + "defined": "Authority" + } + }, + { + "name": "schema", + "type": { + "defined": "ExternalPluginAdapterSchema" + } + } + ] + } + }, + { + "name": "AppDataInitInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "dataAuthority", + "type": { + "defined": "Authority" + } + }, + { + "name": "initPluginAuthority", + "type": { + "option": { + "defined": "Authority" + } + } + }, + { + "name": "schema", + "type": { + "option": { + "defined": "ExternalPluginAdapterSchema" + } + } + } + ] + } + }, + { + "name": "AppDataUpdateInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "schema", + "type": { + "option": { + "defined": "ExternalPluginAdapterSchema" + } + } + } + ] + } + }, { "name": "Attribute", "type": { @@ -2160,14 +2321,14 @@ } }, { - "name": "DataStore", + "name": "DataSection", "type": { "kind": "struct", "fields": [ { - "name": "dataAuthority", + "name": "parentKey", "type": { - "defined": "Authority" + "defined": "LinkedDataKey" } }, { @@ -2180,40 +2341,161 @@ } }, { - "name": "DataStoreInitInfo", + "name": "DataSectionInitInfo", "type": { "kind": "struct", "fields": [ { - "name": "dataAuthority", + "name": "parentKey", "type": { - "defined": "Authority" + "defined": "LinkedDataKey" } }, { - "name": "initPluginAuthority", + "name": "schema", + "type": { + "defined": "ExternalPluginAdapterSchema" + } + } + ] + } + }, + { + "name": "DataSectionUpdateInfo", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "Edition", + "type": { + "kind": "struct", + "fields": [ + { + "name": "number", + "type": "u32" + } + ] + } + }, + { + "name": "FreezeDelegate", + "type": { + "kind": "struct", + "fields": [ + { + "name": "frozen", + "type": "bool" + } + ] + } + }, + { + "name": "ImmutableMetadata", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "ExternalCheckResult", + "type": { + "kind": "struct", + "fields": [ + { + "name": "flags", + "type": "u32" + } + ] + } + }, + { + "name": "LifecycleHook", + "type": { + "kind": "struct", + "fields": [ + { + "name": "hookedProgram", + "type": "publicKey" + }, + { + "name": "extraAccounts", "type": { "option": { - "defined": "Authority" + "vec": { + "defined": "ExtraAccount" + } } } }, { - "name": "schema", + "name": "dataAuthority", "type": { "option": { - "defined": "ExternalPluginAdapterSchema" + "defined": "Authority" } } + }, + { + "name": "schema", + "type": { + "defined": "ExternalPluginAdapterSchema" + } } ] } }, { - "name": "DataStoreUpdateInfo", + "name": "LifecycleHookInitInfo", "type": { "kind": "struct", "fields": [ + { + "name": "hookedProgram", + "type": "publicKey" + }, + { + "name": "initPluginAuthority", + "type": { + "option": { + "defined": "Authority" + } + } + }, + { + "name": "lifecycleChecks", + "type": { + "vec": { + "tuple": [ + { + "defined": "HookableLifecycleEvent" + }, + { + "defined": "ExternalCheckResult" + } + ] + } + } + }, + { + "name": "extraAccounts", + "type": { + "option": { + "vec": { + "defined": "ExtraAccount" + } + } + } + }, + { + "name": "dataAuthority", + "type": { + "option": { + "defined": "Authority" + } + } + }, { "name": "schema", "type": { @@ -2226,50 +2508,116 @@ } }, { - "name": "Edition", + "name": "LifecycleHookUpdateInfo", "type": { "kind": "struct", "fields": [ { - "name": "number", - "type": "u32" + "name": "lifecycleChecks", + "type": { + "option": { + "vec": { + "tuple": [ + { + "defined": "HookableLifecycleEvent" + }, + { + "defined": "ExternalCheckResult" + } + ] + } + } + } + }, + { + "name": "extraAccounts", + "type": { + "option": { + "vec": { + "defined": "ExtraAccount" + } + } + } + }, + { + "name": "schema", + "type": { + "option": { + "defined": "ExternalPluginAdapterSchema" + } + } } ] } }, { - "name": "FreezeDelegate", + "name": "LinkedAppData", "type": { "kind": "struct", "fields": [ { - "name": "frozen", - "type": "bool" + "name": "dataAuthority", + "type": { + "defined": "Authority" + } + }, + { + "name": "schema", + "type": { + "defined": "ExternalPluginAdapterSchema" + } } ] } }, { - "name": "ImmutableMetadata", + "name": "LinkedAppDataInitInfo", "type": { "kind": "struct", - "fields": [] + "fields": [ + { + "name": "dataAuthority", + "type": { + "defined": "Authority" + } + }, + { + "name": "initPluginAuthority", + "type": { + "option": { + "defined": "Authority" + } + } + }, + { + "name": "schema", + "type": { + "option": { + "defined": "ExternalPluginAdapterSchema" + } + } + } + ] } }, { - "name": "ExternalCheckResult", + "name": "LinkedAppDataUpdateInfo", "type": { "kind": "struct", "fields": [ { - "name": "flags", - "type": "u32" + "name": "schema", + "type": { + "option": { + "defined": "ExternalPluginAdapterSchema" + } + } } ] } }, { - "name": "LifecycleHook", + "name": "LinkedLifecycleHook", "type": { "kind": "struct", "fields": [ @@ -2305,7 +2653,7 @@ } }, { - "name": "LifecycleHookInitInfo", + "name": "LinkedLifecycleHookInitInfo", "type": { "kind": "struct", "fields": [ @@ -2366,7 +2714,7 @@ } }, { - "name": "LifecycleHookUpdateInfo", + "name": "LinkedLifecycleHookUpdateInfo", "type": { "kind": "struct", "fields": [ @@ -3179,6 +3527,34 @@ ] } }, + { + "name": "UpdateV2Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newName", + "type": { + "option": "string" + } + }, + { + "name": "newUri", + "type": { + "option": "string" + } + }, + { + "name": "newUpdateAuthority", + "type": { + "option": { + "defined": "UpdateAuthority" + } + } + } + ] + } + }, { "name": "UpdateCollectionV1Args", "type": { @@ -3280,7 +3656,9 @@ }, { "name": "data", - "type": "bytes" + "type": { + "option": "bytes" + } } ] } @@ -3298,7 +3676,9 @@ }, { "name": "data", - "type": "bytes" + "type": { + "option": "bytes" + } } ] } @@ -3586,7 +3966,16 @@ "name": "Oracle" }, { - "name": "DataStore" + "name": "AppData" + }, + { + "name": "LinkedLifecycleHook" + }, + { + "name": "LinkedAppData" + }, + { + "name": "DataSection" } ] } @@ -3613,10 +4002,34 @@ ] }, { - "name": "DataStore", + "name": "AppData", "fields": [ { - "defined": "DataStore" + "defined": "AppData" + } + ] + }, + { + "name": "LinkedLifecycleHook", + "fields": [ + { + "defined": "LinkedLifecycleHook" + } + ] + }, + { + "name": "LinkedAppData", + "fields": [ + { + "defined": "LinkedAppData" + } + ] + }, + { + "name": "DataSection", + "fields": [ + { + "defined": "DataSection" } ] } @@ -3831,10 +4244,34 @@ ] }, { - "name": "DataStore", + "name": "AppData", "fields": [ { - "defined": "DataStoreInitInfo" + "defined": "AppDataInitInfo" + } + ] + }, + { + "name": "LinkedLifecycleHook", + "fields": [ + { + "defined": "LinkedLifecycleHookInitInfo" + } + ] + }, + { + "name": "LinkedAppData", + "fields": [ + { + "defined": "LinkedAppDataInitInfo" + } + ] + }, + { + "name": "DataSection", + "fields": [ + { + "defined": "DataSectionInitInfo" } ] } @@ -3863,10 +4300,26 @@ ] }, { - "name": "DataStore", + "name": "AppData", + "fields": [ + { + "defined": "AppDataUpdateInfo" + } + ] + }, + { + "name": "LinkedLifecycleHook", + "fields": [ + { + "defined": "LinkedLifecycleHookUpdateInfo" + } + ] + }, + { + "name": "LinkedAppData", "fields": [ { - "defined": "DataStoreUpdateInfo" + "defined": "LinkedAppDataUpdateInfo" } ] } @@ -3891,7 +4344,51 @@ ] }, { - "name": "DataStore", + "name": "AppData", + "fields": [ + { + "defined": "Authority" + } + ] + }, + { + "name": "LinkedLifecycleHook", + "fields": [ + "publicKey" + ] + }, + { + "name": "LinkedAppData", + "fields": [ + { + "defined": "Authority" + } + ] + }, + { + "name": "DataSection", + "fields": [ + { + "defined": "LinkedDataKey" + } + ] + } + ] + } + }, + { + "name": "LinkedDataKey", + "type": { + "kind": "enum", + "variants": [ + { + "name": "LinkedLifecycleHook", + "fields": [ + "publicKey" + ] + }, + { + "name": "LinkedAppData", "fields": [ { "defined": "Authority" @@ -4274,12 +4771,12 @@ { "code": 31, "name": "ExternalPluginAdapterNotFound", - "msg": "External PluginExternalPluginAdapter not found" + "msg": "External Plugin Adapter not found" }, { "code": 32, "name": "ExternalPluginAdapterAlreadyExists", - "msg": "External PluginExternalPluginAdapter already exists" + "msg": "External Plugin Adapter already exists" }, { "code": 33, @@ -4330,6 +4827,31 @@ "code": 42, "name": "CollectionMustBeEmpty", "msg": "Collection must be empty to be burned" + }, + { + "code": 43, + "name": "TwoDataSources", + "msg": "Two data sources provided, only one is allowed" + }, + { + "code": 44, + "name": "UnsupportedOperation", + "msg": "External Plugin does not support this operation" + }, + { + "code": 45, + "name": "NoDataSources", + "msg": "No data sources provided, one is required" + }, + { + "code": 46, + "name": "InvalidPluginAdapterTarget", + "msg": "This plugin adapter cannot be added to an Asset" + }, + { + "code": 47, + "name": "CannotAddDataSection", + "msg": "Cannot add a Data Section without a linked external plugin" } ], "metadata": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 327da455..984c7830 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,7 +7,7 @@ settings: devDependencies: '@metaplex-foundation/amman': specifier: ^0.12.1 - version: 0.12.1(typescript@4.9.4) + version: 0.12.1(typescript@4.9.5) '@metaplex-foundation/kinobi': specifier: 0.18.8-alpha.0 version: 0.18.8-alpha.0(fastestsmallesttextencoderdecoder@1.0.22) @@ -19,12 +19,12 @@ devDependencies: version: 9.0.11 typescript: specifier: ^4.9.4 - version: 4.9.4 + version: 4.9.5 packages: - /@babel/runtime@7.24.0: - resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} + /@babel/runtime@7.24.7: + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 @@ -45,9 +45,9 @@ packages: dependencies: '@metaplex-foundation/cusper': 0.0.2 '@solana/spl-token-registry': 0.2.4574 - '@solana/web3.js': 1.91.1 + '@solana/web3.js': 1.93.0 bn.js: 5.2.1 - debug: 4.3.4 + debug: 4.3.5 js-sha3: 0.8.0 socket.io-client: 4.7.5 tweetnacl: 1.0.3 @@ -58,18 +58,18 @@ packages: - utf-8-validate dev: true - /@metaplex-foundation/amman@0.12.1(typescript@4.9.4): + /@metaplex-foundation/amman@0.12.1(typescript@4.9.5): resolution: {integrity: sha512-F3cdHr11ByLGMCrSBRvRCf5uIlhLE+5sWaHT2ZzcE6zVyDta3gs/A12ZBzYZS8ugNETNpJySfB42kMp1VZwbUA==} hasBin: true dependencies: '@metaplex-foundation/amman-client': 0.2.4 '@solana/spl-token': 0.2.0 - '@solana/web3.js': 1.91.1 + '@solana/web3.js': 1.93.0 ansi-colors: 4.1.3 bn.js: 5.2.1 buffer-hexdump: 1.0.0 date-fns: 2.30.0 - debug: 4.3.4 + debug: 4.3.5 deep-diff: 1.0.2 diff: 5.2.0 numeral: 2.0.6 @@ -77,8 +77,8 @@ packages: socket.io: 4.7.5 text-table: 0.2.0 timeago.js: 4.0.2 - ts-essentials: 9.4.1(typescript@4.9.4) - wait-on: 6.0.1(debug@4.3.4) + ts-essentials: 9.4.2(typescript@4.9.5) + wait-on: 6.0.1(debug@4.3.5) yargs: 17.7.2 transitivePeerDependencies: - bufferutil @@ -96,12 +96,12 @@ packages: resolution: {integrity: sha512-0ghdmyGnz1j6yDX52lWJOY63AvkSnxbNSYsHgn1sFnMrnnAK3O3EuaFpZdj5j0C2dRB1a+dGw2Kte7GkuPZL2A==} dependencies: '@noble/hashes': 1.4.0 - '@prettier/sync': 0.5.2(prettier@3.2.5) + '@prettier/sync': 0.5.2(prettier@3.3.2) '@solana/codecs-strings': 2.0.0-preview.1(fastestsmallesttextencoderdecoder@1.0.22) chalk: 4.1.2 json-stable-stringify: 1.1.1 nunjucks: 3.2.4 - prettier: 3.2.5 + prettier: 3.3.2 transitivePeerDependencies: - chokidar - fastestsmallesttextencoderdecoder @@ -110,8 +110,8 @@ packages: /@metaplex-foundation/rustbin@0.3.5: resolution: {integrity: sha512-m0wkRBEQB/8krwMwKBvFugufZtYwMXiGHud2cTDAv+aGXK4M90y0Hx67/wpu+AqqoQfdV8VM9YezUOHKD+Z5kA==} dependencies: - debug: 4.3.4 - semver: 7.6.0 + debug: 4.3.5 + semver: 7.6.2 text-table: 0.2.0 toml: 3.0.0 transitivePeerDependencies: @@ -123,7 +123,7 @@ packages: dependencies: '@metaplex-foundation/rustbin': 0.3.5 ansi-colors: 4.1.3 - debug: 4.3.4 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true @@ -139,13 +139,13 @@ packages: engines: {node: '>= 16'} dev: true - /@prettier/sync@0.5.2(prettier@3.2.5): + /@prettier/sync@0.5.2(prettier@3.3.2): resolution: {integrity: sha512-Yb569su456XNx5BsH/Vyem7xD6g/y9iLmLUzRKM1a/dhU/D7HqqvkAG72znulXlMXztbV0iiu9O5AL8K98TzZQ==} peerDependencies: prettier: '*' dependencies: make-synchronized: 0.2.9 - prettier: 3.2.5 + prettier: 3.3.2 dev: true /@sideway/address@4.1.5: @@ -162,8 +162,8 @@ packages: resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} dev: true - /@socket.io/component-emitter@3.1.0: - resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + /@socket.io/component-emitter@3.1.2: + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} dev: true /@solana/buffer-layout-utils@0.2.0: @@ -171,7 +171,7 @@ packages: engines: {node: '>= 10'} dependencies: '@solana/buffer-layout': 4.0.1 - '@solana/web3.js': 1.91.1 + '@solana/web3.js': 1.93.0 bigint-buffer: 1.1.5 bignumber.js: 9.1.2 transitivePeerDependencies: @@ -216,7 +216,7 @@ packages: hasBin: true dependencies: chalk: 5.3.0 - commander: 12.0.0 + commander: 12.1.0 dev: true /@solana/spl-token-registry@0.2.4574: @@ -232,7 +232,7 @@ packages: dependencies: '@solana/buffer-layout': 4.0.1 '@solana/buffer-layout-utils': 0.2.0 - '@solana/web3.js': 1.91.1 + '@solana/web3.js': 1.93.0 start-server-and-test: 1.15.4 transitivePeerDependencies: - bufferutil @@ -241,10 +241,10 @@ packages: - utf-8-validate dev: true - /@solana/web3.js@1.91.1: - resolution: {integrity: sha512-cPgjZXm688oM9cULvJ8u2VH6Qp5rvptE1N1VODVxn2mAbpZsWrvWNPjmASkMYT/HzyrtqFkPvFdSHg8Xjt7aQA==} + /@solana/web3.js@1.93.0: + resolution: {integrity: sha512-suf4VYwWxERz4tKoPpXCRHFRNst7jmcFUaD65kII+zg9urpy5PeeqgLV6G5eWGzcVzA9tZeXOju1A1Y+0ojEVw==} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.7 '@noble/curves': 1.4.0 '@noble/hashes': 1.4.0 '@solana/buffer-layout': 4.0.1 @@ -257,14 +257,20 @@ packages: fast-stable-stringify: 1.0.0 jayson: 4.1.0 node-fetch: 2.7.0 - rpc-websockets: 7.9.0 - superstruct: 0.14.2 + rpc-websockets: 9.0.1 + superstruct: 1.0.4 transitivePeerDependencies: - bufferutil - encoding - utf-8-validate dev: true + /@swc/helpers@0.5.11: + resolution: {integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==} + dependencies: + tslib: 2.6.3 + dev: true + /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: @@ -278,25 +284,35 @@ packages: /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 20.11.28 + '@types/node': 20.14.2 dev: true /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@20.11.28: - resolution: {integrity: sha512-M/GPWVS2wLkSkNHVeLkrF2fD5Lx5UC4PxA0uZcKc6QqbIQUJyW1jVjueJYi1z8n0I5PxYrtpnPnWglE+y9A0KA==} + /@types/node@20.14.2: + resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} dependencies: undici-types: 5.26.5 dev: true + /@types/uuid@8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + /@types/ws@7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: '@types/node': 12.20.55 dev: true + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 20.14.2 + dev: true + /JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -353,10 +369,10 @@ packages: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} dev: true - /axios@0.25.0(debug@4.3.4): + /axios@0.25.0(debug@4.3.5): resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} dependencies: - follow-redirects: 1.15.6(debug@4.3.4) + follow-redirects: 1.15.6(debug@4.3.5) transitivePeerDependencies: - debug dev: true @@ -441,7 +457,7 @@ packages: engines: {node: '>=6.14.2'} requiresBuild: true dependencies: - node-gyp-build: 4.8.0 + node-gyp-build: 4.8.1 dev: true /call-bind@1.0.7: @@ -500,8 +516,8 @@ packages: delayed-stream: 1.0.0 dev: true - /commander@12.0.0: - resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} + /commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} dev: true @@ -546,7 +562,7 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.24.7 dev: true /debug@4.3.4: @@ -561,6 +577,18 @@ packages: ms: 2.1.2 dev: true + /debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + /deep-diff@1.0.2: resolution: {integrity: sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg==} dev: true @@ -600,8 +628,8 @@ packages: /engine.io-client@6.5.3: resolution: {integrity: sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==} dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 engine.io-parser: 5.2.2 ws: 8.11.0 xmlhttprequest-ssl: 2.0.0 @@ -622,12 +650,12 @@ packages: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 20.11.28 + '@types/node': 20.14.2 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.2 cors: 2.8.5 - debug: 4.3.4 + debug: 4.3.5 engine.io-parser: 5.2.2 ws: 8.11.0 transitivePeerDependencies: @@ -675,8 +703,8 @@ packages: through: 2.3.8 dev: true - /eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} dev: true /execa@5.1.1: @@ -723,6 +751,18 @@ packages: debug: 4.3.4 dev: true + /follow-redirects@1.15.6(debug@4.3.5): + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.5 + dev: true + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -864,8 +904,8 @@ packages: - utf-8-validate dev: true - /joi@17.12.2: - resolution: {integrity: sha512-RonXAIzCiHLc8ss3Ibuz45u28GOsWE1UpfDXLbN/9NKbL4tCJf8TWYVKsoYuuh+sAUt7fsSNpA+r2+TBA6Wjmw==} + /joi@17.13.1: + resolution: {integrity: sha512-vaBlIKCyo4FCUtCm7Eu4QZd/q02bWcxfUO6YSXAZOWF6gzcLBeba8kwotUdYJjDLW8Cz8RywsSOqiNJZW0mNvg==} dependencies: '@hapi/hoek': 9.3.0 '@hapi/topo': 5.1.0 @@ -910,13 +950,6 @@ packages: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - /make-synchronized@0.2.9: resolution: {integrity: sha512-4wczOs8SLuEdpEvp3vGo83wh8rjJ78UsIk7DIX5fxdfmfMJGog4bQzxfvOwq7Q3yCHLC4jp1urPHIxRS/A93gA==} dev: true @@ -985,8 +1018,8 @@ packages: whatwg-url: 5.0.0 dev: true - /node-gyp-build@4.8.0: - resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==} + /node-gyp-build@4.8.1: + resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} hasBin: true requiresBuild: true dev: true @@ -1053,8 +1086,8 @@ packages: selective-whitespace: 1.0.4 dev: true - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + /prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true dev: true @@ -1076,13 +1109,16 @@ packages: engines: {node: '>=0.10.0'} dev: true - /rpc-websockets@7.9.0: - resolution: {integrity: sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw==} + /rpc-websockets@9.0.1: + resolution: {integrity: sha512-JCkdc/TfJBGRfmjIFK7cmqX79nwPWUd9xCM0DAydRbdLShsW3j/GV2gmPlaFa8V1+2u4V/O47fm4ZR5+F6HyDw==} dependencies: - '@babel/runtime': 7.24.0 - eventemitter3: 4.0.7 + '@swc/helpers': 0.5.11 + '@types/uuid': 8.3.4 + '@types/ws': 8.5.10 + buffer: 6.0.3 + eventemitter3: 5.0.1 uuid: 8.3.2 - ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + ws: 8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.8 utf-8-validate: 5.0.10 @@ -1091,7 +1127,7 @@ packages: /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.6.2 + tslib: 2.6.3 dev: true /safe-buffer@5.2.1: @@ -1104,12 +1140,10 @@ packages: tokenize-whitespace: 0.0.1 dev: true - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + /semver@7.6.2: + resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true - dependencies: - lru-cache: 6.0.0 dev: true /set-function-length@1.2.2: @@ -1143,7 +1177,7 @@ packages: /socket.io-adapter@2.5.4: resolution: {integrity: sha512-wDNHGXGewWAjQPt3pyeYBtpWSq9cLE5UW1ZUPL/2eGK9jtse/FpXib7epSTsz0Q0m+6sg6Y4KtcFTlah1bdOVg==} dependencies: - debug: 4.3.4 + debug: 4.3.5 ws: 8.11.0 transitivePeerDependencies: - bufferutil @@ -1155,8 +1189,8 @@ packages: resolution: {integrity: sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==} engines: {node: '>=10.0.0'} dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 engine.io-client: 6.5.3 socket.io-parser: 4.2.4 transitivePeerDependencies: @@ -1169,8 +1203,8 @@ packages: resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} engines: {node: '>=10.0.0'} dependencies: - '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4 + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 transitivePeerDependencies: - supports-color dev: true @@ -1182,7 +1216,7 @@ packages: accepts: 1.3.8 base64id: 2.0.0 cors: 2.8.5 - debug: 4.3.4 + debug: 4.3.5 engine.io: 6.5.4 socket.io-adapter: 2.5.4 socket.io-parser: 4.2.4 @@ -1242,8 +1276,9 @@ packages: engines: {node: '>=6'} dev: true - /superstruct@0.14.2: - resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} + /superstruct@1.0.4: + resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} + engines: {node: '>=14.0.0'} dev: true /supports-color@7.2.0: @@ -1281,27 +1316,27 @@ packages: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true - /ts-essentials@9.4.1(typescript@4.9.4): - resolution: {integrity: sha512-oke0rI2EN9pzHsesdmrOrnqv1eQODmJpd/noJjwj2ZPC3Z4N2wbjrOEqnsEgmvlO2+4fBb0a794DCna2elEVIQ==} + /ts-essentials@9.4.2(typescript@4.9.5): + resolution: {integrity: sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ==} peerDependencies: typescript: '>=4.1.0' peerDependenciesMeta: typescript: optional: true dependencies: - typescript: 4.9.4 + typescript: 4.9.5 dev: true - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} dev: true /tweetnacl@1.0.3: resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} dev: true - /typescript@4.9.4: - resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true dev: true @@ -1315,7 +1350,7 @@ packages: engines: {node: '>=6.14.2'} requiresBuild: true dependencies: - node-gyp-build: 4.8.0 + node-gyp-build: 4.8.1 dev: true /uuid@8.3.2: @@ -1328,13 +1363,13 @@ packages: engines: {node: '>= 0.8'} dev: true - /wait-on@6.0.1(debug@4.3.4): + /wait-on@6.0.1(debug@4.3.5): resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} engines: {node: '>=10.0.0'} hasBin: true dependencies: - axios: 0.25.0(debug@4.3.4) - joi: 17.12.2 + axios: 0.25.0(debug@4.3.5) + joi: 17.13.1 lodash: 4.17.21 minimist: 1.2.8 rxjs: 7.8.1 @@ -1348,7 +1383,7 @@ packages: hasBin: true dependencies: axios: 0.27.2(debug@4.3.4) - joi: 17.12.2 + joi: 17.13.1 lodash: 4.17.21 minimist: 1.2.8 rxjs: 7.8.1 @@ -1410,8 +1445,8 @@ packages: optional: true dev: true - /ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): - resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + /ws@8.17.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -1436,10 +1471,6 @@ packages: engines: {node: '>=10'} dev: true - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} diff --git a/programs/mpl-core/src/error.rs b/programs/mpl-core/src/error.rs index 1c95d35b..266684c2 100644 --- a/programs/mpl-core/src/error.rs +++ b/programs/mpl-core/src/error.rs @@ -133,12 +133,12 @@ pub enum MplCoreError { #[error("Invalid Log Wrapper Program")] InvalidLogWrapperProgram, - /// 31 - External PluginExternalPluginAdapter not found - #[error("External PluginExternalPluginAdapter not found")] + /// 31 - External Plugin Adapter not found + #[error("External Plugin Adapter not found")] ExternalPluginAdapterNotFound, - /// 32 - External PluginExternalPluginAdapter already exists - #[error("External PluginExternalPluginAdapter already exists")] + /// 32 - External Plugin Adapter already exists + #[error("External Plugin Adapter already exists")] ExternalPluginAdapterAlreadyExists, /// 33 - Missing asset needed for extra account PDA derivation @@ -180,6 +180,26 @@ pub enum MplCoreError { /// 42 - Collection must be empty to be burned #[error("Collection must be empty to be burned")] CollectionMustBeEmpty, + + /// 43 - Two data sources provided, only one is allowed + #[error("Two data sources provided, only one is allowed")] + TwoDataSources, + + /// 44 - External Plugin does not support this operation + #[error("External Plugin does not support this operation")] + UnsupportedOperation, + + /// 45 - No data sources provided, one is required + #[error("No data sources provided, one is required")] + NoDataSources, + + /// 46 - This plugin adapter cannot be added to an Asset + #[error("This plugin adapter cannot be added to an Asset")] + InvalidPluginAdapterTarget, + + /// 47 - Cannot add a Data Section without a linked external plugin + #[error("Cannot add a Data Section without a linked external plugin")] + CannotAddDataSection, } impl PrintProgramError for MplCoreError { diff --git a/programs/mpl-core/src/instruction.rs b/programs/mpl-core/src/instruction.rs index 4ee1dffa..ff657069 100644 --- a/programs/mpl-core/src/instruction.rs +++ b/programs/mpl-core/src/instruction.rs @@ -11,7 +11,7 @@ use crate::processor::{ RemoveExternalPluginAdapterV1Args, RemovePluginV1Args, RevokeCollectionPluginAuthorityV1Args, RevokePluginAuthorityV1Args, TransferV1Args, UpdateCollectionExternalPluginAdapterV1Args, UpdateCollectionPluginV1Args, UpdateCollectionV1Args, UpdateExternalPluginAdapterV1Args, - UpdatePluginV1Args, UpdateV1Args, WriteCollectionExternalPluginAdapterDataV1Args, + UpdatePluginV1Args, UpdateV1Args, UpdateV2Args, WriteCollectionExternalPluginAdapterDataV1Args, WriteExternalPluginAdapterDataV1Args, }; @@ -268,16 +268,28 @@ pub(crate) enum MplAssetInstruction { #[account(0, writable, name="asset", desc = "The address of the asset")] #[account(1, optional, writable, name="collection", desc = "The collection to which the asset belongs")] #[account(2, writable, signer, name="payer", desc = "The account paying for the storage fees")] - #[account(3, optional, signer, name="authority", desc = "The Data Authority of the External PluginExternalPluginAdapter")] - #[account(4, name="system_program", desc = "The system program")] - #[account(5, optional, name="log_wrapper", desc = "The SPL Noop Program")] + #[account(3, optional, signer, name="authority", desc = "The Data Authority of the External Plugin Adapter")] + #[account(4, optional, name="buffer", desc = "The buffer to write to the external plugin")] + #[account(5, name="system_program", desc = "The system program")] + #[account(6, optional, name="log_wrapper", desc = "The SPL Noop Program")] WriteExternalPluginAdapterDataV1(WriteExternalPluginAdapterDataV1Args), /// Add an external plugin adapter to an mpl-core. #[account(0, writable, name="collection", desc = "The address of the asset")] #[account(1, writable, signer, name="payer", desc = "The account paying for the storage fees")] - #[account(2, optional, signer, name="authority", desc = "The Data Authority of the External PluginExternalPluginAdapter")] - #[account(3, name="system_program", desc = "The system program")] - #[account(4, optional, name="log_wrapper", desc = "The SPL Noop Program")] + #[account(2, optional, signer, name="authority", desc = "The Data Authority of the External Plugin Adapter")] + #[account(3, optional, name="buffer", desc = "The buffer to write to the external plugin")] + #[account(4, name="system_program", desc = "The system program")] + #[account(5, optional, name="log_wrapper", desc = "The SPL Noop Program")] WriteCollectionExternalPluginAdapterDataV1(WriteCollectionExternalPluginAdapterDataV1Args), + + /// Update an mpl-core V2. + #[account(0, writable, name="asset", desc = "The address of the asset")] + #[account(1, optional, writable, name="collection", desc = "The collection to which the asset belongs")] + #[account(2, writable, signer, name="payer", desc = "The account paying for the storage fees")] + #[account(3, optional, signer, name="authority", desc = "The update authority or update authority delegate of the asset")] + #[account(4, optional, writable, name="new_collection", desc = "A new collection to which to move the asset")] + #[account(5, name="system_program", desc = "The system program")] + #[account(6, optional, name="log_wrapper", desc = "The SPL Noop Program")] + UpdateV2(UpdateV2Args), } diff --git a/programs/mpl-core/src/plugins/data_store.rs b/programs/mpl-core/src/plugins/app_data.rs similarity index 74% rename from programs/mpl-core/src/plugins/data_store.rs rename to programs/mpl-core/src/plugins/app_data.rs index da45859e..0d069558 100644 --- a/programs/mpl-core/src/plugins/data_store.rs +++ b/programs/mpl-core/src/plugins/app_data.rs @@ -8,30 +8,30 @@ use super::{ ValidationResult, }; -/// The data store third party plugin contains arbitrary data that can be written to by the +/// The app data third party plugin contains arbitrary data that can be written to by the /// `data_authority`. Note this is different then the overall plugin authority stored in the /// `ExternalRegistryRecord` as it cannot update/revoke authority or change other metadata for the /// plugin. The data is stored at the plugin's data offset (which in the account is immediately /// after this header). #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] -pub struct DataStore { - /// Data authority who can update the data store. Cannot be changed after plugin is +pub struct AppData { + /// Data authority who can update the app data. Cannot be changed after plugin is /// added. pub data_authority: Authority, /// Schema for the data used by the plugin. pub schema: ExternalPluginAdapterSchema, } -impl DataStore { - /// Updates the data store with the new info. - pub fn update(&mut self, info: &DataStoreUpdateInfo) { +impl AppData { + /// Updates the app data with the new info. + pub fn update(&mut self, info: &AppDataUpdateInfo) { if let Some(schema) = &info.schema { self.schema = *schema; } } } -impl PluginValidation for DataStore { +impl PluginValidation for AppData { fn validate_add_external_plugin_adapter( &self, _ctx: &PluginValidationContext, @@ -47,8 +47,8 @@ impl PluginValidation for DataStore { } } -impl From<&DataStoreInitInfo> for DataStore { - fn from(init_info: &DataStoreInitInfo) -> Self { +impl From<&AppDataInitInfo> for AppData { + fn from(init_info: &AppDataInitInfo) -> Self { Self { data_authority: init_info.data_authority, schema: init_info.schema.unwrap_or_default(), @@ -56,10 +56,10 @@ impl From<&DataStoreInitInfo> for DataStore { } } -/// Data store initialization info. +/// App data initialization info. #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] -pub struct DataStoreInitInfo { - /// Data authority who can update the data store. This field cannot be +pub struct AppDataInitInfo { + /// Data authority who can update the app data. This field cannot be /// changed after the plugin is added. pub data_authority: Authority, /// Initial plugin authority who can update plugin properties. @@ -68,9 +68,9 @@ pub struct DataStoreInitInfo { pub schema: Option, } -/// Data store update info. +/// App data update info. #[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] -pub struct DataStoreUpdateInfo { +pub struct AppDataUpdateInfo { /// Schema for the data used by the plugin. pub schema: Option, } diff --git a/programs/mpl-core/src/plugins/burn_delegate.rs b/programs/mpl-core/src/plugins/burn_delegate.rs index 0d6c145a..a2c8d71f 100644 --- a/programs/mpl-core/src/plugins/burn_delegate.rs +++ b/programs/mpl-core/src/plugins/burn_delegate.rs @@ -3,7 +3,7 @@ use solana_program::program_error::ProgramError; use crate::{ plugins::{abstain, approve}, - state::{Authority, DataBlob}, + state::DataBlob, }; use super::{PluginValidation, PluginValidationContext, ValidationResult}; @@ -42,10 +42,11 @@ impl PluginValidation for BurnDelegate { &self, ctx: &PluginValidationContext, ) -> Result { - if ctx.self_authority - == (&Authority::Address { - address: *ctx.authority_info.key, - }) + if ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority) { approve!() } else { diff --git a/programs/mpl-core/src/plugins/data_section.rs b/programs/mpl-core/src/plugins/data_section.rs new file mode 100644 index 00000000..6f6ad65a --- /dev/null +++ b/programs/mpl-core/src/plugins/data_section.rs @@ -0,0 +1,37 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + +use super::{ExternalPluginAdapterSchema, LinkedDataKey, PluginValidation}; + +/// The data section plugin is a third party plugin that is _always_ managed by another plugin. +/// Currently these are used for the `LinkedAppData`, and `LinkedLifecycleHook` plugins. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct DataSection { + /// The key to the plugin that manages this data section. + pub parent_key: LinkedDataKey, + /// Schema for the data used by the plugin. + pub schema: ExternalPluginAdapterSchema, +} + +impl PluginValidation for DataSection {} + +impl From<&DataSectionInitInfo> for DataSection { + fn from(init_info: &DataSectionInitInfo) -> Self { + Self { + parent_key: init_info.parent_key, + schema: init_info.schema, + } + } +} + +/// App data initialization info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct DataSectionInitInfo { + /// The key to the plugin that manages this data section. + pub parent_key: LinkedDataKey, + /// Schema for the data used by the plugin. + pub schema: ExternalPluginAdapterSchema, +} + +/// App data update info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct DataSectionUpdateInfo {} diff --git a/programs/mpl-core/src/plugins/external_plugin_adapters.rs b/programs/mpl-core/src/plugins/external_plugin_adapters.rs index d4ba7828..257622ff 100644 --- a/programs/mpl-core/src/plugins/external_plugin_adapters.rs +++ b/programs/mpl-core/src/plugins/external_plugin_adapters.rs @@ -12,8 +12,10 @@ use crate::{ }; use super::{ - Authority, DataStore, DataStoreInitInfo, DataStoreUpdateInfo, ExternalCheckResult, - ExternalRegistryRecord, LifecycleHook, LifecycleHookInitInfo, LifecycleHookUpdateInfo, Oracle, + AppData, AppDataInitInfo, AppDataUpdateInfo, Authority, DataSection, DataSectionInitInfo, + ExternalCheckResult, ExternalRegistryRecord, LifecycleHook, LifecycleHookInitInfo, + LifecycleHookUpdateInfo, LinkedAppData, LinkedAppDataInitInfo, LinkedAppDataUpdateInfo, + LinkedLifecycleHook, LinkedLifecycleHookInitInfo, LinkedLifecycleHookUpdateInfo, Oracle, OracleInitInfo, OracleUpdateInfo, PluginValidation, PluginValidationContext, ValidationResult, }; @@ -27,16 +29,27 @@ pub enum ExternalPluginAdapterType { LifecycleHook, /// Oracle. Oracle, - /// Data Store. - DataStore, + /// App Data. + AppData, + /// Linked Lifecycle Hook. + LinkedLifecycleHook, + /// Linked App Data. + LinkedAppData, + /// Data Section. + DataSection, } impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType { fn from(key: &ExternalPluginAdapterKey) -> Self { match key { ExternalPluginAdapterKey::LifecycleHook(_) => ExternalPluginAdapterType::LifecycleHook, + ExternalPluginAdapterKey::LinkedLifecycleHook(_) => { + ExternalPluginAdapterType::LinkedLifecycleHook + } ExternalPluginAdapterKey::Oracle(_) => ExternalPluginAdapterType::Oracle, - ExternalPluginAdapterKey::DataStore(_) => ExternalPluginAdapterType::DataStore, + ExternalPluginAdapterKey::AppData(_) => ExternalPluginAdapterType::AppData, + ExternalPluginAdapterKey::LinkedAppData(_) => ExternalPluginAdapterType::LinkedAppData, + ExternalPluginAdapterKey::DataSection(_) => ExternalPluginAdapterType::DataSection, } } } @@ -48,7 +61,14 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapterType { ExternalPluginAdapterType::LifecycleHook } ExternalPluginAdapterInitInfo::Oracle(_) => ExternalPluginAdapterType::Oracle, - ExternalPluginAdapterInitInfo::DataStore(_) => ExternalPluginAdapterType::DataStore, + ExternalPluginAdapterInitInfo::AppData(_) => ExternalPluginAdapterType::AppData, + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(_) => { + ExternalPluginAdapterType::LinkedLifecycleHook + } + ExternalPluginAdapterInitInfo::LinkedAppData(_) => { + ExternalPluginAdapterType::LinkedAppData + } + ExternalPluginAdapterInitInfo::DataSection(_) => ExternalPluginAdapterType::DataSection, } } } @@ -67,7 +87,17 @@ pub enum ExternalPluginAdapter { Oracle(Oracle), /// Arbitrary data that can be written to by the data `Authority` stored in the attached /// struct. Note this data authority is different then the plugin authority. - DataStore(DataStore), + AppData(AppData), + /// Collection Only: Linked Lifecycle Hook. The hooked program and extra accounts are specified in the attached + /// struct. The hooked program is called at specified lifecycle events and will return a + /// validation result and new data to store. + LinkedLifecycleHook(LinkedLifecycleHook), + /// Collection only: Arbitrary data that can be written to by the data `Authority` stored on any asset in the Collection in the Data Section struct. + /// Authority is different then the plugin authority. + LinkedAppData(LinkedAppData), + /// Data Section. This is a special plugin that is used to contain the data of other external + /// plugins. + DataSection(DataSection), } impl ExternalPluginAdapter { @@ -87,10 +117,22 @@ impl ExternalPluginAdapter { oracle.update(update_info); } ( - ExternalPluginAdapter::DataStore(data_store), - ExternalPluginAdapterUpdateInfo::DataStore(update_info), + ExternalPluginAdapter::AppData(app_data), + ExternalPluginAdapterUpdateInfo::AppData(update_info), + ) => { + app_data.update(update_info); + } + ( + ExternalPluginAdapter::LinkedLifecycleHook(linked_lifecycle_hook), + ExternalPluginAdapterUpdateInfo::LinkedLifecycleHook(update_info), ) => { - data_store.update(update_info); + linked_lifecycle_hook.update(update_info); + } + ( + ExternalPluginAdapter::LinkedAppData(linked_app_data), + ExternalPluginAdapterUpdateInfo::LinkedAppData(update_info), + ) => { + linked_app_data.update(update_info); } _ => unreachable!(), } @@ -121,7 +163,20 @@ impl ExternalPluginAdapter { ExternalCheckResult::none() } } - ExternalPluginAdapterInitInfo::DataStore(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::AppData(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Create) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } + ExternalPluginAdapterInitInfo::LinkedAppData(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::DataSection(_) => ExternalCheckResult::none(), } } @@ -130,12 +185,19 @@ impl ExternalPluginAdapter { external_plugin_adapter: &ExternalPluginAdapter, ctx: &PluginValidationContext, ) -> Result { + solana_program::msg!("ExternalPluginAdapter::validate_create"); match external_plugin_adapter { ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { lifecycle_hook.validate_create(ctx) } ExternalPluginAdapter::Oracle(oracle) => oracle.validate_create(ctx), - ExternalPluginAdapter::DataStore(data_store) => data_store.validate_create(ctx), + ExternalPluginAdapter::AppData(app_data) => app_data.validate_create(ctx), + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_create(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_create(ctx), + // Here we block the creation of a DataSection plugin because this is only done internally. + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), } } @@ -149,7 +211,12 @@ impl ExternalPluginAdapter { lifecycle_hook.validate_update(ctx) } ExternalPluginAdapter::Oracle(oracle) => oracle.validate_update(ctx), - ExternalPluginAdapter::DataStore(data_store) => data_store.validate_update(ctx), + ExternalPluginAdapter::AppData(app_data) => app_data.validate_update(ctx), + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_update(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_update(ctx), + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), } } @@ -163,7 +230,12 @@ impl ExternalPluginAdapter { lifecycle_hook.validate_burn(ctx) } ExternalPluginAdapter::Oracle(oracle) => oracle.validate_burn(ctx), - ExternalPluginAdapter::DataStore(data_store) => data_store.validate_burn(ctx), + ExternalPluginAdapter::AppData(app_data) => app_data.validate_burn(ctx), + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_burn(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_burn(ctx), + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), } } @@ -177,7 +249,12 @@ impl ExternalPluginAdapter { lifecycle_hook.validate_transfer(ctx) } ExternalPluginAdapter::Oracle(oracle) => oracle.validate_transfer(ctx), - ExternalPluginAdapter::DataStore(data_store) => data_store.validate_transfer(ctx), + ExternalPluginAdapter::AppData(app_data) => app_data.validate_transfer(ctx), + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_transfer(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_transfer(ctx), + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), } } @@ -193,9 +270,17 @@ impl ExternalPluginAdapter { ExternalPluginAdapter::Oracle(oracle) => { oracle.validate_add_external_plugin_adapter(ctx) } - ExternalPluginAdapter::DataStore(data_store) => { - data_store.validate_add_external_plugin_adapter(ctx) + ExternalPluginAdapter::AppData(app_data) => { + app_data.validate_add_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_add_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => { + app_data.validate_add_external_plugin_adapter(ctx) } + // Here we block the creation of a DataSection plugin because this is only done internally. + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), } } @@ -221,9 +306,17 @@ impl ExternalPluginAdapter { ExternalPluginAdapter::Oracle(oracle) => { oracle.validate_update_external_plugin_adapter(ctx) } - ExternalPluginAdapter::DataStore(app_data) => { + ExternalPluginAdapter::AppData(app_data) => { + app_data.validate_update_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_update_external_plugin_adapter(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => { app_data.validate_update_external_plugin_adapter(ctx) } + // Here we block the update of a DataSection plugin because this is only done internally. + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), }?; match (&base_result, &result) { @@ -273,8 +366,17 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapter { ExternalPluginAdapterInitInfo::Oracle(init_info) => { ExternalPluginAdapter::Oracle(Oracle::from(init_info)) } - ExternalPluginAdapterInitInfo::DataStore(init_info) => { - ExternalPluginAdapter::DataStore(DataStore::from(init_info)) + ExternalPluginAdapterInitInfo::AppData(init_info) => { + ExternalPluginAdapter::AppData(AppData::from(init_info)) + } + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(init_info) => { + ExternalPluginAdapter::LinkedLifecycleHook(LinkedLifecycleHook::from(init_info)) + } + ExternalPluginAdapterInitInfo::LinkedAppData(init_info) => { + ExternalPluginAdapter::LinkedAppData(LinkedAppData::from(init_info)) + } + ExternalPluginAdapterInitInfo::DataSection(init_info) => { + ExternalPluginAdapter::DataSection(DataSection::from(init_info)) } } } @@ -515,8 +617,14 @@ pub enum ExternalPluginAdapterInitInfo { LifecycleHook(LifecycleHookInitInfo), /// Oracle. Oracle(OracleInitInfo), - /// Data Store. - DataStore(DataStoreInitInfo), + /// App Data. + AppData(AppDataInitInfo), + /// Linked Lifecycle Hook. + LinkedLifecycleHook(LinkedLifecycleHookInitInfo), + /// Linked App Data. + LinkedAppData(LinkedAppDataInitInfo), + /// Data Section. + DataSection(DataSectionInitInfo), } /// Information needed to update an external plugin adapter. @@ -527,22 +635,44 @@ pub enum ExternalPluginAdapterUpdateInfo { LifecycleHook(LifecycleHookUpdateInfo), /// Oracle. Oracle(OracleUpdateInfo), - /// Data Store. - DataStore(DataStoreUpdateInfo), + /// App Data. + AppData(AppDataUpdateInfo), + /// Linked Lifecycle Hook. + LinkedLifecycleHook(LinkedLifecycleHookUpdateInfo), + /// Linked App Data. + LinkedAppData(LinkedAppDataUpdateInfo), } /// Key used to uniquely specify an external plugin adapter after it is created. #[repr(C)] #[derive( - Clone, Copy, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq, EnumCount, PartialOrd, Ord, + Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq, EnumCount, PartialOrd, Ord, )] pub enum ExternalPluginAdapterKey { /// Lifecycle Hook. LifecycleHook(Pubkey), /// Oracle. Oracle(Pubkey), - /// Data Store. - DataStore(Authority), + /// App Data. + AppData(Authority), + /// Linked Lifecycle Hook. + LinkedLifecycleHook(Pubkey), + /// Linked App Data. + LinkedAppData(Authority), + /// Data Section. + DataSection(LinkedDataKey), +} + +/// Key to point to the plugin that manages this data section. +#[repr(C)] +#[derive( + Clone, Copy, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq, EnumCount, PartialOrd, Ord, +)] +pub enum LinkedDataKey { + /// Lifecycle Hook. + LinkedLifecycleHook(Pubkey), + /// Linked App Data. + LinkedAppData(Authority), } impl ExternalPluginAdapterKey { @@ -561,16 +691,33 @@ impl ExternalPluginAdapterKey { Pubkey::deserialize(&mut &account.data.borrow()[pubkey_or_authority_offset..])?; Ok(Self::LifecycleHook(pubkey)) } + ExternalPluginAdapterType::LinkedLifecycleHook => { + let pubkey = + Pubkey::deserialize(&mut &account.data.borrow()[pubkey_or_authority_offset..])?; + Ok(Self::LinkedLifecycleHook(pubkey)) + } ExternalPluginAdapterType::Oracle => { let pubkey = Pubkey::deserialize(&mut &account.data.borrow()[pubkey_or_authority_offset..])?; Ok(Self::Oracle(pubkey)) } - ExternalPluginAdapterType::DataStore => { + ExternalPluginAdapterType::AppData => { let authority = Authority::deserialize( &mut &account.data.borrow()[pubkey_or_authority_offset..], )?; - Ok(Self::DataStore(authority)) + Ok(Self::AppData(authority)) + } + ExternalPluginAdapterType::LinkedAppData => { + let authority = Authority::deserialize( + &mut &account.data.borrow()[pubkey_or_authority_offset..], + )?; + Ok(Self::LinkedAppData(authority)) + } + ExternalPluginAdapterType::DataSection => { + let linked_data_key = LinkedDataKey::deserialize( + &mut &account.data.borrow()[pubkey_or_authority_offset..], + )?; + Ok(Self::DataSection(linked_data_key)) } } } @@ -585,8 +732,17 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapterKey { ExternalPluginAdapterInitInfo::Oracle(init_info) => { ExternalPluginAdapterKey::Oracle(init_info.base_address) } - ExternalPluginAdapterInitInfo::DataStore(init_info) => { - ExternalPluginAdapterKey::DataStore(init_info.data_authority) + ExternalPluginAdapterInitInfo::AppData(init_info) => { + ExternalPluginAdapterKey::AppData(init_info.data_authority) + } + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(init_info) => { + ExternalPluginAdapterKey::LinkedLifecycleHook(init_info.hooked_program) + } + ExternalPluginAdapterInitInfo::LinkedAppData(init_info) => { + ExternalPluginAdapterKey::LinkedAppData(init_info.data_authority) + } + ExternalPluginAdapterInitInfo::DataSection(init_info) => { + ExternalPluginAdapterKey::DataSection(init_info.parent_key) } } } diff --git a/programs/mpl-core/src/plugins/freeze_delegate.rs b/programs/mpl-core/src/plugins/freeze_delegate.rs index 160a5c89..e63e9a28 100644 --- a/programs/mpl-core/src/plugins/freeze_delegate.rs +++ b/programs/mpl-core/src/plugins/freeze_delegate.rs @@ -1,7 +1,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::program_error::ProgramError; -use crate::state::{Authority, DataBlob}; +use crate::state::DataBlob; use super::{ abstain, approve, reject, Plugin, PluginValidation, PluginValidationContext, ValidationResult, @@ -82,10 +82,11 @@ impl PluginValidation for FreezeDelegate { if let Some(Plugin::FreezeDelegate(freeze)) = ctx.target_plugin { if freeze.frozen { return reject!(); - } else if ctx.self_authority - == &(Authority::Address { - address: *ctx.authority_info.key, - }) + } else if ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority) { return approve!(); } diff --git a/programs/mpl-core/src/plugins/lifecycle.rs b/programs/mpl-core/src/plugins/lifecycle.rs index 72546bb3..2f47c5ed 100644 --- a/programs/mpl-core/src/plugins/lifecycle.rs +++ b/programs/mpl-core/src/plugins/lifecycle.rs @@ -1,11 +1,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; use modular_bitfield::{bitfield, specifiers::B29}; -use solana_program::{account_info::AccountInfo, program_error::ProgramError}; +use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use std::collections::BTreeMap; use crate::{ error::MplCoreError, - state::{Authority, Key}, + state::{Authority, Key, UpdateAuthority}, }; use super::{ @@ -824,6 +824,10 @@ pub(crate) struct PluginValidationContext<'a, 'b> { pub resolved_authorities: Option<&'b [Authority]>, /// The new owner account for transfers pub new_owner: Option<&'a AccountInfo<'a>>, + /// The new asset authority address. + pub new_asset_authority: Option<&'b UpdateAuthority>, + /// The new collection authority address. + pub new_collection_authority: Option<&'b Pubkey>, /// The plugin being acted upon with new data from the ix if any. This None for create. pub target_plugin: Option<&'b Plugin>, } @@ -962,6 +966,8 @@ pub(crate) fn validate_plugin_checks<'a>( checks: &BTreeMap, authority: &'a AccountInfo<'a>, new_owner: Option<&'a AccountInfo<'a>>, + new_asset_authority: Option<&UpdateAuthority>, + new_collection_authority: Option<&Pubkey>, new_plugin: Option<&Plugin>, asset: Option<&'a AccountInfo<'a>>, collection: Option<&'a AccountInfo<'a>>, @@ -994,6 +1000,8 @@ pub(crate) fn validate_plugin_checks<'a>( authority_info: authority, resolved_authorities: Some(resolved_authorities), new_owner, + new_asset_authority, + new_collection_authority, target_plugin: new_plugin, }; @@ -1032,6 +1040,8 @@ pub(crate) fn validate_external_plugin_adapter_checks<'a>( >, authority: &'a AccountInfo<'a>, new_owner: Option<&'a AccountInfo<'a>>, + new_asset_authority: Option<&UpdateAuthority>, + new_collection_authority: Option<&Pubkey>, new_plugin: Option<&Plugin>, asset: Option<&'a AccountInfo<'a>>, collection: Option<&'a AccountInfo<'a>>, @@ -1062,6 +1072,8 @@ pub(crate) fn validate_external_plugin_adapter_checks<'a>( authority_info: authority, resolved_authorities: Some(resolved_authorities), new_owner, + new_asset_authority, + new_collection_authority, target_plugin: new_plugin, }; diff --git a/programs/mpl-core/src/plugins/linked_app_data.rs b/programs/mpl-core/src/plugins/linked_app_data.rs new file mode 100644 index 00000000..a2132e3c --- /dev/null +++ b/programs/mpl-core/src/plugins/linked_app_data.rs @@ -0,0 +1,71 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + +use super::{ + Authority, ExternalPluginAdapterSchema, PluginValidation, PluginValidationContext, + ValidationResult, +}; + +/// The app data third party plugin contains arbitrary data that can be written to by the +/// `data_authority`. Note this is different then the overall plugin authority stored in the +/// `ExternalRegistryRecord` as it cannot update/revoke authority or change other metadata for the +/// plugin. The data is stored at the plugin's data offset (which in the account is immediately +/// after this header). +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedAppData { + /// Data authority who can update the app data. Cannot be changed after plugin is + /// added. + pub data_authority: Authority, + /// Schema for the data used by the plugin. + pub schema: ExternalPluginAdapterSchema, +} + +impl LinkedAppData { + /// Updates the app data with the new info. + pub fn update(&mut self, info: &LinkedAppDataUpdateInfo) { + if let Some(schema) = &info.schema { + self.schema = *schema; + } + } +} + +impl PluginValidation for LinkedAppData { + fn validate_create( + &self, + ctx: &PluginValidationContext, + ) -> Result { + solana_program::msg!("LinkedAppData::validate_create"); + if ctx.asset_info.is_some() { + Ok(ValidationResult::Rejected) + } else { + Ok(ValidationResult::Pass) + } + } +} + +impl From<&LinkedAppDataInitInfo> for LinkedAppData { + fn from(init_info: &LinkedAppDataInitInfo) -> Self { + Self { + data_authority: init_info.data_authority, + schema: init_info.schema.unwrap_or_default(), + } + } +} + +/// App data initialization info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedAppDataInitInfo { + /// Data authority who can update the app data. This field cannot be + /// changed after the plugin is added. + pub data_authority: Authority, + /// Initial plugin authority who can update plugin properties. + pub init_plugin_authority: Option, + /// Schema for the data used by the plugin. + pub schema: Option, +} + +/// App data update info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedAppDataUpdateInfo { + /// Schema for the data used by the plugin. + pub schema: Option, +} diff --git a/programs/mpl-core/src/plugins/linked_lifecycle_hook.rs b/programs/mpl-core/src/plugins/linked_lifecycle_hook.rs new file mode 100644 index 00000000..d2846bf0 --- /dev/null +++ b/programs/mpl-core/src/plugins/linked_lifecycle_hook.rs @@ -0,0 +1,96 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::{program_error::ProgramError, pubkey::Pubkey}; + +use super::{ + Authority, ExternalCheckResult, ExternalPluginAdapterSchema, ExtraAccount, + HookableLifecycleEvent, PluginValidation, PluginValidationContext, ValidationResult, +}; + +/// Lifecycle hook that CPIs into the `hooked_program`. This hook is used for any lifecycle events +/// that were selected in the `ExternalRegistryRecord` for the plugin. If any extra accounts are +/// present in the `extra_accounts` optional `Vec`, then these accounts are added to the CPI call +/// in the order in which they are in the Vec. Any PDAs in the `Vec` are derived using the hooked +/// program. The hooked program will return a validation result and new data to store at the +/// plugin's data offset (which in the account is immediately after this header). +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedLifecycleHook { + /// The `Pubkey` for the hooked program. + pub hooked_program: Pubkey, // 32 + /// The extra accounts to use for the lifecycle hook. + pub extra_accounts: Option>, + /// The authority of who can update the Lifecycle Hook data. This can be for the purposes + /// of initialization of data, or schema migration. This field cannot be changed after + /// the plugin is added. + pub data_authority: Option, + /// Schema for the data used by the plugin. + pub schema: ExternalPluginAdapterSchema, // 1 +} + +impl LinkedLifecycleHook { + /// Updates the lifecycle hook with the new info. + pub fn update(&mut self, info: &LinkedLifecycleHookUpdateInfo) { + if let Some(extra_accounts) = &info.extra_accounts { + self.extra_accounts = Some(extra_accounts.clone()); + } + if let Some(schema) = &info.schema { + self.schema = *schema; + } + } +} + +impl PluginValidation for LinkedLifecycleHook { + fn validate_add_external_plugin_adapter( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + Ok(ValidationResult::Pass) + } + + fn validate_transfer( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + Ok(ValidationResult::Pass) + } +} + +impl From<&LinkedLifecycleHookInitInfo> for LinkedLifecycleHook { + fn from(init_info: &LinkedLifecycleHookInitInfo) -> Self { + Self { + hooked_program: init_info.hooked_program, + extra_accounts: init_info.extra_accounts.clone(), + data_authority: init_info.data_authority, + schema: init_info.schema.unwrap_or_default(), + } + } +} + +/// Lifecycle hook initialization info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedLifecycleHookInitInfo { + /// The `Pubkey` for the hooked program. + pub hooked_program: Pubkey, + /// Initial plugin authority. + pub init_plugin_authority: Option, + /// The lifecyle events for which the the external plugin adapter is active. + pub lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, + /// The extra accounts to use for the lifecycle hook. + pub extra_accounts: Option>, + /// The authority of who can update the Lifecycle Hook data. This can be for the purposes + /// of initialization of data, or schema migration. This field cannot be changed after + /// the plugin is added. + pub data_authority: Option, + /// Schema for the data used by the plugin. + pub schema: Option, +} + +/// Lifecycle hook update info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct LinkedLifecycleHookUpdateInfo { + /// The lifecyle events for which the the external plugin adapter is active. + pub lifecycle_checks: Option>, + /// The extra accounts to use for the lifecycle hook. + pub extra_accounts: Option>, + /// Schema for the data used by the plugin. + pub schema: Option, +} diff --git a/programs/mpl-core/src/plugins/mod.rs b/programs/mpl-core/src/plugins/mod.rs index 109987cc..b2177509 100644 --- a/programs/mpl-core/src/plugins/mod.rs +++ b/programs/mpl-core/src/plugins/mod.rs @@ -1,19 +1,19 @@ mod add_blocker; +mod app_data; mod attributes; +mod autograph; mod burn_delegate; -mod data_store; +mod data_section; mod edition; mod external_plugin_adapters; mod freeze_delegate; mod immutable_metadata; mod lifecycle; - mod lifecycle_hook; -mod oracle; - +mod linked_app_data; +mod linked_lifecycle_hook; mod master_edition; - -mod autograph; +mod oracle; mod permanent_burn_delegate; mod permanent_freeze_delegate; mod permanent_transfer_delegate; @@ -26,16 +26,19 @@ mod utils; mod verified_creators; pub use add_blocker::*; +pub use app_data::*; pub use attributes::*; pub use autograph::*; pub use burn_delegate::*; -pub use data_store::*; +pub use data_section::*; pub use edition::*; pub use external_plugin_adapters::*; pub use freeze_delegate::*; pub use immutable_metadata::*; pub use lifecycle::*; pub use lifecycle_hook::*; +pub use linked_app_data::*; +pub use linked_lifecycle_hook::*; pub use master_edition::*; pub use oracle::*; pub use permanent_burn_delegate::*; diff --git a/programs/mpl-core/src/plugins/plugin_registry.rs b/programs/mpl-core/src/plugins/plugin_registry.rs index 24730269..f45b4813 100644 --- a/programs/mpl-core/src/plugins/plugin_registry.rs +++ b/programs/mpl-core/src/plugins/plugin_registry.rs @@ -4,6 +4,7 @@ use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; use std::{cmp::Ordering, collections::BTreeMap}; use crate::{ + error::MplCoreError, plugins::validate_lifecycle_checks, state::{Authority, DataBlob, Key, SolanaAccount}, }; @@ -72,6 +73,40 @@ impl PluginRegistryV1 { Ok(()) } + + /// Increase the offsets of all plugins after a certain offset. + pub(crate) fn bump_offsets(&mut self, offset: usize, size_diff: isize) -> ProgramResult { + for record in &mut self.registry { + if record.offset > offset { + record.offset = (record.offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + as usize; + } + } + + for record in &mut self.external_registry { + if record.offset > offset { + record.offset = (record.offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + as usize; + } + + if let Some(data_offset) = record.data_offset { + if data_offset > offset { + record.data_offset = Some( + (data_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + as usize, + ); + } + } + } + + Ok(()) + } } impl DataBlob for PluginRegistryV1 { @@ -111,7 +146,7 @@ impl RegistryRecord { /// A type to store the mapping of third party plugin type to third party plugin header and data. #[repr(C)] -#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)] +#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] pub struct ExternalRegistryRecord { /// The adapter, third party plugin type. pub plugin_type: ExternalPluginAdapterType, diff --git a/programs/mpl-core/src/plugins/transfer.rs b/programs/mpl-core/src/plugins/transfer.rs index 033dc047..375346e6 100644 --- a/programs/mpl-core/src/plugins/transfer.rs +++ b/programs/mpl-core/src/plugins/transfer.rs @@ -1,7 +1,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::program_error::ProgramError; -use crate::state::{Authority, DataBlob}; +use crate::state::DataBlob; use super::{abstain, approve, PluginValidation, PluginValidationContext, ValidationResult}; @@ -35,41 +35,19 @@ impl DataBlob for TransferDelegate { } impl PluginValidation for TransferDelegate { - fn validate_burn( + fn validate_transfer( &self, ctx: &PluginValidationContext, ) -> Result { - if ctx.self_authority - == (&Authority::Address { - address: *ctx.authority_info.key, - }) + if ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority) { - approve!() - } else { - abstain!() + return approve!(); } - } - fn validate_transfer( - &self, - ctx: &PluginValidationContext, - ) -> Result { - match ctx.self_authority { - Authority::Address { address } if address == ctx.authority_info.key => { - return approve!(); - } - - Authority::UpdateAuthority => { - if ctx - .resolved_authorities - .map_or(false, |auths| auths.contains(&Authority::UpdateAuthority)) - { - return approve!(); - } - } - - _ => {} - } abstain!() } } diff --git a/programs/mpl-core/src/plugins/update_delegate.rs b/programs/mpl-core/src/plugins/update_delegate.rs index dbf268bf..7b6d5644 100644 --- a/programs/mpl-core/src/plugins/update_delegate.rs +++ b/programs/mpl-core/src/plugins/update_delegate.rs @@ -1,8 +1,11 @@ +use std::collections::BTreeSet; + use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::{program_error::ProgramError, pubkey::Pubkey}; use crate::{ error::MplCoreError, + plugins::PluginType, state::{Authority, DataBlob}, }; @@ -49,16 +52,16 @@ impl PluginValidation for UpdateDelegate { &self, ctx: &PluginValidationContext, ) -> Result { - if !self.additional_delegates.is_empty() { - return Err(MplCoreError::NotAvailable.into()); - } - if let Some(resolved_authorities) = ctx.resolved_authorities { if resolved_authorities.contains(ctx.self_authority) { return approve!(); } } + if self.additional_delegates.contains(ctx.authority_info.key) { + return approve!(); + } + abstain!() } @@ -67,16 +70,12 @@ impl PluginValidation for UpdateDelegate { ctx: &PluginValidationContext, ) -> Result { if let Some(new_plugin) = ctx.target_plugin { - if let Plugin::UpdateDelegate(update_delegate) = new_plugin { - if !update_delegate.additional_delegates.is_empty() { - return Err(MplCoreError::NotAvailable.into()); - } - } - - if ctx.self_authority - == (&Authority::Address { - address: *ctx.authority_info.key, - }) + if ((ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + || self.additional_delegates.contains(ctx.authority_info.key)) && new_plugin.manager() == Authority::UpdateAuthority { approve!() @@ -93,10 +92,12 @@ impl PluginValidation for UpdateDelegate { ctx: &PluginValidationContext, ) -> Result { if let Some(plugin_to_remove) = ctx.target_plugin { - if ctx.self_authority - == (&Authority::Address { - address: *ctx.authority_info.key, - }) + if ((ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + || self.additional_delegates.contains(ctx.authority_info.key)) && plugin_to_remove.manager() == Authority::UpdateAuthority { approve!() @@ -108,14 +109,69 @@ impl PluginValidation for UpdateDelegate { } } + // Validate the approve plugin authority lifecycle action. + fn validate_approve_plugin_authority( + &self, + ctx: &PluginValidationContext, + ) -> Result { + let plugin = ctx.target_plugin.ok_or(MplCoreError::InvalidPlugin)?; + + // If the plugin authority is the authority signing. + if ((ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + // Or the authority is one of the additional delegates. + || self.additional_delegates.contains(ctx.authority_info.key)) + // And it's an authority-managed plugin. + && plugin.manager() == Authority::UpdateAuthority + // And the plugin is not an UpdateDelegate plugin, because we cannot change the authority of the UpdateDelegate plugin. + && PluginType::from(plugin) != PluginType::UpdateDelegate + { + solana_program::msg!("UpdateDelegate: Approved"); + Ok(ValidationResult::Approved) + } else { + Ok(ValidationResult::Pass) + } + } + + /// Validate the revoke plugin authority lifecycle action. + fn validate_revoke_plugin_authority( + &self, + ctx: &PluginValidationContext, + ) -> Result { + let plugin = ctx.target_plugin.ok_or(MplCoreError::InvalidPlugin)?; + + // If the plugin authority is the authority signing. + if (ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + // Or the authority is one of the additional delegates. + || (self.additional_delegates.contains(ctx.authority_info.key) && PluginType::from(plugin) != PluginType::UpdateDelegate) + // And it's an authority-managed plugin. + && plugin.manager() == Authority::UpdateAuthority + { + approve!() + } else { + abstain!() + } + } + fn validate_update( &self, ctx: &PluginValidationContext, ) -> Result { - if ctx.self_authority - == (&Authority::Address { - address: *ctx.authority_info.key, - }) + if ((ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + || self.additional_delegates.contains(ctx.authority_info.key)) + // We do not allow the root authority (either Collection or Address) to be changed by this delegate. + && ctx.new_collection_authority.is_none() && ctx.new_asset_authority.is_none() { approve!() } else { @@ -127,10 +183,28 @@ impl PluginValidation for UpdateDelegate { &self, ctx: &PluginValidationContext, ) -> Result { - let plugin_to_update = ctx.target_plugin.ok_or(MplCoreError::InvalidPlugin)?; - if let Plugin::UpdateDelegate(update_delegate) = plugin_to_update { - if !update_delegate.additional_delegates.is_empty() { - return Err(MplCoreError::NotAvailable.into()); + let plugin = ctx.target_plugin.ok_or(MplCoreError::InvalidPlugin)?; + + // If the plugin itself is being updated. + if (ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority)) + || self.additional_delegates.contains(ctx.authority_info.key) + { + if let Plugin::UpdateDelegate(update_delegate) = plugin { + let existing: BTreeSet<_> = self.additional_delegates.iter().collect(); + let new: BTreeSet<_> = update_delegate.additional_delegates.iter().collect(); + + if existing.difference(&new).collect::>() == vec![&ctx.authority_info.key] + && new.difference(&existing).collect::>().is_empty() + { + solana_program::msg!("UpdateDelegate: Approved"); + return Ok(ValidationResult::Approved); + } + } else { + return Ok(ValidationResult::Approved); } } diff --git a/programs/mpl-core/src/plugins/utils.rs b/programs/mpl-core/src/plugins/utils.rs index 117cd7a6..5dd60a9a 100644 --- a/programs/mpl-core/src/plugins/utils.rs +++ b/programs/mpl-core/src/plugins/utils.rs @@ -1,7 +1,10 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - program_memory::sol_memcpy, pubkey::Pubkey, + account_info::AccountInfo, + entrypoint::ProgramResult, + program_error::ProgramError, + program_memory::{sol_memcpy, sol_memmove}, + pubkey::Pubkey, }; use std::collections::HashSet; @@ -13,9 +16,10 @@ use crate::{ }; use super::{ - ExternalPluginAdapter, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, - ExternalPluginAdapterType, ExternalRegistryRecord, Plugin, PluginHeaderV1, PluginRegistryV1, - PluginType, RegistryRecord, + AppDataInitInfo, ExternalPluginAdapter, ExternalPluginAdapterInitInfo, + ExternalPluginAdapterKey, ExternalPluginAdapterType, ExternalRegistryRecord, + LinkedAppDataInitInfo, LinkedDataKey, Plugin, PluginHeaderV1, PluginRegistryV1, PluginType, + RegistryRecord, }; /// Create plugin header and registry if it doesn't exist @@ -185,7 +189,7 @@ pub fn fetch_wrapped_external_plugin_adapter( account: &AccountInfo, core: Option<&T>, plugin_key: &ExternalPluginAdapterKey, -) -> Result<(Authority, ExternalPluginAdapter), ProgramError> { +) -> Result<(ExternalRegistryRecord, ExternalPluginAdapter), ProgramError> { let size = match core { Some(core) => core.get_size(), None => { @@ -211,7 +215,7 @@ pub fn fetch_wrapped_external_plugin_adapter( ExternalPluginAdapter::deserialize(&mut &(*account.data).borrow()[record.offset..])?; // Return the plugin and its authority. - Ok((record.authority, plugin)) + Ok((record.clone(), plugin)) } else { Err(MplCoreError::ExternalPluginAdapterNotFound.into()) } @@ -310,26 +314,39 @@ pub fn initialize_plugin<'a, T: DataBlob + SolanaAccount>( } /// Add an external plugin adapter to the registry and initialize it. +#[allow(clippy::too_many_arguments)] pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( init_info: &ExternalPluginAdapterInitInfo, + core: Option<&T>, plugin_header: &mut PluginHeaderV1, plugin_registry: &mut PluginRegistryV1, account: &AccountInfo<'a>, payer: &AccountInfo<'a>, system_program: &AccountInfo<'a>, + appended_data: Option<&[u8]>, ) -> ProgramResult { - let core = T::load(account, 0)?; - let header_offset = core.get_size(); + let header_offset = match core { + Some(core) => core.get_size(), + None => { + let asset = T::load(account, 0)?; + + if asset.get_size() == account.data_len() { + return Err(MplCoreError::ExternalPluginAdapterNotFound.into()); + } + + asset.get_size() + } + }; let plugin_type = init_info.into(); - // Note currently we are blocking adding LifecycleHook and DataStore external plugin adapters as they + // Note currently we are blocking adding LifecycleHook and LinkedLifecycleHook external plugin adapters as they // are still in development. match init_info { ExternalPluginAdapterInitInfo::LifecycleHook(_) - | ExternalPluginAdapterInitInfo::DataStore(_) => { - return Err(MplCoreError::NotAvailable.into()); + | ExternalPluginAdapterInitInfo::LinkedLifecycleHook(_) => { + return Err(MplCoreError::NotAvailable.into()) } - ExternalPluginAdapterInitInfo::Oracle(_) => (), + _ => {} } // You cannot add a duplicate plugin. @@ -349,6 +366,13 @@ pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( Some(init_info.lifecycle_checks.clone()), ) } + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(init_info) => { + validate_lifecycle_checks(&init_info.lifecycle_checks, false)?; + ( + init_info.init_plugin_authority, + Some(init_info.lifecycle_checks.clone()), + ) + } ExternalPluginAdapterInitInfo::Oracle(init_info) => { validate_lifecycle_checks(&init_info.lifecycle_checks, true)?; ( @@ -356,9 +380,16 @@ pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( Some(init_info.lifecycle_checks.clone()), ) } - ExternalPluginAdapterInitInfo::DataStore(init_info) => { - (init_info.init_plugin_authority, None) - } + ExternalPluginAdapterInitInfo::AppData(AppDataInitInfo { + init_plugin_authority, + .. + }) + | ExternalPluginAdapterInitInfo::LinkedAppData(LinkedAppDataInitInfo { + init_plugin_authority, + .. + }) => (*init_plugin_authority, None), + // The DataSection is only updated via its managing plugin so it has no authority. + ExternalPluginAdapterInitInfo::DataSection(_) => (Some(Authority::None), None), }; let old_registry_offset = plugin_header.plugin_registry_offset; @@ -372,29 +403,46 @@ pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( data_len: None, }; - let mut plugin = ExternalPluginAdapter::from(init_info); - - // If the plugin is a LifecycleHook or DataStore, then we need to set the data offset and length. - match &mut plugin { - ExternalPluginAdapter::LifecycleHook(_) | ExternalPluginAdapter::DataStore(_) => { - new_registry_record.data_offset = Some(old_registry_offset); - new_registry_record.data_len = Some(0); + let plugin = ExternalPluginAdapter::from(init_info); + + // If the plugin is a LifecycleHook or AppData, then we need to set the data offset and length. + match plugin { + ExternalPluginAdapter::LifecycleHook(_) + | ExternalPluginAdapter::AppData(_) + | ExternalPluginAdapter::DataSection(_) => { + // Here we use a 0 value for the data offset as it will be updated after the data is appended. + new_registry_record.data_offset = Some(0); + new_registry_record.data_len = match appended_data { + Some(data) => Some(data.len()), + None => Some(0), + }; } _ => {} }; - let plugin_metadata = plugin.try_to_vec()?; - let plugin_size = plugin_metadata.len(); + let serialized_plugin = plugin.try_to_vec()?; + let plugin_size = serialized_plugin.len(); let size_increase = plugin_size .checked_add(new_registry_record.try_to_vec()?.len()) + .ok_or(MplCoreError::NumericalOverflow)? + .checked_add(new_registry_record.data_len.unwrap_or(0)) .ok_or(MplCoreError::NumericalOverflow)?; - let new_registry_offset = plugin_header + let data_offset = plugin_header .plugin_registry_offset .checked_add(plugin_size) .ok_or(MplCoreError::NumericalOverflow)?; + // If the data offset has been initialized, then we need to set it to the correct value. + if new_registry_record.data_offset.is_some() { + new_registry_record.data_offset = Some(data_offset); + } + + let new_registry_offset = data_offset + .checked_add(new_registry_record.data_len.unwrap_or(0)) + .ok_or(MplCoreError::NumericalOverflow)?; + plugin_header.plugin_registry_offset = new_registry_offset; plugin_registry.external_registry.push(new_registry_record); @@ -407,11 +455,90 @@ pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( resize_or_reallocate_account(account, payer, system_program, new_size)?; plugin_header.save(account, header_offset)?; plugin.save(account, old_registry_offset)?; + + if let Some(data) = appended_data { + sol_memcpy( + &mut account.data.borrow_mut()[data_offset..], + data, + data.len(), + ); + }; + plugin_registry.save(account, new_registry_offset)?; Ok(()) } +/// Add an external plugin adapter to the registry and initialize it. +#[allow(clippy::too_many_arguments)] +pub fn update_external_plugin_adapter_data<'a, T: DataBlob + SolanaAccount>( + record: &ExternalRegistryRecord, + core: Option<&T>, + plugin_header: &mut PluginHeaderV1, + plugin_registry: &mut PluginRegistryV1, + account: &AccountInfo<'a>, + payer: &AccountInfo<'a>, + system_program: &AccountInfo<'a>, + data: &[u8], +) -> ProgramResult { + // Extract the data offset and data length as they should always be set. + let data_offset = record.data_offset.ok_or(MplCoreError::InvalidPlugin)?; + let data_len = record.data_len.ok_or(MplCoreError::InvalidPlugin)?; + let new_data_len = data.len(); + let size_diff = (new_data_len as isize) + .checked_sub(data_len as isize) + .ok_or(MplCoreError::NumericalOverflow)?; + + // Update any offsets that will change. + plugin_registry.bump_offsets(data_offset, size_diff)?; + + let new_registry_offset = (plugin_header.plugin_registry_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)?; + plugin_header.plugin_registry_offset = new_registry_offset as usize; + + let new_size = (account.data_len() as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)?; + + resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; + + let next_plugin_offset = data_offset + .checked_add(data_len) + .ok_or(MplCoreError::NumericalOverflow)?; + let new_next_plugin_offset = (next_plugin_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)?; + + unsafe { + let base = account.data.borrow_mut().as_mut_ptr(); + sol_memmove( + base.add(new_next_plugin_offset as usize), + base.add(next_plugin_offset), + account.data_len().saturating_sub(next_plugin_offset), + ) + } + + sol_memcpy( + &mut account.data.borrow_mut()[data_offset..], + data, + new_data_len, + ); + + // Find the record in the registry and update the data length. + let record_index = plugin_registry + .external_registry + .iter() + .position(|r| r == record) + .ok_or(MplCoreError::InvalidPlugin)?; + plugin_registry.external_registry[record_index].data_len = Some(new_data_len); + + plugin_registry.save(account, new_registry_offset as usize)?; + plugin_header.save(account, core.map_or(0, |core| core.get_size()))?; + + Ok(()) +} + pub(crate) fn validate_lifecycle_checks( lifecycle_checks: &[(HookableLifecycleEvent, ExternalCheckResult)], can_reject_only: bool, @@ -716,7 +843,8 @@ fn check_plugin_key( if record_ref.plugin_type == ExternalPluginAdapterType::from(plugin_key) && (match plugin_key { ExternalPluginAdapterKey::LifecycleHook(address) - | ExternalPluginAdapterKey::Oracle(address) => { + | ExternalPluginAdapterKey::Oracle(address) + | ExternalPluginAdapterKey::LinkedLifecycleHook(address) => { let pubkey_offset = record_ref .offset .checked_add(1) @@ -727,7 +855,8 @@ fn check_plugin_key( Err(_) => return Err(MplCoreError::DeserializationError.into()), } } - ExternalPluginAdapterKey::DataStore(authority) => { + ExternalPluginAdapterKey::AppData(authority) + | ExternalPluginAdapterKey::LinkedAppData(authority) => { let authority_offset = record_ref .offset .checked_add(1) @@ -740,6 +869,19 @@ fn check_plugin_key( Err(_) => return Err(MplCoreError::DeserializationError.into()), } } + ExternalPluginAdapterKey::DataSection(linked_data_key) => { + let linked_data_key_offset = record_ref + .offset + .checked_add(1) + .ok_or(MplCoreError::NumericalOverflow)?; + linked_data_key + == &match LinkedDataKey::deserialize( + &mut &account.data.borrow()[linked_data_key_offset..], + ) { + Ok(linked_data_key) => linked_data_key, + Err(_) => return Err(MplCoreError::DeserializationError.into()), + } + } }) { Ok(true) diff --git a/programs/mpl-core/src/processor/add_external_plugin_adapter.rs b/programs/mpl-core/src/processor/add_external_plugin_adapter.rs index 85cd0733..9f95acf6 100644 --- a/programs/mpl-core/src/processor/add_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/add_external_plugin_adapter.rs @@ -50,6 +50,18 @@ pub(crate) fn add_external_plugin_adapter<'a>( return Err(MplCoreError::NotAvailable.into()); } + // TODO: This should be handled in the validate call. + match args.init_info { + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(_) + | ExternalPluginAdapterInitInfo::LinkedAppData(_) => { + return Err(MplCoreError::InvalidPluginAdapterTarget.into()) + } + ExternalPluginAdapterInitInfo::DataSection(_) => { + return Err(MplCoreError::CannotAddDataSection.into()) + } + _ => (), + } + let validation_ctx = PluginValidationContext { accounts, asset_info: Some(ctx.accounts.asset), @@ -58,6 +70,8 @@ pub(crate) fn add_external_plugin_adapter<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; @@ -79,6 +93,7 @@ pub(crate) fn add_external_plugin_adapter<'a>( ctx.accounts.collection, None, None, + None, Some(&external_plugin_adapter), AssetV1::check_add_external_plugin_adapter, CollectionV1::check_add_external_plugin_adapter, @@ -98,6 +113,7 @@ pub(crate) fn add_external_plugin_adapter<'a>( ctx.accounts.payer, ctx.accounts.system_program, &args.init_info, + &asset, ) } @@ -128,6 +144,10 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( } } + if let ExternalPluginAdapterInitInfo::DataSection(_) = args.init_info { + return Err(MplCoreError::CannotAddDataSection.into()); + } + let validation_ctx = PluginValidationContext { accounts, asset_info: None, @@ -136,6 +156,8 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; @@ -150,11 +172,12 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( let external_plugin_adapter = ExternalPluginAdapter::from(&args.init_info); // Validate collection permissions. - let _ = validate_collection_permissions( + let (core, _, _) = validate_collection_permissions( accounts, authority, ctx.accounts.collection, None, + None, Some(&external_plugin_adapter), CollectionV1::check_add_external_plugin_adapter, PluginType::check_add_external_plugin_adapter, @@ -169,6 +192,7 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( ctx.accounts.payer, ctx.accounts.system_program, &args.init_info, + &core, ) } @@ -177,16 +201,19 @@ fn process_add_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( payer: &AccountInfo<'a>, system_program: &AccountInfo<'a>, init_info: &ExternalPluginAdapterInitInfo, + core: &T, ) -> ProgramResult { let (_, mut plugin_header, mut plugin_registry) = create_meta_idempotent::(account, payer, system_program)?; initialize_external_plugin_adapter::( init_info, + Some(core), &mut plugin_header, &mut plugin_registry, account, payer, system_program, + None, )?; Ok(()) } diff --git a/programs/mpl-core/src/processor/add_plugin.rs b/programs/mpl-core/src/processor/add_plugin.rs index 629de7d3..77c1626b 100644 --- a/programs/mpl-core/src/processor/add_plugin.rs +++ b/programs/mpl-core/src/processor/add_plugin.rs @@ -63,6 +63,8 @@ pub(crate) fn add_plugin<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: Some(&args.plugin), }; if Plugin::validate_add_plugin(&args.plugin, &validation_ctx)? == ValidationResult::Rejected { @@ -76,6 +78,7 @@ pub(crate) fn add_plugin<'a>( ctx.accounts.asset, ctx.accounts.collection, None, + None, Some(&args.plugin), None, AssetV1::check_add_plugin, @@ -135,6 +138,8 @@ pub(crate) fn add_collection_plugin<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: Some(&args.plugin), }; if Plugin::validate_add_plugin(&args.plugin, &validation_ctx)? == ValidationResult::Rejected { @@ -151,6 +156,7 @@ pub(crate) fn add_collection_plugin<'a>( accounts, authority, ctx.accounts.collection, + None, Some(&args.plugin), None, CollectionV1::check_add_plugin, diff --git a/programs/mpl-core/src/processor/approve_plugin_authority.rs b/programs/mpl-core/src/processor/approve_plugin_authority.rs index c115c67b..1486b38a 100644 --- a/programs/mpl-core/src/processor/approve_plugin_authority.rs +++ b/programs/mpl-core/src/processor/approve_plugin_authority.rs @@ -56,6 +56,7 @@ pub(crate) fn approve_plugin_authority<'a>( ctx.accounts.asset, ctx.accounts.collection, None, + None, Some(&plugin), None, AssetV1::check_approve_plugin_authority, @@ -115,6 +116,7 @@ pub(crate) fn approve_collection_plugin_authority<'a>( accounts, authority, ctx.accounts.collection, + None, Some(&plugin), None, CollectionV1::check_approve_plugin_authority, diff --git a/programs/mpl-core/src/processor/burn.rs b/programs/mpl-core/src/processor/burn.rs index 0a125d3f..0fad2e53 100644 --- a/programs/mpl-core/src/processor/burn.rs +++ b/programs/mpl-core/src/processor/burn.rs @@ -91,6 +91,7 @@ pub(crate) fn burn<'a>(accounts: &'a [AccountInfo<'a>], args: BurnV1Args) -> Pro None, None, None, + None, AssetV1::check_burn, CollectionV1::check_burn, PluginType::check_burn, @@ -103,7 +104,7 @@ pub(crate) fn burn<'a>(accounts: &'a [AccountInfo<'a>], args: BurnV1Args) -> Pro process_burn(ctx.accounts.asset, ctx.accounts.payer)?; if let Some(mut collection) = collection { - collection.decrement()?; + collection.decrement_size()?; collection.save(ctx.accounts.collection.unwrap(), 0)?; }; Ok(()) diff --git a/programs/mpl-core/src/processor/compress.rs b/programs/mpl-core/src/processor/compress.rs index 47a40b4f..893a93b3 100644 --- a/programs/mpl-core/src/processor/compress.rs +++ b/programs/mpl-core/src/processor/compress.rs @@ -51,6 +51,7 @@ pub(crate) fn compress<'a>( None, None, None, + None, AssetV1::check_compress, CollectionV1::check_compress, PluginType::check_compress, diff --git a/programs/mpl-core/src/processor/create.rs b/programs/mpl-core/src/processor/create.rs index cb2021f5..52130b9b 100644 --- a/programs/mpl-core/src/processor/create.rs +++ b/programs/mpl-core/src/processor/create.rs @@ -156,6 +156,7 @@ pub(crate) fn process_create<'a>( None, None, None, + None, AssetV1::check_create, CollectionV1::check_create, PluginType::check_create, @@ -195,6 +196,8 @@ pub(crate) fn process_create<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; match Plugin::validate_create(&plugin.plugin, &validation_ctx)? { @@ -228,6 +231,18 @@ pub(crate) fn process_create<'a>( ExternalPluginAdapter::check_create(plugin_init_info), ); + // TODO: This should be handled in the validate call. + match plugin_init_info { + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(_) + | ExternalPluginAdapterInitInfo::LinkedAppData(_) => { + return Err(MplCoreError::InvalidPluginAdapterTarget.into()) + } + ExternalPluginAdapterInitInfo::DataSection(_) => { + return Err(MplCoreError::CannotAddDataSection.into()) + } + _ => (), + } + if external_check_result_bits.can_reject() { let validation_ctx = PluginValidationContext { accounts, @@ -238,6 +253,8 @@ pub(crate) fn process_create<'a>( authority_info: authority, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; if ExternalPluginAdapter::validate_create( @@ -250,11 +267,13 @@ pub(crate) fn process_create<'a>( } initialize_external_plugin_adapter::( plugin_init_info, + Some(&new_asset), &mut plugin_header, &mut plugin_registry, ctx.accounts.asset, ctx.accounts.payer, ctx.accounts.system_program, + None, )?; } } @@ -266,7 +285,8 @@ pub(crate) fn process_create<'a>( } if let Some(mut collection) = collection { - collection.increment()?; + collection.increment_minted()?; + collection.increment_size()?; collection.save(ctx.accounts.collection.unwrap(), 0)?; }; diff --git a/programs/mpl-core/src/processor/create_collection.rs b/programs/mpl-core/src/processor/create_collection.rs index ec57af7d..33d9a732 100644 --- a/programs/mpl-core/src/processor/create_collection.rs +++ b/programs/mpl-core/src/processor/create_collection.rs @@ -140,6 +140,8 @@ pub(crate) fn process_create_collection<'a>( authority_info: ctx.accounts.payer, resolved_authorities: None, new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; match Plugin::validate_create(&plugin.plugin, &validation_ctx)? { @@ -169,13 +171,19 @@ pub(crate) fn process_create_collection<'a>( ctx.accounts.system_program, )?; for plugin_init_info in &plugins { + if let ExternalPluginAdapterInitInfo::DataSection(_) = plugin_init_info { + return Err(MplCoreError::CannotAddDataSection.into()); + } + initialize_external_plugin_adapter::( plugin_init_info, + Some(&new_collection), &mut plugin_header, &mut plugin_registry, ctx.accounts.collection, ctx.accounts.payer, ctx.accounts.system_program, + None, )?; } } diff --git a/programs/mpl-core/src/processor/decompress.rs b/programs/mpl-core/src/processor/decompress.rs index c4d11d77..a9bd17df 100644 --- a/programs/mpl-core/src/processor/decompress.rs +++ b/programs/mpl-core/src/processor/decompress.rs @@ -67,6 +67,7 @@ pub(crate) fn decompress<'a>( None, None, None, + None, AssetV1::check_decompress, CollectionV1::check_decompress, PluginType::check_decompress, diff --git a/programs/mpl-core/src/processor/mod.rs b/programs/mpl-core/src/processor/mod.rs index 476d2629..e3177a48 100644 --- a/programs/mpl-core/src/processor/mod.rs +++ b/programs/mpl-core/src/processor/mod.rs @@ -109,7 +109,7 @@ pub fn process_instruction<'a>( } MplAssetInstruction::UpdateV1(args) => { msg!("Instruction: Update"); - update(accounts, args) + update_v1(accounts, args) } MplAssetInstruction::UpdateCollectionV1(args) => { msg!("Instruction: UpdateCollection"); @@ -164,5 +164,9 @@ pub fn process_instruction<'a>( msg!("Instruction: WriteCollectionExternalPluginAdapterDataV1"); write_collection_external_plugin_adapter_data(accounts, args) } + MplAssetInstruction::UpdateV2(args) => { + msg!("Instruction: UpdateV2"); + update_v2(accounts, args) + } } } diff --git a/programs/mpl-core/src/processor/remove_external_plugin_adapter.rs b/programs/mpl-core/src/processor/remove_external_plugin_adapter.rs index a6e6d716..f5f5f253 100644 --- a/programs/mpl-core/src/processor/remove_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/remove_external_plugin_adapter.rs @@ -71,6 +71,7 @@ pub(crate) fn remove_external_plugin_adapter<'a>( ctx.accounts.collection, None, None, + None, Some(&plugin_to_remove), AssetV1::check_remove_external_plugin_adapter, CollectionV1::check_remove_external_plugin_adapter, @@ -138,6 +139,7 @@ pub(crate) fn remove_collection_external_plugin_adapter<'a>( authority, ctx.accounts.collection, None, + None, Some(&plugin_to_remove), CollectionV1::check_remove_external_plugin_adapter, PluginType::check_remove_external_plugin_adapter, diff --git a/programs/mpl-core/src/processor/remove_plugin.rs b/programs/mpl-core/src/processor/remove_plugin.rs index 9818651b..83efdd9c 100644 --- a/programs/mpl-core/src/processor/remove_plugin.rs +++ b/programs/mpl-core/src/processor/remove_plugin.rs @@ -62,6 +62,7 @@ pub(crate) fn remove_plugin<'a>( ctx.accounts.asset, ctx.accounts.collection, None, + None, Some(&plugin_to_remove), None, AssetV1::check_remove_plugin, @@ -131,6 +132,7 @@ pub(crate) fn remove_collection_plugin<'a>( accounts, authority, ctx.accounts.collection, + None, Some(&plugin_to_remove), None, CollectionV1::check_remove_plugin, diff --git a/programs/mpl-core/src/processor/revoke_plugin_authority.rs b/programs/mpl-core/src/processor/revoke_plugin_authority.rs index aa60a7f6..f68cf57c 100644 --- a/programs/mpl-core/src/processor/revoke_plugin_authority.rs +++ b/programs/mpl-core/src/processor/revoke_plugin_authority.rs @@ -63,6 +63,7 @@ pub(crate) fn revoke_plugin_authority<'a>( ctx.accounts.asset, ctx.accounts.collection, None, + None, Some(&plugin), None, AssetV1::check_revoke_plugin_authority, @@ -136,6 +137,7 @@ pub(crate) fn revoke_collection_plugin_authority<'a>( accounts, authority, ctx.accounts.collection, + None, Some(&plugin), None, CollectionV1::check_revoke_plugin_authority, diff --git a/programs/mpl-core/src/processor/transfer.rs b/programs/mpl-core/src/processor/transfer.rs index fac7c48b..d6c5f550 100644 --- a/programs/mpl-core/src/processor/transfer.rs +++ b/programs/mpl-core/src/processor/transfer.rs @@ -84,6 +84,7 @@ pub(crate) fn transfer<'a>(accounts: &'a [AccountInfo<'a>], args: TransferV1Args Some(ctx.accounts.new_owner), None, None, + None, AssetV1::check_transfer, CollectionV1::check_transfer, PluginType::check_transfer, diff --git a/programs/mpl-core/src/processor/update.rs b/programs/mpl-core/src/processor/update.rs index add0b335..e51f3d38 100644 --- a/programs/mpl-core/src/processor/update.rs +++ b/programs/mpl-core/src/processor/update.rs @@ -6,15 +6,17 @@ use solana_program::{ use crate::{ error::MplCoreError, - instruction::accounts::{UpdateCollectionV1Accounts, UpdateV1Accounts}, + instruction::accounts::{ + Context, UpdateCollectionV1Accounts, UpdateV1Accounts, UpdateV2Accounts, + }, plugins::{ - ExternalPluginAdapter, HookableLifecycleEvent, Plugin, PluginHeaderV1, PluginRegistryV1, - PluginType, + fetch_plugin, ExternalPluginAdapter, HookableLifecycleEvent, Plugin, PluginHeaderV1, + PluginRegistryV1, PluginType, UpdateDelegate, }, state::{AssetV1, CollectionV1, DataBlob, Key, SolanaAccount, UpdateAuthority}, utils::{ - load_key, resize_or_reallocate_account, resolve_authority, validate_asset_permissions, - validate_collection_permissions, + assert_collection_authority, load_key, resize_or_reallocate_account, resolve_authority, + validate_asset_permissions, validate_collection_permissions, }, }; @@ -26,10 +28,65 @@ pub(crate) struct UpdateV1Args { pub new_update_authority: Option, } -pub(crate) fn update<'a>(accounts: &'a [AccountInfo<'a>], args: UpdateV1Args) -> ProgramResult { - // Accounts. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct UpdateV2Args { + pub new_name: Option, + pub new_uri: Option, + pub new_update_authority: Option, +} + +impl From for UpdateV2Args { + fn from(item: UpdateV1Args) -> Self { + UpdateV2Args { + new_name: item.new_name, + new_uri: item.new_uri, + new_update_authority: item.new_update_authority, + } + } +} + +enum InstructionVersion { + V1, + V2, +} + +pub(crate) fn update_v1<'a>(accounts: &'a [AccountInfo<'a>], args: UpdateV1Args) -> ProgramResult { let ctx = UpdateV1Accounts::context(accounts)?; + let v2_accounts = UpdateV2Accounts { + asset: ctx.accounts.asset, + collection: ctx.accounts.collection, + payer: ctx.accounts.payer, + authority: ctx.accounts.authority, + new_collection: None, + system_program: ctx.accounts.system_program, + log_wrapper: ctx.accounts.log_wrapper, + }; + + let v2_ctx = Context { + accounts: v2_accounts, + remaining_accounts: ctx.remaining_accounts, + }; + + update( + v2_ctx, + accounts, + UpdateV2Args::from(args), + InstructionVersion::V1, + ) +} +pub(crate) fn update_v2<'a>(accounts: &'a [AccountInfo<'a>], args: UpdateV2Args) -> ProgramResult { + let ctx = UpdateV2Accounts::context(accounts)?; + update(ctx, accounts, args, InstructionVersion::V2) +} + +fn update<'a>( + ctx: Context>, + accounts: &'a [AccountInfo<'a>], + args: UpdateV2Args, + ix_version: InstructionVersion, +) -> ProgramResult { // Guards. assert_signer(ctx.accounts.payer)?; let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; @@ -55,6 +112,7 @@ pub(crate) fn update<'a>(accounts: &'a [AccountInfo<'a>], args: UpdateV1Args) -> ctx.accounts.asset, ctx.accounts.collection, None, + args.new_update_authority.as_ref(), None, None, AssetV1::check_update, @@ -74,15 +132,86 @@ pub(crate) fn update<'a>(accounts: &'a [AccountInfo<'a>], args: UpdateV1Args) -> let mut dirty = false; if let Some(new_update_authority) = args.new_update_authority { - if let UpdateAuthority::Collection(_collection_address) = new_update_authority { - // Updating collections is not currently available. - return Err(MplCoreError::NotAvailable.into()); - }; - - if let UpdateAuthority::Collection(_collection_address) = asset.update_authority { - // Removing from collection is not currently available. - // will require the collection size to be updated - return Err(MplCoreError::NotAvailable.into()); + // If asset is currently in a collection, remove it from the collection. + // This block is executed when we want to go from collection to no collection, or collection to + // new collection. The permission for this block is established by `validate_asset_permissions`. + if let UpdateAuthority::Collection(_existing_collection_address) = asset.update_authority { + match ix_version { + InstructionVersion::V1 => { + // Removing from or changing collection requires collection size to be updated + // and is not supported by `UpdateV1`. + msg!("Error: Use UpdateV2 to remove asset from or change collection"); + return Err(MplCoreError::NotAvailable.into()); + } + InstructionVersion::V2 => { + let existing_collection_account = ctx + .accounts + .collection + .ok_or(MplCoreError::MissingCollection)?; + + let mut existing_collection = + CollectionV1::load(existing_collection_account, 0)?; + + existing_collection.decrement_size()?; + existing_collection.save(existing_collection_account, 0)?; + } + } + } + + // If new update authority is a collection, add the asset to the new collection. + // This block is executed when we want to go from no collection to collection, or collection + // to new collection. The permission for this block is established in the code block. It is + // similar to creating an asset, in that the new collection's authority or an update delegate + // for the new collecton can approve adding the asset to the new collection. + if let UpdateAuthority::Collection(new_collection_address) = new_update_authority { + match ix_version { + InstructionVersion::V1 => { + msg!("Error: Use UpdateV2 to add asset to a new collection"); + return Err(MplCoreError::NotAvailable.into()); + } + InstructionVersion::V2 => { + // Make sure the account was provided. + let new_collection_account = ctx + .accounts + .new_collection + .ok_or(MplCoreError::MissingCollection)?; + + // Make sure account matches what was provided in the args. + if new_collection_account.key != &new_collection_address { + return Err(MplCoreError::InvalidCollection.into()); + } + + // Deserialize the collection. + let mut new_collection = CollectionV1::load(new_collection_account, 0)?; + + // See if there is an update delegate on the new collection. + let maybe_update_delegate = fetch_plugin::( + new_collection_account, + PluginType::UpdateDelegate, + ); + + // Make sure the authority has authority to add the asset to the new collection. + if let Ok((plugin_authority, _, _)) = maybe_update_delegate { + if assert_collection_authority( + &new_collection, + authority, + &plugin_authority, + ) + .is_err() + && authority.key != &new_collection.update_authority + { + solana_program::msg!("UA: Rejected"); + return Err(MplCoreError::InvalidAuthority.into()); + } + } else if authority.key != &new_collection.update_authority { + solana_program::msg!("UA: Rejected"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + new_collection.increment_size()?; + new_collection.save(new_collection_account, 0)?; + } + }; } asset.update_authority = new_update_authority; @@ -143,6 +272,7 @@ pub(crate) fn update_collection<'a>( accounts, authority, ctx.accounts.collection, + ctx.accounts.new_update_authority.map(|a| a.key), None, None, CollectionV1::check_update, diff --git a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs index 0e030b43..ed6d8622 100644 --- a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs @@ -60,17 +60,19 @@ pub(crate) fn update_external_plugin_adapter<'a>( fetch_core_data::(ctx.accounts.asset)?; let resolved_authorities = resolve_pubkey_to_authorities(authority, ctx.accounts.collection, &asset)?; - let (external_registry_record_authority, external_plugin_adapter) = + let (external_registry_record, external_plugin_adapter) = fetch_wrapped_external_plugin_adapter::(ctx.accounts.asset, None, &args.key)?; let validation_ctx = PluginValidationContext { accounts, asset_info: Some(ctx.accounts.asset), collection_info: ctx.accounts.collection, - self_authority: &external_registry_record_authority, + self_authority: &external_registry_record.authority, authority_info: authority, resolved_authorities: Some(&resolved_authorities), new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; @@ -132,7 +134,7 @@ pub(crate) fn update_collection_external_plugin_adapter<'a>( fetch_core_data::(ctx.accounts.collection)?; let resolved_authorities = resolve_pubkey_to_authorities_collection(authority, ctx.accounts.collection)?; - let (external_registry_record_authority, external_plugin_adapter) = + let (external_registry_record, external_plugin_adapter) = fetch_wrapped_external_plugin_adapter::( ctx.accounts.collection, None, @@ -143,10 +145,12 @@ pub(crate) fn update_collection_external_plugin_adapter<'a>( accounts, asset_info: None, collection_info: Some(ctx.accounts.collection), - self_authority: &external_registry_record_authority, + self_authority: &external_registry_record.authority, authority_info: authority, resolved_authorities: Some(&resolved_authorities), new_owner: None, + new_asset_authority: None, + new_collection_authority: None, target_plugin: None, }; @@ -249,25 +253,7 @@ fn process_update_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( plugin_header.save(account, core.get_size())?; // Move offsets for existing registry records. - for record in &mut plugin_registry.external_registry { - if registry_record.offset < record.offset { - let new_offset = (record.offset as isize) - .checked_add(plugin_size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - - record.offset = new_offset as usize; - } - } - - for record in &mut plugin_registry.registry { - if registry_record.offset < record.offset { - let new_offset = (record.offset as isize) - .checked_add(plugin_size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - - record.offset = new_offset as usize; - } - } + plugin_registry.bump_offsets(registry_record.offset, plugin_size_diff)?; plugin_registry.save(account, new_registry_offset as usize)?; new_plugin.save(account, registry_record.offset)?; diff --git a/programs/mpl-core/src/processor/update_plugin.rs b/programs/mpl-core/src/processor/update_plugin.rs index b1ed0114..a4810f36 100644 --- a/programs/mpl-core/src/processor/update_plugin.rs +++ b/programs/mpl-core/src/processor/update_plugin.rs @@ -53,6 +53,7 @@ pub(crate) fn update_plugin<'a>( ctx.accounts.asset, ctx.accounts.collection, None, + None, Some(&args.plugin), None, AssetV1::check_update_plugin, @@ -111,6 +112,7 @@ pub(crate) fn update_collection_plugin<'a>( accounts, authority, ctx.accounts.collection, + None, Some(&args.plugin), None, CollectionV1::check_update_plugin, @@ -196,26 +198,7 @@ fn process_update_plugin<'a, T: DataBlob + SolanaAccount>( plugin_header.save(account, core.get_size())?; - // Move offsets for existing registry records. - for record in &mut plugin_registry.external_registry { - if registry_record.offset < record.offset { - let new_offset = (record.offset as isize) - .checked_add(size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - - record.offset = new_offset as usize; - } - } - - for record in &mut plugin_registry.registry { - if registry_record.offset < record.offset { - let new_offset = (record.offset as isize) - .checked_add(size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - - record.offset = new_offset as usize; - } - } + plugin_registry.bump_offsets(registry_record.offset, size_diff)?; plugin_registry.save(account, new_registry_offset as usize)?; new_plugin.save(account, registry_record.offset)?; diff --git a/programs/mpl-core/src/processor/write_external_plugin_adapter_data.rs b/programs/mpl-core/src/processor/write_external_plugin_adapter_data.rs index 5c132fcb..ac4060d7 100644 --- a/programs/mpl-core/src/processor/write_external_plugin_adapter_data.rs +++ b/programs/mpl-core/src/processor/write_external_plugin_adapter_data.rs @@ -1,7 +1,28 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, +}; -use crate::{error::MplCoreError, plugins::ExternalPluginAdapterKey}; +use crate::{ + error::MplCoreError, + instruction::accounts::{ + WriteCollectionExternalPluginAdapterDataV1Accounts, + WriteExternalPluginAdapterDataV1Accounts, + }, + plugins::{ + create_meta_idempotent, fetch_wrapped_external_plugin_adapter, + initialize_external_plugin_adapter, update_external_plugin_adapter_data, AppData, + DataSectionInitInfo, ExternalPluginAdapter, ExternalPluginAdapterInitInfo, + ExternalPluginAdapterKey, ExternalRegistryRecord, LifecycleHook, LinkedAppData, + LinkedDataKey, LinkedLifecycleHook, PluginHeaderV1, PluginRegistryV1, + }, + state::{AssetV1, Authority, CollectionV1, DataBlob, Key, SolanaAccount}, + utils::{ + fetch_core_data, load_key, resolve_authority, resolve_pubkey_to_authorities, + resolve_pubkey_to_authorities_collection, + }, +}; #[repr(C)] #[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] @@ -9,14 +30,67 @@ pub(crate) struct WriteExternalPluginAdapterDataV1Args { /// External plugin adapter key. pub key: ExternalPluginAdapterKey, /// The data to write. - pub data: Vec, + pub data: Option>, } pub(crate) fn write_external_plugin_adapter_data<'a>( - _accounts: &'a [AccountInfo<'a>], - _args: WriteExternalPluginAdapterDataV1Args, + accounts: &'a [AccountInfo<'a>], + args: WriteExternalPluginAdapterDataV1Args, ) -> ProgramResult { - Err(MplCoreError::NotAvailable.into()) + let ctx = WriteExternalPluginAdapterDataV1Accounts::context(accounts)?; + + // Guards. + assert_signer(ctx.accounts.payer)?; + let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; + + let (asset, mut header, mut registry) = fetch_core_data::(ctx.accounts.asset)?; + + let authorities = resolve_pubkey_to_authorities(authority, ctx.accounts.collection, &asset)?; + + if ctx.accounts.system_program.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if let Some(log_wrapper) = ctx.accounts.log_wrapper { + if log_wrapper.key != &spl_noop::ID { + return Err(MplCoreError::InvalidLogWrapperProgram.into()); + } + } + + if let Key::HashedAssetV1 = load_key(ctx.accounts.asset, 0)? { + msg!("Error: Update plugin for compressed is not available"); + return Err(MplCoreError::NotAvailable.into()); + } + + let (record, plugin) = match args.key { + ExternalPluginAdapterKey::LifecycleHook(_) | ExternalPluginAdapterKey::AppData(_) => { + fetch_wrapped_external_plugin_adapter::(ctx.accounts.asset, None, &args.key) + } + ExternalPluginAdapterKey::LinkedLifecycleHook(_) + | ExternalPluginAdapterKey::LinkedAppData(_) => { + let collection = ctx + .accounts + .collection + .ok_or(MplCoreError::MissingCollection)?; + fetch_wrapped_external_plugin_adapter::(collection, None, &args.key) + } + _ => return Err(MplCoreError::UnsupportedOperation.into()), + }?; + + process_write_external_plugin_data::( + ctx.accounts.asset, + ctx.accounts.payer, + ctx.accounts.system_program, + ctx.accounts.buffer, + args.data.as_deref(), + &asset, + &record, + &plugin, + header.as_mut(), + registry.as_mut(), + &authorities, + &args.key, + ) } #[repr(C)] @@ -25,12 +99,196 @@ pub(crate) struct WriteCollectionExternalPluginAdapterDataV1Args { /// External plugin adapter key. pub key: ExternalPluginAdapterKey, /// The data to write. - pub data: Vec, + pub data: Option>, } pub(crate) fn write_collection_external_plugin_adapter_data<'a>( - _accounts: &'a [AccountInfo<'a>], - _args: WriteCollectionExternalPluginAdapterDataV1Args, + accounts: &'a [AccountInfo<'a>], + args: WriteCollectionExternalPluginAdapterDataV1Args, +) -> ProgramResult { + let ctx = WriteCollectionExternalPluginAdapterDataV1Accounts::context(accounts)?; + + // Guards. + assert_signer(ctx.accounts.payer)?; + let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; + + let (collection, mut header, mut registry) = + fetch_core_data::(ctx.accounts.collection)?; + + let authorities = resolve_pubkey_to_authorities_collection(authority, ctx.accounts.collection)?; + + if ctx.accounts.system_program.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if let Some(log_wrapper) = ctx.accounts.log_wrapper { + if log_wrapper.key != &spl_noop::ID { + return Err(MplCoreError::InvalidLogWrapperProgram.into()); + } + } + + let (record, plugin) = fetch_wrapped_external_plugin_adapter::( + ctx.accounts.collection, + None, + &args.key, + )?; + + process_write_external_plugin_data::( + ctx.accounts.collection, + ctx.accounts.payer, + ctx.accounts.system_program, + ctx.accounts.buffer, + args.data.as_deref(), + &collection, + &record, + &plugin, + header.as_mut(), + registry.as_mut(), + &authorities, + &args.key, + ) +} + +#[allow(clippy::too_many_arguments)] +fn process_write_external_plugin_data<'a, T: DataBlob + SolanaAccount>( + account: &AccountInfo<'a>, + payer: &AccountInfo<'a>, + system_program: &AccountInfo<'a>, + buffer: Option<&AccountInfo<'a>>, + data: Option<&[u8]>, + core: &T, + record: &ExternalRegistryRecord, + wrapped_plugin: &ExternalPluginAdapter, + header: Option<&mut PluginHeaderV1>, + registry: Option<&mut PluginRegistryV1>, + authorities: &[Authority], + _key: &ExternalPluginAdapterKey, ) -> ProgramResult { - Err(MplCoreError::NotAvailable.into()) + // Check that the authority is the same as the plugin's data authority. + match wrapped_plugin { + ExternalPluginAdapter::LifecycleHook(LifecycleHook { + data_authority: Some(data_authority), + .. + }) + | ExternalPluginAdapter::LinkedLifecycleHook(LinkedLifecycleHook { + data_authority: Some(data_authority), + .. + }) + | ExternalPluginAdapter::AppData(AppData { data_authority, .. }) + | ExternalPluginAdapter::LinkedAppData(LinkedAppData { data_authority, .. }) => { + if !authorities.contains(data_authority) { + return Err(MplCoreError::InvalidAuthority.into()); + } + } + _ => return Err(MplCoreError::UnsupportedOperation.into()), + } + + // AppData and LifecycleHook both write the data after the plugin. + // LinkedAppData writes the data to the asset directly. + match wrapped_plugin { + ExternalPluginAdapter::LifecycleHook(_) | ExternalPluginAdapter::AppData(_) => { + let header = header.ok_or(MplCoreError::PluginsNotInitialized)?; + let registry = registry.ok_or(MplCoreError::PluginsNotInitialized)?; + match (data, buffer) { + (Some(data), None) => update_external_plugin_adapter_data( + record, + Some(core), + header, + registry, + account, + payer, + system_program, + data, + ), + (None, Some(buffer)) => update_external_plugin_adapter_data( + record, + Some(core), + header, + registry, + account, + payer, + system_program, + &buffer.data.borrow(), + ), + (Some(_), Some(_)) => Err(MplCoreError::TwoDataSources.into()), + (None, None) => Err(MplCoreError::NoDataSources.into()), + } + } + ExternalPluginAdapter::LinkedAppData(app_data) => { + let (_, mut header, mut registry) = + create_meta_idempotent::(account, payer, system_program)?; + + match fetch_wrapped_external_plugin_adapter( + account, + Some(core), + &ExternalPluginAdapterKey::DataSection(LinkedDataKey::LinkedAppData( + app_data.data_authority, + )), + ) { + Ok((section_record, _)) => match (data, buffer) { + (Some(data), None) => update_external_plugin_adapter_data( + §ion_record, + Some(core), + &mut header, + &mut registry, + account, + payer, + system_program, + data, + ), + (None, Some(buffer)) => update_external_plugin_adapter_data( + §ion_record, + Some(core), + &mut header, + &mut registry, + account, + payer, + system_program, + &buffer.data.borrow(), + ), + (Some(_), Some(_)) => Err(MplCoreError::TwoDataSources.into()), + (None, None) => Err(MplCoreError::NoDataSources.into()), + }, + Err(ref e) + if *e + == ProgramError::Custom( + MplCoreError::ExternalPluginAdapterNotFound as u32, + ) => + { + match (data, buffer) { + (Some(data), None) => initialize_external_plugin_adapter::( + &ExternalPluginAdapterInitInfo::DataSection(DataSectionInitInfo { + parent_key: LinkedDataKey::LinkedAppData(app_data.data_authority), + schema: app_data.schema, + }), + Some(core), + &mut header, + &mut registry, + account, + payer, + system_program, + Some(data), + ), + (None, Some(buffer)) => initialize_external_plugin_adapter::( + &ExternalPluginAdapterInitInfo::DataSection(DataSectionInitInfo { + parent_key: LinkedDataKey::LinkedAppData(app_data.data_authority), + schema: app_data.schema, + }), + Some(core), + &mut header, + &mut registry, + account, + payer, + system_program, + Some(&buffer.data.borrow()), + ), + (Some(_), Some(_)) => Err(MplCoreError::TwoDataSources.into()), + (None, None) => Err(MplCoreError::NoDataSources.into()), + } + } + Err(e) => Err(e), + } + } + _ => Err(MplCoreError::UnsupportedOperation.into()), + } } diff --git a/programs/mpl-core/src/state/collection.rs b/programs/mpl-core/src/state/collection.rs index 390d2729..f59fd388 100644 --- a/programs/mpl-core/src/state/collection.rs +++ b/programs/mpl-core/src/state/collection.rs @@ -319,13 +319,18 @@ impl CollectionV1 { abstain!() } - /// Increment size of the Collection - pub fn increment(&mut self) -> Result<(), ProgramError> { + /// Increment number of minted items of the Collection + pub fn increment_minted(&mut self) -> Result<(), ProgramError> { self.num_minted = self .num_minted .checked_add(1) .ok_or(MplCoreError::NumericalOverflowError)?; + Ok(()) + } + + /// Increment current size of the Collection + pub fn increment_size(&mut self) -> Result<(), ProgramError> { self.current_size = self .current_size .checked_add(1) @@ -334,8 +339,8 @@ impl CollectionV1 { Ok(()) } - /// Decrements size of the Collection - pub fn decrement(&mut self) -> Result<(), ProgramError> { + /// Decrement current size of the Collection + pub fn decrement_size(&mut self) -> Result<(), ProgramError> { self.current_size = self .current_size .checked_sub(1) diff --git a/programs/mpl-core/src/state/update_authority.rs b/programs/mpl-core/src/state/update_authority.rs index 86b0727b..27245421 100644 --- a/programs/mpl-core/src/state/update_authority.rs +++ b/programs/mpl-core/src/state/update_authority.rs @@ -1,13 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::{program_error::ProgramError, pubkey::Pubkey}; - -use crate::{ - instruction::accounts::{ - BurnV1Accounts, CompressV1Accounts, DecompressV1Accounts, TransferV1Accounts, - UpdateV1Accounts, - }, - plugins::{abstain, approve, reject, CheckResult, ValidationResult}, -}; +use solana_program::pubkey::Pubkey; /// An enum representing the types of accounts that can update data on an asset. #[derive(Clone, BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] @@ -29,61 +21,4 @@ impl UpdateAuthority { Self::Collection(address) => *address, } } - - /// Check permissions for the create lifecycle event. - pub fn check_create() -> CheckResult { - CheckResult::CanReject - } - - /// Check permissions for the update lifecycle event. - pub fn check_update() -> CheckResult { - CheckResult::CanApprove - } - - /// Validate the update lifecycle event. - pub fn validate_update( - &self, - ctx: &UpdateV1Accounts, - ) -> Result { - let authority = match self { - Self::None => return reject!(), - Self::Address(address) => address, - Self::Collection(address) => address, - }; - - if ctx.authority.unwrap_or(ctx.payer).key == authority { - approve!() - } else { - abstain!() - } - } - - /// Validate the burn lifecycle event. - pub fn validate_burn(&self, _ctx: &BurnV1Accounts) -> Result { - abstain!() - } - - /// Validate the transfer lifecycle event. - pub fn validate_transfer( - &self, - _ctx: &TransferV1Accounts, - ) -> Result { - abstain!() - } - - /// Validate the compress lifecycle event. - pub fn validate_compress( - &self, - _ctx: &CompressV1Accounts, - ) -> Result { - abstain!() - } - - /// Validate the decompress lifecycle event. - pub fn validate_decompress( - &self, - _ctx: &DecompressV1Accounts, - ) -> Result { - abstain!() - } } diff --git a/programs/mpl-core/src/utils.rs b/programs/mpl-core/src/utils.rs index bf68bc19..340b6dea 100644 --- a/programs/mpl-core/src/utils.rs +++ b/programs/mpl-core/src/utils.rs @@ -5,8 +5,8 @@ use mpl_utils::assert_signer; use num_traits::{FromPrimitive, ToPrimitive}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program::invoke, - program_error::ProgramError, program_memory::sol_memcpy, rent::Rent, system_instruction, - sysvar::Sysvar, + program_error::ProgramError, program_memory::sol_memcpy, pubkey::Pubkey, rent::Rent, + system_instruction, sysvar::Sysvar, }; use crate::{ @@ -63,14 +63,14 @@ pub fn assert_authority( /// Assert that the account info address is the same as the authority. pub fn assert_collection_authority( - asset: &CollectionV1, + collection: &CollectionV1, authority_info: &AccountInfo, authority: &Authority, ) -> ProgramResult { match authority { Authority::None | Authority::Owner => (), Authority::UpdateAuthority => { - if &asset.update_authority == authority_info.key { + if &collection.update_authority == authority_info.key { return Ok(()); } } @@ -207,6 +207,7 @@ pub(crate) fn validate_asset_permissions<'a>( asset: &'a AccountInfo<'a>, collection: Option<&'a AccountInfo<'a>>, new_owner: Option<&'a AccountInfo<'a>>, + new_authority: Option<&UpdateAuthority>, new_plugin: Option<&Plugin>, new_external_plugin_adapter: Option<&ExternalPluginAdapter>, asset_check_fp: fn() -> CheckResult, @@ -344,6 +345,8 @@ pub(crate) fn validate_asset_permissions<'a>( &checks, authority_info, new_owner, + new_authority, + None, new_plugin, Some(asset), collection, @@ -364,6 +367,8 @@ pub(crate) fn validate_asset_permissions<'a>( &checks, authority_info, new_owner, + new_authority, + None, new_plugin, Some(asset), collection, @@ -385,6 +390,8 @@ pub(crate) fn validate_asset_permissions<'a>( &external_checks, authority_info, new_owner, + new_authority, + None, new_plugin, Some(asset), collection, @@ -404,6 +411,8 @@ pub(crate) fn validate_asset_permissions<'a>( &external_checks, authority_info, new_owner, + new_authority, + None, new_plugin, Some(asset), collection, @@ -433,6 +442,7 @@ pub(crate) fn validate_collection_permissions<'a>( accounts: &'a [AccountInfo<'a>], authority_info: &'a AccountInfo<'a>, collection: &'a AccountInfo<'a>, + new_authority: Option<&Pubkey>, new_plugin: Option<&Plugin>, new_external_plugin_adapter: Option<&ExternalPluginAdapter>, collection_check_fp: fn() -> CheckResult, @@ -528,6 +538,8 @@ pub(crate) fn validate_collection_permissions<'a>( &checks, authority_info, None, + None, + new_authority, new_plugin, None, Some(collection), @@ -549,6 +561,8 @@ pub(crate) fn validate_collection_permissions<'a>( &external_checks, authority_info, None, + None, + new_authority, new_plugin, None, Some(collection),