@nordsym/apiclaw 1.0.0 → 1.1.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.
Files changed (154) hide show
  1. package/AGENTS.md +74 -0
  2. package/HEARTBEAT.md +4 -0
  3. package/IDENTITY.md +22 -0
  4. package/README.md +197 -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 +6 -6
  10. package/convex/credits.ts +211 -0
  11. package/convex/http.ts +490 -0
  12. package/convex/providers.ts +516 -0
  13. package/convex/purchases.ts +183 -0
  14. package/convex/schema.ts +180 -0
  15. package/convex.json +3 -0
  16. package/dist/credentials.d.ts +19 -0
  17. package/dist/credentials.d.ts.map +1 -0
  18. package/dist/credentials.js +158 -0
  19. package/dist/credentials.js.map +1 -0
  20. package/dist/credits.d.ts +14 -11
  21. package/dist/credits.d.ts.map +1 -1
  22. package/dist/credits.js +151 -99
  23. package/dist/credits.js.map +1 -1
  24. package/dist/discovery.d.ts +7 -16
  25. package/dist/discovery.d.ts.map +1 -1
  26. package/dist/discovery.js +33 -40
  27. package/dist/discovery.js.map +1 -1
  28. package/dist/execute.d.ts +19 -0
  29. package/dist/execute.d.ts.map +1 -0
  30. package/dist/execute.js +285 -0
  31. package/dist/execute.js.map +1 -0
  32. package/dist/index.js +106 -30
  33. package/dist/index.js.map +1 -1
  34. package/dist/proxy.d.ts +6 -0
  35. package/dist/proxy.d.ts.map +1 -0
  36. package/dist/proxy.js +19 -0
  37. package/dist/proxy.js.map +1 -0
  38. package/dist/registry/apis.json +95362 -202
  39. package/dist/registry/apis_expanded.json +100853 -0
  40. package/dist/stripe.d.ts +68 -0
  41. package/dist/stripe.d.ts.map +1 -0
  42. package/dist/stripe.js +196 -0
  43. package/dist/stripe.js.map +1 -0
  44. package/dist/test.d.ts +3 -2
  45. package/dist/test.d.ts.map +1 -1
  46. package/dist/test.js +105 -75
  47. package/dist/test.js.map +1 -1
  48. package/dist/types.d.ts +0 -28
  49. package/dist/types.d.ts.map +1 -1
  50. package/dist/webhook.d.ts +2 -0
  51. package/dist/webhook.d.ts.map +1 -0
  52. package/dist/webhook.js +90 -0
  53. package/dist/webhook.js.map +1 -0
  54. package/landing/DESIGN.md +343 -0
  55. package/landing/package-lock.json +1190 -40
  56. package/landing/package.json +5 -2
  57. package/landing/public/android-chrome-192x192.png +0 -0
  58. package/landing/public/android-chrome-512x512.png +0 -0
  59. package/landing/public/apple-touch-icon.png +0 -0
  60. package/landing/public/demo.gif +0 -0
  61. package/landing/public/demo.mp4 +0 -0
  62. package/landing/public/favicon-16x16.png +0 -0
  63. package/landing/public/favicon-32x32.png +0 -0
  64. package/landing/public/favicon.ico +0 -0
  65. package/landing/public/favicon.svg +3 -0
  66. package/landing/public/icon.svg +47 -0
  67. package/landing/public/logo-mono.svg +37 -0
  68. package/landing/public/logo-simple.svg +45 -0
  69. package/landing/public/logo.svg +84 -0
  70. package/landing/public/og-image.png +0 -0
  71. package/landing/public/og-template.html +184 -0
  72. package/landing/public/site.webmanifest +31 -0
  73. package/landing/scripts/generate-assets.js +284 -0
  74. package/landing/scripts/generate-pngs.js +48 -0
  75. package/landing/scripts/generate-stats.js +42 -0
  76. package/landing/src/app/admin/page.tsx +348 -0
  77. package/landing/src/app/api/auth/magic-link/route.ts +73 -0
  78. package/landing/src/app/api/auth/session/route.ts +38 -0
  79. package/landing/src/app/api/auth/verify/route.ts +43 -0
  80. package/landing/src/app/api/og/route.tsx +74 -0
  81. package/landing/src/app/globals.css +439 -100
  82. package/landing/src/app/layout.tsx +37 -9
  83. package/landing/src/app/page.tsx +640 -552
  84. package/landing/src/app/providers/dashboard/login/page.tsx +176 -0
  85. package/landing/src/app/providers/dashboard/page.tsx +589 -0
  86. package/landing/src/app/providers/dashboard/verify/page.tsx +106 -0
  87. package/landing/src/app/providers/layout.tsx +14 -0
  88. package/landing/src/app/providers/page.tsx +402 -0
  89. package/landing/src/app/providers/register/page.tsx +670 -0
  90. package/landing/src/components/ProviderDashboard.tsx +794 -0
  91. package/landing/src/hooks/useDashboardData.ts +99 -0
  92. package/landing/src/lib/apis.json +116054 -0
  93. package/landing/src/lib/convex-client.ts +106 -0
  94. package/landing/src/lib/mock-data.ts +285 -0
  95. package/landing/src/lib/stats.json +6 -0
  96. package/landing/tailwind.config.ts +12 -11
  97. package/landing/tsconfig.tsbuildinfo +1 -0
  98. package/package.json +21 -20
  99. package/scripts/SYMBOT-FIX.md +238 -0
  100. package/scripts/demo-simulation.py +177 -0
  101. package/scripts/expand-more.py +502 -0
  102. package/scripts/expand-registry.py +434 -0
  103. package/scripts/history-sanitizer.ts +272 -0
  104. package/scripts/mass-scrape.py +1308 -0
  105. package/scripts/sync-and-deploy.sh +36 -0
  106. package/src/credentials.ts +177 -0
  107. package/src/credits.ts +190 -122
  108. package/src/discovery.ts +45 -58
  109. package/src/execute.ts +350 -0
  110. package/src/index.ts +113 -31
  111. package/src/proxy.ts +24 -0
  112. package/src/registry/apis.json +95362 -202
  113. package/src/registry/apis_expanded.json +100853 -0
  114. package/src/stripe.ts +243 -0
  115. package/src/test.ts +127 -89
  116. package/src/types.ts +0 -34
  117. package/src/webhook.ts +107 -0
  118. package/.github/ISSUE_TEMPLATE/add-api.yml +0 -123
  119. package/BRIEFING.md +0 -30
  120. package/backend/convex/apiKeys.ts +0 -75
  121. package/backend/convex/purchases.ts +0 -74
  122. package/backend/convex/schema.ts +0 -45
  123. package/backend/convex/transactions.ts +0 -57
  124. package/backend/convex/users.ts +0 -94
  125. package/backend/package-lock.json +0 -521
  126. package/backend/package.json +0 -15
  127. package/dist/registry/parse_apis.py +0 -146
  128. package/dist/revenuecat.d.ts +0 -61
  129. package/dist/revenuecat.d.ts.map +0 -1
  130. package/dist/revenuecat.js +0 -166
  131. package/dist/revenuecat.js.map +0 -1
  132. package/dist/webhooks/revenuecat.d.ts +0 -48
  133. package/dist/webhooks/revenuecat.d.ts.map +0 -1
  134. package/dist/webhooks/revenuecat.js +0 -119
  135. package/dist/webhooks/revenuecat.js.map +0 -1
  136. package/docs/revenuecat-setup.md +0 -89
  137. package/landing/src/app/api/keys/route.ts +0 -71
  138. package/landing/src/app/api/log/route.ts +0 -37
  139. package/landing/src/app/api/stats/route.ts +0 -37
  140. package/landing/src/app/page.tsx.bak +0 -567
  141. package/landing/src/components/AddKeyModal.tsx +0 -159
  142. package/newsletter-template.html +0 -71
  143. package/outreach/OUTREACH-SYSTEM.md +0 -211
  144. package/outreach/email-template.html +0 -179
  145. package/outreach/targets.md +0 -133
  146. package/src/registry/parse_apis.py +0 -146
  147. package/src/revenuecat.ts +0 -239
  148. package/src/webhooks/revenuecat.ts +0 -187
  149. /package/{backend/convex → convex}/README.md +0 -0
  150. /package/{backend/convex → convex}/_generated/api.js +0 -0
  151. /package/{backend/convex → convex}/_generated/dataModel.d.ts +0 -0
  152. /package/{backend/convex → convex}/_generated/server.d.ts +0 -0
  153. /package/{backend/convex → convex}/_generated/server.js +0 -0
  154. /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
+ }