@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.
- package/AGENTS.md +74 -0
- package/HEARTBEAT.md +4 -0
- package/IDENTITY.md +22 -0
- package/README.md +197 -202
- package/SOUL.md +36 -0
- package/STATUS.md +237 -0
- package/TOOLS.md +36 -0
- package/USER.md +17 -0
- package/{backend/convex → convex}/_generated/api.d.ts +6 -6
- package/convex/credits.ts +211 -0
- package/convex/http.ts +490 -0
- package/convex/providers.ts +516 -0
- package/convex/purchases.ts +183 -0
- package/convex/schema.ts +180 -0
- package/convex.json +3 -0
- package/dist/credentials.d.ts +19 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +158 -0
- package/dist/credentials.js.map +1 -0
- package/dist/credits.d.ts +14 -11
- package/dist/credits.d.ts.map +1 -1
- package/dist/credits.js +151 -99
- package/dist/credits.js.map +1 -1
- package/dist/discovery.d.ts +7 -16
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +33 -40
- package/dist/discovery.js.map +1 -1
- package/dist/execute.d.ts +19 -0
- package/dist/execute.d.ts.map +1 -0
- package/dist/execute.js +285 -0
- package/dist/execute.js.map +1 -0
- package/dist/index.js +106 -30
- package/dist/index.js.map +1 -1
- package/dist/proxy.d.ts +6 -0
- package/dist/proxy.d.ts.map +1 -0
- package/dist/proxy.js +19 -0
- package/dist/proxy.js.map +1 -0
- package/dist/registry/apis.json +95362 -202
- package/dist/registry/apis_expanded.json +100853 -0
- package/dist/stripe.d.ts +68 -0
- package/dist/stripe.d.ts.map +1 -0
- package/dist/stripe.js +196 -0
- package/dist/stripe.js.map +1 -0
- package/dist/test.d.ts +3 -2
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +105 -75
- package/dist/test.js.map +1 -1
- package/dist/types.d.ts +0 -28
- package/dist/types.d.ts.map +1 -1
- package/dist/webhook.d.ts +2 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +90 -0
- package/dist/webhook.js.map +1 -0
- package/landing/DESIGN.md +343 -0
- package/landing/package-lock.json +1190 -40
- package/landing/package.json +5 -2
- package/landing/public/android-chrome-192x192.png +0 -0
- package/landing/public/android-chrome-512x512.png +0 -0
- package/landing/public/apple-touch-icon.png +0 -0
- package/landing/public/demo.gif +0 -0
- package/landing/public/demo.mp4 +0 -0
- package/landing/public/favicon-16x16.png +0 -0
- package/landing/public/favicon-32x32.png +0 -0
- package/landing/public/favicon.ico +0 -0
- package/landing/public/favicon.svg +3 -0
- package/landing/public/icon.svg +47 -0
- package/landing/public/logo-mono.svg +37 -0
- package/landing/public/logo-simple.svg +45 -0
- package/landing/public/logo.svg +84 -0
- package/landing/public/og-image.png +0 -0
- package/landing/public/og-template.html +184 -0
- package/landing/public/site.webmanifest +31 -0
- package/landing/scripts/generate-assets.js +284 -0
- package/landing/scripts/generate-pngs.js +48 -0
- package/landing/scripts/generate-stats.js +42 -0
- package/landing/src/app/admin/page.tsx +348 -0
- package/landing/src/app/api/auth/magic-link/route.ts +73 -0
- package/landing/src/app/api/auth/session/route.ts +38 -0
- package/landing/src/app/api/auth/verify/route.ts +43 -0
- package/landing/src/app/api/og/route.tsx +74 -0
- package/landing/src/app/globals.css +439 -100
- package/landing/src/app/layout.tsx +37 -9
- package/landing/src/app/page.tsx +640 -552
- package/landing/src/app/providers/dashboard/login/page.tsx +176 -0
- package/landing/src/app/providers/dashboard/page.tsx +589 -0
- package/landing/src/app/providers/dashboard/verify/page.tsx +106 -0
- package/landing/src/app/providers/layout.tsx +14 -0
- package/landing/src/app/providers/page.tsx +402 -0
- package/landing/src/app/providers/register/page.tsx +670 -0
- package/landing/src/components/ProviderDashboard.tsx +794 -0
- package/landing/src/hooks/useDashboardData.ts +99 -0
- package/landing/src/lib/apis.json +116054 -0
- package/landing/src/lib/convex-client.ts +106 -0
- package/landing/src/lib/mock-data.ts +285 -0
- package/landing/src/lib/stats.json +6 -0
- package/landing/tailwind.config.ts +12 -11
- package/landing/tsconfig.tsbuildinfo +1 -0
- package/package.json +21 -20
- package/scripts/SYMBOT-FIX.md +238 -0
- package/scripts/demo-simulation.py +177 -0
- package/scripts/expand-more.py +502 -0
- package/scripts/expand-registry.py +434 -0
- package/scripts/history-sanitizer.ts +272 -0
- package/scripts/mass-scrape.py +1308 -0
- package/scripts/sync-and-deploy.sh +36 -0
- package/src/credentials.ts +177 -0
- package/src/credits.ts +190 -122
- package/src/discovery.ts +45 -58
- package/src/execute.ts +350 -0
- package/src/index.ts +113 -31
- package/src/proxy.ts +24 -0
- package/src/registry/apis.json +95362 -202
- package/src/registry/apis_expanded.json +100853 -0
- package/src/stripe.ts +243 -0
- package/src/test.ts +127 -89
- package/src/types.ts +0 -34
- package/src/webhook.ts +107 -0
- package/.github/ISSUE_TEMPLATE/add-api.yml +0 -123
- package/BRIEFING.md +0 -30
- package/backend/convex/apiKeys.ts +0 -75
- package/backend/convex/purchases.ts +0 -74
- package/backend/convex/schema.ts +0 -45
- package/backend/convex/transactions.ts +0 -57
- package/backend/convex/users.ts +0 -94
- package/backend/package-lock.json +0 -521
- package/backend/package.json +0 -15
- package/dist/registry/parse_apis.py +0 -146
- package/dist/revenuecat.d.ts +0 -61
- package/dist/revenuecat.d.ts.map +0 -1
- package/dist/revenuecat.js +0 -166
- package/dist/revenuecat.js.map +0 -1
- package/dist/webhooks/revenuecat.d.ts +0 -48
- package/dist/webhooks/revenuecat.d.ts.map +0 -1
- package/dist/webhooks/revenuecat.js +0 -119
- package/dist/webhooks/revenuecat.js.map +0 -1
- package/docs/revenuecat-setup.md +0 -89
- package/landing/src/app/api/keys/route.ts +0 -71
- package/landing/src/app/api/log/route.ts +0 -37
- package/landing/src/app/api/stats/route.ts +0 -37
- package/landing/src/app/page.tsx.bak +0 -567
- package/landing/src/components/AddKeyModal.tsx +0 -159
- package/newsletter-template.html +0 -71
- package/outreach/OUTREACH-SYSTEM.md +0 -211
- package/outreach/email-template.html +0 -179
- package/outreach/targets.md +0 -133
- package/src/registry/parse_apis.py +0 -146
- package/src/revenuecat.ts +0 -239
- package/src/webhooks/revenuecat.ts +0 -187
- /package/{backend/convex → convex}/README.md +0 -0
- /package/{backend/convex → convex}/_generated/api.js +0 -0
- /package/{backend/convex → convex}/_generated/dataModel.d.ts +0 -0
- /package/{backend/convex → convex}/_generated/server.d.ts +0 -0
- /package/{backend/convex → convex}/_generated/server.js +0 -0
- /package/{backend/convex → convex}/tsconfig.json +0 -0
package/src/index.ts
CHANGED
|
@@ -18,14 +18,17 @@ import {
|
|
|
18
18
|
Tool,
|
|
19
19
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
20
20
|
|
|
21
|
-
import { discoverAPIs, getAPIDetails, getCategories, getAllAPIs
|
|
21
|
+
import { discoverAPIs, getAPIDetails, getCategories, getAllAPIs } from './discovery.js';
|
|
22
22
|
import {
|
|
23
23
|
getAgentCredits,
|
|
24
24
|
addCredits,
|
|
25
25
|
purchaseAPIAccess,
|
|
26
26
|
getBalanceSummary,
|
|
27
|
-
getAgentPurchases
|
|
27
|
+
getAgentPurchases,
|
|
28
|
+
getProvidersWithRealCredentials
|
|
28
29
|
} from './credits.js';
|
|
30
|
+
import { hasRealCredentials } from './credentials.js';
|
|
31
|
+
import { executeAPICall, getConnectedProviders } from './execute.js';
|
|
29
32
|
|
|
30
33
|
// Default agent ID for MVP (in production, this would come from auth)
|
|
31
34
|
const DEFAULT_AGENT_ID = 'agent_default';
|
|
@@ -34,22 +37,27 @@ const DEFAULT_AGENT_ID = 'agent_default';
|
|
|
34
37
|
const tools: Tool[] = [
|
|
35
38
|
{
|
|
36
39
|
name: 'discover_apis',
|
|
37
|
-
description: 'Search
|
|
40
|
+
description: 'Search for APIs based on what you need to do. Describe your use case naturally.',
|
|
38
41
|
inputSchema: {
|
|
39
42
|
type: 'object',
|
|
40
43
|
properties: {
|
|
41
44
|
query: {
|
|
42
45
|
type: 'string',
|
|
43
|
-
description: 'Natural language query describing what you need (e.g., "send SMS
|
|
46
|
+
description: 'Natural language query describing what you need (e.g., "send SMS to Sweden", "search the web", "generate speech from text")'
|
|
44
47
|
},
|
|
45
48
|
category: {
|
|
46
49
|
type: 'string',
|
|
47
|
-
description: 'Filter by category
|
|
50
|
+
description: 'Filter by category: communication, search, ai',
|
|
51
|
+
enum: ['communication', 'search', 'ai']
|
|
48
52
|
},
|
|
49
53
|
max_results: {
|
|
50
54
|
type: 'number',
|
|
51
|
-
description: 'Maximum number of results to return (default:
|
|
52
|
-
default:
|
|
55
|
+
description: 'Maximum number of results to return (default: 5)',
|
|
56
|
+
default: 5
|
|
57
|
+
},
|
|
58
|
+
region: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Filter by region (e.g., "SE", "EU", "global")'
|
|
53
61
|
}
|
|
54
62
|
},
|
|
55
63
|
required: ['query']
|
|
@@ -129,6 +137,36 @@ const tools: Tool[] = [
|
|
|
129
137
|
type: 'object',
|
|
130
138
|
properties: {}
|
|
131
139
|
}
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'call_api',
|
|
143
|
+
description: 'Execute an API call through APIClaw Instant Connect. No API keys needed - we handle authentication.',
|
|
144
|
+
inputSchema: {
|
|
145
|
+
type: 'object',
|
|
146
|
+
properties: {
|
|
147
|
+
provider: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description: 'Provider ID (e.g., "46elks", "brave_search", "resend", "openrouter", "elevenlabs", "twilio")'
|
|
150
|
+
},
|
|
151
|
+
action: {
|
|
152
|
+
type: 'string',
|
|
153
|
+
description: 'Action to perform (e.g., "send_sms", "search", "send_email", "chat", "text_to_speech")'
|
|
154
|
+
},
|
|
155
|
+
params: {
|
|
156
|
+
type: 'object',
|
|
157
|
+
description: 'Parameters for the action. Varies by provider/action.'
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
required: ['provider', 'action', 'params']
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'list_connected',
|
|
165
|
+
description: 'List all APIs available for Instant Connect (no API key needed).',
|
|
166
|
+
inputSchema: {
|
|
167
|
+
type: 'object',
|
|
168
|
+
properties: {}
|
|
169
|
+
}
|
|
132
170
|
}
|
|
133
171
|
];
|
|
134
172
|
|
|
@@ -159,9 +197,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
159
197
|
case 'discover_apis': {
|
|
160
198
|
const query = args?.query as string;
|
|
161
199
|
const category = args?.category as string | undefined;
|
|
162
|
-
const maxResults = (args?.max_results as number) ||
|
|
200
|
+
const maxResults = (args?.max_results as number) || 5;
|
|
201
|
+
const region = args?.region as string | undefined;
|
|
163
202
|
|
|
164
|
-
const results = discoverAPIs(query, { category, maxResults });
|
|
203
|
+
const results = discoverAPIs(query, { category, maxResults, region });
|
|
165
204
|
|
|
166
205
|
if (results.length === 0) {
|
|
167
206
|
return {
|
|
@@ -171,8 +210,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
171
210
|
text: JSON.stringify({
|
|
172
211
|
status: 'no_results',
|
|
173
212
|
message: `No APIs found matching "${query}". Try broader terms or check available categories with list_categories.`,
|
|
174
|
-
|
|
175
|
-
available_categories: getCategories().slice(0, 20)
|
|
213
|
+
available_categories: getCategories()
|
|
176
214
|
}, null, 2)
|
|
177
215
|
}
|
|
178
216
|
]
|
|
@@ -187,17 +225,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
187
225
|
status: 'success',
|
|
188
226
|
query,
|
|
189
227
|
results_count: results.length,
|
|
190
|
-
total_apis: getAPICount(),
|
|
191
228
|
results: results.map(r => ({
|
|
192
|
-
id: r.
|
|
193
|
-
name: r.
|
|
194
|
-
description: r.
|
|
195
|
-
category: r.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
keywords: r.api.keywords,
|
|
229
|
+
id: r.provider.id,
|
|
230
|
+
name: r.provider.name,
|
|
231
|
+
description: r.provider.description,
|
|
232
|
+
category: r.provider.category,
|
|
233
|
+
capabilities: r.provider.capabilities,
|
|
234
|
+
pricing_model: r.provider.pricing.model,
|
|
235
|
+
has_free_tier: r.provider.pricing.free_tier,
|
|
236
|
+
agent_success_rate: r.provider.agent_success_rate,
|
|
201
237
|
relevance_score: r.relevance_score,
|
|
202
238
|
match_reasons: r.match_reasons
|
|
203
239
|
}))
|
|
@@ -274,12 +310,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
274
310
|
provider: apiId,
|
|
275
311
|
amount_paid_usd: amountUsd,
|
|
276
312
|
credits_received: result.purchase!.credits_purchased,
|
|
277
|
-
status: result.purchase!.status
|
|
313
|
+
status: result.purchase!.status,
|
|
314
|
+
real_credentials: hasRealCredentials(apiId)
|
|
278
315
|
},
|
|
279
316
|
credentials: result.purchase!.credentials,
|
|
280
317
|
access: {
|
|
281
|
-
|
|
282
|
-
|
|
318
|
+
base_url: api?.base_url,
|
|
319
|
+
docs_url: api?.docs_url,
|
|
320
|
+
auth_type: api?.auth_type
|
|
283
321
|
}
|
|
284
322
|
}, null, 2)
|
|
285
323
|
}
|
|
@@ -301,11 +339,13 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
301
339
|
balance_usd: summary.credits.balance_usd,
|
|
302
340
|
currency: summary.credits.currency,
|
|
303
341
|
total_spent_usd: summary.total_spent_usd,
|
|
342
|
+
real_credential_providers: summary.real_credentials_available,
|
|
304
343
|
active_purchases: summary.active_purchases.map(p => ({
|
|
305
344
|
id: p.id,
|
|
306
345
|
provider: p.provider_id,
|
|
307
|
-
credits_remaining: p.credits_purchased,
|
|
308
|
-
status: p.status
|
|
346
|
+
credits_remaining: p.credits_purchased,
|
|
347
|
+
status: p.status,
|
|
348
|
+
real_credentials: hasRealCredentials(p.provider_id)
|
|
309
349
|
}))
|
|
310
350
|
}, null, 2)
|
|
311
351
|
}
|
|
@@ -335,10 +375,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
335
375
|
|
|
336
376
|
case 'list_categories': {
|
|
337
377
|
const categories = getCategories();
|
|
338
|
-
const
|
|
378
|
+
const apisByCategory: Record<string, string[]> = {};
|
|
339
379
|
|
|
340
380
|
for (const cat of categories) {
|
|
341
|
-
|
|
381
|
+
apisByCategory[cat] = getAllAPIs()
|
|
382
|
+
.filter(a => a.category === cat)
|
|
383
|
+
.map(a => a.id);
|
|
342
384
|
}
|
|
343
385
|
|
|
344
386
|
return {
|
|
@@ -347,9 +389,49 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
347
389
|
type: 'text',
|
|
348
390
|
text: JSON.stringify({
|
|
349
391
|
status: 'success',
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
392
|
+
categories: apisByCategory
|
|
393
|
+
}, null, 2)
|
|
394
|
+
}
|
|
395
|
+
]
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
case 'call_api': {
|
|
400
|
+
const provider = args?.provider as string;
|
|
401
|
+
const action = args?.action as string;
|
|
402
|
+
const params = (args?.params as Record<string, any>) || {};
|
|
403
|
+
|
|
404
|
+
const result = await executeAPICall(provider, action, params);
|
|
405
|
+
|
|
406
|
+
return {
|
|
407
|
+
content: [
|
|
408
|
+
{
|
|
409
|
+
type: 'text',
|
|
410
|
+
text: JSON.stringify({
|
|
411
|
+
status: result.success ? 'success' : 'error',
|
|
412
|
+
provider: result.provider,
|
|
413
|
+
action: result.action,
|
|
414
|
+
...(result.success ? { data: result.data } : { error: result.error }),
|
|
415
|
+
...(result.cost !== undefined ? { cost_sek: result.cost } : {})
|
|
416
|
+
}, null, 2)
|
|
417
|
+
}
|
|
418
|
+
],
|
|
419
|
+
isError: !result.success
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
case 'list_connected': {
|
|
424
|
+
const connected = getConnectedProviders();
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
content: [
|
|
428
|
+
{
|
|
429
|
+
type: 'text',
|
|
430
|
+
text: JSON.stringify({
|
|
431
|
+
status: 'success',
|
|
432
|
+
message: 'These APIs are available for Instant Connect - no API key needed!',
|
|
433
|
+
connected_providers: connected,
|
|
434
|
+
usage: 'Use call_api with provider, action, and params to execute calls.'
|
|
353
435
|
}, null, 2)
|
|
354
436
|
}
|
|
355
437
|
]
|
package/src/proxy.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* APIClaw Proxy - Fallback to hosted API when no local credentials
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const PROXY_BASE = "https://adventurous-avocet-799.convex.site/proxy";
|
|
6
|
+
|
|
7
|
+
export async function callProxy(provider: string, params: any): Promise<any> {
|
|
8
|
+
const url = `${PROXY_BASE}/${provider}`;
|
|
9
|
+
|
|
10
|
+
const response = await fetch(url, {
|
|
11
|
+
method: "POST",
|
|
12
|
+
headers: { "Content-Type": "application/json" },
|
|
13
|
+
body: JSON.stringify(params),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (!response.ok) {
|
|
17
|
+
const errorData = await response.json().catch(() => ({ error: "Proxy request failed" })) as { error?: string };
|
|
18
|
+
throw new Error(errorData.error || `Proxy error: ${response.status}`);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return response.json();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const PROXY_PROVIDERS = ["openrouter", "brave_search", "resend", "elevenlabs"];
|