Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
5cea8436c1 Version Packages (#1341)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-07-17 15:10:05 +02:00
Joaquim VergesandGitHub dac8fa7d98 [SDK] Fix getOwned missing last owner for OpenEdition contracts (#1357) 2023-07-15 22:13:58 +00:00
Joaquim VergesandGitHub 7a6534d1a9 [React] Fix wrong enabled logic in useOwnedNFTs (#1356) 2023-07-15 05:02:06 +00:00
Tair AsimandGitHub d5aee62bf4 [service-utils] remove unused type (#1355) 2023-07-14 23:33:28 +00:00
Tair AsimandGitHub 0bfdedd4ba [service-utils] fix enforce auth param (#1354) 2023-07-14 23:18:10 +00:00
Joaquim VergesandGitHub c5761b99e9 [Wallets] Switch local wallet to seed based wallets (#1352) 2023-07-14 23:07:59 +00:00
Tair AsimandGitHub 42d9ab68d9 [service-utils] allow to skip auth for backwards compat (#1353) 2023-07-14 22:27:14 +00:00
farhanW3andGitHub fd0650dcac Farhan/service utils fix (#1351) 2023-07-14 20:52:30 +00:00
Tair AsimandGitHub ddb3dabe69 [service-utils] allow target addresses and api url stringy (#1349) 2023-07-14 19:17:28 +00:00
Manan TankandGitHub b96a228273 [wallets, react] Various improvements (#1350) 2023-07-14 18:26:26 +00:00
Tair AsimandGitHub 781e26d896 [service-utils] authorize bundle (#1347) 2023-07-14 16:47:22 +00:00
Tair AsimandGitHub f7392138ee [service-utils] api url fix (#1346) 2023-07-14 09:52:23 +00:00
Jonas DanielsandGitHub 5eb6fc1bf3 [service-utils] - rewrite (#1345) 2023-07-14 08:21:03 +00:00
Danny FridayandGitHub 7dc685bbec Add creatorWalletAddress to ApiKey type (#1343) 2023-07-14 04:11:26 +00:00
Jonas DanielsandGitHub 4915ac50f8 [service-utils] add relayer service definition (#1342) 2023-07-14 04:02:47 +00:00
Jonas DanielsandGitHub d724ad85c5 [service-utils] - fix use endpoint (#1340) 2023-07-14 00:27:25 +00:00
56 changed files with 1814 additions and 709 deletions
+7
View File
@@ -1,5 +1,12 @@
# @thirdweb-dev/auth
## 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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.15",
"version": "3.2.16",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+50
View File
@@ -0,0 +1,50 @@
import type { Chain } from "../src/types";
export default {
"name": "Kroma Sepolia",
"title": "Kroma Testnet Sepolia",
"chainId": 2358,
"shortName": "kroma-sepolia",
"chain": "ETH",
"networkId": 2358,
"nativeCurrency": {
"name": "Sepolia Ether",
"symbol": "ETH",
"decimals": 18
},
"rpc": [
"https://kroma-sepolia.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.sepolia.kroma.network"
],
"faucets": [],
"infoURL": "https://kroma.network",
"icon": {
"url": "ipfs://QmcYafk2je5rMqgnFPDZJTaLi6dgFgq96vmX2Li6DX441B",
"width": 320,
"height": 320,
"format": "svg"
},
"explorers": [
{
"name": "blockscout",
"url": "https://blockscout.sepolia.kroma.network",
"icon": {
"url": "ipfs://QmcYafk2je5rMqgnFPDZJTaLi6dgFgq96vmX2Li6DX441B",
"width": 320,
"height": 320,
"format": "svg"
},
"standard": "EIP3091"
}
],
"parent": {
"type": "L2",
"chain": "eip155-11155111",
"bridges": [
{
"url": "https://kroma.network/bridge"
}
]
},
"testnet": true,
"slug": "kroma-sepolia"
} as const satisfies Chain;
+36
View File
@@ -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;
+36
View File
@@ -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;
+36
View File
@@ -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;
+37
View File
@@ -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;
+34
View File
@@ -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;
+36
View File
@@ -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;
+37
View File
@@ -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;
+7
View File
@@ -1,5 +1,12 @@
# thirdweb
## 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
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.10.36",
"version": "0.10.37",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/react-core
## 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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.15",
"version": "3.14.16",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -256,7 +256,7 @@ export function useOwnedNFTs<TContract extends NFTContract>(
invariant(false, "Unknown NFT type");
},
{
enabled: !!erc721 || (!!erc1155 && !!ownerWalletAddress),
enabled: (!!erc721 || !!erc1155) && !!ownerWalletAddress,
},
);
}
@@ -1,5 +1,7 @@
# @thirdweb-dev/react-native-compat
## 0.2.35
## 0.2.34
## 0.2.33
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.34",
"version": "0.2.35",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/react-native
## 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
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.34",
"version": "0.2.35",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+11
View File
@@ -1,5 +1,16 @@
# @thirdweb-dev/react
## 3.14.16
### Patch Changes
- [#1350](https://github.com/thirdweb-dev/js/pull/1350) [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220) Thanks [@MananTank](https://github.com/MananTank)! - Disable autofocus for the Paper/Magic email/phone input in Connect Wallet Modal to avoid keyboard popup on mobile
- 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
## 3.14.15
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.14.15",
"version": "3.14.16",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -43,6 +43,7 @@ export function InputSelectionUI(props: {
}}
>
<Input
tabIndex={-1}
placeholder={props.placeholder}
variant="secondary"
type={props.type}
@@ -1,5 +1,8 @@
import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
import { MetaMaskWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
import {
MetaMaskWallet,
getInjectedMetamaskProvider,
} from "@thirdweb-dev/wallets";
import { MetamaskConnectUI } from "./MetamaskConnectUI";
type MetamaskWalletOptions = {
@@ -27,10 +30,7 @@ export const metamaskWallet = (
},
connectUI: MetamaskConnectUI,
isInstalled() {
if (assertWindowEthereum(globalThis.window)) {
return globalThis.window.ethereum.isMetaMask;
}
return false;
return !!getInjectedMetamaskProvider();
},
};
};
+6
View File
@@ -1,5 +1,11 @@
# @thirdweb-dev/sdk
## 3.10.36
### Patch Changes
- [#1357](https://github.com/thirdweb-dev/js/pull/1357) [`dac8fa7d`](https://github.com/thirdweb-dev/js/commit/dac8fa7d98b6952acf8d13e173099889c1d47da8) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix getOwned not showing last owned NFT for OpenEdition contracts
## 3.10.35
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.10.35",
"version": "3.10.36",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -87,12 +87,18 @@ export class Erc721Supply implements DetectableFeature {
*/
public async allOwners() {
let totalCount: BigNumber;
let startTokenId = BigNumber.from(0);
if (hasFunction<OpenEditionERC721>("startTokenId", this.contractWrapper)) {
startTokenId = await this.contractWrapper.readContract.startTokenId();
}
try {
totalCount = await this.erc721.totalClaimedSupply();
} catch (e) {
totalCount = await this.totalCount();
}
totalCount = totalCount.add(startTokenId);
// TODO use multicall3 if available
// TODO can't call toNumber() here, this can be a very large number
return (
+28
View File
@@ -1,5 +1,33 @@
# @thirdweb-dev/service-utils
## 0.2.0
### Minor Changes
- [#1345](https://github.com/thirdweb-dev/js/pull/1345) [`5eb6fc1b`](https://github.com/thirdweb-dev/js/commit/5eb6fc1bf309a34167bf1f27fe5b09a3ae781219) Thanks [@jnsdls](https://github.com/jnsdls)! - expose separate entrypoints for cloudflare workers and node projects
### Patch Changes
- [#1342](https://github.com/thirdweb-dev/js/pull/1342) [`4915ac50`](https://github.com/thirdweb-dev/js/commit/4915ac50f8ffd90cd965636905f73d1c99cbda29) Thanks [@jnsdls](https://github.com/jnsdls)! - add relayer service definition
- [#1340](https://github.com/thirdweb-dev/js/pull/1340) [`d724ad85`](https://github.com/thirdweb-dev/js/commit/d724ad85c52f6da341a248fbe62d85a99c1b65d0) Thanks [@jnsdls](https://github.com/jnsdls)! - fix use endpoint
- [#1354](https://github.com/thirdweb-dev/js/pull/1354) [`0bfdedd4`](https://github.com/thirdweb-dev/js/commit/0bfdedd4ba6ce9b42f9636303027b4421eb68d65) Thanks [@assimovt](https://github.com/assimovt)! - Fix enforceAuth param
- [#1355](https://github.com/thirdweb-dev/js/pull/1355) [`d5aee62b`](https://github.com/thirdweb-dev/js/commit/d5aee62bf41e45b5fed3061d4338d4a279a27c38) Thanks [@assimovt](https://github.com/assimovt)! - Remove unused type
- [#1349](https://github.com/thirdweb-dev/js/pull/1349) [`ddb3dabe`](https://github.com/thirdweb-dev/js/commit/ddb3dabe694be96d2de4c01c53d8c6fc6b9e211d) Thanks [@assimovt](https://github.com/assimovt)! - Allow target addresses array and fix api url stringy
- [#1351](https://github.com/thirdweb-dev/js/pull/1351) [`fd0650dc`](https://github.com/thirdweb-dev/js/commit/fd0650dcacfa6bf4a3fa479934046957eef8cf94) Thanks [@farhanW3](https://github.com/farhanW3)! - Fixed Node Service Url formation
- [#1353](https://github.com/thirdweb-dev/js/pull/1353) [`42d9ab68`](https://github.com/thirdweb-dev/js/commit/42d9ab68d949bc6788f628042d916a1c5e660b16) Thanks [@assimovt](https://github.com/assimovt)! - Allow to skip auth for backwards compat
- [#1347](https://github.com/thirdweb-dev/js/pull/1347) [`781e26d8`](https://github.com/thirdweb-dev/js/commit/781e26d89632ef421bec2914d4e3abcc17d96816) Thanks [@assimovt](https://github.com/assimovt)! - Authorize service bundle
- [#1343](https://github.com/thirdweb-dev/js/pull/1343) [`7dc685bb`](https://github.com/thirdweb-dev/js/commit/7dc685bbece749030e85a9f6d5aafa48d3ab8a74) Thanks [@nessup](https://github.com/nessup)! - Add missing type to ApiKey
- [#1346](https://github.com/thirdweb-dev/js/pull/1346) [`f7392138`](https://github.com/thirdweb-dev/js/commit/f7392138eeda55a6557b26a6c957d5b6b90b645c) Thanks [@assimovt](https://github.com/assimovt)! - fix api url extraction from URL in fetchKeyMetadataFromApi
## 0.1.0
### Minor Changes
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-service-utils-cf-worker.cjs.js",
"module": "dist/thirdweb-dev-service-utils-cf-worker.esm.js"
}
+4
View File
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-service-utils-node.cjs.js",
"module": "dist/thirdweb-dev-service-utils-node.esm.js"
}
+22 -10
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/service-utils",
"version": "0.1.0",
"version": "0.2.0",
"main": "dist/thirdweb-dev-service-utils.cjs.js",
"module": "dist/thirdweb-dev-service-utils.esm.js",
"exports": {
@@ -8,6 +8,14 @@
"module": "./dist/thirdweb-dev-service-utils.esm.js",
"default": "./dist/thirdweb-dev-service-utils.cjs.js"
},
"./node": {
"module": "./node/dist/thirdweb-dev-service-utils-node.esm.js",
"default": "./node/dist/thirdweb-dev-service-utils-node.cjs.js"
},
"./cf-worker": {
"module": "./cf-worker/dist/thirdweb-dev-service-utils-cf-worker.esm.js",
"default": "./cf-worker/dist/thirdweb-dev-service-utils-cf-worker.cjs.js"
},
"./package.json": "./package.json"
},
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/pay",
@@ -17,29 +25,32 @@
},
"author": "thirdweb eng <[email protected]>",
"files": [
"dist/"
"dist/",
"node/",
"cf-worker/"
],
"preconstruct": {
"entrypoints": [
"index.ts"
"index.ts",
"cf-worker/index.ts",
"node/index.ts"
],
"exports": true
},
"sideEffects": false,
"devDependencies": {
"@cloudflare/workers-types": "^4.20230710.0",
"@preconstruct/cli": "^2.8.1",
"@thirdweb-dev/tsconfig": "workspace:*",
"@types/jest": "^29.5.2",
"@types/node": "^20.4.1",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"eslint": "^8.44.0",
"eslint-config-prettier": "^8.8.0",
"lint-staged": "^13.2.3",
"prettier": "^3.0.0",
"sort-package-json": "^2.5.1",
"ts-node": "^10.9.1",
"@preconstruct/cli": "^2.7.0",
"@thirdweb-dev/tsconfig": "workspace:*",
"eslint-config-thirdweb": "workspace:*",
"jest": "^29.4.3",
"prettier": "^3.0.0",
"typescript": "^5.1.6"
},
"scripts": {
@@ -48,6 +59,7 @@
"fix": "eslint src/ --fix",
"clean": "rm -rf dist/",
"build": "tsc && preconstruct build",
"push": "yalc push"
"push": "yalc push",
"test": "jest"
}
}
-253
View File
@@ -1,253 +0,0 @@
import {
ApiKey,
ApiResponse,
ServiceConfiguration,
AuthorizationResponse,
AuthorizationValidations,
AuthorizeCFWorkerOptions,
AuthorizeNodeServiceOptions,
AuthOptions,
} from "./types";
export async function authorizeCFWorkerService(
options: AuthorizeCFWorkerOptions,
) {
const { kvStore, ctx, authOptions, serviceConfig, validations } = options;
const { clientId } = authOptions;
let cachedKey;
// first, check if the key is in KV
try {
const kvKey = await kvStore.get(clientId);
if (kvKey) {
cachedKey = JSON.parse(kvKey) as ApiKey;
}
} catch (err) {
// ignore JSON parse, assuming not valid
}
const updateKv = async (keyData: ApiKey) => {
kvStore.put(clientId as string, JSON.stringify(keyData), {
expirationTtl: serviceConfig.cacheTtl || 60,
});
};
return authorize({
authOptions,
serviceConfig: {
...serviceConfig,
cachedKey,
onRefetchComplete: (keyData: ApiKey) => {
ctx.waitUntil(updateKv(keyData));
},
},
validations,
});
}
export async function authorizeNodeService(
options: AuthorizeNodeServiceOptions,
) {
const { authOptions, serviceConfig, validations } = options;
return authorize({
authOptions,
serviceConfig,
validations,
});
}
/**
* Authorizes a request for a given client ID
*
* @returns The Promise AuthorizationResponse
*/
async function authorize(options: {
authOptions: AuthOptions;
serviceConfig: ServiceConfiguration;
validations: AuthorizationValidations;
}): Promise<AuthorizationResponse> {
try {
const { authOptions, serviceConfig, validations } = options;
const { clientId } = authOptions;
const { apiUrl, scope, serviceKey, cachedKey, onRefetchComplete } =
serviceConfig;
let keyData = cachedKey;
// no cached key, re-fetch from API
if (!keyData) {
const response = await fetch(
`${apiUrl}/v1/keys/use/?scope=${scope}&clientId=${clientId}`,
{
method: "GET",
headers: {
"x-service-api-key": serviceKey,
"content-type": "application/json",
},
},
);
const apiResponse = (await response.json()) as ApiResponse;
if (!response.ok) {
const { error } = apiResponse;
return {
authorized: false,
errorMessage: error.message,
errorCode: error.code || "",
statusCode: error.statusCode || 401,
};
}
keyData = apiResponse.data as ApiKey;
if (onRefetchComplete) {
onRefetchComplete(keyData);
}
}
//
// Run validations
//
const authResponse = authAccess(authOptions, keyData);
if (!authResponse?.authorized) {
return authResponse;
}
const authzResponse = authzServices(validations, keyData, scope);
if (!authzResponse?.authorized) {
return authzResponse;
}
// FIXME: validate bundleId
return {
authorized: true,
data: keyData,
};
} catch (err) {
console.error("Failed to authorize this key.", err);
return {
authorized: false,
errorMessage: "Internal error",
errorCode: "INTERNAL_ERROR",
statusCode: 500,
};
}
}
function authAccess(authOptions: AuthOptions, apiKey: ApiKey) {
const { origin, secretHash: providedSecretHash } = authOptions;
const { domains, secretHash } = apiKey;
if (providedSecretHash) {
if (secretHash !== providedSecretHash) {
return {
authorized: false,
errorMessage: "The secret is invalid.",
errorCode: "SECRET_INVALID",
statusCode: 401,
};
}
return {
authorized: true,
};
}
// validate domains
if (origin) {
if (
// find matching domain, or if all domains allowed
domains.find((d) => {
if (d === "*") {
return true;
}
// If the allowedDomain has a wildcard,
// we'll check that the ending of our domain matches the wildcard
if (d.startsWith("*.")) {
const domainRoot = d.slice(2);
return origin.endsWith(domainRoot);
}
// If there's no wildcard, we'll check for an exact match
return d === origin;
})
) {
return {
authorized: true,
};
}
return {
authorized: false,
errorMessage: "The origin is not authorized for this key.",
errorCode: "ORIGIN_UNAUTHORIZED",
statusCode: 401,
};
}
// FIXME: validate bundle id
return {
authorized: false,
errorMessage: "The keys are invalid.",
errorCode: "UNAUTHORIZED",
statusCode: 401,
};
}
function authzServices(
validations: AuthorizationValidations,
apiKey: ApiKey,
scope: string,
) {
const { services } = apiKey;
const { serviceTargetAddresses, serviceAction } = validations;
// validate services
const service = services.find((srv) => srv.name === scope);
if (!service) {
return {
authorized: false,
errorMessage: `The service "${scope}" is not authorized for this key.`,
errorCode: "SERVICE_UNAUTHORIZED",
statusCode: 403,
};
}
// validate service actions
if (serviceAction) {
if (!service.actions.includes(serviceAction)) {
return {
authorized: false,
errorMessage: `The service "${scope}" action "${serviceAction}" is not authorized for this key.`,
errorCode: "SERVICE_ACTION_UNAUTHORIZED",
statusCode: 403,
};
}
}
// validate service target addresses
if (
serviceTargetAddresses &&
!service.targetAddresses.find(
(addr) => addr === "*" || serviceTargetAddresses.includes(addr),
)
) {
return {
authorized: false,
errorMessage: `The service "${scope}" target address is not authorized for this key.`,
errorCode: "SERVICE_TARGET_ADDRESS_UNAUTHORIZED",
statusCode: 403,
};
}
return {
authorized: true,
};
}
-68
View File
@@ -1,68 +0,0 @@
import { KVNamespace, ExecutionContext } from "@cloudflare/workers-types";
import { ServiceName } from "../types";
export interface AuthOptions {
clientId: string;
secretHash?: string;
bundleId?: string;
origin?: string;
}
export interface AuthorizeCFWorkerOptions {
ctx: ExecutionContext;
kvStore: KVNamespace<string>;
authOptions: AuthOptions;
serviceConfig: ServiceConfiguration;
validations: AuthorizationValidations;
}
export interface AuthorizeNodeServiceOptions {
authOptions: AuthOptions;
serviceConfig: ServiceConfiguration;
validations: AuthorizationValidations;
}
export interface ServiceConfiguration {
apiUrl: string;
scope: ServiceName;
serviceKey: string;
cachedKey?: ApiKey;
cacheTtl?: number;
onRefetchComplete?: (key: ApiKey) => void;
}
export interface AuthorizationValidations {
serviceTargetAddresses?: string[];
serviceAction?: string;
}
export interface AuthorizationResponse {
authorized: boolean;
errorMessage?: string;
errorCode?: string;
statusCode?: number;
data?: ApiKey;
}
export interface ApiResponse {
data: ApiKey | null;
error: {
code: string;
statusCode: number;
message: string;
};
}
export interface ApiKey {
id: string;
key: string;
secretHash: string;
walletAddresses: string[];
domains: string[];
bundleIds: string[];
services: {
name: string;
targetAddresses: string[];
actions: string[];
}[];
}
@@ -0,0 +1,151 @@
import type { ExecutionContext, KVNamespace } from "@cloudflare/workers-types";
import type { ApiKeyMetadata, CoreServiceConfig } from "../core/api";
import { authorize } from "../core/authorize";
import type { Request } from "@cloudflare/workers-types";
import type { AuthorizationInput } from "../core/authorize";
import type { AuthorizationResult } from "../core/authorize/types";
import type { CoreAuthInput } from "../core/types";
export * from "../core/services";
type WorkerServiceConfig = CoreServiceConfig & {
kvStore: KVNamespace;
ctx: ExecutionContext;
cacheTtlSeconds?: number;
};
const DEFAULT_CACHE_TTL_SECONDS = 60;
type AuthInput = CoreAuthInput & {
req: Request;
};
export async function authorizeWorker(
authInput: AuthInput,
serviceConfig: WorkerServiceConfig,
): Promise<AuthorizationResult> {
let authData;
try {
authData = await extractAuthorizationData(authInput);
} catch (e) {
if (e instanceof Error && e.message === "KEY_CONFLICT") {
return {
authorized: false,
status: 400,
errorMessage: "Please pass either a client id or a secret key.",
errorCode: "KEY_CONFLICT",
};
}
return {
authorized: false,
status: 500,
errorMessage: "Internal Server Error",
errorCode: "INTERNAL_SERVER_ERROR",
};
}
return await authorize(authData, serviceConfig, {
get: async (clientId: string) => serviceConfig.kvStore.get(clientId),
put: (clientId: string, apiKeyMeta: ApiKeyMetadata) =>
serviceConfig.ctx.waitUntil(
serviceConfig.kvStore.put(
clientId,
JSON.stringify({
updatedAt: Date.now(),
apiKeyMeta,
}),
{
expirationTtl:
serviceConfig.cacheTtlSeconds &&
serviceConfig.cacheTtlSeconds >= DEFAULT_CACHE_TTL_SECONDS
? serviceConfig.cacheTtlSeconds
: DEFAULT_CACHE_TTL_SECONDS,
},
),
),
cacheTtlSeconds: serviceConfig.cacheTtlSeconds ?? DEFAULT_CACHE_TTL_SECONDS,
});
}
async function extractAuthorizationData(
authInput: AuthInput,
): Promise<AuthorizationInput> {
const requestUrl = new URL(authInput.req.url);
const headers = authInput.req.headers;
const secretKey = headers.get("x-secret-key");
// prefer clientId that is explicitly passed in
let clientId = authInput.clientId ?? null;
if (!clientId) {
// next preference is clientId from header
clientId = headers.get("x-client-id");
}
// next preference is search param
if (!clientId) {
clientId = requestUrl.searchParams.get("clientId");
}
// bundle id from header is first preference
let bundleId = headers.get("x-bundle-id");
// next preference is search param
if (!bundleId) {
bundleId = requestUrl.searchParams.get("bundleId");
}
let origin = headers.get("origin");
// if origin header is not available we'll fall back to referrer;
if (!origin) {
origin = headers.get("referer");
}
// if we have an origin at this point, normalize it
if (origin) {
try {
origin = new URL(origin).hostname;
} catch (e) {
console.warn("failed to parse origin", origin, e);
}
}
// handle if we a secret key is passed in the headers
let secretKeyHash: string | null = null;
if (secretKey) {
// hash the secret key
secretKeyHash = await hashSecretKey(secretKey);
// derive the client id from the secret key hash
const derivedClientId = deriveClientIdFromSecretKeyHash(secretKeyHash);
// if we already have a client id passed in we need to make sure they match
if (clientId && clientId !== derivedClientId) {
throw new Error("KEY_CONFLICT");
}
// otherwise set the client id to the derived client id (client id based off of secret key)
clientId = derivedClientId;
}
return {
secretKey,
clientId,
origin,
bundleId,
secretKeyHash,
targetAddress: authInput.targetAddress,
};
}
export async function hashSecretKey(secretKey: string) {
return bufferToHex(
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(secretKey)),
);
}
export function deriveClientIdFromSecretKeyHash(secretKeyHash: string) {
return secretKeyHash.slice(0, 32);
}
function bufferToHex(buffer: ArrayBuffer) {
return [...new Uint8Array(buffer)]
.map((x) => x.toString(16).padStart(2, "0"))
.join("");
}
+54
View File
@@ -0,0 +1,54 @@
import type { ServiceName } from "./services";
export type CoreServiceConfig = {
enforceAuth: boolean;
apiUrl: string;
serviceScope: ServiceName;
serviceApiKey: string;
serviceAction?: string;
};
export type ApiKeyMetadata = {
id: string;
key: string;
creatorWalletAddress: string;
secretHash: string;
walletAddresses: string[];
domains: string[];
bundleIds: string[];
services: {
name: string;
targetAddresses: string[];
actions: string[];
}[];
};
export type ApiResponse = {
data: ApiKeyMetadata | null;
error: {
code: string;
statusCode: number;
message: string;
};
};
export async function fetchKeyMetadataFromApi(
clientId: string,
config: CoreServiceConfig,
): Promise<ApiResponse> {
const { apiUrl, serviceScope, serviceApiKey } = config;
const url = `${apiUrl}/v1/keys/use?clientId=${clientId}&scope=${serviceScope}`;
const response = await fetch(url, {
method: "GET",
headers: {
"x-service-api-key": serviceApiKey,
"content-type": "application/json",
},
});
if (!response.ok) {
throw new Error(
`Error fetching key metadata from API: ${response.statusText}`,
);
}
return (await response.json()) as ApiResponse;
}
@@ -0,0 +1,42 @@
import { authorize } from ".";
import { CoreServiceConfig } from "../api";
const validServiceConfig: CoreServiceConfig = {
apiUrl: "https://api.example.com",
serviceScope: "storage",
serviceApiKey: "service key",
enforceAuth: false,
};
describe("authorizeClient", () => {
it("should skip authorization if auth not enforced and no credentials", async () => {
const result = (await authorize(
{
secretKey: null,
clientId: null,
origin: null,
bundleId: null,
secretKeyHash: null,
},
validServiceConfig,
)) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(null);
});
it("should continue authorization if auth enforced", async () => {
const result = (await authorize(
{
secretKey: null,
clientId: null,
origin: null,
bundleId: null,
secretKeyHash: null,
},
{ ...validServiceConfig, enforceAuth: true },
)) as any;
expect(result.authorized).toBe(false);
});
});
@@ -0,0 +1,97 @@
import { ApiKeyMetadata } from "../api";
import { ClientAuthorizationPayload, authorizeClient } from "./client";
describe("authorizeClient", () => {
const validApiKeyMeta: ApiKeyMetadata = {
id: "1",
key: "your-api-key",
creatorWalletAddress: "creator-address",
secretHash: "secret-hash",
walletAddresses: [],
domains: ["example.com", "*.example.com"],
bundleIds: ["com.example.app"],
services: [],
};
const validAuthOptions: ClientAuthorizationPayload = {
secretKeyHash: "secret-hash",
bundleId: null,
origin: "example.com",
};
it("should authorize client with valid secret key", () => {
const result = authorizeClient(validAuthOptions, validApiKeyMeta) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
});
it("should authorize client with matching wildcard domain", () => {
const authOptionsWithWildcardDomain: ClientAuthorizationPayload = {
secretKeyHash: null,
bundleId: null,
origin: "sub.example.com",
};
const result = authorizeClient(
authOptionsWithWildcardDomain,
validApiKeyMeta,
) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
});
it("should not authorize client with non-matching bundle id", () => {
const authOptionsWithBundleId: ClientAuthorizationPayload = {
secretKeyHash: null,
bundleId: "com.foo.bar",
origin: null,
};
const result = authorizeClient(
authOptionsWithBundleId,
validApiKeyMeta,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
"The bundle is not authorized for this key.",
);
expect(result.errorCode).toBe("BUNDLE_UNAUTHORIZED");
expect(result.status).toBe(401);
});
it("should not authorize client with invalid secret key", () => {
const authOptionsWithInvalidSecret: ClientAuthorizationPayload = {
secretKeyHash: "invalid-secret-hash",
bundleId: null,
origin: null,
};
const result = authorizeClient(
authOptionsWithInvalidSecret,
validApiKeyMeta,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe("The secret is invalid.");
expect(result.errorCode).toBe("SECRET_INVALID");
expect(result.status).toBe(401);
});
it("should not authorize client with unauthorized origin", () => {
const authOptionsWithUnauthorizedOrigin: ClientAuthorizationPayload = {
secretKeyHash: null,
bundleId: null,
origin: "unauthorized.com",
};
const result = authorizeClient(
authOptionsWithUnauthorizedOrigin,
validApiKeyMeta,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
"The origin is not authorized for this key.",
);
expect(result.errorCode).toBe("ORIGIN_UNAUTHORIZED");
expect(result.status).toBe(401);
});
});
@@ -0,0 +1,98 @@
import type { ApiKeyMetadata } from "../api";
import type { AuthorizationResult } from "./types";
export type ClientAuthorizationPayload = {
secretKeyHash: string | null;
bundleId: string | null;
origin: string | null;
};
export function authorizeClient(
authOptions: ClientAuthorizationPayload,
apiKeyMeta: ApiKeyMetadata,
): AuthorizationResult {
const { origin, bundleId, secretKeyHash: providedSecretHash } = authOptions;
const { domains, bundleIds, secretHash } = apiKeyMeta;
if (providedSecretHash) {
if (secretHash !== providedSecretHash) {
return {
authorized: false,
errorMessage: "The secret is invalid.",
errorCode: "SECRET_INVALID",
status: 401,
};
}
return {
authorized: true,
apiKeyMeta,
};
}
// validate domains
if (origin) {
if (
// find matching domain, or if all domains allowed
domains.find((d) => {
if (d === "*") {
return true;
}
// If the allowedDomain has a wildcard,
// we'll check that the ending of our domain matches the wildcard
if (d.startsWith("*.")) {
const domainRoot = d.slice(2);
return origin.endsWith(domainRoot);
}
// If there's no wildcard, we'll check for an exact match
return d === origin;
})
) {
return {
authorized: true,
apiKeyMeta,
};
}
return {
authorized: false,
errorMessage: "The origin is not authorized for this key.",
errorCode: "ORIGIN_UNAUTHORIZED",
status: 401,
};
}
// validate bundleId
if (bundleId) {
if (
// find matching bundle id, or if all bundles allowed
bundleIds.find((b) => {
if (b === "*") {
return true;
}
return b === bundleId;
})
) {
return {
authorized: true,
apiKeyMeta,
};
}
return {
authorized: false,
errorMessage: "The bundle is not authorized for this key.",
errorCode: "BUNDLE_UNAUTHORIZED",
status: 401,
};
}
return {
authorized: false,
errorMessage: "The keys are invalid.",
errorCode: "UNAUTHORIZED",
status: 401,
};
}
@@ -0,0 +1,164 @@
import {
ApiKeyMetadata,
CoreServiceConfig,
fetchKeyMetadataFromApi,
} from "../api";
import { authorizeClient } from "./client";
import { authorizeService } from "./service";
import { AuthorizationResult } from "./types";
export type AuthorizationInput = {
secretKey: string | null;
clientId: string | null;
origin: string | null;
bundleId: string | null;
secretKeyHash: string | null;
targetAddress?: string | string[];
};
type CacheOptions = {
get: (clientId: string) => Promise<string | null>;
put: (clientId: string, data: ApiKeyMetadata) => Promise<void> | void;
cacheTtlSeconds: number;
};
type CacheWithPossibleTtl =
| {
apiKeyMeta: ApiKeyMetadata;
updatedAt: number;
}
| ApiKeyMetadata;
export async function authorize(
authData: AuthorizationInput,
serviceConfig: CoreServiceConfig,
cacheOptions?: CacheOptions,
): Promise<AuthorizationResult> {
const { clientId, targetAddress, secretKeyHash } = authData;
const { enforceAuth } = serviceConfig;
// BACKWARDS COMPAT: if auth not enforced and
// we don't have auth credentials bypass
if (!enforceAuth && !clientId && !secretKeyHash) {
return {
authorized: true,
apiKeyMeta: null,
};
}
// if we don't have a client id at this point we can't authorize
if (!clientId) {
return {
authorized: false,
status: 401,
errorMessage: "Missing clientId or secretKey.",
errorCode: "MISSING_KEY",
};
}
let apiKeyMeta: ApiKeyMetadata | null = null;
// if we have cache options we want to check the cache first
if (cacheOptions) {
try {
const cachedKey = await cacheOptions.get(clientId);
if (cachedKey) {
const parsed = JSON.parse(cachedKey) as CacheWithPossibleTtl;
if ("updatedAt" in parsed) {
// we want to compare the updatedAt time to the current time
// if the difference is greater than the cacheTtl we want to ignore the cached data
const now = Date.now();
const diff = now - parsed.updatedAt;
const cacheTtl = cacheOptions.cacheTtlSeconds * 1000;
// only if the diff is less than the cacheTtl do we want to use the cached key
if (diff < cacheTtl * 1000) {
apiKeyMeta = parsed.apiKeyMeta;
}
} else {
apiKeyMeta = parsed;
}
}
} catch (err) {
// ignore errors, proceed as if not in cache
}
}
// if we don't have a cached key, fetch from the API
if (!apiKeyMeta) {
try {
const { data, error } = await fetchKeyMetadataFromApi(
clientId,
serviceConfig,
);
if (error) {
return {
authorized: false,
errorCode: error.code,
errorMessage: error.message,
status: error.statusCode,
};
} else if (!data) {
return {
authorized: false,
errorCode: "NO_KEY",
errorMessage: "No error but also no key returned.",
status: 500,
};
}
// if we have a key for sure then assign it
apiKeyMeta = data;
// cache the retrieved key if we have cache options
if (cacheOptions) {
// we await this always because it can be a promise or not
await cacheOptions.put(clientId, data);
}
} catch (err) {
console.warn("failed to fetch key metadata from api", err);
return {
authorized: false,
status: 500,
errorMessage: "Failed to fetch key metadata.",
errorCode: "FAILED_TO_FETCH_KEY",
};
}
}
if (!apiKeyMeta) {
return {
authorized: false,
status: 401,
errorMessage: "Key is invalid.",
errorCode: "INVALID_KEY",
};
}
// now we can validate the key itself
const clientAuth = authorizeClient(authData, apiKeyMeta);
if (!clientAuth.authorized) {
return {
errorCode: clientAuth.errorCode,
authorized: false,
status: 401,
errorMessage: clientAuth.errorMessage,
};
}
// if we've made it this far we need to check service specific authorization
const serviceAuth = authorizeService(apiKeyMeta, serviceConfig, {
targetAddress,
});
if (!serviceAuth.authorized) {
return {
errorCode: serviceAuth.errorCode,
authorized: false,
status: 403,
errorMessage: serviceAuth.errorMessage,
};
}
// if we reach this point we are authorized!
return {
authorized: true,
apiKeyMeta,
};
}
@@ -0,0 +1,158 @@
import { ApiKeyMetadata, CoreServiceConfig } from "../api";
import { ServiceAuthorizationPayload, authorizeService } from "./service";
describe("authorizeService", () => {
const validApiKeyMeta: ApiKeyMetadata = {
id: "1",
key: "your-api-key",
creatorWalletAddress: "creator-address",
secretHash: "secret-hash",
walletAddresses: [],
domains: [],
bundleIds: [],
services: [
{
name: "storage",
targetAddresses: ["target1", "target2"],
actions: ["action1", "action2"],
},
{
name: "service2",
targetAddresses: ["target3"],
actions: ["action3"],
},
{
name: "bundler",
targetAddresses: ["*"],
actions: ["action3"],
},
],
};
const validServiceConfig: CoreServiceConfig = {
apiUrl: "https://api.example.com",
serviceScope: "storage",
serviceApiKey: "service-api-key",
serviceAction: "action1",
enforceAuth: true,
};
const validBundlerServiceConfig: CoreServiceConfig = {
apiUrl: "https://api.example.com",
serviceScope: "bundler",
serviceApiKey: "service-api-key",
enforceAuth: true,
};
it("should authorize service with valid service scope and action", () => {
const result = authorizeService(validApiKeyMeta, validServiceConfig) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
});
it("should authorize service with valid target address", () => {
const validAuthorizationPayload: ServiceAuthorizationPayload = {
targetAddress: "target2",
};
const result = authorizeService(
validApiKeyMeta,
validServiceConfig,
validAuthorizationPayload,
) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
});
it("should not authorize service with unauthorized service scope", () => {
const invalidServiceConfig: CoreServiceConfig = {
apiUrl: "https://api.example.com",
serviceScope: "rpc",
serviceApiKey: "service-api-key",
serviceAction: "action1",
enforceAuth: true,
};
const result = authorizeService(
validApiKeyMeta,
invalidServiceConfig,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
'The service "rpc" is not authorized for this key.',
);
expect(result.errorCode).toBe("SERVICE_UNAUTHORIZED");
expect(result.status).toBe(403);
});
it("should not authorize service with unauthorized service action", () => {
const invalidServiceConfig: CoreServiceConfig = {
apiUrl: "https://api.example.com",
serviceScope: "storage",
serviceApiKey: "service-api-key",
serviceAction: "unauthorized-action",
enforceAuth: true,
};
const result = authorizeService(
validApiKeyMeta,
invalidServiceConfig,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
'The service "storage" action "unauthorized-action" is not authorized for this key.',
);
expect(result.errorCode).toBe("SERVICE_ACTION_UNAUTHORIZED");
expect(result.status).toBe(403);
});
it("should not authorize service with unauthorized target address", () => {
const invalidAuthorizationPayload: ServiceAuthorizationPayload = {
targetAddress: "unauthorized-target",
};
const result = authorizeService(
validApiKeyMeta,
validServiceConfig,
invalidAuthorizationPayload,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
'The service "storage" target address is not authorized for this key.',
);
expect(result.errorCode).toBe("SERVICE_TARGET_ADDRESS_UNAUTHORIZED");
expect(result.status).toBe(403);
});
it("should not authorize service with unauthorized target addresses", () => {
const invalidAuthorizationPayload: ServiceAuthorizationPayload = {
targetAddress: ["target1", "target2", "target3"],
};
const result = authorizeService(
validApiKeyMeta,
validServiceConfig,
invalidAuthorizationPayload,
) as any;
expect(result.authorized).toBe(false);
expect(result.errorMessage).toBe(
'The service "storage" target address is not authorized for this key.',
);
expect(result.errorCode).toBe("SERVICE_TARGET_ADDRESS_UNAUTHORIZED");
expect(result.status).toBe(403);
});
it("should authorize bundler service with * target addresses", () => {
const authorizationPayload: ServiceAuthorizationPayload = {
targetAddress: ["target1", "target2"],
};
const result = authorizeService(
validApiKeyMeta,
validBundlerServiceConfig,
authorizationPayload,
) as any;
expect(result.authorized).toBe(true);
expect(result.apiKeyMeta).toEqual(validApiKeyMeta);
});
});
@@ -0,0 +1,66 @@
import { ApiKeyMetadata, CoreServiceConfig } from "../api";
import { AuthorizationResult } from "./types";
export type ServiceAuthorizationPayload = { targetAddress?: string | string[] };
export function authorizeService(
apiKeyMetadata: ApiKeyMetadata,
serviceConfig: CoreServiceConfig,
authorizationPayload?: ServiceAuthorizationPayload,
): AuthorizationResult {
const { services } = apiKeyMetadata;
// validate services
const service = services.find(
(srv) => srv.name === serviceConfig.serviceScope,
);
if (!service) {
return {
authorized: false,
errorMessage: `The service "${serviceConfig.serviceScope}" is not authorized for this key.`,
errorCode: "SERVICE_UNAUTHORIZED",
status: 403,
};
}
// validate service actions
if (serviceConfig.serviceAction) {
const isActionAllowed = service.actions.includes(
serviceConfig.serviceAction,
);
if (!isActionAllowed) {
return {
authorized: false,
errorMessage: `The service "${serviceConfig.serviceScope}" action "${serviceConfig.serviceAction}" is not authorized for this key.`,
errorCode: "SERVICE_ACTION_UNAUTHORIZED",
status: 403,
};
}
}
// validate service target addresses
// the service has to pass in the target address for this to be validated
if (authorizationPayload?.targetAddress) {
const checkedAddresses = Array.isArray(authorizationPayload.targetAddress)
? authorizationPayload.targetAddress
: [authorizationPayload.targetAddress];
const allAllowed = service.targetAddresses.includes("*");
if (
!allAllowed &&
checkedAddresses.some((ta) => !service.targetAddresses.includes(ta))
) {
return {
authorized: false,
errorMessage: `The service "${serviceConfig.serviceScope}" target address is not authorized for this key.`,
errorCode: "SERVICE_TARGET_ADDRESS_UNAUTHORIZED",
status: 403,
};
}
}
return {
authorized: true,
apiKeyMeta: apiKeyMetadata,
};
}
@@ -0,0 +1,13 @@
import { ApiKeyMetadata } from "../api";
export type AuthorizationResult =
| {
authorized: true;
apiKeyMeta: ApiKeyMetadata | null;
}
| {
authorized: false;
status: number;
errorMessage: string;
errorCode: string;
};
@@ -1,7 +1,5 @@
export const SERVICE_NAMES = ["bundler", "rpc", "storage"] as const;
export const SERVICES: Service[] = [
{
export const SERVICE_DEFINITIONS = {
storage: {
name: "storage",
title: "Storage",
description: "IPFS Upload and Download",
@@ -18,33 +16,46 @@ export const SERVICES: Service[] = [
},
],
},
{
rpc: {
name: "rpc",
title: "RPC",
description: "Accelerated RPC Edge",
// all actions allowed
actions: [],
},
{
bundler: {
name: "bundler",
title: "Smart Wallets",
description: "Bundler & Paymaster services",
// all actions allowed
actions: [],
},
];
relayer: {
name: "relayer",
title: "Gasless Relayer",
description: "Enable gasless transactions",
// all actions allowed
actions: [],
},
} as const;
export const SERVICE_NAMES = Object.keys(
SERVICE_DEFINITIONS,
) as (keyof typeof SERVICE_DEFINITIONS)[];
export const SERVICES = Object.values(SERVICE_DEFINITIONS);
export type ServiceName = (typeof SERVICE_NAMES)[number];
export interface ServiceAction {
export type ServiceAction = {
name: string;
title: string;
description?: string;
}
};
export interface Service {
name: ServiceName;
title: string;
description?: string;
actions: ServiceAction[];
export type Service =
(typeof SERVICE_DEFINITIONS)[keyof typeof SERVICE_DEFINITIONS];
export function getServiceByName(name: ServiceName) {
return SERVICE_DEFINITIONS[name];
}
+6
View File
@@ -0,0 +1,6 @@
export type CoreAuthInput = {
// for passing it from the subdomain or path or other service specific things
clientId?: string;
// for passing in the address target in RPC or bundler services
targetAddress?: string | string[];
};
+2 -8
View File
@@ -1,8 +1,2 @@
import { SERVICES } from "./types";
export function getServiceByName(name: string) {
return SERVICES.find((srv) => srv.name === name);
}
export * from "./types";
export * from "./auth";
// only exports the public service definitions
export * from "./core/services";
+137
View File
@@ -0,0 +1,137 @@
import type { IncomingHttpHeaders, IncomingMessage } from "node:http";
import { createHash } from "node:crypto";
import type { AuthorizationInput } from "../core/authorize";
import type { CoreServiceConfig } from "../core/api";
import { authorize } from "../core/authorize";
import type { AuthorizationResult } from "../core/authorize/types";
import type { CoreAuthInput } from "../core/types";
export * from "../core/services";
type NodeServiceConfig = CoreServiceConfig;
export type AuthInput = CoreAuthInput & {
req: IncomingMessage;
};
export async function authorizeNode(
authInput: AuthInput,
serviceConfig: NodeServiceConfig,
): Promise<AuthorizationResult> {
let authData;
try {
authData = extractAuthorizationData(authInput);
} catch (e) {
if (e instanceof Error && e.message === "KEY_CONFLICT") {
return {
authorized: false,
status: 400,
errorMessage: "Please pass either a client id or a secret key.",
errorCode: "KEY_CONFLICT",
};
}
return {
authorized: false,
status: 500,
errorMessage: "Internal Server Error",
errorCode: "INTERNAL_SERVER_ERROR",
};
}
return await authorize(authData, serviceConfig);
}
function getHeader(
headers: IncomingHttpHeaders,
headerName: string,
): string | null {
const header = headers[headerName];
if (Array.isArray(header)) {
return header[0];
}
return header ?? null;
}
export function extractAuthorizationData(
authInput: AuthInput,
): AuthorizationInput {
let requestUrl;
try {
requestUrl = new URL(
authInput.req.url || "",
`http://${authInput.req.headers.host}`,
);
} catch (error) {
console.log("** Node URL Error **", error);
throw error;
}
const headers = authInput.req.headers;
const secretKey = getHeader(headers, "x-secret-key");
// prefer clientId that is explicitly passed in
let clientId = authInput.clientId ?? null;
if (!clientId) {
// next preference is clientId from header
clientId = getHeader(headers, "x-client-id");
}
// next preference is search param
if (!clientId) {
clientId = requestUrl.searchParams.get("clientId");
}
// bundle id from header is first preference
let bundleId = getHeader(headers, "x-bundle-id");
// next preference is search param
if (!bundleId) {
bundleId = requestUrl.searchParams.get("bundleId");
}
let origin = getHeader(headers, "origin");
// if origin header is not available we'll fall back to referrer;
if (!origin) {
origin = getHeader(headers, "referer");
}
// if we have an origin at this point, normalize it
if (origin) {
try {
origin = new URL(origin).hostname;
} catch (e) {
console.warn("failed to parse origin", origin, e);
}
}
// handle if we a secret key is passed in the headers
let secretKeyHash: string | null = null;
if (secretKey) {
// hash the secret key
secretKeyHash = hashSecretKey(secretKey);
// derive the client id from the secret key hash
const derivedClientId = deriveClientIdFromSecretKeyHash(secretKeyHash);
// if we already have a client id passed in we need to make sure they match
if (clientId && clientId !== derivedClientId) {
throw new Error("KEY_CONFLICT");
}
// otherwise set the client id to the derived client id (client id based off of secret key)
clientId = derivedClientId;
}
return {
secretKeyHash,
secretKey,
clientId,
origin,
bundleId,
targetAddress: authInput.targetAddress,
};
}
export function hashSecretKey(secretKey: string) {
return createHash("sha256").update(secretKey).digest("hex");
}
export function deriveClientIdFromSecretKeyHash(secretKeyHash: string) {
return secretKeyHash.slice(0, 32);
}
+9
View File
@@ -1,5 +1,14 @@
# @thirdweb-dev/unity-js-bridge
## 0.2.53
### Patch Changes
- 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
- @thirdweb-dev/auth@3.2.16
## 0.2.52
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.2.52",
"version": "0.2.53",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",
+11
View File
@@ -1,5 +1,16 @@
# @thirdweb-dev/wallets
## 1.0.12
### Patch Changes
- [#1352](https://github.com/thirdweb-dev/js/pull/1352) [`c5761b99`](https://github.com/thirdweb-dev/js/commit/c5761b99e9797772481506e90cbfa5c35a05bd1d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Switch to seed based local wallets for faster encryption
- [#1350](https://github.com/thirdweb-dev/js/pull/1350) [`b96a2282`](https://github.com/thirdweb-dev/js/commit/b96a2282730582b684cc96802649a96851af5220) Thanks [@MananTank](https://github.com/MananTank)! - Improved Injected Metamask detection - Do not consider Phantom provider as MetaMask
- Updated dependencies [[`dac8fa7d`](https://github.com/thirdweb-dev/js/commit/dac8fa7d98b6952acf8d13e173099889c1d47da8)]:
- @thirdweb-dev/sdk@3.10.36
## 1.0.11
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "1.0.11",
"version": "1.0.12",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"types": "dist/thirdweb-dev-wallets.cjs.d.ts",
@@ -0,0 +1,67 @@
import { Ethereum } from "../injected/types";
import { assertWindowEthereum } from "../../utils/assertWindowEthereum";
export function getInjectedMetamaskProvider(): Ethereum | undefined {
if (typeof window === "undefined") {
return;
}
function getReady(ethereum?: Ethereum): Ethereum | undefined {
const isMetaMask = !!ethereum?.isMetaMask;
if (!isMetaMask) {
return;
}
// Brave tries to make itself look like MetaMask
// Could also try RPC `web3_clientVersion` if following is unreliable
if (ethereum.isBraveWallet && !ethereum._events && !ethereum._state) {
return;
}
if (ethereum.isPhantom) {
return;
}
if (ethereum.isAvalanche) {
return;
}
if (ethereum.isBitKeep) {
return;
}
if (ethereum.isMathWallet) {
return;
}
if (ethereum.isZerion) {
return;
}
if (ethereum.isKuCoinWallet) {
return;
}
if (ethereum.isPortal) {
return;
}
if (ethereum.isTokenPocket) {
return;
}
if (ethereum.isTokenary) {
return;
}
return ethereum;
}
if (assertWindowEthereum(globalThis.window)) {
if (globalThis.window.ethereum?.providers) {
return globalThis.window.ethereum.providers.find(getReady);
}
return getReady(globalThis.window.ethereum);
}
}
@@ -5,12 +5,11 @@ import {
RpcError,
UserRejectedRequestError,
} from "../../../lib/wagmi-core/errors";
import { assertWindowEthereum } from "../../utils/assertWindowEthereum";
import { walletIds } from "../../constants/walletIds";
import { InjectedConnector, InjectedConnectorOptions } from "../injected";
import { Ethereum } from "../injected/types";
import type { Chain } from "@thirdweb-dev/chains";
import { utils } from "ethers";
import { getInjectedMetamaskProvider } from "./getInjectedMetamaskProvider";
export type MetaMaskConnectorOptions = Pick<
InjectedConnectorOptions,
@@ -37,46 +36,7 @@ export class MetaMaskConnector extends InjectedConnector {
name: "MetaMask",
shimDisconnect: true,
shimChainChangedDisconnect: true,
getProvider() {
function getReady(ethereum?: Ethereum) {
const isMetaMask = !!ethereum?.isMetaMask;
if (!isMetaMask) {
return;
}
// Brave tries to make itself look like MetaMask
// Could also try RPC `web3_clientVersion` if following is unreliable
if (ethereum.isBraveWallet && !ethereum._events && !ethereum._state) {
return;
}
if (ethereum.isAvalanche) {
return;
}
if (ethereum.isKuCoinWallet) {
return;
}
if (ethereum.isPortal) {
return;
}
if (ethereum.isTokenPocket) {
return;
}
if (ethereum.isTokenary) {
return;
}
return ethereum;
}
if (typeof window === "undefined") {
return;
}
if (assertWindowEthereum(globalThis.window)) {
if (globalThis.window.ethereum?.providers) {
return globalThis.window.ethereum.providers.find(getReady);
}
return getReady(globalThis.window.ethereum);
}
},
getProvider: getInjectedMetamaskProvider,
};
const options = {
+1
View File
@@ -44,3 +44,4 @@ export type { Chain } from "@thirdweb-dev/chains";
// export the window ethereum util
export { assertWindowEthereum } from "./utils/assertWindowEthereum";
export { getInjectedMetamaskProvider } from "./connectors/metamask/getInjectedMetamaskProvider";
@@ -94,7 +94,8 @@ export class LocalWallet extends AbstractClientWallet<
if (this.ethersWallet) {
throw new Error("wallet is already initialized");
}
this.ethersWallet = Wallet.createRandom();
const random = utils.randomBytes(32);
this.ethersWallet = new Wallet(random);
return this.ethersWallet.address;
}
+2 -7
View File
@@ -1,11 +1,11 @@
import type { WalletConnectConnector as WalletConnectConnectorType } from "../connectors/wallet-connect";
import type { QRModalOptions } from "../connectors/wallet-connect/qrModalOptions";
import { Connector, WagmiAdapter } from "../interfaces/connector";
import { assertWindowEthereum } from "../utils/assertWindowEthereum";
import { AbstractClientWallet, WalletOptions } from "./base";
import type { MetaMaskConnector as MetamaskConnectorType } from "../connectors/metamask";
import { walletIds } from "../constants/walletIds";
import { TW_WC_PROJECT_ID } from "../constants/wc";
import { getInjectedMetamaskProvider } from "../connectors/metamask/getInjectedMetamaskProvider";
type MetamaskAdditionalOptions = {
/**
@@ -63,12 +63,7 @@ export class MetaMaskWallet extends AbstractClientWallet<MetamaskAdditionalOptio
constructor(options: MetamaskWalletOptions) {
super(MetaMaskWallet.id, options);
if (assertWindowEthereum(globalThis.window)) {
this.isInjected = !!globalThis.window.ethereum?.isMetaMask;
} else {
this.isInjected = false;
}
this.isInjected = !!getInjectedMetamaskProvider();
}
protected async getConnector(): Promise<Connector> {
+269 -291
View File
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
cross-fetch@>=3.0.0 <3.1.5: '>=3.1.5'
got@<11.8.5: '>=11.8.5'
@@ -156,7 +160,7 @@ importers:
version: link:../eslint-config-thirdweb
eslint-plugin-import:
specifier: ^2.26.0
version: 2.27.5(@typescript-eslint/[email protected])(eslint[email protected])(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/[email protected])([email protected])
eslint-plugin-inclusive-language:
specifier: ^2.2.0
version: 2.2.0
@@ -219,7 +223,7 @@ importers:
version: link:../eslint-config-thirdweb
jest:
specifier: ^29.4.3
version: 29.5.0(@types/[email protected])([email protected])
version: 29.5.0(@types/[email protected])
plop:
specifier: ^3.1.2
version: 3.1.2
@@ -600,7 +604,7 @@ importers:
version: 0.0.3([email protected])
eslint-plugin-import:
specifier: ^2.26.0
version: 2.27.5(@typescript-eslint/[email protected])(eslint[email protected])(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/[email protected])([email protected])
eslint-plugin-inclusive-language:
specifier: ^2.2.0
version: 2.2.0
@@ -724,7 +728,7 @@ importers:
version: 0.0.3([email protected])
eslint-plugin-import:
specifier: ^2.26.0
version: 2.27.5(@typescript-eslint/[email protected])(eslint[email protected])(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/[email protected])([email protected])
eslint-plugin-inclusive-language:
specifier: ^2.2.0
version: 2.2.0
@@ -864,7 +868,7 @@ importers:
version: link:../eslint-config-thirdweb
eslint-plugin-import:
specifier: ^2.26.0
version: 2.27.5(@typescript-eslint/[email protected])(eslint[email protected])(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/[email protected])([email protected])
eslint-plugin-inclusive-language:
specifier: ^2.2.0
version: 2.2.0
@@ -879,7 +883,7 @@ importers:
version: 47.0.14(@babel/[email protected])
jest:
specifier: ^29.4.3
version: 29.5.0(@types/[email protected])([email protected])
version: 29.5.0(@types/[email protected])
prettier:
specifier: ^2.8.8
version: 2.8.8
@@ -1085,7 +1089,7 @@ importers:
version: 0.0.3([email protected])
eslint-plugin-import:
specifier: ^2.26.0
version: 2.27.5(@typescript-eslint/[email protected])(eslint[email protected])(eslint@8.43.0)
version: 2.27.5(@typescript-eslint/[email protected])([email protected])
eslint-plugin-inclusive-language:
specifier: ^2.2.0
version: 2.2.0
@@ -1126,11 +1130,14 @@ importers:
specifier: ^4.20230710.0
version: 4.20230710.0
'@preconstruct/cli':
specifier: ^2.7.0
version: 2.7.0
specifier: ^2.8.1
version: 2.8.1
'@thirdweb-dev/tsconfig':
specifier: workspace:*
version: link:../tw-tsconfig
'@types/jest':
specifier: ^29.5.2
version: 29.5.2
'@types/node':
specifier: ^20.4.1
version: 20.4.1
@@ -1149,18 +1156,12 @@ importers:
eslint-config-thirdweb:
specifier: workspace:*
version: link:../eslint-config-thirdweb
lint-staged:
specifier: ^13.2.3
version: 13.2.3
jest:
specifier: ^29.4.3
version: 29.5.0(@types/[email protected])
prettier:
specifier: ^3.0.0
version: 3.0.0
sort-package-json:
specifier: ^2.5.1
version: 2.5.1
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/[email protected])([email protected])
typescript:
specifier: ^5.1.6
version: 5.1.6
@@ -2756,16 +2757,6 @@ packages:
'@babel/core': 7.22.5
'@babel/helper-plugin-utils': 7.22.5
/@babel/[email protected](@babel/[email protected]):
resolution: {integrity: sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==}
engines: {node: '>=6.9.0'}
peerDependencies:
'@babel/core': ^7.0.0-0
dependencies:
'@babel/core': 7.22.5
'@babel/helper-plugin-utils': 7.22.5
dev: true
/@babel/[email protected](@babel/[email protected]):
resolution: {integrity: sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==}
engines: {node: '>=6.9.0'}
@@ -7281,6 +7272,52 @@ packages:
- supports-color
dev: true
/@preconstruct/[email protected]:
resolution: {integrity: sha512-PX5w+au06iY/QaT+9RLmRlIfavRCRoMTC/krwtNrgPEnubR9e6P+QlywrKmwiEvkzbR9AEzGnRZL8uNRDDMzrQ==}
hasBin: true
dependencies:
'@babel/code-frame': 7.22.5
'@babel/core': 7.22.5
'@babel/helper-module-imports': 7.22.5
'@babel/runtime': 7.22.5
'@preconstruct/hook': 0.4.0
'@rollup/plugin-alias': 3.1.9([email protected])
'@rollup/plugin-commonjs': 15.1.0([email protected])
'@rollup/plugin-json': 4.1.0([email protected])
'@rollup/plugin-node-resolve': 11.2.1([email protected])
'@rollup/plugin-replace': 2.4.2([email protected])
builtin-modules: 3.3.0
chalk: 4.1.2
dataloader: 2.2.2
detect-indent: 6.1.0
enquirer: 2.3.6
estree-walker: 2.0.2
fast-deep-equal: 2.0.1
fast-glob: 3.2.12
fs-extra: 9.1.0
is-ci: 2.0.0
is-reference: 1.2.1
jest-worker: 26.6.2
magic-string: 0.30.0
meow: 7.1.1
ms: 2.1.3
normalize-path: 3.0.0
npm-packlist: 2.2.2
p-limit: 3.1.0
parse-glob: 3.0.4
parse-json: 5.2.0
quick-lru: 5.1.1
resolve: 1.22.1
resolve-from: 5.0.0
rollup: 2.79.1
semver: 7.5.3
terser: 5.18.2
v8-compile-cache: 2.3.0
zod: 3.21.4
transitivePeerDependencies:
- supports-color
dev: true
/@preconstruct/[email protected]:
resolution: {integrity: sha512-a7mrlPTM3tAFJyz43qb4pPVpUx8j8TzZBFsNFqcKcE/sEakNXRlQAuCT4RGZRf9dQiiUnBahzSIWawU4rENl+Q==}
dependencies:
@@ -11037,6 +11074,7 @@ packages:
typescript: 5.1.6
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/[email protected]([email protected])([email protected]):
resolution: {integrity: sha512-pHWlc3alg2oSMGwsU/Is8hbm3XFbcrb6P5wIxcQW9NsYBfnrubl/GhVVD/Jm/t8HXhA2WncoIRfBtnCgRGV96Q==}
@@ -12148,13 +12186,6 @@ packages:
dependencies:
acorn: 8.10.0
/[email protected]([email protected]):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.8.2
/[email protected]:
resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==}
dependencies:
@@ -12647,11 +12678,6 @@ packages:
resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==}
engines: {node: '>=4'}
/[email protected]:
resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
engines: {node: '>=8'}
dev: true
/[email protected]:
resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==}
@@ -14049,22 +14075,6 @@ packages:
resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==}
engines: {node: '>=6'}
/[email protected]:
resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
engines: {node: '>=8'}
dependencies:
slice-ansi: 3.0.0
string-width: 4.2.3
dev: true
/[email protected]:
resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
slice-ansi: 5.0.0
string-width: 5.1.2
dev: true
/[email protected]:
resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==}
engines: {node: '>= 10'}
@@ -14223,11 +14233,6 @@ packages:
typical: 5.2.0
dev: true
/[email protected]:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'}
dev: true
/[email protected]:
resolution: {integrity: sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==}
@@ -15172,20 +15177,10 @@ packages:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
/[email protected]:
resolution: {integrity: sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==}
engines: {node: '>=12.20'}
dev: true
/[email protected]:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'}
/[email protected]:
resolution: {integrity: sha512-1aXUEPdfGdzVPFpzGJJNgq9o81bGg1s09uxTWsqBlo9PI332uyJRQq13+LK/UN4JfxJbFdCXonUFQ9R/p7yCtw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/[email protected]:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
dev: false
@@ -16019,7 +16014,7 @@ packages:
eslint: 8.44.0
eslint-import-resolver-node: 0.3.7
eslint-import-resolver-typescript: 3.5.3([email protected])([email protected])
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]3.0)
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]4.0)
eslint-plugin-jsx-a11y: 6.7.1([email protected])
eslint-plugin-react: 7.32.2([email protected])
eslint-plugin-react-hooks: 4.6.0([email protected])
@@ -16090,7 +16085,7 @@ packages:
confusing-browser-globals: 1.0.11
eslint: 8.44.0
eslint-plugin-flowtype: 8.0.3(@babel/[email protected])(@babel/[email protected])([email protected])
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]3.0)
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]4.0)
eslint-plugin-jest: 25.7.0(@typescript-eslint/[email protected])([email protected])([email protected])([email protected])
eslint-plugin-jsx-a11y: 6.7.1([email protected])
eslint-plugin-react: 7.32.2([email protected])
@@ -16142,6 +16137,7 @@ packages:
synckit: 0.8.5
transitivePeerDependencies:
- supports-color
dev: true
/[email protected]([email protected])([email protected]):
resolution: {integrity: sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==}
@@ -16153,7 +16149,7 @@ packages:
debug: 4.3.4([email protected])
enhanced-resolve: 5.12.0
eslint: 8.44.0
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]3.0)
eslint-plugin-import: 2.27.5(@typescript-eslint/[email protected])([email protected])([email protected]4.0)
get-tsconfig: 4.4.0
globby: 13.1.3
is-core-module: 2.11.0
@@ -16191,6 +16187,37 @@ packages:
eslint-import-resolver-typescript: 3.5.3([email protected])([email protected])
transitivePeerDependencies:
- supports-color
dev: true
/[email protected](@typescript-eslint/[email protected])([email protected])([email protected])([email protected]):
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint:
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.60.1([email protected])([email protected])
debug: 3.2.7
eslint: 8.44.0
eslint-import-resolver-node: 0.3.7
eslint-import-resolver-typescript: 3.5.3([email protected])([email protected])
transitivePeerDependencies:
- supports-color
dev: false
/[email protected]([email protected]):
resolution: {integrity: sha512-U5OjauLSVcXvlh2La3ptPwIs6JwLPJKP20OQdTDBe2oh0cHvBeEwhQ8mjFrEoCMdQdmMdrSBkSRLG3gLxFjK3A==}
@@ -16278,6 +16305,73 @@ packages:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/[email protected](@typescript-eslint/[email protected])([email protected])([email protected]):
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.60.1([email protected])([email protected])
array-includes: 3.1.6
array.prototype.flat: 1.3.1
array.prototype.flatmap: 1.3.1
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.44.0
eslint-import-resolver-node: 0.3.7
eslint-module-utils: 2.7.4(@typescript-eslint/[email protected])([email protected])([email protected])([email protected])
has: 1.0.3
is-core-module: 2.11.0
is-glob: 4.0.3
minimatch: 3.1.2
object.values: 1.1.6
resolve: 1.22.1
semver: 7.5.3
tsconfig-paths: 3.14.2
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: false
/[email protected](@typescript-eslint/[email protected])([email protected]):
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.60.1([email protected])([email protected])
array-includes: 3.1.6
array.prototype.flat: 1.3.1
array.prototype.flatmap: 1.3.1
debug: 3.2.7
doctrine: 2.1.0
eslint: 8.43.0
eslint-import-resolver-node: 0.3.7
eslint-module-utils: 2.7.4(@typescript-eslint/[email protected])([email protected])([email protected])([email protected])
has: 1.0.3
is-core-module: 2.11.0
is-glob: 4.0.3
minimatch: 3.1.2
object.values: 1.1.6
resolve: 1.22.1
semver: 7.5.3
tsconfig-paths: 3.14.2
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
dev: true
/[email protected]:
resolution: {integrity: sha512-RzPeSjuw1NYiTSQyFzYl2uTDgiPQWDUmFCiGAMCITmXN627DsWZ9rR4KNzrb8vnk/gLL5qdYr8oxh44xsrcO5Q==}
@@ -16323,7 +16417,7 @@ packages:
'@typescript-eslint/eslint-plugin': 5.60.1(@typescript-eslint/[email protected])([email protected])([email protected])
'@typescript-eslint/utils': 5.60.1([email protected])([email protected])
eslint: 8.43.0
jest: 29.5.0(@types/[email protected])([email protected])
jest: 29.5.0(@types/[email protected])
transitivePeerDependencies:
- supports-color
- typescript
@@ -16647,8 +16741,8 @@ packages:
resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 8.8.2
acorn-jsx: 5.3.2(acorn@8.8.2)
acorn: 8.10.0
acorn-jsx: 5.3.2(acorn@8.10.0)
eslint-visitor-keys: 3.4.1
/[email protected]:
@@ -16967,21 +17061,6 @@ packages:
signal-exit: 3.0.7
strip-final-newline: 2.0.0
/[email protected]:
resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==}
engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0}
dependencies:
cross-spawn: 7.0.3
get-stream: 6.0.1
human-signals: 4.3.1
is-stream: 3.0.0
merge-stream: 2.0.0
npm-run-path: 5.1.0
onetime: 6.0.0
signal-exit: 3.0.7
strip-final-newline: 3.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==}
dev: true
@@ -17875,11 +17954,6 @@ packages:
resolution: {integrity: sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==}
engines: {node: '>=4'}
/[email protected]:
resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
engines: {node: '>=6'}
@@ -17915,10 +17989,6 @@ packages:
resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==}
engines: {node: '>=6'}
/[email protected]:
resolution: {integrity: sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==}
dev: true
/[email protected]:
resolution: {integrity: sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==}
engines: {node: '>=0.10.0'}
@@ -18612,11 +18682,6 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
/[email protected]:
resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==}
engines: {node: '>=14.18.0'}
dev: true
/[email protected]:
resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
dependencies:
@@ -18977,11 +19042,6 @@ packages:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
/[email protected]:
resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==}
dev: false
@@ -19105,11 +19165,6 @@ packages:
engines: {node: '>=10'}
dev: false
/[email protected]:
resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
@@ -19175,11 +19230,6 @@ packages:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
/[email protected]:
resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dev: true
/[email protected]:
resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
engines: {node: '>= 0.4'}
@@ -19523,6 +19573,34 @@ packages:
- utf-8-validate
dev: false
/[email protected](@types/[email protected]):
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.5.0([email protected])
'@jest/test-result': 29.5.0
'@jest/types': 29.5.0
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
import-local: 3.1.0
jest-config: 29.5.0(@types/[email protected])([email protected])
jest-util: 29.5.0
jest-validate: 29.5.0
prompts: 2.4.2
yargs: 17.7.2
transitivePeerDependencies:
- '@types/node'
- supports-color
- ts-node
dev: true
/[email protected](@types/[email protected])([email protected]):
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -19551,6 +19629,34 @@ packages:
- ts-node
dev: true
/[email protected](@types/[email protected]):
resolution: {integrity: sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.5.0([email protected])
'@jest/test-result': 29.5.0
'@jest/types': 29.5.0
chalk: 4.1.2
exit: 0.1.2
graceful-fs: 4.2.11
import-local: 3.1.0
jest-config: 29.5.0(@types/[email protected])([email protected])
jest-util: 29.5.0
jest-validate: 29.5.0
prompts: 2.4.2
yargs: 17.7.2
transitivePeerDependencies:
- '@types/node'
- supports-color
- ts-node
dev: true
/[email protected]:
resolution: {integrity: sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
@@ -20197,7 +20303,7 @@ packages:
'@babel/core': 7.22.5
'@babel/generator': 7.22.5
'@babel/plugin-syntax-jsx': 7.22.5(@babel/[email protected])
'@babel/plugin-syntax-typescript': 7.20.0(@babel/[email protected])
'@babel/plugin-syntax-typescript': 7.22.5(@babel/[email protected])
'@babel/traverse': 7.22.5
'@babel/types': 7.22.5
'@jest/expect-utils': 29.5.0
@@ -20403,6 +20509,26 @@ packages:
- utf-8-validate
dev: false
/[email protected](@types/[email protected]):
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.5.0([email protected])
'@jest/types': 29.5.0
import-local: 3.1.0
jest-cli: 29.5.0(@types/[email protected])
transitivePeerDependencies:
- '@types/node'
- supports-color
- ts-node
dev: true
/[email protected](@types/[email protected])([email protected]):
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -20423,6 +20549,26 @@ packages:
- ts-node
dev: true
/[email protected](@types/[email protected]):
resolution: {integrity: sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
hasBin: true
peerDependencies:
node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
peerDependenciesMeta:
node-notifier:
optional: true
dependencies:
'@jest/core': 29.5.0([email protected])
'@jest/types': 29.5.0
import-local: 3.1.0
jest-cli: 29.5.0(@types/[email protected])
transitivePeerDependencies:
- '@types/node'
- supports-color
- ts-node
dev: true
/[email protected]:
resolution: {integrity: sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==}
@@ -20859,48 +21005,6 @@ packages:
/[email protected]:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
/[email protected]:
resolution: {integrity: sha512-zVVEXLuQIhr1Y7R7YAWx4TZLdvuzk7DnmrsTNL0fax6Z3jrpFcas+vKbzxhhvp6TA55m1SQuWkpzI1qbfDZbAg==}
engines: {node: ^14.13.1 || >=16.0.0}
hasBin: true
dependencies:
chalk: 5.2.0
cli-truncate: 3.1.0
commander: 10.0.1
debug: 4.3.4([email protected])
execa: 7.1.1
lilconfig: 2.1.0
listr2: 5.0.8
micromatch: 4.0.5
normalize-path: 3.0.0
object-inspect: 1.12.3
pidtree: 0.6.0
string-argv: 0.3.1
yaml: 2.3.1
transitivePeerDependencies:
- enquirer
- supports-color
dev: true
/[email protected]:
resolution: {integrity: sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==}
engines: {node: ^14.13.1 || >=16.0.0}
peerDependencies:
enquirer: '>= 2.3.0 < 3'
peerDependenciesMeta:
enquirer:
optional: true
dependencies:
cli-truncate: 2.1.0
colorette: 2.0.19
log-update: 4.0.0
p-map: 4.0.0
rfdc: 1.3.0
rxjs: 7.8.0
through: 2.3.8
wrap-ansi: 7.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-6ZgxBR9KNroqKb6+htkyBwD90XGRiqKDHVrW/Eh0EZ+l+iC+u+v+w3/BA5NGi4nizAVHGYvQBHUDuSmLjPp7NQ==}
dependencies:
@@ -21103,16 +21207,6 @@ packages:
is-unicode-supported: 1.3.0
dev: true
/[email protected]:
resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
engines: {node: '>=10'}
dependencies:
ansi-escapes: 4.3.2
cli-cursor: 3.1.0
slice-ansi: 4.0.0
wrap-ansi: 6.2.0
dev: true
/[email protected]:
resolution: {integrity: sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ==}
hasBin: true
@@ -21809,11 +21903,6 @@ packages:
resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
engines: {node: '>=6'}
/[email protected]:
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
@@ -22477,13 +22566,6 @@ packages:
dependencies:
path-key: 3.1.1
/[email protected]:
resolution: {integrity: sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
dependencies:
path-key: 4.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
dependencies:
@@ -22731,13 +22813,6 @@ packages:
dependencies:
mimic-fn: 2.1.0
/[email protected]:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
dependencies:
mimic-fn: 4.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==}
engines: {node: '>=8'}
@@ -23146,11 +23221,6 @@ packages:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
/[email protected]:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@@ -23212,12 +23282,6 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
/[email protected]:
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
engines: {node: '>=0.10'}
hasBin: true
dev: true
/[email protected]:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
@@ -25424,10 +25488,6 @@ packages:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
/[email protected]:
resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
dev: true
/[email protected]:
resolution: {integrity: sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==}
hasBin: true
@@ -25965,32 +26025,6 @@ packages:
astral-regex: 1.0.0
is-fullwidth-code-point: 2.0.0
/[email protected]:
resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
engines: {node: '>=8'}
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
astral-regex: 2.0.0
is-fullwidth-code-point: 3.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
engines: {node: '>=12'}
dependencies:
ansi-styles: 6.2.1
is-fullwidth-code-point: 4.0.0
dev: true
/[email protected]:
resolution: {integrity: sha512-8mo9bslnBO3tr5PEVFzMPIWwWnipGS0xVbYf65zxDqfNwmzYn1LpiKNrR6DlClusuvo+hDHd1zKpmfAe83NQSQ==}
engines: {node: '>=8.0.0'}
@@ -26146,23 +26180,6 @@ packages:
lodash: 4.17.21
dev: true
/[email protected]:
resolution: {integrity: sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==}
dev: true
/[email protected]:
resolution: {integrity: sha512-vx/KoZxm8YNMUqdlw7SGTfqR5pqZ/sUfgOuRtDILiOy/3AvzhAibyUe2cY3OpLs3oRSow9up4yLVtQaM24rbDQ==}
hasBin: true
dependencies:
detect-indent: 7.0.1
detect-newline: 4.0.0
get-stdin: 9.0.0
git-hooks-list: 3.1.0
globby: 13.1.3
is-plain-obj: 4.1.0
sort-object-keys: 1.1.3
dev: true
/[email protected]:
resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==}
dev: false
@@ -26596,11 +26613,6 @@ packages:
resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
engines: {node: '>=6'}
/[email protected]:
resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==}
engines: {node: '>=12'}
dev: true
/[email protected]:
resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==}
engines: {node: '>=6.5.0', npm: '>=3'}
@@ -27278,37 +27290,6 @@ packages:
yn: 3.1.1
dev: true
/[email protected](@types/[email protected])([email protected]):
resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
hasBin: true
peerDependencies:
'@swc/core': '>=1.2.50'
'@swc/wasm': '>=1.2.50'
'@types/node': '*'
typescript: '>=2.7'
peerDependenciesMeta:
'@swc/core':
optional: true
'@swc/wasm':
optional: true
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.9
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.3
'@types/node': 20.4.1
acorn: 8.8.2
acorn-walk: 8.2.0
arg: 4.1.3
create-require: 1.1.1
diff: 4.0.2
make-error: 1.3.6
typescript: 5.1.6
v8-compile-cache-lib: 3.0.1
yn: 3.1.1
dev: true
/[email protected]:
resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==}
dependencies:
@@ -29131,6 +29112,7 @@ packages:
/[email protected]:
resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
engines: {node: '>= 14'}
dev: false
/[email protected]:
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
@@ -29269,7 +29251,3 @@ packages:
version: 5.4.7
engines: {node: '>=0.11'}
dev: true
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
+4
View File
@@ -60,6 +60,10 @@
"inputs": ["package.json"],
"dependsOn": ["^build"]
},
"@thirdweb-dev/service-utils#build": {
"outputs": ["dist/**", "cf-worker/**", "node/**"],
"dependsOn": ["^build"]
},
"test": {
"outputs": [],
"inputs": ["src/**", "test/**"],