@nordsym/apiclaw 2.2.0 → 2.3.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 (176) hide show
  1. package/README.md +15 -2
  2. package/dist/bin-http.js +0 -0
  3. package/dist/bin.bundled.js +79288 -0
  4. package/dist/gateway-client.d.ts.map +1 -1
  5. package/dist/gateway-client.js +24 -2
  6. package/dist/gateway-client.js.map +1 -1
  7. package/dist/index.bundled.js +61263 -0
  8. package/dist/index.js +2 -2
  9. package/dist/index.js.map +1 -1
  10. package/package.json +7 -2
  11. package/.claude/settings.local.json +0 -13
  12. package/.env.prod +0 -1
  13. package/apiclaw-README.md +0 -494
  14. package/convex/_generated/api.d.ts +0 -145
  15. package/convex/_generated/api.js +0 -23
  16. package/convex/_generated/dataModel.d.ts +0 -60
  17. package/convex/_generated/server.d.ts +0 -143
  18. package/convex/_generated/server.js +0 -93
  19. package/convex/_listWorkspaces.ts +0 -13
  20. package/convex/adminActivate.ts +0 -53
  21. package/convex/adminStats.ts +0 -306
  22. package/convex/agents.ts +0 -939
  23. package/convex/analytics.ts +0 -187
  24. package/convex/apiKeys.ts +0 -220
  25. package/convex/backfillAnalytics.ts +0 -272
  26. package/convex/backfillSearchLogs.ts +0 -35
  27. package/convex/billing.ts +0 -834
  28. package/convex/capabilities.ts +0 -157
  29. package/convex/chains.ts +0 -1318
  30. package/convex/credits.ts +0 -211
  31. package/convex/crons.ts +0 -65
  32. package/convex/debugFilestackLogs.ts +0 -16
  33. package/convex/debugGetToken.ts +0 -18
  34. package/convex/directCall.ts +0 -713
  35. package/convex/earnProgress.ts +0 -753
  36. package/convex/email.ts +0 -329
  37. package/convex/feedback.ts +0 -265
  38. package/convex/funnel.ts +0 -431
  39. package/convex/guards.ts +0 -174
  40. package/convex/http.ts +0 -3756
  41. package/convex/inbound.ts +0 -32
  42. package/convex/logs.ts +0 -701
  43. package/convex/migrateFilestack.ts +0 -81
  44. package/convex/migratePartnersProd.ts +0 -174
  45. package/convex/migratePratham.ts +0 -126
  46. package/convex/migrateProviderWorkspaces.ts +0 -175
  47. package/convex/mou.ts +0 -91
  48. package/convex/nurture.ts +0 -355
  49. package/convex/providerKeys.ts +0 -289
  50. package/convex/providers.ts +0 -1135
  51. package/convex/purchases.ts +0 -183
  52. package/convex/ratelimit.ts +0 -104
  53. package/convex/schema.ts +0 -926
  54. package/convex/searchLogs.ts +0 -265
  55. package/convex/seedAPILayerAPIs.ts +0 -191
  56. package/convex/seedDirectCallConfigs.ts +0 -336
  57. package/convex/seedPratham.ts +0 -149
  58. package/convex/spendAlerts.ts +0 -442
  59. package/convex/stripeActions.ts +0 -607
  60. package/convex/teams.ts +0 -243
  61. package/convex/telemetry.ts +0 -81
  62. package/convex/tsconfig.json +0 -25
  63. package/convex/updateAPIStatus.ts +0 -44
  64. package/convex/usage.ts +0 -260
  65. package/convex/usageReports.ts +0 -357
  66. package/convex/waitlist.ts +0 -55
  67. package/convex/webhooks.ts +0 -494
  68. package/convex/workspaceSettings.ts +0 -143
  69. package/convex/workspaces.ts +0 -1331
  70. package/convex.json +0 -3
  71. package/direct-test.mjs +0 -51
  72. package/email-templates/filestack-provider-outreach.html +0 -162
  73. package/email-templates/partnership-template.html +0 -116
  74. package/email-templates/pratham-draft-preview.txt +0 -57
  75. package/email-templates/pratham-partnership-draft.html +0 -141
  76. package/reports/APIClaw-Session-Report-2026-04-05.pdf +0 -0
  77. package/reports/pipeline/PIPELINE-REPORT.json +0 -153
  78. package/reports/pipeline/acquire_apisguru.json +0 -17
  79. package/reports/pipeline/capabilities.json +0 -38
  80. package/reports/pipeline/discover_azure_recursive.json +0 -1551
  81. package/reports/pipeline/discover_github.json +0 -25
  82. package/reports/pipeline/discover_github_repos.json +0 -49
  83. package/reports/pipeline/discover_swaggerhub.json +0 -24
  84. package/reports/pipeline/discover_well_known.json +0 -23
  85. package/reports/pipeline/fetch_specs.json +0 -19
  86. package/reports/pipeline/generate_providers.json +0 -14
  87. package/reports/pipeline/match_registry.json +0 -11
  88. package/reports/pipeline/parse_specs.json +0 -17
  89. package/reports/pipeline/promote_candidates.json +0 -34
  90. package/reports/pipeline/validate.json +0 -30
  91. package/reports/pipeline/validate_smoke_details.json +0 -3835
  92. package/reports/session-report-2026-04-05.html +0 -433
  93. package/seed-apis-direct.mjs +0 -106
  94. package/src/access-control.ts +0 -174
  95. package/src/adapters/base.ts +0 -364
  96. package/src/adapters/claude-desktop.ts +0 -41
  97. package/src/adapters/cline.ts +0 -88
  98. package/src/adapters/continue.ts +0 -91
  99. package/src/adapters/cursor.ts +0 -43
  100. package/src/adapters/custom.ts +0 -188
  101. package/src/adapters/detect.ts +0 -202
  102. package/src/adapters/index.ts +0 -47
  103. package/src/adapters/windsurf.ts +0 -44
  104. package/src/bin-http.ts +0 -45
  105. package/src/bin.ts +0 -34
  106. package/src/capability-router.ts +0 -331
  107. package/src/chainExecutor.ts +0 -730
  108. package/src/chainResolver.test.ts +0 -246
  109. package/src/chainResolver.ts +0 -658
  110. package/src/cli/commands/demo.ts +0 -109
  111. package/src/cli/commands/doctor.ts +0 -435
  112. package/src/cli/commands/index.ts +0 -9
  113. package/src/cli/commands/login.ts +0 -203
  114. package/src/cli/commands/mcp-install.ts +0 -373
  115. package/src/cli/commands/restore.ts +0 -333
  116. package/src/cli/commands/setup.ts +0 -297
  117. package/src/cli/commands/uninstall.ts +0 -240
  118. package/src/cli/index.ts +0 -148
  119. package/src/cli.ts +0 -370
  120. package/src/confirmation.ts +0 -296
  121. package/src/credentials.ts +0 -455
  122. package/src/credits.ts +0 -329
  123. package/src/crypto.ts +0 -75
  124. package/src/discovery.ts +0 -568
  125. package/src/enterprise/env.ts +0 -156
  126. package/src/enterprise/index.ts +0 -7
  127. package/src/enterprise/script-generator.ts +0 -481
  128. package/src/execute-dynamic.ts +0 -617
  129. package/src/execute.ts +0 -2386
  130. package/src/funnel-client.ts +0 -168
  131. package/src/funnel.test.ts +0 -187
  132. package/src/gateway-client.ts +0 -192
  133. package/src/hivr-whitelist.ts +0 -110
  134. package/src/http-api.ts +0 -286
  135. package/src/http-server-minimal.ts +0 -154
  136. package/src/index.ts +0 -2702
  137. package/src/intelligent-gateway.ts +0 -339
  138. package/src/mcp-analytics.ts +0 -156
  139. package/src/metered.ts +0 -149
  140. package/src/open-apis-generated.ts +0 -157
  141. package/src/open-apis.ts +0 -558
  142. package/src/postinstall.ts +0 -40
  143. package/src/product-whitelist.ts +0 -246
  144. package/src/proxy.ts +0 -36
  145. package/src/registration-guard.ts +0 -117
  146. package/src/session.ts +0 -129
  147. package/src/stripe.ts +0 -497
  148. package/src/telemetry.ts +0 -71
  149. package/src/test.ts +0 -135
  150. package/src/types/convex-api.d.ts +0 -20
  151. package/src/types/convex-api.ts +0 -21
  152. package/src/types.ts +0 -109
  153. package/src/ui/colors.ts +0 -219
  154. package/src/ui/errors.ts +0 -394
  155. package/src/ui/index.ts +0 -17
  156. package/src/ui/prompts.ts +0 -390
  157. package/src/ui/spinner.ts +0 -325
  158. package/src/utils/backup.ts +0 -224
  159. package/src/utils/config.ts +0 -318
  160. package/src/utils/os.ts +0 -124
  161. package/src/utils/paths.ts +0 -203
  162. package/src/webhook.ts +0 -107
  163. package/test-10-working.cjs +0 -97
  164. package/test-14-final.cjs +0 -96
  165. package/test-actual-handlers.ts +0 -92
  166. package/test-apilayer-all-14.ts +0 -249
  167. package/test-apilayer-fixed.ts +0 -248
  168. package/test-direct-endpoints.ts +0 -174
  169. package/test-exact-endpoints.ts +0 -144
  170. package/test-final.ts +0 -83
  171. package/test-full-routing.ts +0 -100
  172. package/test-handlers-correct.ts +0 -217
  173. package/test-numverify-key.ts +0 -41
  174. package/test-via-handlers.ts +0 -92
  175. package/test-worldnews.mjs +0 -26
  176. package/tsconfig.json +0 -20
package/src/discovery.ts DELETED
@@ -1,568 +0,0 @@
1
- // Discovery engine for APIvault
2
- // MVP: Keyword matching. Future: Embeddings + semantic search
3
-
4
- import { APIProvider, SearchResult, APIDetailsResponse } from './types.js';
5
- import { readFileSync } from 'fs';
6
- import { fileURLToPath } from 'url';
7
- import { dirname, join } from 'path';
8
- import { getConnectedProviders } from './execute.js';
9
- import { openAPIs, isOpenAPI } from './open-apis.js';
10
-
11
- const __filename = fileURLToPath(import.meta.url);
12
- const __dirname = dirname(__filename);
13
-
14
- const apisData = JSON.parse(
15
- readFileSync(join(__dirname, 'registry', 'apis.json'), 'utf-8')
16
- );
17
- const apis: APIProvider[] = apisData.apis;
18
-
19
- // Direct Call provider specs (hardcoded handlers with params)
20
- // Ordered: AI-first (models, LLM routing, audio), then infrastructure (code, web, search, email, SMS)
21
- const DIRECT_CALL_SPECS: Record<string, {
22
- description: string;
23
- auth: string;
24
- docs: string;
25
- actions: Record<string, { params: { name: string; required: boolean; desc: string }[]; desc: string }>;
26
- }> = {
27
- openrouter: {
28
- description: 'LLM routing (100+ models)',
29
- auth: 'bearer',
30
- docs: 'https://openrouter.ai/docs',
31
- actions: {
32
- chat: {
33
- desc: 'Chat completion',
34
- params: [
35
- { name: 'messages', required: true, desc: 'Array of {role, content}' },
36
- { name: 'model', required: false, desc: 'Model ID (default: claude-3-haiku)' },
37
- { name: 'max_tokens', required: false, desc: 'Max response tokens (default: 1000)' },
38
- ],
39
- },
40
- },
41
- },
42
- replicate: {
43
- description: 'Run any AI model (images, video, audio)',
44
- auth: 'bearer',
45
- docs: 'https://replicate.com/docs',
46
- actions: {
47
- run: {
48
- desc: 'Run a model',
49
- params: [
50
- { name: 'model', required: true, desc: 'Model ID (e.g., stability-ai/sdxl:...)' },
51
- { name: 'input', required: true, desc: 'Model input parameters' },
52
- ],
53
- },
54
- list_models: {
55
- desc: 'List available models',
56
- params: [],
57
- },
58
- },
59
- },
60
- elevenlabs: {
61
- description: 'Text-to-speech',
62
- auth: 'api_key',
63
- docs: 'https://elevenlabs.io/docs',
64
- actions: {
65
- text_to_speech: {
66
- desc: 'Generate audio from text',
67
- params: [
68
- { name: 'text', required: true, desc: 'Text to speak' },
69
- { name: 'voice_id', required: false, desc: 'Voice ID (default: Rachel)' },
70
- { name: 'model_id', required: false, desc: 'Model ID' },
71
- ],
72
- },
73
- },
74
- },
75
- e2b: {
76
- description: 'Code sandbox for AI agents',
77
- auth: 'api_key',
78
- docs: 'https://e2b.dev/docs',
79
- actions: {
80
- run_code: {
81
- desc: 'Execute code in sandbox',
82
- params: [
83
- { name: 'code', required: true, desc: 'Code to run' },
84
- { name: 'language', required: false, desc: 'Language (default: python)' },
85
- ],
86
- },
87
- run_shell: {
88
- desc: 'Execute shell command',
89
- params: [
90
- { name: 'command', required: true, desc: 'Shell command' },
91
- ],
92
- },
93
- },
94
- },
95
- firecrawl: {
96
- description: 'Web scraping and crawling',
97
- auth: 'bearer',
98
- docs: 'https://firecrawl.dev/docs',
99
- actions: {
100
- scrape: {
101
- desc: 'Scrape a URL',
102
- params: [
103
- { name: 'url', required: true, desc: 'URL to scrape' },
104
- { name: 'formats', required: false, desc: 'Output formats (default: ["markdown"])' },
105
- ],
106
- },
107
- crawl: {
108
- desc: 'Start a crawl job',
109
- params: [
110
- { name: 'url', required: true, desc: 'Starting URL' },
111
- { name: 'limit', required: false, desc: 'Max pages (default: 10)' },
112
- ],
113
- },
114
- map: {
115
- desc: 'Map site structure',
116
- params: [
117
- { name: 'url', required: true, desc: 'URL to map' },
118
- ],
119
- },
120
- },
121
- },
122
- github: {
123
- description: 'Code repos and developer data',
124
- auth: 'bearer',
125
- docs: 'https://docs.github.com/rest',
126
- actions: {
127
- search_repos: {
128
- desc: 'Search repositories',
129
- params: [
130
- { name: 'query', required: true, desc: 'Search query' },
131
- { name: 'sort', required: false, desc: 'Sort by (default: stars)' },
132
- { name: 'limit', required: false, desc: 'Max results (default: 10)' },
133
- ],
134
- },
135
- get_repo: {
136
- desc: 'Get repo details',
137
- params: [
138
- { name: 'owner', required: true, desc: 'Repo owner' },
139
- { name: 'repo', required: true, desc: 'Repo name' },
140
- ],
141
- },
142
- list_issues: {
143
- desc: 'List issues',
144
- params: [
145
- { name: 'owner', required: true, desc: 'Repo owner' },
146
- { name: 'repo', required: true, desc: 'Repo name' },
147
- { name: 'state', required: false, desc: 'State filter (default: open)' },
148
- ],
149
- },
150
- create_issue: {
151
- desc: 'Create issue',
152
- params: [
153
- { name: 'owner', required: true, desc: 'Repo owner' },
154
- { name: 'repo', required: true, desc: 'Repo name' },
155
- { name: 'title', required: true, desc: 'Issue title' },
156
- { name: 'body', required: false, desc: 'Issue body' },
157
- ],
158
- },
159
- get_file: {
160
- desc: 'Get file contents',
161
- params: [
162
- { name: 'owner', required: true, desc: 'Repo owner' },
163
- { name: 'repo', required: true, desc: 'Repo name' },
164
- { name: 'path', required: true, desc: 'File path' },
165
- ],
166
- },
167
- },
168
- },
169
- brave_search: {
170
- description: 'Web search API',
171
- auth: 'api_key',
172
- docs: 'https://api.search.brave.com/docs',
173
- actions: {
174
- search: {
175
- desc: 'Search the web',
176
- params: [
177
- { name: 'query', required: true, desc: 'Search query' },
178
- { name: 'count', required: false, desc: 'Number of results (default: 5)' },
179
- ],
180
- },
181
- },
182
- },
183
- resend: {
184
- description: 'Email API',
185
- auth: 'bearer',
186
- docs: 'https://resend.com/docs',
187
- actions: {
188
- send_email: {
189
- desc: 'Send email',
190
- params: [
191
- { name: 'to', required: true, desc: 'Recipient email' },
192
- { name: 'subject', required: true, desc: 'Email subject' },
193
- { name: 'html', required: false, desc: 'HTML body' },
194
- { name: 'text', required: false, desc: 'Plain text body' },
195
- { name: 'from', required: false, desc: 'Sender (default: noreply@apiclaw.cloud)' },
196
- ],
197
- },
198
- },
199
- },
200
- '46elks': {
201
- description: 'Swedish SMS and voice API',
202
- auth: 'basic',
203
- docs: 'https://46elks.com/docs',
204
- actions: {
205
- send_sms: {
206
- desc: 'Send SMS message',
207
- params: [
208
- { name: 'to', required: true, desc: 'Phone number (+46...)' },
209
- { name: 'message', required: true, desc: 'SMS text (max 160 chars for 1 segment)' },
210
- { name: 'from', required: false, desc: 'Sender ID (default: APIClaw)' },
211
- ],
212
- },
213
- },
214
- },
215
- twilio: {
216
- description: 'Global SMS and voice API',
217
- auth: 'basic',
218
- docs: 'https://www.twilio.com/docs',
219
- actions: {
220
- send_sms: {
221
- desc: 'Send SMS message',
222
- params: [
223
- { name: 'to', required: true, desc: 'Phone number (E.164 format)' },
224
- { name: 'message', required: true, desc: 'SMS text' },
225
- { name: 'from', required: false, desc: 'Sender phone number' },
226
- ],
227
- },
228
- },
229
- },
230
- apilayer: {
231
- description: 'APILayer marketplace — currency, news, scraping, PDFs, verification & more',
232
- auth: 'api_key',
233
- docs: 'https://apilayer.com',
234
- actions: {
235
- exchange_rates: {
236
- desc: 'Get live or historical currency exchange rates',
237
- params: [
238
- { name: 'base', required: false, desc: 'Base currency (default: USD)' },
239
- { name: 'symbols', required: false, desc: 'Comma-separated target currencies' },
240
- { name: 'date', required: false, desc: 'Historical date YYYY-MM-DD (omit for live)' },
241
- ],
242
- },
243
- market_data: {
244
- desc: 'End-of-day stock market data',
245
- params: [
246
- { name: 'symbols', required: true, desc: 'Stock ticker(s), comma-separated e.g. AAPL,MSFT' },
247
- { name: 'date_from', required: false, desc: 'Start date YYYY-MM-DD' },
248
- { name: 'date_to', required: false, desc: 'End date YYYY-MM-DD' },
249
- ],
250
- },
251
- aviation: {
252
- desc: 'Real-time flight data and tracking',
253
- params: [
254
- { name: 'flight_iata', required: false, desc: 'IATA flight number e.g. AA100' },
255
- { name: 'dep_iata', required: false, desc: 'Departure airport IATA code' },
256
- { name: 'arr_iata', required: false, desc: 'Arrival airport IATA code' },
257
- ],
258
- },
259
- pdf_generate: {
260
- desc: 'Generate PDF from URL or HTML',
261
- params: [
262
- { name: 'document_url', required: false, desc: 'URL to convert to PDF' },
263
- { name: 'document_html', required: false, desc: 'HTML string to convert (alternative to URL)' },
264
- { name: 'page_size', required: false, desc: 'Page size: A4, Letter, etc (default: A4)' },
265
- ],
266
- },
267
- screenshot: {
268
- desc: 'Capture full-page screenshot of any URL',
269
- params: [
270
- { name: 'url', required: true, desc: 'URL to screenshot' },
271
- { name: 'viewport', required: false, desc: 'Viewport size e.g. 1440x900 (default)' },
272
- { name: 'fullpage', required: false, desc: '1 for full page, 0 for viewport only (default: 0)' },
273
- ],
274
- },
275
- verify_email: {
276
- desc: 'Validate email address format and deliverability',
277
- params: [
278
- { name: 'email', required: true, desc: 'Email address to verify' },
279
- ],
280
- },
281
- verify_number: {
282
- desc: 'Validate and lookup phone number details',
283
- params: [
284
- { name: 'number', required: true, desc: 'Phone number in E.164 format e.g. +46701234567' },
285
- ],
286
- },
287
- vat_check: {
288
- desc: 'Validate EU VAT number',
289
- params: [
290
- { name: 'vat_number', required: true, desc: 'EU VAT number e.g. SE556012345601' },
291
- ],
292
- },
293
- world_news: {
294
- desc: 'Extract and analyze news articles from a URL',
295
- params: [
296
- { name: 'url', required: true, desc: 'URL of the news article to analyze' },
297
- { name: 'analyze', required: false, desc: 'Whether to analyze the news (default: true)' },
298
- ],
299
- },
300
- finance_news: {
301
- desc: 'Latest financial and stock market news',
302
- params: [
303
- { name: 'tickers', required: false, desc: 'Stock tickers comma-separated e.g. AAPL,TSLA' },
304
- { name: 'text', required: false, desc: 'Keyword filter' },
305
- { name: 'number', required: false, desc: 'Number of results (default: 5)' },
306
- ],
307
- },
308
- scrape: {
309
- desc: 'Advanced web scraper — returns clean page content',
310
- params: [
311
- { name: 'url', required: true, desc: 'URL to scrape' },
312
- ],
313
- },
314
- image_crop: {
315
- desc: 'Smart crop an image to specified dimensions',
316
- params: [
317
- { name: 'url', required: true, desc: 'Image URL to crop' },
318
- { name: 'width', required: false, desc: 'Target width in pixels' },
319
- { name: 'height', required: false, desc: 'Target height in pixels' },
320
- ],
321
- },
322
- skills: {
323
- desc: 'Search 7000+ professional skills database',
324
- params: [
325
- { name: 'q', required: true, desc: 'Skill search query e.g. "machine learning"' },
326
- { name: 'count', required: false, desc: 'Number of results (default: 10)' },
327
- ],
328
- },
329
- form_submit: {
330
- desc: 'Submit form data to a FormAPI endpoint',
331
- params: [
332
- { name: 'endpoint', required: true, desc: 'FormAPI endpoint path' },
333
- { name: 'data', required: false, desc: 'Form data object to submit' },
334
- ],
335
- },
336
- },
337
- },
338
- };
339
-
340
- /**
341
- * Discover APIs based on a natural language query
342
- * MVP uses keyword matching; production would use embeddings
343
- */
344
- export function discoverAPIs(
345
- query: string,
346
- options: {
347
- category?: string;
348
- maxResults?: number;
349
- maxPrice?: number;
350
- region?: string;
351
- } = {}
352
- ): SearchResult[] {
353
- const { category, maxResults = 5, maxPrice, region } = options;
354
-
355
- const queryLower = query.toLowerCase();
356
- const queryWords = queryLower.split(/\s+/).filter(w => w.length > 2);
357
-
358
- const results: SearchResult[] = [];
359
-
360
- for (const api of apis) {
361
- // Category filter
362
- if (category && api.category !== category) continue;
363
-
364
- // Region filter
365
- if (region && api.regions && !api.regions.includes(region) && !api.regions.includes('global')) continue;
366
-
367
- // Calculate relevance score
368
- let score = 0;
369
- const matchReasons: string[] = [];
370
-
371
- // Check keywords
372
- for (const word of queryWords) {
373
- // Direct keyword match
374
- if (api.keywords?.some(k => k.includes(word))) {
375
- score += 10;
376
- matchReasons.push(`keyword: ${word}`);
377
- }
378
-
379
- // Capability match
380
- if (api.capabilities?.some(c => c.includes(word))) {
381
- score += 15;
382
- matchReasons.push(`capability: ${word}`);
383
- }
384
-
385
- // Name match
386
- if (api.name.toLowerCase().includes(word)) {
387
- score += 20;
388
- matchReasons.push(`name: ${word}`);
389
- }
390
-
391
- // Description match
392
- if (api.description.toLowerCase().includes(word)) {
393
- score += 5;
394
- matchReasons.push(`description: ${word}`);
395
- }
396
-
397
- // Feature match
398
- if (api.features?.some(f => f.toLowerCase().includes(word))) {
399
- score += 8;
400
- matchReasons.push(`feature: ${word}`);
401
- }
402
- }
403
-
404
- // Boost for high success rate (default to 0.8 if not set)
405
- score += (api.agent_success_rate ?? 0.8) * 10;
406
-
407
- // Boost for low latency (default to 500ms if not set)
408
- score += Math.max(0, (1000 - (api.avg_latency_ms ?? 500)) / 100);
409
-
410
- // Boost for free tier
411
- if (api.pricing?.free_tier) {
412
- score += 5;
413
- matchReasons.push('has free tier');
414
- }
415
-
416
- if (score > 0) {
417
- results.push({
418
- provider: api,
419
- relevance_score: Math.round(score * 100) / 100,
420
- match_reasons: [...new Set(matchReasons)]
421
- });
422
- }
423
- }
424
-
425
- // Sort by relevance
426
- results.sort((a, b) => b.relevance_score - a.relevance_score);
427
-
428
- return results.slice(0, maxResults);
429
- }
430
-
431
- /**
432
- * Get detailed information about a specific API
433
- * @param apiId - The API provider ID
434
- * @param options.compact - If true, returns minified spec (saves ~60% tokens)
435
- */
436
- export function getAPIDetails(
437
- apiId: string,
438
- options: { compact?: boolean } = {}
439
- ): APIDetailsResponse | null {
440
- const { compact = false } = options;
441
-
442
- // Check if it's a Direct Call provider (hardcoded handlers)
443
- const directSpec = DIRECT_CALL_SPECS[apiId];
444
- if (directSpec) {
445
- if (compact) {
446
- // Minified format: ~60% smaller
447
- return {
448
- id: apiId,
449
- type: 'direct_call',
450
- desc: directSpec.description,
451
- auth: directSpec.auth,
452
- actions: Object.fromEntries(
453
- Object.entries(directSpec.actions).map(([action, info]) => [
454
- action,
455
- {
456
- params: info.params.map(p =>
457
- p.required ? p.name : `${p.name}?`
458
- ),
459
- },
460
- ])
461
- ),
462
- } as APIDetailsResponse;
463
- }
464
-
465
- return {
466
- id: apiId,
467
- type: 'direct_call',
468
- name: apiId,
469
- description: directSpec.description,
470
- auth_type: directSpec.auth,
471
- docs_url: directSpec.docs,
472
- direct_call: true,
473
- actions: Object.fromEntries(
474
- Object.entries(directSpec.actions).map(([action, info]) => [
475
- action,
476
- {
477
- description: info.desc,
478
- params: info.params,
479
- },
480
- ])
481
- ),
482
- } as APIDetailsResponse;
483
- }
484
-
485
- // Check if it's an Open API (free, no auth)
486
- if (isOpenAPI(apiId)) {
487
- const openApi = openAPIs[apiId];
488
- const actions = Object.keys(openApi.actions);
489
-
490
- if (compact) {
491
- return {
492
- id: apiId,
493
- type: 'open',
494
- desc: openApi.description,
495
- auth: 'none',
496
- actions: Object.fromEntries(
497
- actions.map(a => [a, { params: [] }])
498
- ),
499
- } as APIDetailsResponse;
500
- }
501
-
502
- return {
503
- id: apiId,
504
- type: 'open',
505
- name: openApi.name,
506
- description: openApi.description,
507
- auth_type: 'none',
508
- free: true,
509
- actions: Object.fromEntries(
510
- actions.map(a => [a, { description: `Execute ${a}`, params: [] }])
511
- ),
512
- } as APIDetailsResponse;
513
- }
514
-
515
- // Fall back to registry (19,000+ APIs - basic info only)
516
- const registryApi = apis.find(api =>
517
- api.id === apiId ||
518
- api.name?.toLowerCase() === apiId.toLowerCase()
519
- );
520
-
521
- if (!registryApi) {
522
- return null;
523
- }
524
-
525
- if (compact) {
526
- return {
527
- id: registryApi.id || registryApi.name,
528
- type: 'registry',
529
- desc: registryApi.description?.slice(0, 80),
530
- auth: registryApi.auth_type || (registryApi as any).auth || 'unknown',
531
- url: registryApi.base_url || (registryApi as any).baseUrl,
532
- } as APIDetailsResponse;
533
- }
534
-
535
- return {
536
- id: registryApi.id || registryApi.name,
537
- type: 'registry',
538
- name: registryApi.name,
539
- description: registryApi.description,
540
- category: registryApi.category,
541
- auth_type: registryApi.auth_type || (registryApi as any).auth,
542
- base_url: registryApi.base_url || (registryApi as any).baseUrl,
543
- docs_url: registryApi.docs_url || (registryApi as any).docsUrl,
544
- pricing: registryApi.pricing || (registryApi as any).pricing,
545
- note: 'Registry API - use call_api with customer_key or check docs for integration',
546
- } as APIDetailsResponse;
547
- }
548
-
549
- /**
550
- * List all APIs in a category
551
- */
552
- export function listByCategory(category: string): APIProvider[] {
553
- return apis.filter(api => api.category === category);
554
- }
555
-
556
- /**
557
- * Get all available categories
558
- */
559
- export function getCategories(): string[] {
560
- return [...new Set(apis.map(api => api.category))];
561
- }
562
-
563
- /**
564
- * Get all APIs
565
- */
566
- export function getAllAPIs(): APIProvider[] {
567
- return apis;
568
- }