Spaces:
Sleeping
Sleeping
Upload 10 files
Browse files- README.md +162 -13
- components.json +21 -0
- netlify.toml +7 -0
- next.config.mjs +12 -0
- package.json +45 -0
- pnpm-lock.yaml +0 -0
- postcss.config.mjs +8 -0
- test-validation.js +28 -0
- tsconfig.json +27 -0
- vercel.json +52 -0
README.md
CHANGED
|
@@ -1,13 +1,162 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
}
|