Compare commits

...
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c578a437cc Version Packages (#1234)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-26 18:42:04 -07:00
Danny FridayandGitHub 0c5b03b8d6 Remove ipfs-2 gateway (#1246) 2023-06-27 00:31:06 +00:00
nkrishangandGitHub 9af346eead [SDK][React] SmartWalletFactory: use getAllAccounts instead of event logs of AccountCreated to get accounts of a factory (#1241) 2023-06-26 17:51:22 +00:00
iketwandGitHub d9fb134ad4 [RN] better design for custom details button (#1245) 2023-06-26 15:25:19 +00:00
Mariano FuentesandGitHub 1c7264b403 Fix install bug (#1240) 2023-06-24 00:59:52 +00:00
Joaquim VergesandGitHub a140ee99b2 add zora extension in auto docs (#1239) 2023-06-24 00:23:07 +00:00
iketwandGitHub 6e1fe6e582 [React] Add Rainbow and Trust wallets connection hooks (#1238) 2023-06-23 23:06:59 +00:00
iketwandGitHub 536b0f1240 [React] Add Rainbow Wallet (#1237) 2023-06-23 22:11:40 +00:00
b626782b0e [React/Wallets] Add Trust Wallet (#1236)
Co-authored-by: Manan Tank <[email protected]>
2023-06-23 21:23:13 +00:00
Nacho IacovinoandGitHub 1d76334dd3 [React] Fix required type for address on useSmartWalletsForAddress (#1235) 2023-06-23 18:44:00 +00:00
nkrishangandGitHub d498c79a91 [SDK] Fix smartWalletFactory.getAllWallets (#1233) 2023-06-23 18:20:03 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
736b45ac8e Version Packages (#1211)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-23 10:33:33 -07:00
Nacho IacovinoandGitHub b5e1d3bb2b [React] Add useSmartWalletsForAddress hook (#1230) 2023-06-23 12:00:37 +00:00
Jonas DanielsandGitHub 6816219ac1 [chains] - add/update chains (#1229) 2023-06-22 23:57:03 +00:00
Nacho IacovinoandGitHub 48065bcd91 [SDK] Accept string in shared metadata (#1222) 2023-06-22 23:39:34 +00:00
Manan TankandGitHub a388d07a3d Add Magic Connect support (#1226) 2023-06-22 20:28:04 +00:00
Nacho IacovinoandGitHub 483e2b9109 [SDK] Fix namespace for platformFees (#1225) 2023-06-22 19:24:04 +00:00
Nacho IacovinoandGitHub f7f4f20737 [React + SDK] Better return type for get shared metadata (#1224) 2023-06-22 18:46:57 +00:00
Joaquim VergesandGitHub 6aa6f7e0bd [SDK] fix maxId in getAll for Open Edition contracts (#1223) 2023-06-22 03:42:24 +00:00
d4d9550713 [React + SDK] Add get shared metadata (#1218)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-22 01:56:48 +00:00
iketwandGitHub 3cb298ac4b [RN/Wallets] Fix Coinbase Wallet connection rejection error (#1220) 2023-06-22 00:29:24 +00:00
Joaquim VergesandGitHub c747670b98 [SDK] Fix nextTokenIdToMint for open edition (#1219) 2023-06-22 00:08:55 +00:00
Joaquim VergesandGitHub c08e6ba988 [SDK] Fix claim counts for Open Edition contracts (#1216) 2023-06-21 23:49:27 +00:00
Manan TankandGitHub 60fb188943 [react] Fix safeWallet tree-shaking (#1212) 2023-06-21 20:17:13 +00:00
iketwandGitHub 1ce8558df4 [Wallets] Fix switchChain in WCV2 connector (#1214) 2023-06-21 16:28:16 +00:00
iketwandGitHub 3ce5f9a0c3 [RC/Wallets] Improve error messages for wc and auth (#1213) 2023-06-21 15:45:03 +00:00
3d615a62d0 [SDK] Code abstraction; import/export updates (#1188)
Co-authored-by: Manan Tank <[email protected]>
2023-06-21 14:40:12 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
6ce366f59e Version Packages (#1190)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-20 23:26:22 -07:00
8a2d92046a [SDK] update polygon gas station url (#1208)
Co-authored-by: Joaquim Verges <[email protected]>
2023-06-21 06:04:20 +00:00
YashandGitHub 45ae105ed3 [SDK] Minimal forwarders for ZKSync (#1191) 2023-06-21 05:53:53 +00:00
Jonas DanielsandGitHub 23d61cfeff [SDK] - open edition feature (#1193) 2023-06-21 02:33:58 +00:00
nkrishangandGitHub 990c665de9 Feature detection and SDK class for Smart Wallet. (#1134) 2023-06-20 23:46:01 +00:00
Joaquim VergesandGitHub 08eaefcf0b [SDK] shortcut getAllOwners for NFT drops to only check claimed (#1203) 2023-06-20 23:40:36 +00:00
Manan TankandGitHub 3d62278aba [wallets, react, react-core] Add eslint-plugin-better-tree-shaking (#1206) 2023-06-20 20:53:22 +00:00
iketwandGitHub 3ab7d1e975 [ReactNative] Export more components for easy development (#1205) 2023-06-20 19:19:21 +00:00
Manan TankandGitHub c6f44722f9 [sdk] Add eslint-plugin-better-tree-shaking (#1199) 2023-06-20 15:06:30 +00:00
Joaquim VergesandGitHub e0ce4a3759 [SDK] Zora claim extension (#1197) 2023-06-20 04:47:02 +00:00
iketwandGitHub 04416e7c93 [RN] Return connection Promise for better error handling (#1202) 2023-06-19 20:30:41 +00:00
Manan TankandGitHub 5166b24a48 [readme] Update install command for windows in contributing.md (#1200) 2023-06-19 17:29:33 +00:00
Manan TankandGitHub bb7ca20e49 [sdk] Better PURE annotations for tree-shaking (#1198) 2023-06-17 19:34:08 +00:00
Jonas DanielsandGitHub f41f1a2958 [chains] - fix arbitrum goerli (#1192) 2023-06-16 21:55:21 +00:00
Manan TankandGitHub d9b7360d1d [sdk] Refactor erc-721.ts, erc-1155.ts, erc-20.ts (#1196) 2023-06-16 21:36:38 +00:00
Manan TankandGitHub 8941b22682 [sdk] Add PURE annotations for improved tree-shaking (#1189) 2023-06-16 13:51:28 +00:00
github-actions[bot]andGitHub f61beace93 Version Packages (#1158) 2023-06-15 19:49:18 -07:00
Adam MajmudarandGitHub 08403dd9da Expose useSwitchAccount (#1187) 2023-06-16 00:35:25 +00:00
Nacho IacovinoandGitHub 36f3191f3e [React] Fix useIsSmartWalletDeployed cache (#1186) 2023-06-15 23:46:24 +00:00
YashandGitHub 7d2a446ece [SDK] Expose salt input for deployments (#1155) 2023-06-15 21:20:56 +00:00
ab575726fe [unity-js-bridge] add allChains to unity bridge wallet instantiation (#1176)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-15 18:20:02 +00:00
Jonas DanielsandGitHub 8e28b0f5e7 [chains] add zora mainnet (#1185) 2023-06-15 17:57:43 +00:00
Mariano FuentesandGitHub e7f1ce43b0 Detector typo fix (#1184) 2023-06-15 17:46:31 +00:00
Mariano FuentesandGitHub 224b7241dc Bugfix for python detectors (#1183) 2023-06-15 17:20:41 +00:00
iketwandGitHub a0eee749a2 Ike/demo (#1182) 2023-06-15 14:21:13 +00:00
iketwandGitHub 20bbad1abc [SDK] Switch warn to debug console message (#1181) 2023-06-15 12:53:15 +00:00
YashandGitHub a430160e6b [SDK] Util for deterministic direct deployments (#1162) 2023-06-14 23:56:58 +00:00
Mariano FuentesandGitHub 5745481584 Revert Checking for pip and pip3 (#1178) 2023-06-14 21:22:29 +00:00
Mariano FuentesandGitHub afdedb1feb [Install] - Handle pip and pip3 install automatically (#1177) 2023-06-14 20:30:58 +00:00
Manan TankandGitHub 01293857fa [sdk] Tree shaking improvements (#1175) 2023-06-14 17:25:02 +00:00
Nacho IacovinoandGitHub ecdcf82cf3 [React] Add password data-test (#1172) 2023-06-14 00:29:46 +00:00
12b07aad9a [SDK] Fix circular deps issue between metadata-resolver <-> core/sdk (#1167)
Co-authored-by: Joaquim Verges <[email protected]>
2023-06-14 00:20:01 +00:00
Mariano FuentesandGitHub c0e2c9457f Bug fixes for install (#1171) 2023-06-13 23:56:37 +00:00
654b8ab351 [REACT] Add Zerion Wallet (#1160)
Co-authored-by: iketw <[email protected]>
Co-authored-by: Manan Tank <[email protected]>
2023-06-13 17:02:26 +00:00
a5578abf66 [REACT] Reduce circular dependencies (#1164)
Co-authored-by: Joaquim Verges <[email protected]>
2023-06-13 10:37:30 +00:00
Nacho IacovinoandGitHub 541e488d5b [React] Add data-address to ConnectWallet (#1166) 2023-06-13 00:42:46 +00:00
Adam MajmudarandGitHub 088f2567f6 [Auth] Include chain id in login payload (#1165) 2023-06-13 00:29:31 +00:00
Nacho IacovinoandGitHub 6803e8ca09 [React] Add data-test to ConnectWallet (#1163) 2023-06-12 23:41:44 +00:00
Adam MajmudarandGitHub d60e544a24 [Auth] Update with refresh interval and active account (#1150) 2023-06-12 22:52:08 +00:00
cc20f93e17 Update Install Command (#1074)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-12 17:47:43 +00:00
329bccec4b [react, wallets] Add Frame wallet (#1000)
Co-authored-by: Jonas Daniels <[email protected]>
Co-authored-by: Manan Tank <[email protected]>
Co-authored-by: ikethirdweb <[email protected]>
2023-06-12 14:06:24 +00:00
02d55a063e fix: always use latest CLI version to prevent build failures in CI (#1154)
Co-authored-by: Jonas Daniels <[email protected]>
2023-06-09 19:09:23 +00:00
433 changed files with 17036 additions and 6414 deletions
+6
View File
@@ -59,9 +59,15 @@ To begin:
```
pnpm install
```
If you are on windows, use the `--ignore-scripts` flag
```
pnpm install --ignore-scripts
```
Now you have got the repo on your local machine, and you're ready to start making your changes!
<br/>
### Test Your Changes
We use [yalc](https://github.com/wclr/yalc) to test changes locally.
+1 -1
View File
@@ -43,7 +43,7 @@
"@playwright/test": "1.31.2",
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
"@types/node": "^18.15.11",
"eslint": "^8.37.0",
"eslint": "^8.42.0",
"mocha": "^10.2.0",
"prettier": "^2.8.7",
"turbo": "^1.9.8",
+34
View File
@@ -1,5 +1,39 @@
# @thirdweb-dev/auth
## 3.2.3
### Patch Changes
- Updated dependencies [[`536b0f12`](https://github.com/thirdweb-dev/js/commit/536b0f1240ab446aac22cf547a4e09e73ee6bf7b), [`b626782b`](https://github.com/thirdweb-dev/js/commit/b626782b0e8c6b76673472d3aee1c802dfb11b5f)]:
- @thirdweb-dev/wallets@0.3.3
## 3.2.2
### Patch Changes
- Updated dependencies [[`3cb298ac`](https://github.com/thirdweb-dev/js/commit/3cb298ac4b04d295899b5ac77c7fc5869ec2f5f2), [`3ce5f9a0`](https://github.com/thirdweb-dev/js/commit/3ce5f9a0c3fc7e99b5abf691a87048ab8475f6b1), [`a388d07a`](https://github.com/thirdweb-dev/js/commit/a388d07a3d449e56dc53fed9600931022f4a15e1), [`1ce8558d`](https://github.com/thirdweb-dev/js/commit/1ce8558df47186bcba5ee8564fdb04583bf115dd), [`60fb1889`](https://github.com/thirdweb-dev/js/commit/60fb18894372f14d9cd815fa9a239926d31bb273)]:
- @thirdweb-dev/wallets@0.3.2
## 3.2.1
### Patch Changes
- Updated dependencies [[`3d62278a`](https://github.com/thirdweb-dev/js/commit/3d62278aba79101ae1158fb726d6ddfed505c939)]:
- @thirdweb-dev/wallets@0.3.1
## 3.2.0
### Minor Changes
- [#1150](https://github.com/thirdweb-dev/js/pull/1150) [`d60e544a`](https://github.com/thirdweb-dev/js/commit/d60e544a240b93312743e62096ee2dc77d0c1bd1) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for multipled logged in accounts and token refreshing to auth
### Patch Changes
- [#1165](https://github.com/thirdweb-dev/js/pull/1165) [`088f2567`](https://github.com/thirdweb-dev/js/commit/088f2567f615360edd44776b20ae0bedff250f43) Thanks [@adam-maj](https://github.com/adam-maj)! - Include chain id in login payload
- Updated dependencies [[`654b8ab3`](https://github.com/thirdweb-dev/js/commit/654b8ab35184e02127a5a47f05d78606dd5b29ca), [`329bccec`](https://github.com/thirdweb-dev/js/commit/329bccec4b88b02db5bac6c1415158928843376a)]:
- @thirdweb-dev/wallets@0.3.0
## 3.1.1
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.1.1",
"version": "3.2.3",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
@@ -101,7 +101,7 @@
"@typescript-eslint/parser": "^5.33.0",
"chai": "^4.3.6",
"cookie-parser": "^1.4.6",
"eslint": "^8.21.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-thirdweb": "workspace:*",
"eslint-plugin-import": "^2.26.0",
+7
View File
@@ -0,0 +1,7 @@
const THIRDWEB_AUTH_COOKIE_PREFIX = `thirdweb_auth`;
export const THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX = `${THIRDWEB_AUTH_COOKIE_PREFIX}_token`;
export const THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE = `${THIRDWEB_AUTH_COOKIE_PREFIX}_active_account`;
export const THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS = 60 * 10;
export const THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS = 60 * 60 * 24;
export const THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS = 5;
+64 -26
View File
@@ -1,3 +1,7 @@
import {
THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
} from "../constants";
import {
LoginOptions,
LoginPayload,
@@ -15,6 +19,7 @@ import {
Json,
LoginOptionsSchema,
AuthenticationPayload,
AuthenticationPayloadDataInput,
} from "./schema";
import { isBrowser } from "./utils";
import type { GenericAuthWallet } from "@thirdweb-dev/wallets";
@@ -54,9 +59,17 @@ export class ThirdwebAuth {
chain_id: chainId,
nonce: parsedOptions?.nonce,
expiration_time:
parsedOptions?.expirationTime || new Date(Date.now() + 1000 * 60 * 10),
parsedOptions?.expirationTime ||
new Date(
Date.now() +
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
),
invalid_before:
parsedOptions?.invalidBefore || new Date(Date.now() - 1000 * 60 * 10),
parsedOptions?.invalidBefore ||
new Date(
Date.now() -
1000 * THIRDWEB_AUTH_DEFAULT_LOGIN_PAYLOAD_DURATION_IN_SECONDS,
),
resources: parsedOptions?.resources,
});
}
@@ -218,41 +231,37 @@ export class ThirdwebAuth {
}
const adminAddress = await this.wallet.getAddress();
const payloadData = AuthenticationPayloadDataSchema.parse({
return this.createToken({
iss: adminAddress,
sub: userAddress,
aud: domain,
nbf: parsedOptions?.invalidBefore || new Date(),
exp:
parsedOptions?.expirationTime ||
new Date(Date.now() + 1000 * 60 * 60 * 5),
new Date(
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
),
iat: new Date(),
jti: parsedOptions?.tokenId,
ctx: session,
});
}
const message = JSON.stringify(payloadData);
const signature = await this.wallet.signMessage(message);
// Header used for JWT token specifying hash algorithm
const header = {
// Specify ECDSA with SHA-256 for hashing algorithm
alg: "ES256",
typ: "JWT",
};
const encodedHeader = Buffer.from(JSON.stringify(header)).toString(
"base64",
);
const encodedData = Buffer.from(JSON.stringify(payloadData))
.toString("base64")
.replace(/=/g, "");
const encodedSignature = Buffer.from(signature).toString("base64");
// Generate a JWT token with base64 encoded header, payload, and signature
const token = `${encodedHeader}.${encodedData}.${encodedSignature}`;
return token;
public async refresh(token: string, expirationTime?: Date): Promise<string> {
const { payload } = this.parseToken(token);
return this.createToken({
iss: payload.iss,
sub: payload.sub,
aud: payload.aud,
nbf: new Date(),
exp:
expirationTime ||
new Date(
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
),
iat: new Date(),
ctx: payload.ctx,
});
}
/**
@@ -369,6 +378,35 @@ export class ThirdwebAuth {
};
}
private async createToken(
payload: AuthenticationPayloadDataInput,
): Promise<string> {
const payloadData = AuthenticationPayloadDataSchema.parse(payload);
const message = JSON.stringify(payloadData);
const signature = await this.wallet.signMessage(message);
// Header used for JWT token specifying hash algorithm
const header = {
// Specify ECDSA with SHA-256 for hashing algorithm
alg: "ES256",
typ: "JWT",
};
const encodedHeader = Buffer.from(JSON.stringify(header)).toString(
"base64",
);
const encodedData = Buffer.from(JSON.stringify(payloadData))
.toString("base64")
.replace(/=/g, "");
const encodedSignature = Buffer.from(signature).toString("base64");
// Generate a JWT token with base64 encoded header, payload, and signature
const token = `${encodedHeader}.${encodedData}.${encodedSignature}`;
return token;
}
private async verifySignature(
message: string,
signature: string,
+7
View File
@@ -180,6 +180,13 @@ export type AuthenticationPayloadData = z.output<
typeof AuthenticationPayloadDataSchema
>;
/**
* @internal
*/
export type AuthenticationPayloadDataInput = z.input<
typeof AuthenticationPayloadDataSchema
>;
/**
* @public
*/
+34 -7
View File
@@ -1,24 +1,51 @@
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { Json } from "../../core/schema";
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
import { Request } from "express";
function getToken(req: Request): string | undefined {
export function getCookie(req: Request, cookie: string): string | undefined {
if (typeof req.cookies.get === "function") {
return req.cookies.get(cookie);
}
return req.cookies[cookie];
}
export function getActiveCookie(req: Request): string | undefined {
if (!req.cookies) {
return undefined;
}
const activeAccount = getCookie(req, THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE);
if (activeAccount) {
return `${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${activeAccount}`;
}
// If active account is not present, then use the old default
return THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX;
}
export function getToken(req: Request): string | undefined {
if (req.headers["authorization"]) {
const authorizationHeader = req.headers["authorization"].split(" ");
if (authorizationHeader?.length === 2) {
return authorizationHeader[1];
}
}
if (!req.cookies) {
return undefined;
}
const cookie: string | undefined = !req.cookies
? undefined
: typeof req.cookies.get === "function"
? (req.cookies as any).get("thirdweb_auth_token")
: (req.cookies as any).thirdweb_auth_token;
const activeCookie = getActiveCookie(req);
if (!activeCookie) {
return undefined;
}
return cookie;
return getCookie(req, activeCookie);
}
export async function getUser<
+8
View File
@@ -4,6 +4,7 @@ import payloadHandler from "./routes/payload";
import loginHandler from "./routes/login";
import logoutHandler from "./routes/logout";
import userHandler from "./routes/user";
import switchAccountHandler from "./routes/switch-account";
import {
ThirdwebAuthConfig,
ThirdwebAuthContext,
@@ -76,6 +77,13 @@ export function ThirdwebAuth<
),
);
router.post(
"/switch-account",
asyncHandler((req: Request, res: Response) =>
switchAccountHandler(req, res, ctx as ThirdwebAuthContext),
),
);
return {
authRouter: router,
authMiddleware: cookieMiddleware,
+19 -4
View File
@@ -1,3 +1,7 @@
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { GenerateOptions } from "../../core";
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
import { serialize } from "cookie";
@@ -70,9 +74,20 @@ export default async function handler(
// Securely set httpOnly cookie on request to prevent XSS on frontend
// And set path to / to enable thirdweb_auth_token usage on all endpoints
res.setHeader(
"Set-Cookie",
serialize("thirdweb_auth_token", token, {
res.setHeader("Set-Cookie", [
serialize(
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${payload.payload.address}`,
token,
{
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(exp * 1000),
httpOnly: true,
secure: true,
},
),
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
@@ -80,7 +95,7 @@ export default async function handler(
httpOnly: true,
secure: true,
}),
);
]);
// Send token in body and as cookie for frontend and backend use cases
return res.status(200).json({ token });
+9 -2
View File
@@ -1,4 +1,4 @@
import { getUser } from "../helpers/user";
import { getActiveCookie, getUser } from "../helpers/user";
import { ThirdwebAuthContext } from "../types";
import { serialize } from "cookie";
import { Request, Response } from "express";
@@ -14,6 +14,13 @@ export default async function handler(
});
}
const activeCookie = getActiveCookie(req);
if (!activeCookie) {
return res.status(400).json({
error: "No logged in user to logout.",
});
}
if (ctx.callbacks?.onLogout) {
const user = await getUser(req, ctx);
if (user) {
@@ -24,7 +31,7 @@ export default async function handler(
// Set the access token to 'none' and expire in 5 seconds
res.setHeader(
"Set-Cookie",
serialize("thirdweb_auth_token", "", {
serialize(activeCookie, "", {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
+1 -1
View File
@@ -23,7 +23,7 @@ export default async function handler(
statement: ctx.authOptions?.statement,
uri: ctx.authOptions?.uri,
version: ctx.authOptions?.version,
chainId: ctx.authOptions?.chainId,
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
resources: ctx.authOptions?.resources,
});
@@ -0,0 +1,63 @@
import { Request, Response } from "express";
import { ActiveBodySchema, ThirdwebAuthContext } from "../types";
import { serialize } from "cookie";
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { getCookie } from "../helpers/user";
export default async function handler(
req: Request,
res: Response,
ctx: ThirdwebAuthContext,
) {
if (req.method !== "POST") {
return res.status(405).json({
error: "Invalid method. Only POST supported.",
});
}
const parsedPayload = ActiveBodySchema.safeParse(req.body);
if (!parsedPayload.success) {
return res.status(400).json({ error: "Please provide an address" });
}
let cookieExpiration: Date;
const cookie = getCookie(
req,
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${parsedPayload.data.address}`,
);
if (cookie) {
// If the new account is already logged in, get the expiration time from the cookie
const {
payload: { exp },
} = ctx.auth.parseToken(cookie);
cookieExpiration = new Date(exp * 1000);
} else if (ctx.authOptions?.tokenDurationInSeconds) {
// Otherwise, if we have a token duration in seconds, set it to that
cookieExpiration = new Date(
Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds,
);
} else {
// Otherwise, just default to 24 hours
cookieExpiration = new Date(
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
);
}
res.setHeader("Set-Cookie", [
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, parsedPayload.data.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: cookieExpiration,
httpOnly: true,
secure: true,
}),
]);
return res.status(200).end();
}
+56 -1
View File
@@ -1,6 +1,12 @@
import { getUser } from "../helpers/user";
import { serialize } from "cookie";
import { getToken, getUser } from "../helpers/user";
import { ThirdwebAuthContext } from "../types";
import { Request, Response } from "express";
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
export default async function handler(
req: Request,
@@ -14,5 +20,54 @@ export default async function handler(
}
const user = await getUser(req, ctx);
// Importantly, make sure the user was actually logged in before refreshing
if (user) {
const token = getToken(req);
if (token) {
const payload = ctx.auth.parseToken(token);
const refreshDate = ctx.authOptions?.refreshIntervalInSeconds
? new Date(
payload.payload.iat * 1000 +
ctx.authOptions.refreshIntervalInSeconds * 1000,
)
: new Date(
payload.payload.iat * 1000 +
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS * 1000,
);
if (new Date() > refreshDate) {
const expirationTime = ctx.authOptions?.tokenDurationInSeconds
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
: undefined;
const refreshedToken = await ctx.auth.refresh(token, expirationTime);
const refreshedPayload = ctx.auth.parseToken(refreshedToken);
res.setHeader("Set-Cookie", [
serialize(
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${user.address}`,
refreshedToken,
{
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(refreshedPayload.payload.exp * 1000),
httpOnly: true,
secure: true,
},
),
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(refreshedPayload.payload.exp * 1000),
httpOnly: true,
secure: true,
}),
]);
}
}
}
return res.status(200).json(user);
}
+6
View File
@@ -6,6 +6,11 @@ import { z } from "zod";
export const PayloadBodySchema = z.object({
address: z.string(),
chainId: z.string().optional(),
});
export const ActiveBodySchema = z.object({
address: z.string(),
});
export const LoginPayloadBodySchema = z.object({
@@ -40,6 +45,7 @@ export type ThirdwebAuthConfig<
| ((tokenId: string) => void)
| ((tokenId: string) => Promise<void>);
tokenDurationInSeconds?: number;
refreshIntervalInSeconds?: number;
};
cookieOptions?: {
domain?: string;
+39 -7
View File
@@ -1,9 +1,40 @@
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { Json } from "../../core/schema";
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
import { GetServerSidePropsContext, NextApiRequest } from "next";
import { NextRequest } from "next/server";
function getToken(
export function getCookie(
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
cookie: string,
): string | undefined {
if (typeof req.cookies.get === "function") {
return req.cookies.get(cookie);
}
return (req.cookies as any)[cookie];
}
export function getActiveCookie(
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
): string | undefined {
if (!req.cookies) {
return undefined;
}
const activeAccount = getCookie(req, THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE);
if (activeAccount) {
return `${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${activeAccount}`;
}
// If active account is not present, then use the old default
return THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX;
}
export function getToken(
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
): string | undefined {
if (!!(req as NextApiRequest).headers["authorization"]) {
@@ -13,17 +44,18 @@ function getToken(
if (authorizationHeader?.length === 2) {
return authorizationHeader[1];
}
}
if (!req.cookies) {
return undefined;
}
const cookie: string | undefined = !req.cookies
? undefined
: typeof req.cookies.get === "function"
? (req.cookies as any).get("thirdweb_auth_token")
: (req.cookies as any).thirdweb_auth_token;
const activeCookie = getActiveCookie(req);
if (!activeCookie) {
return undefined;
}
return cookie;
return getCookie(req, activeCookie);
}
export async function getUser<
+3
View File
@@ -4,6 +4,7 @@ import payloadHandler from "./routes/payload";
import loginHandler from "./routes/login";
import logoutHandler from "./routes/logout";
import userHandler from "./routes/user";
import switchAccountHandler from "./routes/switch-account";
import {
ThirdwebAuthConfig,
ThirdwebAuthContext,
@@ -36,6 +37,8 @@ async function ThirdwebAuthRouter(
return await userHandler(req, res, ctx);
case "logout":
return await logoutHandler(req, res, ctx);
case "switch-account":
return await switchAccountHandler(req, res, ctx);
default:
return res.status(400).json({
message: "Invalid route for authentication.",
+19 -4
View File
@@ -1,3 +1,7 @@
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { GenerateOptions } from "../../core";
import { LoginPayloadBodySchema, ThirdwebAuthContext } from "../types";
import { serialize } from "cookie";
@@ -70,9 +74,20 @@ export default async function handler(
// Securely set httpOnly cookie on request to prevent XSS on frontend
// And set path to / to enable thirdweb_auth_token usage on all endpoints
res.setHeader(
"Set-Cookie",
serialize("thirdweb_auth_token", token, {
res.setHeader("Set-Cookie", [
serialize(
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${payload.payload.address}`,
token,
{
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(exp * 1000),
httpOnly: true,
secure: true,
},
),
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, payload.payload.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
@@ -80,7 +95,7 @@ export default async function handler(
httpOnly: true,
secure: true,
}),
);
]);
// Send token in body and as cookie for frontend and backend use cases
return res.status(200).json({ token });
+9 -2
View File
@@ -1,4 +1,4 @@
import { getUser } from "../helpers/user";
import { getActiveCookie, getUser } from "../helpers/user";
import { ThirdwebAuthContext } from "../types";
import { serialize } from "cookie";
import { NextApiRequest, NextApiResponse } from "next";
@@ -14,6 +14,13 @@ export default async function handler(
});
}
const activeCookie = getActiveCookie(req);
if (!activeCookie) {
return res.status(400).json({
error: "No logged in user to logout.",
});
}
if (ctx.callbacks?.onLogout) {
const user = await getUser(req, ctx);
if (user) {
@@ -24,7 +31,7 @@ export default async function handler(
// Set the access token to 'none' and expire in 5 seconds
res.setHeader(
"Set-Cookie",
serialize("thirdweb_auth_token", "", {
serialize(activeCookie, "", {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
+1 -1
View File
@@ -23,7 +23,7 @@ export default async function handler(
statement: ctx.authOptions?.statement,
uri: ctx.authOptions?.uri,
version: ctx.authOptions?.version,
chainId: ctx.authOptions?.chainId,
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
resources: ctx.authOptions?.resources,
});
@@ -0,0 +1,63 @@
import { serialize } from "cookie";
import { getCookie } from "../helpers/user";
import { ActiveBodySchema, ThirdwebAuthContext } from "../types";
import { NextApiRequest, NextApiResponse } from "next";
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
ctx: ThirdwebAuthContext,
) {
if (req.method !== "POST") {
return res.status(405).json({
error: "Invalid method. Only POST supported.",
});
}
const parsedPayload = ActiveBodySchema.safeParse(req.body);
if (!parsedPayload.success) {
return res.status(400).json({ error: "Please provide an address" });
}
let cookieExpiration: Date;
const cookie = getCookie(
req,
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${parsedPayload.data.address}`,
);
if (cookie) {
// If the new account is already logged in, get the expiration time from the cookie
const {
payload: { exp },
} = ctx.auth.parseToken(cookie);
cookieExpiration = new Date(exp * 1000);
} else if (ctx.authOptions?.tokenDurationInSeconds) {
// Otherwise, if we have a token duration in seconds, set it to that
cookieExpiration = new Date(
Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds,
);
} else {
// Otherwise, just default to 24 hours
cookieExpiration = new Date(
Date.now() + 1000 * THIRDWEB_AUTH_DEFAULT_TOKEN_DURATION_IN_SECONDS,
);
}
res.setHeader("Set-Cookie", [
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, parsedPayload.data.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: cookieExpiration,
httpOnly: true,
secure: true,
}),
]);
return res.status(200).end();
}
+56 -1
View File
@@ -1,4 +1,10 @@
import { getUser } from "../helpers/user";
import { serialize } from "cookie";
import {
THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE,
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS,
THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX,
} from "../../constants";
import { getToken, getUser } from "../helpers/user";
import { ThirdwebAuthContext } from "../types";
import { NextApiRequest, NextApiResponse } from "next";
@@ -14,5 +20,54 @@ export default async function handler(
}
const user = await getUser(req, ctx);
// Importantly, make sure the user was actually logged in before refreshing
if (user) {
const token = getToken(req);
if (token) {
const payload = ctx.auth.parseToken(token);
const refreshDate = ctx.authOptions?.refreshIntervalInSeconds
? new Date(
payload.payload.iat * 1000 +
ctx.authOptions.refreshIntervalInSeconds * 1000,
)
: new Date(
payload.payload.iat * 1000 +
THIRDWEB_AUTH_DEFAULT_REFRESH_INTERVAL_IN_SECONDS * 1000,
);
if (new Date() > refreshDate) {
const expirationTime = ctx.authOptions?.tokenDurationInSeconds
? new Date(Date.now() + 1000 * ctx.authOptions.tokenDurationInSeconds)
: undefined;
const refreshedToken = await ctx.auth.refresh(token, expirationTime);
const refreshedPayload = ctx.auth.parseToken(refreshedToken);
res.setHeader("Set-Cookie", [
serialize(
`${THIRDWEB_AUTH_TOKEN_COOKIE_PREFIX}_${user.address}`,
refreshedToken,
{
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(refreshedPayload.payload.exp * 1000),
httpOnly: true,
secure: true,
},
),
serialize(THIRDWEB_AUTH_ACTIVE_ACCOUNT_COOKIE, user.address, {
domain: ctx.cookieOptions?.domain,
path: ctx.cookieOptions?.path || "/",
sameSite: ctx.cookieOptions?.sameSite || "none",
expires: new Date(refreshedPayload.payload.exp * 1000),
httpOnly: true,
secure: true,
}),
]);
}
}
}
return res.status(200).json(user);
}
+12 -1
View File
@@ -7,6 +7,11 @@ import { z } from "zod";
export const PayloadBodySchema = z.object({
address: z.string(),
chainId: z.string().optional(),
});
export const ActiveBodySchema = z.object({
address: z.string(),
});
export const LoginPayloadBodySchema = z.object({
@@ -18,7 +23,12 @@ type RequestType =
| NextRequest
| NextApiRequest;
export type ThirdwebAuthRoute = "payload" | "login" | "logout" | "user";
export type ThirdwebAuthRoute =
| "payload"
| "login"
| "logout"
| "user"
| "switch-account";
export type ThirdwebAuthUser<
TData extends Json = Json,
@@ -46,6 +56,7 @@ export type ThirdwebAuthConfig<
| ((tokenId: string) => void)
| ((tokenId: string) => Promise<void>);
tokenDurationInSeconds?: number;
refreshIntervalInSeconds?: number;
};
cookieOptions?: {
domain?: string;
+26
View File
@@ -1,5 +1,31 @@
# @thirdweb-dev/chains
## 0.1.24
### Patch Changes
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
## 0.1.23
### Patch Changes
- [#1229](https://github.com/thirdweb-dev/js/pull/1229) [`6816219a`](https://github.com/thirdweb-dev/js/commit/6816219ac13ae571a0c90db6ab389c319bc1f052) Thanks [@jnsdls](https://github.com/jnsdls)! - add/update chains
## 0.1.22
### Patch Changes
- [#1192](https://github.com/thirdweb-dev/js/pull/1192) [`f41f1a29`](https://github.com/thirdweb-dev/js/commit/f41f1a2958a2cedcf0496c9a3ca284d0b98f1b89) Thanks [@jnsdls](https://github.com/jnsdls)! - fix arbitrum goerli infura url
## 0.1.21
### Patch Changes
- [#1074](https://github.com/thirdweb-dev/js/pull/1074) [`cc20f93e`](https://github.com/thirdweb-dev/js/commit/cc20f93e178d86ee2b3f39102bbb0811de211f05) Thanks [@Marfuen](https://github.com/Marfuen)! - Enhance CLI Install command and update chains
- [#1185](https://github.com/thirdweb-dev/js/pull/1185) [`8e28b0f5`](https://github.com/thirdweb-dev/js/commit/8e28b0f5e75596d29273ed80269bcee6d209adb4) Thanks [@jnsdls](https://github.com/jnsdls)! - add Zora Mainnet
## 0.1.20
### Patch Changes
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "SatoshiChain Mainnet",
"chain": "SATS",
"icon": {
"url": "ipfs://QmRegpZQBW4o1imYNsW3d27MQjygBSU23Gf6JKje26nvs7",
"width": 1251,
"height": 1251,
"format": "png"
},
"rpc": [
"https://satoshichain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet-rpc.satoshichain.io"
],
"faucets": [],
"nativeCurrency": {
"name": "SatoshiChain Coin",
"symbol": "SATS",
"decimals": 18
},
"infoURL": "https://satoshichain.net",
"shortName": "sats",
"chainId": 12009,
"networkId": 12009,
"explorers": [
{
"name": "SatoshiChain Explorer",
"url": "https://satoshiscan.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "satoshichain"
} as const satisfies Chain;
+36
View File
@@ -0,0 +1,36 @@
import type { Chain } from "../src/types";
export default {
"name": "BRC Chain Mainnet",
"chain": "BRC",
"rpc": [
"https://brc-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.brcchain.io"
],
"faucets": [
"https://faucet.brcchain.io"
],
"nativeCurrency": {
"name": "BRC Chain mainnet native token",
"symbol": "BRC",
"decimals": 18
},
"infoURL": "https://bridge.brcchain.io",
"shortName": "BRC",
"chainId": 12123,
"networkId": 12123,
"icon": {
"url": "ipfs://QmX8qGX7xoZqYUpHxA85uZwQX2fgbTHvmddE1NfseDyBED",
"width": 512,
"height": 512,
"format": "png"
},
"explorers": [
{
"name": "BRC Chain Explorer",
"url": "https://scan.brcchain.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "brc-chain"
} as const satisfies Chain;
+2 -2
View File
@@ -4,7 +4,7 @@ export default {
"chain": "ATH",
"rpc": [
"https://atheios.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://wallet.atheios.com:8797"
"https://rpc.atheios.org/"
],
"faucets": [],
"nativeCurrency": {
@@ -12,7 +12,7 @@ export default {
"symbol": "ATH",
"decimals": 18
},
"infoURL": "https://atheios.com",
"infoURL": "https://atheios.org",
"shortName": "ath",
"chainId": 1620,
"networkId": 11235813,
+33
View File
@@ -0,0 +1,33 @@
import type { Chain } from "../src/types";
export default {
"name": "Omni Testnet 1",
"chain": "Omni",
"rpc": [
"https://omni-testnet-1.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-1.omni.network"
],
"features": [
{
"name": "EIP155"
}
],
"faucets": [],
"nativeCurrency": {
"name": "Omni",
"symbol": "OMNI",
"decimals": 18
},
"infoURL": "https://docs.omni.network/",
"shortName": "omni_testnet",
"chainId": 165,
"networkId": 165,
"explorers": [
{
"name": "Omni Explorer",
"url": "https://testnet-1.explorer.omni.network",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "omni-testnet-1"
} as const satisfies Chain;
-51
View File
@@ -1,51 +0,0 @@
import type { Chain } from "../src/types";
export default {
"name": "Horizen Yuma Testnet",
"shortName": "Yuma",
"chain": "Yuma",
"icon": {
"url": "ipfs://QmSFMBk3rMyu45Sy9KQHjgArFj4HdywANNYrSosLMUdcti",
"width": 1213,
"height": 1213,
"format": "png"
},
"rpc": [
"https://horizen-yuma-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://yuma-testnet.horizenlabs.io/ethv1"
],
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"faucets": [
"https://yuma-testnet-faucet.horizen.io"
],
"nativeCurrency": {
"name": "Testnet Zen",
"symbol": "tZEN",
"decimals": 18
},
"infoURL": "https://horizen.io/",
"chainId": 1662,
"networkId": 1662,
"slip44": 121,
"explorers": [
{
"name": "Yuma Testnet Block Explorer",
"url": "https://yuma-explorer.horizen.io",
"icon": {
"url": "ipfs://QmSFMBk3rMyu45Sy9KQHjgArFj4HdywANNYrSosLMUdcti",
"width": 1213,
"height": 1213,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "horizen-yuma-testnet"
} as const satisfies Chain;
+2 -1
View File
@@ -11,7 +11,8 @@ export default {
},
"rpc": [
"https://horizen-gobi-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://gobi-testnet.horizenlabs.io/ethv1"
"https://gobi-testnet.horizenlabs.io/ethv1",
"https://rpc.ankr.com/horizen_testnet_evm"
],
"features": [
{
+21
View File
@@ -0,0 +1,21 @@
import type { Chain } from "../src/types";
export default {
"name": "Shrapnel Subnet",
"chain": "shrapnel",
"rpc": [
"https://shrapnel-subnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://subnets.avax.network/shrapnel/mainnet/rpc"
],
"faucets": [],
"nativeCurrency": {
"name": "Shrapnel Gas Token",
"symbol": "SHRAPG",
"decimals": 18
},
"infoURL": "https://www.shrapnel.com/",
"shortName": "Shrapnel",
"chainId": 2044,
"networkId": 2044,
"testnet": false,
"slug": "shrapnel-subnet"
} as const satisfies Chain;
+2 -2
View File
@@ -19,8 +19,8 @@ export default {
"networkId": 1,
"icon": {
"url": "ipfs://QmT7PSXBiVBma6E15hNkivmstqLu3JSnG1jXN5pTmcCGRC",
"width": 200,
"height": 200,
"width": 180,
"height": 180,
"format": "png"
},
"explorers": [
-12
View File
@@ -2,12 +2,6 @@ import type { Chain } from "../src/types";
export default {
"name": "Metaplayerone Dubai Testnet",
"chain": "MP1 Dubai-Testnet",
"icon": {
"url": "ipfs://QmfJKxmubJrqYWDcR2PnPvmpukxPz4fYDu3hqTaSnpJDxC",
"width": 42,
"height": 23,
"format": "svg"
},
"rpc": [
"https://metaplayerone-dubai-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-dubai.mp1network.com/"
@@ -26,12 +20,6 @@ export default {
{
"name": "MP1Scan",
"url": "https://dubai.mp1scan.io",
"icon": {
"url": "ipfs://QmfJKxmubJrqYWDcR2PnPvmpukxPz4fYDu3hqTaSnpJDxC",
"width": 42,
"height": 23,
"format": "svg"
},
"standard": "EIP3091"
}
],
+2 -2
View File
@@ -21,8 +21,8 @@ export default {
"networkId": 1,
"icon": {
"url": "ipfs://QmT7PSXBiVBma6E15hNkivmstqLu3JSnG1jXN5pTmcCGRC",
"width": 200,
"height": 200,
"width": 180,
"height": 180,
"format": "png"
},
"explorers": [
+2 -1
View File
@@ -11,7 +11,8 @@ export default {
"rpc": [
"https://lachain-lachain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc1.mainnet.lachain.network",
"https://rpc2.mainnet.lachain.network"
"https://rpc2.mainnet.lachain.network",
"https://lachain.rpc-nodes.cedalio.dev"
],
"faucets": [],
"nativeCurrency": {
-12
View File
@@ -24,22 +24,10 @@ export default {
"shortName": "ncnt",
"chainId": 303,
"networkId": 303,
"icon": {
"url": "ipfs://Qmc9zDWXar67cMUodp28mbN5pnwbVibxGXhwa8YCDvxmTR",
"width": 62,
"height": 59,
"format": "svg"
},
"explorers": [
{
"name": "neuroscan",
"url": "https://testnet.ncnscan.com",
"icon": {
"url": "ipfs://Qmc9zDWXar67cMUodp28mbN5pnwbVibxGXhwa8YCDvxmTR",
"width": 62,
"height": 59,
"format": "svg"
},
"standard": "EIP3091"
}
],
-12
View File
@@ -25,22 +25,10 @@ export default {
"shortName": "ncn",
"chainId": 313,
"networkId": 313,
"icon": {
"url": "ipfs://Qmc9zDWXar67cMUodp28mbN5pnwbVibxGXhwa8YCDvxmTR",
"width": 62,
"height": 59,
"format": "svg"
},
"explorers": [
{
"name": "neuroscan",
"url": "https://ncnscan.com",
"icon": {
"url": "ipfs://Qmc9zDWXar67cMUodp28mbN5pnwbVibxGXhwa8YCDvxmTR",
"width": 62,
"height": 59,
"format": "svg"
},
"standard": "EIP3091"
}
],
+9 -9
View File
@@ -1,10 +1,10 @@
import type { Chain } from "../src/types";
export default {
"name": "Metacodechain",
"chain": "metacode",
"name": "Jouleverse Mainnet",
"chain": "Jouleverse",
"rpc": [
"https://metacodechain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://j.blockcoach.com:8503"
"https://jouleverse.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.jnsdao.com:8503"
],
"faucets": [],
"nativeCurrency": {
@@ -12,17 +12,17 @@ export default {
"symbol": "J",
"decimals": 18
},
"infoURL": "https://j.blockcoach.com:8089",
"shortName": "metacode",
"infoURL": "https://jnsdao.com",
"shortName": "jouleverse",
"chainId": 3666,
"networkId": 3666,
"explorers": [
{
"name": "meta",
"url": "https://j.blockcoach.com:8089",
"name": "jscan",
"url": "https://jscan.jnsdao.com",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "metacodechain"
"slug": "jouleverse"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Ozone Chain Mainnet",
"chain": "OZONE",
"rpc": [
"https://ozone-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://node1.ozonechain.io"
],
"faucets": [],
"nativeCurrency": {
"name": "OZONE",
"symbol": "OZO",
"decimals": 18
},
"infoURL": "https://ozonechain.io",
"shortName": "ozo",
"chainId": 4000,
"networkId": 4000,
"icon": {
"url": "ipfs://QmbM4weV8Bk6c9yNhosYntkVw39SNZtCHYGgWyXTxkevZ8",
"width": 1600,
"height": 1600,
"format": "png"
},
"explorers": [
{
"name": "OZONE Scan",
"url": "https://ozonescan.io",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "ozone-chain"
} as const satisfies Chain;
+40
View File
@@ -0,0 +1,40 @@
import type { Chain } from "../src/types";
export default {
"name": "Peperium Chain Testnet",
"chain": "PERIUM",
"rpc": [
"https://peperium-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-testnet.peperium.io"
],
"faucets": [],
"nativeCurrency": {
"name": "Peperium Chain Testnet",
"symbol": "PERIUM",
"decimals": 18
},
"infoURL": "https://peperium.io",
"shortName": "PERIUM",
"chainId": 4001,
"networkId": 4001,
"icon": {
"url": "ipfs://Qmag2hr5DQghRzKPN3oUFBkjWzqd5CndQzZeb5LfoiMCXf",
"width": 160,
"height": 160,
"format": "png"
},
"explorers": [
{
"name": "Peperium Chain Explorer",
"url": "https://scan-testnet.peperium.io",
"icon": {
"url": "ipfs://Qmag2hr5DQghRzKPN3oUFBkjWzqd5CndQzZeb5LfoiMCXf",
"width": 160,
"height": 160,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "peperium-chain-testnet"
} as const satisfies Chain;
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Ozone Chain Testnet",
"chain": "OZONE",
"rpc": [
"https://ozone-chain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://node1.testnet.ozonechain.io"
],
"faucets": [],
"nativeCurrency": {
"name": "OZONE",
"symbol": "OZO",
"decimals": 18
},
"infoURL": "https://ozonechain.io",
"shortName": "ozo_tst",
"chainId": 401,
"networkId": 401,
"icon": {
"url": "ipfs://QmbM4weV8Bk6c9yNhosYntkVw39SNZtCHYGgWyXTxkevZ8",
"width": 1600,
"height": 1600,
"format": "png"
},
"explorers": [
{
"name": "OZONE Scan",
"url": "https://testnet.ozonescan.io",
"standard": "EIP3091"
}
],
"testnet": true,
"slug": "ozone-chain-testnet"
} as const satisfies Chain;
+24
View File
@@ -0,0 +1,24 @@
import type { Chain } from "../src/types";
export default {
"name": "Omega Mainnet",
"chain": "OmegaNetwork",
"shortName": "OmegaNetwork",
"chainId": 408,
"testnet": false,
"icon": {
"format": "png",
"url": "ipfs://bafkreig676zxfhwhcx5bvvvjxedx6ftr2wq4iiznrwm3c6ozrprbc4oxwm",
"height": 512,
"width": 512
},
"rpc": [
"https://omega.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet-rpc.omtch.com"
],
"nativeCurrency": {
"name": "Omega Network Coin",
"symbol": "OMN",
"decimals": 18
},
"slug": "omega"
} as const satisfies Chain;
+2 -1
View File
@@ -10,7 +10,8 @@ export default {
},
"rpc": [
"https://latestnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.testnet.lachain.network"
"https://rpc.testnet.lachain.network",
"https://lachain-testnet.rpc-nodes.cedalio.dev"
],
"faucets": [
"https://faucet.lachain.network"
+1 -1
View File
@@ -14,7 +14,7 @@ export default {
"rpc": [
"https://arbitrum-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
"https://abritrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://arbitrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://goerli-rollup.arbitrum.io/rpc/"
],
"faucets": [],
+1 -1
View File
@@ -12,7 +12,7 @@ export default {
"rpc": [
"https://wireshape-floripa-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc-floripa.wireshape.org",
"https://floripa.rpc.thirdweb.com"
"https://wireshape-floripa-testnet.rpc.thirdweb.com"
],
"faucets": [],
"nativeCurrency": {
+29
View File
@@ -0,0 +1,29 @@
import type { Chain } from "../src/types";
export default {
"name": "Titan",
"chain": "ETH",
"rpc": [
"https://titan.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.titan.tokamak.network",
"wss://rpc.titan.tokamak.network/ws"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"infoURL": "https://tokamak.network",
"shortName": "teth",
"chainId": 55004,
"networkId": 55004,
"explorers": [
{
"name": "blockscout",
"url": "https://explorer.titan.tokamak.network",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "titan"
} as const satisfies Chain;
+35
View File
@@ -0,0 +1,35 @@
import type { Chain } from "../src/types";
export default {
"name": "opBNB",
"chain": "opBNB",
"shortName": "opBNB",
"chainId": 5611,
"testnet": true,
"nativeCurrency": {
"name": "Testnet bnb",
"symbol": "Tbnb",
"decimals": 18
},
"rpc": [
"https://opbnb.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://opbnb-testnet-rpc.bnbchain.org"
],
"explorers": [
{
"name": "opBNB Scan",
"url": "https://opbnbscan.com/",
"standard": ""
}
],
"faucets": [
"https://opbnb-testnet-bridge.bnbchain.org/"
],
"infoURL": "https://docs.bnbchain.org/",
"icon": {
"url": "ipfs://QmfFvfFsQKby3M32uqr8T55ENBnTHL8bkdeeu6rYVL2n4z/opbnblogo.svg",
"height": 512,
"width": 512,
"format": "svg"
},
"slug": "opbnb"
} as const satisfies Chain;
+4 -4
View File
@@ -10,7 +10,7 @@ export default {
},
"rpc": [
"https://satoshichain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.satoshichain.io"
"https://testnet-rpc.satoshichain.io"
],
"faucets": [
"https://faucet.satoshichain.io"
@@ -21,13 +21,13 @@ export default {
"decimals": 18
},
"infoURL": "https://satoshichain.net",
"shortName": "sats",
"shortName": "satst",
"chainId": 5758,
"networkId": 5758,
"explorers": [
{
"name": "SatoshiChain Explorer",
"url": "https://satoshiscan.io",
"name": "SatoshiChain Testnet Explorer",
"url": "https://testnet.satoshiscan.io",
"standard": "EIP3091"
}
],
+4 -4
View File
@@ -3,9 +3,9 @@ export default {
"name": "ZetaChain Mainnet",
"chain": "ZetaChain",
"icon": {
"url": "ipfs://QmeABfwZ2nAxDzYyqZ1LEypPgQFMjEyrx8FfnoPLkF8R3f",
"width": 1280,
"height": 1280,
"url": "ipfs://QmP4Gnf4Lkp8q5LQVePNjAWxSqrw8vU2JAf7amcFz4vEUy",
"width": 712,
"height": 712,
"format": "png"
},
"rpc": [
@@ -18,7 +18,7 @@ export default {
"symbol": "ZETA",
"decimals": 18
},
"infoURL": "https://docs.zetachain.com/",
"infoURL": "https://zetachain.com/docs/",
"shortName": "zetachain-mainnet",
"chainId": 7000,
"networkId": 7000,
+6 -5
View File
@@ -3,14 +3,15 @@ export default {
"name": "ZetaChain Athens Testnet",
"chain": "ZetaChain",
"icon": {
"url": "ipfs://QmeABfwZ2nAxDzYyqZ1LEypPgQFMjEyrx8FfnoPLkF8R3f",
"width": 1280,
"height": 1280,
"url": "ipfs://QmP4Gnf4Lkp8q5LQVePNjAWxSqrw8vU2JAf7amcFz4vEUy",
"width": 712,
"height": 712,
"format": "png"
},
"rpc": [
"https://zetachain-athens-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://api.athens2.zetachain.com/evm"
"https://zetachain-athens-evm.blockpi.network/v1/rpc/public",
"wss://zetachain-athens.blockpi.network/rpc/v1/public/websocket"
],
"faucets": [
"https://labs.zetachain.com/get-zeta"
@@ -20,7 +21,7 @@ export default {
"symbol": "aZETA",
"decimals": 18
},
"infoURL": "https://docs.zetachain.com/",
"infoURL": "https://zetachain.com/docs",
"shortName": "zetachain-athens",
"chainId": 7001,
"networkId": 7001,
+34
View File
@@ -0,0 +1,34 @@
import type { Chain } from "../src/types";
export default {
"name": "Zora",
"chain": "ETH",
"rpc": [
"https://zora.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.zora.energy/"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"icon": {
"url": "ipfs://QmZ6qaRwTPFEZUspwMUjaxC6KhmzcELdRQcQzS3P72Dzts/Vector.svg",
"height": 512,
"width": 512,
"format": "svg"
},
"infoURL": "https://zora.energy",
"shortName": "zora",
"chainId": 7777777,
"networkId": 7777777,
"explorers": [
{
"name": "Zora Network Explorer",
"url": "https://explorer.zora.energy",
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "zora"
} as const satisfies Chain;
+27
View File
@@ -2,6 +2,12 @@ import type { Chain } from "../src/types";
export default {
"name": "Patex",
"chain": "ETH",
"icon": {
"url": "ipfs://QmTNTSNn3t5WpSEzQmUYbkxYkBKaH6QahyVdVrRKyPHChr",
"width": 800,
"height": 800,
"format": "png"
},
"rpc": [
"https://patex.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.patex.io/"
@@ -12,10 +18,31 @@ export default {
"symbol": "ETH",
"decimals": 18
},
"features": [
{
"name": "EIP155"
},
{
"name": "EIP1559"
}
],
"infoURL": "https://patex.io/",
"shortName": "peth",
"chainId": 789,
"networkId": 789,
"explorers": [
{
"name": "patexscan",
"url": "https://patexscan.io",
"icon": {
"url": "ipfs://QmTNTSNn3t5WpSEzQmUYbkxYkBKaH6QahyVdVrRKyPHChr",
"width": 800,
"height": 800,
"format": "png"
},
"standard": "EIP3091"
}
],
"testnet": false,
"slug": "patex"
} as const satisfies Chain;
+15 -19
View File
@@ -1,39 +1,35 @@
import type { Chain } from "../src/types";
export default {
"name": "Shardeum Liberty 2.X",
"name": "Shardeum Sphinx DApp 1.X",
"shortName": "Sphinx",
"chain": "Shardeum",
"chainId": 8081,
"icon": {
"url": "ipfs://Qma1bfuubpepKn7DLDy4NPSKDeT3S4VPCNhu6UmdGrb6YD",
"width": 609,
"height": 533,
"height": 1200,
"width": 1200,
"url": "ipfs://QmQWzHUy4kmk1eGksDREGQL3GWrssdAPBxHt4aKGAFHSfJ",
"format": "png"
},
"rpc": [
"https://shardeum-liberty-2-x.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://liberty20.shardeum.org/"
],
"faucets": [
"https://faucet.liberty20.shardeum.org"
"https://shardeum-sphinx-dapp-1-x.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://dapps.shardeum.org/sphinx"
],
"nativeCurrency": {
"name": "Shardeum SHM",
"name": "Shardeum",
"symbol": "SHM",
"decimals": 18
},
"infoURL": "https://docs.shardeum.org/",
"shortName": "Liberty20",
"chainId": 8081,
"networkId": 8081,
"explorers": [
{
"name": "Shardeum Scan",
"url": "https://explorer-liberty20.shardeum.org",
"url": "https://explorer-dapps.shardeum.org",
"standard": "EIP3091"
}
],
"redFlags": [
"reusedChainId"
"faucets": [
"https://faucet-dapps.shardeum.org/"
],
"testnet": false,
"slug": "shardeum-liberty-2-x"
"infoURL": "https://docs.shardeum.org/",
"testnet": true,
"slug": "shardeum-sphinx-dapp-1-x"
} as const satisfies Chain;
+45
View File
@@ -0,0 +1,45 @@
import type { Chain } from "../src/types";
export default {
"name": "CamDL Mainnet",
"chain": "CADL",
"rpc": [
"https://camdl.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc1.camdl.gov.kh/"
],
"faucets": [
"https://faucet.camdl.gov.kh/"
],
"nativeCurrency": {
"name": "CADL",
"symbol": "CADL",
"decimals": 18
},
"features": [
{
"name": "EIP155"
}
],
"infoURL": "https://camdl.gov.kh/",
"shortName": "camdl",
"chainId": 95,
"networkId": 95,
"redFlags": [
"reusedChainId"
],
"icon": {
"url": "ipfs://QmW5Fpb2Ywnfqcj4ibvpbKvPv5Mo5eseWdYZnnUvLkj2Hp",
"width": 1453,
"height": 1453,
"format": "png"
},
"explorers": [
{
"name": "CamDL Block Explorer",
"url": "https://explorer.camdl.gov.kh",
"standard": "EIP3091"
}
],
"status": "active",
"testnet": false,
"slug": "camdl"
} as const satisfies Chain;
+23
View File
@@ -0,0 +1,23 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "Omega Mainnet",
chain: "OmegaNetwork",
shortName: "OmegaNetwork",
chainId: 408,
testnet: false,
icon: {
format: "png",
url: "ipfs://bafkreig676zxfhwhcx5bvvvjxedx6ftr2wq4iiznrwm3c6ozrprbc4oxwm",
height: 512,
width: 512,
},
rpc: ["https://mainnet-rpc.omtch.com"],
nativeCurrency: {
name: "Omega Network Coin",
symbol: "OMN",
decimals: 18,
},
};
+32
View File
@@ -0,0 +1,32 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "opBNB",
chain: "opBNB",
shortName: "opBNB",
chainId: 5611,
testnet: true,
nativeCurrency: {
name: "Testnet bnb",
symbol: "Tbnb",
decimals: 18,
},
rpc: ["https://opbnb-testnet-rpc.bnbchain.org"],
explorers: [
{
name: "opBNB Scan",
url: "https://opbnbscan.com/",
standard: "",
},
],
faucets: ["https://opbnb-testnet-bridge.bnbchain.org/"],
infoURL: "https://docs.bnbchain.org/",
icon: {
url: "ipfs://QmfFvfFsQKby3M32uqr8T55ENBnTHL8bkdeeu6rYVL2n4z/opbnblogo.svg",
height: 512,
width: 512,
format: "svg",
},
};
+32
View File
@@ -0,0 +1,32 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "Shardeum Sphinx DApp 1.X",
shortName: "Sphinx",
chain: "Shardeum",
chainId: 8081,
icon: {
height: 1200,
width: 1200,
url: "ipfs://QmQWzHUy4kmk1eGksDREGQL3GWrssdAPBxHt4aKGAFHSfJ",
format: "png",
},
rpc: ["https://dapps.shardeum.org/sphinx"],
nativeCurrency: {
name: "Shardeum",
symbol: "SHM",
decimals: 18,
},
explorers: [
{
name: "Shardeum Scan",
url: "https://explorer-dapps.shardeum.org",
standard: "EIP3091",
},
],
faucets: ["https://faucet-dapps.shardeum.org/"],
infoURL: "https://docs.shardeum.org/",
testnet: true,
};
+1 -1
View File
@@ -10,7 +10,7 @@ export default {
format: "png",
},
rpc: [
"https://abritrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://arbitrum-goerli.infura.io/v3/${INFURA_API_KEY}",
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
],
};
@@ -0,0 +1,12 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Partial<Chain>} */
export default {
icon: {
url: "ipfs://QmZ6qaRwTPFEZUspwMUjaxC6KhmzcELdRQcQzS3P72Dzts/Vector.svg",
height: 512,
width: 512,
format: "svg",
},
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.20",
"version": "0.1.24",
"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
+45
View File
@@ -1,5 +1,50 @@
# thirdweb
## 0.10.26
### Patch Changes
- [#1240](https://github.com/thirdweb-dev/js/pull/1240) [`1c7264b4`](https://github.com/thirdweb-dev/js/commit/1c7264b40330d068ece67df537a0f5db0f6aedca) Thanks [@Marfuen](https://github.com/Marfuen)! - Small bug fix for updating packages using --nightly
- Updated dependencies [[`d498c79a`](https://github.com/thirdweb-dev/js/commit/d498c79a911d478077dfb8a2490eb1bf91523186), [`0c5b03b8`](https://github.com/thirdweb-dev/js/commit/0c5b03b8d6cc6a4e69bb2a4647d3626e69f1283c), [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea)]:
- @thirdweb-dev/sdk@3.10.25
- @thirdweb-dev/storage@1.1.5
- @thirdweb-dev/chains@0.1.24
## 0.10.25
### Patch Changes
- Updated dependencies [[`6816219a`](https://github.com/thirdweb-dev/js/commit/6816219ac13ae571a0c90db6ab389c319bc1f052), [`48065bcd`](https://github.com/thirdweb-dev/js/commit/48065bcd91c13e1f44d54343b5c6c2646b9e86e4), [`6aa6f7e0`](https://github.com/thirdweb-dev/js/commit/6aa6f7e0bd2313e2e1ad96dd41aad91e6694d380), [`f7f4f207`](https://github.com/thirdweb-dev/js/commit/f7f4f20737ac5d78424ca9c91220f00b85adde6b), [`d4d95507`](https://github.com/thirdweb-dev/js/commit/d4d95507130b2b5408bfaa73ef3b708ca00c773e), [`483e2b91`](https://github.com/thirdweb-dev/js/commit/483e2b910934d75276a68bae64d04c47cd7d57e3), [`c08e6ba9`](https://github.com/thirdweb-dev/js/commit/c08e6ba988ad97aa27d5868cec8abe3498d07a0a), [`3d615a62`](https://github.com/thirdweb-dev/js/commit/3d615a62d0a6801f6fb0e63f9b95c2f98446add1)]:
- @thirdweb-dev/chains@0.1.23
- @thirdweb-dev/sdk@3.10.24
## 0.10.24
### Patch Changes
- Updated dependencies [[`d9b7360d`](https://github.com/thirdweb-dev/js/commit/d9b7360d1d78abcdaca89aa35e66388cbc5eb26c), [`8a2d9204`](https://github.com/thirdweb-dev/js/commit/8a2d92046a416c99c6bfecf63a6fdb6cc02ea175), [`990c665d`](https://github.com/thirdweb-dev/js/commit/990c665de9e5c1070dc80fe0f1b434e251f70a94), [`c6f44722`](https://github.com/thirdweb-dev/js/commit/c6f44722f9d123db4e7c4c799fe8e0374a02107c), [`45ae105e`](https://github.com/thirdweb-dev/js/commit/45ae105ed3e48bfbf6be84aa12ecb0fb55a917b7), [`f41f1a29`](https://github.com/thirdweb-dev/js/commit/f41f1a2958a2cedcf0496c9a3ca284d0b98f1b89), [`bb7ca20e`](https://github.com/thirdweb-dev/js/commit/bb7ca20e49c5c374b12a4ed746a2ac3db488abd9), [`23d61cfe`](https://github.com/thirdweb-dev/js/commit/23d61cfeff2e5a885c511416d7491e7933ed404a), [`8941b226`](https://github.com/thirdweb-dev/js/commit/8941b22682d1b15a6e0d311b1e8548b95d6cfadf), [`e0ce4a37`](https://github.com/thirdweb-dev/js/commit/e0ce4a37596a91a072f8551e323fce6723113dcb)]:
- @thirdweb-dev/sdk@3.10.23
- @thirdweb-dev/chains@0.1.22
## 0.10.23
### Patch Changes
- [#1184](https://github.com/thirdweb-dev/js/pull/1184) [`e7f1ce43`](https://github.com/thirdweb-dev/js/commit/e7f1ce43b04c6ea81fd05c02c8392a16c38d6053) Thanks [@Marfuen](https://github.com/Marfuen)! - Fix typo issues with python detectors
- [#1074](https://github.com/thirdweb-dev/js/pull/1074) [`cc20f93e`](https://github.com/thirdweb-dev/js/commit/cc20f93e178d86ee2b3f39102bbb0811de211f05) Thanks [@Marfuen](https://github.com/Marfuen)! - Enhance CLI Install command and update chains
- [#1154](https://github.com/thirdweb-dev/js/pull/1154) [`02d55a06`](https://github.com/thirdweb-dev/js/commit/02d55a063e7c53761d57e6cb6bf63ea78e454d70) Thanks [@beauwilliams](https://github.com/beauwilliams)! - fix: always use latest CLI version in CI
- [#1171](https://github.com/thirdweb-dev/js/pull/1171) [`c0e2c945`](https://github.com/thirdweb-dev/js/commit/c0e2c9457f5ba992163b175f85b0f4b92b070f48) Thanks [@Marfuen](https://github.com/Marfuen)! - Minor bug fixes and improvements
- [#1183](https://github.com/thirdweb-dev/js/pull/1183) [`224b7241`](https://github.com/thirdweb-dev/js/commit/224b7241dc82155d3207a2d16523ceaae5532f40) Thanks [@Marfuen](https://github.com/Marfuen)! - Python detectors bug fixes
- Updated dependencies [[`cc20f93e`](https://github.com/thirdweb-dev/js/commit/cc20f93e178d86ee2b3f39102bbb0811de211f05), [`a430160e`](https://github.com/thirdweb-dev/js/commit/a430160e6b4771c03d97f6ede91f1aeaa043e50e), [`12b07aad`](https://github.com/thirdweb-dev/js/commit/12b07aad9ae3176daf9d05864247d4806a16c9d2), [`7d2a446e`](https://github.com/thirdweb-dev/js/commit/7d2a446ecef9c6c14959d31e9a66537783b9adac), [`8e28b0f5`](https://github.com/thirdweb-dev/js/commit/8e28b0f5e75596d29273ed80269bcee6d209adb4), [`01293857`](https://github.com/thirdweb-dev/js/commit/01293857fac8531bd94764203cd24b3daa4db51f), [`20bbad1a`](https://github.com/thirdweb-dev/js/commit/20bbad1abcb1ec573318d326b09278492a488abd)]:
- @thirdweb-dev/chains@0.1.21
- @thirdweb-dev/sdk@3.10.22
## 0.10.22
### Patch Changes
+4 -9
View File
@@ -34,9 +34,6 @@ describe("npx thirdweb detect", () => {
// wait for program to finish
await create.waitForFinish();
// the process should exit with code 0
expect(create.getExitCode()).toEqual(0);
// check if the contract was created
expect(await exists("thirdweb-contracts/contracts/Contract.sol")).toEqual(
true,
@@ -56,14 +53,15 @@ describe("npx thirdweb detect", () => {
"./thirdweb-contracts",
);
// Select pnpm as package manager.
await detect.pressKey("arrowDown");
await detect.pressKey("enter");
// wait for program to finish
await detect.waitForFinish();
const lines = detect.getStdout();
// check that detect excited successfully
expect(detect.getExitCode()).toEqual(0);
// Detected extensions
expect(lines.findIndex((line) => line.includes("ERC721"))).toBeGreaterThan(
-1,
@@ -86,9 +84,6 @@ describe("npx thirdweb detect", () => {
lines.findIndex((line) => line.includes("- ERC721SignatureMint")),
).toBeGreaterThan(-1);
// the process should exit with code 0
expect(detect.getExitCode()).toEqual(0);
await cleanup(); // cleanup after test
});
});
+2 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.10.22",
"version": "0.10.26",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -47,6 +47,7 @@
"got": "11.8.5",
"inquirer": "^8.2.3",
"js-yaml": "^4.1.0",
"node-fetch": "^3.3.1",
"open": "^8.4.0",
"prompts": "^2.4.2",
"rimraf": "^3.0.2",
+4 -15
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env node
import { detectExtensions } from "../common/feature-detector";
import { detectProjectV2 } from "../common/project-detector-v2";
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";
@@ -9,7 +9,6 @@ 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/command";
import { upload } from "../storage/command";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import chalk from "chalk";
@@ -18,6 +17,7 @@ import { Command } from "commander";
import open from "open";
import prompts from "prompts";
import Cache from "sync-disk-cache";
import { install } from "../install";
const main = async () => {
// eslint-disable-next-line turbo/no-undeclared-env-vars
@@ -204,6 +204,7 @@ 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);
});
@@ -398,25 +399,13 @@ const main = async () => {
program
.command("detect")
.description(
"(deprecated) Compile contracts and detect implemented thirdweb contract extensions",
)
.option("-p, --path <project-path>", "path to project", ".")
.option("-d, --debug", "show debug logs")
.option("-a, --all", "run detection on all contracts")
.action(async (options) => {
await detectExtensions(options);
});
program
.command("detect-project")
.description(
"Detect the type of project your are running and let you know what it is.",
)
.option("-p, --path <project-path>", "path to project", ".")
.option("-d, --debug", "show debug logs")
.action(async (options) => {
await detectProjectV2(options);
await detectProject(options);
});
program
@@ -1,48 +0,0 @@
import detectPackageManager from "../core/detection/detectPackageManager";
import detectFramework from "../core/detection/detectFramework";
import detectLibrary from "../core/detection/detectLibrary";
import detectLanguage from "../core/detection/detectLanguage";
import { logger } from "../core/helpers/logger";
import path from "path";
import { ContractLibrariesType, contractLibraries } from "../core/types/ProjectType";
export async function detectProjectV2(options: any) {
logger.setSettings({
minLevel: options.debug ? "debug" : "info",
});
let projectPath = process.cwd();
if (options.path) {
logger.debug("Overriding project path to " + options.path);
const resolvedPath = (options.path as string).startsWith("/")
? options.path
: path.resolve(`${projectPath}/${options.path}`);
projectPath = resolvedPath;
}
logger.debug("Processing project at path " + projectPath);
const detectedPackageManager = await detectPackageManager(
projectPath,
options,
);
const detectedLanguage = await detectLanguage(projectPath, options);
const detectedLibrary = await detectLibrary(
projectPath,
options,
detectedPackageManager,
);
const detectedFramework = await detectFramework(
projectPath,
options,
detectedPackageManager,
);
const detectedAppType = contractLibraries.includes(detectedFramework as ContractLibrariesType) ? "contract" : "app";
logger.debug("Detected package manager: " + detectedPackageManager);
logger.debug("Detected library: " + detectedLibrary);
logger.debug("Detected language: " + detectedLanguage);
logger.debug("Detected framework: " + detectedFramework);
logger.debug("Detected app type: " + detectedAppType);
}
+136 -111
View File
@@ -1,17 +1,20 @@
import { ALWAYS_SUGGESTED } from "../constants/features";
import build from "../core/builder/build";
import detect from "../core/detection/detect";
import detectPackageManager from "../core/detection/detectPackageManager";
import detectFramework from "../core/detection/detectFramework";
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 { FeatureWithEnabled, detectFeatures } from "@thirdweb-dev/sdk";
import chalk from "chalk";
import ora from "ora";
import { ContractPayload } from "../core/interfaces/ContractPayload";
import { createContractsPrompt } from "../core/helpers/selector";
import { ContractFeatures, Feature } from "../core/interfaces/ContractFeatures";
import { ContractPayload } from "../core/interfaces/ContractPayload";
import { getPkgManager } from "../create/helpers/get-pkg-manager";
import { detectFeatures, FeatureWithEnabled } from "@thirdweb-dev/sdk";
import chalk from "chalk";
import { existsSync, readFileSync } from "fs";
import ora from "ora";
import path from "path";
import { getPkgManager } from "../create/helpers/get-pkg-manager";
import { ALWAYS_SUGGESTED } from "../constants/features";
import build from "../core/builder/build";
export async function detectProject(options: any) {
logger.setSettings({
@@ -30,115 +33,137 @@ export async function detectProject(options: any) {
logger.debug("Processing project at path " + projectPath);
const packageManagerType = await detectPackageManager(projectPath, options);
console.log(packageManagerType);
const projectType = await detect(projectPath, options);
let compiledResult;
const compileLoader = spinner("Compiling project...");
try {
compiledResult = await build(projectPath, projectType, options);
} catch (e) {
compileLoader.fail("Compilation failed");
logger.error(e);
process.exit(1);
}
compileLoader.succeed("Compilation successful");
let selectedContracts: ContractPayload[] = [];
if (compiledResult.contracts.length === 1) {
selectedContracts = [compiledResult.contracts[0]];
} else {
if (options.all) {
selectedContracts = compiledResult.contracts;
} else {
const choices = compiledResult.contracts.map((c) => ({
name: c.name,
value: c,
}));
const prompt = createContractsPrompt(
choices,
"Choose which contracts to run detection on",
);
const selection: Record<string, ContractPayload> = await prompt.run();
selectedContracts = Object.keys(selection).map((key) => selection[key]);
}
}
let contractsWithFeatures: ContractFeatures[] = selectedContracts.map(
(contract) => {
const abi: Parameters<typeof detectFeatures>[0] = JSON.parse(
contract.metadata,
)["output"]["abi"];
const features = extractFeatures(detectFeatures(abi));
const enabledFeatures: Feature[] = features.enabledFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
const suggestedFeatures: Feature[] = features.suggestedFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
return {
name: contract.name,
enabledFeatures,
suggestedFeatures,
};
},
const detectedPackageManager = await detectPackageManager(
projectPath,
options,
);
const detectedLanguage = await detectLanguage(projectPath, options);
const detectedLibrary = await detectLibrary(
projectPath,
options,
detectedPackageManager,
);
const detectedFramework = await detectFramework(
projectPath,
options,
detectedPackageManager,
);
const detectedAppType = detectedFramework !== "none" ? contractLibraries.includes(detectedFramework as ContractLibrariesType) ? "contract" : "app" : "app";
const detectedContractLibrary = detectedAppType === "contract" ? detectedFramework as ContractLibrariesType : "none";
contractsWithFeatures.map((contractWithFeatures) => {
logger.info(`\n`);
if (contractWithFeatures.enabledFeatures.length === 0) {
ora(
`No extensions detected on ${chalk.blueBright(
contractWithFeatures.name,
)}`,
).stopAndPersist({ symbol: "🔎" });
} else {
ora(
`Detected extension on ${chalk.blueBright(contractWithFeatures.name)}`,
).stopAndPersist({ symbol: "🔎" });
contractWithFeatures.enabledFeatures.map((feature) => {
logger.info(`✔️ ${chalk.green(feature.name)}`);
});
logger.info("Detected package manager: " + detectedPackageManager);
logger.info("Detected library: " + detectedLibrary);
logger.info("Detected language: " + detectedLanguage);
logger.info("Detected framework: " + detectedFramework);
logger.info("Detected app type: " + detectedAppType);
if (detectedAppType === "contract") {
let compiledResult;
const compileLoader = spinner("Compiling project...");
try {
compiledResult = await build(projectPath, detectedContractLibrary, options);
} catch (e) {
compileLoader.fail("Compilation failed");
logger.error(e);
process.exit(1);
}
logger.info(``);
ora(`Suggested extensions`).info();
contractWithFeatures.suggestedFeatures.map((feature) => {
logger.info(
`${chalk.dim(chalk.gray(`-`))} ${chalk.gray(
feature.name,
)} - ${chalk.dim(chalk.gray(feature.reference))}`,
);
});
compileLoader.succeed("Compilation successful");
let deployCmd = `npx thirdweb@latest deploy`;
if (existsSync(projectPath + "/package.json")) {
const packageManager = getPkgManager();
const useYarn = packageManager === "yarn";
const pkgJson = JSON.parse(
readFileSync(projectPath + "/package.json", "utf-8"),
);
if (pkgJson?.scripts?.deploy === deployCmd) {
deployCmd = `${packageManager}${useYarn ? "" : " run"} deploy`;
let selectedContracts: ContractPayload[] = [];
if (compiledResult.contracts.length === 1) {
selectedContracts = [compiledResult.contracts[0]];
} else {
if (options.all) {
selectedContracts = compiledResult.contracts;
} else {
const choices = compiledResult.contracts.map((c) => ({
name: c.name,
value: c,
}));
const prompt = createContractsPrompt(
choices,
"Choose which contracts to run detection on",
);
const selection: Record<string, ContractPayload> = await prompt.run();
selectedContracts = Object.keys(selection).map((key) => selection[key]);
}
}
logger.info(``);
ora(
`Once you're done writing your contracts, you can run the following command to deploy them:`,
).info();
logger.info(``);
logger.info(` ${chalk.cyan(deployCmd)}`);
logger.info(``);
});
let contractsWithFeatures: ContractFeatures[] = selectedContracts.map(
(contract) => {
const abi: Parameters<typeof detectFeatures>[0] = JSON.parse(
contract.metadata,
)["output"]["abi"];
const features = extractFeatures(detectFeatures(abi));
const enabledFeatures: Feature[] = features.enabledFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
const suggestedFeatures: Feature[] = features.suggestedFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
return {
name: contract.name,
enabledFeatures,
suggestedFeatures,
};
},
);
contractsWithFeatures.map((contractWithFeatures) => {
logger.info(`\n`);
if (contractWithFeatures.enabledFeatures.length === 0) {
ora(
`No extensions detected on ${chalk.blueBright(
contractWithFeatures.name,
)}`,
).stopAndPersist({ symbol: "🔎" });
} else {
ora(
`Detected extension on ${chalk.blueBright(contractWithFeatures.name)}`,
).stopAndPersist({ symbol: "🔎" });
contractWithFeatures.enabledFeatures.map((feature) => {
logger.info(`✔️ ${chalk.green(feature.name)}`);
});
}
logger.info(``);
ora(`Suggested extensions`).info();
contractWithFeatures.suggestedFeatures.map((feature) => {
logger.info(
`${chalk.dim(chalk.gray(`-`))} ${chalk.gray(
feature.name,
)} - ${chalk.dim(chalk.gray(feature.reference))}`,
);
});
let deployCmd = `npx thirdweb@latest deploy`;
if (existsSync(projectPath + "/package.json")) {
const packageManager = getPkgManager();
const useYarn = packageManager === "yarn";
const pkgJson = JSON.parse(
readFileSync(projectPath + "/package.json", "utf-8"),
);
if (pkgJson?.scripts?.deploy === deployCmd) {
deployCmd = `${packageManager}${useYarn ? "" : " run"} deploy`;
}
}
logger.info(``);
ora(
`Once you're done writing your contracts, you can run the following command to deploy them:`,
).info();
logger.info(``);
logger.info(` ${chalk.cyan(deployCmd)}`);
logger.info(``);
});
}
}
function extractFeatures(
@@ -29,7 +29,6 @@ export default async function detect(
options: any,
detectedPackageManager: PackageManagerType,
): Promise<FrameworkType> {
// We could optimize further if we want, by only running the detectors that match the package manager.
const frameworkDetectors: FrameworkDetector[] = [
new BrownieDetector(),
new CRADetector(),
@@ -66,6 +65,10 @@ export default async function detect(
return possibleFrameworks[0];
}
if (possibleFrameworks.includes("expo") && possibleFrameworks.includes("react-native-cli")) {
return "expo";
}
info(
`Detected multiple possible frameworks: ${possibleFrameworks
.map((s) => `"${s}"`)
@@ -30,6 +30,10 @@ export default async function detect(
return possibleLanguages[0];
}
if (possibleLanguages.includes("typescript") && possibleLanguages.includes("javascript")) {
return "typescript";
}
info(
`Detected multiple possible languages: ${possibleLanguages
.map((s) => `"${s}"`)
@@ -36,6 +36,10 @@ export default async function detect(
return possibleLibraries[0];
}
if (possibleLibraries.includes("react-native") && possibleLibraries.includes("react")) {
return "react-native";
}
info(
`Detected multiple possible libraries: ${possibleLibraries
.map((s) => `"${s}"`)
@@ -5,10 +5,12 @@ import inquirer from "inquirer";
import NPMDetector from "./packageManagers/npm";
import YarnDetector from "./packageManagers/yarn";
import PnpmDetector from "./packageManagers/pnpm";
import CondaDetector from "./packageManagers/conda";
import PipDetector from "./packageManagers/pip";
import PipEnvDetector from "./packageManagers/pipenv";
import PoetryDetector from "./packageManagers/poetry";
import BrownieDetector from "./packageManagers/brownie";
import FoundryDetector from "./packageManagers/foundry";
import GoModulesDetector from "./packageManagers/goModules";
export default async function detect(
path: string,
@@ -18,14 +20,18 @@ export default async function detect(
new NPMDetector(),
new YarnDetector(),
new PnpmDetector(),
new CondaDetector(),
new PipDetector(),
new PipEnvDetector(),
new PoetryDetector(),
new GoModulesDetector(),
new BrownieDetector(),
new FoundryDetector(),
];
const possiblePackageManagers = packageManagerDetectors
.filter((detector) => detector.matches(path))
.filter((detector) => {
return detector.matches(path);
})
.map((detector) => detector.packageManagerType);
if (!possiblePackageManagers.length) {
@@ -36,6 +42,10 @@ export default async function detect(
return possiblePackageManagers[0];
}
if (possiblePackageManagers.includes("brownie") && possiblePackageManagers.includes("pip")) {
return "brownie";
}
info(
`Detected multiple possible package managers: ${possiblePackageManagers
.map((s) => `"${s}"`)
@@ -20,10 +20,16 @@ export default class BrownieDetector implements FrameworkDetector {
existsSync(path + file),
);
const additionalDirectoriesToCheck = ["/build", "/contracts", "/reports"];
const additionalDirectoriesExist = additionalDirectoriesToCheck.every((dir) => {
return existsSync(path + dir);
});
return (
dependencies.includes("brownie") ||
devDependencies.includes("brownie") ||
!!dependencies.find(dep => dep.includes("brownie")) ||
!!devDependencies.find(dep => dep.includes("brownie")) ||
additionalFilesExist ||
additionalDirectoriesExist ||
false
);
}
@@ -16,8 +16,8 @@ export default class CRADetector implements FrameworkDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const craDependencyExists =
dependencies["react-scripts"] ||
devDependencies["react-scripts"] ||
!!dependencies["react-scripts"] ||
!!devDependencies["react-scripts"] ||
false;
return craDependencyExists;
@@ -18,8 +18,8 @@ export default class DjangoDetector implements FrameworkDetector {
);
return (
dependencies.includes("django") ||
devDependencies.includes("django") ||
!!dependencies.find(dep => dep.includes("Django")) ||
!!devDependencies.find(dep => dep.includes("Django")) ||
additionalFilesExist ||
false
);
@@ -16,14 +16,14 @@ export default class ExpoDetector implements FrameworkDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const additionalFilesToCheck = ["/app.json", "/app.config.js", "/assets"];
const additionalFilesToCheck = ["/app.json", "/app.config.js"];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
const expoDependencyExists =
dependencies["expo"] ||
devDependencies["expo"] ||
!!dependencies["expo"] ||
!!devDependencies["expo"] ||
additionalFilesExist ||
false;
@@ -12,14 +12,14 @@ export default class FastAPIDetector implements FrameworkDetector {
packageManager,
);
const additionalFilesToCheck = ["/app.py", "/main.py"];
const additionalFilesToCheck: string[] = [];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
return (
dependencies.includes("fastapi") ||
devDependencies.includes("fastapi") ||
!!dependencies.find(dep => dep.includes("fastapi")) ||
!!devDependencies.find(dep => dep.includes("fastapi")) ||
additionalFilesExist ||
false
);
@@ -16,19 +16,14 @@ export default class FastifyDetector implements FrameworkDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const additionalFilesToCheck = [
"/server.js",
"/app.js",
"/server.ts",
"/app.ts",
];
const additionalFilesToCheck: string[] = [];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
const fastifyDependencyExists =
dependencies["fastify"] ||
devDependencies["fastify"] ||
!!dependencies["fastify"] ||
!!devDependencies["fastify"] ||
additionalFilesExist ||
false;
@@ -12,14 +12,14 @@ export default class FlaskDetector implements FrameworkDetector {
packageManager,
);
const additionalFilesToCheck = ["/app.py", "/application.py"];
const additionalFilesToCheck: string[] = [];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
return (
dependencies.includes("flask") ||
devDependencies.includes("flask") ||
!!dependencies.find(dep => dep.includes("Flask")) ||
!!devDependencies.find(dep => dep.includes("Flask")) ||
additionalFilesExist ||
false
);
@@ -22,8 +22,8 @@ export default class GatsbyDetector implements FrameworkDetector {
);
const gatsbyDependencyExists =
dependencies["gatsby"] ||
devDependencies["gatsby"] ||
!!dependencies["gatsby"] ||
!!devDependencies["gatsby"] ||
additionalFilesExist ||
false;
@@ -16,14 +16,14 @@ export default class HardhatDetector implements FrameworkDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const additionalFilesToCheck = ["/hardhat.config.js", "/contracts/"];
const additionalFilesToCheck = ["/hardhat.config.js"];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
const hardhatDependencyExists =
dependencies["hardhat"] ||
devDependencies["hardhat"] ||
!!dependencies["hardhat"] ||
!!devDependencies["hardhat"] ||
additionalFilesExist ||
false;
@@ -22,8 +22,8 @@ export default class NextDetector implements FrameworkDetector {
);
const nextDependencyExists =
dependencies["next"] ||
devDependencies["next"] ||
!!dependencies["next"] ||
!!devDependencies["next"] ||
additionalFilesExist ||
false;
@@ -18,8 +18,8 @@ export default class PopulusDetector implements FrameworkDetector {
);
return (
dependencies.includes("populus") ||
devDependencies.includes("populus") ||
!!dependencies.find(dep => dep === "populus") ||
!!devDependencies.find(dep => dep === "populus") ||
additionalFilesExist ||
false
);
@@ -16,14 +16,14 @@ export default class ReactNativeCLIDetector implements FrameworkDetector {
const packageJson = readFileSync(packageJsonPath);
const { dependencies, devDependencies } = parsePackageJson(packageJson);
const additionalFilesToCheck = ["/android", "/ios"];
const additionalFilesToCheck: string[] = [];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
return (
dependencies["react-native"] ||
devDependencies["react-native"] ||
!!dependencies["react-native"] ||
!!devDependencies["react-native"] ||
additionalFilesExist ||
false
);
@@ -19,15 +19,14 @@ export default class TruffleDetector implements FrameworkDetector {
const additionalFilesToCheck = [
"/truffle.config.js",
"/truffle.js",
"/contracts/",
];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
return (
dependencies["truffle"] ||
devDependencies["truffle"] ||
!!dependencies["truffle"] ||
!!devDependencies["truffle"] ||
additionalFilesExist ||
false
);
@@ -22,8 +22,8 @@ export default class VueDetector implements FrameworkDetector {
);
return (
dependencies["vue"] ||
devDependencies["vue"] ||
!!dependencies["vue"] ||
!!devDependencies["vue"] ||
additionalFilesExist ||
false
);
@@ -12,7 +12,7 @@ export default class Web3PyDetector implements LibraryDetector {
);
return (
dependencies.includes("web3") || devDependencies.includes("web3") || false
!!dependencies.find(dep => dep.includes("web3")) || !!devDependencies.find(dep => dep.includes("web3")) || false
);
}
}
@@ -0,0 +1,30 @@
import { PackageManagerDetector } from "../detector";
import { existsSync } from "fs";
import { PackageManagerType } from "../../types/ProjectType";
export default class BrownieDetector implements PackageManagerDetector {
public packageManagerType: PackageManagerType = "brownie";
public matches(path: string): boolean {
const additionalFilesToCheck = [
"/brownie-config.yaml",
"/brownie-config.json",
];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
// Check that all of these exist.
const additionalDirectoriesToCheck = ["/build", "/contracts", "/reports"];
const additionalDirectoriesExist = additionalDirectoriesToCheck.every((dir) => {
return existsSync(path + dir);
});
return (
additionalFilesExist ||
additionalDirectoriesExist ||
false
);
}
}
@@ -1,20 +0,0 @@
import { PackageManagerDetector } from "../detector";
import { existsSync } from "fs";
import { PackageManagerType } from "../../types/ProjectType";
export default class CondaDetector implements PackageManagerDetector {
public packageManagerType: PackageManagerType = "conda";
public matches(path: string): boolean {
const files = [
"/environment.yml",
"/environment.yaml",
"/conda-requirements.txt",
"/.conda",
"/.condarc",
];
// Check if at least one of these files exists in the current path.
return files.some((file) => existsSync(path + file));
}
}
@@ -0,0 +1,16 @@
import { PackageManagerType } from "../../types/ProjectType";
import { PackageManagerDetector } from "../detector";
import { existsSync } from "fs";
export default class FoundryDetector implements PackageManagerDetector {
public packageManagerType: PackageManagerType = "foundry";
public matches(path: string): boolean {
const additionalFilesToCheck = ["/foundry.toml", "/lib/forge-std/"];
const additionalFilesExist = additionalFilesToCheck.some((file) =>
existsSync(path + file),
);
return additionalFilesExist || false;
}
}
+4 -4
View File
@@ -18,10 +18,11 @@ export type PackageManagerType =
| "npm"
| "pnpm"
| "pip"
| "conda"
| "pipenv"
| "poetry"
| "go-modules"
| "brownie"
| "foundry"
| "none";
export type LanguageType =
| "javascript"
@@ -59,14 +60,13 @@ export type FrameworkType =
export type LibraryType =
| "react"
| "react-native"
| "vue"
| "svelte"
| "vite"
| "express"
| "web3py"
| "playmaker"
| "none";
export type AppType = "app" | "contract" | "library" | "none";
export type AppType = "app" | "contract" | "none";
export type ContractLibrariesType =
| "brownie"
| "foundry"
@@ -83,4 +83,4 @@ export const contractLibraries: readonly ContractLibrariesType[] = [
"truffle",
"solc",
"none",
] as const;
] as const;
+12 -6
View File
@@ -1,4 +1,4 @@
import spawn from "cross-spawn";
import { spawn } from "cross-spawn";
export async function runCommand(
command: string,
@@ -9,8 +9,9 @@ export async function runCommand(
return new Promise<void>((resolve, reject) => {
/**
* Spawn the installation process.
*/
*/
const child = spawn(command, args);
child.stdout?.on("data", (data) => {
if (onData) {
onData(data);
@@ -20,17 +21,22 @@ export async function runCommand(
}
});
child.stderr?.on("error", (err) => {
child.stderr?.on("data", (data) => {
if (logging) {
console.error(err);
console.error(data.toString());
}
});
child.on("error", (err) => {
console.log("Spawn error", err)
});
child.on("close", (code) => {
if (code !== 0) {
reject({ command: `${command}` });
reject({ command: `${command}`, exitCode: code });
return;
}
resolve();
});
});
}
}
+2 -2
View File
@@ -197,8 +197,8 @@ export async function generate(options: GenerateOptions) {
const postinstall = packageJson.scripts?.postinstall
? packageJson.scripts.postinstall +
` && export THIRDWEB_CLI_SKIP_INTRO=true && npx thirdweb generate --skip-update-check`
: `export THIRDWEB_CLI_SKIP_INTRO=true && npx thirdweb generate --skip-update-check`;
` && export THIRDWEB_CLI_SKIP_INTRO=true && npx --yes thirdweb@latest generate`
: `export THIRDWEB_CLI_SKIP_INTRO=true && npx --yes thirdweb@latest generate`;
fs.writeFileSync(
packageJsonPath,
-159
View File
@@ -1,159 +0,0 @@
import BrownieDetector from "../core/detection/brownie";
import CRADetector from "../core/detection/cra";
import FoundryDetector from "../core/detection/foundry";
import HardhatDetector from "../core/detection/hardhat";
import NextDetector from "../core/detection/next";
import NPMDetector from "../core/detection/npm";
import SolcDetector from "../core/detection/solc";
import TruffleDetector from "../core/detection/truffle";
import ViteDetector from "../core/detection/vite";
import YarnDetector from "../core/detection/yarn";
import { runCommand } from "../create/helpers/run-command";
import fs from "fs";
import ora from "ora";
import { info } from "../core/helpers/logger";
const EXCLUDED_DEPENDENCIES = ["@thirdweb-dev/chain-icons"];
export async function install(projectPath = ".", options: any) {
const supportedContractFrameworks = [
new BrownieDetector(),
new FoundryDetector(),
new HardhatDetector(),
new TruffleDetector(),
new SolcDetector(),
].filter((detector) => detector.matches(projectPath));
const supportedAppFrameworks = [
new ViteDetector(),
new NextDetector(),
new CRADetector(),
].filter((detector) => detector.matches(projectPath));
const hasYarn = new YarnDetector().matches(".");
const hasNPM = new NPMDetector().matches(".");
let packageJson;
try {
packageJson = JSON.parse(
fs.readFileSync(projectPath + "/package.json", "utf8"),
);
} catch (e) {
console.error(
"No package.json file found. Please run this command in the root of your project.",
);
return;
}
const hasEthers =
!!packageJson?.dependencies?.ethers ||
!!packageJson?.devDependencies?.ethers;
const version = options.dev
? "@dev"
: options.nightly
? "@nightly"
: "@latest";
if (
supportedAppFrameworks.length === 0 &&
supportedContractFrameworks.length === 0
) {
throw new Error("No supported project detected");
}
const thirdwebDepsToUpdate = new Set<string>([
...Object.keys(packageJson.dependencies || {}).filter((dep) =>
dep.startsWith("@thirdweb-dev/"),
),
...Object.keys(packageJson.devDependencies || {}).filter((dep) =>
dep.startsWith("@thirdweb-dev/"),
),
...Object.keys(packageJson.peerDependencies || {}).filter((dep) =>
dep.startsWith("@thirdweb-dev/"),
),
]);
const thirdwebDepsToInstall = new Set<string>();
const otherDeps = new Set<string>();
// only expect one contract framework to be detected
const contractFramework = supportedContractFrameworks[0];
// only expect one app framework to be detected
const appFramerwork = supportedAppFrameworks[0];
if (contractFramework) {
info(`Detected project: "${contractFramework.projectType}"`);
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/contracts`)) {
thirdwebDepsToInstall.add(`@thirdweb-dev/contracts`);
}
} else if (appFramerwork) {
info(`Detected project: "${appFramerwork.projectType}"`);
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react`)) {
thirdwebDepsToInstall.add(`@thirdweb-dev/react`);
}
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/sdk`)) {
thirdwebDepsToInstall.add(`@thirdweb-dev/sdk`);
}
if (!hasEthers) {
otherDeps.add("ethers@5");
}
}
// remove exluded dependencies
EXCLUDED_DEPENDENCIES.forEach((excludedDep) => {
thirdwebDepsToUpdate.delete(excludedDep);
thirdwebDepsToInstall.delete(excludedDep);
});
let installer;
let updater;
try {
if (thirdwebDepsToInstall.size !== 0) {
installer = ora(
`Installing: "${[...thirdwebDepsToInstall].join('", "')}"`,
).start();
}
if (thirdwebDepsToUpdate.size !== 0) {
updater = ora(
`Updating: "${[...thirdwebDepsToUpdate].join('", "')}"`,
).start();
}
const dependenciesToAdd = [
...[...thirdwebDepsToInstall].map((dep) => `${dep}${version}`),
...otherDeps,
];
const dependenciesToUpdate = [...thirdwebDepsToUpdate].map(
(dep) => `${dep}${version}`,
);
if (hasYarn) {
if (dependenciesToAdd.length !== 0) {
await runCommand("yarn", ["add", ...dependenciesToAdd]);
installer?.succeed(`Installed: "${dependenciesToAdd.join('", "')}"`);
}
if (dependenciesToUpdate.length !== 0) {
await runCommand("yarn", ["upgrade", ...dependenciesToUpdate]);
updater?.succeed(`Updated: "${dependenciesToUpdate.join('", "')}"`);
}
} else if (hasNPM) {
if (dependenciesToAdd.length !== 0) {
await runCommand("npm", ["install", ...dependenciesToAdd]);
installer?.succeed(`Installed: "${dependenciesToAdd.join('", "')}"`);
}
if (dependenciesToUpdate.length !== 0) {
await runCommand("npm", ["update", ...dependenciesToUpdate]);
updater?.succeed(`Updated: "${dependenciesToUpdate.join('", "')}"`);
}
}
} catch (err) {
console.error("Can't install within project");
return Promise.reject("Can't install within project");
}
}
+235
View File
@@ -0,0 +1,235 @@
// 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");
}
}
+20
View File
@@ -0,0 +1,20 @@
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;
detectedFramework: FrameworkType;
thirdwebDepsToUpdate: Set<string>;
thirdwebDepsToInstall: Set<string>;
isJSPackageManager: boolean;
isPythonPackageManager: boolean;
isGoPackageManager: boolean;
hasEthers: boolean;
otherDeps: Set<string>;
}
+277 -37
View File
@@ -1,14 +1,40 @@
import * as toml from "@iarna/toml";
import * as yaml from "js-yaml";
import { PackageManagerType } from "../core/types/ProjectType";
import { existsSync, readFileSync } from "fs";
import path from "path";
import { PackageManagerType } from "../core/types/ProjectType";
import { runCommand } from "../create/helpers/run-command";
import { IProcessAppTypeArgs, IProcessContractAppTypeArgs } from "./types";
export const parsePackageJson = (packageJson: Buffer) => {
export function convertDependenciesToStringFormat(dependenciesObject: object) {
return Object.entries(dependenciesObject).map(([pkg, versionDetails]) => {
let version = '';
if (typeof versionDetails === 'string') {
version = versionDetails;
} else if (typeof versionDetails === 'object') {
version = versionDetails.version;
}
// Replace '^' with nothing as '^' is not a valid version specifier in Python
version = version.replace('^', '');
return `${pkg}==${version}`;
});
}
export const parsePackageJson = (packageJson: Buffer): {
dependencies: {
[key: string]: string;
};
devDependencies: {
[key: string]: string;
};
peerDependencies: {
[key: string]: string;
};
} => {
const packageJsonContent = JSON.parse(packageJson.toString());
const dependencies = packageJsonContent.dependencies || {};
const devDependencies = packageJsonContent.devDependencies || {};
return { dependencies, devDependencies };
const peerDependencies = packageJsonContent.peerDependencies || {};
return { dependencies, devDependencies, peerDependencies };
};
export const parseRequirementsTxt = (requirementsTxt: Buffer) => {
@@ -30,20 +56,13 @@ export const parsePipFile = (PipFile: string) => {
export const parsePyProjectToml = (pyProjectToml: string) => {
const pyProjectFile = toml.parse(pyProjectToml) as any;
const dependencies =
(pyProjectFile["tool"]["poetry"]["dependencies"] as string[]) || [];
(pyProjectFile["tool"]["poetry"]["dependencies"]) || [];
const devDependencies =
(pyProjectFile["tool"]["poetry"]["dev-dependencies"] as string[]) || [];
return {
dependencies,
devDependencies,
};
};
(pyProjectFile["tool"]["poetry"]["dev-dependencies"]) || [];
export const parseCondaYml = (condaYml: string) => {
const conda = yaml.load(condaYml) as any;
const dependencies = (conda.dependencies as string[]) || [];
return {
dependencies,
dependencies: convertDependenciesToStringFormat(dependencies),
devDependencies: convertDependenciesToStringFormat(devDependencies),
};
};
@@ -82,44 +101,43 @@ export const fileContainsImport = (file: string, importToCheck: string) => {
};
export const getDependenciesForPython = (
path: string,
filePath: string,
packageManager: PackageManagerType,
) => {
let dependencies: string[] = [];
let devDependencies: string[] = [];
switch (packageManager) {
case "pip" || "pipenv":
const foundPipFile = existsSync(path + "Pipfile");
if (foundPipFile) {
const pipFile = readFileSync(path + "Pipfile", "utf-8");
const parsedPipFile = parsePipFile(pipFile);
dependencies = parsedPipFile.dependencies;
devDependencies = parsedPipFile.devDependencies;
break;
}
const foundRequirementsTxt = existsSync(path + "/requirements.txt");
case "pip":
const foundRequirementsTxt = existsSync(filePath + "/requirements.txt");
if (!foundRequirementsTxt) {
// Create a temporary requirements.txt file
// runCommand("pip", ["freeze"], true, undefined, "requirements.txt");
break;
}
const requirementsTxt = readFileSync(path + "/requirements.txt");
const requirementsTxt = readFileSync(filePath + "/requirements.txt");
dependencies = parseRequirementsTxt(requirementsTxt).dependencies;
// Delete file now that we're done with it
// runCommand("rm", ["requirements.txt"], true);
break;
case "pipenv":
const foundPipFile = existsSync(filePath + "Pipfile");
if (!foundPipFile) {
break;
}
const pipFile = readFileSync(filePath + "Pipfile", "utf-8");
const parsedPipFile = parsePipFile(pipFile);
dependencies = parsedPipFile.dependencies;
devDependencies = parsedPipFile.devDependencies;
break;
case "poetry":
const foundPyProjectToml = existsSync(path + "/pyproject.toml");
const foundPyProjectToml = existsSync(filePath + "/pyproject.toml");
if (!foundPyProjectToml) {
break;
}
const pyProjectFile = readFileSync(path + "/pyproject.toml", "utf-8");
const pyProjectFile = readFileSync(filePath + "/pyproject.toml", "utf-8");
dependencies = parsePyProjectToml(pyProjectFile).dependencies;
break;
case "conda":
const foundCondaYml = existsSync(path + "/environment.yml");
if (!foundCondaYml) {
break;
}
const condaYml = readFileSync(path + "/environment.yml", "utf-8");
dependencies = parseCondaYml(condaYml).dependencies;
default:
break;
}
@@ -129,3 +147,225 @@ export const getDependenciesForPython = (
devDependencies,
};
};
export const getLatestVersion = async (packageName: string): Promise<any> => {
try {
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'];
} 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 }) => {
let runner: string = "";
let installCommand: string[] = [];
let updateCommand: string[] = [];
let deleteCommand: string[] = [];
let printLogs = options?.debug || false;
switch (packageManager) {
case "npm":
runner = "npm";
installCommand = ["install"];
updateCommand = ["install", "--legacy-peer-deps"]
break;
case "yarn":
runner = "yarn";
installCommand = ["add"];
updateCommand = ["add"];
break;
case "pnpm":
runner = "pnpm";
installCommand = ["install"];
updateCommand = ["update"];
break;
case "pip":
runner = "pip";
installCommand = ["install"];
updateCommand = ["install", "--upgrade"];
break;
case "pipenv":
runner = "pipenv";
installCommand = ["install"];
updateCommand = ["update"];
break;
case "poetry":
runner = "poetry";
installCommand = ["add"];
updateCommand = ["update"];
break;
case "go-modules":
runner = "go";
installCommand = ["get"];
updateCommand = ["get", "-u"];
break;
case "brownie":
runner = "brownie";
installCommand = ["pm", "install"]
updateCommand = ["pm", "update"]
deleteCommand = ["pm", "delete"]
break;
case "foundry":
runner = "forge";
installCommand = ["install", "--no-commit"];
updateCommand = ["update"];
deleteCommand = ["remove"];
break;
default:
break;
}
if (typeOfAction === "install") {
if (!dependenciesToAdd.length) { return; }
const commands = [...installCommand, ...dependenciesToAdd];
await runCommand(runner, commands, printLogs);
if (options?.oldVersion) {
await runCommand(runner, [...deleteCommand, options.oldVersion], printLogs);
}
}
if (typeOfAction === "update") {
if (!dependenciesToUpdate.length) { return; }
const commands = [...updateCommand, ...dependenciesToUpdate];
await runCommand(runner, commands, printLogs);
}
};
export const checkIfBrowniePackageIsInstalled = async (regex: RegExp) => {
const deps = await getDependenciesForBrownie();
const match = deps.match(regex);
if (match !== null) {
const packageAndVersion = match[0];
return {
package: packageAndVersion,
exists: true,
};
}
return {
package: "",
exists: false,
};
};
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, '');
return deps;
};
export const getDependenciesForFoundry = async (filePath: string, libName: string) => {
const fullPath = path.join(filePath, "lib", libName);
return existsSync(fullPath);
};
type GoModule = {
name: string;
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
const name = words[1].trim();
const version = words[2];
modules.push({ name, version });
}
}
return modules;
}
export const processContractAppType = async (args: IProcessContractAppTypeArgs): Promise<void> => {
const { detectedPackageManager, thirdwebDepsToUpdate, thirdwebDepsToInstall, isJSPackageManager } = args;
if (isJSPackageManager) {
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/contracts`)) {
thirdwebDepsToInstall.add(`@thirdweb-dev/contracts`);
}
}
if (detectedPackageManager === "brownie") {
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}`)) {
thirdwebDepsToInstall.add(`thirdweb-dev/contracts@${latestThirdwebContractVersion}`);
}
}
if (detectedPackageManager === "foundry") {
if (!thirdwebDepsToUpdate.has("lib/thirdweb-contracts")) {
thirdwebDepsToInstall.add("thirdweb-contracts=thirdweb-dev/contracts");
}
}
};
export const processAppType = async (args: IProcessAppTypeArgs): Promise<void> => {
const { detectedFramework, thirdwebDepsToUpdate, thirdwebDepsToInstall, hasEthers, isJSPackageManager, otherDeps, isPythonPackageManager, isGoPackageManager, detectedLibrary } = args;
const reactlibs = [
"react",
"react-native",
"next",
"gatsby",
"cra",
"remix",
"vue",
"vite",
"svelte",
]
const shouldInstallThirdwebReact = reactlibs.includes(detectedFramework as string);
const shouldInstallThirdwebReactNative = detectedLibrary === "react-native";
if (isJSPackageManager) {
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react`) && shouldInstallThirdwebReact) {
thirdwebDepsToInstall.add(`@thirdweb-dev/react`);
}
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/sdk`) && !shouldInstallThirdwebReactNative) {
thirdwebDepsToInstall.add(`@thirdweb-dev/sdk`);
}
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native`) && shouldInstallThirdwebReactNative) {
thirdwebDepsToInstall.add(`@thirdweb-dev/react-native`);
}
if (!thirdwebDepsToUpdate.has(`@thirdweb-dev/react-native-compat`) && shouldInstallThirdwebReactNative) {
thirdwebDepsToInstall.add(`@thirdweb-dev/react-native-compat`);
}
if (!hasEthers) {
otherDeps.add("ethers@5");
}
}
if (isPythonPackageManager) {
if (!thirdwebDepsToUpdate.has(`thirdweb-sdk`)) {
thirdwebDepsToInstall.add(`thirdweb-sdk`);
}
}
if (isGoPackageManager) {
if (!thirdwebDepsToUpdate.has("github.com/thirdweb-dev/go-sdk/v2")) {
thirdwebDepsToInstall.add("github.com/thirdweb-dev/go-sdk/v2");
}
}
};
+14
View File
@@ -1,5 +1,19 @@
# @thirdweb-dev/contracts-js
## 1.3.7
### Patch Changes
- [#1241](https://github.com/thirdweb-dev/js/pull/1241) [`9af346ee`](https://github.com/thirdweb-dev/js/commit/9af346eeada1037be27c8d3c9e1777f7be11a8ea) Thanks [@nkrishang](https://github.com/nkrishang)! - Use fn getAllAccounts instead of event logs AccountCreated
## 1.3.6
### Patch Changes
- [#1197](https://github.com/thirdweb-dev/js/pull/1197) [`e0ce4a37`](https://github.com/thirdweb-dev/js/commit/e0ce4a37596a91a072f8551e323fce6723113dcb) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Added Zora drop ABI
- [#1134](https://github.com/thirdweb-dev/js/pull/1134) [`990c665d`](https://github.com/thirdweb-dev/js/commit/990c665de9e5c1070dc80fe0f1b434e251f70a94) Thanks [@nkrishang](https://github.com/nkrishang)! - Introduce SmartWallet sdk class
## 1.3.5
### Patch Changes
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.3.5",
"version": "1.3.7",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"browser": {
@@ -10,7 +10,7 @@
"license": "Apache-2.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
"dependencies": {
"@thirdweb-dev/contracts": "3.5.5"
"@thirdweb-dev/contracts": "3.5.9"
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
@@ -41,7 +41,7 @@
"sideEffects": false,
"scripts": {
"clean": "rm -rf dist/",
"typechain": "rm -rf ./src && typechain --target ethers-v5 --out-dir src './node_modules/@thirdweb-dev/contracts/abi/*.json'",
"typechain": "rm -rf ./src && cp ./external_abis/*.json ./node_modules/@thirdweb-dev/contracts/abi && typechain --target ethers-v5 --out-dir src './node_modules/@thirdweb-dev/contracts/abi/*.json'",
"extract-abi": "node ./scripts/extract-abis.mjs",
"build": "pnpm typechain && tsc && pnpm preconstruct build && pnpm extract-abi",
"push": "yalc push"
@@ -9,15 +9,20 @@ import {
import { basename, join, resolve } from "path";
const main = () => {
const libFolder = resolve(
const sourceFolders = [];
sourceFolders.push(resolve(
"node_modules",
"@thirdweb-dev/contracts/abi",
);
));
sourceFolders.push(resolve(
"external_abis",
));
const destinationFolder = "./dist/abis";
if (existsSync(destinationFolder)) {
rmSync(destinationFolder, { recursive: true });
}
mkdirSync(destinationFolder);
for(const libFolder of sourceFolders) {
const abiFiles = readdirSync(libFolder);
for (const abiFile of abiFiles) {
const contractJsonFile = readFileSync(join(libFolder, abiFile), "utf-8");
@@ -28,6 +33,7 @@ const main = () => {
JSON.stringify(abi, null, 2),
);
}
}
};
main();

Some files were not shown because too many files have changed in this diff Show More