{"_id":"@0xbanana/js","_rev":"1-def51914004b60908838849253c2d698","name":"@0xbanana/js","dist-tags":{"latest":"0.15.1"},"versions":{"0.15.0":{"name":"@0xbanana/js","version":"0.15.0","sideEffects":false,"module":"dist/esm/index.mjs","main":"dist/cjs/index.cjs","types":"dist/types/index.d.ts","exports":{".":{"import":"./dist/esm/index.mjs","require":"./dist/cjs/index.cjs"}},"publishConfig":{"access":"public"},"license":"MIT","description":"Metaplex JavaScript SDK","keywords":["nft","metaplex","solana","blockchain"],"author":{"name":"Metaplex Maintainers","email":"contact@metaplex.com"},"homepage":"https://metaplex.com","repository":{"url":"git+https://github.com/metaplex-foundation/js.git"},"scripts":{"clean":"rimraf dist","build":"yarn clean && tsc && tsc-alias && tsc -p test/tsconfig.json && tsc-alias -p test/tsconfig.json && rollup -c","test":"tape dist/test/**/*.test.js && yarn test:exports","test:exports":"node ./test/cjs-export.test.cjs && node ./test/esm-export.test.mjs","preversion":"yarn build","postversion":"git push --follow-tags"},"dependencies":{"@bundlr-network/client":"^0.7.14","@metaplex-foundation/beet":"^0.4.0","@metaplex-foundation/beet-solana":"^0.3.0","@metaplex-foundation/mpl-auction-house":"^2.1.1","@metaplex-foundation/mpl-candy-machine":"^4.4.1","@metaplex-foundation/mpl-token-metadata":"^2.2.2","@solana/spl-token":"^0.2.0","@solana/web3.js":"^1.47.3","abort-controller":"^3.0.0","bignumber.js":"^9.0.2","bn.js":"^5.2.0","bs58":"^5.0.0","buffer":"^6.0.3","cross-fetch":"^3.1.5","debug":"^4.3.4","eventemitter3":"^4.0.7","lodash.clonedeep":"^4.5.0","lodash.isequal":"^4.5.0","mime":"^3.0.0","tweetnacl":"^1.0.3"},"engines":{"node":">=16.0"},"browserslist":["defaults","not IE 11","maintained node versions"],"typedoc":{"entryPoint":"./src/index.ts","readmeFile":"./README.md","displayName":"js"},"gitHead":"022278a69b45f85ab9dc34470dfdb12a4c01e406","bugs":{"url":"https://github.com/metaplex-foundation/js/issues"},"_id":"@0xbanana/js@0.15.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-5e8EgblpLPik8s46QhTMoo/jl1oQfSEgFypp7p4bdf6hBo/SbbCrzEexAPJWSntjpU7nH5VBIHwyDXy4nWuM2g==","shasum":"1fee7c5bb62d356753a7c1ae32ce6da4511c08ab","tarball":"https://registry.npmjs.org/@0xbanana/js/-/js-0.15.0.tgz","fileCount":1178,"unpackedSize":4382088,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDP1T7efSgDOMpp3YHQy0ZSUWDLZQ5r8V6G2P7Q9trd8QIhANVklzMCB7PHegdTE1M9UBBeMqiy7YITxcuocQMoBCdD"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjJl80ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmo1eg//advTRLVETvjzMPcZXSAYnSFv+7M73nTeTdkJkBh7asscKOzl\r\nHpmE0jSkihdYpjkSYxClCw75zscLuV3ogA8fK6ICroW6jJsnqk/7dDynNdzZ\r\nedsDL5HwI1pJ+6NDCBr2b6Rv3za9TDpKzHpgB3/KVwvnooZZKe+AdumB4Z6q\r\nXufTXS1++qD4vyatZpY3RwtYJByC2bfok5yu2xFH8nG+HQ1JuWC7P81ycRw2\r\nlB5OW06m1uDYA6rXq55ZjSKzNYbkgw0LXDw644vxgBWOm3iN2NOwdeMXpuEh\r\n/u1+EDzjWPSBXjoi8cpX5F4N4mxHG/NpIZGMzywXAC5RFKW890+y4jWRzY+X\r\nucSFvj7KHKmTapvZxgULcPaksdoP0/F59W/E3AoRqCCSKCkfnYpTjFqr5iqL\r\nqaOKhUV1nq2LDBOHOv74hIWrgwDnPT82qB2CZDm9zePS/VBbdbui+qdJPzsI\r\nG1o8ydFlOo0n7LiQmmHCuzzeBWSrqy0MHXstXEzH0mH99va4KSnZVvrkdeHm\r\nTe9RHw7WyCGIMDaJUOc82U8jBmaH3OtPmWrdn7he/YqWNPAsbN7VPr+rkZIk\r\ntaMsT6ufOen8Udtxwxkejepr9bS1ANMxkEQGGQ1IGaU3a03l6vRIyFv+XdkI\r\nQKhtKFO3+V/NDMNQoXiXJlc+KMK6BYf+Dm0=\r\n=wr9I\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"0xbanana","email":"jason@holaplex.com"},"directories":{},"maintainers":[{"name":"0xbanana","email":"jason@holaplex.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/js_0.15.0_1663459124709_0.4817775211549893"},"_hasShrinkwrap":false},"0.15.1":{"name":"@0xbanana/js","version":"0.15.1","sideEffects":false,"module":"dist/esm/index.mjs","main":"dist/cjs/index.cjs","types":"dist/types/index.d.ts","exports":{".":{"import":"./dist/esm/index.mjs","require":"./dist/cjs/index.cjs"}},"publishConfig":{"access":"public"},"license":"MIT","description":"Metaplex JavaScript SDK","keywords":["nft","metaplex","solana","blockchain"],"author":{"name":"Metaplex Maintainers","email":"contact@metaplex.com"},"homepage":"https://metaplex.com","repository":{"url":"git+https://github.com/metaplex-foundation/js.git"},"scripts":{"clean":"rimraf dist","build":"yarn clean && tsc && tsc-alias && tsc -p test/tsconfig.json && tsc-alias -p test/tsconfig.json && rollup -c","test":"tape dist/test/**/*.test.js && yarn test:exports","test:exports":"node ./test/cjs-export.test.cjs && node ./test/esm-export.test.mjs","preversion":"yarn build","postversion":"git push --follow-tags"},"dependencies":{"@bundlr-network/client":"^0.7.14","@metaplex-foundation/beet":"^0.4.0","@metaplex-foundation/beet-solana":"^0.3.0","@metaplex-foundation/mpl-auction-house":"^2.1.1","@metaplex-foundation/mpl-candy-machine":"^4.4.1","@metaplex-foundation/mpl-token-metadata":"^2.2.2","@solana/spl-token":"^0.2.0","@solana/web3.js":"^1.47.3","abort-controller":"^3.0.0","bignumber.js":"^9.0.2","bn.js":"^5.2.0","bs58":"^5.0.0","buffer":"^6.0.3","cross-fetch":"^3.1.5","debug":"^4.3.4","eventemitter3":"^4.0.7","lodash.clonedeep":"^4.5.0","lodash.isequal":"^4.5.0","mime":"^3.0.0","tweetnacl":"^1.0.3"},"engines":{"node":">=16.0"},"browserslist":["defaults","not IE 11","maintained node versions"],"typedoc":{"entryPoint":"./src/index.ts","readmeFile":"./README.md","displayName":"js"},"gitHead":"022278a69b45f85ab9dc34470dfdb12a4c01e406","bugs":{"url":"https://github.com/metaplex-foundation/js/issues"},"_id":"@0xbanana/js@0.15.1","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-JWQs9N4NqAvZi08m8r0iuaBTmwV1YYxQjIAShvh5y3wINRwtGzu4TXwfbmmNCMK9A//JwDQjedtmQbXmiQzXFw==","shasum":"462baeb3436dce61ce4b6c3d27b01db7bdebfaee","tarball":"https://registry.npmjs.org/@0xbanana/js/-/js-0.15.1.tgz","fileCount":1178,"unpackedSize":4381251,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDXIAV5L/Ezb3ezWgq9XsQeXlxjulSl5uqI3cInkhAcQgIgUDybQnjhC8OY4K5CUC1G+G8h7N0PxmvOJ3XV61RIKE8="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJjJmEMACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqGcBAAo9LzIoM8XgCyBWNpfxMacEgen0VT/eePQ/+a2HyNbuHW4QA5\r\nE3HHi0Flp0LqsbCDVYm7laAgRjO9L1+Dh+p7vuj8wih/wuJcWiX55Rm/yiiv\r\nIIeQ5ruVlRv92Mmh0UFAE7P/DW0JLFKCop2Azlo4qDq06lsou+KI1ZqgACUx\r\nd/u9SDzrbWn1WsRty4fKRJcP+Oqz1zBWlPH0RNH7R+VgeV9b60v5BCYRe9l0\r\nmMesh19Amupu2NeSJ+0IoxD+HWSNI75PrUC3wu2xZ1+w9FcyTTsngbAqXZJS\r\nAX0b2j+qgBbiWELVuD7og3O+K4CFx6grkIc41glp5NPG243BdAXxvUbO2n7l\r\n3MiL28AhrDCjP+Cc52gByiAKFD9IdX2aNK8IbFFmAtAU13G5igIV38GriOKf\r\ny25P2O21cqU6l5Zoq9PfMSvi2pOEbWIei4RBFch79wYzvIuDaBJVWcB8r+gd\r\nqdFgcGdC6PJXVIzAwzdCJzTnq7nI6ANiUipemZOI/x0IIGDzUqTNWeh7cLb/\r\ndkSOl4hAsOBOXrSG7cdUkWBP+p6Q0X7RWOIx/DsaUNQ2FkoeyvagsJMQHn3v\r\n3y0HfkX30mF65WaIvsJDRJy6NSCJLF5ZrCBzoNo/Z2097B7FE+KJQZNZLZVD\r\nWOBHLi7U71FfwGiRGek/kevI3fcaDSGSFis=\r\n=a+px\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"0xbanana","email":"jason@holaplex.com"},"directories":{},"maintainers":[{"name":"0xbanana","email":"jason@holaplex.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/js_0.15.1_1663459595533_0.6809600307031511"},"_hasShrinkwrap":false}},"time":{"created":"2022-09-17T23:58:44.626Z","0.15.0":"2022-09-17T23:58:44.916Z","modified":"2022-09-18T00:06:36.046Z","0.15.1":"2022-09-18T00:06:35.972Z"},"maintainers":[{"name":"0xbanana","email":"jason@holaplex.com"}],"description":"Metaplex JavaScript SDK","homepage":"https://metaplex.com","keywords":["nft","metaplex","solana","blockchain"],"repository":{"url":"git+https://github.com/metaplex-foundation/js.git"},"author":{"name":"Metaplex Maintainers","email":"contact@metaplex.com"},"bugs":{"url":"https://github.com/metaplex-foundation/js/issues"},"license":"MIT","readme":"# Metaplex JavaScript SDK\n\nThis SDK helps developers get started with the on-chain tools provided by Metaplex. It focuses its API on common use-cases to provide a smooth developer experience whilst allowing third parties to extend its features via plugins.\n\nPlease note that this SDK has been re-implemented from scratch and is still in active development. This means **some of the core API and interfaces might change from one version to another**. However, feel free to use it and provide some early feedback if you wish to contribute to the direction of this project.\n\n## Installation\n```sh\nnpm install @metaplex-foundation/js @solana/web3.js\n```\n\n🔥 **Pro Tip**: Check out our examples and starter kits on the [\"JS Examples\" repository](https://github.com/metaplex-foundation/js-examples).\n\n## Setup\nThe entry point to the JavaScript SDK is a `Metaplex` instance that will give you access to its API.\n\nIt accepts a `Connection` instance from `@solana/web3.js` that will be used to communicate with the cluster.\n\n```ts\nimport { Metaplex } from \"@metaplex-foundation/js\";\nimport { Connection, clusterApiUrl } from \"@solana/web3.js\";\n\nconst connection = new Connection(clusterApiUrl(\"mainnet-beta\"));\nconst metaplex = new Metaplex(connection);\n```\n\nOn top of that, you can customise who the SDK should interact on behalf of and which storage provider to use when uploading assets. We refer to these as \"Identity Drivers\" and \"Storage Drivers\" respectively. You may change these drivers by calling the `use` method on the Metaplex instance like so. We'll see all available drivers in more detail below.\n\n```ts\nimport { Metaplex, keypairIdentity, bundlrStorage } from \"@metaplex-foundation/js\";\nimport { Connection, clusterApiUrl, Keypair } from \"@solana/web3.js\";\n\nconst connection = new Connection(clusterApiUrl(\"mainnet-beta\"));\nconst wallet = Keypair.generate();\n\nconst metaplex = Metaplex.make(connection)\n    .use(keypairIdentity(wallet))\n    .use(bundlrStorage());\n```\n\nNotice how you can create a `Metaplex` instance using `Metaplex.make(...)` instead of `new Metaplex(...)` in order to make the fluent API more readable.\n\n## Usage\nOnce properly configured, that `Metaplex` instance can be used to access modules providing different sets of features. Currently, there is only one (documented) NFT module that can be accessed via the `nfts()` method. From that module, you will be able to find, create and update NFTs with more features to come.\n\nEvery method that you call on the SDK will return an instance of type `Task<T>` where `T` is the return value you can expect when running the task. For instance, say you want to fetch an NFT via its mint address, you can access the `Task<Nft>` and run it like so:\n\n```ts\nconst task = metaplex.nfts().findByMint(mintAddress);\nconst nft = await task.run();\n\n// Or for short:\nconst nft = await metaplex.nfts().findByMint(mintAddress).run();\n```\n\nThere are several advantages in consistently wrapping these operations into tasks. For instance, you can use the `task` instance to keep track of its progress _and_ you can cancel the task using an `AbortSignal` (similarly to how you cancel an HTTP request).\n\n```ts\n// Access the task that fetches the NFT.\nconst task = metaplex.nfts().findByMint(mintAddress);\n\n// Listen to status changes an log them in the console.\ntask.onStatusChange((status: TaskStatus) => console.log(status));\n\n// Create an AbortController that aborts in 100ms.\nconst abortController = new AbortController();\nsetTimeout(() => abortController.abort(), 100);\n\n// Run the task using the AbortController's signal.\nconst nft = await task.run({ signal: abortController.signal });\n```\n\nWe'll talk more about tasks and what you can do with them [in a later section](#tasks).\n\nNow, let’s look into the NFT module in a bit more detail before moving on to the identity and storage drivers.\n\n## NFTs\nThe NFT module can be accessed via `metaplex.nfts()` and provides the following methods.\n\n- [`findByMint(mint, options)`](#findByMint)\n- [`findAllByMintList(mints, options)`](#findAllByMintList)\n- [`load(metadata, options)`](#load)\n- [`findAllByOwner(owner, options)`](#findAllByOwner)\n- [`findAllByCreator(creator, options)`](#findAllByCreator)\n- [`uploadMetadata(metadata)`](#uploadMetadata)\n- [`create(input)`](#create)\n- [`update(nft, input)`](#update)\n- [`printNewEdition(originalMint, input)`](#printNewEdition)\n- [`use(nft, input)`](#useNft)\n\nAnd the following model, either returned or used by the above methods.\n\n- [The `Nft` model](#the-nft-model)\n\n### findByMint\n\nThe `findByMint` method accepts a `mint` public key and returns [an `Nft` object](#the-nft-model).\n\n```ts\nconst mint = new PublicKey(\"ATe3DymKZadrUoqAMn7HSpraxE4gB88uo1L9zLGmzJeL\");\n\nconst nft = await metaplex.nfts().findByMint(mint).run();\n```\n\nThe returned `Nft` object will have its JSON metadata already loaded so you can, for instance, access its image URL like so (provided it is present in the downloaded metadata).\n\n```ts\nconst imageUrl = nft.json.image;\n```\n\nSimilarly, the `Edition` information of the NFT — original or printed — is also available on the object via the `edition` property. Its type depends on whether the NFT is the original or a printed edition.\n\n```ts\nconst editionAddress = nft.edition.address;\n\nif (nft.edition.isOriginal) {\n    const totalPrintedNfts = nft.edition.supply;\n    const maxNftsThatCanBePrinted = nft.edition.maxSupply;\n} else {\n    const mintAddressOfOriginalNft = nft.edition.parent;\n    const editionNumber = nft.edition.number;\n}\n```\n\nYou can [read more about the `NFT` model below](#the-nft-model).\n\n### findAllByMintList\n\nThe `findAllByMintList` operation accepts an array of mint addresses and returns an array of NFTs. However, `null` values will be returned for each provided mint address that is not associated with an NFT.\n\nNote that this is much more efficient than calling `findByMint` for each mint in the list as the SDK can optimise the query and fetch multiple NFTs in much fewer requests.\n\n```ts\nconst [nftA, nftB] = await metaplex\n    .nfts()\n    .findAllByMintList([mintA, mintB])\n    .run();\n```\n\nNFTs retrieved via `findAllByMintList` may be of type `Metadata` rather than `Nft`.\n\nWhat this means is they won't have their JSON metadata loaded because this would require one request per NFT and could be inefficient if you provide a long list of mint addresses. Additionally, you might want to fetch these on-demand, as the NFTs are being displayed on your web app for instance. The same goes for the `edition` property which requires an extra account to fetch and might be irrelevant until the user clicks on the NFT.\n\nNote that, since plugins can swap operation handlers with their own implementations, it is possible that a plugin relying on indexers return an array of `Nft`s directly instead of `Metadata`s. The default implementation though, will return `Metadata`s.\n\nThus, if you want to load the `json` and/or `edition` properties of an NFT, you need to load that `Metadata` into an `Nft`. Which you can do with the next operation.\n\n### load\n\nFor performance reasons, when fetching NFTs in bulk, you may received `Metadata`s which exclude the JSON Metadata and the Edition information of the NFT. In order to transform a `Metadata` into an `Nft`, you may use the `load` operation like so.\n\n```ts\nconst nft = await metaplex.nfts().load(metadata).run();\n```\n\nThis will give you access to the `json` and `edition` properties of the NFT as explained in [the NFT model documentation](#the-nft-model).\n\n### findAllByOwner\n\nThe `findAllByOwner` method accepts a public key and returns all NFTs owned by that public key.\n\n```ts\nconst myNfts = await metaplex\n    .nfts()\n    .findAllByOwner(metaplex.identity().publicKey)\n    .run();\n```\n\nSimilarly to `findAllByMintList`, the returned NFTs may be `Metadata`s.\n\n### findAllByCreator\n\nThe `findAllByCreator` method accepts a public key and returns all NFTs that have that public key registered as their first creator. Additionally, you may provide an optional position parameter to match the public key at a specific position in the creator list.\n\n```ts\nconst nfts = await metaplex.nfts().findAllByCreator(creatorPublicKey).run();\nconst nfts = await metaplex.nfts().findAllByCreator(creatorPublicKey, { position: 1 }).run(); // Equivalent to the previous line.\nconst nfts = await metaplex.nfts().findAllByCreator(creatorPublicKey, { position: 2 }).run(); // Now matching the second creator field.\n```\n\nSimilarly to `findAllByMintList`, the returned NFTs may be `Metadata`s.\n\n### uploadMetadata\n\nWhen creating or updating an NFT, you will need a URI pointing to some JSON Metadata describing the NFT. Depending on your requirement, you may do this on-chain or off-chain.\n\nIf your JSON metadata is not already uploaded, you may do this using the SDK via the `uploadMetadata` method. It accepts a metadata object and returns the URI of the uploaded metadata. Where exactly the metadata will be uploaded depends on the selected `StorageDriver`.\n\n```ts\nconst { uri } = await metaplex\n    .nfts()\n    .uploadMetadata({\n        name: \"My NFT\",\n        description: \"My description\",\n        image: \"https://arweave.net/123\",\n    })\n    .run();\n\nconsole.log(uri) // https://arweave.net/789\n```\n\nSome properties inside that metadata object will also require you to upload some assets to provide their URI — such as the `image` property on the example above.\n\nTo make this process easier, the `uploadMetadata` method will recognise any instances of `MetaplexFile` within the provided object and upload them in bulk to the current storage driver. It will then create a new version of the provided metadata where all instances of `MetaplexFile` are replaced with their URI. Finally, it will upload that replaced metadata to the storage driver and return it.\n\n```ts\n// Assuming the user uploaded two images via an input field of type \"file\".\nconst browserFiles = event.target.files;\n\nconst { uri, metadata } = await metaplex\n    .nfts()\n    .uploadMetadata({\n        name: \"My NFT\",\n        image: await toMetaplexFileFromBrowser(browserFiles[0]),\n        properties: {\n            files: [\n                {\n                    type: \"video/mp4\",\n                    uri: await toMetaplexFileFromBrowser(browserFiles[1]),\n                },\n            ]\n        }\n    })\n    .run();\n\nconsole.log(metadata.image) // https://arweave.net/123\nconsole.log(metadata.properties.files[0].uri) // https://arweave.net/456\nconsole.log(uri) // https://arweave.net/789\n```\n\nNote that `MetaplexFile`s can be created in various different ways based on where the file is coming from. You can [read more about `MetaplexFile` objects and how to use them here](#MetaplexFile).\n\n### create\n\nThe `create` method accepts [a variety of parameters](src/plugins/nftModule/operations/createNft.ts) that define the on-chain data of the NFT. The only parameters required are its `name`, its `sellerFeeBasisPoints` — i.e. royalties — and the `uri` pointing to its JSON metadata — remember that you can use `uploadMetadata` to get that URI. All other parameters are optional as the SDK will do its best to provide sensible default values.\n\nHere's how you can create a new NFT with minimum configuration.\n\n```ts\nconst { nft } = await metaplex\n    .nfts()\n    .create({\n        uri: \"https://arweave.net/123\",\n        name: \"My NFT\",\n        sellerFeeBasisPoints: 500, // Represents 5.00%.\n    })\n    .run();\n```\n\nThis will take care of creating the mint account, the associated token account, the metadata PDA and the original edition PDA (a.k.a. the master edition) for you.\n\nAdditionally, since no other optional parameters were provided, it will do its best to provide sensible default values for the rest of the parameters. Namely:\n- Since no owner, mint authority or update authority were provided, the “identity” of the SDK will be used by default for these parameters. Meaning the SDK's identity will be the owner of that new NFT.\n- It will also default to setting the identity as the first and only creator with a 100% share.\n- It will default to making the NFT mutable — meaning the update authority will be able to update it later on.\n\nIf some of these default parameters are not suitable for your use case, you may provide them explicitly when creating the NFT. [Here is the exhaustive list of parameters](src/plugins/nftModule/operations/createNft.ts) accepted by the `create` method.\n\n### update\n\nThe `update` method accepts an `Nft` object and a set of parameters to update on the NFT. It then returns a new `Nft` object representing the updated NFT.\n\nFor instance, here is how you would change the on-chain name of an NFT.\n\n```ts\nconst { nft: updatedNft } = await metaplex\n    .nfts()\n    .update(nft, { name: \"My Updated Name\" })\n    .run();\n```\n\nAnything that you don’t provide in the parameters will stay unchanged.\n\nIf you’d like to change the JSON metadata of the NFT, you’d first need to upload a new metadata object using the `uploadMetadata` method and then use the provided URI to update the NFT.\n\n```ts\nconst { uri: newUri } = await metaplex\n    .nfts()\n    .uploadMetadata({\n        ...nft.json,\n        name: \"My Updated Metadata Name\",\n        description: \"My Updated Metadata Description\",\n    })\n    .run();\n\nconst { nft: updatedNft } = await metaplex\n    .nfts()\n    .update(nft, { uri: newUri })\n    .run();\n```\n\n### printNewEdition\n\nThe `printNewEdition` method requires the mint address of the original NFT and returns a brand-new NFT printed from the original edition.\n\nThis is how you would print a new edition of the `originalNft` NFT.\n\n```ts\nconst { nft: printedNft } = await metaplex\n    .nfts()\n    .printNewEdition(originalNft.mint)\n    .run();\n```\n\nBy default, it will print using the token account of the original NFT as proof of ownership, and it will do so using the current `identity` of the SDK. You may customise all of these parameters by providing them explicitly.\n\n```ts\nmetaplex.nfts().printNewEdition(originalMint, {\n  newMint,                   // Defaults to a brand-new Keypair.\n  newUpdateAuthority,        // Defaults to the current identity.\n  newOwner,                  // Defaults to the current identity.\n  payer,                     // Defaults to the current identity.\n  originalTokenAccountOwner, // Defaults to the current identity.\n  originalTokenAccount,      // Defaults to the associated token account of the current identity.\n});\n```\n\nNotice that, by default, update authority will be transfered to the metaplex identity. If you want the printed edition to retain the update authority of the original edition, you might want to provide it explicitly like so.\n\n```ts\nmetaplex.nfts().printNewEdition(originalMint, {\n  newUpdateAuthority: originalNft.updateAuthorityAddress,\n});\n```\n\n### useNft\n\nThe `use` method requires [a usable NFT](https://docs.metaplex.com/programs/token-metadata/using-nfts) and will decrease the amount of uses by one. You may also provide the `numberOfUses` parameter, if you'd like to use it more than once in the same instruction.\n\n```ts\nconst { nft: usedNft } = await mx.nfts().use(nft).run(); // Use once.\nconst { nft: usedNft } = await mx.nfts().use(nft, { numberOfUses: 3 }).run(); // Use three times.\n```\n\n### The `Nft` model\n\nAll of the methods above either return or interact with an `Nft` object. The `Nft` object is a read-only data representation of your NFT that contains all the information you need at the top level.\n\nHere is an overview of the properties that are available on the `Nft` object.\n\n```ts\ntype Nft = Readonly<{\n    model: 'nft';\n    address: PublicKey;\n    metadataAddress: Pda;\n    updateAuthorityAddress: PublicKey;\n    json: Option<Json>;\n    jsonLoaded: boolean;\n    name: string;\n    symbol: string;\n    uri: string;\n    isMutable: boolean;\n    primarySaleHappened: boolean;\n    sellerFeeBasisPoints: number;\n    editionNonce: Option<number>;\n    creators: Creator[];\n    tokenStandard: Option<TokenStandard>;\n    collection: Option<{\n        address: PublicKey;\n        verified: boolean;\n    }>;\n    collectionDetails: Option<{\n        version: 'V1';\n        size: BigNumber;\n    }>;\n    uses: Option<{\n        useMethod: UseMethod;\n        remaining: BigNumber;\n        total: BigNumber;\n    }>;\n    mint: {\n        model: 'mint';\n        address: PublicKey;\n        mintAuthorityAddress: Option<PublicKey>;\n        freezeAuthorityAddress: Option<PublicKey>;\n        decimals: number;\n        supply: SplTokenAmount;\n        isWrappedSol: boolean;\n        currency: SplTokenCurrency;\n    };\n    edition:\n        | {\n            model: 'nftEdition';\n            isOriginal: true;\n            address: PublicKey;\n            supply: BigNumber;\n            maxSupply: Option<BigNumber>;\n        }\n        | {\n            model: 'nftEdition';\n            isOriginal: false;\n            address: PublicKey;\n            parent: PublicKey;\n            number: BigNumber;\n        };\n}>\n```\n\nAdditionally, The SDK may sometimes return a `Metadata` instead of an `Nft` object. The `Metadata` model contains the same data as the `Nft` model but it excludes the following properties: `json`, `mint` and `edition`. This is because they are not always needed and/or can be expensive to load. Therefore, the SDK uses the following rule of thumb:\n- If you're only fetching one NFT — e.g. by using `findByMint` — then you will receive an `Nft` object containing these properties.\n- If you're fetching multiple NFTs — e.g. by using `findAllByMintLint` — then you will receive an array of `Metadata` that do not contain these properties.\n\nYou may obtain an `Nft` object from a `Metadata` object by using [the `load` method](#load) explained above,\n\n## Candy Machines\nThe Candy Machine module can be accessed via `metaplex.candyMachines()` and provides the following documented methods.\n\n- [`findMintedNfts(candyMachine, options)`](#findMintedNfts)\n\nThe Candy Machine actually contains more features and models but we are still in the process of documenting them.\n\n### findMintedNfts\n\nThe `findMintedNfts` method accepts the public key of a Candy Machine and returns all NFTs that have been minted from that Candy Machine so far.\n\nBy default, it will assume you're providing the public key of a Candy Machine v2. If you want to use a different version, you can provide the version as the second parameter.\n\n```ts\nconst nfts = await metaplex.candyMachines().findMintedNfts(candyMachine).run();\nconst nfts = await metaplex.candyMachines().findMintedNfts(candyMachine, { version: 2 }).run(); // Equivalent to the previous line.\nconst nfts = await metaplex.candyMachines().findMintedNfts(candyMachine, { version: 1 }).run(); // Now finding NFTs for Candy Machine v1.\n```\n\nNote that the current implementation of this method delegates to `nfts().findAllByCreator()` whilst fetching the appropriate PDA for Candy Machines v2.\n\nSimilarly to `findAllByMintList`, the returned NFTs may be `Metadata`s.\n\n## Identity\nThe current identity of a `Metaplex` instance can be accessed via `metaplex.identity()` and provide information on the wallet we are acting on behalf of when interacting with the SDK.\n\nThis method returns an identity client with the following interface.\n\n```ts\nclass IdentityClient {\n    driver(): IdentityDriver;\n    setDriver(newDriver: IdentityDriver): void;\n    publicKey: PublicKey;\n    secretKey?: Uint8Array;\n    signMessage(message: Uint8Array): Promise<Uint8Array>;\n    verifyMessage(message: Uint8Array, signature: Uint8Array): boolean;\n    signTransaction(transaction: Transaction): Promise<Transaction>;\n    signAllTransactions(transactions: Transaction[]): Promise<Transaction[]>;\n    equals(that: Signer | PublicKey): boolean;\n    hasSecretKey(): this is KeypairSigner;\n}\n```\n\nThe `IdentityClient` delegates to whichever `IdentityDriver` is currently set to provide this set of methods. Thus, the implementation of these methods depends on the concrete identity driver being used. For instance, in the CLI, these methods will directly use a key pair whereas, in the browser, they will delegate to a wallet adapter.\n\nLet’s have a quick look at the concrete identity drivers available to us.\n\n### guestIdentity\n\nThe `guestIdentity` driver is the default driver and requires no parameter. It is essentially a `null` driver that can be useful when we don’t need to send any signed transactions.\n\n```ts\nimport { guestIdentity } from \"@metaplex-foundation/js\";\n\nmetaplex.use(guestIdentity());\n```\n\nIf we try to sign a message or a transaction using this driver, an error will be thrown.\n\n### keypairIdentity\n\nThe `keypairIdentity` driver accepts a `Keypair` object as a parameter. This is useful when using the SDK locally such as within CLI applications.\n\n```ts\nimport { keypairIdentity } from \"@metaplex-foundation/js\";\nimport { Keypair } from \"@solana/web3.js\";\n\n// Load a local keypair.\nconst keypairFile = fs.readFileSync('/Users/username/.config/solana/id.json');\nconst keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(keypairFile.toString())));\n\n// Use it in the SDK.\nmetaplex.use(keypairIdentity(keypair));\n```\n\n### walletAdapterIdentity\n\nThe `walletAdapterIdentity` driver accepts a wallet adapter as defined by the [“wallet-adapter” repo from Solana Labs](https://github.com/solana-labs/wallet-adapter). This is useful when using the SDK in a web application that requires the user to manually approve transactions.\n\n```ts\nimport { walletAdapterIdentity } from \"@metaplex-foundation/js\";\nimport { useWallet } from '@solana/wallet-adapter-react';\n\nconst wallet = useWallet();\nmetaplex.use(walletAdapterIdentity(wallet));\n```\n\n## Storage\nYou may access the storage client using `metaplex.storage()` which will give you access to the following interface.\n\n```ts\nclass StorageClient {\n    driver(): StorageDriver\n    setDriver(newDriver: StorageDriver): void;\n    getUploadPriceForBytes(bytes: number): Promise<Amount>;\n    getUploadPriceForFile(file: MetaplexFile): Promise<Amount>;\n    getUploadPriceForFiles(files: MetaplexFile[]): Promise<Amount>;\n    upload(file: MetaplexFile): Promise<string>;\n    uploadAll(files: MetaplexFile[]): Promise<string[]>;\n    uploadJson<T extends object = object>(json: T): Promise<string>;\n    download(uri: string, options?: RequestInit): Promise<MetaplexFile>;\n    downloadJson<T extends object = object>(uri: string, options?: RequestInit): Promise<T>;\n}\n```\n\nSimilarly to the `IdentityClient`, the `StorageClient` delegates to the current `StorageDriver` when executing these methods. We'll take a look at the storage drivers available to us, but first, let's talk about the `MetaplexFile` type which is being used throughout the `StorageClient` API.\n\n### MetaplexFile\n\nThe `MetaplexFile` type is a simple wrapper around `Buffer` that adds additional context relevant to files and assets such as their filename, content type, extension, etc. It contains the following data.\n\n```ts\ntype MetaplexFile = Readonly<{\n    buffer: Buffer;\n    fileName: string;\n    displayName: string;\n    uniqueName: string;\n    contentType: string | null;\n    extension: string | null;\n    tags: MetaplexFileTag[];\n}>\n```\n\nYou may use the `toMetaplexFile` function to create a `MetaplexFile` object from a `Buffer` instance (or content `string`) and a filename. The filename is necessary to infer the extension and the mime type of the provided file.\n\n```ts\nconst file = toMetaplexFile('The content of my file', 'my-file.txt');\n```\n\nYou may also explicitly provide these options by passing a third parameter to the constructor.\n\n```ts\nconst file = toMetaplexFile('The content of my file', 'my-file.txt', {\n    displayName = 'A Nice Title For My File'; // Defaults to the filename.\n    uniqueName = 'my-company/files/some-identifier'; // Defaults to a random string.\n    contentType = 'text/plain'; // Infer it from filename by default.\n    extension = 'txt'; // Infer it from filename by default.\n    tags = [{ name: 'my-tag', value: 'some-value' }]; // Defaults to [].\n});\n```\n\nNote that if you want to create a `MetaplexFile` directly from a JSON object, there's a `toMetaplexFileFromJson` helper method that you can use like so.\n\n```ts\nconst file = toMetaplexFileFromJson({ foo: 42 });\n```\n\nIn practice, you will most likely be creating `MetaplexFile`s from files either present on your computer or uploaded by some user on the browser. You can do the former by using `fs.readFileSync`.\n\n```ts\nconst buffer = fs.readFileSync('/path/to/my-file.txt');\nconst file = toMetaplexFile(buffer, 'my-file.txt');\n```\n\nAnd the latter by using the `toMetaplexFileFromBrowser` helper method which accepts a `File` object as defined in the browser.\n\n```ts\nconst browserFile: File = event.target.files[0];\nconst file: MetaplexFile = await toMetaplexFileFromBrowser(browserFile);\n```\n\nOkay, now let’s talk about the concrete storage drivers available to us and how to set them up.\n\n### bundlrStorage\n\nThe `bundlrStorage` driver is the default driver and uploads assets on Arweave using the [Bundlr network](https://bundlr.network/).\n\nBy default, it will use the same RPC endpoint used by the `Metaplex` instance as a `providerUrl` and the mainnet address `\"https://node1.bundlr.network\"` as the Bundlr address.\n\nYou may customise these by passing a parameter object to the `bundlrStorage` method. For instance, here’s how you can use Bundlr on devnet.\n\n```ts\nimport { bundlrStorage } from \"@metaplex-foundation/js\";\n\nmetaplex.use(bundlrStorage({\n    address: 'https://devnet.bundlr.network',\n    providerUrl: 'https://api.devnet.solana.com',\n    timeout: 60000,\n}));\n```\n\nTo fund your bundlr storage account you can cast it in TypeScript like so:\n\n```ts\nconst bundlrStorage = metaplex.storage().driver() as BundlrStorageDriver;\n```\n\nThis gives you access to useful public methods such as:\n\n```ts\nbundlrStorage.fund([metaplexFile1, metaplexFile2]); // Fund using file size.\nbundlrStorage.fund(1000); // Fund using byte size.\n(await bundlrStorage.bundlr()).fund(1000); // Fund using lamports directly.\n```\n\n\n### awsStorage\n\nThe `awsStorage` driver uploads assets off-chain to an S3 bucket of your choice.\n\nThis storage driver is not bundled by the JS SDK by default, you first need to install it by running:\n\n```sh\nnpm install @metaplex-foundation/js-plugin-aws\n```\n\nThen, to set this up, you need to pass in the AWS client as well as the bucket name you wish to use. For instance:\n\n```ts\nimport { awsStorage } from \"@metaplex-foundation/js-plugin-aws\";\nimport { S3Client } from \"@aws-sdk/client-s3\";\n\nconst awsClient = new S3Client({\n    region: \"us-east-1\",\n    credentials: {\n      accessKeyId: \"\",\n      secretAccessKey: \"\",\n    },\n  });\n\nmetaplex.use(awsStorage(awsClient, 'my-nft-bucket'));\n```\n\nWhen uploading a `MetaplexFile` using `metaplex.storage().upload(file)`, the unique name of the file will be used as the AWS key. By default, this will be a random string generated by the SDK but you may explicitly provide your own like so.\n\n```ts\nconst file = toMetaplexFile('file-content', 'filename.jpg', {\n    uniqueName: 'my-unique-aws-key',\n})\n\nconst uri = await metaplex.storage().upload(file);\n```\n\n### mockStorage\n\nThe `mockStorage` driver is a fake driver mostly used for testing purposes. It will not actually upload the assets anywhere but instead will generate random URLs and keep track of their content in a local dictionary. That way, once uploaded, an asset can be retrieved using the `download` method.\n\n```ts\nimport { mockStorage } from \"@metaplex-foundation/js\";\n\nmetaplex.use(mockStorage());\n```\n\n## Tasks\n\nTasks are a core component of the JS SDK and enable you to do more with your asynchronous operations. This includes:\n\n- Cancelling asynchronous operations via `AbortController`s.\n- Listening to status updates — e.g. pending, running, failed, etc.\n- Nesting tasks together to create and keep track of more complex asynchronous operations.\n\nThe client of every module will return a `Task<T>` object where `T` is the return value you can expect when running the task using `await task.run()`.\n\nHere's an overview of the methods available in `Task` objects.\n\n```ts\nclass Task<T> = {\n    getStatus: () => TaskStatus;\n    getResult: () => T | undefined;\n    getError: () => unknown;\n    isPending: () => boolean;\n    isRunning: () => boolean;\n    isCompleted: () => boolean;\n    isSuccessful: () => boolean;\n    isFailed: () => boolean;\n    isCanceled: () => boolean;\n    run: (options?: TaskOptions) => Promise<T>;\n    loadWith: (preloadedResult: T) => Task<T>;\n    reset: () => Task<T>;\n    onStatusChange: (callback: (status: TaskStatus) => unknown) => Task<T>;\n    onStatusChangeTo: (status: TaskStatus, callback: () => unknown) => Task<T>;\n    onSuccess: (callback: () => unknown) => Task<T>;\n    onFailure: (callback: () => unknown) => Task<T>;\n    onCancel: (callback: () => unknown) => Task<T>;\n    setChildren: (children: Task<any>[]) => Task<T>;\n    getChildren: () => Task<any>[];\n    getDescendants: () => Task<any>[];\n    setContext: (context: object) => Task<T>;\n    getContext: () => object;\n};\n\nexport type TaskOptions = {\n    signal?: AbortSignal;\n    force?: boolean;\n};\n```\n\nAs you can see, you get a bunch of methods to check the status of a task, listen to its changes, run it and reset its data. You also get a `loadWith` method which allows you to bypass the task and load the provided data directly.\n\nYou may also provide an `AbortSignal` using the `signal` property of the `TaskOptions` when running a task, allowing you to cancel the task if you need to. This needs to be supported by the concrete implementation of the task as they will have to consistently check that the task was not cancelled and return early if it was. The `force` property of `TaskOptions` can be used to force the task to run even if the task was already completed.\n\nTasks can also contain nested Tasks to keep track of the progress of a more complex operation if needed. You may use the `setChildren` and `getChildren` methods to add and retrieve nested tasks. The `getDescendants` method returns all the children of the task recursively.\n\nFinally, you can set a context for the task using the `setContext` and `getContext` methods. This is useful for passing any custom data to a task such as a \"name\" and a \"description\" that can be used by the UI.\n","readmeFilename":"README.md"}