Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions apps/dashboard/src/app/pay/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,44 @@ type SearchParams = {
[key: string]: string | string[] | undefined;
};

const onlyAddress = (v: string) => (isAddress(v) ? v : undefined);
const onlyNumber = (v: string) =>
Number.isNaN(Number(v)) ? undefined : Number(v);

/**
* Validates and normalizes a URL string.
* Only allows http: and https: protocols with a valid hostname.
* @returns normalized URL string on success, undefined on failure
*/
const onlyUrl = (v: string): string | undefined => {
try {
const url = new URL(v);
// Only allow http or https protocols
if (url.protocol !== "http:" && url.protocol !== "https:") {
return undefined;
}
// Ensure hostname is non-empty
if (!url.hostname) {
return undefined;
}
// Return normalized URL
return url.toString();
} catch {
// Invalid URL format
return undefined;
}
};

export default async function PayPage(props: {
searchParams: Promise<SearchParams>;
}) {
const searchParams = await props.searchParams;

const onlyAddress = (v: string) => (isAddress(v) ? v : undefined);
const onlyNumber = (v: string) =>
Number.isNaN(Number(v)) ? undefined : Number(v);

const receiver = parse(searchParams.receiver, onlyAddress);
const token = parse(searchParams.token, onlyAddress);
const chain = parse(searchParams.chain, onlyNumber);
const amount = parse(searchParams.amount, onlyNumber);
const successUrl = parse(searchParams.successUrl, onlyUrl);

return (
<ThemeProvider
Expand All @@ -51,6 +76,22 @@ export default async function PayPage(props: {
tokenAddress={token}
receiverAddress={receiver}
amount={amount ? amount.toString() : undefined}
onSuccess={() => {
if (successUrl) {
try {
const url = new URL(successUrl);
url.searchParams.set("success", "true");
window.location.href = url.toString();
} catch (error) {
// Log URL construction error for debugging
console.error(
"Failed to construct redirect URL:",
successUrl,
error,
);
}
}
}}
/>
</div>
</div>
Expand Down
13 changes: 13 additions & 0 deletions packages/nexus-fetch/.size-limit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"import": "*",
"limit": "1 kB",
"name": "@thirdweb-dev/nexus (esm)",
"path": "./dist/esm/exports/nexus.js"
},
{
"limit": "1 kB",
"name": "@thirdweb-dev/nexus (cjs)",
"path": "./dist/cjs/exports/nexus.js"
}
]
16 changes: 16 additions & 0 deletions packages/nexus-fetch/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.6/schema.json",
"extends": "//",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix the invalid Biome extends entry.

extends must resolve to an actual Biome config or shareable preset. The literal string "//" has no meaning here, so pnpm biome check fails while trying to load that path. Point it at the real base config (e.g. ../../biome.json) or drop the property altogether so biome can run.

🤖 Prompt for AI Agents
In packages/nexus-fetch/biome.json around line 3, the "extends" entry is invalid
("//"); replace it with a real Biome config path (for example
"../../biome.json") or remove the "extends" property entirely so Biome can
resolve a base config and pnpm biome check will succeed.

"overrides": [
{
"assist": {
"actions": {
"source": {
"useSortedKeys": "off"
}
}
},
"includes": ["package.json"]
}
]
}
12 changes: 12 additions & 0 deletions packages/nexus-fetch/knip.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://unpkg.com/knip@5/schema.json",
"entry": ["src/exports/**"],
"ignore": ["src/**/__generated__/**", "**/*.bench.ts"],
"ignoreBinaries": ["printf"],
"ignoreDependencies": ["tslib"],
"project": ["src/**/*.{ts,tsx}"],
"rules": {
"enumMembers": "off",
"optionalPeerDependencies": "off"
}
}
76 changes: 76 additions & 0 deletions packages/nexus-fetch/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"author": "thirdweb eng <eng@thirdweb.com>",
"browser": {
"crypto": false
},
"bugs": {
"url": "https://github.com/thirdweb-dev/js/issues"
},
"devDependencies": {
"@biomejs/biome": "2.0.6",
"@size-limit/preset-small-lib": "11.2.0",
"knip": "5.60.2",
"rimraf": "6.0.1",
"size-limit": "11.2.0",
"typescript": "5.8.3"
},
"engines": {
"node": ">=22"
},
"exports": {
".": {
"types": "./dist/types/exports/nexus-fetch.d.ts",
"import": "./dist/esm/exports/nexus-fetch.js",
"default": "./dist/cjs/exports/nexus-fetch.js"
}
},
"files": [
"dist/*",
"src/*",
"!**/*.tsbuildinfo",
"!**/*.test.ts",
"!**/*.test.tsx",
"!**/*.test.ts.snap",
"!**/*.test-d.ts",
"!**/*.bench.ts",
"!tsconfig.build.json"
],
"license": "Apache-2.0",
"main": "./dist/cjs/exports/nexus-fetch.js",
"module": "./dist/esm/exports/nexus-fetch.js",
"name": "@thirdweb-dev/fetch",
"peerDependencies": {
"typescript": ">=5.0.4"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
},
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
},
"scripts": {
"build": "pnpm clean && pnpm build:types && pnpm build:cjs && pnpm build:esm",
"build:cjs": "tsc --noCheck --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json",
"build:esm": "tsc --noCheck --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
"build:types": "tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
"clean": "rimraf dist",
"dev": "tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --outDir ./dist/esm --watch",
"dev:cjs": "printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json && tsc --noCheck --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false --watch",
"dev:esm": "printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json && tsc --noCheck --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm --watch",
"fix": "biome check ./src --fix",
"format": "biome format ./src --write",
"knip": "knip",
"lint": "knip && biome check ./src && tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit",
"size": "size-limit",
"typecheck": "tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit",
"test:ui": "bun ./testing/test.html --watch"
},
"sideEffects": false,
"type": "module",
"types": "./dist/types/exports/nexus-fetch.d.ts",
"typings": "./dist/types/exports/nexus-fetch.d.ts",
"version": "0.0.0"
}
1 change: 1 addition & 0 deletions packages/nexus-fetch/src/exports/nexus-fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { wrap } from "../fetch.js";
Loading
Loading