onenoly11 commited on
Commit
7d1cdb2
·
verified ·
1 Parent(s): d8229c0

Upload 10 files

Browse files
Files changed (10) hide show
  1. README.md +162 -13
  2. components.json +21 -0
  3. netlify.toml +7 -0
  4. next.config.mjs +12 -0
  5. package.json +45 -0
  6. pnpm-lock.yaml +0 -0
  7. postcss.config.mjs +8 -0
  8. test-validation.js +28 -0
  9. tsconfig.json +27 -0
  10. vercel.json +52 -0
README.md CHANGED
@@ -1,13 +1,162 @@
1
- ---
2
- title: Quantum Pi Forge
3
- emoji: 📚
4
- colorFrom: gray
5
- colorTo: purple
6
- sdk: gradio
7
- sdk_version: 5.49.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Quantum Pi Forge (v6)
2
+
3
+ This repository powers the Quantum Pi Forge site. It currently ships as a Create React App but includes the scaffolding for a Next.js static export; the Netlify deployment (see below) relies on the Next configuration in `next.config.mjs`.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node.js 18+ and `corepack` (bundled with Node 18+). `corepack` lets us invoke `pnpm` without a global install.
8
+ - One of the supported package managers (this repo uses `pnpm`).
9
+
10
+ ## Getting started
11
+
12
+ 1. Install dependencies:
13
+
14
+ ```powershell
15
+ corepack pnpm install
16
+ ```
17
+
18
+ 1. Start the development server:
19
+
20
+ ```powershell
21
+ corepack pnpm start
22
+ ```
23
+
24
+ 1. Build for production (runs the CRA-based compiler that currently drives the site):
25
+
26
+ ```powershell
27
+ corepack pnpm build
28
+ ```
29
+
30
+ ## Deploying to Vercel (production)
31
+
32
+ The CRA portion still runs via `corepack pnpm build`, but the payment workflow now lives inside Vercel Serverless functions. Configure your site in the Vercel dashboard (or run `vercel --prod`) after the build artifact is ready.
33
+
34
+ ### Vercel configuration
35
+
36
+ `vercel.json` wires everything together:
37
+
38
+ ```json
39
+ {
40
+ "version": 3,
41
+ "routes": [
42
+ {
43
+ "src": "/validation-key.txt",
44
+ "dest": "/public/validation-key.txt",
45
+ "headers": {
46
+ "Cache-Control": "public, max-age=0, must-revalidate",
47
+ "Content-Type": "text/plain; charset=utf-8"
48
+ }
49
+ },
50
+ {
51
+ "src": "/.well-known/validation-key.txt",
52
+ "dest": "/public/validation-key.txt",
53
+ "headers": {
54
+ "Cache-Control": "public, max-age=0, must-revalidate",
55
+ "Content-Type": "text/plain; charset=utf-8"
56
+ }
57
+ }
58
+ ],
59
+ "functions": {
60
+ "api/**/*.ts": {
61
+ "memory": 1024,
62
+ "maxDuration": 30
63
+ }
64
+ },
65
+ "rewrites": [
66
+ {
67
+ "source": "/.netlify/functions/(.*)",
68
+ "destination": "/api/$1"
69
+ }
70
+ ],
71
+ "headers": [
72
+ {
73
+ "source": "/api/(.*)",
74
+ "headers": [
75
+ { "key": "Access-Control-Allow-Origin", "value": "*" },
76
+ { "key": "Access-Control-Allow-Headers", "value": "Content-Type, Authorization, X-Signature, X-Timestamp" },
77
+ { "key": "Access-Control-Allow-Methods", "value": "GET, POST, OPTIONS" }
78
+ ]
79
+ }
80
+ ]
81
+ }
82
+ ```
83
+
84
+ ### Pi Mainnet validation bundle
85
+
86
+ The static `public/validation-key.txt` file exposes the Pi validation key at both `/validation-key.txt` and `/.well-known/validation-key.txt` so that the Pi Developer Portal can immediately confirm `quantumpiforge.com`. The routes above force `text/plain` semantics and disable caching so the validation status is always fresh.
87
+
88
+ To confirm the file locally before deployment run:
89
+
90
+ ```bash
91
+ curl -s https://quantumpiforge.com/validation-key.txt
92
+ ```
93
+
94
+ Once deployed, rerun the same command or execute the `test-validation.js` helper to ensure the response is `50f70d548675a0db693c46b99c0eff07e2`. Run it with `node test-validation.js` after a short delay to verify the deployment pulls the correct key, then trigger the Pi Developer Console validation flow and expect the domain to turn green automatically. A GitHub Action (`.github/workflows/validation-check.yml`) already runs this same script hourly (and on every `main` push) to detect if the validation key ever becomes unreachable and fail the workflow so it can be investigated.
95
+
96
+ ### Pi Mainnet activation checklist
97
+
98
+ After the validation key is live, add a Pi App Manifest so the Pi Studio checks the metadata immediately. Create `public/pi-app-manifest.json` with the following content before deploying:
99
+
100
+ ```json
101
+ {
102
+ "name": "Quantum Pi Forge",
103
+ "description": "A Sovereign App built on Pi Network.",
104
+ "url": "https://quantumpiforge.com",
105
+ "permissions": ["username", "payments"]
106
+ }
107
+ ```
108
+
109
+ Once deployed, confirm these resources return 200 before pressing **Verify Domain** in Pi Studio:
110
+
111
+ - `https://quantumpiforge.com/pi-app-manifest.json`
112
+ - `https://quantumpiforge.com/validation-key.txt`
113
+ - `https://quantumpiforge.com` loads without TLS issues
114
+
115
+ Pi Studio will then verify the manifest, call the validation key, and let you submit the app for Pi Mainnet.
116
+
117
+ The rewrite keeps older webhooks that still call `/.netlify/functions/...` intact; all the logic now executes in `api/*` handlers so you can delete the legacy `netlify/` files once you confirm the new functions behave identically.
118
+
119
+ ## Serverless functions
120
+
121
+ All backend behavior lives inside `api/*.ts`. Each file imports `lib/tracing.ts` so the OpenTelemetry SDK bootstraps before business logic runs, preserving the existing tracing output in the AI Toolkit Trace Viewer.
122
+
123
+ | Handler | Responsibility |
124
+ | --- | --- |
125
+ | `api/pi-create-payment.ts` | Accepts POST requests that create Pi payments, enriches metadata, and points the webhook to `api/pi-payment-webhook`. Uses `PI_BACKEND_URL`, `URL`, and `TEAM_TOKEN` to speak to the Pi backend and internal alerts. |
126
+ | `api/pi-payment-webhook.ts` | Validates `x-pi-signature` via `PI_PAYMENT_SECRET`, deduplicates `payment_id`, upserts into Supabase (service key), and triggers `api/ethical-audit.ts` when an ethical audit is due. Alerts and retries go through `api/alert-webhook.ts`. |
127
+ | `api/ethical-audit.ts` | Inserts audit entries into Supabase after verifying `X-Signature` + timestamp signed with `WEBHOOK_SECRET`, and responds with the inserted row ID so downstream UI can surface progress. |
128
+ | `api/alert-webhook.ts` | Lightweight logging endpoint used by the webhook pipeline to capture failure contexts, keeping the same payloads as the prior Netlify handler. |
129
+ | `api/auth-callback.ts` | Supabase auth callback used in the Pi Developer Console; exchanges the OAuth `code` for a session and redirects to `/auth/success`. |
130
+
131
+ These handlers rely on the same environment secrets you had for Netlify, but the `URL` variable should now point at `https://quantumpiforge.com` (or whichever Vercel domain hosts the functions) so each helper can call its peers via `https://<site>/api/...`.
132
+
133
+ ### Asynchronous Pi payment flow
134
+
135
+ The Supabase schema remains unchanged – keep the `payments` table defined as before, with indexes on `payment_id` and auditing columns. When `pi-create-payment` responds with a `payment_id`, show `Pending` on the frontend and watch Supabase Realtime for updates to that row. Once `status = 'completed' && audit_completed = true`, display the audit score and mining boost.
136
+
137
+ ### Environment checklist
138
+
139
+ These values are still required inside Vercel Environment Variables:
140
+
141
+ 1. `PI_PAYMENT_SECRET` – Pi webhook HMAC secret.
142
+ 2. `SUPABASE_URL` & `SUPABASE_SERVICE_KEY` – Service key for inserts/updates.
143
+ 3. `URL` – Vercel site URL so functions can call each other (e.g., `https://quantumpiforge.com`).
144
+ 4. `TEAM_TOKEN` – Internal auth token that gates audit/alert calls.
145
+ 5. `PI_BACKEND_URL` – Backend proxy that actually talks to Pi Network.
146
+ 6. `WEBHOOK_SECRET` – Signing secret for `ethical-audit`.
147
+ 7. `PI_BACKEND_URL` – Keep referencing to talk to the payment backend.
148
+ 8. (Optional) `PI_DEVELOPER_REDIRECT` – Keep this aligned with `https://quantumpiforge.com/api/auth-callback` when updating Pi Developer Console redirect URIs.
149
+
150
+ ## Tracing
151
+
152
+ All Vercel API handlers import `lib/tracing.ts`, so OpenTelemetry spans continue to stream to AI Toolkit. Start tracing locally with `ai-mlstudio.tracing.open` and inspect data in the Trace Viewer the same way you did for Netlify functions:
153
+
154
+ - **Collector endpoint:** `http://localhost:4318/v1/traces` (override with `OTLP_ENDPOINT`).
155
+ - **Trace scope:** HTTP entry spans, Supabase writes, HMAC validations, and internal fetch calls between functions.
156
+ - **What to watch:** `pi-payment-webhook` spans should show audit calls, alert fallbacks, and Supabase upserts within a single trace.
157
+
158
+ ## Legacy Netlify notes
159
+
160
+ - `.github/workflows/netlify-guardian.yml` is retained for reference, but it only applies while Netlify still owns the domain. Once `quantumpiforge.com` is fully on Vercel you can remove the workflow and the `netlify/` functions directory.
161
+ - `netlify/functions/*` still exists for history, but all production traffic now hits `api/*` with the same request/response contracts.
162
+
components.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/globals.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "@/components",
15
+ "utils": "@/lib/utils",
16
+ "ui": "@/components/ui",
17
+ "lib": "@/lib",
18
+ "hooks": "@/hooks"
19
+ },
20
+ "iconLibrary": "lucide"
21
+ }
netlify.toml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ [functions]
2
+ node_bundler = "esbuild"
3
+ included_files = []
4
+ external_node_modules = ["@supabase/supabase-js"]
5
+
6
+ [functions."pi-payment-webhook"]
7
+ included_files = []
next.config.mjs ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('next').NextConfig} */
2
+ const nextConfig = {
3
+ output: 'export',
4
+ typescript: {
5
+ ignoreBuildErrors: true,
6
+ },
7
+ images: {
8
+ unoptimized: true,
9
+ },
10
+ }
11
+
12
+ export default nextConfig
package.json ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "quantum-pi-forge-v6",
3
+ "version": "6.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "build": "react-scripts build",
7
+ "eject": "react-scripts eject",
8
+ "start": "react-scripts start",
9
+ "test": "react-scripts test"
10
+ },
11
+ "dependencies": {
12
+ "@opentelemetry/api": "^1.9.0",
13
+ "@opentelemetry/auto-instrumentations-node": "^0.67.0",
14
+ "@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
15
+ "@opentelemetry/sdk-node": "^0.208.0",
16
+ "@supabase/supabase-js": "^2.45.0",
17
+ "node-fetch": "^3.3.2",
18
+ "class-variance-authority": "^0.7.1",
19
+ "clsx": "^2.1.1",
20
+ "lucide-react": "^0.454.0",
21
+ "react": "^18.2.0",
22
+ "react-dom": "latest",
23
+ "react-scripts": "5.0.1",
24
+ "tailwind-merge": "^2.5.5",
25
+ "tailwindcss-animate": "^1.0.7"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22",
29
+ "@vercel/node": "^3.0.0",
30
+ "postcss": "^8.5",
31
+ "typescript": "^5"
32
+ },
33
+ "browserslist": {
34
+ "production": [
35
+ ">0.2%",
36
+ "not dead",
37
+ "not op_mini all"
38
+ ],
39
+ "development": [
40
+ "last 1 chrome version",
41
+ "last 1 firefox version",
42
+ "last 1 safari version"
43
+ ]
44
+ }
45
+ }
pnpm-lock.yaml ADDED
The diff for this file is too large to render. See raw diff
 
postcss.config.mjs ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /** @type {import('postcss-load-config').Config} */
2
+ const config = {
3
+ plugins: {
4
+ '@tailwindcss/postcss': {},
5
+ },
6
+ }
7
+
8
+ export default config
test-validation.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const https = require('https');
2
+
3
+ const EXPECTED = '50f70d548675a0db693c46b99c0eff07e2';
4
+ const URL = 'https://quantumpiforge.com/validation-key.txt';
5
+
6
+ https
7
+ .get(URL, (res) => {
8
+ let data = '';
9
+ res.on('data', (chunk) => {
10
+ data += chunk;
11
+ });
12
+
13
+ res.on('end', () => {
14
+ const content = data.trim();
15
+ console.log('Status:', res.statusCode);
16
+ console.log('Content:', content);
17
+ if (res.statusCode === 200 && content === EXPECTED) {
18
+ console.log('Valid: ✅ PASS');
19
+ process.exit(0);
20
+ }
21
+ console.log('Valid: ❌ FAIL');
22
+ process.exit(1);
23
+ });
24
+ })
25
+ .on('error', (err) => {
26
+ console.error('Request error:', err.message);
27
+ process.exit(1);
28
+ });
tsconfig.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["dom", "dom.iterable", "esnext"],
4
+ "allowJs": true,
5
+ "target": "ES6",
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26
+ "exclude": ["node_modules"]
27
+ }
vercel.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": 3,
3
+ "routes": [
4
+ {
5
+ "src": "/validation-key.txt",
6
+ "dest": "/public/validation-key.txt",
7
+ "headers": {
8
+ "Cache-Control": "public, max-age=0, must-revalidate",
9
+ "Content-Type": "text/plain; charset=utf-8"
10
+ }
11
+ },
12
+ {
13
+ "src": "/.well-known/validation-key.txt",
14
+ "dest": "/public/validation-key.txt",
15
+ "headers": {
16
+ "Cache-Control": "public, max-age=0, must-revalidate",
17
+ "Content-Type": "text/plain; charset=utf-8"
18
+ }
19
+ }
20
+ ],
21
+ "functions": {
22
+ "api/**/*.ts": {
23
+ "memory": 1024,
24
+ "maxDuration": 30
25
+ }
26
+ },
27
+ "rewrites": [
28
+ {
29
+ "source": "/.netlify/functions/(.*)",
30
+ "destination": "/api/$1"
31
+ }
32
+ ],
33
+ "headers": [
34
+ {
35
+ "source": "/api/(.*)",
36
+ "headers": [
37
+ {
38
+ "key": "Access-Control-Allow-Origin",
39
+ "value": "*"
40
+ },
41
+ {
42
+ "key": "Access-Control-Allow-Headers",
43
+ "value": "Content-Type, Authorization, X-Signature, X-Timestamp"
44
+ },
45
+ {
46
+ "key": "Access-Control-Allow-Methods",
47
+ "value": "GET, POST, OPTIONS"
48
+ }
49
+ ]
50
+ }
51
+ ]
52
+ }