Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6b52ea56b | ||
|
|
da95dce580 | ||
|
|
44dbf283c9 | ||
|
+1 |
d844714609 | ||
|
|
5cea8436c1 | ||
|
|
dac8fa7d98 | ||
|
|
7a6534d1a9 | ||
|
|
d5aee62bf4 | ||
|
|
0bfdedd4ba | ||
|
|
c5761b99e9 | ||
|
|
42d9ab68d9 | ||
|
|
fd0650dcac | ||
|
|
ddb3dabe69 | ||
|
|
b96a228273 | ||
|
|
781e26d896 | ||
|
|
f7392138ee | ||
|
|
5eb6fc1bf3 | ||
|
|
7dc685bbec | ||
|
|
4915ac50f8 | ||
|
|
d724ad85c5 | ||
|
|
1d32b299a0 | ||
|
|
cfa7ecbc9a | ||
|
|
8dd7540c45 | ||
|
|
07c7d97c28 |
@@ -131,3 +131,4 @@ jobs:
|
||||
run: pnpm e2e
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
CLI_E2E_API_KEY: ${{ secrets.CLI_E2E_API_KEY }}
|
||||
|
||||
+4
-4
@@ -38,15 +38,15 @@
|
||||
"@changesets/get-dependents-graph": "^1.3.6",
|
||||
"@changesets/get-release-plan": "^3.0.17",
|
||||
"@changesets/parse": "^0.3.16",
|
||||
"@manypkg/cli": "^0.20.0",
|
||||
"@manypkg/cli": "^0.21.0",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@playwright/test": "1.31.2",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||
"@types/node": "^18.16.18",
|
||||
"eslint": "^8.43.0",
|
||||
"eslint": "^8.45.0",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.8",
|
||||
"turbo": "^1.10.6",
|
||||
"prettier": "^3.0.0",
|
||||
"turbo": "^1.10.7",
|
||||
"yalc": "1.0.0-pre.53"
|
||||
},
|
||||
"manypkg": {
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 3.2.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b)]:
|
||||
- @thirdweb-dev/wallets@1.1.0
|
||||
|
||||
## 3.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`c5761b99`](https://github.com/thirdweb-dev/js/commit/c5761b99e9797772481506e90cbfa5c35a05bd1d), [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220)]:
|
||||
- @thirdweb-dev/wallets@1.0.12
|
||||
|
||||
## 3.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/wallets@1.0.11
|
||||
|
||||
## 3.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.14",
|
||||
"version": "3.2.17",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
@@ -101,7 +101,7 @@
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"chai": "^4.3.6",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"eslint": "^8.43.0",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
@@ -113,7 +113,7 @@
|
||||
"mocha": "^10.2.0",
|
||||
"next": "^12.3.4",
|
||||
"next-auth": "^4.22.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.0.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Adds support for clientId / secretKey
|
||||
|
||||
## 0.1.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1338](https://github.com/thirdweb-dev/js/pull/1338) [`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
|
||||
|
||||
## 0.1.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "ChainX-EVM",
|
||||
"name": "BEVM",
|
||||
"chain": "ChainX",
|
||||
"rpc": [
|
||||
"https://chainx-evm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://bevm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.chainx.org/rpc",
|
||||
"https://mainnet2.chainx.org/rpc"
|
||||
],
|
||||
@@ -19,11 +19,11 @@ export default {
|
||||
"networkId": 1501,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "chainx-evm scan",
|
||||
"name": "bevm scan",
|
||||
"url": "https://evm.chainx.org",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "chainx-evm"
|
||||
"slug": "bevm"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Antofy Mainnet",
|
||||
"chain": "ABN",
|
||||
"icon": {
|
||||
"url": "ipfs://QmdTfku81ohnG9ECU1Xswmeumt678cBhwHWuFYZ7i1Qsto",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://antofy.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.antofy.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.antofy.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Antofy",
|
||||
"symbol": "ABN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://antofy.io",
|
||||
"shortName": "ABNm",
|
||||
"chainId": 2202,
|
||||
"networkId": 2202,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Antofy Mainnet",
|
||||
"url": "https://antofyscan.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "antofy"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Antofy Testnet",
|
||||
"chain": "ABN",
|
||||
"icon": {
|
||||
"url": "ipfs://QmdTfku81ohnG9ECU1Xswmeumt678cBhwHWuFYZ7i1Qsto",
|
||||
"width": 400,
|
||||
"height": 400,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://antofy-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet-rpc.antofy.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.antofy.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "Antofy",
|
||||
"symbol": "ABN",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://antofy.io",
|
||||
"shortName": "ABNt",
|
||||
"chainId": 23006,
|
||||
"networkId": 23006,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Antofy Testnet",
|
||||
"url": "https://test.antofyscan.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "antofy-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -2,10 +2,10 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Kroma Sepolia",
|
||||
"title": "Kroma Testnet Sepolia",
|
||||
"chainId": 2357,
|
||||
"chainId": 2358,
|
||||
"shortName": "kroma-sepolia",
|
||||
"chain": "ETH",
|
||||
"networkId": 2357,
|
||||
"networkId": 2358,
|
||||
"nativeCurrency": {
|
||||
"name": "Sepolia Ether",
|
||||
"symbol": "ETH",
|
||||
@@ -2,10 +2,7 @@ import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Neon EVM MainNet",
|
||||
"chain": "Solana",
|
||||
"rpc": [
|
||||
"https://neon-evm.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://mainnet.neonevm.org"
|
||||
],
|
||||
"rpc": [],
|
||||
"faucets": [],
|
||||
"icon": {
|
||||
"url": "ipfs://Qmcxevb3v8PEvnvfYgcG3bCBuPhe5YAdsHeaufDChSSR3Q",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "EgonCoin Mainnet",
|
||||
"chain": "EGON",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNZiMmzMQYjyGtNSghtzLg4UooYhDgMQsa677DAP5KsBg",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://egoncoin.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.egcscan.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.egcscan.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "EgonCoin",
|
||||
"symbol": "EGON",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://egcscan.com",
|
||||
"shortName": "EGONm",
|
||||
"chainId": 271,
|
||||
"networkId": 271,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "EgonCoin Mainnet",
|
||||
"url": "https://egcscan.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "egoncoin"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "EgonCoin Testnet",
|
||||
"chain": "EGON",
|
||||
"icon": {
|
||||
"url": "ipfs://QmNZiMmzMQYjyGtNSghtzLg4UooYhDgMQsa677DAP5KsBg",
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://egoncoin-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpctest.egcscan.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.egcscan.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "EgonCoin",
|
||||
"symbol": "EGON",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://egcscan.com",
|
||||
"shortName": "EGONt",
|
||||
"chainId": 271271,
|
||||
"networkId": 271271,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "EgonCoin Testnet",
|
||||
"url": "https://testnet.egcscan.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "egoncoin-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "SenjePowers Mainnet",
|
||||
"chain": "SPC",
|
||||
"icon": {
|
||||
"url": "ipfs://QmcpyTj4hUyHJZ2VmSdkXFpPpRcNKRP1VxMs7Cp1anymNy",
|
||||
"width": 504,
|
||||
"height": 495,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://senjepowers.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.senjepowersscan.com"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.senjepowersscan.com"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "SenjePowers",
|
||||
"symbol": "SPC",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://senjepowersscan.com",
|
||||
"shortName": "SPCm",
|
||||
"chainId": 3699,
|
||||
"networkId": 3699,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "SenjePowers",
|
||||
"url": "https://senjepowersscan.com",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "senjepowers"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Toronet Testnet",
|
||||
"chain": "Toronet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmciSvgLatP6jhgdazuiyD3fSrhipfAN7wC943v1qxcrpv",
|
||||
"width": 846,
|
||||
"height": 733,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://toronet-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://testnet.toronet.org/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Toro",
|
||||
"symbol": "TORO",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://toronet.org",
|
||||
"shortName": "ToronetTestnet",
|
||||
"chainId": 54321,
|
||||
"networkId": 54321,
|
||||
"ens": {
|
||||
"registry": "0x059C474f26D65B0458F9da10A649a7322aB02C09"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "toronet_explorer",
|
||||
"url": "https://testnet.toronet.org",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "toronet-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,34 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Bitrock Mainnet",
|
||||
"chain": "Bitrock",
|
||||
"icon": {
|
||||
"url": "ipfs://QmfXZCAh3HWS2bJroUStN9TieL4QA9QArMotie3X4pwBfj",
|
||||
"width": 72,
|
||||
"height": 72,
|
||||
"format": "svg"
|
||||
},
|
||||
"rpc": [
|
||||
"https://bitrock.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://connect.bit-rock.io"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "BITROCK",
|
||||
"symbol": "BROCK",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://bit-rock.io",
|
||||
"shortName": "bitrock",
|
||||
"chainId": 7171,
|
||||
"networkId": 7171,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Bitrock Explorer",
|
||||
"url": "https://scan.bit-rock.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "bitrock"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Bitrock Testnet",
|
||||
"chain": "Bitrock",
|
||||
"icon": {
|
||||
"url": "ipfs://QmfXZCAh3HWS2bJroUStN9TieL4QA9QArMotie3X4pwBfj",
|
||||
"width": 72,
|
||||
"height": 72,
|
||||
"format": "svg"
|
||||
},
|
||||
"rpc": [
|
||||
"https://bitrock-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://testnet.bit-rock.io"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet.bit-rock.io"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "BITROCK",
|
||||
"symbol": "BROCK",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://bit-rock.io",
|
||||
"shortName": "tbitrock",
|
||||
"chainId": 7771,
|
||||
"networkId": 7771,
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Bitrock Testnet Explorer",
|
||||
"url": "https://testnetscan.bit-rock.io",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "bitrock-testnet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Toronet Mainnet",
|
||||
"chain": "Toronet",
|
||||
"icon": {
|
||||
"url": "ipfs://QmciSvgLatP6jhgdazuiyD3fSrhipfAN7wC943v1qxcrpv",
|
||||
"width": 846,
|
||||
"height": 733,
|
||||
"format": "png"
|
||||
},
|
||||
"rpc": [
|
||||
"https://toronet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"http://toronet.org/rpc"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Toro",
|
||||
"symbol": "TORO",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://toronet.org",
|
||||
"shortName": "Toronet",
|
||||
"chainId": 77777,
|
||||
"networkId": 77777,
|
||||
"ens": {
|
||||
"registry": "0x1f45a71f4aAD769E27c969c4359E0e250C67165c"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "toronet_explorer",
|
||||
"url": "https://toronet.org/explorer",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "toronet"
|
||||
} as const satisfies Chain;
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "ARDENIUM Athena",
|
||||
"chain": "ATHENA",
|
||||
"rpc": [
|
||||
"https://ardenium-athena.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc-athena.ardescan.com/"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucet-athena.ardescan.com/"
|
||||
],
|
||||
"nativeCurrency": {
|
||||
"name": "ARD",
|
||||
"symbol": "tARD",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://ardenium.org",
|
||||
"shortName": "ard",
|
||||
"chainId": 7895,
|
||||
"networkId": 7895,
|
||||
"icon": {
|
||||
"url": "ipfs://QmdwifhejRfF8QfyzYrNdFVhfhCR6iuzWMmppK4eL7kttG",
|
||||
"width": 120,
|
||||
"height": 120,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "ARDENIUM Athena Explorer",
|
||||
"icon": {
|
||||
"url": "ipfs://QmdwifhejRfF8QfyzYrNdFVhfhCR6iuzWMmppK4eL7kttG",
|
||||
"width": 120,
|
||||
"height": 120,
|
||||
"format": "png"
|
||||
},
|
||||
"url": "https://testnet.ardscan.com",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"slug": "ardenium-athena"
|
||||
} as const satisfies Chain;
|
||||
@@ -3,7 +3,8 @@ export default {
|
||||
"name": "Base",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://base.rpc.thirdweb.com/${THIRDWEB_API_KEY}"
|
||||
"https://base.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://developer-access-mainnet.base.org/"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
@@ -15,13 +16,25 @@ export default {
|
||||
"shortName": "base",
|
||||
"chainId": 8453,
|
||||
"networkId": 8453,
|
||||
"status": "active",
|
||||
"icon": {
|
||||
"url": "ipfs://QmW5Vn15HeRkScMfPcW12ZdZcC2yUASpu6eCsECRdEmjjj/base-512.png",
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "basescout",
|
||||
"url": "https://base.blockscout.com",
|
||||
"standard": "none"
|
||||
},
|
||||
{
|
||||
"name": "basescan",
|
||||
"url": "https://basescan.org",
|
||||
"standard": "none"
|
||||
}
|
||||
],
|
||||
"status": "active",
|
||||
"testnet": false,
|
||||
"slug": "base"
|
||||
} as const satisfies Chain;
|
||||
@@ -18,6 +18,12 @@ export default {
|
||||
"shortName": "basegor",
|
||||
"chainId": 84531,
|
||||
"networkId": 84531,
|
||||
"icon": {
|
||||
"url": "ipfs://QmW5Vn15HeRkScMfPcW12ZdZcC2yUASpu6eCsECRdEmjjj/base-512.png",
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "basescout",
|
||||
@@ -31,11 +37,5 @@ export default {
|
||||
}
|
||||
],
|
||||
"testnet": true,
|
||||
"icon": {
|
||||
"url": "ipfs://QmW5Vn15HeRkScMfPcW12ZdZcC2yUASpu6eCsECRdEmjjj/base-512.png",
|
||||
"height": 512,
|
||||
"width": 512,
|
||||
"format": "png"
|
||||
},
|
||||
"slug": "base-goerli"
|
||||
} as const satisfies Chain;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.33",
|
||||
"version": "0.1.35",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -69,6 +69,64 @@ export function getChainRPCs(
|
||||
return processedRPCs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct the list of RPC URLs given a specific chain config. Format any RPC URLs
|
||||
* with necessary clientId/secretKey and returns the first valid one.
|
||||
*
|
||||
* @param chain - The chain config to assemble RPC URLs from
|
||||
* @param clientId - The client id to use for the RPC URL
|
||||
* @param secretKey - The secret key to use for the RPC URL
|
||||
* @returns The first valid RPC URL for the chain
|
||||
*/
|
||||
export function getValidChainRPCs(
|
||||
chain: Pick<Chain, "rpc" | "chainId">,
|
||||
clientId?: string,
|
||||
mode: "http" | "ws" = "http",
|
||||
): string[] {
|
||||
const processedRPCs: string[] = [];
|
||||
|
||||
chain.rpc.forEach((rpc) => {
|
||||
// exclude RPC if mode mismatch
|
||||
if (mode === "http" && !rpc.startsWith("http")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === "ws" && !rpc.startsWith("ws")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace API_KEY placeholder with value
|
||||
if (rpc.includes("${THIRDWEB_API_KEY}")) {
|
||||
if (clientId) {
|
||||
processedRPCs.push(rpc.replace("${THIRDWEB_API_KEY}", clientId));
|
||||
} else {
|
||||
// if no client id, let it through with empty string
|
||||
// if secretKey is present, it will be used in header
|
||||
// if none are passed, will have reduced access
|
||||
processedRPCs.push(rpc.replace("${THIRDWEB_API_KEY}", ""));
|
||||
}
|
||||
}
|
||||
|
||||
// exclude RPCs with unknown placeholder
|
||||
else if (rpc.includes("${")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add as is
|
||||
else {
|
||||
processedRPCs.push(rpc);
|
||||
}
|
||||
});
|
||||
|
||||
if (processedRPCs.length === 0) {
|
||||
throw new Error(
|
||||
`No RPC available for chainId "${chain.chainId}" with mode ${mode}`,
|
||||
);
|
||||
}
|
||||
|
||||
return processedRPCs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest priority RPC URL for a specific chain
|
||||
*
|
||||
@@ -118,3 +176,18 @@ export function configureChain(
|
||||
// prepend additional RPCs to the chain's RPCs
|
||||
return { ...chain, rpc: [...additionalRPCs, ...chain.rpc] };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* use the clientId and return a new chain object with updated RPCs
|
||||
*/
|
||||
export function updateChainRPCs(chain: Chain, clientId?: string) {
|
||||
try {
|
||||
return {
|
||||
...chain,
|
||||
rpc: getValidChainRPCs(chain, clientId),
|
||||
};
|
||||
} catch (error) {
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,50 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Introducing API secret key restrictions for certain commands. Get your API secret key from [here](https://thirdweb.com/dashboard/settings/api-keys).
|
||||
|
||||
The following commands will require you to have logged in with your API secret key:
|
||||
|
||||
- `thirdweb deploy`
|
||||
- `thirdweb release`
|
||||
- `thirdweb publish`
|
||||
- `thirdweb upload`
|
||||
|
||||
Implemented 2 new commands for managing your session with the CLI:
|
||||
|
||||
- thirdweb login
|
||||
- thirdweb logout
|
||||
|
||||
Note: If you try to call a command that requires you to be logged in, you will be prompted to login.
|
||||
|
||||
Updated chains.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`44dbf283`](https://github.com/thirdweb-dev/js/commit/44dbf283c985f3e2ecbeb1cfdf09fe1d84e26298), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b)]:
|
||||
- @thirdweb-dev/storage@1.2.0
|
||||
- @thirdweb-dev/sdk@3.10.37
|
||||
- @thirdweb-dev/chains@0.1.35
|
||||
|
||||
## 0.10.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`dac8fa7d`](https://github.com/thirdweb-dev/js/commit/dac8fa7d98b6952acf8d13e173099889c1d47da8)]:
|
||||
- @thirdweb-dev/sdk@3.10.36
|
||||
|
||||
## 0.10.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b), [`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b)]:
|
||||
- @thirdweb-dev/storage@1.1.9
|
||||
- @thirdweb-dev/chains@0.1.34
|
||||
- @thirdweb-dev/sdk@3.10.35
|
||||
|
||||
## 0.10.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ERROR_MESSAGES } from "../constants/constants";
|
||||
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
|
||||
import { copyFile } from "fs/promises";
|
||||
import { resolve } from "path";
|
||||
import { ERROR_MESSAGES } from "../constants/constants";
|
||||
|
||||
// this creates an app, can take some time that's fine
|
||||
jest.setTimeout(120_000);
|
||||
@@ -9,6 +9,14 @@ jest.setTimeout(120_000);
|
||||
describe("npx thirdweb deploy", () => {
|
||||
it("should return deploy page url", async () => {
|
||||
const { spawn, cleanup, exists, path } = await prepareEnvironment();
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const apiSecretKey = process.env.CLI_E2E_API_KEY as string;
|
||||
|
||||
if (!apiSecretKey) {
|
||||
throw new Error(
|
||||
"CLI_E2E_API_KEY is not set in the environment variables",
|
||||
);
|
||||
}
|
||||
|
||||
await copyFile(
|
||||
resolve("./e2e/files/BasicContract.sol"),
|
||||
@@ -16,7 +24,10 @@ describe("npx thirdweb deploy", () => {
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js deploy --contract");
|
||||
await spawn(
|
||||
"node",
|
||||
`./dist/cli/index.js deploy --contract -k ${apiSecretKey}`,
|
||||
);
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
import { ERROR_MESSAGES } from "../constants/constants";
|
||||
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
|
||||
import { copyFile } from "fs/promises";
|
||||
import { resolve } from "path";
|
||||
import { ERROR_MESSAGES } from "../constants/constants";
|
||||
|
||||
// this creates an app, can take some time that's fine
|
||||
jest.setTimeout(120_000);
|
||||
|
||||
describe("npx thirdweb publish", () => {
|
||||
it("should return publish page url", async () => {
|
||||
// TOOD: turn this test back on when we figure out why it's failing
|
||||
it.skip("should return publish page url", async () => {
|
||||
const { spawn, cleanup, exists, path } = await prepareEnvironment();
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const apiSecretKey = process.env.CLI_E2E_API_KEY as string;
|
||||
|
||||
if (!apiSecretKey) {
|
||||
throw new Error(
|
||||
"CLI_E2E_API_KEY is not set in the environment variables",
|
||||
);
|
||||
}
|
||||
|
||||
await copyFile(
|
||||
resolve("./e2e/files/BasicContract.sol"),
|
||||
@@ -16,7 +25,7 @@ describe("npx thirdweb publish", () => {
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js publish");
|
||||
await spawn("node", `./dist/cli/index.js publish -k ${apiSecretKey}}`);
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.10.35",
|
||||
"version": "0.11.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -28,7 +28,7 @@
|
||||
"hardhat": "^2.16.1",
|
||||
"jest": "^29.4.3",
|
||||
"ora": "^6.3.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.0.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-node": "^10.7.0",
|
||||
"tsup": "^6.7.0",
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import chalk from "chalk";
|
||||
import prompts from "prompts";
|
||||
import Cache, { CacheEntry } from "sync-disk-cache";
|
||||
import { ApiResponse } from "../lib/types";
|
||||
|
||||
export async function loginUser(
|
||||
cache: Cache,
|
||||
options?: { new: boolean },
|
||||
showLogs?: boolean,
|
||||
) {
|
||||
const keyFound = getSession(cache);
|
||||
if (keyFound && !options?.new) {
|
||||
if (showLogs) {
|
||||
console.log(chalk.green("You are already logged in"));
|
||||
}
|
||||
return keyFound;
|
||||
} else {
|
||||
const apiKey = await createSession(cache);
|
||||
return apiKey;
|
||||
}
|
||||
}
|
||||
|
||||
export async function logoutUser(cache: Cache) {
|
||||
try {
|
||||
cache.remove("api-secret-key");
|
||||
console.log(chalk.green("You have been logged out"));
|
||||
} catch (error) {
|
||||
console.log(chalk.red("Something went wrong", error));
|
||||
}
|
||||
}
|
||||
|
||||
export function getSession(cache: Cache) {
|
||||
try {
|
||||
const apiKey: CacheEntry = cache.get("api-secret-key");
|
||||
return apiKey.value;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function createSession(cache: Cache) {
|
||||
try {
|
||||
const response = await prompts({
|
||||
type: "text",
|
||||
name: "apiSecretKey",
|
||||
message: `Please enter your API secret key, you can find or create it on ${chalk.blue(
|
||||
"https://thirdweb.com/create-api-key",
|
||||
)}`,
|
||||
});
|
||||
|
||||
try {
|
||||
await validateKey(response.apiSecretKey);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
process.exit(1);
|
||||
}
|
||||
cache.set("api-secret-key", response.apiSecretKey);
|
||||
return response.apiSecretKey;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateKey(apiSecretKey: string) {
|
||||
const fetch = (await import("node-fetch")).default;
|
||||
// TODO: CHANGE THIS TO PROD BEFORE MERGING!!!
|
||||
const response = await fetch(
|
||||
`https://api.thirdweb.com/v1/keys/use?scope=storage`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-secret-key": apiSecretKey,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const apiResponse = (await response.json()) as ApiResponse;
|
||||
|
||||
if (!response.ok) {
|
||||
const { error } = apiResponse;
|
||||
throw new Error(chalk.red(error.message));
|
||||
} else {
|
||||
return apiSecretKey;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,34 @@
|
||||
#!/usr/bin/env node
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { detectProject } from "../common/project-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger, spinner } from "../core/helpers/logger";
|
||||
import { CacheEntry } from "../core/types/cache";
|
||||
import { twCreate } from "../create/command";
|
||||
import { deploy } from "../deploy";
|
||||
import { generate } from "../generate/command";
|
||||
import { findPackageInstallation } from "../helpers/detect-local-packages";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { exec, spawn } from "child_process";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import prompts from "prompts";
|
||||
import Cache from "sync-disk-cache";
|
||||
import Cache, { CacheEntry } from "sync-disk-cache";
|
||||
import { loginUser, logoutUser, validateKey } from "../auth";
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { detectProject } from "../common/project-detector";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger, spinner } from "../core/helpers/logger";
|
||||
import { twCreate } from "../create/command";
|
||||
import { deploy } from "../deploy";
|
||||
import { generate } from "../generate/command";
|
||||
import { findPackageInstallation } from "../helpers/detect-local-packages";
|
||||
import { install } from "../install";
|
||||
import { upload } from "../storage/command";
|
||||
|
||||
const main = async () => {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
|
||||
|
||||
const program = new Command();
|
||||
const cache = new Cache("thirdweb:cli");
|
||||
const cache = new Cache("thirdweb:cli", {
|
||||
location: path.join(os.homedir(), ".thirdweb", "creds"),
|
||||
});
|
||||
|
||||
// yes this has to look like this, eliminates whitespace
|
||||
if (!skipIntro) {
|
||||
@@ -205,8 +209,8 @@ const main = async () => {
|
||||
.option("--nightly", "Install the nightly version of packages.")
|
||||
.option("--dev", "Install the dev version of packages")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.action(async (path, options) => {
|
||||
await install(path, options);
|
||||
.action(async (_path, options) => {
|
||||
await install(_path, options);
|
||||
});
|
||||
|
||||
program
|
||||
@@ -246,8 +250,8 @@ const main = async () => {
|
||||
"-c, --contract-name [name]",
|
||||
"Name of the new smart contract to create",
|
||||
)
|
||||
.action(async (type, path, options) => {
|
||||
await twCreate(type, path, options);
|
||||
.action(async (type, _path, options) => {
|
||||
await twCreate(type, _path, options);
|
||||
});
|
||||
|
||||
program
|
||||
@@ -296,8 +300,17 @@ const main = async () => {
|
||||
"Deploy a dynamic smart contract made up of extensions to blockchains",
|
||||
)
|
||||
.option("--zksync", "Deploy on ZKSync")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (options) => {
|
||||
const url = await deploy(options);
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
const url = await deploy(options, apiSecretKey);
|
||||
if (url) {
|
||||
await open(url);
|
||||
}
|
||||
@@ -319,11 +332,20 @@ const main = async () => {
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (options) => {
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
logger.warn(
|
||||
"'release' is deprecated and will be removed in a future update. Please use 'publish' instead.",
|
||||
);
|
||||
const url = await processProject(options, "publish");
|
||||
const url = await processProject(options, "publish", apiSecretKey);
|
||||
info(
|
||||
`Open this link to publish your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
@@ -350,8 +372,17 @@ const main = async () => {
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (options) => {
|
||||
const url = await processProject(options, "publish");
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
const url = await processProject(options, "publish", apiSecretKey);
|
||||
info(
|
||||
`Open this link to publish your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
@@ -364,10 +395,21 @@ const main = async () => {
|
||||
.command("upload")
|
||||
.description("Upload any file or directory to decentralized storage (IPFS)")
|
||||
.argument("[upload]", "path to file or directory to upload")
|
||||
.action(async (path) => {
|
||||
const storage = new ThirdwebStorage();
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (_path, options) => {
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
try {
|
||||
const uri = await upload(storage, path);
|
||||
const uri = await upload(storage, _path);
|
||||
info(
|
||||
`Files stored at the following IPFS URI: ${chalk.blueBright(
|
||||
uri.toString(),
|
||||
@@ -414,8 +456,36 @@ const main = async () => {
|
||||
"Preload ABIs and generate types for your smart contract to strongly type the thirdweb SDK",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("-k, --key <key>", "API key to authorize usage")
|
||||
.action(async (options) => {
|
||||
await generate(options);
|
||||
let apiSecretKey = "";
|
||||
// If no key is passed in, prompt the user to login. If it is passed in, use it.
|
||||
if (!options.key) {
|
||||
apiSecretKey = await loginUser(cache);
|
||||
} else {
|
||||
await validateKey(options.key);
|
||||
apiSecretKey = options.key;
|
||||
}
|
||||
await generate(options, apiSecretKey);
|
||||
});
|
||||
|
||||
program
|
||||
.command("login")
|
||||
.description(
|
||||
"Authenticate with the thirdweb CLI using your API secret key or replace an existing API secret key",
|
||||
)
|
||||
.option("-n, --new", "Login with a new API secret key", false)
|
||||
.action(async (options) => {
|
||||
await loginUser(cache, options, true);
|
||||
});
|
||||
|
||||
program
|
||||
.command("logout")
|
||||
.description(
|
||||
"Logout of the thirdweb CLI, effectively removing your API secret key from your machine",
|
||||
)
|
||||
.action(async () => {
|
||||
await logoutUser(cache);
|
||||
});
|
||||
|
||||
await program.parseAsync();
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import { detectFeatures } from "@thirdweb-dev/sdk";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { ethers } from "ethers";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import ora from "ora";
|
||||
import path from "path";
|
||||
import {
|
||||
EXTENSION_REGISTRY_ADDRESS,
|
||||
ROUTER_CONTRACTS,
|
||||
PreDeployedRouter,
|
||||
TWRouterParams,
|
||||
ROUTER_CONTRACTS,
|
||||
RouterParams,
|
||||
TWRouterParams,
|
||||
} from "../constants/router-contracts";
|
||||
import { cliVersion, THIRDWEB_URL } from "../constants/urls";
|
||||
import { THIRDWEB_URL, cliVersion } from "../constants/urls";
|
||||
import build from "../core/builder/build";
|
||||
import detect from "../core/detection/detect";
|
||||
import { execute } from "../core/helpers/exec";
|
||||
@@ -17,24 +24,20 @@ import {
|
||||
import { ContractPayload } from "../core/interfaces/ContractPayload";
|
||||
import {
|
||||
Extension,
|
||||
ExtensionDeployArgs,
|
||||
ExtensionFunction,
|
||||
ExtensionMetadata,
|
||||
ExtensionDeployArgs,
|
||||
} from "../core/interfaces/Extension";
|
||||
import { detectFeatures } from "@thirdweb-dev/sdk";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { ethers } from "ethers";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import ora from "ora";
|
||||
import path from "path";
|
||||
|
||||
export async function processProject(
|
||||
options: any,
|
||||
command: "deploy" | "publish",
|
||||
apiSecretKey: string,
|
||||
) {
|
||||
// TODO: allow overriding the default storage
|
||||
const storage = new ThirdwebStorage();
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
|
||||
logger.setSettings({
|
||||
minLevel: options.debug ? "debug" : "info",
|
||||
@@ -237,6 +240,7 @@ export async function processProject(
|
||||
} else {
|
||||
const deployArgs: RouterParams = await formatToExtensions(
|
||||
selectedContracts,
|
||||
apiSecretKey,
|
||||
);
|
||||
|
||||
const outputDeployArgs = JSON.stringify(deployArgs, undefined, 2);
|
||||
@@ -364,11 +368,16 @@ export function getUrl(hashes: string[], command: string) {
|
||||
return url;
|
||||
}
|
||||
|
||||
async function formatToExtensions(contracts: ContractPayload[]): Promise<{
|
||||
async function formatToExtensions(
|
||||
contracts: ContractPayload[],
|
||||
apiSecretKey: string,
|
||||
): Promise<{
|
||||
extensions: Extension[];
|
||||
extensionDeployArgs: ExtensionDeployArgs[];
|
||||
}> {
|
||||
const storage = new ThirdwebStorage();
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
const extensions: Extension[] = [];
|
||||
const extensionDeployArgs: ExtensionDeployArgs[] = [];
|
||||
|
||||
|
||||
@@ -4,7 +4,10 @@ import detectLibrary from "../core/detection/detectLibrary";
|
||||
import detectLanguage from "../core/detection/detectLanguage";
|
||||
import { logger, spinner } from "../core/helpers/logger";
|
||||
import path from "path";
|
||||
import { ContractLibrariesType, contractLibraries } from "../core/types/ProjectType";
|
||||
import {
|
||||
ContractLibrariesType,
|
||||
contractLibraries,
|
||||
} from "../core/types/ProjectType";
|
||||
import { FeatureWithEnabled, detectFeatures } from "@thirdweb-dev/sdk";
|
||||
import chalk from "chalk";
|
||||
import ora from "ora";
|
||||
@@ -48,8 +51,16 @@ export async function detectProject(options: any) {
|
||||
options,
|
||||
detectedPackageManager,
|
||||
);
|
||||
const detectedAppType = detectedFramework !== "none" ? contractLibraries.includes(detectedFramework as ContractLibrariesType) ? "contract" : "app" : "app";
|
||||
const detectedContractLibrary = detectedAppType === "contract" ? detectedFramework as ContractLibrariesType : "none";
|
||||
const detectedAppType =
|
||||
detectedFramework !== "none"
|
||||
? contractLibraries.includes(detectedFramework as ContractLibrariesType)
|
||||
? "contract"
|
||||
: "app"
|
||||
: "app";
|
||||
const detectedContractLibrary =
|
||||
detectedAppType === "contract"
|
||||
? (detectedFramework as ContractLibrariesType)
|
||||
: "none";
|
||||
|
||||
logger.info("Detected package manager: " + detectedPackageManager);
|
||||
logger.info("Detected library: " + detectedLibrary);
|
||||
@@ -61,7 +72,11 @@ export async function detectProject(options: any) {
|
||||
let compiledResult;
|
||||
const compileLoader = spinner("Compiling project...");
|
||||
try {
|
||||
compiledResult = await build(projectPath, detectedContractLibrary, options);
|
||||
compiledResult = await build(
|
||||
projectPath,
|
||||
detectedContractLibrary,
|
||||
options,
|
||||
);
|
||||
} catch (e) {
|
||||
compileLoader.fail("Compilation failed");
|
||||
logger.error(e);
|
||||
@@ -127,7 +142,9 @@ export async function detectProject(options: any) {
|
||||
).stopAndPersist({ symbol: "🔎" });
|
||||
} else {
|
||||
ora(
|
||||
`Detected extension on ${chalk.blueBright(contractWithFeatures.name)}`,
|
||||
`Detected extension on ${chalk.blueBright(
|
||||
contractWithFeatures.name,
|
||||
)}`,
|
||||
).stopAndPersist({ symbol: "🔎" });
|
||||
contractWithFeatures.enabledFeatures.map((feature) => {
|
||||
logger.info(`✔️ ${chalk.green(feature.name)}`);
|
||||
|
||||
@@ -16,11 +16,14 @@ export class SolcBuilder extends BaseBuilder {
|
||||
const inputPaths: string[] = [];
|
||||
findFiles(options.projectPath, /^.*\.sol$/, inputPaths);
|
||||
|
||||
const sources = inputPaths.reduce((acc, curr) => {
|
||||
const source = readFileSync(curr, "utf-8");
|
||||
acc[basename(curr)] = { content: source };
|
||||
return acc;
|
||||
}, {} as Record<string, { content: string }>);
|
||||
const sources = inputPaths.reduce(
|
||||
(acc, curr) => {
|
||||
const source = readFileSync(curr, "utf-8");
|
||||
acc[basename(curr)] = { content: source };
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, { content: string }>,
|
||||
);
|
||||
|
||||
const input = {
|
||||
language: "Solidity",
|
||||
|
||||
@@ -67,7 +67,10 @@ export default async function detect(
|
||||
return possibleFrameworks[0];
|
||||
}
|
||||
|
||||
if (possibleFrameworks.includes("expo") && possibleFrameworks.includes("react-native-cli")) {
|
||||
if (
|
||||
possibleFrameworks.includes("expo") &&
|
||||
possibleFrameworks.includes("react-native-cli")
|
||||
) {
|
||||
return "expo";
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,10 @@ export default async function detect(
|
||||
return possibleLanguages[0];
|
||||
}
|
||||
|
||||
if (possibleLanguages.includes("typescript") && possibleLanguages.includes("javascript")) {
|
||||
if (
|
||||
possibleLanguages.includes("typescript") &&
|
||||
possibleLanguages.includes("javascript")
|
||||
) {
|
||||
return "typescript";
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ export default async function detect(
|
||||
return possibleLibraries[0];
|
||||
}
|
||||
|
||||
if (possibleLibraries.includes("react-native") && possibleLibraries.includes("react")) {
|
||||
if (
|
||||
possibleLibraries.includes("react-native") &&
|
||||
possibleLibraries.includes("react")
|
||||
) {
|
||||
return "react-native";
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,10 @@ export default async function detect(
|
||||
return possiblePackageManagers[0];
|
||||
}
|
||||
|
||||
if (possiblePackageManagers.includes("brownie") && possiblePackageManagers.includes("pip")) {
|
||||
if (
|
||||
possiblePackageManagers.includes("brownie") &&
|
||||
possiblePackageManagers.includes("pip")
|
||||
) {
|
||||
return "brownie";
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,15 @@ export default class BrownieDetector implements FrameworkDetector {
|
||||
);
|
||||
|
||||
const additionalDirectoriesToCheck = ["/build", "/contracts", "/reports"];
|
||||
const additionalDirectoriesExist = additionalDirectoriesToCheck.every((dir) => {
|
||||
return existsSync(path + dir);
|
||||
});
|
||||
const additionalDirectoriesExist = additionalDirectoriesToCheck.every(
|
||||
(dir) => {
|
||||
return existsSync(path + dir);
|
||||
},
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep.includes("brownie")) ||
|
||||
!!devDependencies.find(dep => dep.includes("brownie")) ||
|
||||
!!dependencies.find((dep) => dep.includes("brownie")) ||
|
||||
!!devDependencies.find((dep) => dep.includes("brownie")) ||
|
||||
additionalFilesExist ||
|
||||
additionalDirectoriesExist ||
|
||||
false
|
||||
|
||||
@@ -18,8 +18,8 @@ export default class DjangoDetector implements FrameworkDetector {
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep.includes("Django")) ||
|
||||
!!devDependencies.find(dep => dep.includes("Django")) ||
|
||||
!!dependencies.find((dep) => dep.includes("Django")) ||
|
||||
!!devDependencies.find((dep) => dep.includes("Django")) ||
|
||||
additionalFilesExist ||
|
||||
false
|
||||
);
|
||||
|
||||
@@ -18,8 +18,8 @@ export default class FastAPIDetector implements FrameworkDetector {
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep.includes("fastapi")) ||
|
||||
!!devDependencies.find(dep => dep.includes("fastapi")) ||
|
||||
!!dependencies.find((dep) => dep.includes("fastapi")) ||
|
||||
!!devDependencies.find((dep) => dep.includes("fastapi")) ||
|
||||
additionalFilesExist ||
|
||||
false
|
||||
);
|
||||
|
||||
@@ -18,8 +18,8 @@ export default class FlaskDetector implements FrameworkDetector {
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep.includes("Flask")) ||
|
||||
!!devDependencies.find(dep => dep.includes("Flask")) ||
|
||||
!!dependencies.find((dep) => dep.includes("Flask")) ||
|
||||
!!devDependencies.find((dep) => dep.includes("Flask")) ||
|
||||
additionalFilesExist ||
|
||||
false
|
||||
);
|
||||
|
||||
@@ -18,8 +18,8 @@ export default class PopulusDetector implements FrameworkDetector {
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep === "populus") ||
|
||||
!!devDependencies.find(dep => dep === "populus") ||
|
||||
!!dependencies.find((dep) => dep === "populus") ||
|
||||
!!devDependencies.find((dep) => dep === "populus") ||
|
||||
additionalFilesExist ||
|
||||
false
|
||||
);
|
||||
|
||||
@@ -16,10 +16,7 @@ export default class TruffleDetector implements FrameworkDetector {
|
||||
const packageJson = readFileSync(packageJsonPath);
|
||||
const { dependencies, devDependencies } = parsePackageJson(packageJson);
|
||||
|
||||
const additionalFilesToCheck = [
|
||||
"/truffle.config.js",
|
||||
"/truffle.js",
|
||||
];
|
||||
const additionalFilesToCheck = ["/truffle.config.js", "/truffle.js"];
|
||||
const additionalFilesExist = additionalFilesToCheck.some((file) =>
|
||||
existsSync(path + file),
|
||||
);
|
||||
|
||||
@@ -12,7 +12,9 @@ export default class Web3PyDetector implements LibraryDetector {
|
||||
);
|
||||
|
||||
return (
|
||||
!!dependencies.find(dep => dep.includes("web3")) || !!devDependencies.find(dep => dep.includes("web3")) || false
|
||||
!!dependencies.find((dep) => dep.includes("web3")) ||
|
||||
!!devDependencies.find((dep) => dep.includes("web3")) ||
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ export default class BrownieDetector implements PackageManagerDetector {
|
||||
public packageManagerType: PackageManagerType = "brownie";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
|
||||
const additionalFilesToCheck = [
|
||||
"/brownie-config.yaml",
|
||||
"/brownie-config.json",
|
||||
@@ -17,14 +16,12 @@ export default class BrownieDetector implements PackageManagerDetector {
|
||||
|
||||
// Check that all of these exist.
|
||||
const additionalDirectoriesToCheck = ["/build", "/contracts", "/reports"];
|
||||
const additionalDirectoriesExist = additionalDirectoriesToCheck.every((dir) => {
|
||||
return existsSync(path + dir);
|
||||
});
|
||||
|
||||
return (
|
||||
additionalFilesExist ||
|
||||
additionalDirectoriesExist ||
|
||||
false
|
||||
const additionalDirectoriesExist = additionalDirectoriesToCheck.every(
|
||||
(dir) => {
|
||||
return existsSync(path + dir);
|
||||
},
|
||||
);
|
||||
|
||||
return additionalFilesExist || additionalDirectoriesExist || false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,6 @@ export type ContractLibrariesType =
|
||||
| "solc"
|
||||
| "none";
|
||||
|
||||
|
||||
export const contractLibraries: readonly ContractLibrariesType[] = [
|
||||
"brownie",
|
||||
"foundry",
|
||||
@@ -84,4 +83,4 @@ export const contractLibraries: readonly ContractLibrariesType[] = [
|
||||
"truffle",
|
||||
"solc",
|
||||
"none",
|
||||
] as const;
|
||||
] as const;
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export type CacheEntry = {
|
||||
isCached: boolean;
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
declare module "sync-disk-cache";
|
||||
declare module "solc";
|
||||
@@ -0,0 +1,21 @@
|
||||
declare module 'sync-disk-cache' {
|
||||
export type CacheEntry = {
|
||||
isCached: boolean;
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export default class Cache {
|
||||
constructor(key: string, options?: { location?: string; compression?: "gzip" | "deflate" | "deflateRaw"; });
|
||||
clear(): void;
|
||||
has(key: string): boolean;
|
||||
get(key: string): CacheEntry;
|
||||
set(key: string, value: string): string;
|
||||
remove(key: string): boolean;
|
||||
pathFor(key: string): string;
|
||||
decompress(value: string): string;
|
||||
compress(value: string): string;
|
||||
}
|
||||
}
|
||||
|
||||
declare module "solc"
|
||||
@@ -321,7 +321,10 @@ export async function twCreate(
|
||||
const res = await prompts({
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: projectType === "extension" ? CREATE_MESSAGES.extensionName : CREATE_MESSAGES.contractName,
|
||||
message:
|
||||
projectType === "extension"
|
||||
? CREATE_MESSAGES.extensionName
|
||||
: CREATE_MESSAGES.contractName,
|
||||
initial: defaultName,
|
||||
validate: (name: string) => {
|
||||
const isValid = /(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(name);
|
||||
|
||||
@@ -9,7 +9,7 @@ export async function runCommand(
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
/**
|
||||
* Spawn the installation process.
|
||||
*/
|
||||
*/
|
||||
const child = spawn(command, args);
|
||||
|
||||
child.stdout?.on("data", (data) => {
|
||||
@@ -28,7 +28,7 @@ export async function runCommand(
|
||||
});
|
||||
|
||||
child.on("error", (err) => {
|
||||
console.log("Spawn error", err)
|
||||
console.log("Spawn error", err);
|
||||
});
|
||||
|
||||
child.on("close", (code) => {
|
||||
@@ -39,4 +39,4 @@ export async function runCommand(
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,20 @@ import { logger } from "../core/helpers/logger";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { upload } from "../storage/command";
|
||||
|
||||
export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
const storage = new ThirdwebStorage();
|
||||
export async function deployApp(
|
||||
distPath = "dist",
|
||||
projectPath = ".",
|
||||
apiSecretKey: string,
|
||||
) {
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
const detectedPackageManager = await detectPackageManager(projectPath, {});
|
||||
const detectedFramework = await detectFramework(projectPath, {}, detectedPackageManager);
|
||||
const detectedFramework = await detectFramework(
|
||||
projectPath,
|
||||
{},
|
||||
detectedPackageManager,
|
||||
);
|
||||
|
||||
if (detectedFramework === "none") {
|
||||
throw new Error("No supported project detected");
|
||||
@@ -60,7 +70,10 @@ export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
|
||||
try {
|
||||
const uri = await upload(storage, distPath);
|
||||
return `${uri.replace("ipfs://", "https://ipfs-public.thirdwebcdn.com/ipfs/")}`;
|
||||
return `${uri.replace(
|
||||
"ipfs://",
|
||||
"https://ipfs-public.thirdwebcdn.com/ipfs/",
|
||||
)}`;
|
||||
} catch (err) {
|
||||
console.error("Can't upload project", err);
|
||||
return Promise.reject("Can't upload project");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import chalk from "chalk";
|
||||
import { processProject } from "../common/processor";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { deployApp } from "./app";
|
||||
import chalk from "chalk";
|
||||
|
||||
type DeployOptions = {
|
||||
name: string;
|
||||
@@ -12,7 +12,7 @@ type DeployOptions = {
|
||||
distPath?: string;
|
||||
};
|
||||
|
||||
export async function deploy(options: DeployOptions) {
|
||||
export async function deploy(options: DeployOptions, apiSecretKey: string) {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
@@ -33,7 +33,7 @@ export async function deploy(options: DeployOptions) {
|
||||
|
||||
if (options.app) {
|
||||
try {
|
||||
let url = await deployApp(options.distPath, options.path);
|
||||
let url = await deployApp(options.distPath, options.path, apiSecretKey);
|
||||
info(`Here is the link to your app: ${chalk.blueBright(url.toString())}`);
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
@@ -44,7 +44,7 @@ export async function deploy(options: DeployOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy");
|
||||
const url = await processProject(options, "deploy", apiSecretKey);
|
||||
info(
|
||||
`Open this link to deploy your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { GENERATE_MESSAGES } from "../../constants/constants";
|
||||
import { allChains } from "@thirdweb-dev/chains";
|
||||
import {
|
||||
DeployedContract,
|
||||
fetchContractMetadataFromAddress,
|
||||
getChainProvider,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { info } from "../core/helpers/logger";
|
||||
import { allChains } from "@thirdweb-dev/chains";
|
||||
import fs from "fs";
|
||||
import prompts from "prompts";
|
||||
import { findMatches } from "../common/file-helper";
|
||||
import ora from "ora";
|
||||
import prompts from "prompts";
|
||||
import { GENERATE_MESSAGES } from "../../constants/constants";
|
||||
import { findMatches } from "../common/file-helper";
|
||||
import { info } from "../core/helpers/logger";
|
||||
import { GenerateOptions, ThirdwebConfig } from "./types";
|
||||
import { CHAIN_OPTIONS, getContractsForAddresses } from "./utils";
|
||||
|
||||
export async function generate(options: GenerateOptions) {
|
||||
export async function generate(options: GenerateOptions, apiSecretKey: string) {
|
||||
let projectPath: string = options.path?.replace(/\/$/, "") || ".";
|
||||
let contracts: DeployedContract[] = [];
|
||||
|
||||
@@ -96,7 +96,9 @@ export async function generate(options: GenerateOptions) {
|
||||
|
||||
// Attempt to download the ABI for each contract
|
||||
ora(`Downloading ABIs for contracts configured in 'thirdweb.json'`).info();
|
||||
const storage = new ThirdwebStorage();
|
||||
const storage = new ThirdwebStorage({
|
||||
secretKey: apiSecretKey,
|
||||
});
|
||||
const metadata: {
|
||||
address: string;
|
||||
metadata: Awaited<ReturnType<typeof fetchContractMetadataFromAddress>>;
|
||||
@@ -147,10 +149,13 @@ export async function generate(options: GenerateOptions) {
|
||||
|
||||
const file = fs.readFileSync(filePath, "utf-8");
|
||||
const abiRegex = /GENERATED_ABI = \{.*\};\n\n/s;
|
||||
const contractAbis = metadata.reduce((acc, contract) => {
|
||||
acc[contract.address] = contract.metadata.abi;
|
||||
return acc;
|
||||
}, {} as Record<string, any>);
|
||||
const contractAbis = metadata.reduce(
|
||||
(acc, contract) => {
|
||||
acc[contract.address] = contract.metadata.abi;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
const updatedAbis = JSON.stringify(contractAbis, null, 2);
|
||||
const updatedFile = file.replace(
|
||||
abiRegex,
|
||||
@@ -169,10 +174,13 @@ export async function generate(options: GenerateOptions) {
|
||||
|
||||
const file = fs.readFileSync(typeFilePath, "utf-8");
|
||||
const abiRegex = /GENERATED_ABI: \{.*\}/s;
|
||||
const contractAbis = metadata.reduce((acc, contract) => {
|
||||
acc[contract.address] = contract.metadata.abi;
|
||||
return acc;
|
||||
}, {} as Record<string, any>);
|
||||
const contractAbis = metadata.reduce(
|
||||
(acc, contract) => {
|
||||
acc[contract.address] = contract.metadata.abi;
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, any>,
|
||||
);
|
||||
const updatedAbis = JSON.stringify(contractAbis, null, 2);
|
||||
const updatedFile = file.replace(abiRegex, `GENERATED_ABI: ${updatedAbis}`);
|
||||
fs.writeFileSync(typeFilePath, updatedFile);
|
||||
|
||||
+295
-235
@@ -1,235 +1,295 @@
|
||||
// Import required dependencies
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import ora from "ora";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
// Import project dependencies
|
||||
import detectFramework from "../core/detection/detectFramework";
|
||||
import detectPackageManager from "../core/detection/detectPackageManager";
|
||||
import detectLibrary from "../core/detection/detectLibrary";
|
||||
import { ContractLibrariesType, contractLibraries } from "../core/types/ProjectType";
|
||||
import { checkIfBrowniePackageIsInstalled, getDependenciesForFoundry, getDependenciesForGo, getDependenciesForPython, installOrUpdate, parsePackageJson, processAppType, processContractAppType } from "../lib/utils";
|
||||
import { logger } from "../core/helpers/logger";
|
||||
|
||||
// Define excluded dependencies
|
||||
const EXCLUDED_DEPENDENCIES = ["@thirdweb-dev/chain-icons"];
|
||||
|
||||
export async function install(projectPath = ".", options: any) {
|
||||
const debug = options.debug || false;
|
||||
let installer;
|
||||
let updater;
|
||||
|
||||
// Initialize all dependencies.
|
||||
let jsDependencies: { [key: string]: string } | string[] = {};
|
||||
let jsDevDependencies: { [key: string]: string } | string[] = {};
|
||||
let pythonDependencies: string[] = [];
|
||||
let pythonDevDependencies: string[] = [];
|
||||
let peerDependencies: { [key: string]: string } = {};
|
||||
let goDependencies: { name: string; version: string }[] = [];
|
||||
const thirdwebDepsToInstall = new Set<string>();
|
||||
const otherDeps = new Set<string>();
|
||||
|
||||
// Initialize brownie and foundry checks
|
||||
let thirdwebExistsInBrownie = { package: "", exists: false };
|
||||
let thirdwebExistsInFoundry = false;
|
||||
|
||||
|
||||
// Detect the package manager, and framework used in the project
|
||||
const detectedPackageManager = await detectPackageManager(projectPath, options);
|
||||
const detectedFramework = await detectFramework(projectPath, options, detectedPackageManager);
|
||||
const detectedLibrary = await detectLibrary(projectPath, options, detectedPackageManager);
|
||||
|
||||
// Determine project type
|
||||
const detectedAppType = detectedFramework !== "none" ? contractLibraries.includes(detectedFramework as ContractLibrariesType) ? "contract" : "app" : "app";
|
||||
|
||||
// Identify which specific package manager is used
|
||||
const isBrowniePackageManager = detectedPackageManager === "brownie";
|
||||
const isFoundryPackageManager = detectedPackageManager === "foundry";
|
||||
const isGoPackageManager = detectedPackageManager === "go-modules";
|
||||
const isPythonPackageManager = ["pip", "pipenv", "poetry"].includes(detectedPackageManager);
|
||||
const isJSPackageManager = ["yarn", "pnpm", "npm"].includes(detectedPackageManager);
|
||||
|
||||
// Processing JS/TS dependencies
|
||||
if (isJSPackageManager) {
|
||||
let packageJson;
|
||||
const packageJsonPath = projectPath + "/package.json";
|
||||
|
||||
// Check if package.json exists
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
console.error(
|
||||
"No package.json file found. Please run this command in the root of your project."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse package.json
|
||||
packageJson = readFileSync(packageJsonPath);
|
||||
const parsedJSDeps = parsePackageJson(packageJson);
|
||||
jsDependencies = parsedJSDeps.dependencies;
|
||||
jsDevDependencies = parsedJSDeps.devDependencies;
|
||||
peerDependencies = parsedJSDeps.peerDependencies;
|
||||
}
|
||||
|
||||
// Processing Python dependencies
|
||||
if (isPythonPackageManager) {
|
||||
const pythonDeps = getDependenciesForPython(projectPath, detectedPackageManager);
|
||||
pythonDependencies = pythonDeps.dependencies;
|
||||
pythonDevDependencies = pythonDeps.devDependencies;
|
||||
}
|
||||
|
||||
// Processing Brownie dependencies
|
||||
if (isBrowniePackageManager) {
|
||||
const regex = /\s*thirdweb-dev\/contracts@\d+\.\d+\.\d+/g;
|
||||
const res = await checkIfBrowniePackageIsInstalled(regex);
|
||||
thirdwebExistsInBrownie = res;
|
||||
}
|
||||
|
||||
// Processing Foundry dependencies
|
||||
if (isFoundryPackageManager) {
|
||||
const exists = await getDependenciesForFoundry(projectPath, "thirdweb-contracts");
|
||||
thirdwebExistsInFoundry = exists;
|
||||
}
|
||||
|
||||
// Processing Go dependencies
|
||||
if (isGoPackageManager) {
|
||||
const deps = getDependenciesForGo(projectPath);
|
||||
goDependencies = deps;
|
||||
}
|
||||
|
||||
const hasEthers =
|
||||
!!jsDependencies?.ethers ||
|
||||
!!jsDevDependencies?.ethers;
|
||||
|
||||
const version = !isJSPackageManager ? "" :
|
||||
options.dev
|
||||
? "@dev"
|
||||
: options.nightly
|
||||
? "@nightly" : "";
|
||||
|
||||
const thirdwebDepsToUpdate = new Set<string>(
|
||||
[
|
||||
...Object.keys(jsDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...Object.keys(jsDevDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...Object.keys(peerDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...pythonDependencies
|
||||
.filter((dep) => dep.startsWith("thirdweb-sdk"))
|
||||
.map((dep) => dep.split('==')[0]),
|
||||
...pythonDevDependencies
|
||||
.filter((dep) => dep.startsWith("thirdweb-sdk"))
|
||||
.map((dep) => dep.split('==')[0]),
|
||||
...goDependencies
|
||||
.filter((dep) => {
|
||||
console.log('dep', dep)
|
||||
return dep.name === "github.com/thirdweb-dev/go-sdk/v2"
|
||||
})
|
||||
.map((dep) => dep.name),
|
||||
].concat(thirdwebExistsInBrownie.exists ? [thirdwebExistsInBrownie.package] : [])
|
||||
.concat(thirdwebExistsInFoundry ? ["lib/thirdweb-contracts"] : [])
|
||||
);
|
||||
|
||||
// Figure out which dependencies to install and which to update.
|
||||
if (detectedAppType === "contract") {
|
||||
processContractAppType({ detectedPackageManager, thirdwebDepsToUpdate, thirdwebDepsToInstall, isJSPackageManager })
|
||||
} else if (detectedAppType === "app") {
|
||||
processAppType({
|
||||
detectedLibrary,
|
||||
detectedFramework,
|
||||
hasEthers,
|
||||
isGoPackageManager,
|
||||
isJSPackageManager,
|
||||
isPythonPackageManager,
|
||||
otherDeps,
|
||||
thirdwebDepsToInstall,
|
||||
thirdwebDepsToUpdate,
|
||||
})
|
||||
}
|
||||
|
||||
// remove exluded dependencies
|
||||
EXCLUDED_DEPENDENCIES.forEach((excludedDep) => {
|
||||
thirdwebDepsToUpdate.delete(excludedDep);
|
||||
thirdwebDepsToInstall.delete(excludedDep);
|
||||
});
|
||||
|
||||
// Ask which dependencies to install
|
||||
if (thirdwebDepsToInstall.size !== 0) {
|
||||
const answer = await inquirer.prompt({
|
||||
type: "checkbox",
|
||||
choices: [...thirdwebDepsToInstall],
|
||||
message: "Which thirdweb dependencies would you like to install?",
|
||||
name: "dependencies",
|
||||
default: [...thirdwebDepsToInstall],
|
||||
});
|
||||
|
||||
if (answer.dependencies.length !== thirdwebDepsToInstall.size) {
|
||||
thirdwebDepsToInstall.clear();
|
||||
answer.dependencies.forEach((dep: string) => thirdwebDepsToInstall.add(dep));
|
||||
}
|
||||
}
|
||||
|
||||
// Ask which dependencies to update
|
||||
if (thirdwebDepsToUpdate.size !== 0) {
|
||||
const answer = await inquirer.prompt({
|
||||
type: "checkbox",
|
||||
choices: [...thirdwebDepsToUpdate],
|
||||
message: "Which thirdweb dependencies would you like to update?",
|
||||
name: "dependencies",
|
||||
default: [...thirdwebDepsToUpdate],
|
||||
});
|
||||
|
||||
if (answer.dependencies.length !== thirdwebDepsToUpdate.size) {
|
||||
thirdwebDepsToUpdate.clear();
|
||||
answer.dependencies.forEach((dep: string) => thirdwebDepsToUpdate.add(dep));
|
||||
}
|
||||
}
|
||||
|
||||
if (thirdwebDepsToInstall.size === 0 && thirdwebDepsToUpdate.size === 0) {
|
||||
console.log("No thirdweb dependencies to install or update.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
logger.info("Detected package manager: " + detectedPackageManager);
|
||||
logger.info("Detected library: " + detectedLibrary);
|
||||
logger.info("Detected framework: " + detectedFramework);
|
||||
logger.info("Detected app type: " + detectedAppType);
|
||||
}
|
||||
|
||||
try {
|
||||
const dependenciesToAdd = [
|
||||
...[...thirdwebDepsToInstall].map((dep) => `${dep}${version}`),
|
||||
...otherDeps,
|
||||
];
|
||||
|
||||
const dependenciesToUpdate = [...thirdwebDepsToUpdate].map(
|
||||
(dep) => `${dep}${version}`,
|
||||
)
|
||||
|
||||
if (thirdwebDepsToInstall.size !== 0) {
|
||||
installer = ora(
|
||||
`Installing: "${[...thirdwebDepsToInstall].join('", "')}"`,
|
||||
).start();
|
||||
await installOrUpdate(detectedPackageManager, dependenciesToAdd, [], "install", { oldVersion: thirdwebExistsInBrownie.package, debug });
|
||||
installer?.succeed(`Installed: "${dependenciesToAdd.join('", "')}"`);
|
||||
}
|
||||
|
||||
if (thirdwebDepsToUpdate.size !== 0) {
|
||||
updater = ora(
|
||||
`Updating: "${[...thirdwebDepsToUpdate].join('", "')}"`,
|
||||
).start();
|
||||
await installOrUpdate(detectedPackageManager, [], dependenciesToUpdate, "update", {
|
||||
debug,
|
||||
});
|
||||
updater?.succeed(`Updated: "${dependenciesToUpdate.join('", "')}"`);
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error("Can't install within project: ", err);
|
||||
return Promise.reject("Can't install within project");
|
||||
}
|
||||
}
|
||||
// Import required dependencies
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import ora from "ora";
|
||||
import inquirer from "inquirer";
|
||||
|
||||
// Import project dependencies
|
||||
import detectFramework from "../core/detection/detectFramework";
|
||||
import detectPackageManager from "../core/detection/detectPackageManager";
|
||||
import detectLibrary from "../core/detection/detectLibrary";
|
||||
import {
|
||||
ContractLibrariesType,
|
||||
contractLibraries,
|
||||
} from "../core/types/ProjectType";
|
||||
import {
|
||||
checkIfBrowniePackageIsInstalled,
|
||||
getDependenciesForFoundry,
|
||||
getDependenciesForGo,
|
||||
getDependenciesForPython,
|
||||
installOrUpdate,
|
||||
parsePackageJson,
|
||||
processAppType,
|
||||
processContractAppType,
|
||||
} from "../lib/utils";
|
||||
import { logger } from "../core/helpers/logger";
|
||||
|
||||
// Define excluded dependencies
|
||||
const EXCLUDED_DEPENDENCIES = ["@thirdweb-dev/chain-icons"];
|
||||
|
||||
export async function install(projectPath = ".", options: any) {
|
||||
const debug = options.debug || false;
|
||||
let installer;
|
||||
let updater;
|
||||
|
||||
// Initialize all dependencies.
|
||||
let jsDependencies: { [key: string]: string } | string[] = {};
|
||||
let jsDevDependencies: { [key: string]: string } | string[] = {};
|
||||
let pythonDependencies: string[] = [];
|
||||
let pythonDevDependencies: string[] = [];
|
||||
let peerDependencies: { [key: string]: string } = {};
|
||||
let goDependencies: { name: string; version: string }[] = [];
|
||||
const thirdwebDepsToInstall = new Set<string>();
|
||||
const otherDeps = new Set<string>();
|
||||
|
||||
// Initialize brownie and foundry checks
|
||||
let thirdwebExistsInBrownie = { package: "", exists: false };
|
||||
let thirdwebExistsInFoundry = false;
|
||||
|
||||
// Detect the package manager, and framework used in the project
|
||||
const detectedPackageManager = await detectPackageManager(
|
||||
projectPath,
|
||||
options,
|
||||
);
|
||||
const detectedFramework = await detectFramework(
|
||||
projectPath,
|
||||
options,
|
||||
detectedPackageManager,
|
||||
);
|
||||
const detectedLibrary = await detectLibrary(
|
||||
projectPath,
|
||||
options,
|
||||
detectedPackageManager,
|
||||
);
|
||||
|
||||
// Determine project type
|
||||
const detectedAppType =
|
||||
detectedFramework !== "none"
|
||||
? contractLibraries.includes(detectedFramework as ContractLibrariesType)
|
||||
? "contract"
|
||||
: "app"
|
||||
: "app";
|
||||
|
||||
// Identify which specific package manager is used
|
||||
const isBrowniePackageManager = detectedPackageManager === "brownie";
|
||||
const isFoundryPackageManager = detectedPackageManager === "foundry";
|
||||
const isGoPackageManager = detectedPackageManager === "go-modules";
|
||||
const isPythonPackageManager = ["pip", "pipenv", "poetry"].includes(
|
||||
detectedPackageManager,
|
||||
);
|
||||
const isJSPackageManager = ["yarn", "pnpm", "npm"].includes(
|
||||
detectedPackageManager,
|
||||
);
|
||||
|
||||
// Processing JS/TS dependencies
|
||||
if (isJSPackageManager) {
|
||||
let packageJson;
|
||||
const packageJsonPath = projectPath + "/package.json";
|
||||
|
||||
// Check if package.json exists
|
||||
if (!existsSync(packageJsonPath)) {
|
||||
console.error(
|
||||
"No package.json file found. Please run this command in the root of your project.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse package.json
|
||||
packageJson = readFileSync(packageJsonPath);
|
||||
const parsedJSDeps = parsePackageJson(packageJson);
|
||||
jsDependencies = parsedJSDeps.dependencies;
|
||||
jsDevDependencies = parsedJSDeps.devDependencies;
|
||||
peerDependencies = parsedJSDeps.peerDependencies;
|
||||
}
|
||||
|
||||
// Processing Python dependencies
|
||||
if (isPythonPackageManager) {
|
||||
const pythonDeps = getDependenciesForPython(
|
||||
projectPath,
|
||||
detectedPackageManager,
|
||||
);
|
||||
pythonDependencies = pythonDeps.dependencies;
|
||||
pythonDevDependencies = pythonDeps.devDependencies;
|
||||
}
|
||||
|
||||
// Processing Brownie dependencies
|
||||
if (isBrowniePackageManager) {
|
||||
const regex = /\s*thirdweb-dev\/contracts@\d+\.\d+\.\d+/g;
|
||||
const res = await checkIfBrowniePackageIsInstalled(regex);
|
||||
thirdwebExistsInBrownie = res;
|
||||
}
|
||||
|
||||
// Processing Foundry dependencies
|
||||
if (isFoundryPackageManager) {
|
||||
const exists = await getDependenciesForFoundry(
|
||||
projectPath,
|
||||
"thirdweb-contracts",
|
||||
);
|
||||
thirdwebExistsInFoundry = exists;
|
||||
}
|
||||
|
||||
// Processing Go dependencies
|
||||
if (isGoPackageManager) {
|
||||
const deps = getDependenciesForGo(projectPath);
|
||||
goDependencies = deps;
|
||||
}
|
||||
|
||||
const hasEthers = !!jsDependencies?.ethers || !!jsDevDependencies?.ethers;
|
||||
|
||||
const version = !isJSPackageManager
|
||||
? ""
|
||||
: options.dev
|
||||
? "@dev"
|
||||
: options.nightly
|
||||
? "@nightly"
|
||||
: "";
|
||||
|
||||
const thirdwebDepsToUpdate = new Set<string>(
|
||||
[
|
||||
...Object.keys(jsDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...Object.keys(jsDevDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...Object.keys(peerDependencies).filter((dep) =>
|
||||
dep.startsWith("@thirdweb-dev/"),
|
||||
),
|
||||
...pythonDependencies
|
||||
.filter((dep) => dep.startsWith("thirdweb-sdk"))
|
||||
.map((dep) => dep.split("==")[0]),
|
||||
...pythonDevDependencies
|
||||
.filter((dep) => dep.startsWith("thirdweb-sdk"))
|
||||
.map((dep) => dep.split("==")[0]),
|
||||
...goDependencies
|
||||
.filter((dep) => {
|
||||
console.log("dep", dep);
|
||||
return dep.name === "github.com/thirdweb-dev/go-sdk/v2";
|
||||
})
|
||||
.map((dep) => dep.name),
|
||||
]
|
||||
.concat(
|
||||
thirdwebExistsInBrownie.exists ? [thirdwebExistsInBrownie.package] : [],
|
||||
)
|
||||
.concat(thirdwebExistsInFoundry ? ["lib/thirdweb-contracts"] : []),
|
||||
);
|
||||
|
||||
// Figure out which dependencies to install and which to update.
|
||||
if (detectedAppType === "contract") {
|
||||
processContractAppType({
|
||||
detectedPackageManager,
|
||||
thirdwebDepsToUpdate,
|
||||
thirdwebDepsToInstall,
|
||||
isJSPackageManager,
|
||||
});
|
||||
} else if (detectedAppType === "app") {
|
||||
processAppType({
|
||||
detectedLibrary,
|
||||
detectedFramework,
|
||||
hasEthers,
|
||||
isGoPackageManager,
|
||||
isJSPackageManager,
|
||||
isPythonPackageManager,
|
||||
otherDeps,
|
||||
thirdwebDepsToInstall,
|
||||
thirdwebDepsToUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
// remove exluded dependencies
|
||||
EXCLUDED_DEPENDENCIES.forEach((excludedDep) => {
|
||||
thirdwebDepsToUpdate.delete(excludedDep);
|
||||
thirdwebDepsToInstall.delete(excludedDep);
|
||||
});
|
||||
|
||||
// Ask which dependencies to install
|
||||
if (thirdwebDepsToInstall.size !== 0) {
|
||||
const answer = await inquirer.prompt({
|
||||
type: "checkbox",
|
||||
choices: [...thirdwebDepsToInstall],
|
||||
message: "Which thirdweb dependencies would you like to install?",
|
||||
name: "dependencies",
|
||||
default: [...thirdwebDepsToInstall],
|
||||
});
|
||||
|
||||
if (answer.dependencies.length !== thirdwebDepsToInstall.size) {
|
||||
thirdwebDepsToInstall.clear();
|
||||
answer.dependencies.forEach((dep: string) =>
|
||||
thirdwebDepsToInstall.add(dep),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Ask which dependencies to update
|
||||
if (thirdwebDepsToUpdate.size !== 0) {
|
||||
const answer = await inquirer.prompt({
|
||||
type: "checkbox",
|
||||
choices: [...thirdwebDepsToUpdate],
|
||||
message: "Which thirdweb dependencies would you like to update?",
|
||||
name: "dependencies",
|
||||
default: [...thirdwebDepsToUpdate],
|
||||
});
|
||||
|
||||
if (answer.dependencies.length !== thirdwebDepsToUpdate.size) {
|
||||
thirdwebDepsToUpdate.clear();
|
||||
answer.dependencies.forEach((dep: string) =>
|
||||
thirdwebDepsToUpdate.add(dep),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (thirdwebDepsToInstall.size === 0 && thirdwebDepsToUpdate.size === 0) {
|
||||
console.log("No thirdweb dependencies to install or update.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
logger.info("Detected package manager: " + detectedPackageManager);
|
||||
logger.info("Detected library: " + detectedLibrary);
|
||||
logger.info("Detected framework: " + detectedFramework);
|
||||
logger.info("Detected app type: " + detectedAppType);
|
||||
}
|
||||
|
||||
try {
|
||||
const dependenciesToAdd = [
|
||||
...[...thirdwebDepsToInstall].map((dep) => `${dep}${version}`),
|
||||
...otherDeps,
|
||||
];
|
||||
|
||||
const dependenciesToUpdate = [...thirdwebDepsToUpdate].map(
|
||||
(dep) => `${dep}${version}`,
|
||||
);
|
||||
|
||||
if (thirdwebDepsToInstall.size !== 0) {
|
||||
installer = ora(
|
||||
`Installing: "${[...thirdwebDepsToInstall].join('", "')}"`,
|
||||
).start();
|
||||
await installOrUpdate(
|
||||
detectedPackageManager,
|
||||
dependenciesToAdd,
|
||||
[],
|
||||
"install",
|
||||
{ oldVersion: thirdwebExistsInBrownie.package, debug },
|
||||
);
|
||||
installer?.succeed(`Installed: "${dependenciesToAdd.join('", "')}"`);
|
||||
}
|
||||
|
||||
if (thirdwebDepsToUpdate.size !== 0) {
|
||||
updater = ora(
|
||||
`Updating: "${[...thirdwebDepsToUpdate].join('", "')}"`,
|
||||
).start();
|
||||
await installOrUpdate(
|
||||
detectedPackageManager,
|
||||
[],
|
||||
dependenciesToUpdate,
|
||||
"update",
|
||||
{
|
||||
debug,
|
||||
},
|
||||
);
|
||||
updater?.succeed(`Updated: "${dependenciesToUpdate.join('", "')}"`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Can't install within project: ", err);
|
||||
return Promise.reject("Can't install within project");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import { FrameworkType, LibraryType, PackageManagerType } from "../core/types/ProjectType";
|
||||
import {
|
||||
FrameworkType,
|
||||
LibraryType,
|
||||
PackageManagerType,
|
||||
} from "../core/types/ProjectType";
|
||||
|
||||
export type IProcessContractAppTypeArgs = {
|
||||
detectedPackageManager: PackageManagerType;
|
||||
thirdwebDepsToUpdate: Set<string>;
|
||||
thirdwebDepsToInstall: Set<string>;
|
||||
isJSPackageManager: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type IProcessAppTypeArgs = {
|
||||
detectedLibrary: LibraryType;
|
||||
@@ -17,4 +21,26 @@ export type IProcessAppTypeArgs = {
|
||||
isGoPackageManager: boolean;
|
||||
hasEthers: boolean;
|
||||
otherDeps: Set<string>;
|
||||
}
|
||||
};
|
||||
|
||||
export type ApiKey = {
|
||||
id: string;
|
||||
key: string;
|
||||
walletAddresses: string[];
|
||||
domains: string[];
|
||||
services?: [
|
||||
{
|
||||
name: string;
|
||||
targetAddresses: string[];
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export type ApiResponse = {
|
||||
data: ApiKey | null;
|
||||
error: {
|
||||
code: string;
|
||||
statusCode: number;
|
||||
message: string;
|
||||
};
|
||||
};
|
||||
|
||||
+107
-43
@@ -7,19 +7,21 @@ import { IProcessAppTypeArgs, IProcessContractAppTypeArgs } from "./types";
|
||||
|
||||
export function convertDependenciesToStringFormat(dependenciesObject: object) {
|
||||
return Object.entries(dependenciesObject).map(([pkg, versionDetails]) => {
|
||||
let version = '';
|
||||
if (typeof versionDetails === 'string') {
|
||||
let version = "";
|
||||
if (typeof versionDetails === "string") {
|
||||
version = versionDetails;
|
||||
} else if (typeof versionDetails === 'object') {
|
||||
} else if (typeof versionDetails === "object") {
|
||||
version = versionDetails.version;
|
||||
}
|
||||
// Replace '^' with nothing as '^' is not a valid version specifier in Python
|
||||
version = version.replace('^', '');
|
||||
version = version.replace("^", "");
|
||||
return `${pkg}==${version}`;
|
||||
});
|
||||
}
|
||||
|
||||
export const parsePackageJson = (packageJson: Buffer): {
|
||||
export const parsePackageJson = (
|
||||
packageJson: Buffer,
|
||||
): {
|
||||
dependencies: {
|
||||
[key: string]: string;
|
||||
};
|
||||
@@ -55,10 +57,9 @@ export const parsePipFile = (PipFile: string) => {
|
||||
|
||||
export const parsePyProjectToml = (pyProjectToml: string) => {
|
||||
const pyProjectFile = toml.parse(pyProjectToml) as any;
|
||||
const dependencies =
|
||||
(pyProjectFile["tool"]["poetry"]["dependencies"]) || [];
|
||||
const dependencies = pyProjectFile["tool"]["poetry"]["dependencies"] || [];
|
||||
const devDependencies =
|
||||
(pyProjectFile["tool"]["poetry"]["dev-dependencies"]) || [];
|
||||
pyProjectFile["tool"]["poetry"]["dev-dependencies"] || [];
|
||||
|
||||
return {
|
||||
dependencies: convertDependenciesToStringFormat(dependencies),
|
||||
@@ -150,20 +151,26 @@ export const getDependenciesForPython = (
|
||||
|
||||
export const getLatestVersion = async (packageName: string): Promise<any> => {
|
||||
try {
|
||||
const fetch = (await import('node-fetch')).default;
|
||||
const url = `https://registry.npmjs.org/${packageName}`
|
||||
const fetch = (await import("node-fetch")).default;
|
||||
const url = `https://registry.npmjs.org/${packageName}`;
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data: any = await response.json();
|
||||
return data['dist-tags']['latest'];
|
||||
return data["dist-tags"]["latest"];
|
||||
} catch (error) {
|
||||
console.error(`Failed to get latest version of ${packageName}:`, error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const installOrUpdate = async (packageManager: PackageManagerType, dependenciesToAdd: string[], dependenciesToUpdate: string[], typeOfAction: "install" | "update", options?: { oldVersion?: string, debug?: boolean }) => {
|
||||
export const installOrUpdate = async (
|
||||
packageManager: PackageManagerType,
|
||||
dependenciesToAdd: string[],
|
||||
dependenciesToUpdate: string[],
|
||||
typeOfAction: "install" | "update",
|
||||
options?: { oldVersion?: string; debug?: boolean },
|
||||
) => {
|
||||
let runner: string = "";
|
||||
let installCommand: string[] = [];
|
||||
let updateCommand: string[] = [];
|
||||
@@ -174,7 +181,7 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
case "npm":
|
||||
runner = "npm";
|
||||
installCommand = ["install"];
|
||||
updateCommand = ["install", "--legacy-peer-deps"]
|
||||
updateCommand = ["install", "--legacy-peer-deps"];
|
||||
break;
|
||||
case "yarn":
|
||||
runner = "yarn";
|
||||
@@ -208,9 +215,9 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
break;
|
||||
case "brownie":
|
||||
runner = "brownie";
|
||||
installCommand = ["pm", "install"]
|
||||
updateCommand = ["pm", "update"]
|
||||
deleteCommand = ["pm", "delete"]
|
||||
installCommand = ["pm", "install"];
|
||||
updateCommand = ["pm", "update"];
|
||||
deleteCommand = ["pm", "delete"];
|
||||
break;
|
||||
case "foundry":
|
||||
runner = "forge";
|
||||
@@ -223,17 +230,25 @@ export const installOrUpdate = async (packageManager: PackageManagerType, depend
|
||||
}
|
||||
|
||||
if (typeOfAction === "install") {
|
||||
if (!dependenciesToAdd.length) { return; }
|
||||
if (!dependenciesToAdd.length) {
|
||||
return;
|
||||
}
|
||||
const commands = [...installCommand, ...dependenciesToAdd];
|
||||
|
||||
await runCommand(runner, commands, printLogs);
|
||||
|
||||
if (options?.oldVersion) {
|
||||
await runCommand(runner, [...deleteCommand, options.oldVersion], printLogs);
|
||||
await runCommand(
|
||||
runner,
|
||||
[...deleteCommand, options.oldVersion],
|
||||
printLogs,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (typeOfAction === "update") {
|
||||
if (!dependenciesToUpdate.length) { return; }
|
||||
if (!dependenciesToUpdate.length) {
|
||||
return;
|
||||
}
|
||||
const commands = [...updateCommand, ...dependenciesToUpdate];
|
||||
await runCommand(runner, commands, printLogs);
|
||||
}
|
||||
@@ -259,13 +274,16 @@ export const getDependenciesForBrownie = async () => {
|
||||
let deps = "";
|
||||
await runCommand("brownie", ["pm", "list"], true, (data) => {
|
||||
deps += data.toString();
|
||||
})
|
||||
});
|
||||
// strip out colors from output
|
||||
deps = deps.replace(/\u001b\[\d+(;\d+)*m/g, '');
|
||||
deps = deps.replace(/\u001b\[\d+(;\d+)*m/g, "");
|
||||
return deps;
|
||||
};
|
||||
|
||||
export const getDependenciesForFoundry = async (filePath: string, libName: string) => {
|
||||
export const getDependenciesForFoundry = async (
|
||||
filePath: string,
|
||||
libName: string,
|
||||
) => {
|
||||
const fullPath = path.join(filePath, "lib", libName);
|
||||
return existsSync(fullPath);
|
||||
};
|
||||
@@ -275,15 +293,14 @@ type GoModule = {
|
||||
version: string;
|
||||
};
|
||||
|
||||
|
||||
export const getDependenciesForGo = (filePath: string): GoModule[] => {
|
||||
const content = readFileSync(filePath + "/go.mod", "utf-8");
|
||||
const lines = content.split("\n");
|
||||
const modules: GoModule[] = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.includes('github.com/thirdweb-dev')) {
|
||||
const words = line.split(/\s+/); // split on any amount of whitespace
|
||||
if (line.includes("github.com/thirdweb-dev")) {
|
||||
const words = line.split(/\s+/); // split on any amount of whitespace
|
||||
const name = words[1].trim();
|
||||
const version = words[2];
|
||||
modules.push({ name, version });
|
||||
@@ -291,10 +308,17 @@ export const getDependenciesForGo = (filePath: string): GoModule[] => {
|
||||
}
|
||||
|
||||
return modules;
|
||||
}
|
||||
};
|
||||
|
||||
export const processContractAppType = async (args: IProcessContractAppTypeArgs): Promise<void> => {
|
||||
const { detectedPackageManager, thirdwebDepsToUpdate, thirdwebDepsToInstall, isJSPackageManager } = args;
|
||||
export const processContractAppType = async (
|
||||
args: IProcessContractAppTypeArgs,
|
||||
): Promise<void> => {
|
||||
const {
|
||||
detectedPackageManager,
|
||||
thirdwebDepsToUpdate,
|
||||
thirdwebDepsToInstall,
|
||||
isJSPackageManager,
|
||||
} = args;
|
||||
|
||||
if (isJSPackageManager) {
|
||||
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/contracts`)) {
|
||||
@@ -303,15 +327,29 @@ export const processContractAppType = async (args: IProcessContractAppTypeArgs):
|
||||
}
|
||||
|
||||
if (detectedPackageManager === "brownie") {
|
||||
const latestThirdwebContractVersion = await getLatestVersion("@thirdweb-dev/contracts");
|
||||
const latestThirdwebContractVersion = await getLatestVersion(
|
||||
"@thirdweb-dev/contracts",
|
||||
);
|
||||
|
||||
// Exit out early if the user already has the latest version of thirdweb installed.
|
||||
if (thirdwebDepsToUpdate.has(`thirdweb-dev/contracts@${latestThirdwebContractVersion}`)) {
|
||||
return Promise.reject("You already have the latest version of thirdweb-dev/contracts installed.");
|
||||
if (
|
||||
thirdwebDepsToUpdate.has(
|
||||
`thirdweb-dev/contracts@${latestThirdwebContractVersion}`,
|
||||
)
|
||||
) {
|
||||
return Promise.reject(
|
||||
"You already have the latest version of thirdweb-dev/contracts installed.",
|
||||
);
|
||||
}
|
||||
|
||||
if (!thirdwebDepsToUpdate.has(`thirdweb-dev/contracts@${latestThirdwebContractVersion}`)) {
|
||||
thirdwebDepsToInstall.add(`thirdweb-dev/contracts@${latestThirdwebContractVersion}`);
|
||||
if (
|
||||
!thirdwebDepsToUpdate.has(
|
||||
`thirdweb-dev/contracts@${latestThirdwebContractVersion}`,
|
||||
)
|
||||
) {
|
||||
thirdwebDepsToInstall.add(
|
||||
`thirdweb-dev/contracts@${latestThirdwebContractVersion}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,8 +360,20 @@ export const processContractAppType = async (args: IProcessContractAppTypeArgs):
|
||||
}
|
||||
};
|
||||
|
||||
export const processAppType = async (args: IProcessAppTypeArgs): Promise<void> => {
|
||||
const { detectedFramework, thirdwebDepsToUpdate, thirdwebDepsToInstall, hasEthers, isJSPackageManager, otherDeps, isPythonPackageManager, isGoPackageManager, detectedLibrary } = args;
|
||||
export const processAppType = async (
|
||||
args: IProcessAppTypeArgs,
|
||||
): Promise<void> => {
|
||||
const {
|
||||
detectedFramework,
|
||||
thirdwebDepsToUpdate,
|
||||
thirdwebDepsToInstall,
|
||||
hasEthers,
|
||||
isJSPackageManager,
|
||||
otherDeps,
|
||||
isPythonPackageManager,
|
||||
isGoPackageManager,
|
||||
detectedLibrary,
|
||||
} = args;
|
||||
|
||||
const reactlibs = [
|
||||
"react",
|
||||
@@ -335,21 +385,35 @@ export const processAppType = async (args: IProcessAppTypeArgs): Promise<void> =
|
||||
"vue",
|
||||
"vite",
|
||||
"svelte",
|
||||
]
|
||||
const shouldInstallThirdwebReact = reactlibs.includes(detectedFramework as string);
|
||||
];
|
||||
const shouldInstallThirdwebReact = reactlibs.includes(
|
||||
detectedFramework as string,
|
||||
);
|
||||
const shouldInstallThirdwebReactNative = detectedLibrary === "react-native";
|
||||
|
||||
if (isJSPackageManager) {
|
||||
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react`) && shouldInstallThirdwebReact) {
|
||||
if (
|
||||
!thirdwebDepsToUpdate.has(`@thirdweb-dev/react`) &&
|
||||
shouldInstallThirdwebReact
|
||||
) {
|
||||
thirdwebDepsToInstall.add(`@thirdweb-dev/react`);
|
||||
}
|
||||
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/sdk`) && !shouldInstallThirdwebReactNative) {
|
||||
if (
|
||||
!thirdwebDepsToUpdate.has(`@thirdweb-dev/sdk`) &&
|
||||
!shouldInstallThirdwebReactNative
|
||||
) {
|
||||
thirdwebDepsToInstall.add(`@thirdweb-dev/sdk`);
|
||||
}
|
||||
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native`) && shouldInstallThirdwebReactNative) {
|
||||
if (
|
||||
!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native`) &&
|
||||
shouldInstallThirdwebReactNative
|
||||
) {
|
||||
thirdwebDepsToInstall.add(`@thirdweb-dev/react-native`);
|
||||
}
|
||||
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native-compat`) && shouldInstallThirdwebReactNative) {
|
||||
if (
|
||||
!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native-compat`) &&
|
||||
shouldInstallThirdwebReactNative
|
||||
) {
|
||||
thirdwebDepsToInstall.add(`@thirdweb-dev/react-native-compat`);
|
||||
}
|
||||
if (!hasEthers) {
|
||||
@@ -368,4 +432,4 @@ export const processAppType = async (args: IProcessAppTypeArgs): Promise<void> =
|
||||
thirdwebDepsToInstall.add("github.com/thirdweb-dev/go-sdk/v2");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -51,9 +51,14 @@ export async function upload(
|
||||
const spin = spinner(
|
||||
"Uploading directory to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
const uris = await storage.uploadBatch(files);
|
||||
spin.succeed("Successfully uploaded directory to IPFS");
|
||||
uri = uris[0].substring(0, uris[0].lastIndexOf("/"));
|
||||
try {
|
||||
const uris = await storage.uploadBatch(files);
|
||||
spin.succeed("Successfully uploaded directory to IPFS");
|
||||
uri = uris[0].substring(0, uris[0].lastIndexOf("/"));
|
||||
} catch (err) {
|
||||
spin.fail("Failed to upload directory to IPFS.");
|
||||
return Promise.reject(err);
|
||||
}
|
||||
} else if (fileType.isFile()) {
|
||||
const fileName = path.parse(uploadPath).base;
|
||||
const fileData = fs.readFileSync(uploadPath);
|
||||
@@ -62,7 +67,12 @@ export async function upload(
|
||||
const spin = spinner(
|
||||
"Uploading file to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
try {
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
} catch (err) {
|
||||
spin.fail("Failed to upload file to IPFS.");
|
||||
return Promise.reject(err);
|
||||
}
|
||||
spin.succeed("Successfully uploaded file to IPFS.");
|
||||
} else {
|
||||
return Promise.reject("Invalid path provided");
|
||||
|
||||
@@ -1,5 +1,43 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 3.14.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Adds new `clientId` prop to access thirdweb's services.
|
||||
|
||||
You can create a _free_ `clientId` [on the thirdweb Dashboard](https://thirdweb.com/dashboard)
|
||||
|
||||
```javascript
|
||||
<ThirdwebProvider clientId="your-client-id" />
|
||||
```
|
||||
|
||||
- Updated dependencies [[`44dbf283`](https://github.com/thirdweb-dev/js/commit/44dbf283c985f3e2ecbeb1cfdf09fe1d84e26298), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b)]:
|
||||
- @thirdweb-dev/storage@1.2.0
|
||||
- @thirdweb-dev/sdk@3.10.37
|
||||
- @thirdweb-dev/chains@0.1.35
|
||||
- @thirdweb-dev/wallets@1.1.0
|
||||
|
||||
## 3.14.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1356](https://github.com/thirdweb-dev/js/pull/1356) [`7a6534d1`](https://github.com/thirdweb-dev/js/commit/7a6534d1a98cab1eb47cf88d13e2b7ec04037e42) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix useOwnedNFT enabled state
|
||||
|
||||
- Updated dependencies [[`dac8fa7d`](https://github.com/thirdweb-dev/js/commit/dac8fa7d98b6952acf8d13e173099889c1d47da8), [`c5761b99`](https://github.com/thirdweb-dev/js/commit/c5761b99e9797772481506e90cbfa5c35a05bd1d), [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220)]:
|
||||
- @thirdweb-dev/sdk@3.10.36
|
||||
- @thirdweb-dev/wallets@1.0.12
|
||||
|
||||
## 3.14.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b), [`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b)]:
|
||||
- @thirdweb-dev/storage@1.1.9
|
||||
- @thirdweb-dev/chains@0.1.34
|
||||
- @thirdweb-dev/sdk@3.10.35
|
||||
- @thirdweb-dev/wallets@1.0.11
|
||||
|
||||
## 3.14.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.14",
|
||||
"version": "3.14.17",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -84,7 +84,7 @@
|
||||
"@types/react": "^18.2.14",
|
||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"eslint": "^8.43.0",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-better-tree-shaking": "0.0.3",
|
||||
@@ -93,7 +93,7 @@
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.2",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.0.0",
|
||||
"react": "^18.2.0",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const AUTH_TOKEN_STORAGE_KEY = "auth_token_storage_key";
|
||||
export const AUTH_TOKEN_STORAGE_KEY = "auth_token_storage_key";
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export const DEFAULT_API_KEY =
|
||||
"fb52f0ca630bdd02f0d5210d9e8e3568272ac765dd0709272918eefb29d3ac9e";
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ThirdwebAuthProvider } from "../../evm/contexts/ThirdwebAuthProvider";
|
||||
import { useUpdateChainsWithApiKeys } from "../../evm/hooks/chain-hooks";
|
||||
import { useUpdateChainsWithClientId } from "../../evm/hooks/chain-hooks";
|
||||
import { ThirdwebSDKProvider } from "../../evm/providers/thirdweb-sdk-provider";
|
||||
import { ThirdwebSDKProviderProps } from "../../evm/providers/types";
|
||||
import { WalletConfig } from "../types/wallet";
|
||||
@@ -106,12 +106,10 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
}, [props.supportedChains, activeChain]);
|
||||
|
||||
const [supportedChainsWithKey, activeChainIdOrObjWithKey] =
|
||||
useUpdateChainsWithApiKeys(
|
||||
useUpdateChainsWithClientId(
|
||||
supportedChainsNonNull,
|
||||
props.activeChain || supportedChainsNonNull[0],
|
||||
props.thirdwebApiKey,
|
||||
props.alchemyApiKey,
|
||||
props.infuraApiKey,
|
||||
props.clientId,
|
||||
);
|
||||
|
||||
const activeChainWithKey = useMemo(() => {
|
||||
@@ -155,6 +153,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
activeChain={activeChainWithKey}
|
||||
autoSwitch={props.autoSwitch}
|
||||
autoConnectTimeout={props.autoConnectTimeout}
|
||||
clientId={props.clientId}
|
||||
>
|
||||
<ThirdwebSDKProviderWrapper
|
||||
queryClient={props.queryClient}
|
||||
@@ -163,9 +162,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
activeChain={activeChainWithKey}
|
||||
storageInterface={props.storageInterface}
|
||||
authConfig={props.authConfig}
|
||||
thirdwebApiKey={props.thirdwebApiKey}
|
||||
alchemyApiKey={props.alchemyApiKey}
|
||||
infuraApiKey={props.infuraApiKey}
|
||||
clientId={props.clientId}
|
||||
>
|
||||
<ThirdwebAuthProvider value={props.authConfig}>
|
||||
{props.children}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { DAppMetaData } from "../types/dAppMeta";
|
||||
import type { WalletConfig, WalletInstance } from "../types/wallet";
|
||||
import { ThirdwebThemeContext } from "./theme-context";
|
||||
import type {
|
||||
WalletConfig,
|
||||
WalletInstance,
|
||||
WalletOptions,
|
||||
} from "../types/wallet";
|
||||
import { Chain } from "@thirdweb-dev/chains";
|
||||
import {
|
||||
AbstractClientWallet,
|
||||
@@ -102,6 +105,7 @@ export function ThirdwebWalletProvider(
|
||||
chains: Chain[];
|
||||
autoSwitch?: boolean;
|
||||
autoConnectTimeout?: number;
|
||||
clientId?: string;
|
||||
}>,
|
||||
) {
|
||||
const [signer, setSigner] = useState<Signer | undefined>(undefined);
|
||||
@@ -130,21 +134,14 @@ export function ThirdwebWalletProvider(
|
||||
// if autoSwitch is enabled - enforce connection to activeChain
|
||||
const chainToConnect = props.autoSwitch ? props.activeChain : undefined;
|
||||
|
||||
const theme = useContext(ThirdwebThemeContext);
|
||||
|
||||
const walletParams = useMemo(() => {
|
||||
const walletChains = props.chains;
|
||||
const walletOptions = {
|
||||
chains: walletChains,
|
||||
dappMetadata: props.dAppMeta,
|
||||
};
|
||||
|
||||
const walletParams: WalletOptions = useMemo(() => {
|
||||
return {
|
||||
...walletOptions,
|
||||
chains: props.chains,
|
||||
dappMetadata: props.dAppMeta,
|
||||
chain: props.activeChain || props.chains[0],
|
||||
theme: theme || "dark",
|
||||
clientId: props.clientId,
|
||||
};
|
||||
}, [props.chains, props.dAppMeta, props.activeChain, theme]);
|
||||
}, [props.chains, props.dAppMeta, props.activeChain, props.clientId]);
|
||||
|
||||
const createWalletInstance = useCallback(
|
||||
<I extends WalletInstance>(walletConfig: WalletConfig<I>): I => {
|
||||
@@ -494,7 +491,14 @@ async function getLastConnectedWalletInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JSON.parse(str) as LastConnectedWalletInfo;
|
||||
try {
|
||||
return JSON.parse(str) as LastConnectedWalletInfo;
|
||||
} catch {
|
||||
await lastConnectedWalletStorage.removeItem(
|
||||
LAST_CONNECTED_WALLET_STORAGE_KEY,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function saveLastConnectedWalletInfo(
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
import type {
|
||||
AbstractClientWallet,
|
||||
Chain,
|
||||
DAppMetaData,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import type { AbstractClientWallet, Chain } from "@thirdweb-dev/wallets";
|
||||
import { WalletOptions as WalletOptions_ } from "@thirdweb-dev/wallets";
|
||||
|
||||
// these are extra options provided by the react-core package
|
||||
export type ExtraCoreWalletOptions = {
|
||||
chain: Chain;
|
||||
};
|
||||
|
||||
export type WalletOptions = {
|
||||
chains: Chain[];
|
||||
walletId?: string;
|
||||
dappMetadata?: DAppMetaData;
|
||||
} & ExtraCoreWalletOptions;
|
||||
export type WalletOptions = WalletOptions_<ExtraCoreWalletOptions>;
|
||||
|
||||
export type WalletInstance = AbstractClientWallet;
|
||||
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { getChainRPCs, ChainRPCOptions, Chain } from "@thirdweb-dev/chains";
|
||||
|
||||
/**
|
||||
*
|
||||
* use the keys and return a new chain object with updated RPCs
|
||||
*/
|
||||
export const updateChainRPCs = (chain: Chain, options: ChainRPCOptions) => {
|
||||
try {
|
||||
return {
|
||||
...chain,
|
||||
rpc: getChainRPCs(chain, options),
|
||||
};
|
||||
} catch (error) {
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
@@ -3,9 +3,7 @@ import React, { createContext, PropsWithChildren, useContext } from "react";
|
||||
|
||||
interface ThirdwebConfigContext {
|
||||
chains: Chain[];
|
||||
thirdwebApiKey?: string;
|
||||
alchemyApiKey?: string;
|
||||
infuraApiKey?: string;
|
||||
clientId?: string;
|
||||
}
|
||||
|
||||
const ThirdwebConfigContext =
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { createContext } from "react";
|
||||
|
||||
export interface TWSDKContext {
|
||||
sdk?: ThirdwebSDK;
|
||||
_inProvider?: true;
|
||||
}
|
||||
|
||||
export const ThirdwebSDKContext = /* @__PURE__ */ createContext<TWSDKContext>(
|
||||
{},
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { __DEV__ } from "../../core/constants/runtime";
|
||||
import { useThirdwebConfigContext } from "./thirdweb-config";
|
||||
import { getChainRPC } from "@thirdweb-dev/chains";
|
||||
import { getValidChainRPCs } from "@thirdweb-dev/chains";
|
||||
import { UserWallet } from "@thirdweb-dev/sdk";
|
||||
import { Signer } from "ethers";
|
||||
import React, {
|
||||
@@ -10,6 +10,7 @@ import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
} from "react";
|
||||
import { useSDK } from "../hooks/useSDK";
|
||||
|
||||
interface ThirdwebConnectedWalletContext {
|
||||
wallet: UserWallet | undefined;
|
||||
@@ -33,8 +34,8 @@ const ThirdwebConnectedWalletContext =
|
||||
export const ThirdwebConnectedWalletProvider: React.FC<
|
||||
PropsWithChildren<{ signer?: Signer }>
|
||||
> = ({ signer, children }) => {
|
||||
const { chains, thirdwebApiKey, alchemyApiKey, infuraApiKey } =
|
||||
useThirdwebConfigContext();
|
||||
const { chains, clientId } = useThirdwebConfigContext();
|
||||
const storage = useSDK()?.storage;
|
||||
|
||||
const [contextValue, setContextValue] =
|
||||
useState<ThirdwebConnectedWalletContext>({
|
||||
@@ -50,6 +51,10 @@ export const ThirdwebConnectedWalletProvider: React.FC<
|
||||
}, [signer]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!storage) {
|
||||
return;
|
||||
}
|
||||
|
||||
let s = signer;
|
||||
if (signer) {
|
||||
// just get both of these up front and keep them around with the context
|
||||
@@ -59,11 +64,7 @@ export const ThirdwebConnectedWalletProvider: React.FC<
|
||||
let rpcUrl = undefined;
|
||||
if (chain) {
|
||||
try {
|
||||
rpcUrl = getChainRPC(chain, {
|
||||
thirdwebApiKey,
|
||||
alchemyApiKey,
|
||||
infuraApiKey,
|
||||
});
|
||||
rpcUrl = getValidChainRPCs(chain, clientId)[0];
|
||||
} catch (e) {
|
||||
// failed to get a viable rpc url, nothing we can do
|
||||
console.error(e);
|
||||
@@ -72,14 +73,18 @@ export const ThirdwebConnectedWalletProvider: React.FC<
|
||||
|
||||
// only if the signer is still the same!
|
||||
if (signer === s) {
|
||||
const wallet = new UserWallet(signer, {
|
||||
readonlySettings: rpcUrl
|
||||
? {
|
||||
rpcUrl,
|
||||
chainId,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
const wallet = new UserWallet(
|
||||
signer,
|
||||
{
|
||||
readonlySettings: rpcUrl
|
||||
? {
|
||||
rpcUrl,
|
||||
chainId,
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
storage,
|
||||
);
|
||||
setContextValue({ wallet, address, chainId, signer });
|
||||
}
|
||||
})
|
||||
@@ -100,7 +105,7 @@ export const ThirdwebConnectedWalletProvider: React.FC<
|
||||
s = undefined;
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [signer, thirdwebApiKey, alchemyApiKey, infuraApiKey]);
|
||||
}, [signer, clientId]);
|
||||
|
||||
return (
|
||||
<ThirdwebConnectedWalletContext.Provider value={contextValue}>
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK, useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDK, useSDKChainId } from "../useSDK";
|
||||
import { getErcs, DropContract, WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDK, useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDK, useSDKChainId } from "../useSDK";
|
||||
import { ContractAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
ClaimNFTParams,
|
||||
ClaimNFTReturnType,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
AcceptDirectOffer,
|
||||
BuyFromListingParams,
|
||||
@@ -596,7 +596,10 @@ export function useBidBuffer(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getBidBufferBps(contractAddress, listingId),
|
||||
cacheKeys.contract.marketplace.auction.getBidBufferBps(
|
||||
contractAddress,
|
||||
listingId,
|
||||
),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
@@ -1426,13 +1429,13 @@ export function useBuyDirectListing(contract: RequiredParam<MarketplaceV3>) {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.directListings.buyFromListing,
|
||||
"contract does not support directListings.buyFromListing"
|
||||
"contract does not support directListings.buyFromListing",
|
||||
);
|
||||
|
||||
return await contract.directListings.buyFromListing(
|
||||
data.listingId,
|
||||
data.quantity,
|
||||
data.buyer
|
||||
data.buyer,
|
||||
);
|
||||
},
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
AirdropNFTParams,
|
||||
BurnNFTParams,
|
||||
@@ -256,7 +256,7 @@ export function useOwnedNFTs<TContract extends NFTContract>(
|
||||
invariant(false, "Unknown NFT type");
|
||||
},
|
||||
{
|
||||
enabled: !!erc721 || (!!erc1155 && !!ownerWalletAddress),
|
||||
enabled: (!!erc721 || !!erc1155) && !!ownerWalletAddress,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import {
|
||||
ClaimTokenParams,
|
||||
getErc20,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { updateChainRPCs } from "../../core/utils/updateChainRpcs";
|
||||
import { useMemo } from "react";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import { updateChainRPCs, type Chain } from "@thirdweb-dev/chains";
|
||||
|
||||
export function useUpdateChainsWithApiKeys<
|
||||
export function useUpdateChainsWithClientId<
|
||||
TChains extends Chain[],
|
||||
TActiveChain extends
|
||||
| Chain
|
||||
@@ -11,22 +10,11 @@ export function useUpdateChainsWithApiKeys<
|
||||
>(
|
||||
supportedChains: NonNullable<TChains>,
|
||||
activeChain: TActiveChain,
|
||||
thirdwebApiKey?: string,
|
||||
alchemyApiKey?: string,
|
||||
infuraApiKey?: string,
|
||||
clientId?: string,
|
||||
) {
|
||||
const keys = useMemo(
|
||||
() => ({
|
||||
thirdwebApiKey: thirdwebApiKey,
|
||||
alchemyApiKey: alchemyApiKey,
|
||||
infuraApiKey: infuraApiKey,
|
||||
}),
|
||||
[thirdwebApiKey, alchemyApiKey, infuraApiKey],
|
||||
);
|
||||
|
||||
const supportedChainsWithKey = useMemo(() => {
|
||||
return supportedChains.map((chain) => updateChainRPCs(chain, keys));
|
||||
}, [supportedChains, keys]);
|
||||
return supportedChains.map((chain) => updateChainRPCs(chain, clientId));
|
||||
}, [supportedChains, clientId]);
|
||||
|
||||
const activeChainIdOrObjWithKey = useMemo(() => {
|
||||
if (
|
||||
@@ -37,8 +25,8 @@ export function useUpdateChainsWithApiKeys<
|
||||
return activeChain;
|
||||
}
|
||||
|
||||
return updateChainRPCs(activeChain, keys);
|
||||
}, [activeChain, keys]);
|
||||
return updateChainRPCs(activeChain, clientId);
|
||||
}, [activeChain, clientId]);
|
||||
|
||||
return [supportedChainsWithKey, activeChainIdOrObjWithKey] as const;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "../useSDK";
|
||||
import { createCacheKeyWithNetwork } from "../../utils/cache-keys";
|
||||
import {
|
||||
QueryFunction,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useSDK } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDK } from "../useSDK";
|
||||
|
||||
export { useStorageUpload } from "./useStorageUpload";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useSDK } from "../../providers/thirdweb-sdk-provider";
|
||||
import { useSDK } from "../useSDK";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { IpfsUploadBatchOptions, UploadOptions } from "@thirdweb-dev/storage";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useSDKChainId } from "../providers/thirdweb-sdk-provider";
|
||||
import { useSDKChainId } from "./useSDK";
|
||||
import { useChainId } from "./wallet";
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { useContext } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
import { TWSDKContext, ThirdwebSDKContext } from "../contexts/thirdweb-sdk";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useSDKContext(): TWSDKContext {
|
||||
const ctx = useContext(ThirdwebSDKContext);
|
||||
invariant(
|
||||
ctx._inProvider,
|
||||
"useSDK must be called from within a ThirdwebProvider, did you forget to wrap your app in a <ThirdwebProvider />?",
|
||||
);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {@link ThirdwebSDK}
|
||||
* Access the instance of the thirdweb SDK created by the ThirdwebProvider
|
||||
* to call methods using the connected wallet on the desiredChainId.
|
||||
* @example
|
||||
* ```javascript
|
||||
* const sdk = useSDK();
|
||||
* ```
|
||||
*/
|
||||
export function useSDK(): ThirdwebSDK | undefined {
|
||||
const { sdk } = useSDKContext();
|
||||
return sdk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useSDKChainId(): number | undefined {
|
||||
const sdk = useSDK();
|
||||
return (sdk as any)?._chainId;
|
||||
}
|
||||
@@ -242,11 +242,8 @@ export { useSupportedWallet } from "./hooks/useSupportedWallet";
|
||||
export { useAppURI, useSetAppURI } from "./hooks/async/app";
|
||||
|
||||
// sdk provider
|
||||
export {
|
||||
ThirdwebSDKProvider,
|
||||
useSDK,
|
||||
useSDKChainId,
|
||||
} from "./providers/thirdweb-sdk-provider";
|
||||
export { ThirdwebSDKProvider } from "./providers/thirdweb-sdk-provider";
|
||||
export { useSDK, useSDKChainId } from "./hooks/useSDK";
|
||||
export type { ThirdwebSDKProviderProps } from "./providers/types";
|
||||
|
||||
// types
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
import { DEFAULT_API_KEY } from "../../core/constants/rpc";
|
||||
import { useMemo, useEffect } from "react";
|
||||
import { QueryClientProviderWithDefault } from "../../core/providers/query-client";
|
||||
import { ThirdwebConfigProvider } from "../contexts/thirdweb-config";
|
||||
import { ThirdwebSDKContext } from "../contexts/thirdweb-sdk";
|
||||
import { ThirdwebConnectedWalletProvider } from "../contexts/thirdweb-wallet";
|
||||
import { useUpdateChainsWithApiKeys } from "../hooks/chain-hooks";
|
||||
import { useUpdateChainsWithClientId } from "../hooks/chain-hooks";
|
||||
import { ThirdwebSDKProviderProps } from "./types";
|
||||
import { Chain, defaultChains, getChainRPC } from "@thirdweb-dev/chains";
|
||||
import { Chain, defaultChains, getValidChainRPCs } from "@thirdweb-dev/chains";
|
||||
import { SDKOptionsOutput, ThirdwebSDK } from "@thirdweb-dev/sdk/evm";
|
||||
import { createContext, useContext, useEffect, useMemo } from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
interface TWSDKContext {
|
||||
sdk?: ThirdwebSDK;
|
||||
_inProvider?: true;
|
||||
}
|
||||
|
||||
const ThirdwebSDKContext = /* @__PURE__ */ createContext<TWSDKContext>({});
|
||||
import { checkClientIdOrSecretKey } from "@thirdweb-dev/sdk";
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -27,9 +20,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
activeChain,
|
||||
signer,
|
||||
children,
|
||||
thirdwebApiKey,
|
||||
infuraApiKey,
|
||||
alchemyApiKey,
|
||||
clientId,
|
||||
}: React.PropsWithChildren<
|
||||
{ supportedChains: Readonly<TChains> } & Omit<
|
||||
ThirdwebSDKProviderProps<TChains>,
|
||||
@@ -70,11 +61,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
|
||||
if (supportedChain && supportedChain.rpc.length > 0) {
|
||||
try {
|
||||
const rpcUrl = getChainRPC(supportedChain, {
|
||||
thirdwebApiKey,
|
||||
infuraApiKey,
|
||||
alchemyApiKey,
|
||||
});
|
||||
const rpcUrl = getValidChainRPCs(supportedChain, clientId)[0];
|
||||
|
||||
readonlySettings = {
|
||||
chainId: supportedChain.chainId,
|
||||
@@ -105,7 +92,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
// sdk from chainId
|
||||
sdk_ = new ThirdwebSDK(
|
||||
chainId,
|
||||
{ ...mergedOptions, infuraApiKey, alchemyApiKey, thirdwebApiKey },
|
||||
{ ...mergedOptions, clientId },
|
||||
storageInterface,
|
||||
);
|
||||
}
|
||||
@@ -126,15 +113,7 @@ const WrappedThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
(sdk_ as any)._chainId = chainId;
|
||||
|
||||
return sdk_;
|
||||
}, [
|
||||
activeChainId,
|
||||
alchemyApiKey,
|
||||
infuraApiKey,
|
||||
supportedChains,
|
||||
sdkOptions,
|
||||
storageInterface,
|
||||
thirdwebApiKey,
|
||||
]);
|
||||
}, [activeChainId, supportedChains, sdkOptions, storageInterface, clientId]);
|
||||
|
||||
useEffect(() => {
|
||||
// if we have an sdk and a signer update the signer
|
||||
@@ -179,21 +158,24 @@ export const ThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
queryClient,
|
||||
supportedChains,
|
||||
activeChain,
|
||||
thirdwebApiKey = DEFAULT_API_KEY,
|
||||
alchemyApiKey,
|
||||
infuraApiKey,
|
||||
clientId,
|
||||
...restProps
|
||||
}: React.PropsWithChildren<ThirdwebSDKProviderProps<TChains>>) => {
|
||||
if (!clientId) {
|
||||
checkClientIdOrSecretKey(
|
||||
"No clientId provided in ThirdwebSDK. You will have limited access to thirdweb's services for storage, RPC, and account abstraction. You can get a clientId from https://thirdweb.com/create-api-key",
|
||||
clientId,
|
||||
undefined,
|
||||
);
|
||||
}
|
||||
const supportedChainsNonNull = useMemo(() => {
|
||||
return supportedChains || (defaultChains as any as TChains);
|
||||
}, [supportedChains]);
|
||||
const [supportedChainsWithKey, activeChainIdOrObjWithKey] =
|
||||
useUpdateChainsWithApiKeys(
|
||||
useUpdateChainsWithClientId(
|
||||
supportedChainsNonNull,
|
||||
activeChain || supportedChainsNonNull[0],
|
||||
thirdwebApiKey,
|
||||
alchemyApiKey,
|
||||
infuraApiKey,
|
||||
clientId,
|
||||
);
|
||||
|
||||
const mergedChains = useMemo(() => {
|
||||
@@ -222,61 +204,22 @@ export const ThirdwebSDKProvider = <TChains extends Chain[]>({
|
||||
<ThirdwebConfigProvider
|
||||
value={{
|
||||
chains: mergedChains as Chain[],
|
||||
thirdwebApiKey,
|
||||
alchemyApiKey,
|
||||
infuraApiKey,
|
||||
clientId,
|
||||
}}
|
||||
>
|
||||
<ThirdwebConnectedWalletProvider signer={signer}>
|
||||
<QueryClientProviderWithDefault queryClient={queryClient}>
|
||||
<WrappedThirdwebSDKProvider
|
||||
signer={signer}
|
||||
supportedChains={mergedChains}
|
||||
thirdwebApiKey={thirdwebApiKey}
|
||||
alchemyApiKey={alchemyApiKey}
|
||||
infuraApiKey={infuraApiKey}
|
||||
activeChain={activeChainIdOrObjWithKey}
|
||||
{...restProps}
|
||||
>
|
||||
<QueryClientProviderWithDefault queryClient={queryClient}>
|
||||
<WrappedThirdwebSDKProvider
|
||||
signer={signer}
|
||||
supportedChains={mergedChains}
|
||||
clientId={clientId}
|
||||
activeChain={activeChainIdOrObjWithKey}
|
||||
{...restProps}
|
||||
>
|
||||
<ThirdwebConnectedWalletProvider signer={signer}>
|
||||
{children}
|
||||
</WrappedThirdwebSDKProvider>
|
||||
</QueryClientProviderWithDefault>
|
||||
</ThirdwebConnectedWalletProvider>
|
||||
</ThirdwebConnectedWalletProvider>
|
||||
</WrappedThirdwebSDKProvider>
|
||||
</QueryClientProviderWithDefault>
|
||||
</ThirdwebConfigProvider>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
function useSDKContext(): TWSDKContext {
|
||||
const ctx = useContext(ThirdwebSDKContext);
|
||||
invariant(
|
||||
ctx._inProvider,
|
||||
"useSDK must be called from within a ThirdwebProvider, did you forget to wrap your app in a <ThirdwebProvider />?",
|
||||
);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {@link ThirdwebSDK}
|
||||
* Access the instance of the thirdweb SDK created by the ThirdwebProvider
|
||||
* to call methods using the connected wallet on the desiredChainId.
|
||||
* @example
|
||||
* ```javascript
|
||||
* const sdk = useSDK();
|
||||
* ```
|
||||
*/
|
||||
export function useSDK(): ThirdwebSDK | undefined {
|
||||
const { sdk } = useSDKContext();
|
||||
return sdk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function useSDKChainId(): number | undefined {
|
||||
const sdk = useSDK();
|
||||
return (sdk as any)?._chainId;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { QueryClientProviderProps } from "../../core/providers/query-client
|
||||
import type { ThirdwebAuthConfig } from "../contexts/thirdweb-auth";
|
||||
import type { Chain } from "@thirdweb-dev/chains";
|
||||
import type { SDKOptions } from "@thirdweb-dev/sdk";
|
||||
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import type { IThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import type { Signer } from "ethers";
|
||||
|
||||
export interface ThirdwebSDKProviderProps<TChains extends Chain[]>
|
||||
@@ -22,7 +22,7 @@ export interface ThirdwebSDKProviderProps<TChains extends Chain[]>
|
||||
/**
|
||||
* The storage interface to use with the sdk.
|
||||
*/
|
||||
storageInterface?: ThirdwebStorage;
|
||||
storageInterface?: IThirdwebStorage;
|
||||
/**
|
||||
* The configuration used for thirdweb auth usage. Enables users to login
|
||||
* to backends with their wallet.
|
||||
@@ -41,8 +41,6 @@ export interface ThirdwebSDKProviderProps<TChains extends Chain[]>
|
||||
| (string & {})
|
||||
| Chain;
|
||||
|
||||
// api keys that can be passed
|
||||
thirdwebApiKey?: string;
|
||||
alchemyApiKey?: string;
|
||||
infuraApiKey?: string;
|
||||
// client Id for thirdweb services
|
||||
clientId?: string;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ export const ThirdwebSDKProvider: ComponentWithChildren<
|
||||
sdk,
|
||||
desiredNetwork: network || "unknown",
|
||||
_inProvider: true,
|
||||
} as const),
|
||||
}) as const,
|
||||
[sdk, network],
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Adds support for clientId / secretKey
|
||||
|
||||
## 0.2.35
|
||||
|
||||
## 0.2.34
|
||||
|
||||
## 0.2.33
|
||||
|
||||
## 0.2.32
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
module.exports = {
|
||||
presets: ['module:metro-react-native-babel-preset'],
|
||||
presets: ["module:metro-react-native-babel-preset"],
|
||||
plugins: [
|
||||
[
|
||||
"module-resolver",
|
||||
{
|
||||
alias: {
|
||||
crypto: "react-native-crypto",
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.33",
|
||||
"version": "0.2.36",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
@@ -25,7 +25,8 @@
|
||||
"@walletconnect/react-native-compat": "^2.8.6",
|
||||
"base-64": "^1.0.0",
|
||||
"big-integer": "^1.6.51",
|
||||
"react-native-get-random-values": "^1.9.0"
|
||||
"react-native-get-random-values": "^1.9.0",
|
||||
"react-native-url-polyfill": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ethers": "^5.5.1",
|
||||
@@ -33,6 +34,7 @@
|
||||
"react-native": ">=0.70.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@thirdweb-dev/tsconfig": "workspace:*",
|
||||
"@types/node": "^18.16.18",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
|
||||
@@ -2,4 +2,7 @@
|
||||
// prettier-ignore
|
||||
import "react-native-get-random-values";
|
||||
|
||||
// URL polyfill for React Native
|
||||
import 'react-native-url-polyfill/auto';
|
||||
|
||||
import "./shims";
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.2.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1362](https://github.com/thirdweb-dev/js/pull/1362) [`44dbf283`](https://github.com/thirdweb-dev/js/commit/44dbf283c985f3e2ecbeb1cfdf09fe1d84e26298) Thanks [@iketw](https://github.com/iketw)! - Correctly pass clientId in storage
|
||||
|
||||
- [#1316](https://github.com/thirdweb-dev/js/pull/1316) [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b) Thanks [@iketw](https://github.com/iketw)! - Adds new `clientId` prop to access thirdweb's services.
|
||||
|
||||
You can create a _free_ `clientId` [on the thirdweb Dashboard](https://thirdweb.com/dashboard)
|
||||
|
||||
```javascript
|
||||
<ThirdwebProvider clientId="your-client-id" />
|
||||
```
|
||||
|
||||
- Updated dependencies [[`44dbf283`](https://github.com/thirdweb-dev/js/commit/44dbf283c985f3e2ecbeb1cfdf09fe1d84e26298), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b), [`d8447146`](https://github.com/thirdweb-dev/js/commit/d8447146092c1962f410155ab2047225453aaa2b)]:
|
||||
- @thirdweb-dev/storage@1.2.0
|
||||
- @thirdweb-dev/sdk@3.10.37
|
||||
- @thirdweb-dev/react-core@3.14.17
|
||||
- @thirdweb-dev/chains@0.1.35
|
||||
- @thirdweb-dev/wallets@1.1.0
|
||||
|
||||
## 0.2.35
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7a6534d1`](https://github.com/thirdweb-dev/js/commit/7a6534d1a98cab1eb47cf88d13e2b7ec04037e42), [`dac8fa7d`](https://github.com/thirdweb-dev/js/commit/dac8fa7d98b6952acf8d13e173099889c1d47da8), [`c5761b99`](https://github.com/thirdweb-dev/js/commit/c5761b99e9797772481506e90cbfa5c35a05bd1d), [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220)]:
|
||||
- @thirdweb-dev/react-core@3.14.16
|
||||
- @thirdweb-dev/sdk@3.10.36
|
||||
- @thirdweb-dev/wallets@1.0.12
|
||||
|
||||
## 0.2.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b), [`8dd7540c`](https://github.com/thirdweb-dev/js/commit/8dd7540c455aa70534f6d29986537592fd12169b)]:
|
||||
- @thirdweb-dev/storage@1.1.9
|
||||
- @thirdweb-dev/chains@0.1.34
|
||||
- @thirdweb-dev/react-core@3.14.15
|
||||
- @thirdweb-dev/sdk@3.10.35
|
||||
- @thirdweb-dev/wallets@1.0.11
|
||||
|
||||
## 0.2.33
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.33",
|
||||
"version": "0.2.36",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -35,6 +35,7 @@
|
||||
"@thirdweb-dev/storage": "workspace:*",
|
||||
"@thirdweb-dev/wallets": "workspace:*",
|
||||
"abitype": "^0.2.5",
|
||||
"expo-application": "^5.3.0",
|
||||
"expo-clipboard": "^4.1.2",
|
||||
"expo-document-picker": "^11.2.2",
|
||||
"expo-file-system": "^15.2.2",
|
||||
@@ -56,7 +57,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.60.1",
|
||||
"@typescript-eslint/parser": "^5.60.1",
|
||||
"babel-jest": "^29.2.1",
|
||||
"eslint": "^8.43.0",
|
||||
"eslint": "^8.45.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-thirdweb": "workspace:*",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
@@ -65,7 +66,7 @@
|
||||
"ethers": "^5.7.2",
|
||||
"expo": "^47.0.14",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier": "^3.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-native": "^0.71.11",
|
||||
"react-native-camera": "^4.2.1",
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import {
|
||||
GatewayUrls,
|
||||
IStorageUploader,
|
||||
IpfsUploadBatchOptions,
|
||||
ThirdwebStorageOptions,
|
||||
UploadOptions,
|
||||
parseGatewayUrls,
|
||||
replaceObjectSchemesWithGatewayUrls,
|
||||
replaceSchemeWithGatewayUrl,
|
||||
IThirdwebStorage,
|
||||
IStorageDownloader,
|
||||
StorageDownloader,
|
||||
} from "@thirdweb-dev/storage";
|
||||
|
||||
import { prepareGatewayUrls } from "./utils";
|
||||
import { IpfsUploader } from "./uploader";
|
||||
import { UploadDataValue } from "./types";
|
||||
|
||||
export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
|
||||
implements IThirdwebStorage
|
||||
{
|
||||
private uploader: IStorageUploader<T>;
|
||||
private downloader: IStorageDownloader;
|
||||
private gatewayUrls: GatewayUrls;
|
||||
|
||||
constructor(options?: ThirdwebStorageOptions<T>) {
|
||||
this.uploader =
|
||||
options?.uploader ||
|
||||
new IpfsUploader({
|
||||
clientId: options?.clientId,
|
||||
});
|
||||
this.downloader =
|
||||
options?.downloader ||
|
||||
new StorageDownloader({
|
||||
clientId: options?.clientId,
|
||||
});
|
||||
this.gatewayUrls = prepareGatewayUrls(
|
||||
parseGatewayUrls(options?.gatewayUrls),
|
||||
options?.clientId,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve any scheme on a URL to get a retrievable URL for the data
|
||||
*
|
||||
* @param url - The URL to resolve the scheme of
|
||||
* @returns The URL with its scheme resolved
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const uri = "ipfs://example";
|
||||
* const url = storage.resolveScheme(uri);
|
||||
* console.log(url);
|
||||
* ```
|
||||
*/
|
||||
resolveScheme(url: string): string {
|
||||
return replaceSchemeWithGatewayUrl(url, this.gatewayUrls) as string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads arbitrary data from any URL scheme.
|
||||
*
|
||||
* @param url - The URL of the data to download
|
||||
* @returns The response object fetched from the resolved URL
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const uri = "ipfs://example";
|
||||
* const data = await storage.download(uri);
|
||||
* ```
|
||||
*/
|
||||
async download(url: string): Promise<Response> {
|
||||
return this.downloader.download(url, this.gatewayUrls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads JSON data from any URL scheme.
|
||||
* Resolves any URLs with schemes to retrievable gateway URLs.
|
||||
*
|
||||
* @param url - The URL of the JSON data to download
|
||||
* @returns The JSON data fetched from the resolved URL
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const uri = "ipfs://example";
|
||||
* const json = await storage.downloadJSON(uri);
|
||||
* ```
|
||||
*/
|
||||
async downloadJSON<TJSON = any>(url: string): Promise<TJSON> {
|
||||
const res = await this.download(url);
|
||||
|
||||
// If we get a JSON object, recursively replace any schemes with gatewayUrls
|
||||
const json = await res.json();
|
||||
return replaceObjectSchemesWithGatewayUrls(json, this.gatewayUrls) as TJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload arbitrary file or JSON data using the configured decentralized storage system.
|
||||
* Automatically uploads any file data within JSON objects and replaces them with hashes.
|
||||
*
|
||||
* @param data - Arbitrary file or JSON data to upload
|
||||
* @param options - Options to pass through to the storage uploader class
|
||||
* @returns - The URI of the uploaded data
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* // Upload an image
|
||||
* launchImageLibrary({mediaType: 'photo'}, async response => {
|
||||
* if (response.assets?.[0]) {
|
||||
* const {fileName, type, uri} = response.assets[0];
|
||||
* if (!uri) {
|
||||
* throw new Error('No uri');
|
||||
* }
|
||||
* const resp = await storage.upload({
|
||||
* uri,
|
||||
* type,
|
||||
* name: fileName,
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
* const jsonUri = await storage.upload(json);
|
||||
* ```
|
||||
*/
|
||||
async upload(data: UploadDataValue, options?: T): Promise<string> {
|
||||
const [uri] = await this.uploadBatch([data], options);
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch upload arbitrary file or JSON data using the configured decentralized storage system.
|
||||
* Automatically uploads any file data within JSON objects and replaces them with hashes.
|
||||
*
|
||||
* @param data - Array of arbitrary file or JSON data to upload
|
||||
* @param options - Options to pass through to the storage uploader class
|
||||
* @returns - The URIs of the uploaded data
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* // Upload an image
|
||||
* launchImageLibrary({mediaType: 'photo'}, async response => {
|
||||
* if (response.assets?.[0]) {
|
||||
* const {fileName, type, uri} = response.assets[0];
|
||||
* if (!uri) {
|
||||
* throw new Error('No uri');
|
||||
* }
|
||||
* const resp = await storage.upload({
|
||||
* uri,
|
||||
* type,
|
||||
* name: fileName,
|
||||
* });
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* // Upload an array of JSON objects
|
||||
* const objects = [
|
||||
* { name: "JSON 1", text: "Hello World" },
|
||||
* { name: "JSON 2", trait: "Awesome" },
|
||||
* ];
|
||||
* const jsonUris = await storage.uploadBatch(objects);
|
||||
* ```
|
||||
*/
|
||||
async uploadBatch(data: UploadDataValue[], options?: T): Promise<string[]> {
|
||||
data = data.filter((item) => item !== undefined);
|
||||
|
||||
if (!data.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const uris: string[] = await this.uploader.uploadBatch(data, options);
|
||||
|
||||
if (options?.uploadWithGatewayUrl || this.uploader.uploadWithGatewayUrl) {
|
||||
return uris.map((uri) => this.resolveScheme(uri));
|
||||
} else {
|
||||
return uris;
|
||||
}
|
||||
}
|
||||
|
||||
getGatewayUrls(): GatewayUrls {
|
||||
return this.gatewayUrls;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type IpfsDownloaderOptions = {
|
||||
/**
|
||||
* Optional clientId to associate with the IpfsDownloader - when used from the frontend.
|
||||
* You can get a clientId here: https://thirdweb.com/create-api-key
|
||||
*/
|
||||
clientId?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type IpfsUploaderOptions = {
|
||||
/**
|
||||
* Whether or not to replace any URLs with schemes with resolved URLs before upload
|
||||
*/
|
||||
uploadWithGatewayUrl?: boolean;
|
||||
/**
|
||||
* Optional clientId to associate with the IpfsUploader.
|
||||
* You can get an clientId here: https://thirdweb.com/create-api-key
|
||||
*/
|
||||
clientId?: string;
|
||||
};
|
||||
|
||||
export type UploadFile = { name?: string; type?: string; uri: string };
|
||||
|
||||
export type UploadDataValue = UploadFile | any;
|
||||
@@ -0,0 +1,256 @@
|
||||
import {
|
||||
IStorageUploader,
|
||||
IpfsUploadBatchOptions,
|
||||
isFileBufferOrStringEqual,
|
||||
TW_UPLOAD_SERVER_URL,
|
||||
} from "@thirdweb-dev/storage";
|
||||
import { IpfsUploaderOptions, UploadDataValue } from "./types";
|
||||
import * as Application from "expo-application";
|
||||
|
||||
const APP_BUNDLE_ID = Application.applicationId;
|
||||
const METADATA_NAME = "Storage React Native SDK";
|
||||
|
||||
export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
|
||||
public uploadWithGatewayUrl?: boolean | undefined;
|
||||
private clientId?: string;
|
||||
|
||||
constructor(options?: IpfsUploaderOptions) {
|
||||
this.uploadWithGatewayUrl = options?.uploadWithGatewayUrl || false;
|
||||
this.clientId = options?.clientId;
|
||||
}
|
||||
|
||||
async uploadBatch(
|
||||
data: UploadDataValue[],
|
||||
options?: IpfsUploadBatchOptions | undefined,
|
||||
): Promise<string[]> {
|
||||
if (data.length === 0) {
|
||||
throw new Error("[UPLOAD_BATCH_ERROR] No files or objects to upload.");
|
||||
}
|
||||
|
||||
// if (options?.uploadWithoutDirectory && data.length > 1) {
|
||||
// throw new Error(
|
||||
// "[UPLOAD_WITHOUT_DIRECTORY_ERROR] Cannot upload more than one file without directory!",
|
||||
// );
|
||||
// }
|
||||
|
||||
const metadata = {
|
||||
name: METADATA_NAME,
|
||||
keyvalues: { ...options?.metadata },
|
||||
};
|
||||
|
||||
if ("uri" in data[0] && "type" in data[0] && "name" in data[0]) {
|
||||
// then it's an array of files
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const formData = new FormData();
|
||||
|
||||
const { form, fileNames } = this.buildFormData(
|
||||
formData,
|
||||
data as { name?: string; type?: string; uri: string }[],
|
||||
options,
|
||||
);
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
let timer = setTimeout(() => {
|
||||
xhr.abort();
|
||||
reject(
|
||||
new Error(
|
||||
"Request to upload timed out! No upload progress received in 30s",
|
||||
),
|
||||
);
|
||||
}, 30000);
|
||||
|
||||
xhr.upload.addEventListener("loadstart", () => {
|
||||
console.log(`[${Date.now()}] [IPFS] Started`);
|
||||
});
|
||||
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
console.log(`[IPFS] Progress Event ${event.loaded}/${event.total}`);
|
||||
|
||||
clearTimeout(timer);
|
||||
|
||||
if (event.loaded < event.total) {
|
||||
timer = setTimeout(() => {
|
||||
xhr.abort();
|
||||
reject(
|
||||
new Error(
|
||||
"Request to upload timed out! No upload progress received in 30s",
|
||||
),
|
||||
);
|
||||
}, 30000);
|
||||
} else {
|
||||
console.log(
|
||||
`[${Date.now()}] [IPFS] Uploaded files. Waiting for response.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
xhr.addEventListener("load", () => {
|
||||
console.log(`[${Date.now()}] [IPFS] Load`);
|
||||
clearTimeout(timer);
|
||||
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
let body;
|
||||
try {
|
||||
body = JSON.parse(xhr.responseText);
|
||||
} catch (err) {
|
||||
return reject(
|
||||
new Error("Failed to parse JSON from upload response"),
|
||||
);
|
||||
}
|
||||
|
||||
const cid = body.IpfsHash;
|
||||
if (!cid) {
|
||||
throw new Error("Failed to get IPFS hash from upload response");
|
||||
}
|
||||
|
||||
if (options?.uploadWithoutDirectory) {
|
||||
return resolve([`ipfs://${cid}`]);
|
||||
} else {
|
||||
return resolve(fileNames.map((name) => `ipfs://${cid}/${name}`));
|
||||
}
|
||||
}
|
||||
|
||||
return reject(
|
||||
new Error(
|
||||
`Upload failed with status ${xhr.status} - ${xhr.responseText}`,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
xhr.addEventListener("error", () => {
|
||||
console.log("[IPFS] Load");
|
||||
clearTimeout(timer);
|
||||
|
||||
if (
|
||||
(xhr.readyState !== 0 && xhr.readyState !== 4) ||
|
||||
xhr.status === 0
|
||||
) {
|
||||
return reject(
|
||||
new Error(
|
||||
`This looks like a network error, the endpoint might be blocked by an internet provider or a firewall. ${xhr.responseText}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return reject(new Error("Unknown upload error occured"));
|
||||
});
|
||||
|
||||
xhr.open("POST", `${TW_UPLOAD_SERVER_URL}/ipfs/upload`);
|
||||
xhr.setRequestHeader("x-bundle-id", APP_BUNDLE_ID || ""); // only empty on web
|
||||
if (this.clientId) {
|
||||
xhr.setRequestHeader("x-client-id", this.clientId);
|
||||
}
|
||||
|
||||
xhr.send(form);
|
||||
});
|
||||
} else {
|
||||
// assume an array of things
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const fetchBody = JSON.stringify({
|
||||
metadata: metadata,
|
||||
content: data,
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await fetch(`${TW_UPLOAD_SERVER_URL}/ipfs/pin-json`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-bundle-id": APP_BUNDLE_ID || "", // only empty on web
|
||||
...(this.clientId ? { "x-client-id": this.clientId } : {}),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: fetchBody,
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const ipfs = await res.json();
|
||||
const cid = ipfs.IpfsHash;
|
||||
|
||||
return resolve([`ipfs://${cid}`]);
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private buildFormData(
|
||||
form: FormData,
|
||||
files: { name?: string; type?: string; uri: string }[],
|
||||
options?: IpfsUploadBatchOptions,
|
||||
) {
|
||||
const fileNameToFileMap = new Map<
|
||||
string,
|
||||
{ name?: string; type?: string; uri: string }
|
||||
>();
|
||||
const fileNames: string[] = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
let fileName = "";
|
||||
|
||||
if (options?.rewriteFileNames) {
|
||||
let extensions = "";
|
||||
if (file.name) {
|
||||
const extensionStartIndex = file.name.lastIndexOf(".");
|
||||
if (extensionStartIndex > -1) {
|
||||
extensions = file.name.substring(extensionStartIndex);
|
||||
}
|
||||
}
|
||||
fileName = `${
|
||||
i + options.rewriteFileNames.fileStartNumber
|
||||
}${extensions}`;
|
||||
} else {
|
||||
fileName = `${file.name}`;
|
||||
}
|
||||
|
||||
// TODO: If we don't want to wrap with directory, adjust the filepath
|
||||
// const filepath = options?.uploadWithoutDirectory
|
||||
// ? 'files'
|
||||
// : `files/${fileName}`;
|
||||
|
||||
if (fileNameToFileMap.has(fileName)) {
|
||||
// if the file in the map is the same as the file we are already looking at then just skip and continue
|
||||
if (isFileBufferOrStringEqual(fileNameToFileMap.get(fileName), file)) {
|
||||
// we add it to the filenames array so that we can return the correct number of urls,
|
||||
fileNames.push(fileName);
|
||||
// but then we skip because we don't need to upload it multiple times
|
||||
continue;
|
||||
}
|
||||
// otherwise if file names are the same but they are not the same file then we should throw an error (trying to upload to differnt files but with the same names)
|
||||
throw new Error(
|
||||
`[DUPLICATE_FILE_NAME_ERROR] File name ${fileName} was passed for more than one different file.`,
|
||||
);
|
||||
}
|
||||
|
||||
// add it to the map so that we can check for duplicates
|
||||
fileNameToFileMap.set(fileName, file);
|
||||
// add it to the filenames array so that we can return the correct number of urls
|
||||
fileNames.push(fileName);
|
||||
|
||||
form.append("file", file);
|
||||
}
|
||||
|
||||
const metadata = {
|
||||
name: METADATA_NAME,
|
||||
keyvalues: { ...options?.metadata },
|
||||
};
|
||||
form.append("pinataMetadata", JSON.stringify(metadata));
|
||||
|
||||
if (options?.uploadWithoutDirectory) {
|
||||
form.append(
|
||||
"pinataOptions",
|
||||
JSON.stringify({
|
||||
wrapWithDirectory: false,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
form,
|
||||
// encode the file names on the way out (which is what the upload backend expects)
|
||||
fileNames: fileNames.map((fName) => encodeURIComponent(fName)),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { DEFAULT_GATEWAY_URLS, GatewayUrls } from "@thirdweb-dev/storage";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function prepareGatewayUrls(
|
||||
gatewayUrls: GatewayUrls,
|
||||
clientId?: string,
|
||||
): GatewayUrls {
|
||||
const allGatewayUrls = {
|
||||
...DEFAULT_GATEWAY_URLS,
|
||||
...gatewayUrls,
|
||||
};
|
||||
|
||||
for (const key of Object.keys(allGatewayUrls)) {
|
||||
const cleanedGatewayUrls = allGatewayUrls[key]
|
||||
.map((url) => {
|
||||
// inject clientId when present
|
||||
if (clientId && url.includes("{clientId}")) {
|
||||
return url.replace("{clientId}", clientId);
|
||||
} else if (url.includes("{clientId}")) {
|
||||
// if no client id passed, filter out the url
|
||||
return undefined;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
})
|
||||
.filter((url) => url !== undefined) as string[];
|
||||
|
||||
allGatewayUrls[key] = cleanedGatewayUrls;
|
||||
}
|
||||
|
||||
return allGatewayUrls;
|
||||
}
|
||||
+1
-1
@@ -165,7 +165,7 @@ export const ConnectWalletDetailsModal = ({
|
||||
/>
|
||||
|
||||
{activeWallet?.walletId === LocalWallet.id ? (
|
||||
<Text variant="error">
|
||||
<Text variant="error" textAlign="left">
|
||||
{
|
||||
"This is a temporary guest wallet. Download a backup if you don't want to lose access to it."
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user