@nordsym/apiclaw 1.0.0
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/.github/ISSUE_TEMPLATE/add-api.yml +123 -0
- package/BRIEFING.md +30 -0
- package/CONCEPT.md +494 -0
- package/README.md +272 -0
- package/backend/convex/README.md +90 -0
- package/backend/convex/_generated/api.d.ts +55 -0
- package/backend/convex/_generated/api.js +23 -0
- package/backend/convex/_generated/dataModel.d.ts +60 -0
- package/backend/convex/_generated/server.d.ts +143 -0
- package/backend/convex/_generated/server.js +93 -0
- package/backend/convex/apiKeys.ts +75 -0
- package/backend/convex/purchases.ts +74 -0
- package/backend/convex/schema.ts +45 -0
- package/backend/convex/transactions.ts +57 -0
- package/backend/convex/tsconfig.json +25 -0
- package/backend/convex/users.ts +94 -0
- package/backend/package-lock.json +521 -0
- package/backend/package.json +15 -0
- package/dist/credits.d.ts +54 -0
- package/dist/credits.d.ts.map +1 -0
- package/dist/credits.js +209 -0
- package/dist/credits.js.map +1 -0
- package/dist/discovery.d.ts +37 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +109 -0
- package/dist/discovery.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +355 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/apis.json +20894 -0
- package/dist/registry/parse_apis.py +146 -0
- package/dist/revenuecat.d.ts +61 -0
- package/dist/revenuecat.d.ts.map +1 -0
- package/dist/revenuecat.js +166 -0
- package/dist/revenuecat.js.map +1 -0
- package/dist/test.d.ts +6 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +81 -0
- package/dist/test.js.map +1 -0
- package/dist/types.d.ts +96 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/webhooks/revenuecat.d.ts +48 -0
- package/dist/webhooks/revenuecat.d.ts.map +1 -0
- package/dist/webhooks/revenuecat.js +119 -0
- package/dist/webhooks/revenuecat.js.map +1 -0
- package/docs/revenuecat-setup.md +89 -0
- package/landing/next-env.d.ts +5 -0
- package/landing/next.config.mjs +6 -0
- package/landing/package-lock.json +1666 -0
- package/landing/package.json +27 -0
- package/landing/postcss.config.js +6 -0
- package/landing/src/app/api/keys/route.ts +71 -0
- package/landing/src/app/api/log/route.ts +37 -0
- package/landing/src/app/api/stats/route.ts +37 -0
- package/landing/src/app/globals.css +261 -0
- package/landing/src/app/layout.tsx +37 -0
- package/landing/src/app/page.tsx +753 -0
- package/landing/src/app/page.tsx.bak +567 -0
- package/landing/src/components/AddKeyModal.tsx +159 -0
- package/landing/tailwind.config.ts +34 -0
- package/landing/tsconfig.json +20 -0
- package/newsletter-template.html +71 -0
- package/outreach/OUTREACH-SYSTEM.md +211 -0
- package/outreach/email-template.html +179 -0
- package/outreach/targets.md +133 -0
- package/package.json +39 -0
- package/src/credits.ts +261 -0
- package/src/discovery.ts +147 -0
- package/src/index.ts +396 -0
- package/src/registry/apis.json +20894 -0
- package/src/registry/parse_apis.py +146 -0
- package/src/revenuecat.ts +239 -0
- package/src/test.ts +97 -0
- package/src/types.ts +110 -0
- package/src/webhooks/revenuecat.ts +187 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "apivault-landing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@vercel/analytics": "^1.6.1",
|
|
13
|
+
"lucide-react": "^0.350.0",
|
|
14
|
+
"next": "^14.2.0",
|
|
15
|
+
"react": "^18.2.0",
|
|
16
|
+
"react-dom": "^18.2.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^20",
|
|
20
|
+
"@types/react": "^18",
|
|
21
|
+
"@types/react-dom": "^18",
|
|
22
|
+
"autoprefixer": "^10",
|
|
23
|
+
"postcss": "^8",
|
|
24
|
+
"tailwindcss": "^3.4.1",
|
|
25
|
+
"typescript": "^5"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
2
|
+
|
|
3
|
+
const CONVEX_URL = "https://fastidious-bloodhound-287.convex.cloud";
|
|
4
|
+
|
|
5
|
+
export async function POST(req: NextRequest) {
|
|
6
|
+
try {
|
|
7
|
+
const body = await req.json();
|
|
8
|
+
const { userEmail, apiId, apiName, keyName, keyValue } = body;
|
|
9
|
+
|
|
10
|
+
if (!userEmail || !apiId || !keyValue) {
|
|
11
|
+
return NextResponse.json({ error: "Missing required fields" }, { status: 400 });
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Save to Convex
|
|
15
|
+
const response = await fetch(`${CONVEX_URL}/api/mutation`, {
|
|
16
|
+
method: "POST",
|
|
17
|
+
headers: { "Content-Type": "application/json" },
|
|
18
|
+
body: JSON.stringify({
|
|
19
|
+
path: "apiKeys:add",
|
|
20
|
+
args: {
|
|
21
|
+
userEmail,
|
|
22
|
+
apiId,
|
|
23
|
+
apiName: apiName || apiId,
|
|
24
|
+
keyName: keyName || "API Key",
|
|
25
|
+
keyValue,
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error("Convex mutation failed");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const result = await response.json();
|
|
35
|
+
return NextResponse.json({ success: true, id: result });
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error("Error saving key:", error);
|
|
38
|
+
return NextResponse.json({ error: "Failed to save key" }, { status: 500 });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function GET(req: NextRequest) {
|
|
43
|
+
try {
|
|
44
|
+
const email = req.nextUrl.searchParams.get("email");
|
|
45
|
+
const apiId = req.nextUrl.searchParams.get("apiId");
|
|
46
|
+
|
|
47
|
+
if (!email) {
|
|
48
|
+
return NextResponse.json({ error: "Email required" }, { status: 400 });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Query Convex
|
|
52
|
+
const path = apiId ? "apiKeys:get" : "apiKeys:listByEmail";
|
|
53
|
+
const args = apiId ? { userEmail: email, apiId } : { userEmail: email };
|
|
54
|
+
|
|
55
|
+
const response = await fetch(`${CONVEX_URL}/api/query`, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
headers: { "Content-Type": "application/json" },
|
|
58
|
+
body: JSON.stringify({ path, args }),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
throw new Error("Convex query failed");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const keys = await response.json();
|
|
66
|
+
return NextResponse.json({ keys });
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error("Error fetching keys:", error);
|
|
69
|
+
return NextResponse.json({ error: "Failed to fetch keys" }, { status: 500 });
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
// Use Mission Control Convex for logging
|
|
4
|
+
const MC_CONVEX_URL = 'https://agile-crane-840.convex.cloud';
|
|
5
|
+
|
|
6
|
+
export async function POST(request: Request) {
|
|
7
|
+
try {
|
|
8
|
+
const body = await request.json();
|
|
9
|
+
const { event, data } = body;
|
|
10
|
+
|
|
11
|
+
// Log to Mission Control as activity
|
|
12
|
+
await fetch(`${MC_CONVEX_URL}/api/mutation`, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
headers: { 'Content-Type': 'application/json' },
|
|
15
|
+
body: JSON.stringify({
|
|
16
|
+
path: 'activities:create',
|
|
17
|
+
args: {
|
|
18
|
+
type: 'notification',
|
|
19
|
+
title: `APIClaw: ${event}`,
|
|
20
|
+
description: JSON.stringify(data),
|
|
21
|
+
status: 'auto_done',
|
|
22
|
+
agentId: 'apiclaw',
|
|
23
|
+
agentLabel: 'APIClaw Landing'
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return NextResponse.json({ ok: true });
|
|
29
|
+
} catch (error) {
|
|
30
|
+
// Silently fail - don't block user experience
|
|
31
|
+
return NextResponse.json({ ok: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function GET() {
|
|
36
|
+
return NextResponse.json({ status: 'logging endpoint' });
|
|
37
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export const dynamic = 'force-dynamic';
|
|
6
|
+
export const revalidate = 0;
|
|
7
|
+
|
|
8
|
+
export async function GET() {
|
|
9
|
+
try {
|
|
10
|
+
// Read from the registry
|
|
11
|
+
const registryPath = path.join(process.cwd(), '..', 'src', 'registry', 'apis.json');
|
|
12
|
+
|
|
13
|
+
let apiCount = 1490; // fallback
|
|
14
|
+
let categories = 52; // fallback
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const data = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
|
|
18
|
+
apiCount = data.length;
|
|
19
|
+
categories = new Set(data.map((api: any) => api.category)).size;
|
|
20
|
+
} catch (e) {
|
|
21
|
+
// Use fallbacks if file not found
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return NextResponse.json({
|
|
25
|
+
apis: apiCount,
|
|
26
|
+
categories: categories,
|
|
27
|
+
timestamp: new Date().toISOString()
|
|
28
|
+
}, {
|
|
29
|
+
headers: {
|
|
30
|
+
'Cache-Control': 'no-store, max-age=0',
|
|
31
|
+
'Access-Control-Allow-Origin': '*'
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return NextResponse.json({ apis: 1490, categories: 52 }, { status: 200 });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap');
|
|
6
|
+
|
|
7
|
+
html {
|
|
8
|
+
scroll-behavior: smooth;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
body {
|
|
12
|
+
background: #0d0d0d;
|
|
13
|
+
color: #ffffff;
|
|
14
|
+
font-feature-settings: "cv11", "ss01";
|
|
15
|
+
transition: background-color 0.3s, color 0.3s;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Light mode */
|
|
19
|
+
html.light body {
|
|
20
|
+
background: #f8f9fa;
|
|
21
|
+
color: #1a1a1a;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
html.light .bg-background\/90 {
|
|
25
|
+
background: rgba(248, 249, 250, 0.9) !important;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
html.light .bg-surface-elevated,
|
|
29
|
+
html.light .bg-surface {
|
|
30
|
+
background: #ffffff !important;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
html.light .border-border,
|
|
34
|
+
html.light .border-border-subtle {
|
|
35
|
+
border-color: #e5e5e5 !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
html.light .text-text-muted {
|
|
39
|
+
color: #737373 !important;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
html.light .text-text-secondary {
|
|
43
|
+
color: #525252 !important;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
html.light .text-text-primary,
|
|
47
|
+
html.light .text-white {
|
|
48
|
+
color: #1a1a1a !important;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
html.light .terminal,
|
|
52
|
+
html.light .code-block {
|
|
53
|
+
background: #f1f1f1 !important;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
html.light .terminal-header {
|
|
57
|
+
background: #e5e5e5 !important;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
html.light .testimonial-card {
|
|
61
|
+
background: #ffffff !important;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Heading styles */
|
|
65
|
+
h1, h2, h3 {
|
|
66
|
+
letter-spacing: -0.03em;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Section labels */
|
|
70
|
+
.section-label {
|
|
71
|
+
font-size: 0.75rem;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
letter-spacing: 0.15em;
|
|
74
|
+
text-transform: uppercase;
|
|
75
|
+
color: #ef4444;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@keyframes gradient {
|
|
79
|
+
0%, 100% { background-position: 0% 50%; }
|
|
80
|
+
50% { background-position: 100% 50%; }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.gradient-text {
|
|
84
|
+
background: linear-gradient(135deg, #ef4444 0%, #f87171 50%, #fca5a5 100%);
|
|
85
|
+
background-size: 200% 200%;
|
|
86
|
+
animation: gradient 5s ease infinite;
|
|
87
|
+
-webkit-background-clip: text;
|
|
88
|
+
-webkit-text-fill-color: transparent;
|
|
89
|
+
background-clip: text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.glow {
|
|
93
|
+
box-shadow: 0 0 80px rgba(34, 197, 94, 0.2);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.glow-subtle {
|
|
97
|
+
box-shadow: 0 0 40px rgba(34, 197, 94, 0.1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.card-hover {
|
|
101
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.card-hover:hover {
|
|
105
|
+
transform: translateY(-4px);
|
|
106
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
107
|
+
box-shadow: 0 12px 40px rgba(34, 197, 94, 0.1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.code-block {
|
|
111
|
+
background: linear-gradient(135deg, #0f0f0f 0%, #141414 100%);
|
|
112
|
+
border: 1px solid #2a2a2a;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Terminal styling */
|
|
116
|
+
.terminal {
|
|
117
|
+
background: #0f0f0f;
|
|
118
|
+
border: 1px solid #2a2a2a;
|
|
119
|
+
border-radius: 12px;
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.terminal-header {
|
|
124
|
+
display: flex;
|
|
125
|
+
gap: 6px;
|
|
126
|
+
padding: 12px 16px;
|
|
127
|
+
border-bottom: 1px solid #222;
|
|
128
|
+
background: #141414;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.terminal-dot {
|
|
132
|
+
width: 12px;
|
|
133
|
+
height: 12px;
|
|
134
|
+
border-radius: 50%;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.terminal-dot-red { background: #ff5f57; }
|
|
138
|
+
.terminal-dot-yellow { background: #febc2e; }
|
|
139
|
+
.terminal-dot-green { background: #ef4444; }
|
|
140
|
+
|
|
141
|
+
.terminal-body {
|
|
142
|
+
padding: 20px;
|
|
143
|
+
font-family: 'JetBrains Mono', monospace;
|
|
144
|
+
font-size: 14px;
|
|
145
|
+
line-height: 1.6;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.terminal-prompt {
|
|
149
|
+
color: #ef4444;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.terminal-command {
|
|
153
|
+
color: #ffffff;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.terminal-output {
|
|
157
|
+
color: #737373;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* Testimonial card */
|
|
161
|
+
.testimonial-card {
|
|
162
|
+
background: #1a1a1a;
|
|
163
|
+
border: 1px solid #2a2a2a;
|
|
164
|
+
transition: all 0.3s ease;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.testimonial-card:hover {
|
|
168
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Input styling */
|
|
172
|
+
input[type="email"] {
|
|
173
|
+
background: #141414;
|
|
174
|
+
border: 1px solid #2a2a2a;
|
|
175
|
+
transition: all 0.2s ease;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
input[type="email"]:focus {
|
|
179
|
+
outline: none;
|
|
180
|
+
border-color: #ef4444;
|
|
181
|
+
box-shadow: 0 0 0 3px rgba(34, 197, 94, 0.1);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
input[type="email"]::placeholder {
|
|
185
|
+
color: #525252;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Badge styling */
|
|
189
|
+
.badge {
|
|
190
|
+
display: inline-flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
gap: 6px;
|
|
193
|
+
padding: 4px 12px;
|
|
194
|
+
font-size: 12px;
|
|
195
|
+
font-weight: 500;
|
|
196
|
+
border-radius: 9999px;
|
|
197
|
+
background: rgba(34, 197, 94, 0.1);
|
|
198
|
+
border: 1px solid rgba(34, 197, 94, 0.2);
|
|
199
|
+
color: #ef4444;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* Integration badges */
|
|
203
|
+
.integration-badge {
|
|
204
|
+
display: inline-flex;
|
|
205
|
+
align-items: center;
|
|
206
|
+
gap: 8px;
|
|
207
|
+
padding: 8px 16px;
|
|
208
|
+
font-size: 13px;
|
|
209
|
+
font-weight: 500;
|
|
210
|
+
border-radius: 8px;
|
|
211
|
+
background: #1a1a1a;
|
|
212
|
+
border: 1px solid #2a2a2a;
|
|
213
|
+
color: #a3a3a3;
|
|
214
|
+
transition: all 0.2s ease;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.integration-badge:hover {
|
|
218
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
219
|
+
color: #ffffff;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/* Button base */
|
|
223
|
+
.btn-primary {
|
|
224
|
+
display: inline-flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
gap: 8px;
|
|
227
|
+
padding: 12px 24px;
|
|
228
|
+
font-weight: 600;
|
|
229
|
+
border-radius: 12px;
|
|
230
|
+
background: #ef4444;
|
|
231
|
+
color: #0d0d0d;
|
|
232
|
+
transition: all 0.2s ease;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.btn-primary:hover {
|
|
236
|
+
background: #dc2626;
|
|
237
|
+
transform: translateY(-1px);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.btn-secondary {
|
|
241
|
+
display: inline-flex;
|
|
242
|
+
align-items: center;
|
|
243
|
+
gap: 8px;
|
|
244
|
+
padding: 12px 24px;
|
|
245
|
+
font-weight: 500;
|
|
246
|
+
border-radius: 12px;
|
|
247
|
+
background: #1a1a1a;
|
|
248
|
+
border: 1px solid #2a2a2a;
|
|
249
|
+
color: #ffffff;
|
|
250
|
+
transition: all 0.2s ease;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.btn-secondary:hover {
|
|
254
|
+
border-color: rgba(34, 197, 94, 0.5);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* Divider */
|
|
258
|
+
.divider {
|
|
259
|
+
height: 1px;
|
|
260
|
+
background: linear-gradient(90deg, transparent, #2a2a2a, transparent);
|
|
261
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Metadata } from "next";
|
|
2
|
+
import { Analytics } from "@vercel/analytics/react";
|
|
3
|
+
import "./globals.css";
|
|
4
|
+
|
|
5
|
+
export const metadata: Metadata = {
|
|
6
|
+
title: "APIClaw | APIs for Agents",
|
|
7
|
+
description: "Agents discover, evaluate, and connect to APIs directly. No dashboards. No signups. Just APIs.",
|
|
8
|
+
openGraph: {
|
|
9
|
+
title: "APIClaw | APIs for Agents",
|
|
10
|
+
description: "Agents discover, evaluate, and connect to APIs directly. No dashboards. No signups. Just APIs.",
|
|
11
|
+
type: "website",
|
|
12
|
+
},
|
|
13
|
+
twitter: {
|
|
14
|
+
card: "summary_large_image",
|
|
15
|
+
title: "APIClaw | APIs for Agents",
|
|
16
|
+
description: "Agents discover, evaluate, and connect to APIs directly.",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default function RootLayout({
|
|
21
|
+
children,
|
|
22
|
+
}: Readonly<{
|
|
23
|
+
children: React.ReactNode;
|
|
24
|
+
}>) {
|
|
25
|
+
return (
|
|
26
|
+
<html lang="en" className="dark">
|
|
27
|
+
<head>
|
|
28
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
29
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
30
|
+
</head>
|
|
31
|
+
<body className="antialiased bg-background text-text-primary">
|
|
32
|
+
{children}
|
|
33
|
+
<Analytics />
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
);
|
|
37
|
+
}
|