@payai/x402-next-starter 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +2 -0
- package/README.md +85 -0
- package/bin/create.js +87 -0
- package/package.json +39 -0
- package/template/.env-local +3 -0
- package/template/.prettierignore +8 -0
- package/template/.prettierrc +11 -0
- package/template/README.md +127 -0
- package/template/app/assets/x402_wordmark_dark.png +0 -0
- package/template/app/assets/x402_wordmark_dark.svg +4 -0
- package/template/app/assets/x402_wordmark_light.svg +1 -0
- package/template/app/favicon.ico +0 -0
- package/template/app/globals.css +33 -0
- package/template/app/layout.tsx +51 -0
- package/template/app/page.tsx +51 -0
- package/template/app/protected/page.tsx +16 -0
- package/template/eslint.config.js +73 -0
- package/template/middleware.ts +31 -0
- package/template/next.config.ts +17 -0
- package/template/package-lock.json +8726 -0
- package/template/package.json +42 -0
- package/template/postcss.config.mjs +8 -0
- package/template/public/apple-touch-icon.png +0 -0
- package/template/public/favicon-96x96.png +0 -0
- package/template/public/favicon.svg +3 -0
- package/template/public/site.webmanifest +21 -0
- package/template/public/web-app-manifest-192x192.png +0 -0
- package/template/public/web-app-manifest-512x512.png +0 -0
- package/template/public/x402-icon-blue.png +0 -0
- package/template/tailwind.config.ts +18 -0
- package/template/tsconfig.json +27 -0
- package/template/types/svg.d.ts +5 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
import WordmarkCondensed from './assets/x402_wordmark_light.svg';
|
|
3
|
+
|
|
4
|
+
export default function Home() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="min-h-screen bg-gradient-to-b from-gray-50 to-gray-100 text-gray-900 flex flex-col">
|
|
7
|
+
<div className="flex-grow">
|
|
8
|
+
{/* Hero Section */}
|
|
9
|
+
<section className="max-w-6xl mx-auto px-4 py-20 lg:py-28">
|
|
10
|
+
<div className="text-center">
|
|
11
|
+
<div className="w-64 mb-6 mx-auto">
|
|
12
|
+
<WordmarkCondensed className="mx-auto" />
|
|
13
|
+
</div>
|
|
14
|
+
<p className="text-xl text-gray-600 mb-8 font-mono">
|
|
15
|
+
Fullstack demo powered by Next.js
|
|
16
|
+
</p>
|
|
17
|
+
<div className="flex flex-wrap gap-4 justify-center">
|
|
18
|
+
<Link
|
|
19
|
+
href="/protected"
|
|
20
|
+
className="px-6 py-3 bg-blue-600 hover:bg-blue-700 rounded-lg font-mono transition-colors text-white"
|
|
21
|
+
>
|
|
22
|
+
Live demo
|
|
23
|
+
</Link>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</section>
|
|
27
|
+
</div>
|
|
28
|
+
<footer className="py-8 text-center text-sm text-gray-500">
|
|
29
|
+
By using this site, you agree to be bound by the{' '}
|
|
30
|
+
<a
|
|
31
|
+
href="https://www.coinbase.com/legal/developer-platform/terms-of-service"
|
|
32
|
+
target="_blank"
|
|
33
|
+
rel="noopener noreferrer"
|
|
34
|
+
className="text-blue-500"
|
|
35
|
+
>
|
|
36
|
+
CDP Terms of Service
|
|
37
|
+
</a>{' '}
|
|
38
|
+
and{' '}
|
|
39
|
+
<a
|
|
40
|
+
href="https://www.coinbase.com/legal/privacy"
|
|
41
|
+
target="_blank"
|
|
42
|
+
rel="noopener noreferrer"
|
|
43
|
+
className="text-blue-500"
|
|
44
|
+
>
|
|
45
|
+
Global Privacy Policy
|
|
46
|
+
</a>
|
|
47
|
+
.
|
|
48
|
+
</footer>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export default function ProtectedPage() {
|
|
2
|
+
return (
|
|
3
|
+
<div className="min-h-screen flex items-center justify-center">
|
|
4
|
+
<div className="max-w-2xl mx-auto p-8">
|
|
5
|
+
<h1 className="text-4xl font-bold mb-4">Protected Content</h1>
|
|
6
|
+
<p className="text-lg">
|
|
7
|
+
Your payment was successful! Enjoy this banger song.
|
|
8
|
+
</p>
|
|
9
|
+
<iframe width="100%" height="300" scrolling="no" frameBorder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/2044190296&color=%23ff5500&auto_play=true&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true"></iframe>
|
|
10
|
+
<div style={{ fontSize: '10px', color: '#cccccc', lineBreak: 'anywhere', wordBreak: 'normal', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis', fontFamily: 'Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif', fontWeight: '100' }}>
|
|
11
|
+
<a href="https://soundcloud.com/dan-kim-675678711" title="danXkim" target="_blank" style={{ color: '#cccccc', textDecoration: 'none' }}>danXkim</a> · <a href="https://soundcloud.com/dan-kim-675678711/x402" title="x402 (DJ Reppel Remix)" target="_blank" style={{ color: '#cccccc', textDecoration: 'none' }}>x402 (DJ Reppel Remix)</a>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
);
|
|
16
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import ts from "@typescript-eslint/eslint-plugin";
|
|
3
|
+
import tsParser from "@typescript-eslint/parser";
|
|
4
|
+
import prettier from "eslint-plugin-prettier";
|
|
5
|
+
import jsdoc from "eslint-plugin-jsdoc";
|
|
6
|
+
import importPlugin from "eslint-plugin-import";
|
|
7
|
+
|
|
8
|
+
export default [
|
|
9
|
+
{
|
|
10
|
+
ignores: ["dist/**", "node_modules/**", ".next/**"],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
files: ["**/*.ts"],
|
|
14
|
+
languageOptions: {
|
|
15
|
+
parser: tsParser,
|
|
16
|
+
sourceType: "module",
|
|
17
|
+
ecmaVersion: 2020,
|
|
18
|
+
globals: {
|
|
19
|
+
process: "readonly",
|
|
20
|
+
__dirname: "readonly",
|
|
21
|
+
module: "readonly",
|
|
22
|
+
require: "readonly",
|
|
23
|
+
Buffer: "readonly",
|
|
24
|
+
console: "readonly",
|
|
25
|
+
exports: "readonly",
|
|
26
|
+
setTimeout: "readonly",
|
|
27
|
+
clearTimeout: "readonly",
|
|
28
|
+
setInterval: "readonly",
|
|
29
|
+
clearInterval: "readonly",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
plugins: {
|
|
33
|
+
"@typescript-eslint": ts,
|
|
34
|
+
prettier: prettier,
|
|
35
|
+
jsdoc: jsdoc,
|
|
36
|
+
import: importPlugin,
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
...ts.configs.recommended.rules,
|
|
40
|
+
"import/first": "error",
|
|
41
|
+
"prettier/prettier": "error",
|
|
42
|
+
"@typescript-eslint/member-ordering": "error",
|
|
43
|
+
"@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }],
|
|
44
|
+
"jsdoc/tag-lines": ["error", "any", { startLines: 1 }],
|
|
45
|
+
"jsdoc/check-alignment": "error",
|
|
46
|
+
"jsdoc/no-undefined-types": "off",
|
|
47
|
+
"jsdoc/check-param-names": "error",
|
|
48
|
+
"jsdoc/check-tag-names": "error",
|
|
49
|
+
"jsdoc/check-types": "error",
|
|
50
|
+
"jsdoc/implements-on-classes": "error",
|
|
51
|
+
"jsdoc/require-description": "error",
|
|
52
|
+
"jsdoc/require-jsdoc": [
|
|
53
|
+
"error",
|
|
54
|
+
{
|
|
55
|
+
require: {
|
|
56
|
+
FunctionDeclaration: true,
|
|
57
|
+
MethodDefinition: true,
|
|
58
|
+
ClassDeclaration: true,
|
|
59
|
+
ArrowFunctionExpression: false,
|
|
60
|
+
FunctionExpression: false,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
"jsdoc/require-param": "error",
|
|
65
|
+
"jsdoc/require-param-description": "error",
|
|
66
|
+
"jsdoc/require-param-type": "off",
|
|
67
|
+
"jsdoc/require-returns": "error",
|
|
68
|
+
"jsdoc/require-returns-description": "error",
|
|
69
|
+
"jsdoc/require-returns-type": "off",
|
|
70
|
+
"jsdoc/require-hyphen-before-param-description": ["error", "always"],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Address } from "viem";
|
|
2
|
+
import { paymentMiddleware, Network, Resource } from "x402-next";
|
|
3
|
+
|
|
4
|
+
const facilitatorUrl = process.env.NEXT_PUBLIC_FACILITATOR_URL as Resource;
|
|
5
|
+
const payTo = process.env.RESOURCE_WALLET_ADDRESS as Address;
|
|
6
|
+
const network = process.env.NETWORK as Network;
|
|
7
|
+
|
|
8
|
+
export const middleware = paymentMiddleware(
|
|
9
|
+
payTo,
|
|
10
|
+
{
|
|
11
|
+
"/protected": {
|
|
12
|
+
price: "$0.01",
|
|
13
|
+
network,
|
|
14
|
+
config: {
|
|
15
|
+
description: "Access to protected content",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
url: facilitatorUrl,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
appName: "Next x402 Demo",
|
|
24
|
+
appLogo: "/x402-icon-blue.png",
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
// Configure which paths the middleware should run on
|
|
29
|
+
export const config = {
|
|
30
|
+
matcher: ["/protected/:path*"],
|
|
31
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { NextConfig } from "next";
|
|
2
|
+
|
|
3
|
+
const nextConfig: NextConfig = {
|
|
4
|
+
env: {
|
|
5
|
+
RESOURCE_WALLET_ADDRESS: process.env.RESOURCE_WALLET_ADDRESS,
|
|
6
|
+
NEXT_PUBLIC_FACILITATOR_URL: process.env.NEXT_PUBLIC_FACILITATOR_URL,
|
|
7
|
+
},
|
|
8
|
+
webpack(config) {
|
|
9
|
+
config.module.rules.push({
|
|
10
|
+
test: /\.svg$/,
|
|
11
|
+
use: ["@svgr/webpack"],
|
|
12
|
+
});
|
|
13
|
+
return config;
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default nextConfig;
|