Compare commits
186
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
517e2a75e3 | ||
|
|
72692689e9 | ||
|
|
efc56fa580 | ||
|
|
564b17e760 | ||
|
|
b4507db963 | ||
|
|
f451da6395 | ||
|
|
ee47840767 | ||
|
|
bef97f72f4 | ||
|
|
3e87dd3ccb | ||
|
|
def42511ff | ||
|
|
c42545a647 | ||
|
|
6e20d1f21a | ||
|
|
e684d7e1ca | ||
|
|
f545a67e9f | ||
|
|
034a257442 | ||
|
|
1bfb91dbf3 | ||
|
|
5d95cbcdb2 | ||
|
|
639e535ed5 | ||
|
|
af3acc6b10 | ||
|
|
eca47763cd | ||
|
|
37b5bec897 | ||
|
|
48d91e4431 | ||
|
|
a20be881e3 | ||
|
|
47f8945325 | ||
|
|
1b0bf99da7 | ||
|
|
f03be398e0 | ||
|
|
27996cb4bc | ||
|
|
2eaa67acbe | ||
|
|
aafd7968df | ||
|
|
48797c7cf0 | ||
|
|
4edcb37100 | ||
|
|
83dcaf7058 | ||
|
|
b4e005be7f | ||
|
|
ccb7db4873 | ||
|
|
9151aa7dc8 | ||
|
|
5a01c537e3 | ||
|
|
f09c153ff7 | ||
|
|
15431621fd | ||
|
|
887af24450 | ||
|
|
15514f190a | ||
|
|
72589ec234 | ||
|
|
f8bceec10c | ||
|
|
7c0744a006 | ||
|
|
846022e2cf | ||
|
|
96bd92e724 | ||
|
|
c2b6d977ed | ||
|
|
7cb8e59be4 | ||
|
|
04a47e8971 | ||
|
|
8a6a97a3e9 | ||
|
|
612bcdd16f | ||
|
|
0ed77d2c9e | ||
|
|
7129aef6e1 | ||
|
|
f50b74819d | ||
|
|
3eba69afd7 | ||
|
|
98c2253e8f | ||
|
|
32d91ef709 | ||
|
|
b79dc18f7a | ||
|
|
4af785c37c | ||
|
|
6f818f393e | ||
|
|
97ed4779a9 | ||
|
|
2d3fca5237 | ||
|
|
7016019f2a | ||
|
|
4e7b293c54 | ||
|
|
c9c0e4ff39 | ||
|
|
06c24c153a | ||
|
|
aa6d9ed75d | ||
|
|
42a606588d | ||
|
|
2820761003 | ||
|
|
5200d5d7e7 | ||
|
|
e731c1a7c3 | ||
|
|
2e8d3fd6e7 | ||
|
|
cc4613b5fd | ||
|
|
78566babaa | ||
|
|
65fc7ba6ff | ||
|
|
1c24c3c3c4 | ||
|
|
408c5a81fa | ||
|
|
352291791e | ||
|
|
aabbb149e8 | ||
|
|
d59450f814 | ||
|
|
7d9a4c6abc | ||
|
|
99806e595d | ||
|
|
21c21c1adf | ||
|
|
4b10719047 | ||
|
|
989cf7347c | ||
|
|
72227b2e16 | ||
|
|
ed6c54f20d | ||
|
|
26116a6f63 | ||
|
|
f11a2719ff | ||
|
|
ef27aad0aa | ||
|
|
b03a902145 | ||
|
|
340605b507 | ||
|
|
15f8006e1f | ||
|
|
811c5a1166 | ||
|
|
c41a80d86d | ||
|
|
ad851f7b4d | ||
|
|
6218c88584 | ||
|
|
c9b564feaf | ||
|
|
87fd6ab14e | ||
|
|
df74340fa5 | ||
|
|
a57b4f01f3 | ||
|
|
126752d7d0 | ||
|
|
89ff921a7d | ||
|
|
9124b3180c | ||
|
|
f41a443c57 | ||
|
|
b7cd744cd0 | ||
|
|
bb1b4e6ac3 | ||
|
|
2f8ec89c4c | ||
|
|
6ae52664e5 | ||
|
|
4f867e15ed | ||
|
|
cc8f983615 | ||
|
|
f45ef62128 | ||
|
|
9727502eb3 | ||
|
|
b6eec6146c | ||
|
|
88daa3c5cb | ||
|
|
53c6507669 | ||
|
|
782b58d3f6 | ||
|
|
e17e41f4d1 | ||
|
|
712b11a43e | ||
|
|
306debb029 | ||
|
|
86f0ceff46 | ||
|
|
7f0d1ec947 | ||
|
|
b1218cbd7d | ||
|
|
97ef35ce0f | ||
|
|
1f46f270cd | ||
|
|
e8c25ed0f2 | ||
|
|
78d6d3c159 | ||
|
|
c72d92956a | ||
|
|
cf88795376 | ||
|
|
47287fb189 | ||
|
|
3763326c25 | ||
|
|
894eb27dfa | ||
|
|
8b3b97c8f7 | ||
|
|
89d87a5eb3 | ||
|
|
492a818079 | ||
|
|
86f608390a | ||
|
|
8096c78b46 | ||
|
|
521a49c6ec | ||
|
|
25a4773bba | ||
|
|
18381fac73 | ||
|
|
89b5c6fe07 | ||
|
|
4dccccc6fa | ||
|
|
de15e4212f | ||
|
|
1f41adbd2c | ||
|
|
1918495f2e | ||
|
|
24514a6e9f | ||
|
|
ad06c5b289 | ||
|
|
9de3f8c8e9 | ||
|
|
b1fa17158d | ||
|
|
2bdf1984cb | ||
|
|
df048af605 | ||
|
|
41507d32a7 | ||
|
|
b2cadf164c | ||
|
|
57b9c671aa | ||
|
|
3b7d10ed93 | ||
|
|
d6bb61b7fa | ||
|
|
8e591383fc | ||
|
|
6f95a520e6 | ||
|
|
f669d3ef4a | ||
|
|
83575058db | ||
|
|
028cb78125 | ||
|
|
c8261b74b5 | ||
|
|
a36c788415 | ||
|
|
ac232b5aff | ||
|
|
ba6f45027a | ||
|
|
d677e9d634 | ||
|
|
9b92697fb7 | ||
|
|
c19e471f65 | ||
|
|
b6fc298d0c | ||
|
|
ea41231b3e | ||
|
|
2ea3f00c41 | ||
|
|
20745f8cd6 | ||
|
|
caf979537b | ||
|
|
e4b10bc5bd | ||
|
|
ef0bac7f44 | ||
|
|
23de9eac4f | ||
|
|
1972f3ec0d | ||
|
|
ffd0fc42ae | ||
|
|
93531a5d47 | ||
|
|
b16aaebc4c | ||
|
|
1136d959ba | ||
|
|
db23f0588d | ||
|
|
e662408e19 | ||
|
|
afe4ba6471 | ||
|
|
6647f707bd | ||
|
|
cac373b010 | ||
|
|
9412d41683 |
@@ -2,12 +2,12 @@
|
||||
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
|
||||
"changelog": ["@changesets/changelog-github", { "repo": "thirdweb-dev/js" }],
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"fixed": [["@thirdweb-dev/sdk", "@thirdweb-dev/react"]],
|
||||
"linked": [],
|
||||
"access": "public",
|
||||
"baseBranch": "main",
|
||||
"updateInternalDependencies": "patch",
|
||||
"ignore": [],
|
||||
"ignore": ["e2e-cra-5", "e2e-next-12", "e2e-vite-3"],
|
||||
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
|
||||
"updateInternalDependents": "always",
|
||||
"onlyUpdatePeerDependentsWhenOutOfRange": true
|
||||
|
||||
@@ -9,7 +9,7 @@ runs:
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
# cache: "yarn"
|
||||
cache: "yarn"
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
|
||||
@@ -14,8 +14,7 @@ jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
# timeout-minutes: 15
|
||||
# try out buildjet to speed up build and test
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204
|
||||
runs-on: ubuntu-latest-32
|
||||
# To use Remote Caching, uncomment the next lines and follow the steps below.
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
@@ -30,8 +29,6 @@ jobs:
|
||||
- name: Install
|
||||
uses: ./.github/composite-actions/install
|
||||
|
||||
- name: Build
|
||||
run: yarn build
|
||||
|
||||
- name: Test
|
||||
# this already builds anything that changed...
|
||||
- name: Build & Test
|
||||
run: yarn test
|
||||
|
||||
@@ -13,8 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
integration-tests:
|
||||
timeout-minutes: 60
|
||||
# try out buildjet to speed up build and test
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204
|
||||
runs-on: ubuntu-latest-32
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -28,9 +27,3 @@ jobs:
|
||||
run: yarn e2e
|
||||
env:
|
||||
NODE_OPTIONS: "--max_old_space_size=4096"
|
||||
- uses: actions/upload-artifact@v2
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: packages/react/playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
@@ -40,8 +40,7 @@ jobs:
|
||||
comment_body: ${{ github.event.comment.body }}
|
||||
|
||||
deploy:
|
||||
# try out buildjet to speed up build and test
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204
|
||||
runs-on: ubuntu-latest-32
|
||||
needs: deploy-check
|
||||
if: needs.deploy-check.outputs.triggered == 'true'
|
||||
steps:
|
||||
|
||||
@@ -14,8 +14,7 @@ concurrency:
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
# try out buildjet to speed up build and test
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204
|
||||
runs-on: ubuntu-latest-32
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Compressed Size
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest-32
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- uses: preactjs/compressed-size-action@v2
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
strip-hash: "\\-(\\w{8})(?:\\.esm|\\.cjs)"
|
||||
minimum-change-threshold: 100
|
||||
# exclude source maps, node modules and any test related files
|
||||
exclude: "{**/*.map,**/node_modules/**,**/test/**}"
|
||||
+6
-1
@@ -12,4 +12,9 @@ server/dist
|
||||
public/dist
|
||||
.turbo
|
||||
./packages/contracts-js/abis
|
||||
.idea/
|
||||
.idea/
|
||||
.yalc/
|
||||
yalc.lock
|
||||
build/
|
||||
playwright-report/
|
||||
.vscode/
|
||||
@@ -1,4 +1,3 @@
|
||||
lib
|
||||
node_modules
|
||||
dist
|
||||
contracts-js
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
| [/auth](./packages/auth) | Best in class wallet authentication for Node backends | <a href="https://www.npmjs.com/package/@thirdweb-dev/auth"><img src="https://img.shields.io/npm/v/@thirdweb-dev/auth?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/solana](./packages/solana) | Solana SDK for Browser, Node and React Native | <a href="https://www.npmjs.com/package/@thirdweb-dev/solana"><img src="https://img.shields.io/npm/v/@thirdweb-dev/solana?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
## Documentation
|
||||
|
||||
|
||||
+6
-10
@@ -8,14 +8,15 @@
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*"
|
||||
"packages/*",
|
||||
"test/**/*"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"test": "turbo run test && turbo run test:evm && turbo run test:solana",
|
||||
"test": "turbo run test test:evm test:solana",
|
||||
"e2e": "turbo run e2e",
|
||||
"build": "turbo run build",
|
||||
"build:release": "turbo run build --force",
|
||||
"build": "turbo run build --filter=./packages/*",
|
||||
"build:release": "turbo run build --force --filter=./packages/*",
|
||||
"dev": "turbo run dev --no-cache --parallel --continue",
|
||||
"fix:repo": "manypkg fix",
|
||||
"lint": "turbo run lint",
|
||||
@@ -27,12 +28,7 @@
|
||||
"release": "node ./scripts/pre-release.mjs && changeset publish",
|
||||
"version-packages:nightly": "changeset version --snapshot nightly",
|
||||
"release:nightly": "node ./scripts/pre-release.mjs && changeset publish --tag nightly",
|
||||
"push": "turbo run push"
|
||||
},
|
||||
"preconstruct": {
|
||||
"packages": [
|
||||
"packages/*"
|
||||
]
|
||||
"push": "turbo run push --filter=./packages/*"
|
||||
},
|
||||
"packageManager": "[email protected]",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.35
|
||||
|
||||
## 2.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
|
||||
|
||||
## 2.0.33
|
||||
|
||||
## 2.0.32
|
||||
|
||||
## 2.0.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#397](https://github.com/thirdweb-dev/js/pull/397) [`72589ec`](https://github.com/thirdweb-dev/js/commit/72589ec234d86939b67b0ca8b3b789f2e9c54cc2) Thanks [@adam-maj](https://github.com/adam-maj)! - Call user callback in getUser
|
||||
|
||||
## 2.0.30
|
||||
|
||||
## 2.0.29
|
||||
|
||||
## 2.0.28
|
||||
|
||||
## 2.0.27
|
||||
|
||||
## 2.0.26
|
||||
|
||||
## 2.0.25
|
||||
|
||||
## 2.0.24
|
||||
|
||||
## 2.0.23
|
||||
|
||||
## 2.0.22
|
||||
|
||||
## 2.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - enable e2e testing
|
||||
|
||||
## 2.0.20
|
||||
|
||||
## 2.0.19
|
||||
|
||||
## 2.0.18
|
||||
|
||||
## 2.0.17
|
||||
|
||||
## 2.0.16
|
||||
|
||||
## 2.0.15
|
||||
|
||||
## 2.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#274](https://github.com/thirdweb-dev/js/pull/274) [`ad06c5b`](https://github.com/thirdweb-dev/js/commit/ad06c5b28902422f9b416d65255c64c937a5e046) Thanks [@adam-maj](https://github.com/adam-maj)! - Add solana auth support and plugins for react and auth package
|
||||
|
||||
## 2.0.13
|
||||
|
||||
## 2.0.12
|
||||
|
||||
## 2.0.11
|
||||
|
||||
## 2.0.10
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-next-evm.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-next-evm.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-auth-next-solana.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth-next-solana.esm.js"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.11",
|
||||
"version": "2.0.35",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
@@ -10,10 +10,18 @@
|
||||
"module": "./express/dist/thirdweb-dev-auth-express.esm.js",
|
||||
"default": "./express/dist/thirdweb-dev-auth-express.cjs.js"
|
||||
},
|
||||
"./next/evm": {
|
||||
"module": "./next/evm/dist/thirdweb-dev-auth-next-evm.esm.js",
|
||||
"default": "./next/evm/dist/thirdweb-dev-auth-next-evm.cjs.js"
|
||||
},
|
||||
"./next-auth": {
|
||||
"module": "./next-auth/dist/thirdweb-dev-auth-next-auth.esm.js",
|
||||
"default": "./next-auth/dist/thirdweb-dev-auth-next-auth.cjs.js"
|
||||
},
|
||||
"./next/solana": {
|
||||
"module": "./next/solana/dist/thirdweb-dev-auth-next-solana.esm.js",
|
||||
"default": "./next/solana/dist/thirdweb-dev-auth-next-solana.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/auth",
|
||||
@@ -35,6 +43,8 @@
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"next/index.ts",
|
||||
"next/evm/index.ts",
|
||||
"next/solana/index.ts",
|
||||
"express/index.ts",
|
||||
"next-auth/index.ts"
|
||||
],
|
||||
@@ -44,6 +54,7 @@
|
||||
"exports": true
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
@@ -62,11 +73,13 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.2",
|
||||
"express": "^4.18.1",
|
||||
"next": "^12.2.0",
|
||||
"next-auth": "^4.10.3",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { Express, NextFunction, Request, Response } from "express";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
export function getUser(req: Request): ThirdwebAuthUser | null {
|
||||
return req.user;
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(app: Express, cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
const authUrl = cfg.authUrl?.replace(/\/$/, "") || "/auth";
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use(async (req: Request, _: Response, next: NextFunction) => {
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
req.user = user as ThirdwebAuthUser | null;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get(`${authUrl}/:route`, (req: Request, res: Response) => {
|
||||
const action = req.params.route as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return userHandler(req, res);
|
||||
case "logout":
|
||||
return logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
+1
-1
@@ -43,7 +43,7 @@ export default async function handler(
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,68 +1 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import cookieParser from "cookie-parser";
|
||||
import { Express, NextFunction, Request, Response } from "express";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
export function getUser(req: Request): ThirdwebAuthUser | null {
|
||||
return req.user;
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(app: Express, cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
const authUrl = cfg.authUrl?.replace(/\/$/, "") || "/auth";
|
||||
|
||||
app.use(cookieParser());
|
||||
|
||||
app.use(async (req: Request, _: Response, next: NextFunction) => {
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
req.user = user as ThirdwebAuthUser | null;
|
||||
next();
|
||||
});
|
||||
|
||||
app.get(`${authUrl}/:route`, (req: Request, res: Response) => {
|
||||
const action = req.params.route as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return userHandler(req, res);
|
||||
case "logout":
|
||||
return logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import { ThirdwebNextAuthConfig } from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next";
|
||||
import NextAuth, {
|
||||
NextAuthOptions,
|
||||
Session,
|
||||
unstable_getServerSession,
|
||||
} from "next-auth";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
|
||||
export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
|
||||
const sdk = ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet");
|
||||
|
||||
function ThirdwebProvider(res: GetServerSidePropsContext["res"]) {
|
||||
return CredentialsProvider({
|
||||
name: "ThirdwebAuth",
|
||||
credentials: {
|
||||
payload: {
|
||||
label: "Payload",
|
||||
type: "text",
|
||||
placeholder: "",
|
||||
},
|
||||
},
|
||||
async authorize({ payload }: any) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload);
|
||||
const token = await sdk.auth.generateAuthToken(cfg.domain, parsed);
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
|
||||
// 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, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
return { id: address, address };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextOptions(
|
||||
req: GetServerSidePropsContext["req"],
|
||||
res: GetServerSidePropsContext["res"],
|
||||
): NextAuthOptions {
|
||||
async function session({
|
||||
session: _session,
|
||||
}: {
|
||||
session: Session;
|
||||
}): Promise<Session> {
|
||||
const token = req.cookies.thirdweb_auth_token || "";
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
_session.user = { ..._session.user, address } as Session["user"];
|
||||
return _session;
|
||||
} catch {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const providers: NextAuthOptions["providers"] = [
|
||||
...cfg.nextOptions.providers,
|
||||
ThirdwebProvider(res),
|
||||
];
|
||||
|
||||
const configSession = cfg.nextOptions.callbacks?.session;
|
||||
const callbacks: NextAuthOptions["callbacks"] = {
|
||||
...cfg.nextOptions.callbacks,
|
||||
session: configSession
|
||||
? async (params) => {
|
||||
params.session = await session(params);
|
||||
return configSession(params);
|
||||
}
|
||||
: session,
|
||||
};
|
||||
|
||||
const configSignOut = cfg.nextOptions.events?.signOut;
|
||||
const events: NextAuthOptions["events"] = {
|
||||
...cfg.nextOptions.events,
|
||||
signOut: configSignOut
|
||||
? async (params) => {
|
||||
signOut();
|
||||
return configSignOut(params);
|
||||
}
|
||||
: signOut,
|
||||
};
|
||||
|
||||
return {
|
||||
...cfg.nextOptions,
|
||||
providers,
|
||||
callbacks,
|
||||
events,
|
||||
};
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
...args:
|
||||
| [NextApiRequest, NextApiResponse]
|
||||
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]]
|
||||
) {
|
||||
return unstable_getServerSession(
|
||||
args[0],
|
||||
args[1],
|
||||
nextOptions(args[0], args[1]),
|
||||
);
|
||||
}
|
||||
|
||||
function NextAuthHandler(...args: [] | [NextApiRequest, NextApiResponse]) {
|
||||
if (args.length === 0) {
|
||||
return (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return NextAuth(req, res, nextOptions(req, res));
|
||||
};
|
||||
}
|
||||
|
||||
return NextAuth(args[0], args[1], nextOptions(args[0], args[1]));
|
||||
}
|
||||
|
||||
return {
|
||||
NextAuthHandler,
|
||||
getUser,
|
||||
};
|
||||
}
|
||||
@@ -1,145 +1 @@
|
||||
import { ThirdwebNextAuthConfig } from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next";
|
||||
import NextAuth, {
|
||||
NextAuthOptions,
|
||||
Session,
|
||||
unstable_getServerSession,
|
||||
} from "next-auth";
|
||||
import CredentialsProvider from "next-auth/providers/credentials";
|
||||
|
||||
export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
|
||||
const sdk = ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet");
|
||||
|
||||
function ThirdwebProvider(res: GetServerSidePropsContext["res"]) {
|
||||
return CredentialsProvider({
|
||||
name: "ThirdwebAuth",
|
||||
credentials: {
|
||||
payload: {
|
||||
label: "Payload",
|
||||
type: "text",
|
||||
placeholder: "",
|
||||
},
|
||||
},
|
||||
async authorize({ payload }: any) {
|
||||
try {
|
||||
const parsed = JSON.parse(payload);
|
||||
const token = await sdk.auth.generateAuthToken(cfg.domain, parsed);
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
|
||||
// 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, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
}),
|
||||
);
|
||||
|
||||
return { address };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function nextOptions(
|
||||
req: GetServerSidePropsContext["req"],
|
||||
res: GetServerSidePropsContext["res"],
|
||||
): NextAuthOptions {
|
||||
async function session({
|
||||
session: _session,
|
||||
}: {
|
||||
session: Session;
|
||||
}): Promise<Session> {
|
||||
const token = req.cookies.thirdweb_auth_token || "";
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(cfg.domain, token);
|
||||
_session.user = { ..._session.user, address } as Session["user"];
|
||||
return _session;
|
||||
} catch {
|
||||
return _session;
|
||||
}
|
||||
}
|
||||
|
||||
function signOut() {
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const providers: NextAuthOptions["providers"] = [
|
||||
...cfg.nextOptions.providers,
|
||||
ThirdwebProvider(res),
|
||||
];
|
||||
|
||||
const configSession = cfg.nextOptions.callbacks?.session;
|
||||
const callbacks: NextAuthOptions["callbacks"] = {
|
||||
...cfg.nextOptions.callbacks,
|
||||
session: configSession
|
||||
? async (params) => {
|
||||
params.session = await session(params);
|
||||
return configSession(params);
|
||||
}
|
||||
: session,
|
||||
};
|
||||
|
||||
const configSignOut = cfg.nextOptions.events?.signOut;
|
||||
const events: NextAuthOptions["events"] = {
|
||||
...cfg.nextOptions.events,
|
||||
signOut: configSignOut
|
||||
? async (params) => {
|
||||
signOut();
|
||||
return configSignOut(params);
|
||||
}
|
||||
: signOut,
|
||||
};
|
||||
|
||||
return {
|
||||
...cfg.nextOptions,
|
||||
providers,
|
||||
callbacks,
|
||||
events,
|
||||
};
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
...args:
|
||||
| [NextApiRequest, NextApiResponse]
|
||||
| [GetServerSidePropsContext["req"], GetServerSidePropsContext["res"]]
|
||||
) {
|
||||
return unstable_getServerSession(
|
||||
args[0],
|
||||
args[1],
|
||||
nextOptions(args[0], args[1]),
|
||||
);
|
||||
}
|
||||
|
||||
function NextAuthHandler(...args: [] | [NextApiRequest, NextApiResponse]) {
|
||||
if (args.length === 0) {
|
||||
return (req: NextApiRequest, res: NextApiResponse) => {
|
||||
return NextAuth(req, res, nextOptions(req, res));
|
||||
};
|
||||
}
|
||||
|
||||
return NextAuth(args[0], args[1], nextOptions(args[0], args[1]));
|
||||
}
|
||||
|
||||
return {
|
||||
NextAuthHandler,
|
||||
getUser,
|
||||
};
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
let data = {};
|
||||
if (ctx.callbacks?.user) {
|
||||
data = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...data, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
@@ -47,7 +47,7 @@ export default async function handler(
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -1,83 +1 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey(cfg.privateKey, "mainnet"),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
export * from "./evm";
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import loginHandler from "./routes/login";
|
||||
import logoutHandler from "./routes/logout";
|
||||
import userHandler from "./routes/user";
|
||||
import {
|
||||
ThirdwebAuthConfig,
|
||||
ThirdwebAuthContext,
|
||||
ThirdwebAuthRoute,
|
||||
ThirdwebAuthUser,
|
||||
} from "./types";
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
import { NextRequest } from "next/server";
|
||||
import {
|
||||
GetServerSidePropsContext,
|
||||
NextApiRequest,
|
||||
NextApiResponse,
|
||||
} from "next/types";
|
||||
|
||||
export * from "./types";
|
||||
|
||||
async function ThirdwebAuthRouter(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
// Catch-all route must be named with [...thirdweb]
|
||||
const { thirdweb } = req.query;
|
||||
const action = thirdweb?.[0] as ThirdwebAuthRoute;
|
||||
|
||||
switch (action) {
|
||||
case "login":
|
||||
return await loginHandler(req, res, ctx);
|
||||
case "user":
|
||||
return await userHandler(req, res, ctx);
|
||||
case "logout":
|
||||
return await logoutHandler(req, res);
|
||||
default:
|
||||
return res.status(400).json({
|
||||
message: "Invalid route for authentication.",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
const ctx = {
|
||||
...cfg,
|
||||
sdk: ThirdwebSDK.fromPrivateKey("mainnet-beta", cfg.privateKey),
|
||||
};
|
||||
|
||||
function ThirdwebAuthHandler(
|
||||
...args: [] | [NextApiRequest, NextApiResponse]
|
||||
) {
|
||||
if (args.length === 0) {
|
||||
return async (req: NextApiRequest, res: NextApiResponse) =>
|
||||
await ThirdwebAuthRouter(req, res, ctx);
|
||||
}
|
||||
|
||||
return ThirdwebAuthRouter(args[0], args[1], ctx);
|
||||
}
|
||||
|
||||
async function getUser(
|
||||
req: GetServerSidePropsContext["req"] | NextRequest | NextApiRequest,
|
||||
) {
|
||||
const { sdk, domain } = ctx;
|
||||
let user: ThirdwebAuthUser | null = null;
|
||||
const token =
|
||||
typeof req.cookies.get === "function"
|
||||
? (req.cookies as any).get("thirdweb_auth_token")
|
||||
: (req.cookies as any).thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
let data = {};
|
||||
if (ctx.callbacks?.user) {
|
||||
data = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...data, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
return { ThirdwebAuthHandler, getUser };
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { ThirdwebAuthContext } from "../types";
|
||||
import { LoginPayload } from "@thirdweb-dev/sdk";
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
function redirectWithError(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
error: string,
|
||||
) {
|
||||
const encodedError = encodeURIComponent(error);
|
||||
const url = new URL(req.headers.referer as string);
|
||||
url.searchParams.set("error", encodedError);
|
||||
return res.redirect(url.toString());
|
||||
}
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return redirectWithError(req, res, "INVALID_METHOD");
|
||||
}
|
||||
|
||||
const { sdk, domain } = ctx;
|
||||
|
||||
// Get signed login payload from the frontend
|
||||
const payload = JSON.parse(atob(req.query.payload as string)) as LoginPayload;
|
||||
if (!payload) {
|
||||
redirectWithError(req, res, "MISSING_LOGIN_PAYLOAD");
|
||||
}
|
||||
|
||||
let token;
|
||||
try {
|
||||
// Generate an access token with the SDK using the signed payload
|
||||
token = await sdk.auth.generateAuthToken(domain, payload);
|
||||
} catch {
|
||||
return redirectWithError(req, res, "INVALID_LOGIN_PAYLOAD");
|
||||
}
|
||||
|
||||
// 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, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
if (ctx.callbacks?.login) {
|
||||
const address = sdk.auth.verify(domain, payload);
|
||||
await ctx.callbacks.login(address);
|
||||
}
|
||||
|
||||
return res.status(301).redirect(req.query.redirect as string);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { serialize } from "cookie";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(400).json({
|
||||
error: "Invalid method. Only GET supported.",
|
||||
});
|
||||
}
|
||||
|
||||
// Set the access token to 'none' and expire in 5 seconds
|
||||
res.setHeader(
|
||||
"Set-Cookie",
|
||||
serialize("thirdweb_auth_token", "", {
|
||||
path: "/",
|
||||
expires: new Date(Date.now() + 5 * 1000),
|
||||
}),
|
||||
);
|
||||
|
||||
return res.status(301).redirect(req.headers.referer as string);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ThirdwebAuthContext, ThirdwebAuthUser } from "../types";
|
||||
import { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
ctx: ThirdwebAuthContext,
|
||||
) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(400).json({
|
||||
error: "Invalid method. Only GET supported.",
|
||||
});
|
||||
}
|
||||
|
||||
const { sdk, domain } = ctx;
|
||||
let user = null;
|
||||
const token = req.cookies.thirdweb_auth_token;
|
||||
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
|
||||
if (ctx.callbacks?.user) {
|
||||
user = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...user, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
}
|
||||
|
||||
return res.status(200).json(user as ThirdwebAuthUser | null);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { ThirdwebSDK } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export type ThirdwebAuthRoute = "login" | "logout" | "user";
|
||||
|
||||
export type ThirdwebAuthConfig = {
|
||||
privateKey: string;
|
||||
domain: string;
|
||||
callbacks?: {
|
||||
login?: (address: string) => Promise<void> | void;
|
||||
user?: (
|
||||
address: string,
|
||||
) =>
|
||||
| Promise<Omit<ThirdwebAuthUser, "address">>
|
||||
| Omit<ThirdwebAuthUser, "address">;
|
||||
};
|
||||
};
|
||||
|
||||
export type ThirdwebAuthContext = {
|
||||
sdk: ThirdwebSDK;
|
||||
domain: string;
|
||||
callbacks?: {
|
||||
login?: (address: string) => Promise<void> | void;
|
||||
user?: (
|
||||
address: string,
|
||||
) =>
|
||||
| Promise<Omit<ThirdwebAuthUser, "address">>
|
||||
| Omit<ThirdwebAuthUser, "address">;
|
||||
};
|
||||
};
|
||||
|
||||
export type ThirdwebAuthUser = {
|
||||
address: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
@@ -1,5 +1,215 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.9.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1)]:
|
||||
- @thirdweb-dev/sdk@3.6.5
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#430](https://github.com/thirdweb-dev/js/pull/430) [`e684d7e`](https://github.com/thirdweb-dev/js/commit/e684d7e1ca16f633bce8698529d16bf60c264aa4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix uploading contracts with special characters in the comments
|
||||
|
||||
- [#435](https://github.com/thirdweb-dev/js/pull/435) [`bef97f7`](https://github.com/thirdweb-dev/js/commit/bef97f72f4860596b7b70b05e67fcadf2c9a012e) Thanks [@adam-maj](https://github.com/adam-maj)! - Make solc default backup compilation
|
||||
|
||||
- [#432](https://github.com/thirdweb-dev/js/pull/432) [`3e87dd3`](https://github.com/thirdweb-dev/js/commit/3e87dd3ccb04a2b73437357c939a251e83b783b2) Thanks [@adam-maj](https://github.com/adam-maj)! - Display file name on duplicate contract names
|
||||
|
||||
- [#431](https://github.com/thirdweb-dev/js/pull/431) [`c42545a`](https://github.com/thirdweb-dev/js/commit/c42545a64725492136025fa1dcdb4d46ba674a30) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
|
||||
|
||||
- [#428](https://github.com/thirdweb-dev/js/pull/428) [`6e20d1f`](https://github.com/thirdweb-dev/js/commit/6e20d1f21a622f102e94b956f700d0871c0dc779) Thanks [@adam-maj](https://github.com/adam-maj)! - Update CLI to enable create contract inside contracts project
|
||||
|
||||
- Updated dependencies [[`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703), [`af3acc6`](https://github.com/thirdweb-dev/js/commit/af3acc6b10751b840e56aef6400da5eea6040df2), [`1bfb91d`](https://github.com/thirdweb-dev/js/commit/1bfb91dbf3a39160c987a425813ac5dbb84703ad), [`ee47840`](https://github.com/thirdweb-dev/js/commit/ee478407673b0416e0c1cfe2be11bd6963395348), [`def4251`](https://github.com/thirdweb-dev/js/commit/def42511ff5a20d83f9094164dafb87e412571b5), [`034a257`](https://github.com/thirdweb-dev/js/commit/034a257442314c67729f7bafcbe3740cff33fa32), [`eca4776`](https://github.com/thirdweb-dev/js/commit/eca47763cd89cc3b7aa57b542971837987540b55), [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45)]:
|
||||
- @thirdweb-dev/sdk@3.6.4
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#415](https://github.com/thirdweb-dev/js/pull/415) [`48d91e4`](https://github.com/thirdweb-dev/js/commit/48d91e4431a3740d0f98f730ed5abf5b287f92c1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix mappings for prebuilts redirect on deploy
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#403](https://github.com/thirdweb-dev/js/pull/403) [`27996cb`](https://github.com/thirdweb-dev/js/commit/27996cb4bc6f054f45b0a66b0a3aca732e0ef610) Thanks [@avneesh0612](https://github.com/avneesh0612)! - Add CLI Support for solana with --solana flag on create command
|
||||
|
||||
- [#283](https://github.com/thirdweb-dev/js/pull/283) [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d) Thanks [@adam-maj](https://github.com/adam-maj)! - add capability to deploy apps
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#413](https://github.com/thirdweb-dev/js/pull/413) [`1b0bf99`](https://github.com/thirdweb-dev/js/commit/1b0bf99da796df88ff307dd004cdaf239fb2b1ba) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - small interface tweaks
|
||||
|
||||
- Updated dependencies [[`48797c7`](https://github.com/thirdweb-dev/js/commit/48797c7cf0695965e33eb6bf602be4652f7085a8), [`83dcaf7`](https://github.com/thirdweb-dev/js/commit/83dcaf70584af8c5cdf0427f9fc1ba82d89f0887), [`f03be39`](https://github.com/thirdweb-dev/js/commit/f03be398e0d7b75c9c5b4fb643f35903e89a17e7), [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d), [`47f8945`](https://github.com/thirdweb-dev/js/commit/47f8945325447874b1ace0359919c1d54fd55436)]:
|
||||
- @thirdweb-dev/sdk@3.6.3
|
||||
|
||||
## 0.8.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715), [`9151aa7`](https://github.com/thirdweb-dev/js/commit/9151aa7dc80754a7aa4fd3f6ce0207bccbb6451f), [`5a01c53`](https://github.com/thirdweb-dev/js/commit/5a01c537e30bd7ef562aad1012413990de6faedf)]:
|
||||
- @thirdweb-dev/sdk@3.6.2
|
||||
|
||||
## 0.8.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`15514f1`](https://github.com/thirdweb-dev/js/commit/15514f190a844d809ae5b1edb580aab46a682485), [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510), [`f8bceec`](https://github.com/thirdweb-dev/js/commit/f8bceec10c60b30dc3d6f45926e2a9e018202578), [`887af24`](https://github.com/thirdweb-dev/js/commit/887af24450e316c2ea390cd49c0563cebe793c0f), [`96bd92e`](https://github.com/thirdweb-dev/js/commit/96bd92e724ec7d880d23348071b26ab8c21dd868)]:
|
||||
- @thirdweb-dev/sdk@3.6.1
|
||||
|
||||
## 0.8.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1), [`0ed77d2`](https://github.com/thirdweb-dev/js/commit/0ed77d2c9e7526444ef660aab82a950865234aa6), [`04a47e8`](https://github.com/thirdweb-dev/js/commit/04a47e8971d28da2532ebd9db824eeb459c17bd4)]:
|
||||
- @thirdweb-dev/sdk@3.6.0
|
||||
|
||||
## 0.8.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3eba69a`](https://github.com/thirdweb-dev/js/commit/3eba69afd78b7aa472a9c00c9d4220bb69ad1d3e), [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855), [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd), [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0)]:
|
||||
- @thirdweb-dev/sdk@3.5.2
|
||||
|
||||
## 0.8.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4e7b293`](https://github.com/thirdweb-dev/js/commit/4e7b293c543244de79c150ca8c37d941221fc9a3), [`c9c0e4f`](https://github.com/thirdweb-dev/js/commit/c9c0e4ff39b054af746f3aec75fcbd0a3ef7239d)]:
|
||||
- @thirdweb-dev/sdk@3.5.1
|
||||
|
||||
## 0.8.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`5200d5d`](https://github.com/thirdweb-dev/js/commit/5200d5d7e730da58bd4d3e7c222e3c661265f913), [`42a6065`](https://github.com/thirdweb-dev/js/commit/42a606588dfed03c67c57357dd0ee1ad19fad6ea)]:
|
||||
- @thirdweb-dev/sdk@3.5.0
|
||||
|
||||
## 0.8.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e731c1a`](https://github.com/thirdweb-dev/js/commit/e731c1a7c341e6f2b9cc42c88d5c1b036dcf4a7c)]:
|
||||
- @thirdweb-dev/sdk@3.4.5
|
||||
|
||||
## 0.8.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.4.4
|
||||
|
||||
## 0.8.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`1c24c3c`](https://github.com/thirdweb-dev/js/commit/1c24c3c3c48476a824f817e09e7bf0fbe67c1db5), [`65fc7ba`](https://github.com/thirdweb-dev/js/commit/65fc7ba6fff093a971b53cb0979c39768e090ba1)]:
|
||||
- @thirdweb-dev/sdk@3.4.3
|
||||
|
||||
## 0.8.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`21c21c1`](https://github.com/thirdweb-dev/js/commit/21c21c1adfd09b60ad563bfd4c308597140de33c), [`3522917`](https://github.com/thirdweb-dev/js/commit/352291791ee900e1500f84f095290497934d2f60)]:
|
||||
- @thirdweb-dev/sdk@3.4.2
|
||||
|
||||
## 0.8.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`72227b2`](https://github.com/thirdweb-dev/js/commit/72227b2e166a3a68bbb41cf2b389322f5b7547a2)]:
|
||||
- @thirdweb-dev/sdk@3.4.1
|
||||
|
||||
## 0.8.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - enable e2e testing
|
||||
|
||||
- Updated dependencies [[`340605b`](https://github.com/thirdweb-dev/js/commit/340605b507f384fbd2999b9c16542af3c53e84a9), [`26116a6`](https://github.com/thirdweb-dev/js/commit/26116a6f637ee845f7bd17f20ffe17caf184658e), [`15f8006`](https://github.com/thirdweb-dev/js/commit/15f8006e1fb22333b7ee239b45e7b1b12d6dccc8), [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5)]:
|
||||
- @thirdweb-dev/sdk@3.4.0
|
||||
|
||||
## 0.8.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ad851f7`](https://github.com/thirdweb-dev/js/commit/ad851f7b4d6abb5ab9364ef3dec229f913e18ce5), [`6218c88`](https://github.com/thirdweb-dev/js/commit/6218c885842e6b4e44ec38ec92a9211e56c49bf4)]:
|
||||
- @thirdweb-dev/sdk@3.3.1
|
||||
|
||||
## 0.8.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#326](https://github.com/thirdweb-dev/js/pull/326) [`126752d`](https://github.com/thirdweb-dev/js/commit/126752d7d02c9a808a63fb9e67a9df6658b5682b) Thanks [@jnsdls](https://github.com/jnsdls)! - remove tons of unused dependencies, use SDK function for extracting ipfs has from bytecode
|
||||
|
||||
- Updated dependencies [[`126752d`](https://github.com/thirdweb-dev/js/commit/126752d7d02c9a808a63fb9e67a9df6658b5682b), [`df74340`](https://github.com/thirdweb-dev/js/commit/df74340fa51323304c32419761d6f18628b060fa), [`89ff921`](https://github.com/thirdweb-dev/js/commit/89ff921a7d9f0e42b4e6707c8b56d0aab95c1aa0), [`a57b4f0`](https://github.com/thirdweb-dev/js/commit/a57b4f01f3a49590b897101f2730582e4124a554)]:
|
||||
- @thirdweb-dev/sdk@3.3.0
|
||||
|
||||
## 0.8.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4f867e1`](https://github.com/thirdweb-dev/js/commit/4f867e15edbe5757afbf54cab207458711a8986c), [`b6eec61`](https://github.com/thirdweb-dev/js/commit/b6eec6146c23b66a3681bbb48b173b9019254214), [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1), [`782b58d`](https://github.com/thirdweb-dev/js/commit/782b58d3f6a3b49ff9b3d837551db5161f96171a), [`f41a443`](https://github.com/thirdweb-dev/js/commit/f41a443c5785240197607b5bf93ff18a1c8e8307), [`f45ef62`](https://github.com/thirdweb-dev/js/commit/f45ef62128cfefe06275a38440c90d45e9f3cef7), [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69), [`b7cd744`](https://github.com/thirdweb-dev/js/commit/b7cd744cd0482a6c3fe5ae0c858f20cd380d4114), [`53c6507`](https://github.com/thirdweb-dev/js/commit/53c65076696a43bd9a7e58a7493d4e65c172900f)]:
|
||||
- @thirdweb-dev/sdk@3.2.6
|
||||
|
||||
## 0.8.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`712b11a`](https://github.com/thirdweb-dev/js/commit/712b11a43e389ae10b7f09648779a69c05b2c913)]:
|
||||
- @thirdweb-dev/sdk@3.2.5
|
||||
|
||||
## 0.8.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.4
|
||||
|
||||
## 0.8.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.3
|
||||
|
||||
## 0.8.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#276](https://github.com/thirdweb-dev/js/pull/276) [`24514a6`](https://github.com/thirdweb-dev/js/commit/24514a6e9fc1316622c1494e5be225e53f88d26e) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - build is now default compile command, reorganized the help list
|
||||
|
||||
- [#279](https://github.com/thirdweb-dev/js/pull/279) [`1918495`](https://github.com/thirdweb-dev/js/commit/1918495f2ee7f50d94083d9577dab0bf1c828c94) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - Updating command list order, helper text and changed detect -> build
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#277](https://github.com/thirdweb-dev/js/pull/277) [`9de3f8c`](https://github.com/thirdweb-dev/js/commit/9de3f8c8e954733bfc3eb6e8e0e786ff5b296f0c) Thanks [@adam-maj](https://github.com/adam-maj)! - Add recursive folder upload support
|
||||
|
||||
- [#268](https://github.com/thirdweb-dev/js/pull/268) [`57b9c67`](https://github.com/thirdweb-dev/js/commit/57b9c671aaf7fce0076dd332c171ba6944752e7a) Thanks [@adam-maj](https://github.com/adam-maj)! - Update storage upload cLI
|
||||
|
||||
- Updated dependencies [[`521a49c`](https://github.com/thirdweb-dev/js/commit/521a49c6ec6a73068adcfbc1d94d2f3f17afae86), [`8b3b97c`](https://github.com/thirdweb-dev/js/commit/8b3b97c8f7b3710ce62ed86cfeb4f6de3c23d559), [`25a4773`](https://github.com/thirdweb-dev/js/commit/25a4773bba406f4e270ac86e68c5266d24c08330), [`b2cadf1`](https://github.com/thirdweb-dev/js/commit/b2cadf164cfe9fb27081df7530356baf70ec2b3a), [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c), [`78d6d3c`](https://github.com/thirdweb-dev/js/commit/78d6d3c15968a449924b3f24354e151a90e4b20d), [`89d87a5`](https://github.com/thirdweb-dev/js/commit/89d87a5eb31e78e68e097718e9ae6e4c4d101868), [`41507d3`](https://github.com/thirdweb-dev/js/commit/41507d32a78c556f50c88de81c4d6109b1783c78), [`8096c78`](https://github.com/thirdweb-dev/js/commit/8096c78b466a7f5f9c2aac6e2c56a06f9d3a25d6), [`b1fa171`](https://github.com/thirdweb-dev/js/commit/b1fa17158dcac00265bc8f4d64f1f9708482cdb5), [`18381fa`](https://github.com/thirdweb-dev/js/commit/18381fac73741826934212ac6441842ed42a64a0), [`df048af`](https://github.com/thirdweb-dev/js/commit/df048af605f449279b01d7352b604e7856ac223c), [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c), [`cf88795`](https://github.com/thirdweb-dev/js/commit/cf88795376d3110f9d3aa839928d22276904b15a), [`89b5c6f`](https://github.com/thirdweb-dev/js/commit/89b5c6fe079e4df2cf12cb557aa9784f88c5d159)]:
|
||||
- @thirdweb-dev/sdk@3.2.2
|
||||
|
||||
## 0.7.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#259](https://github.com/thirdweb-dev/js/pull/259) [`6f95a52`](https://github.com/thirdweb-dev/js/commit/6f95a520e6cc69e08f734705e8adc71431b091cc) Thanks [@adam-maj](https://github.com/adam-maj)! - Add npx thirdweb upload command
|
||||
|
||||
- Updated dependencies []:
|
||||
- @thirdweb-dev/sdk@3.2.1
|
||||
|
||||
## 0.7.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#246](https://github.com/thirdweb-dev/js/pull/246) [`ef0bac7`](https://github.com/thirdweb-dev/js/commit/ef0bac7f44b93939bfc9e2706b39edaa22992eec) Thanks [@simonlim94](https://github.com/simonlim94)! - Renamed initial commit message during thirdweb cli createApp
|
||||
|
||||
- Updated dependencies [[`ba6f450`](https://github.com/thirdweb-dev/js/commit/ba6f45027a6ec11aebb4a1918ab2ba4f88894ede), [`c8261b7`](https://github.com/thirdweb-dev/js/commit/c8261b74b5828ac66ea3a6d7636aa57e40ea1a14), [`20745f8`](https://github.com/thirdweb-dev/js/commit/20745f8cd603235eb5039e61a39c0959c5860bca), [`2ea3f00`](https://github.com/thirdweb-dev/js/commit/2ea3f00c41b5e70d9bb634cd86790890520fc4d6), [`9412d41`](https://github.com/thirdweb-dev/js/commit/9412d416832c87ab2c858cb120c6c5de03459c50), [`d677e9d`](https://github.com/thirdweb-dev/js/commit/d677e9d6341252013762882d25408ea8f93791e5), [`e662408`](https://github.com/thirdweb-dev/js/commit/e662408e1936983485936609552f80a56cbed082), [`e4b10bc`](https://github.com/thirdweb-dev/js/commit/e4b10bc5bd12178cba8856b60255732123cb7ae5), [`caf9795`](https://github.com/thirdweb-dev/js/commit/caf979537b5acb1610f182c94afa5d95c208ec3f), [`028cb78`](https://github.com/thirdweb-dev/js/commit/028cb781252b0050943b14cfdf38132c18753a4b), [`1972f3e`](https://github.com/thirdweb-dev/js/commit/1972f3ec0d511fbc17642b2a30852a177092a09e), [`6647f70`](https://github.com/thirdweb-dev/js/commit/6647f707bdd050725264a8a74220c11912f68e57), [`cac373b`](https://github.com/thirdweb-dev/js/commit/cac373b010ce3be3615a36671b66815a27785061)]:
|
||||
- @thirdweb-dev/sdk@3.2.0
|
||||
|
||||
## 0.7.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export const CREATE_MESSAGES = {
|
||||
typeOfProject: "What type of project do you want to create?",
|
||||
projectName: "What is your project named?",
|
||||
contractName: "What will be the name of your new smart contract?",
|
||||
chain: "Which blockchain do you want to use?",
|
||||
framework: "What framework do you want to use?",
|
||||
language: "What language do you want to use?",
|
||||
contract: "What type of contract do you want to start from?",
|
||||
@@ -9,5 +11,5 @@ export const CREATE_MESSAGES = {
|
||||
|
||||
export const ERROR_MESSAGES = {
|
||||
noConfiguration:
|
||||
"Failed to find a supported project configuration file in current directory",
|
||||
"No contract project configuration file found in current directory",
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
|
||||
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
|
||||
|
||||
// this creates an app, can take some time that's fine
|
||||
jest.setTimeout(120_000);
|
||||
jest.setTimeout(150_000);
|
||||
|
||||
describe("npx thirdweb create", () => {
|
||||
it("should create app (CRA) successfully", async () => {
|
||||
@@ -16,6 +16,8 @@ describe("npx thirdweb create", () => {
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.projectName);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.chain);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.framework);
|
||||
// select CRA
|
||||
await pressKey("arrowDown");
|
||||
|
||||
@@ -15,8 +15,8 @@ describe("npx thirdweb deploy", () => {
|
||||
`${path}/BasicContract.sol`,
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
|
||||
await spawn("node", "./dist/cli/index.js deploy");
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js deploy --contract");
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("npx thirdweb deploy", () => {
|
||||
// wait for program to finish
|
||||
await waitForFinish();
|
||||
|
||||
expect(getStdout().at(-1)).toContain(
|
||||
expect(getStderr().at(-1)).toContain(
|
||||
"https://thirdweb.com/contracts/deploy/",
|
||||
);
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ describe("npx thirdweb detect", () => {
|
||||
await create.waitForText(CREATE_MESSAGES.framework);
|
||||
// select hardhat
|
||||
await create.pressKey("enter");
|
||||
await create.waitForText(CREATE_MESSAGES.contractName);
|
||||
// set contract name
|
||||
await create.writeText("Contract");
|
||||
await create.pressKey("enter");
|
||||
await create.waitForText(CREATE_MESSAGES.contract);
|
||||
// select ERC721
|
||||
await create.pressKey("arrowDown");
|
||||
|
||||
@@ -15,7 +15,7 @@ describe("npx thirdweb release", () => {
|
||||
`${path}/BasicContract.sol`,
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js release");
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
@@ -26,7 +26,7 @@ describe("npx thirdweb release", () => {
|
||||
// wait for program to finish
|
||||
await waitForFinish();
|
||||
|
||||
expect(getStdout().at(-1)).toContain(
|
||||
expect(getStderr().at(-1)).toContain(
|
||||
"https://thirdweb.com/contracts/release/",
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.7.22",
|
||||
"version": "0.9.3",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gmrchk/cli-testing-library": "^0.1.2",
|
||||
"@types/async-retry": "1.3.0",
|
||||
"@types/async-retry": "^1.3.0",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/inquirer": "^8.2.1",
|
||||
"@types/jest": "^29.0.0",
|
||||
@@ -31,24 +31,17 @@
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"async-retry": "^1.3.3",
|
||||
"cbor": "^8.1.0",
|
||||
"commander": "^9.1.0",
|
||||
"cpy": "^9.0.1",
|
||||
"enquirer": "^2.3.6",
|
||||
"ethers": "^5.7.0",
|
||||
"form-data": "^4.0.0",
|
||||
"ethers": "^5.7.2",
|
||||
"got": "11.8.5",
|
||||
"inquirer": "^8.2.3",
|
||||
"ipfs-unixfs": "^6.0.7",
|
||||
"ipld-dag-pb": "^0.22.3",
|
||||
"multihashes": "^4.0.3",
|
||||
"open": "^8.4.0",
|
||||
"prompts": "^2.4.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"solc": "0.8.13",
|
||||
"solc": "0.8.17",
|
||||
"tar": "^6.1.11",
|
||||
"tslog": "^3.3.3",
|
||||
"update-check": "^1.5.4",
|
||||
"update-notifier": "^6.0.2",
|
||||
"validate-npm-package-name": "^4.0.0",
|
||||
"yaml": "^2.1.1"
|
||||
|
||||
+133
-85
@@ -1,11 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
import { installGithubAction } from "../common/ci-installer";
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import { twCreate } from "../create/command";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { deploy } from "../deploy";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
@@ -39,101 +40,45 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
.version(cliVersion, "-v, --version");
|
||||
|
||||
program
|
||||
.command("create")
|
||||
.command("create [projectType] [projectPath]")
|
||||
.description(
|
||||
"Create a thirdweb app from any of our official templates. Checkout some examples you can use here: https://github.com/thirdweb-example/",
|
||||
"Create a web3 app from any of our official templates: https://github.com/thirdweb-example/",
|
||||
)
|
||||
.option("--app", `Create a thirdweb app.`)
|
||||
.option("--contract", `Create a thirdweb contracts project.`)
|
||||
.option("--ts, --typescript", `Initialize as a TypeScript project.`)
|
||||
.option("--js, --javascript", `Initialize as a JavaScript project.`)
|
||||
.option("--forge", `Initialize as a Forge project.`)
|
||||
.option("--hardhat", `Initialize as a Hardhat project.`)
|
||||
.option("--cra", `Initialize as a Create React App project.`)
|
||||
.option("--next", `Initialize as a Next.js project.`)
|
||||
.option("--vite", `Initialize as a Vite project.`)
|
||||
.option("--app", "Create a web3 app.")
|
||||
.option("--contract", "Create a web3 contract project")
|
||||
.option("--ts, --typescript", "Initialize as a TypeScript project.")
|
||||
.option("--js, --javascript", "Initialize as a JavaScript project.")
|
||||
.option("--forge", "Initialize as a Forge project.")
|
||||
.option("--hardhat", "Initialize as a Hardhat project.")
|
||||
.option("--cra", "Initialize as a Create React App project.")
|
||||
.option("--next", "Initialize as a Next.js project.")
|
||||
.option("--vite", "Initialize as a Vite project.")
|
||||
.option(
|
||||
"--use-npm",
|
||||
`Explicitly tell the CLI to bootstrap the app using npm`,
|
||||
"Explicitly tell the CLI to bootstrap the app using npm",
|
||||
)
|
||||
.option(
|
||||
"--use-pnpm",
|
||||
`Explicitly tell the CLI to bootstrap the app using pnpm`,
|
||||
"Explicitly tell the CLI to bootstrap the app using pnpm",
|
||||
)
|
||||
.option("--framework [name]", `The preferred framework.`)
|
||||
.option("--framework [name]", "The preferred framework.")
|
||||
.option("--solana", "Initialize as a Solana project.")
|
||||
.option("--evm", "Initialize as an Ethereum project.")
|
||||
.option(
|
||||
"-t, --template [name]",
|
||||
`A template to start your project from. You can use an template repository name from the official thirdweb-example org.`,
|
||||
)
|
||||
.action(async (options) => {
|
||||
await twCreate(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("deploy")
|
||||
.description(
|
||||
"Deploy contracts through your thirdweb dashboard, without dealing with private keys.",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option(
|
||||
"-n, --name [name]",
|
||||
"Name of the pre-built or released contract (such as nft-drop)",
|
||||
"A template to start your project from. You can use an template repository name from the official thirdweb-example org.",
|
||||
)
|
||||
.option(
|
||||
"-cv, --contract-version [version]",
|
||||
"Version of the released contract",
|
||||
"-c, --contract-name [name]",
|
||||
"Name of the new smart contract to create",
|
||||
)
|
||||
.action(async (options) => {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
if (!url) {
|
||||
logger.error(
|
||||
chalk.red(
|
||||
`Could not find a contract named ${options.name} ${
|
||||
options.contractVersion || ""
|
||||
}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
info(`Open this link to deploy your contract:`);
|
||||
logger.info(chalk.blueBright(url));
|
||||
open(url.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy");
|
||||
info(`Open this link to deploy your contracts:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
open(url.toString());
|
||||
.action(async (type, path, options) => {
|
||||
await twCreate(type, path, options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("release")
|
||||
.description(
|
||||
"Release contracts, making them available for others to deploy and unlocking SDKs, Dashboards and Analytics.",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.action(async (options) => {
|
||||
const url = await processProject(options, "release");
|
||||
info(`Open this link to release your contracts:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
open(url.toString());
|
||||
});
|
||||
|
||||
program
|
||||
.command("detect")
|
||||
.description(
|
||||
"Compile contracts and detect implemented thirdweb contract extensions",
|
||||
)
|
||||
.command("build")
|
||||
.description("Compile contract and detect 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")
|
||||
@@ -142,12 +87,115 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
});
|
||||
|
||||
program
|
||||
.command("install-ci")
|
||||
.description(
|
||||
"(alpha) Set up continuous integration for your contracts. This adds a github action to deploy the project on pull requests and pushes to branches. Publishes on push the the main branch.",
|
||||
.command("deploy")
|
||||
.description("Deploy your (or team) contracts securely to blockchains")
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option(
|
||||
"--dist-path [distPath]",
|
||||
"Path to the dist folder where the HTML based App is",
|
||||
)
|
||||
.option(
|
||||
"-n, --name [name]",
|
||||
"Name of the pre-built or released contract (such as nft-drop)",
|
||||
)
|
||||
.option(
|
||||
"-f, --file [name]",
|
||||
"Filter for contract files that contain this file name",
|
||||
)
|
||||
.option(
|
||||
"-cn, --contract-name [name]",
|
||||
"Filter for contracts that contain this contract name",
|
||||
)
|
||||
.option(
|
||||
"-cv, --contract-version [version]",
|
||||
"Version of the released contract",
|
||||
)
|
||||
.option("--app", "Deploy a web app to decentralized storage")
|
||||
.option("--contract", "Deploy a smart contract to blockchains")
|
||||
.action(async (options) => {
|
||||
await installGithubAction(options);
|
||||
const url = await deploy(options);
|
||||
if (url) {
|
||||
open(url);
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
.command("release")
|
||||
.description(
|
||||
"Release your protocol so other devs can deploy them and unlock SDKs, Dashboards and Analytics",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option(
|
||||
"-f, --file [name]",
|
||||
"Filter for contract files that contain the file name",
|
||||
)
|
||||
.option(
|
||||
"-cn, --contract-name [name]",
|
||||
"Filter for contracts that contain this contract name",
|
||||
)
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.action(async (options) => {
|
||||
const url = await processProject(options, "release");
|
||||
info(
|
||||
`Open this link to release your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
open(url.toString());
|
||||
});
|
||||
|
||||
program
|
||||
.command("upload")
|
||||
.description("Upload any file or directory to decentralized storage (IPFS)")
|
||||
.argument("[upload]", "path to file or directory to upload")
|
||||
.action(async (path) => {
|
||||
const storage = new ThirdwebStorage();
|
||||
try {
|
||||
const uri = await upload(storage, path);
|
||||
info(
|
||||
`Files stored at the following IPFS URI: ${chalk.blueBright(
|
||||
uri.toString(),
|
||||
)}`,
|
||||
);
|
||||
|
||||
const url = storage.resolveScheme(uri);
|
||||
info(
|
||||
`Open this link to view your upload: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (
|
||||
err.toString() === "No files detected in specified directory" ||
|
||||
err.toString() === "Invalid path provided" ||
|
||||
err.toString() === "No path provided"
|
||||
) {
|
||||
logger.error(
|
||||
chalk.redBright(
|
||||
"Please specify a valid file or directory to upload",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
logger.error(chalk.redBright("Failed to upload files"), err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
await program.parseAsync();
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function processProject(
|
||||
}
|
||||
}
|
||||
|
||||
let compiledResult;
|
||||
let compiledResult: { contracts: ContractPayload[] };
|
||||
const compileLoader = spinner("Compiling project...");
|
||||
try {
|
||||
compiledResult = await build(projectPath, projectType);
|
||||
@@ -106,10 +106,47 @@ export async function processProject(
|
||||
if (options.ci) {
|
||||
selectedContracts = compiledResult.contracts;
|
||||
} else {
|
||||
const choices = compiledResult.contracts.map((c) => ({
|
||||
name: c.name,
|
||||
value: c,
|
||||
}));
|
||||
const filtered = compiledResult.contracts
|
||||
.filter((c) => {
|
||||
if (typeof options.file === "string" && options.file.length > 0) {
|
||||
return c.fileName.includes(options.file);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.filter((c) => {
|
||||
if (
|
||||
typeof options.contractName === "string" &&
|
||||
options.contractName.length > 0
|
||||
) {
|
||||
return c.name.includes(options.contractName);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (filtered.length === 0) {
|
||||
logger.error(`No contracts found matching the specified filters.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const choices = filtered.map((c) => {
|
||||
if (
|
||||
compiledResult.contracts.filter(
|
||||
(other: ContractPayload) => other.name === c.name,
|
||||
).length > 1
|
||||
) {
|
||||
return {
|
||||
name: `${c.name} - ${chalk.gray(c.fileName)}`,
|
||||
value: c,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: c.name,
|
||||
value: c,
|
||||
};
|
||||
});
|
||||
const prompt = createContractsPrompt(
|
||||
choices,
|
||||
`Choose which contract(s) to ${command}`,
|
||||
@@ -164,7 +201,7 @@ export async function processProject(
|
||||
const metadataURIs = await Promise.all(
|
||||
selectedContracts.map(async (c) => {
|
||||
logger.debug(`Uploading ${c.name}...`);
|
||||
return await storage.upload(JSON.parse(c.metadata), {
|
||||
return await storage.upload(JSON.parse(JSON.stringify(c.metadata)), {
|
||||
uploadWithoutDirectory: true,
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -55,6 +55,7 @@ export class BrownieBuilder extends BaseBuilder {
|
||||
metadata: {},
|
||||
bytecode,
|
||||
sources: [], // TODO
|
||||
fileName: "", // TODO
|
||||
name: contractName,
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { extractIPFSHashFromBytecode } from "../helpers/ipfs";
|
||||
import { logger } from "../helpers/logger";
|
||||
import { CompileOptions, IBuilder } from "../interfaces/Builder";
|
||||
import { ContractPayload } from "../interfaces/ContractPayload";
|
||||
import { extractIPFSHashFromBytecode } from "@thirdweb-dev/sdk/evm";
|
||||
|
||||
export abstract class BaseBuilder implements IBuilder {
|
||||
abstract compile(
|
||||
|
||||
@@ -88,6 +88,11 @@ export class FoundryBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (
|
||||
this.shouldProcessContract(
|
||||
contractInfo.abi,
|
||||
@@ -99,6 +104,7 @@ export class FoundryBuilder extends BaseBuilder {
|
||||
name: contractName,
|
||||
metadata,
|
||||
bytecode,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export class HardhatBuilder extends BaseBuilder {
|
||||
//the hardhat extractor **logs out** the runtime config of hardhat, we take that stdout and parse it
|
||||
const stringifiedConfig = (
|
||||
await execute(
|
||||
`npx hardhat run ${configExtractorScriptPath} --no-compile`,
|
||||
`npx hardhat run "${configExtractorScriptPath}" --no-compile`,
|
||||
options.projectPath,
|
||||
)
|
||||
).stdout;
|
||||
@@ -123,11 +123,17 @@ export class HardhatBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
meta?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,11 +140,17 @@ export class SolcBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources: _sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,11 +72,18 @@ export class TruffleBuilder extends BaseBuilder {
|
||||
return undefined;
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export default async function detect(
|
||||
name: "continue",
|
||||
message:
|
||||
"Do you want to continue and compile this project with solc instead?",
|
||||
initial: true,
|
||||
});
|
||||
const shouldCompile = await prompt.run();
|
||||
if (!shouldCompile) {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class NPMDetector implements Detector {
|
||||
public projectType: ProjectType = "npm";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return existsSync(path + "/package-lock.json");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class ViteDetector implements Detector {
|
||||
public projectType: ProjectType = "vite";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return (
|
||||
existsSync(path + "/vite.config.js") ||
|
||||
existsSync(path + "/vite.config.ts")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class YarnDetector implements Detector {
|
||||
public projectType: ProjectType = "yarn";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return existsSync(path + "/yarn.lock");
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
import { decodeFirstSync } from "cbor";
|
||||
import { UnixFS } from "ipfs-unixfs";
|
||||
import { DAGNode } from "ipld-dag-pb";
|
||||
import { toB58String } from "multihashes";
|
||||
|
||||
/**
|
||||
* Derives IPFS hash of string
|
||||
* @param {String} str
|
||||
* @return {String} IPFS hash (ex: "Qm")
|
||||
*/
|
||||
export async function getIPFSHash(str: string) {
|
||||
const file = new UnixFS({
|
||||
type: "file",
|
||||
data: Buffer.from(str),
|
||||
});
|
||||
const node = new DAGNode(file.marshal());
|
||||
const metadataLink = await node.toDAGLink();
|
||||
return toB58String(metadataLink.Hash.multihash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the IPFS hash from the given bytecode
|
||||
* @param bytecode
|
||||
* @returns
|
||||
*/
|
||||
export function extractIPFSHashFromBytecode(
|
||||
bytecode: string,
|
||||
): string | undefined {
|
||||
const numericBytecode = hexToBytes(bytecode);
|
||||
const cborLength: number =
|
||||
numericBytecode[numericBytecode.length - 2] * 0x100 +
|
||||
numericBytecode[numericBytecode.length - 1];
|
||||
const bytecodeBuffer = Buffer.from(
|
||||
numericBytecode.slice(numericBytecode.length - 2 - cborLength, -2),
|
||||
);
|
||||
const cborData = decodeFirstSync(bytecodeBuffer);
|
||||
if (cborData["ipfs"]) {
|
||||
const uri = toB58String(cborData["ipfs"]);
|
||||
return uri;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function hexToBytes(hex: string | number) {
|
||||
hex = hex.toString(16);
|
||||
if (!hex.startsWith("0x")) {
|
||||
hex = `0x${hex}`;
|
||||
}
|
||||
if (!isHexStrict(hex)) {
|
||||
throw new Error('Given value "' + hex + '" is not a valid hex string.');
|
||||
}
|
||||
|
||||
hex = hex.replace(/^0x/i, "");
|
||||
|
||||
for (var bytes = [], c = 0; c < hex.length; c += 2) {
|
||||
bytes.push(parseInt(hex.slice(c, c + 2), 16));
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
function isHexStrict(hex: string | number) {
|
||||
return (
|
||||
(typeof hex === "string" || typeof hex === "number") &&
|
||||
/^(-)?0x[0-9a-f]*$/i.test(hex.toString())
|
||||
);
|
||||
}
|
||||
@@ -17,6 +17,11 @@ export interface ContractPayload {
|
||||
*/
|
||||
metadata: any;
|
||||
|
||||
/**
|
||||
* The file name of the original compiled file
|
||||
*/
|
||||
fileName: string;
|
||||
|
||||
/**
|
||||
* The source file paths
|
||||
*/
|
||||
|
||||
@@ -4,4 +4,10 @@ export type ProjectType =
|
||||
| "hardhat"
|
||||
| "truffle"
|
||||
| "solc"
|
||||
| "vite"
|
||||
| "next"
|
||||
| "cra"
|
||||
| "spa-webapp"
|
||||
| "yarn"
|
||||
| "npm"
|
||||
| "none";
|
||||
|
||||
+265
-134
@@ -2,60 +2,82 @@
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { CREATE_MESSAGES } from "../../constants/constants";
|
||||
import detect from "../core/detection/detect";
|
||||
import { DownloadError, createApp } from "./helpers/create-app";
|
||||
import { createContract } from "./helpers/create-contract";
|
||||
import { createContractProject } from "./helpers/create-contract";
|
||||
import { getPkgManager } from "./helpers/get-pkg-manager";
|
||||
import { validateNpmName } from "./helpers/validate-pkg";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import prompts from "prompts";
|
||||
|
||||
let projectType: string = "";
|
||||
let contractName: string = "";
|
||||
let projectPath: string = "";
|
||||
let projectType: string = "";
|
||||
let framework: string = "";
|
||||
let language: string = "";
|
||||
let baseContract: string = "";
|
||||
let chain: string = "";
|
||||
/* let createType: string = "app"; */
|
||||
|
||||
export async function twCreate(options: any) {
|
||||
if (typeof projectPath === "string") {
|
||||
projectPath = projectPath.trim();
|
||||
export async function twCreate(
|
||||
pType: string,
|
||||
pPath: string = "",
|
||||
options: any,
|
||||
) {
|
||||
if (typeof pPath === "string") {
|
||||
projectPath = pPath;
|
||||
}
|
||||
|
||||
if (options.app) {
|
||||
if (typeof options.contractName === "string") {
|
||||
contractName = options.contractName;
|
||||
}
|
||||
|
||||
if (pType === "app" || options.app) {
|
||||
projectType = "app";
|
||||
}
|
||||
|
||||
if (options.contract) {
|
||||
} else if (pType === "contract" || options.contract) {
|
||||
projectType = "contract";
|
||||
}
|
||||
|
||||
if (options.typescript) {
|
||||
language = "typescript";
|
||||
if (projectType === "app") {
|
||||
if (options.typescript) {
|
||||
language = "typescript";
|
||||
}
|
||||
|
||||
if (options.javascript) {
|
||||
language = "javascript";
|
||||
}
|
||||
|
||||
if (options.next) {
|
||||
framework = "next";
|
||||
}
|
||||
|
||||
if (options.cra) {
|
||||
framework = "cra";
|
||||
}
|
||||
|
||||
if (options.vite) {
|
||||
framework = "vite";
|
||||
}
|
||||
|
||||
if (options.solana) {
|
||||
chain = "solana";
|
||||
}
|
||||
|
||||
if (options.evm) {
|
||||
chain = "evm";
|
||||
}
|
||||
}
|
||||
|
||||
if (options.javascript) {
|
||||
language = "javascript";
|
||||
}
|
||||
if (projectType === "contract") {
|
||||
if (options.forge) {
|
||||
framework = "forge";
|
||||
}
|
||||
|
||||
if (options.next) {
|
||||
framework = "next";
|
||||
}
|
||||
|
||||
if (options.cra) {
|
||||
framework = "cra";
|
||||
}
|
||||
|
||||
if (options.vite) {
|
||||
framework = "vite";
|
||||
}
|
||||
|
||||
if (options.forge) {
|
||||
framework = "forge";
|
||||
}
|
||||
|
||||
if (options.hardhat) {
|
||||
framework = "hardhat";
|
||||
if (options.hardhat) {
|
||||
framework = "hardhat";
|
||||
}
|
||||
}
|
||||
|
||||
if (options.framework) {
|
||||
@@ -76,103 +98,216 @@ export async function twCreate(options: any) {
|
||||
if (typeof res.projectType === "string") {
|
||||
projectType = res.projectType.trim();
|
||||
}
|
||||
} else if (!projectType && options.template) {
|
||||
} else if (!projectType || options.template) {
|
||||
// If no project type is specified, but a template is, we assume the user wants to create an app.
|
||||
// We do this so old users can still use the --template flag to create an app.
|
||||
projectType = "app";
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
const defaultName =
|
||||
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
|
||||
const res = await prompts({
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.projectName,
|
||||
initial: options.template || defaultName,
|
||||
format: (name: string) => name.toLowerCase(),
|
||||
validate: (name: string) => {
|
||||
const validation = validateNpmName(
|
||||
path.basename(path.resolve(name.toLowerCase())),
|
||||
);
|
||||
if (validation.valid) {
|
||||
return true;
|
||||
}
|
||||
return "Invalid project name: " + validation.problems?.[0];
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.path === "string") {
|
||||
projectPath = res.path.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
console.log(
|
||||
"\nPlease specify the project directory:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"<project-directory>",
|
||||
)}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"my-thirdweb-app",
|
||||
)}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!options.template) {
|
||||
if (projectType === "app" && !framework) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !language) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "language",
|
||||
message: CREATE_MESSAGES.language,
|
||||
choices: [
|
||||
{ title: "JavaScript", value: "javascript" },
|
||||
{ title: "TypeScript", value: "typescript" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.language === "string") {
|
||||
language = res.language.trim();
|
||||
}
|
||||
}
|
||||
// Whether to only create a new contract without the project
|
||||
let onlyContract = false;
|
||||
if (projectType === "contract") {
|
||||
const resolvedProjectPath = path.resolve(projectPath);
|
||||
const contractProjectType = await detect(resolvedProjectPath, {});
|
||||
|
||||
if (
|
||||
projectType === "contract" &&
|
||||
framework !== "forge" &&
|
||||
framework !== "hardhat"
|
||||
contractProjectType === "foundry" &&
|
||||
fs.existsSync(path.join(resolvedProjectPath, "src"))
|
||||
) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, "src");
|
||||
} else if (contractProjectType === "hardhat") {
|
||||
if (fs.existsSync(path.join(resolvedProjectPath, "contracts"))) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, "contracts");
|
||||
} else {
|
||||
// If there's no expected contracts folder, check for a directory that has .sol files
|
||||
const directories = fs
|
||||
.readdirSync(resolvedProjectPath)
|
||||
.filter((file) =>
|
||||
fs.lstatSync(path.join(resolvedProjectPath, file)).isDirectory(),
|
||||
);
|
||||
for (const directory of directories) {
|
||||
const files = fs.readdirSync(path.join(projectPath, directory));
|
||||
if (files.some((file) => file.endsWith(".sol"))) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, directory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyContract) {
|
||||
if (!projectPath) {
|
||||
const defaultName =
|
||||
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Hardhat", value: "hardhat" },
|
||||
{ title: "Forge", value: "forge" },
|
||||
],
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.projectName,
|
||||
initial: options.template || defaultName,
|
||||
format: (name: string) => name.toLowerCase(),
|
||||
validate: (name: string) => {
|
||||
const validation = validateNpmName(
|
||||
path.basename(path.resolve(name.toLowerCase())),
|
||||
);
|
||||
if (validation.valid) {
|
||||
return true;
|
||||
}
|
||||
return "Invalid project name: " + validation.problems?.[0];
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
if (typeof res.path === "string") {
|
||||
projectPath = path.join(projectPath, res.path.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
console.log(
|
||||
"\nPlease specify the project directory:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"<project-directory>",
|
||||
)}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"my-thirdweb-app",
|
||||
)}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!options.template) {
|
||||
if (projectType === "app" && !chain) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "chain",
|
||||
message: CREATE_MESSAGES.chain,
|
||||
choices: [
|
||||
{ title: "EVM", value: "evm" },
|
||||
{ title: "Solana", value: "solana" },
|
||||
],
|
||||
});
|
||||
|
||||
if (res.chain === "solana") {
|
||||
chain = "solana";
|
||||
} else {
|
||||
chain = "evm";
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !framework) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices:
|
||||
// Solana doesn't support Vite just yet:
|
||||
chain === "solana"
|
||||
? [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
// { title: "Vite", value: "vite" },
|
||||
]
|
||||
: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !language) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "language",
|
||||
message: CREATE_MESSAGES.language,
|
||||
choices: [
|
||||
{ title: "JavaScript", value: "javascript" },
|
||||
{ title: "TypeScript", value: "typescript" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.language === "string") {
|
||||
language = res.language.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
projectType === "contract" &&
|
||||
framework !== "forge" &&
|
||||
framework !== "hardhat"
|
||||
) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Hardhat", value: "hardhat" },
|
||||
{ title: "Forge", value: "forge" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "contract") {
|
||||
// Select contract name
|
||||
if (!contractName) {
|
||||
const defaultName = "MyContract";
|
||||
const res = await prompts({
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.contractName,
|
||||
initial: defaultName,
|
||||
validate: (name: string) => {
|
||||
const isValid = /(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(name);
|
||||
if (isValid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return `Invalid contract name 'contractName' (only alphanumeric characters allowed)`;
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.path === "string") {
|
||||
contractName = res.path.trim();
|
||||
}
|
||||
|
||||
if (!contractName) {
|
||||
console.log(
|
||||
"\nPlease specify the contract name:\n" +
|
||||
` ${chalk.cyan(
|
||||
"npx thirdweb create --contract --name",
|
||||
)} ${chalk.green("<contract-name>")}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan(
|
||||
"npx thirdweb create --contract --name",
|
||||
)} ${chalk.green("MyContract")}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +319,9 @@ export async function twCreate(options: any) {
|
||||
name: "standard",
|
||||
message: CREATE_MESSAGES.contract,
|
||||
choices: [
|
||||
{ title: "Empty Contract", value: "none" },
|
||||
...(!onlyContract
|
||||
? [{ title: "Empty Contract", value: "none" }]
|
||||
: []),
|
||||
{ title: "ERC721", value: "erc721" },
|
||||
{ title: "ERC20", value: "erc20" },
|
||||
{ title: "ERC1155", value: "erc1155" },
|
||||
@@ -238,20 +375,11 @@ export async function twCreate(options: any) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedProjectPath = path.resolve(projectPath);
|
||||
const projectName = path.basename(resolvedProjectPath);
|
||||
// Resolve project path
|
||||
projectPath = path.resolve(projectPath);
|
||||
const projectName = path.basename(projectPath);
|
||||
|
||||
const { valid, problems } = validateNpmName(projectName);
|
||||
if (!valid) {
|
||||
@@ -283,18 +411,21 @@ export async function twCreate(options: any) {
|
||||
try {
|
||||
if (projectType === "app") {
|
||||
await createApp({
|
||||
appPath: resolvedProjectPath,
|
||||
appPath: projectPath,
|
||||
packageManager,
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
});
|
||||
} else {
|
||||
await createContract({
|
||||
contractPath: resolvedProjectPath,
|
||||
await createContractProject({
|
||||
contractPath: projectPath,
|
||||
packageManager,
|
||||
framework,
|
||||
contractName,
|
||||
baseContract,
|
||||
onlyContract,
|
||||
});
|
||||
}
|
||||
} catch (reason) {
|
||||
|
||||
@@ -22,12 +22,14 @@ export async function createApp({
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
}: {
|
||||
appPath: string;
|
||||
packageManager: PackageManager;
|
||||
framework?: string;
|
||||
language?: string;
|
||||
template?: string;
|
||||
chain?: string;
|
||||
}): Promise<void> {
|
||||
let frameworkPath = "";
|
||||
|
||||
@@ -43,7 +45,9 @@ export async function createApp({
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (framework) {
|
||||
frameworkPath = `${framework}-${language || "javascript"}-starter`;
|
||||
frameworkPath = `${framework}-${language || "javascript"}-${
|
||||
chain === "solana" ? "solana-" : ""
|
||||
}starter`;
|
||||
const found = await hasTemplate(frameworkPath);
|
||||
|
||||
if (!found) {
|
||||
|
||||
@@ -11,22 +11,28 @@ import { submodules } from "./submodules";
|
||||
import { downloadAndExtractRepo } from "./templates";
|
||||
import retry from "async-retry";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import { writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
interface ICreateContract {
|
||||
interface ICreateContractProject {
|
||||
contractPath: string;
|
||||
packageManager: PackageManager;
|
||||
contractName: string;
|
||||
framework?: string;
|
||||
baseContract?: string;
|
||||
onlyContract: boolean;
|
||||
}
|
||||
|
||||
export async function createContract({
|
||||
export async function createContractProject({
|
||||
contractPath,
|
||||
packageManager,
|
||||
framework,
|
||||
contractName,
|
||||
baseContract,
|
||||
}: ICreateContract) {
|
||||
onlyContract,
|
||||
}: ICreateContractProject) {
|
||||
// Check that the selected base contract is valid
|
||||
if (baseContract) {
|
||||
const found = hasBaseContract(baseContract);
|
||||
|
||||
@@ -40,8 +46,8 @@ export async function createContract({
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we have write permission for the specified directory
|
||||
const root = path.resolve(contractPath);
|
||||
|
||||
if (!(await isWriteable(path.dirname(root)))) {
|
||||
console.error(
|
||||
"The application path is not writable, please check folder permissions and try again.",
|
||||
@@ -52,117 +58,165 @@ export async function createContract({
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const projectName = path.basename(root);
|
||||
|
||||
await makeDir(root);
|
||||
if (!isFolderEmpty(root, projectName)) {
|
||||
// Check that the contract name is valid
|
||||
if (!/(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(contractName)) {
|
||||
console.error(
|
||||
`Contract name ${chalk.red(
|
||||
`"${contractName}"`,
|
||||
)} is not valid (only alphanumeric characters are allowed).`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Clean the contract name
|
||||
contractName = contractName.replace(/\.sol$/, "") + ".sol";
|
||||
|
||||
const useYarn = packageManager === "yarn";
|
||||
const isOnline = !useYarn || (await getOnline());
|
||||
const originalDirectory = process.cwd();
|
||||
|
||||
console.log(
|
||||
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
process.chdir(root);
|
||||
|
||||
function isErrorLike(err: unknown): err is { message: string } {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
typeof (err as { message?: unknown }).message === "string"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Downloading files. This might take a moment.`);
|
||||
|
||||
let starter = "";
|
||||
if (framework === "hardhat") {
|
||||
starter = "hardhat-javascript-starter";
|
||||
} else if (framework === "forge") {
|
||||
starter = "forge-starter";
|
||||
} else {
|
||||
console.error("Please provide a valid contracts framework.");
|
||||
if (onlyContract) {
|
||||
// If we are already in a contracts project, just create a new contract
|
||||
if (fs.existsSync(path.join(root, contractName))) {
|
||||
console.error(
|
||||
`A contract with the name ${chalk.red(
|
||||
`"${contractName}"`,
|
||||
)} already exists in specified directory.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await retry(
|
||||
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
|
||||
{
|
||||
retries: 3,
|
||||
},
|
||||
);
|
||||
|
||||
// Modify the /contracts/MyContract.sol contents to match the base contract
|
||||
if (baseContract && baseContract.length > 0) {
|
||||
const baseContractText = readBaseContract(baseContract);
|
||||
|
||||
// Set the contents of the Contract.sol file to the base contract
|
||||
let contractFile = "";
|
||||
if (framework === "hardhat") {
|
||||
contractFile = path.join(root, "contracts", "Contract.sol");
|
||||
}
|
||||
if (framework === "forge") {
|
||||
contractFile = path.join(root, "src", "Contract.sol");
|
||||
}
|
||||
contractFile = path.join(root, contractName);
|
||||
|
||||
// Write the base contract to the MyContract.sol file
|
||||
await writeFile(contractFile, baseContractText);
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${contractName} at ${contractPath}`,
|
||||
);
|
||||
}
|
||||
} catch (reason) {
|
||||
throw new DownloadError(
|
||||
isErrorLike(reason) ? reason.message : String(reason),
|
||||
} else {
|
||||
// Otherwise, create a new contracts project
|
||||
const projectName = path.basename(root);
|
||||
|
||||
await makeDir(root);
|
||||
if (!isFolderEmpty(root, projectName)) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const isOnline = !useYarn || (await getOnline());
|
||||
const originalDirectory = process.cwd();
|
||||
|
||||
console.log(
|
||||
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
|
||||
);
|
||||
}
|
||||
console.log();
|
||||
|
||||
console.log("Installing packages. This might take a couple of minutes.");
|
||||
console.log();
|
||||
process.chdir(root);
|
||||
|
||||
await install(root, null, { packageManager, isOnline });
|
||||
console.log();
|
||||
function isErrorLike(err: unknown): err is { message: string } {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
typeof (err as { message?: unknown }).message === "string"
|
||||
);
|
||||
}
|
||||
|
||||
if (tryGitInit(root)) {
|
||||
console.log("Initialized a git repository.");
|
||||
try {
|
||||
console.log(`Downloading files. This might take a moment.`);
|
||||
|
||||
let starter = "";
|
||||
if (framework === "hardhat") {
|
||||
starter = "hardhat-javascript-starter";
|
||||
} else if (framework === "forge") {
|
||||
starter = "forge-starter";
|
||||
} else {
|
||||
console.error("Please provide a valid contracts framework.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await retry(
|
||||
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
|
||||
{
|
||||
retries: 3,
|
||||
},
|
||||
);
|
||||
|
||||
// Add in a new contracts file with specific base contract
|
||||
if (baseContract && baseContract.length > 0) {
|
||||
const baseContractText = readBaseContract(baseContract);
|
||||
|
||||
// Set the filename of the new file and delete the dummy Contract.sol file
|
||||
let contractFile = "";
|
||||
if (framework === "hardhat") {
|
||||
fs.unlinkSync(path.join(root, "contracts", "Contract.sol"));
|
||||
contractFile = path.join(root, "contracts", contractName);
|
||||
}
|
||||
if (framework === "forge") {
|
||||
fs.unlinkSync(path.join(root, "src", "Contract.sol"));
|
||||
contractFile = path.join(root, "src", contractName);
|
||||
}
|
||||
|
||||
// Write the base contract to the new file
|
||||
await writeFile(contractFile, baseContractText);
|
||||
}
|
||||
} catch (reason) {
|
||||
throw new DownloadError(
|
||||
isErrorLike(reason) ? reason.message : String(reason),
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Installing packages. This might take a couple of minutes.");
|
||||
console.log();
|
||||
|
||||
await install(root, null, { packageManager, isOnline });
|
||||
console.log();
|
||||
|
||||
if (tryGitInit(root)) {
|
||||
console.log("Initialized a git repository.");
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (framework === "forge") {
|
||||
await submodules();
|
||||
}
|
||||
|
||||
let cdpath: string;
|
||||
if (path.join(originalDirectory, projectName) === contractPath) {
|
||||
cdpath = projectName;
|
||||
} else {
|
||||
cdpath = contractPath;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
|
||||
);
|
||||
console.log();
|
||||
console.log("Inside that directory, you can run several commands:");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`),
|
||||
);
|
||||
console.log(
|
||||
" Compiles your contracts and detects thirdweb extensions implemented on them.",
|
||||
);
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`),
|
||||
);
|
||||
console.log(" Deploys your contracts with the thirdweb deploy flow.");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
|
||||
);
|
||||
console.log(" Releases your contracts with the thirdweb release flow.");
|
||||
console.log();
|
||||
console.log("We suggest that you begin by typing:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(" cd"), cdpath);
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (framework === "forge") {
|
||||
await submodules();
|
||||
}
|
||||
|
||||
let cdpath: string;
|
||||
if (path.join(originalDirectory, projectName) === contractPath) {
|
||||
cdpath = projectName;
|
||||
} else {
|
||||
cdpath = contractPath;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
|
||||
);
|
||||
console.log();
|
||||
console.log("Inside that directory, you can run several commands:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`));
|
||||
console.log(
|
||||
" Compiles your contracts and detects thirdweb extensions implemented on them.",
|
||||
);
|
||||
console.log();
|
||||
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`));
|
||||
console.log(" Deploys your contracts with the thirdweb deploy flow.");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
|
||||
);
|
||||
console.log(" Releases your contracts with the thirdweb release flow.");
|
||||
console.log();
|
||||
console.log("We suggest that you begin by typing:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(" cd"), cdpath);
|
||||
console.log();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export function tryGitInit(root: string): boolean {
|
||||
execSync("git checkout -b main", { stdio: "ignore" });
|
||||
|
||||
execSync("git add -A", { stdio: "ignore" });
|
||||
execSync('git commit -m "Initial commit from Create thirdweb app"', {
|
||||
execSync('git commit -m "Initial commit from npx thirdweb create"', {
|
||||
stdio: "ignore",
|
||||
});
|
||||
return true;
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
import spawn from "cross-spawn";
|
||||
|
||||
export async function runCommand(command: string, args: string[]) {
|
||||
export async function runCommand(
|
||||
command: string,
|
||||
args: string[],
|
||||
logging: boolean = false,
|
||||
) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
/**
|
||||
* Spawn the installation process.
|
||||
*/
|
||||
const child = spawn(command, args);
|
||||
child.stdout?.on("data", (data) => {
|
||||
if (logging) {
|
||||
console.log(data.toString());
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr?.on("error", (err) => {
|
||||
if (logging) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
reject({ command: `${command}` });
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import NPMDetector from "../core/detection/npm";
|
||||
import ViteDetector from "../core/detection/vite";
|
||||
import YarnDetector from "../core/detection/yarn";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { upload } from "../storage/command";
|
||||
import { DEFAULT_IPFS_GATEWAY } from "@thirdweb-dev/sdk";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
|
||||
export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
const storage = new ThirdwebStorage();
|
||||
const supportedFrameworks = [new ViteDetector()];
|
||||
|
||||
const possibleProjects = supportedFrameworks
|
||||
.filter((detector) => detector.matches(projectPath))
|
||||
.map((detector) => detector.projectType);
|
||||
|
||||
const hasYarn = new YarnDetector().matches(".");
|
||||
const hasNPM = new NPMDetector().matches(".");
|
||||
|
||||
if (possibleProjects.length === 0) {
|
||||
throw new Error("No supported project detected");
|
||||
}
|
||||
|
||||
try {
|
||||
if (hasYarn) {
|
||||
await runCommand("yarn", ["build"]);
|
||||
} else if (hasNPM) {
|
||||
await runCommand("npm", ["build"]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Can't build project");
|
||||
return Promise.reject("Can't build project");
|
||||
}
|
||||
|
||||
try {
|
||||
let url = await upload(storage, distPath);
|
||||
url = url.replace("ipfs://", DEFAULT_IPFS_GATEWAY);
|
||||
return `${url}/index.html`;
|
||||
} catch (err) {
|
||||
console.error("Can't upload project");
|
||||
return Promise.reject("Can't upload project");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { processProject } from "../common/processor";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { deployApp } from "./app";
|
||||
import chalk from "chalk";
|
||||
|
||||
type DeployOptions = {
|
||||
name: string;
|
||||
contractVersion: string;
|
||||
app: boolean;
|
||||
path?: string;
|
||||
distPath?: string;
|
||||
};
|
||||
|
||||
export async function deploy(options: DeployOptions) {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
if (!url) {
|
||||
logger.error(
|
||||
chalk.red(
|
||||
`Could not find a contract named ${options.name} ${
|
||||
options.contractVersion || ""
|
||||
}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
info(`Open this link to deploy your contract: ${chalk.blueBright(url)}`);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
if (options.app) {
|
||||
try {
|
||||
let url = await deployApp(options.distPath, options.path);
|
||||
info(`Here is the link to your app: ${chalk.blueBright(url.toString())}`);
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
logger.error("Failed to deploy app, No compatible project found", err);
|
||||
return Promise.reject(
|
||||
"failed to deploy app, no compatible project found",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy");
|
||||
info(
|
||||
`Open this link to deploy your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
return url.toString();
|
||||
}
|
||||
@@ -13,18 +13,18 @@ export default function generateDashboardUrl(
|
||||
// Pre-built contract
|
||||
else {
|
||||
const mapping = {
|
||||
"signature-drop": "drop/signature-drop",
|
||||
"nft-drop": "drop/nft-drop",
|
||||
"edition-drop": "drop/edition-drop",
|
||||
"nft-collection": "token/nft-collection",
|
||||
edition: "token/edition",
|
||||
"token-drop": "drop/token-drop",
|
||||
token: "token/token",
|
||||
marketplace: "marketplace/marketplace",
|
||||
split: "governance/split",
|
||||
vote: "governance/vote",
|
||||
pack: "token/pack",
|
||||
multiwrap: "token/multiwrap",
|
||||
"signature-drop": "SignatureDrop",
|
||||
"nft-drop": "DropERC721",
|
||||
"edition-drop": "DropERC1155",
|
||||
"nft-collection": "TokenERC721",
|
||||
edition: "TokenERC1155",
|
||||
"token-drop": "DropERC20",
|
||||
token: "TokenERC20",
|
||||
marketplace: "Marketplace",
|
||||
split: "Split",
|
||||
vote: "VoteERC20",
|
||||
pack: "Pack",
|
||||
multiwrap: "Multiwrap",
|
||||
};
|
||||
|
||||
const foundMapping = mapping[name as keyof typeof mapping];
|
||||
@@ -33,6 +33,6 @@ export default function generateDashboardUrl(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return `https://thirdweb.com/contracts/new/pre-built/${foundMapping}`;
|
||||
return `https://thirdweb.com/thirdweb.eth/${foundMapping}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { spinner } from "../core/helpers/logger";
|
||||
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
function recurseFiles(
|
||||
uploadPath: string,
|
||||
basePath: string,
|
||||
): BufferOrStringWithName[] {
|
||||
const files = [];
|
||||
|
||||
const fileType = fs.lstatSync(uploadPath);
|
||||
if (fileType.isFile()) {
|
||||
const fileName = path.relative(basePath, uploadPath);
|
||||
const fileData = fs.readFileSync(uploadPath);
|
||||
files.push({ name: fileName, data: fileData });
|
||||
} else if (fileType.isDirectory()) {
|
||||
const paths = fs.readdirSync(uploadPath);
|
||||
paths.forEach((subPath) => {
|
||||
const fullSubPath = path.join(uploadPath, subPath);
|
||||
const subFiles = recurseFiles(fullSubPath, basePath);
|
||||
subFiles.forEach((file) => files.push(file));
|
||||
});
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
export async function upload(
|
||||
storage: ThirdwebStorage,
|
||||
uploadPath: string,
|
||||
): Promise<string> {
|
||||
if (!uploadPath) {
|
||||
return Promise.reject("No path provided");
|
||||
}
|
||||
|
||||
const pathExists = fs.existsSync(uploadPath);
|
||||
if (!pathExists) {
|
||||
return Promise.reject("Invalid path provided");
|
||||
}
|
||||
|
||||
let uri = "";
|
||||
const fileType = fs.lstatSync(uploadPath);
|
||||
if (fileType.isDirectory()) {
|
||||
const files = recurseFiles(uploadPath, uploadPath);
|
||||
|
||||
if (files.length === 0) {
|
||||
return Promise.reject("No files detected in specified directory");
|
||||
}
|
||||
|
||||
const spin = spinner(
|
||||
"Uploading directory to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
const uris = await storage.uploadBatch(files);
|
||||
spin.succeed("Successfully uploaded directory to IPFS");
|
||||
uri = uris[0].substring(0, uris[0].lastIndexOf("/"));
|
||||
} else if (fileType.isFile()) {
|
||||
const fileName = path.parse(uploadPath).base;
|
||||
const fileData = fs.readFileSync(uploadPath);
|
||||
const file = { name: fileName, data: fileData };
|
||||
|
||||
const spin = spinner(
|
||||
"Uploading file to IPFS. This may take a while depending on file sizes.",
|
||||
);
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
spin.succeed("Succesfully uploaded file to IPFS.");
|
||||
} else {
|
||||
return Promise.reject("Invalid path provided");
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
@@ -1,5 +1,25 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#438](https://github.com/thirdweb-dev/js/pull/438) [`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SigMint detection for OSRF NFT Collection contracts
|
||||
|
||||
## 1.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#376](https://github.com/thirdweb-dev/js/pull/376) [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop with tokens claimed
|
||||
|
||||
- [#373](https://github.com/thirdweb-dev/js/pull/373) [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop contract version
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#333](https://github.com/thirdweb-dev/js/pull/333) [`aa6d9ed`](https://github.com/thirdweb-dev/js/commit/aa6d9ed75d126d7a0cca9fb8fc389ff94e9d1e14) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to contracts package v3.2.0
|
||||
|
||||
## 1.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistry__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistry__factory.esm.js"
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.1.9",
|
||||
"version": "1.2.2",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"license": "Apache-2.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/contracts": "3.1.8-0"
|
||||
"@thirdweb-dev/contracts": "3.2.8-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"ethers": "^5.7.0",
|
||||
"@typechain/ethers-v5": "10.0.0",
|
||||
"ethers": "^5.7.2",
|
||||
"typechain": "^8.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
|
||||
@@ -11,7 +11,8 @@ module.exports = {
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-parameter-properties": "error",
|
||||
"@typescript-eslint/no-unused-vars": "warn",
|
||||
// making this an error going forward
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
|
||||
// import rules
|
||||
"import/first": "error",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"eslint-config-next": "^12.0.8",
|
||||
"eslint-config-next": "12.3.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-turbo": "latest",
|
||||
"eslint-plugin-react": "^7.28.0"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-typescript",
|
||||
["@babel/preset-env", { "targets": "defaults, not ie 11" }]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# folders
|
||||
dist/
|
||||
|
||||
# files
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["thirdweb"],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
# @thirdweb-dev/pay
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#433](https://github.com/thirdweb-dev/js/pull/433) [`7269268`](https://github.com/thirdweb-dev/js/commit/72692689e9adb41e92038765fd01a36c2b7457e1) Thanks [@jnsdls](https://github.com/jnsdls)! - Initialize Pay Package
|
||||
@@ -0,0 +1,16 @@
|
||||
<p align="center">
|
||||
<br />
|
||||
<a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/packages/sdk/logo.svg?raw=true" width="200" alt=""/></a>
|
||||
<br />
|
||||
</p>
|
||||
<h1 align="center">thirdweb wallets</h1>
|
||||
<p align="center">
|
||||
<!-- <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> -->
|
||||
<!-- <a href="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml"><img alt="Build Status" src="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml/badge.svg"/></a> -->
|
||||
<!-- <a href="https://discord.gg/thirdweb"><img alt="Join our Discord!" src="https://img.shields.io/discord/834227967404146718.svg?color=7289da&label=discord&logo=discord&style=flat"/></a> -->
|
||||
|
||||
</p>
|
||||
<!-- <p align="center"><strong>Best in class Web3 SDK for Browser, Node and Mobile apps</strong></p> -->
|
||||
<br />
|
||||
|
||||
### todo
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-pay-integrations-coinbase.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay-integrations-coinbase.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/pay",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/thirdweb-dev-pay.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay.esm.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"module": "./dist/thirdweb-dev-pay.esm.js",
|
||||
"default": "./dist/thirdweb-dev-pay.cjs.js"
|
||||
},
|
||||
"./integrations/coinbase": {
|
||||
"module": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.esm.js",
|
||||
"default": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/pay",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"files": [
|
||||
"dist/",
|
||||
"integrations/"
|
||||
],
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"integrations/**"
|
||||
],
|
||||
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
|
||||
"exports": true
|
||||
},
|
||||
"exports": true
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@coinbase/cbpay-js": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write 'src/**/*'",
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"build": "tsc && preconstruct build",
|
||||
"push": "yalc push"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./integrations/coinbase";
|
||||
@@ -0,0 +1,62 @@
|
||||
import { initOnRamp, InitOnRampParams } from "@coinbase/cbpay-js";
|
||||
|
||||
interface CoinbasePayOptions extends Pick<InitOnRampParams, "appId"> {}
|
||||
|
||||
const CHAIN_ID_MAP = {
|
||||
[-1]: "solana",
|
||||
1: "ethereum",
|
||||
69: "optimism",
|
||||
137: "polygon",
|
||||
} as const;
|
||||
|
||||
export type FundWalletOptions = {
|
||||
address: string;
|
||||
chainId: keyof typeof CHAIN_ID_MAP;
|
||||
assets?: string[];
|
||||
};
|
||||
|
||||
export class CoinbasePayIntegration {
|
||||
#appId: string;
|
||||
constructor(options: CoinbasePayOptions) {
|
||||
this.#appId = options.appId;
|
||||
}
|
||||
|
||||
async fundWallet(opts: FundWalletOptions): Promise<void> {
|
||||
const { address, chainId, assets } = opts;
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
initOnRamp(
|
||||
{
|
||||
appId: this.#appId,
|
||||
widgetParameters: {
|
||||
destinationWallets: [
|
||||
{
|
||||
address,
|
||||
assets,
|
||||
supportedNetworks: [CHAIN_ID_MAP[chainId]],
|
||||
},
|
||||
],
|
||||
},
|
||||
experienceLoggedIn: "embedded",
|
||||
experienceLoggedOut: "popup",
|
||||
closeOnExit: true,
|
||||
onSuccess: () => {
|
||||
res();
|
||||
},
|
||||
onExit(error) {
|
||||
if (error) {
|
||||
return rej(error);
|
||||
}
|
||||
return res();
|
||||
},
|
||||
},
|
||||
(err, instance) => {
|
||||
if (err || !instance) {
|
||||
return rej(err);
|
||||
}
|
||||
instance.open();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@thirdweb-dev/tsconfig/sdk.json",
|
||||
"include": ["src", "types"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@@ -5,3 +5,8 @@ node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
etc/
|
||||
temp/
|
||||
temp-evm/
|
||||
temp-solana/
|
||||
docs/
|
||||
@@ -1,5 +1,211 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.6.5
|
||||
|
||||
## 3.6.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
|
||||
|
||||
- [#420](https://github.com/thirdweb-dev/js/pull/420) [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45) Thanks [@jnsdls](https://github.com/jnsdls)! - update deps
|
||||
|
||||
## 3.6.3
|
||||
|
||||
## 3.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#405](https://github.com/thirdweb-dev/js/pull/405) [`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add updateAll param to creators and royalty update hooks for Solana
|
||||
|
||||
## 3.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#392](https://github.com/thirdweb-dev/js/pull/392) [`846022e`](https://github.com/thirdweb-dev/js/commit/846022e2cfb12b846aae029b85899fb72fd2c9ad) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix unlimited price for useActiveClaimConditionForWallet
|
||||
|
||||
- [#388](https://github.com/thirdweb-dev/js/pull/388) [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for total supply and pagination on get all
|
||||
|
||||
## 3.6.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#386](https://github.com/thirdweb-dev/js/pull/386) [`612bcdd`](https://github.com/thirdweb-dev/js/commit/612bcdd16fc242d8b04bc70d609e44b0df47ed3f) Thanks [@jnsdls](https://github.com/jnsdls)! - [Gnosis Connector] - switch to safe.global hostname & add support for bsc and optimism chains
|
||||
|
||||
- [#364](https://github.com/thirdweb-dev/js/pull/364) [`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add experimental `useActiveClaimConditionForWallet()` hook
|
||||
|
||||
## 3.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#369](https://github.com/thirdweb-dev/js/pull/369) [`2d3fca5`](https://github.com/thirdweb-dev/js/commit/2d3fca52373046c88392139922e9c9da79f9a2d4) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useClaimerProofs hook
|
||||
|
||||
- [#378](https://github.com/thirdweb-dev/js/pull/378) [`32d91ef`](https://github.com/thirdweb-dev/js/commit/32d91ef709c8fb92a903e52c65b27538a80ea4eb) Thanks [@mykcryptodev](https://github.com/mykcryptodev)! - round borders for buttons and menus on safari
|
||||
|
||||
- [#377](https://github.com/thirdweb-dev/js/pull/377) [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0) Thanks [@adam-maj](https://github.com/adam-maj)! - Add event filters
|
||||
|
||||
## 3.5.1
|
||||
|
||||
## 3.5.0
|
||||
|
||||
## 3.4.5
|
||||
|
||||
## 3.4.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#356](https://github.com/thirdweb-dev/js/pull/356) [`cc4613b`](https://github.com/thirdweb-dev/js/commit/cc4613b5fd69840f4f9cfd0ac1c4e6743e62fe52) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add Pack and Multiwrap as NFTContract types
|
||||
|
||||
## 3.4.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#353](https://github.com/thirdweb-dev/js/pull/353) [`1c24c3c`](https://github.com/thirdweb-dev/js/commit/1c24c3c3c48476a824f817e09e7bf0fbe67c1db5) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useUpdateCreators hook, fix CreatorInput schema
|
||||
|
||||
## 3.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#348](https://github.com/thirdweb-dev/js/pull/348) [`7d9a4c6`](https://github.com/thirdweb-dev/js/commit/7d9a4c6abcad1b4f43e431ce7b0b38db9016ea9a) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add `useUpdateRoyaltySettings()` hook
|
||||
[SOL] - change `useRoyalty()` hook -> `useRoyaltySettings()` for consistency
|
||||
|
||||
- [#352](https://github.com/thirdweb-dev/js/pull/352) [`3522917`](https://github.com/thirdweb-dev/js/commit/352291791ee900e1500f84f095290497934d2f60) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - expose useExecuteAuctionSale and useAcceptDirectListingOffer
|
||||
|
||||
- [#351](https://github.com/thirdweb-dev/js/pull/351) [`aabbb14`](https://github.com/thirdweb-dev/js/commit/aabbb149e81d6824015a4797b2b6c929ca359545) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - fix wallet connection during dev (hot reload)
|
||||
|
||||
## 3.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#343](https://github.com/thirdweb-dev/js/pull/343) [`72227b2`](https://github.com/thirdweb-dev/js/commit/72227b2e166a3a68bbb41cf2b389322f5b7547a2) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose new useOffers and useMakeOffer hooks
|
||||
|
||||
## 3.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - Gnosis Safe and Magic Link connectors are no longer included in the default export. They are now available as named exports instead.
|
||||
|
||||
## Gnosis Safe
|
||||
|
||||
### Connector
|
||||
|
||||
```diff
|
||||
- import { GnosisSafeConnector } from "@thirdweb-dev/react";
|
||||
+ import { GnosisSafeConnector } from "@thirdweb-dev/react/evm/connectors/gnosis-safe";
|
||||
```
|
||||
|
||||
### Hook
|
||||
|
||||
```diff
|
||||
- import { useGnosis } from "@thirdweb-dev/react";
|
||||
+ import { useGnosis } from "@thirdweb-dev/react/evm/connectors/gnosis-safe";
|
||||
```
|
||||
|
||||
## Magic Link
|
||||
|
||||
### Connector
|
||||
|
||||
```diff
|
||||
- import { MagicLink } from "@thirdweb-dev/react";
|
||||
+ import { MagicConnector } from "@thirdweb-dev/react/evm/connectors/magic";
|
||||
```
|
||||
|
||||
### Hook
|
||||
|
||||
```diff
|
||||
- import { useMagic } from "@thirdweb-dev/react";
|
||||
+ import { useMagic } from "@thirdweb-dev/react/evm/connectors/magic";
|
||||
```
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#339](https://github.com/thirdweb-dev/js/pull/339) [`b03a902`](https://github.com/thirdweb-dev/js/commit/b03a9021451b79f802f682f66e5ae8e9355d7e6f) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix docs for some functions
|
||||
|
||||
## 3.3.1
|
||||
|
||||
## 3.3.0
|
||||
|
||||
## 3.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#316](https://github.com/thirdweb-dev/js/pull/316) [`6ae5266`](https://github.com/thirdweb-dev/js/commit/6ae52664e5865564cd4fc2e00e3120675b9e0ca3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SIWE when using an external signer
|
||||
|
||||
- [#310](https://github.com/thirdweb-dev/js/pull/310) [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add useMintNFTSupply hook in react and accomodate inputs for it in SDK
|
||||
|
||||
- [#319](https://github.com/thirdweb-dev/js/pull/319) [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose total claimed and unclaimed supply for erc721 drop contracts
|
||||
|
||||
- [#318](https://github.com/thirdweb-dev/js/pull/318) [`bb1b4e6`](https://github.com/thirdweb-dev/js/commit/bb1b4e6ac39d98cc68b8e31e659cd68be3a5b967) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useMinimumNextBid hook and change invariant for other marketplace hooks
|
||||
|
||||
## 3.2.5
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#301](https://github.com/thirdweb-dev/js/pull/301) [`86f0cef`](https://github.com/thirdweb-dev/js/commit/86f0ceff46f72df8ebd81f843e3c66a245f23992) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Remove useAddress hook for now
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#299](https://github.com/thirdweb-dev/js/pull/299) [`b1218cb`](https://github.com/thirdweb-dev/js/commit/b1218cbd7d97ca7949d94a7e4ab93fef4ffbacd5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Recreate SDK on wallet changes for hook propagation
|
||||
|
||||
## 3.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#289](https://github.com/thirdweb-dev/js/pull/289) [`521a49c`](https://github.com/thirdweb-dev/js/commit/521a49c6ec6a73068adcfbc1d94d2f3f17afae86) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Standarize useClaimNFT to evm
|
||||
|
||||
- [#274](https://github.com/thirdweb-dev/js/pull/274) [`ad06c5b`](https://github.com/thirdweb-dev/js/commit/ad06c5b28902422f9b416d65255c64c937a5e046) Thanks [@adam-maj](https://github.com/adam-maj)! - Add solana auth support and plugins for react and auth package
|
||||
|
||||
- [#269](https://github.com/thirdweb-dev/js/pull/269) [`b2cadf1`](https://github.com/thirdweb-dev/js/commit/b2cadf164cfe9fb27081df7530356baf70ec2b3a) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - remove deprecated chains from support
|
||||
|
||||
- [#272](https://github.com/thirdweb-dev/js/pull/272) [`2bdf198`](https://github.com/thirdweb-dev/js/commit/2bdf1984cb97121c447cffd27aa6a5f4f92679b3) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add claim conditions hook for Solana
|
||||
|
||||
- [#291](https://github.com/thirdweb-dev/js/pull/291) [`86f6083`](https://github.com/thirdweb-dev/js/commit/86f608390a7848cda82c0f7e8913ca60f7d3901f) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - expose `.program` on `useProgram()` return type to mirror `.contract` on EVM
|
||||
|
||||
- [#292](https://github.com/thirdweb-dev/js/pull/292) [`492a818`](https://github.com/thirdweb-dev/js/commit/492a818079aff67c7f88bc43666c87c3714cc957) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] expose `useAddress()` hook that returns the connected wallet address in base58
|
||||
|
||||
- [#290](https://github.com/thirdweb-dev/js/pull/290) [`8096c78`](https://github.com/thirdweb-dev/js/commit/8096c78b466a7f5f9c2aac6e2c56a06f9d3a25d6) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - `useClaimNFT()` allow claiming to connected wallet without passing address explicitly
|
||||
[EVM] - `useClaimNFT()` allow claiming to connected wallet without passing address explicitly
|
||||
|
||||
- [#298](https://github.com/thirdweb-dev/js/pull/298) [`e8c25ed`](https://github.com/thirdweb-dev/js/commit/e8c25ed0f28d566203d70bf59a8908e59216334a) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - fix useBalance
|
||||
|
||||
- [#263](https://github.com/thirdweb-dev/js/pull/263) [`d6bb61b`](https://github.com/thirdweb-dev/js/commit/d6bb61b7fac759fff7d6293edd46f693f5a7889c) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add chainId getter on contracts
|
||||
|
||||
- [#266](https://github.com/thirdweb-dev/js/pull/266) [`3b7d10e`](https://github.com/thirdweb-dev/js/commit/3b7d10ed93d8e3b698e9f905c93ba79863b35325) Thanks [@adam-maj](https://github.com/adam-maj)! - Add storage hooks to react
|
||||
|
||||
- [#282](https://github.com/thirdweb-dev/js/pull/282) [`1f41adb`](https://github.com/thirdweb-dev/js/commit/1f41adbd2ccfbc367757620e0842ef32bc783a08) Thanks [@jarrodwatts](https://github.com/jarrodwatts)! - Fix useActiveClaimCondition invariant failing for token ID 0
|
||||
|
||||
- [#296](https://github.com/thirdweb-dev/js/pull/296) [`cf88795`](https://github.com/thirdweb-dev/js/commit/cf88795376d3110f9d3aa839928d22276904b15a) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - add `useBalance` hook
|
||||
|
||||
## 3.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#264](https://github.com/thirdweb-dev/js/pull/264) [`f669d3e`](https://github.com/thirdweb-dev/js/commit/f669d3ef4a84368c23f0359aec304f66a4063042) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Standarize data between evm/solana for useLazyMint hook
|
||||
|
||||
## 3.2.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#261](https://github.com/thirdweb-dev/js/pull/261) [`c8261b7`](https://github.com/thirdweb-dev/js/commit/c8261b74b5828ac66ea3a6d7636aa57e40ea1a14) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - align behavior of `useContract()` and `getContract()` across react & sdk to both allow passing optional second params of contract types or ABIs
|
||||
|
||||
- [#236](https://github.com/thirdweb-dev/js/pull/236) [`cac373b`](https://github.com/thirdweb-dev/js/commit/cac373b010ce3be3615a36671b66815a27785061) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - do not require a connection, instead handle a network directly
|
||||
|
||||
- [#251](https://github.com/thirdweb-dev/js/pull/251) [`ea41231`](https://github.com/thirdweb-dev/js/commit/ea41231b3ec4a2aef6a203db195d0e450c45ef56) Thanks [@jnsdls](https://github.com/jnsdls)! - fix missing Buffer implementation for WalletConnect and CoinbaseWallet connectors
|
||||
|
||||
- [#253](https://github.com/thirdweb-dev/js/pull/253) [`b6fc298`](https://github.com/thirdweb-dev/js/commit/b6fc298d0cf63bc7129104f7779cc9d84e405093) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow passing contractType as second param to `useContract()`
|
||||
|
||||
- [#243](https://github.com/thirdweb-dev/js/pull/243) [`1136d95`](https://github.com/thirdweb-dev/js/commit/1136d959baf936c166e5f7c051d5173d68d9eb9b) Thanks [@jnsdls](https://github.com/jnsdls)! - fix persister logic
|
||||
|
||||
- [#258](https://github.com/thirdweb-dev/js/pull/258) [`ac232b5`](https://github.com/thirdweb-dev/js/commit/ac232b5affe31780ef1c10ec76edb21596850e7e) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Accept SmartContract instead of erc20 instance
|
||||
|
||||
- [#245](https://github.com/thirdweb-dev/js/pull/245) [`1972f3e`](https://github.com/thirdweb-dev/js/commit/1972f3ec0d511fbc17642b2a30852a177092a09e) Thanks [@jnsdls](https://github.com/jnsdls)! - [SOL] - expose `useBurnNFT` hook
|
||||
|
||||
- [#255](https://github.com/thirdweb-dev/js/pull/255) [`9b92697`](https://github.com/thirdweb-dev/js/commit/9b92697fb77d3072e3e53b451f9b348595ae410e) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - `useContract()` and `<Web3Button />` can now accept an optional ABI directly and will return a `SmartContract` based on it
|
||||
|
||||
## 3.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -26,11 +26,11 @@ The `useContractCall` hook to call a smart contract function has been renamed to
|
||||
|
||||
### Prebuilt Contract Hooks
|
||||
|
||||
Hooks to connect to prebuilt contracts such as `useNFTDrop` and `useMarketplace` are now deprecated in favour of using the generic `useContract` hook:
|
||||
Hooks to connect to prebuilt contracts such as `useNFTDrop` and `useMarketplace` are now deprecated in favour of using the generic `useContract` hook followed by the contract type:
|
||||
|
||||
```diff
|
||||
- const contract = useNFTDrop("0x...")
|
||||
+ const { contract } = useContract("0x...")
|
||||
+ const { contract } = useContract("0x...", "nft-drop")
|
||||
```
|
||||
|
||||
You can currently still continue to use the prebuilt hooks, however they provide a warning in the console informing you of their deprecation. We will likely remove these hooks in a future version of the SDK.
|
||||
|
||||
@@ -71,7 +71,7 @@ Below are examples of where to set this up in your application:
|
||||
|
||||
### Connect to a User's Wallet
|
||||
|
||||
Now the provider is set up, we can use all of the hooks and UI components available in the SDK, such as the [ConnectWallet](https://portal.thirdweb.com/sdk/ui-components/connectwalletbutton) component.
|
||||
Now the provider is set up, we can use all of the hooks and UI components available in the SDK, such as the [ConnectWallet](https://portal.thirdweb.com/ui-components/connectwalletbutton) component.
|
||||
|
||||
Once the user has connected their wallet, all the calls we make to interact with contracts using the SDK will be on behalf of the user.
|
||||
|
||||
@@ -143,7 +143,7 @@ Each [extension](https://portal.thirdweb.com/extensions) you implement in your s
|
||||
|
||||
These hooks make it easy to interact with your smart contracts by implementing the complex logic for you under the hood.
|
||||
|
||||
For example, if your smart contract implements [ERC721Supply](https://portal.thirdweb.com/extensions/erc721supply#unlocked-features), you unlock the ability to [view all NFTs](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721supply#get-all-minted-nfts) on that contract using the SDK; which fetches all of your NFT metadata and the current owner of each NFT in parallel. In the React SDK, that is available using `useNFTs`:
|
||||
For example, if your smart contract implements [ERC721Supply](https://portal.thirdweb.com/contractkit/interfaces/erc721supply#unlocked-features), you unlock the ability to [view all NFTs](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721supply#get-all-minted-nfts) on that contract using the SDK; which fetches all of your NFT metadata and the current owner of each NFT in parallel. In the React SDK, that is available using `useNFTs`:
|
||||
|
||||
```jsx
|
||||
import { useContract, useNFTs } from "@thirdweb-dev/react";
|
||||
@@ -154,7 +154,7 @@ export default function Home() {
|
||||
}
|
||||
```
|
||||
|
||||
If we want to mint an NFT and our contract implements [ERC721Mintable](https://portal.thirdweb.com/extensions/erc721mintable#unlocked-features), we can use the [`useMintNFT`](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721mintable) hook to mint an NFT from the connected wallet; handling all of the logic of uploading and pinning the metadata to IPFS for us behind the scenes.
|
||||
If we want to mint an NFT and our contract implements [ERC721Mintable](https://portal.thirdweb.com/contractkit/interfaces/erc721mintable#unlocked-features), we can use the [`useMintNFT`](https://portal.thirdweb.com/sdk/interacting-with-contracts/erc721mintable) hook to mint an NFT from the connected wallet; handling all of the logic of uploading and pinning the metadata to IPFS for us behind the scenes.
|
||||
|
||||
```jsx
|
||||
import { useContract, useNFTs, useMintNFT } from "@thirdweb-dev/react";
|
||||
@@ -172,7 +172,7 @@ export default function Home() {
|
||||
|
||||
The SDK provides many UI components to help you build your application.
|
||||
|
||||
For example, we can render each of the NFTs using the [`NFT Media Renderer`](https://portal.thirdweb.com/sdk/ui-components/nft-renderer)
|
||||
For example, we can render each of the NFTs using the [`NFT Media Renderer`](https://portal.thirdweb.com/ui-components/nft-renderer)
|
||||
component, making use of the loading state from `useNFTs`:
|
||||
|
||||
```jsx title="pages/index.jsx"
|
||||
@@ -191,7 +191,7 @@ export default function Home() {
|
||||
<div>
|
||||
{nfts.map((nft) => (
|
||||
<ThirdwebNftMedia
|
||||
key={nft.tokenId}
|
||||
key={nft.metadata.id}
|
||||
metadata={nft.metadata}
|
||||
height={200}
|
||||
/>
|
||||
@@ -203,7 +203,7 @@ export default function Home() {
|
||||
}
|
||||
```
|
||||
|
||||
The [`Web3Button`](https://portal.thirdweb.com/sdk/ui-components/web3button) component ensures the user has connected their wallet and is currently configured to the same network as your smart contract before calling the function. It also has access to the `contract` directly, allowing you to perform any action on your smart contract when the button is clicked.
|
||||
The [`Web3Button`](https://portal.thirdweb.com/ui-components/web3button) component ensures the user has connected their wallet and is currently configured to the same network as your smart contract before calling the function. It also has access to the `contract` directly, allowing you to perform any action on your smart contract when the button is clicked.
|
||||
|
||||
For example, we can mint an NFT like so:
|
||||
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
|
||||
*/
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||
/**
|
||||
* Optionally specifies another JSON config file that this file extends from. This provides a way for
|
||||
* standard settings to be shared across multiple projects.
|
||||
*
|
||||
* If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains
|
||||
* the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be
|
||||
* resolved using NodeJS require().
|
||||
*
|
||||
* SUPPORTED TOKENS: none
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "extends": "./shared/api-extractor-base.json"
|
||||
// "extends": "my-package/include/api-extractor-base.json"
|
||||
/**
|
||||
* Determines the "<projectFolder>" token that can be used with other config file settings. The project folder
|
||||
* typically contains the tsconfig.json and package.json config files, but the path is user-defined.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting.
|
||||
*
|
||||
* The default value for "projectFolder" is the token "<lookup>", which means the folder is determined by traversing
|
||||
* parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder
|
||||
* that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error
|
||||
* will be reported.
|
||||
*
|
||||
* SUPPORTED TOKENS: <lookup>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "projectFolder": "..",
|
||||
/**
|
||||
* (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor
|
||||
* analyzes the symbols exported by this module.
|
||||
*
|
||||
* The file extension must be ".d.ts" and not ".ts".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
*/
|
||||
"mainEntryPointFilePath": "<projectFolder>/solana/dist/thirdweb-dev-react-solana.cjs.d.ts",
|
||||
/**
|
||||
* A list of NPM package names whose exports should be treated as part of this package.
|
||||
*
|
||||
* For example, suppose that Webpack is used to generate a distributed bundle for the project "library1",
|
||||
* and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part
|
||||
* of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly
|
||||
* imports library2. To avoid this, we can specify:
|
||||
*
|
||||
* "bundledPackages": [ "library2" ],
|
||||
*
|
||||
* This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been
|
||||
* local files for library1.
|
||||
*/
|
||||
"bundledPackages": [
|
||||
"wagmi",
|
||||
"wagmi-core"
|
||||
],
|
||||
/**
|
||||
* Determines how the TypeScript compiler engine will be invoked by API Extractor.
|
||||
*/
|
||||
"compiler": {
|
||||
/**
|
||||
* Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* Note: This setting will be ignored if "overrideTsconfig" is used.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/tsconfig.json"
|
||||
*/
|
||||
// "tsconfigFilePath": "<projectFolder>/tsconfig.json",
|
||||
/**
|
||||
* Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk.
|
||||
* The object must conform to the TypeScript tsconfig schema:
|
||||
*
|
||||
* http://json.schemastore.org/tsconfig
|
||||
*
|
||||
* If omitted, then the tsconfig.json file will be read from the "projectFolder".
|
||||
*
|
||||
* DEFAULT VALUE: no overrideTsconfig section
|
||||
*/
|
||||
"overrideTsconfig": {
|
||||
"skipLibCheck": true
|
||||
}
|
||||
/**
|
||||
* This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended
|
||||
* and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when
|
||||
* dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses
|
||||
* for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "skipLibCheck": true,
|
||||
},
|
||||
/**
|
||||
* Configures how the API report file (*.api.md) will be generated.
|
||||
*/
|
||||
"apiReport": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate an API report.
|
||||
*/
|
||||
"enabled": true
|
||||
/**
|
||||
* The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce
|
||||
* a full file path.
|
||||
*
|
||||
* The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/".
|
||||
*
|
||||
* SUPPORTED TOKENS: <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<unscopedPackageName>.api.md"
|
||||
*/
|
||||
// "reportFileName": "<unscopedPackageName>.api.md",
|
||||
/**
|
||||
* Specifies the folder where the API report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy,
|
||||
* e.g. for an API review.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/etc/"
|
||||
*/
|
||||
// "reportFolder": "<projectFolder>/etc/",
|
||||
/**
|
||||
* Specifies the folder where the temporary report file is written. The file name portion is determined by
|
||||
* the "reportFileName" setting.
|
||||
*
|
||||
* After the temporary file is written to disk, it is compared with the file in the "reportFolder".
|
||||
* If they are different, a production build will fail.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/"
|
||||
*/
|
||||
// "reportTempFolder": "<projectFolder>/temp/"
|
||||
},
|
||||
/**
|
||||
* Configures how the doc model file (*.api.json) will be generated.
|
||||
*/
|
||||
"docModel": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate a doc model file.
|
||||
*/
|
||||
"enabled": true
|
||||
/**
|
||||
* The output path for the doc model file. The file extension should be ".api.json".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
*/
|
||||
// "apiJsonFilePath": "<projectFolder>/temp/<unscopedPackageName>.api.json"
|
||||
},
|
||||
/**
|
||||
* Configures how the .d.ts rollup file will be generated.
|
||||
*/
|
||||
"dtsRollup": {
|
||||
/**
|
||||
* (REQUIRED) Whether to generate the .d.ts rollup file.
|
||||
*/
|
||||
"enabled": false,
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated without any trimming.
|
||||
* This file will include all declarations that are exported by the main entry point.
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<projectFolder>/dist/<unscopedPackageName>.d.ts"
|
||||
*/
|
||||
"untrimmedFilePath": "<projectFolder>/lib/<unscopedPackageName>.d.ts"
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release.
|
||||
* This file will include only declarations that are marked as "@public" or "@beta".
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-beta.d.ts",
|
||||
/**
|
||||
* Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release.
|
||||
* This file will include only declarations that are marked as "@public".
|
||||
*
|
||||
* If the path is an empty string, then this file will not be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: ""
|
||||
*/
|
||||
// "publicTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>-public.d.ts",
|
||||
/**
|
||||
* When a declaration is trimmed, by default it will be replaced by a code comment such as
|
||||
* "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the
|
||||
* declaration completely.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "omitTrimmingComments": true
|
||||
},
|
||||
/**
|
||||
* Configures how the tsdoc-metadata.json file will be generated.
|
||||
*/
|
||||
"tsdocMetadata": {
|
||||
/**
|
||||
* Whether to generate the tsdoc-metadata.json file.
|
||||
*
|
||||
* DEFAULT VALUE: true
|
||||
*/
|
||||
// "enabled": true,
|
||||
/**
|
||||
* Specifies where the TSDoc metadata file should be written.
|
||||
*
|
||||
* The path is resolved relative to the folder of the config file that contains the setting; to change this,
|
||||
* prepend a folder token such as "<projectFolder>".
|
||||
*
|
||||
* The default value is "<lookup>", which causes the path to be automatically inferred from the "tsdocMetadata",
|
||||
* "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup
|
||||
* falls back to "tsdoc-metadata.json" in the package folder.
|
||||
*
|
||||
* SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
|
||||
* DEFAULT VALUE: "<lookup>"
|
||||
*/
|
||||
// "tsdocMetadataFilePath": "<projectFolder>/dist/tsdoc-metadata.json"
|
||||
},
|
||||
/**
|
||||
* Specifies what type of newlines API Extractor should use when writing output files. By default, the output files
|
||||
* will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead.
|
||||
* To use the OS's default newline kind, specify "os".
|
||||
*
|
||||
* DEFAULT VALUE: "crlf"
|
||||
*/
|
||||
// "newlineKind": "crlf",
|
||||
/**
|
||||
* Configures how API Extractor reports error and warning messages produced during analysis.
|
||||
*
|
||||
* There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages.
|
||||
*/
|
||||
"messages": {
|
||||
/**
|
||||
* Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing
|
||||
* the input .d.ts files.
|
||||
*
|
||||
* TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"compilerMessageReporting": {
|
||||
/**
|
||||
* Configures the default routing for messages that don't match an explicit rule in this table.
|
||||
*/
|
||||
"default": {
|
||||
/**
|
||||
* Specifies whether the message should be written to the the tool's output log. Note that
|
||||
* the "addToApiReportFile" property may supersede this option.
|
||||
*
|
||||
* Possible values: "error", "warning", "none"
|
||||
*
|
||||
* Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail
|
||||
* and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes
|
||||
* the "--local" option), the warning is displayed but the build will not fail.
|
||||
*
|
||||
* DEFAULT VALUE: "warning"
|
||||
*/
|
||||
"logLevel": "warning"
|
||||
/**
|
||||
* When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md),
|
||||
* then the message will be written inside that file; otherwise, the message is instead logged according to
|
||||
* the "logLevel" option.
|
||||
*
|
||||
* DEFAULT VALUE: false
|
||||
*/
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "TS2551": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
/**
|
||||
* Configures handling of messages reported by API Extractor during its analysis.
|
||||
*
|
||||
* API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag"
|
||||
*
|
||||
* DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings
|
||||
*/
|
||||
"extractorMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "ae-extra-release-tag": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
},
|
||||
/**
|
||||
* Configures handling of messages reported by the TSDoc parser when analyzing code comments.
|
||||
*
|
||||
* TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text"
|
||||
*
|
||||
* DEFAULT VALUE: A single "default" entry with logLevel=warning.
|
||||
*/
|
||||
"tsdocMessageReporting": {
|
||||
"default": {
|
||||
"logLevel": "warning"
|
||||
// "addToApiReportFile": false
|
||||
}
|
||||
// "tsdoc-link-tag-unescaped-text": {
|
||||
// "logLevel": "warning",
|
||||
// "addToApiReportFile": true
|
||||
// },
|
||||
//
|
||||
// . . .
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-react-evm-connectors-gnosis-safe.cjs.js",
|
||||
"module": "dist/thirdweb-dev-react-evm-connectors-gnosis-safe.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-react-evm-connectors-magic.cjs.js",
|
||||
"module": "dist/thirdweb-dev-react-evm-connectors-magic.esm.js"
|
||||
}
|
||||
+27
-22
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.1.2",
|
||||
"version": "3.6.5",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -20,6 +20,14 @@
|
||||
"module": "./solana/dist/thirdweb-dev-react-solana.esm.js",
|
||||
"default": "./solana/dist/thirdweb-dev-react-solana.cjs.js"
|
||||
},
|
||||
"./evm/connectors/magic": {
|
||||
"module": "./evm/connectors/magic/dist/thirdweb-dev-react-evm-connectors-magic.esm.js",
|
||||
"default": "./evm/connectors/magic/dist/thirdweb-dev-react-evm-connectors-magic.cjs.js"
|
||||
},
|
||||
"./evm/connectors/gnosis-safe": {
|
||||
"module": "./evm/connectors/gnosis-safe/dist/thirdweb-dev-react-evm-connectors-gnosis-safe.esm.js",
|
||||
"default": "./evm/connectors/gnosis-safe/dist/thirdweb-dev-react-evm-connectors-gnosis-safe.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
@@ -31,7 +39,8 @@
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"solana/index.ts",
|
||||
"evm/index.ts"
|
||||
"evm/index.ts",
|
||||
"evm/connectors/**.ts"
|
||||
],
|
||||
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
|
||||
"exports": true
|
||||
@@ -44,32 +53,29 @@
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"generate-docs": "api-extractor run --local && yarn api-documenter markdown -i ./temp -o ./docs && yarn generate-snippets",
|
||||
"generate:md-docs": "yarn api-documenter markdown -i ./temp -o ./docs",
|
||||
"generate-snippets": "node ./scripts/generate-snippets.mjs && node ./scripts/generate-feature-snippets.mjs",
|
||||
"generate-docs": "yarn generate-docs:evm && yarn generate-docs:solana && yarn generate-snippets",
|
||||
"generate-docs:evm": "api-extractor run --local --config ./config/api-extractor-evm.json && api-documenter markdown -i ./temp -o ./docs/evm && rm -rf ./temp-evm && mv ./temp ./temp-evm",
|
||||
"generate-docs:solana": "api-extractor run --local --config ./config/api-extractor-solana.json && api-documenter markdown -i ./temp -o ./docs/solana && rm -rf ./temp-solana && mv ./temp ./temp-solana",
|
||||
"generate-snippets": "node ./scripts/generate-snippets-evm.mjs && node ./scripts/generate-snippets-solana.mjs && node ./scripts/generate-feature-snippets-evm.mjs",
|
||||
"build": "tsc && preconstruct build",
|
||||
"e2e": "yarn test-ct",
|
||||
"test-ct": "playwright test -c playwright-ct.config.ts",
|
||||
"push": "yalc push"
|
||||
},
|
||||
"sideEffects:": false,
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.10",
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@babel/runtime": "^7.19.0",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
"@microsoft/api-extractor": "^7.29.2",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@playwright/experimental-ct-react": "1.25.1",
|
||||
"@playwright/test": "1.25.1",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@solana/wallet-adapter-base": "^0.9.17",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/wallet-adapter-wallets": "^0.19.0",
|
||||
"@solana/web3.js": "^1.63.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"@thirdweb-dev/solana": "*",
|
||||
"@types/color": "^3.0.3",
|
||||
"@types/mime": "^3.0.1",
|
||||
"@types/react": "^18.0.5",
|
||||
@@ -82,7 +88,7 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.2",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
@@ -91,13 +97,15 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/styled": "^11.10.0",
|
||||
"@gnosis.pm/safe-core-sdk": "2.1.0",
|
||||
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.9",
|
||||
"@gnosis.pm/safe-ethers-lib": "1.1.0",
|
||||
"@gnosis.pm/safe-core-sdk": "^3.1.1",
|
||||
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.11",
|
||||
"@gnosis.pm/safe-ethers-lib": "^1.6.1",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@solana/wallet-adapter-phantom": "^0.9.17",
|
||||
"@tanstack/react-query": "^4.0.10",
|
||||
"@zag-js/menu": "0.1.14",
|
||||
"@zag-js/react": "0.1.16",
|
||||
"@zag-js/menu": "^0.1.16",
|
||||
"@zag-js/react": "^0.1.18",
|
||||
"buffer": "^6.0.3",
|
||||
"color": "^4.2.3",
|
||||
"copy-to-clipboard": "^3.3.2",
|
||||
"detect-browser": "^5.3.0",
|
||||
@@ -111,7 +119,7 @@
|
||||
"@solana/wallet-adapter-base": "^0.9.17",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/wallet-adapter-wallets": "^0.19.0",
|
||||
"@solana/web3.js": "^1.63.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"ethers": ">=5.5.1",
|
||||
"react": ">=18.0.0",
|
||||
@@ -133,9 +141,6 @@
|
||||
},
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
},
|
||||
"@thirdweb-dev/solana": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import type { PlaywrightTestConfig } from "@playwright/experimental-ct-react";
|
||||
import { devices } from "@playwright/experimental-ct-react";
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
const config: PlaywrightTestConfig = {
|
||||
testDir: "./",
|
||||
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
|
||||
snapshotDir: "./__snapshots__",
|
||||
/* Maximum time one test can run for. */
|
||||
timeout: 10 * 1000,
|
||||
/* Run tests in files in parallel */
|
||||
fullyParallel: true,
|
||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
// workers: process.env.CI ? 1 : undefined,
|
||||
// we can use parallel tests because we have more cores now
|
||||
workers: undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
reporter: "html",
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
use: {
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: "on-first-retry",
|
||||
|
||||
/* Port to use for Playwright component endpoint. */
|
||||
ctPort: 3100,
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: {
|
||||
...devices["Desktop Chrome"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "firefox",
|
||||
use: {
|
||||
...devices["Desktop Firefox"],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "webkit",
|
||||
use: {
|
||||
...devices["Desktop Safari"],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,4 +0,0 @@
|
||||
// Import styles, initialize component theme here.
|
||||
// import '../src/common.css';
|
||||
|
||||
export {};
|
||||
+2
-2
@@ -44,7 +44,7 @@ config.setSupportForTag(tag, true);
|
||||
const tsdocParser = new TSDocParser(config);
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp/react.api.json`, "utf8"),
|
||||
fs.readFileSync(`${process.cwd()}/temp-evm/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
@@ -160,6 +160,6 @@ classes.forEach((m) => {
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/feature_snippets.json`,
|
||||
`${process.cwd()}/docs/evm/feature_snippets.json`,
|
||||
JSON.stringify(features, null, 2),
|
||||
);
|
||||
+25
-41
@@ -27,41 +27,6 @@ export class Formatter {
|
||||
}
|
||||
}
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
const CONTRACT_HOOKS = [
|
||||
"useSignatureDrop",
|
||||
"useNFTDrop",
|
||||
"useEditionDrop",
|
||||
"useNFTCollection",
|
||||
"useEdition",
|
||||
"useTokenDrop",
|
||||
"useToken",
|
||||
"useMarketplace",
|
||||
"useSplit",
|
||||
"useVote",
|
||||
"usePack",
|
||||
"useMultiwrap",
|
||||
"useContract",
|
||||
];
|
||||
|
||||
const NFT_HOOKS = [
|
||||
"useNFT",
|
||||
"useNFTs",
|
||||
@@ -141,7 +106,7 @@ const CONTRACT_SETTINGS_HOOKS = [
|
||||
"useRevokeRole",
|
||||
];
|
||||
|
||||
const CONTRACT_SUBHOOKS = {
|
||||
const HOOKS_CONFIG = {
|
||||
useSignatureDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
useNFTDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
useEditionDrop: [...NFT_HOOKS, ...DROP_HOOKS, ...CLAIM_CONDITIONS_HOOKS],
|
||||
@@ -162,8 +127,27 @@ const CONTRACT_SUBHOOKS = {
|
||||
],
|
||||
};
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp-evm/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
const hooks = json.members[0].members.filter(
|
||||
(m) => m.kind === "Function" && CONTRACT_HOOKS.includes(m.name),
|
||||
(m) => m.kind === "Function" && Object.keys(HOOKS_CONFIG).includes(m.name),
|
||||
);
|
||||
|
||||
function parseExampleTag(docComment) {
|
||||
@@ -192,7 +176,7 @@ function parseExampleTag(docComment) {
|
||||
return examples;
|
||||
}
|
||||
|
||||
const baseDocUrl = "https://docs.thirdweb.com/typescript/react.";
|
||||
const baseDocUrl = "https://portal.thirdweb.com/react/react.";
|
||||
|
||||
const extractReferenceLink = (m, kind, contractName) => {
|
||||
if (kind === "Property") {
|
||||
@@ -212,7 +196,7 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
const examples = parseExampleTag(docComment);
|
||||
|
||||
const contractSubhooks = json.members[0].members.filter(
|
||||
(f) => f.kind === "Function" && CONTRACT_SUBHOOKS[m.name].includes(f.name),
|
||||
(f) => f.kind === "Function" && HOOKS_CONFIG[m.name].includes(f.name),
|
||||
);
|
||||
|
||||
const contractHooks = contractSubhooks.map((subhookContent) => {
|
||||
@@ -223,7 +207,7 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
return {
|
||||
name: subhookContent.name,
|
||||
example: subhookExamples?.javascript || "",
|
||||
reference: `https://portal.thirdweb.com/react/react.${subhookContent.name.toLowerCase()}`,
|
||||
reference: `${baseDocUrl}${subhookContent.name.toLowerCase()}`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -241,6 +225,6 @@ const moduleMap = hooks.reduce((acc, m) => {
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/snippets.json`,
|
||||
`${process.cwd()}/docs/evm/snippets.json`,
|
||||
JSON.stringify(moduleMap, null, 2),
|
||||
);
|
||||
@@ -0,0 +1,135 @@
|
||||
import { Formatter } from "./generate-snippets-evm.mjs";
|
||||
import { TSDocParser } from "@microsoft/tsdoc";
|
||||
import fs from "fs";
|
||||
|
||||
const NFT_HOOKS = ["useMintNFT", "useNFT", "useNFTs", "useTransferNFT"];
|
||||
|
||||
const DROP_HOOKS = [
|
||||
"useClaimedSupply",
|
||||
"useClaimNFT",
|
||||
"useLazyMintNFT",
|
||||
"useUnclaimedSupply",
|
||||
];
|
||||
|
||||
const TOKEN_HOOKS = [
|
||||
"useMintToken",
|
||||
"useTokenBalance",
|
||||
"useTokenSupply",
|
||||
"useTransferToken",
|
||||
];
|
||||
|
||||
const HOOKS_CONFIG = {
|
||||
useNFTCollection: [...NFT_HOOKS],
|
||||
useNFTDrop: [...NFT_HOOKS, ...DROP_HOOKS],
|
||||
useToken: [...TOKEN_HOOKS],
|
||||
useProgram: [],
|
||||
};
|
||||
|
||||
const tsdocParser = new TSDocParser();
|
||||
|
||||
const json = JSON.parse(
|
||||
fs.readFileSync(`${process.cwd()}/temp-solana/react.api.json`, "utf8"),
|
||||
);
|
||||
|
||||
function languageNameToKey(languageName) {
|
||||
switch (languageName) {
|
||||
case "js":
|
||||
case "jsx":
|
||||
return "javascript";
|
||||
case "ts":
|
||||
case "tsx":
|
||||
return "typescript";
|
||||
default:
|
||||
return languageName;
|
||||
}
|
||||
}
|
||||
|
||||
function parseExampleTag(docComment) {
|
||||
const exampleBlocks = docComment._customBlocks.filter(
|
||||
(b) => b._blockTag._tagName === "@example",
|
||||
);
|
||||
|
||||
const examplesString = Formatter.renderDocNodes(exampleBlocks);
|
||||
|
||||
const regex = /```([a-zA-Z]*)\n([\S\s]*?)\n```/g;
|
||||
|
||||
let matches;
|
||||
|
||||
const examples = {};
|
||||
|
||||
while ((matches = regex.exec(examplesString)) !== null) {
|
||||
// This is necessary to avoid infinite loops with zero-width matches
|
||||
if (matches.index === regex.lastIndex) {
|
||||
regex.lastIndex++;
|
||||
}
|
||||
|
||||
const re = /\n( *)\/\/ For example((.|\n)*)\.\.\.\n/g;
|
||||
const example = matches[2].replace(re, "");
|
||||
examples[languageNameToKey(matches[1])] = example;
|
||||
}
|
||||
return examples;
|
||||
}
|
||||
|
||||
const baseDocUrl = "https://portal.thirdweb.com/react/solana/react.";
|
||||
|
||||
const extractReferenceLink = (m, kind, contractName) => {
|
||||
if (kind === "Property") {
|
||||
return m.excerptTokens
|
||||
.filter((e) => e.kind === "Reference")
|
||||
.map((e) => `${baseDocUrl}${e.text.toLowerCase()}`)[0];
|
||||
}
|
||||
if (kind === "Method") {
|
||||
return `${baseDocUrl}${contractName}.${m.name}`;
|
||||
}
|
||||
return `${baseDocUrl}${m.name}`;
|
||||
};
|
||||
|
||||
const moduleMap = Object.keys(HOOKS_CONFIG).reduce((acc, hookName) => {
|
||||
let summary = "";
|
||||
let examples = {};
|
||||
let reference = "";
|
||||
|
||||
const doc = json.members[0].members.find(
|
||||
(m) =>
|
||||
m.kind === "Function" && Object.keys(HOOKS_CONFIG).includes(hookName),
|
||||
);
|
||||
|
||||
if (doc) {
|
||||
const parserContext = tsdocParser.parseString(doc);
|
||||
const docComment = parserContext.docComment;
|
||||
summary = Formatter.renderDocNode(docComment.summarySection);
|
||||
examples = parseExampleTag(docComment);
|
||||
reference = extractReferenceLink(doc);
|
||||
}
|
||||
|
||||
const contractSubhooks = json.members[0].members.filter(
|
||||
(f) => f.kind === "Function" && HOOKS_CONFIG[hookName].includes(f.name),
|
||||
);
|
||||
|
||||
const subhooks = contractSubhooks.map((subhookContent) => {
|
||||
const subhookContext = tsdocParser.parseString(subhookContent.docComment);
|
||||
const subhookComment = subhookContext.docComment;
|
||||
const subhookExamples = parseExampleTag(subhookComment);
|
||||
|
||||
return {
|
||||
name: subhookContent.name,
|
||||
example: subhookExamples?.javascript || "",
|
||||
reference: `${baseDocUrl}${subhookContent.name.toLowerCase()}`,
|
||||
};
|
||||
});
|
||||
|
||||
acc[hookName] = {
|
||||
name: hookName,
|
||||
summary,
|
||||
examples,
|
||||
subhooks,
|
||||
reference,
|
||||
};
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(
|
||||
`${process.cwd()}/docs/solana/snippets.json`,
|
||||
JSON.stringify(moduleMap, null, 2),
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RequiredParam } from "../types/shared";
|
||||
import { QueryKey } from "@tanstack/react-query";
|
||||
import type { ChainId } from "@thirdweb-dev/sdk";
|
||||
import { RequiredParam } from "./required-param";
|
||||
import type { QueryKey } from "@tanstack/react-query";
|
||||
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
|
||||
import type {
|
||||
Network,
|
||||
NFTCollection,
|
||||
@@ -13,7 +13,7 @@ const TW_QUERY_KEY_PREFIX = "__tw__";
|
||||
// marker to make sure the query will not get stored in local storage by a query persister
|
||||
const NEVER_PERSIST_QUERY_POSTFIX = { persist: false } as const;
|
||||
|
||||
function ensureTWPrefix<TKey extends QueryKey>(key: TKey) {
|
||||
export function ensureTWPrefix<TKey extends QueryKey>(key: TKey) {
|
||||
if (key[0] === TW_QUERY_KEY_PREFIX) {
|
||||
return key as unknown as Readonly<[typeof TW_QUERY_KEY_PREFIX, ...TKey]>;
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export function neverPersist<TKey extends QueryKey>(key: TKey) {
|
||||
export function shouldNeverPersistQuery<TKey extends QueryKey>(
|
||||
key: TKey,
|
||||
): boolean {
|
||||
return key[key.length] === NEVER_PERSIST_QUERY_POSTFIX;
|
||||
return key[key.length - 1] === NEVER_PERSIST_QUERY_POSTFIX;
|
||||
}
|
||||
|
||||
// EVM
|
||||
@@ -37,11 +37,23 @@ export function createEVMQueryKey<TKey extends QueryKey>(key: TKey) {
|
||||
}
|
||||
export function createEVMQueryKeyWithChain<TKey extends QueryKey>(
|
||||
key: TKey,
|
||||
chainId: RequiredParam<ChainId>,
|
||||
chainId: RequiredParam<number>,
|
||||
) {
|
||||
return ensureTWPrefix([chainId, ...key] as const);
|
||||
}
|
||||
|
||||
export function createEVMContractQueryKey<TKey extends QueryKey>(
|
||||
contract: RequiredParam<ValidContractInstance>,
|
||||
key: TKey = [] as unknown as TKey,
|
||||
) {
|
||||
const chainId = contract?.chainId;
|
||||
const address = contract?.getAddress();
|
||||
return createEVMQueryKeyWithChain(
|
||||
["contract", address, ...key] as const,
|
||||
chainId,
|
||||
);
|
||||
}
|
||||
|
||||
// SOL
|
||||
|
||||
export function createSOLQueryKey<TKey extends QueryKey>(key: TKey) {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type RequiredParam<T> = T | null | undefined;
|
||||
|
||||
export function requiredParamInvariant<TValue>(
|
||||
condition: RequiredParam<TValue>,
|
||||
message?: string,
|
||||
): asserts condition {
|
||||
invariant(condition !== null || condition !== undefined, message);
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
/**
|
||||
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export type RequiredParam<T> = T | null | undefined;
|
||||
@@ -1,15 +0,0 @@
|
||||
import { ConnectWallet } from ".";
|
||||
import { ThirdwebProvider } from "../../providers/full";
|
||||
import { test, expect } from "@playwright/experimental-ct-react";
|
||||
|
||||
test.use({ viewport: { width: 500, height: 500 } });
|
||||
|
||||
test("should render the connect wallet button", async ({ mount }) => {
|
||||
const component = await mount(
|
||||
<ThirdwebProvider desiredChainId={1}>
|
||||
<ConnectWallet />
|
||||
</ThirdwebProvider>,
|
||||
);
|
||||
|
||||
await expect(component).toContainText("Connect Wallet");
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user