@nordsym/apiclaw 1.0.0 → 1.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.
Files changed (161) hide show
  1. package/AGENTS.md +74 -0
  2. package/HEARTBEAT.md +4 -0
  3. package/IDENTITY.md +22 -0
  4. package/README.md +193 -202
  5. package/SOUL.md +36 -0
  6. package/STATUS.md +237 -0
  7. package/TOOLS.md +36 -0
  8. package/USER.md +17 -0
  9. package/{backend/convex → convex}/_generated/api.d.ts +12 -6
  10. package/convex/analytics.ts +90 -0
  11. package/convex/credits.ts +211 -0
  12. package/convex/http.ts +578 -0
  13. package/convex/providers.ts +516 -0
  14. package/convex/purchases.ts +183 -0
  15. package/convex/ratelimit.ts +104 -0
  16. package/convex/schema.ts +220 -0
  17. package/convex/telemetry.ts +81 -0
  18. package/convex.json +3 -0
  19. package/dist/credentials.d.ts +19 -0
  20. package/dist/credentials.d.ts.map +1 -0
  21. package/dist/credentials.js +158 -0
  22. package/dist/credentials.js.map +1 -0
  23. package/dist/credits.d.ts +14 -11
  24. package/dist/credits.d.ts.map +1 -1
  25. package/dist/credits.js +151 -99
  26. package/dist/credits.js.map +1 -1
  27. package/dist/discovery.d.ts +7 -16
  28. package/dist/discovery.d.ts.map +1 -1
  29. package/dist/discovery.js +33 -40
  30. package/dist/discovery.js.map +1 -1
  31. package/dist/execute.d.ts +19 -0
  32. package/dist/execute.d.ts.map +1 -0
  33. package/dist/execute.js +285 -0
  34. package/dist/execute.js.map +1 -0
  35. package/dist/index.js +175 -31
  36. package/dist/index.js.map +1 -1
  37. package/dist/proxy.d.ts +6 -0
  38. package/dist/proxy.d.ts.map +1 -0
  39. package/dist/proxy.js +19 -0
  40. package/dist/proxy.js.map +1 -0
  41. package/dist/registry/apis.json +95362 -202
  42. package/dist/registry/apis_expanded.json +100853 -0
  43. package/dist/stripe.d.ts +68 -0
  44. package/dist/stripe.d.ts.map +1 -0
  45. package/dist/stripe.js +196 -0
  46. package/dist/stripe.js.map +1 -0
  47. package/dist/telemetry.d.ts +28 -0
  48. package/dist/telemetry.d.ts.map +1 -0
  49. package/dist/telemetry.js +50 -0
  50. package/dist/telemetry.js.map +1 -0
  51. package/dist/test.d.ts +3 -2
  52. package/dist/test.d.ts.map +1 -1
  53. package/dist/test.js +105 -75
  54. package/dist/test.js.map +1 -1
  55. package/dist/types.d.ts +0 -28
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/webhook.d.ts +2 -0
  58. package/dist/webhook.d.ts.map +1 -0
  59. package/dist/webhook.js +90 -0
  60. package/dist/webhook.js.map +1 -0
  61. package/landing/DESIGN.md +343 -0
  62. package/landing/package-lock.json +1196 -7
  63. package/landing/package.json +5 -1
  64. package/landing/public/android-chrome-192x192.png +0 -0
  65. package/landing/public/android-chrome-512x512.png +0 -0
  66. package/landing/public/apple-touch-icon.png +0 -0
  67. package/landing/public/demo.gif +0 -0
  68. package/landing/public/demo.mp4 +0 -0
  69. package/landing/public/favicon-16x16.png +0 -0
  70. package/landing/public/favicon-32x32.png +0 -0
  71. package/landing/public/favicon.ico +0 -0
  72. package/landing/public/favicon.svg +3 -0
  73. package/landing/public/icon.svg +47 -0
  74. package/landing/public/logo-mono.svg +37 -0
  75. package/landing/public/logo-simple.svg +45 -0
  76. package/landing/public/logo.svg +84 -0
  77. package/landing/public/og-template.html +184 -0
  78. package/landing/public/site.webmanifest +31 -0
  79. package/landing/scripts/generate-assets.js +284 -0
  80. package/landing/scripts/generate-pngs.js +48 -0
  81. package/landing/scripts/generate-stats.js +42 -0
  82. package/landing/src/app/admin/page.tsx +348 -0
  83. package/landing/src/app/api/auth/magic-link/route.ts +73 -0
  84. package/landing/src/app/api/auth/session/route.ts +38 -0
  85. package/landing/src/app/api/auth/verify/route.ts +43 -0
  86. package/landing/src/app/api/og/route.tsx +84 -0
  87. package/landing/src/app/globals.css +439 -100
  88. package/landing/src/app/layout.tsx +37 -7
  89. package/landing/src/app/page.tsx +627 -552
  90. package/landing/src/app/providers/dashboard/login/page.tsx +176 -0
  91. package/landing/src/app/providers/dashboard/page.tsx +589 -0
  92. package/landing/src/app/providers/dashboard/verify/page.tsx +106 -0
  93. package/landing/src/app/providers/layout.tsx +14 -0
  94. package/landing/src/app/providers/page.tsx +402 -0
  95. package/landing/src/app/providers/register/page.tsx +670 -0
  96. package/landing/src/components/ProviderDashboard.tsx +794 -0
  97. package/landing/src/hooks/useDashboardData.ts +99 -0
  98. package/landing/src/lib/apis.json +116054 -0
  99. package/landing/src/lib/convex-client.ts +106 -0
  100. package/landing/src/lib/mock-data.ts +285 -0
  101. package/landing/src/lib/stats.json +6 -0
  102. package/landing/tailwind.config.ts +12 -11
  103. package/landing/tsconfig.tsbuildinfo +1 -0
  104. package/package.json +21 -20
  105. package/scripts/SYMBOT-FIX.md +238 -0
  106. package/scripts/demo-simulation.py +177 -0
  107. package/scripts/expand-more.py +502 -0
  108. package/scripts/expand-registry.py +434 -0
  109. package/scripts/history-sanitizer.ts +272 -0
  110. package/scripts/mass-scrape.py +1308 -0
  111. package/scripts/sync-and-deploy.sh +36 -0
  112. package/src/credentials.ts +177 -0
  113. package/src/credits.ts +190 -122
  114. package/src/discovery.ts +45 -58
  115. package/src/execute.ts +350 -0
  116. package/src/index.ts +184 -32
  117. package/src/proxy.ts +24 -0
  118. package/src/registry/apis.json +95362 -202
  119. package/src/registry/apis_expanded.json +100853 -0
  120. package/src/stripe.ts +243 -0
  121. package/src/telemetry.ts +71 -0
  122. package/src/test.ts +127 -89
  123. package/src/types.ts +0 -34
  124. package/src/webhook.ts +107 -0
  125. package/.github/ISSUE_TEMPLATE/add-api.yml +0 -123
  126. package/BRIEFING.md +0 -30
  127. package/backend/convex/apiKeys.ts +0 -75
  128. package/backend/convex/purchases.ts +0 -74
  129. package/backend/convex/schema.ts +0 -45
  130. package/backend/convex/transactions.ts +0 -57
  131. package/backend/convex/users.ts +0 -94
  132. package/backend/package-lock.json +0 -521
  133. package/backend/package.json +0 -15
  134. package/dist/registry/parse_apis.py +0 -146
  135. package/dist/revenuecat.d.ts +0 -61
  136. package/dist/revenuecat.d.ts.map +0 -1
  137. package/dist/revenuecat.js +0 -166
  138. package/dist/revenuecat.js.map +0 -1
  139. package/dist/webhooks/revenuecat.d.ts +0 -48
  140. package/dist/webhooks/revenuecat.d.ts.map +0 -1
  141. package/dist/webhooks/revenuecat.js +0 -119
  142. package/dist/webhooks/revenuecat.js.map +0 -1
  143. package/docs/revenuecat-setup.md +0 -89
  144. package/landing/src/app/api/keys/route.ts +0 -71
  145. package/landing/src/app/api/log/route.ts +0 -37
  146. package/landing/src/app/api/stats/route.ts +0 -37
  147. package/landing/src/app/page.tsx.bak +0 -567
  148. package/landing/src/components/AddKeyModal.tsx +0 -159
  149. package/newsletter-template.html +0 -71
  150. package/outreach/OUTREACH-SYSTEM.md +0 -211
  151. package/outreach/email-template.html +0 -179
  152. package/outreach/targets.md +0 -133
  153. package/src/registry/parse_apis.py +0 -146
  154. package/src/revenuecat.ts +0 -239
  155. package/src/webhooks/revenuecat.ts +0 -187
  156. /package/{backend/convex → convex}/README.md +0 -0
  157. /package/{backend/convex → convex}/_generated/api.js +0 -0
  158. /package/{backend/convex → convex}/_generated/dataModel.d.ts +0 -0
  159. /package/{backend/convex → convex}/_generated/server.d.ts +0 -0
  160. /package/{backend/convex → convex}/_generated/server.js +0 -0
  161. /package/{backend/convex → convex}/tsconfig.json +0 -0
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generate PNG assets from SVG for APIClaw
4
+ * - Favicons (16x16, 32x32, 180x180)
5
+ * - OG Image (1200x630)
6
+ */
7
+
8
+ const { execSync } = require('child_process');
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const publicDir = path.join(__dirname, '..', 'public');
13
+
14
+ // Create OG image HTML template
15
+ const ogImageHtml = `
16
+ <!DOCTYPE html>
17
+ <html>
18
+ <head>
19
+ <meta charset="UTF-8">
20
+ <style>
21
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap');
22
+
23
+ * { margin: 0; padding: 0; box-sizing: border-box; }
24
+
25
+ body {
26
+ width: 1200px;
27
+ height: 630px;
28
+ background: linear-gradient(135deg, #0a0a0a 0%, #171717 100%);
29
+ font-family: 'Inter', system-ui, sans-serif;
30
+ display: flex;
31
+ flex-direction: column;
32
+ justify-content: center;
33
+ padding: 80px;
34
+ position: relative;
35
+ overflow: hidden;
36
+ }
37
+
38
+ /* Background pattern */
39
+ .pattern {
40
+ position: absolute;
41
+ top: 0;
42
+ left: 0;
43
+ right: 0;
44
+ bottom: 0;
45
+ background-image:
46
+ radial-gradient(circle at 20% 80%, rgba(239, 68, 68, 0.15) 0%, transparent 50%),
47
+ radial-gradient(circle at 80% 20%, rgba(239, 68, 68, 0.1) 0%, transparent 40%);
48
+ pointer-events: none;
49
+ }
50
+
51
+ /* Grid lines */
52
+ .grid {
53
+ position: absolute;
54
+ top: 0;
55
+ left: 0;
56
+ right: 0;
57
+ bottom: 0;
58
+ background-image:
59
+ linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
60
+ linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
61
+ background-size: 60px 60px;
62
+ pointer-events: none;
63
+ }
64
+
65
+ .content {
66
+ position: relative;
67
+ z-index: 1;
68
+ }
69
+
70
+ .logo-row {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: 24px;
74
+ margin-bottom: 40px;
75
+ }
76
+
77
+ .logo {
78
+ width: 80px;
79
+ height: 80px;
80
+ background: linear-gradient(135deg, #f87171 0%, #dc2626 100%);
81
+ border-radius: 20px;
82
+ display: flex;
83
+ align-items: center;
84
+ justify-content: center;
85
+ font-size: 48px;
86
+ }
87
+
88
+ .brand {
89
+ font-size: 48px;
90
+ font-weight: 800;
91
+ color: #fafafa;
92
+ letter-spacing: -0.02em;
93
+ }
94
+
95
+ .tagline {
96
+ font-size: 56px;
97
+ font-weight: 800;
98
+ line-height: 1.2;
99
+ letter-spacing: -0.03em;
100
+ margin-bottom: 32px;
101
+ }
102
+
103
+ .tagline .gradient {
104
+ background: linear-gradient(135deg, #f87171 0%, #ef4444 50%, #fca5a5 100%);
105
+ -webkit-background-clip: text;
106
+ -webkit-text-fill-color: transparent;
107
+ background-clip: text;
108
+ }
109
+
110
+ .tagline .white {
111
+ color: #fafafa;
112
+ }
113
+
114
+ .subtitle {
115
+ font-size: 24px;
116
+ color: #a3a3a3;
117
+ max-width: 700px;
118
+ line-height: 1.5;
119
+ }
120
+
121
+ .footer {
122
+ position: absolute;
123
+ bottom: 60px;
124
+ left: 80px;
125
+ right: 80px;
126
+ display: flex;
127
+ justify-content: space-between;
128
+ align-items: center;
129
+ }
130
+
131
+ .stats {
132
+ display: flex;
133
+ gap: 48px;
134
+ }
135
+
136
+ .stat {
137
+ text-align: left;
138
+ }
139
+
140
+ .stat-value {
141
+ font-size: 32px;
142
+ font-weight: 800;
143
+ color: #ef4444;
144
+ }
145
+
146
+ .stat-label {
147
+ font-size: 14px;
148
+ color: #737373;
149
+ text-transform: uppercase;
150
+ letter-spacing: 0.1em;
151
+ }
152
+
153
+ .url {
154
+ font-size: 20px;
155
+ color: #525252;
156
+ font-weight: 500;
157
+ }
158
+ </style>
159
+ </head>
160
+ <body>
161
+ <div class="pattern"></div>
162
+ <div class="grid"></div>
163
+
164
+ <div class="content">
165
+ <div class="logo-row">
166
+ <div class="logo">🦞</div>
167
+ <div class="brand">APIClaw</div>
168
+ </div>
169
+
170
+ <h1 class="tagline">
171
+ <span class="gradient">The API layer</span><br>
172
+ <span class="white">for AI agents</span>
173
+ </h1>
174
+
175
+ <p class="subtitle">
176
+ Agents discover and evaluate APIs via MCP. Structured data. Ranked results. No more googling.
177
+ </p>
178
+ </div>
179
+
180
+ <div class="footer">
181
+ <div class="stats">
182
+ <div class="stat">
183
+ <div class="stat-value">1,400+</div>
184
+ <div class="stat-label">APIs</div>
185
+ </div>
186
+ <div class="stat">
187
+ <div class="stat-value">52</div>
188
+ <div class="stat-label">Categories</div>
189
+ </div>
190
+ <div class="stat">
191
+ <div class="stat-value">MCP</div>
192
+ <div class="stat-label">Native</div>
193
+ </div>
194
+ </div>
195
+ <div class="url">apiclaw.com</div>
196
+ </div>
197
+ </body>
198
+ </html>
199
+ `;
200
+
201
+ // Write OG image HTML
202
+ fs.writeFileSync(path.join(publicDir, 'og-template.html'), ogImageHtml);
203
+ console.log('✓ Created OG image template');
204
+
205
+ // Try to generate PNGs using various methods
206
+ async function generateAssets() {
207
+ // Check for available tools
208
+ const hasRsvgConvert = (() => {
209
+ try {
210
+ execSync('which rsvg-convert', { stdio: 'pipe' });
211
+ return true;
212
+ } catch { return false; }
213
+ })();
214
+
215
+ const hasConvert = (() => {
216
+ try {
217
+ execSync('which convert', { stdio: 'pipe' });
218
+ return true;
219
+ } catch { return false; }
220
+ })();
221
+
222
+ const hasSips = (() => {
223
+ try {
224
+ execSync('which sips', { stdio: 'pipe' });
225
+ return true;
226
+ } catch { return false; }
227
+ })();
228
+
229
+ console.log(`Available tools: rsvg-convert=${hasRsvgConvert}, convert=${hasConvert}, sips=${hasSips}`);
230
+
231
+ // Generate favicons from icon.svg
232
+ const iconSvg = path.join(publicDir, 'icon.svg');
233
+
234
+ const sizes = [
235
+ { size: 16, name: 'favicon-16x16.png' },
236
+ { size: 32, name: 'favicon-32x32.png' },
237
+ { size: 180, name: 'apple-touch-icon.png' },
238
+ { size: 192, name: 'android-chrome-192x192.png' },
239
+ { size: 512, name: 'android-chrome-512x512.png' },
240
+ ];
241
+
242
+ for (const { size, name } of sizes) {
243
+ const output = path.join(publicDir, name);
244
+
245
+ if (hasRsvgConvert) {
246
+ try {
247
+ execSync(`rsvg-convert -w ${size} -h ${size} "${iconSvg}" -o "${output}"`, { stdio: 'pipe' });
248
+ console.log(`✓ Generated ${name} (${size}x${size})`);
249
+ } catch (e) {
250
+ console.log(`✗ Failed to generate ${name}: ${e.message}`);
251
+ }
252
+ } else if (hasConvert) {
253
+ try {
254
+ execSync(`convert -background none -resize ${size}x${size} "${iconSvg}" "${output}"`, { stdio: 'pipe' });
255
+ console.log(`✓ Generated ${name} (${size}x${size})`);
256
+ } catch (e) {
257
+ console.log(`✗ Failed to generate ${name}: ${e.message}`);
258
+ }
259
+ } else {
260
+ console.log(`⚠ Cannot generate ${name} - no SVG converter available`);
261
+ }
262
+ }
263
+
264
+ // Generate favicon.ico (multi-size ICO)
265
+ if (hasConvert) {
266
+ try {
267
+ const ico16 = path.join(publicDir, 'favicon-16x16.png');
268
+ const ico32 = path.join(publicDir, 'favicon-32x32.png');
269
+ const icoOut = path.join(publicDir, 'favicon.ico');
270
+
271
+ if (fs.existsSync(ico16) && fs.existsSync(ico32)) {
272
+ execSync(`convert "${ico16}" "${ico32}" "${icoOut}"`, { stdio: 'pipe' });
273
+ console.log('✓ Generated favicon.ico');
274
+ }
275
+ } catch (e) {
276
+ console.log(`⚠ Could not generate favicon.ico: ${e.message}`);
277
+ }
278
+ }
279
+
280
+ console.log('\\n📝 Note: For OG image, open og-template.html in browser and screenshot at 1200x630');
281
+ console.log(' Or use: npx playwright screenshot --viewport-size=1200,630 public/og-template.html public/og-image.png');
282
+ }
283
+
284
+ generateAssets().catch(console.error);
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Generate PNG assets from SVG using Sharp
4
+ */
5
+
6
+ const sharp = require('sharp');
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ const publicDir = path.join(__dirname, '..', 'public');
11
+
12
+ async function generateFavicons() {
13
+ const iconSvg = fs.readFileSync(path.join(publicDir, 'icon.svg'));
14
+
15
+ const sizes = [
16
+ { size: 16, name: 'favicon-16x16.png' },
17
+ { size: 32, name: 'favicon-32x32.png' },
18
+ { size: 180, name: 'apple-touch-icon.png' },
19
+ { size: 192, name: 'android-chrome-192x192.png' },
20
+ { size: 512, name: 'android-chrome-512x512.png' },
21
+ ];
22
+
23
+ for (const { size, name } of sizes) {
24
+ try {
25
+ await sharp(iconSvg)
26
+ .resize(size, size)
27
+ .png()
28
+ .toFile(path.join(publicDir, name));
29
+ console.log(`✓ Generated ${name} (${size}x${size})`);
30
+ } catch (e) {
31
+ console.log(`✗ Failed ${name}: ${e.message}`);
32
+ }
33
+ }
34
+
35
+ // Generate favicon.ico (just use 32x32 as .ico)
36
+ try {
37
+ await sharp(iconSvg)
38
+ .resize(32, 32)
39
+ .toFile(path.join(publicDir, 'favicon.ico'));
40
+ console.log('✓ Generated favicon.ico');
41
+ } catch (e) {
42
+ console.log(`✗ Failed favicon.ico: ${e.message}`);
43
+ }
44
+ }
45
+
46
+ generateFavicons().then(() => {
47
+ console.log('\n✅ Favicon generation complete!');
48
+ }).catch(console.error);
@@ -0,0 +1,42 @@
1
+ // Generate stats at build time from apis.json
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Try local copy first (for Vercel), then parent directory (for local dev)
6
+ const localRegistryPath = path.join(__dirname, '../src/lib/apis.json');
7
+ const parentRegistryPath = path.join(__dirname, '../../src/registry/apis.json');
8
+ const registryPath = fs.existsSync(localRegistryPath) ? localRegistryPath : parentRegistryPath;
9
+ const outputPath = path.join(__dirname, '../src/lib/stats.json');
10
+
11
+ try {
12
+ const registry = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
13
+
14
+ const categories = [...new Set(registry.apis.map(api => api.category))];
15
+
16
+ const stats = {
17
+ apiCount: registry.count,
18
+ categoryCount: categories.length,
19
+ lastUpdated: registry.lastUpdated || new Date().toISOString().split('T')[0],
20
+ generatedAt: new Date().toISOString()
21
+ };
22
+
23
+ // Ensure directory exists
24
+ const dir = path.dirname(outputPath);
25
+ if (!fs.existsSync(dir)) {
26
+ fs.mkdirSync(dir, { recursive: true });
27
+ }
28
+
29
+ fs.writeFileSync(outputPath, JSON.stringify(stats, null, 2));
30
+ console.log('✓ Stats generated:', stats);
31
+ } catch (err) {
32
+ console.error('Failed to generate stats:', err);
33
+ // Write fallback stats
34
+ const fallback = {
35
+ apiCount: 4518,
36
+ categoryCount: 93,
37
+ lastUpdated: new Date().toISOString().split('T')[0],
38
+ generatedAt: new Date().toISOString()
39
+ };
40
+ fs.writeFileSync(outputPath, JSON.stringify(fallback, null, 2));
41
+ console.log('✓ Fallback stats written');
42
+ }