@nordsym/apiclaw 1.5.18 → 1.6.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 (141) hide show
  1. package/CODEBASE.md +42 -0
  2. package/CONCEPT.md +9 -0
  3. package/DASHBOARD_FIX.md +9 -0
  4. package/EARN-CREDITS-SPEC.md +9 -0
  5. package/HIVR-INTEGRATION.md +9 -0
  6. package/HTTP-API.md +9 -0
  7. package/PRD-ANALYTICS-AGENTS-TEAMS.md +9 -0
  8. package/PRD-API-CHAINING.md +9 -0
  9. package/PRD-HARDEN-SHELL.md +9 -0
  10. package/PRD-LOGS-SUBAGENTS-V2.md +9 -0
  11. package/VISION.md +9 -0
  12. package/{AGENTS.md → apiclaw-AGENTS.md} +9 -0
  13. package/{CHANGELOG.md → apiclaw-CHANGELOG.md} +31 -0
  14. package/{CONTRIBUTING.md → apiclaw-CONTRIBUTING.md} +9 -0
  15. package/{HEARTBEAT.md → apiclaw-HEARTBEAT.md} +9 -0
  16. package/{IDENTITY.md → apiclaw-IDENTITY.md} +9 -0
  17. package/{README.md → apiclaw-README.md} +9 -0
  18. package/{SOUL.md → apiclaw-SOUL.md} +9 -0
  19. package/{TOOLS.md → apiclaw-TOOLS.md} +9 -0
  20. package/{USER.md → apiclaw-USER.md} +9 -0
  21. package/convex/_generated/api.d.ts +2 -0
  22. package/convex/{README.md → apiclaw-convex-README.md} +9 -0
  23. package/convex/http.ts +315 -0
  24. package/convex/seedPratham.ts +161 -0
  25. package/dist/credentials.d.ts.map +1 -1
  26. package/dist/credentials.js +136 -2
  27. package/dist/credentials.js.map +1 -1
  28. package/dist/execute.d.ts.map +1 -1
  29. package/dist/execute.js +289 -1
  30. package/dist/execute.js.map +1 -1
  31. package/docs/PRD-BILLING.md +9 -0
  32. package/docs/PRD-EARN-SYSTEM.md +9 -0
  33. package/docs/PRD-MCP-AUTO-SETUP.md +9 -0
  34. package/docs/PRD-ORGANIC-DISTRIBUTION.md +9 -0
  35. package/docs/PRD-agent-first-billing.md +9 -0
  36. package/docs/PRD-customer-key-passthrough.md +9 -0
  37. package/docs/PRD-final-polish.md +9 -0
  38. package/docs/PRD-mobile-responsive.md +9 -0
  39. package/docs/PRD-navigation-expansion.md +9 -0
  40. package/docs/PRD-stripe-billing.md +9 -0
  41. package/docs/PRD-workspace-cleanup.md +9 -0
  42. package/docs/PRD-workspace-fixes.md +9 -0
  43. package/docs/SUBAGENT-NAMING.md +9 -0
  44. package/docs/enterprise-deployment.md +6 -0
  45. package/email-templates/{README.md → email-templates-README.md} +9 -0
  46. package/landing/DESIGN.md +9 -0
  47. package/package.json +2 -2
  48. package/scripts/SYMBOT-FIX.md +9 -0
  49. package/src/credentials.ts +150 -2
  50. package/src/execute.ts +306 -1
  51. package/test-legacy-apis.sh +51 -0
  52. package/convex/adminActivate.d.ts +0 -3
  53. package/convex/adminActivate.js +0 -47
  54. package/convex/adminActivate.js.map +0 -1
  55. package/convex/adminStats.d.ts +0 -3
  56. package/convex/adminStats.js +0 -42
  57. package/convex/adminStats.js.map +0 -1
  58. package/convex/agents.d.ts +0 -54
  59. package/convex/agents.js +0 -499
  60. package/convex/agents.js.map +0 -1
  61. package/convex/analytics.d.ts +0 -5
  62. package/convex/analytics.js +0 -166
  63. package/convex/analytics.js.map +0 -1
  64. package/convex/billing.d.ts +0 -88
  65. package/convex/billing.js +0 -655
  66. package/convex/billing.js.map +0 -1
  67. package/convex/capabilities.d.ts +0 -9
  68. package/convex/capabilities.js +0 -145
  69. package/convex/capabilities.js.map +0 -1
  70. package/convex/chains.d.ts +0 -67
  71. package/convex/chains.js +0 -1042
  72. package/convex/chains.js.map +0 -1
  73. package/convex/credits.d.ts +0 -25
  74. package/convex/credits.js +0 -186
  75. package/convex/credits.js.map +0 -1
  76. package/convex/crons.d.ts +0 -3
  77. package/convex/crons.js +0 -17
  78. package/convex/crons.js.map +0 -1
  79. package/convex/directCall.d.ts +0 -72
  80. package/convex/directCall.js +0 -627
  81. package/convex/directCall.js.map +0 -1
  82. package/convex/earnProgress.d.ts +0 -58
  83. package/convex/earnProgress.js +0 -649
  84. package/convex/earnProgress.js.map +0 -1
  85. package/convex/email.d.ts +0 -14
  86. package/convex/email.js +0 -300
  87. package/convex/email.js.map +0 -1
  88. package/convex/feedback.d.ts +0 -7
  89. package/convex/feedback.js +0 -227
  90. package/convex/feedback.js.map +0 -1
  91. package/convex/http.d.ts +0 -3
  92. package/convex/http.js +0 -1106
  93. package/convex/http.js.map +0 -1
  94. package/convex/http.ts.bak +0 -934
  95. package/convex/logs.d.ts +0 -38
  96. package/convex/logs.js +0 -487
  97. package/convex/logs.js.map +0 -1
  98. package/convex/mou.d.ts +0 -6
  99. package/convex/mou.js +0 -82
  100. package/convex/mou.js.map +0 -1
  101. package/convex/providerKeys.d.ts +0 -31
  102. package/convex/providerKeys.js +0 -257
  103. package/convex/providerKeys.js.map +0 -1
  104. package/convex/providers.d.ts +0 -29
  105. package/convex/providers.js +0 -756
  106. package/convex/providers.js.map +0 -1
  107. package/convex/purchases.d.ts +0 -7
  108. package/convex/purchases.js +0 -157
  109. package/convex/purchases.js.map +0 -1
  110. package/convex/ratelimit.d.ts +0 -4
  111. package/convex/ratelimit.js +0 -91
  112. package/convex/ratelimit.js.map +0 -1
  113. package/convex/searchLogs.d.ts +0 -4
  114. package/convex/searchLogs.js +0 -129
  115. package/convex/searchLogs.js.map +0 -1
  116. package/convex/spendAlerts.d.ts +0 -36
  117. package/convex/spendAlerts.js +0 -380
  118. package/convex/spendAlerts.js.map +0 -1
  119. package/convex/stripeActions.d.ts +0 -19
  120. package/convex/stripeActions.js +0 -411
  121. package/convex/stripeActions.js.map +0 -1
  122. package/convex/teams.d.ts +0 -21
  123. package/convex/teams.js +0 -215
  124. package/convex/teams.js.map +0 -1
  125. package/convex/telemetry.d.ts +0 -4
  126. package/convex/telemetry.js +0 -74
  127. package/convex/telemetry.js.map +0 -1
  128. package/convex/usage.d.ts +0 -27
  129. package/convex/usage.js +0 -229
  130. package/convex/usage.js.map +0 -1
  131. package/convex/waitlist.d.ts +0 -4
  132. package/convex/waitlist.js +0 -49
  133. package/convex/waitlist.js.map +0 -1
  134. package/convex/webhooks.d.ts +0 -12
  135. package/convex/webhooks.js +0 -410
  136. package/convex/webhooks.js.map +0 -1
  137. package/convex/workspaces.d.ts +0 -29
  138. package/convex/workspaces.js +0 -880
  139. package/convex/workspaces.js.map +0 -1
  140. package/dist/registry/apis.json.bak +0 -248811
  141. package/src/registry/apis.json.bak +0 -248811
@@ -1,3 +1,9 @@
1
+ ---
2
+ nord_type: ENGINE
3
+ nord_owner: APIClaw
4
+ nord_status: LIVE
5
+ ---
6
+
1
7
  # Symbot/Clawdbot Fix — Message History Sanitizer
2
8
 
3
9
  **Problem:** `unexpected tool_use_id found in tool_result blocks: toolu_012ogrVbszMVvQZF6Jpcbvar`
@@ -236,3 +242,6 @@ Om problem kvarstår:
236
242
 
237
243
  *Created: 2026-02-21*
238
244
  *Status: TESTED ✅*
245
+
246
+ ---
247
+ *[[03 - Products/Apiclaw/Apiclaw|APIClaw]] · [[MOC|Production Line]]*
@@ -172,17 +172,127 @@ const providers: Record<string, ProviderCredential> = {
172
172
  type: 'api_key',
173
173
  get(): APICredentials | null {
174
174
  const env = loadEnvFile('apilayer.env');
175
- // Return all keys — handler picks the right one per action
175
+ const legacy = loadEnvFile('apilayer-legacy.env');
176
+
177
+ // Merge unified + legacy keys
176
178
  const keys: Record<string, string> = {};
179
+
180
+ // Unified APILayer keys (APILAYER_*)
177
181
  for (const [k, v] of Object.entries(env)) {
178
182
  if (k.startsWith('APILAYER_') && v) {
179
183
  keys[k] = v;
180
184
  }
181
185
  }
186
+
187
+ // Legacy keys (separate API domains)
188
+ for (const [k, v] of Object.entries(legacy)) {
189
+ if (v && k.endsWith('_API_KEY')) {
190
+ keys[k] = v;
191
+ }
192
+ }
193
+
182
194
  if (Object.keys(keys).length === 0) return null;
183
195
  return { type: 'api_key', api_key: keys.APILAYER_EXCHANGERATE_KEY || '', ...keys } as any;
184
196
  },
185
197
  },
198
+
199
+ groq: {
200
+ type: 'bearer',
201
+ get(): APICredentials | null {
202
+ const env = loadEnvFile('groq.env');
203
+ const key = env.GROQ_API_KEY || process.env.GROQ_API_KEY;
204
+ if (key) {
205
+ return { type: 'bearer', api_key: key };
206
+ }
207
+ return null;
208
+ },
209
+ },
210
+
211
+ mistral: {
212
+ type: 'bearer',
213
+ get(): APICredentials | null {
214
+ const env = loadEnvFile('mistral.env');
215
+ const key = env.MISTRAL_API_KEY || process.env.MISTRAL_API_KEY;
216
+ if (key) {
217
+ return { type: 'bearer', api_key: key };
218
+ }
219
+ return null;
220
+ },
221
+ },
222
+
223
+ cohere: {
224
+ type: 'bearer',
225
+ get(): APICredentials | null {
226
+ const env = loadEnvFile('cohere.env');
227
+ const key = env.COHERE_API_KEY || process.env.COHERE_API_KEY;
228
+ if (key) {
229
+ return { type: 'bearer', api_key: key };
230
+ }
231
+ return null;
232
+ },
233
+ },
234
+
235
+ together: {
236
+ type: 'bearer',
237
+ get(): APICredentials | null {
238
+ const env = loadEnvFile('together.env');
239
+ const key = env.TOGETHER_API_KEY || process.env.TOGETHER_API_KEY;
240
+ if (key) {
241
+ return { type: 'bearer', api_key: key };
242
+ }
243
+ return null;
244
+ },
245
+ },
246
+
247
+ stability: {
248
+ type: 'api_key',
249
+ get(): APICredentials | null {
250
+ const env = loadEnvFile('stability.env');
251
+ const key = env.STABILITY_API_KEY || process.env.STABILITY_API_KEY;
252
+ if (key) {
253
+ return { type: 'api_key', api_key: key };
254
+ }
255
+ return null;
256
+ },
257
+ },
258
+
259
+ deepgram: {
260
+ type: 'api_key',
261
+ get(): APICredentials | null {
262
+ const env = loadEnvFile('deepgram.env');
263
+ const key = env.DEEPGRAM_API_KEY || process.env.DEEPGRAM_API_KEY;
264
+ if (key) {
265
+ return { type: 'api_key', api_key: key };
266
+ }
267
+ return null;
268
+ },
269
+ },
270
+
271
+ assemblyai: {
272
+ type: 'api_key',
273
+ get(): APICredentials | null {
274
+ const env = loadEnvFile('assemblyai.env');
275
+ const key = env.ASSEMBLYAI_API_KEY || process.env.ASSEMBLYAI_API_KEY;
276
+ if (key) {
277
+ return { type: 'api_key', api_key: key };
278
+ }
279
+ return null;
280
+ },
281
+ },
282
+
283
+ serper: {
284
+ type: 'api_key',
285
+ get(): APICredentials | null {
286
+ // Note: local file is serpapi.env for historical reasons
287
+ const env = loadEnvFile('serper.env');
288
+ const envAlt = loadEnvFile('serpapi.env');
289
+ const key = env.SERPER_API_KEY || envAlt.SERPAPI_API_KEY || envAlt.SERPER_API_KEY || process.env.SERPER_API_KEY;
290
+ if (key) {
291
+ return { type: 'api_key', api_key: key };
292
+ }
293
+ return null;
294
+ },
295
+ },
186
296
  };
187
297
 
188
298
  /**
@@ -233,7 +343,45 @@ export function hasRealCredentials(providerId: string): boolean {
233
343
  }
234
344
  if (providerId === 'apilayer') {
235
345
  const env = loadEnvFile('apilayer.env');
236
- return !!(env.APILAYER_EXCHANGERATE_KEY || process.env.APILAYER_EXCHANGERATE_KEY);
346
+ const legacy = loadEnvFile('apilayer-legacy.env');
347
+ return !!(
348
+ env.APILAYER_EXCHANGERATE_KEY ||
349
+ process.env.APILAYER_EXCHANGERATE_KEY ||
350
+ Object.keys(legacy).length > 0
351
+ );
352
+ }
353
+ if (providerId === 'groq') {
354
+ const env = loadEnvFile('groq.env');
355
+ return !!(env.GROQ_API_KEY || process.env.GROQ_API_KEY);
356
+ }
357
+ if (providerId === 'mistral') {
358
+ const env = loadEnvFile('mistral.env');
359
+ return !!(env.MISTRAL_API_KEY || process.env.MISTRAL_API_KEY);
360
+ }
361
+ if (providerId === 'cohere') {
362
+ const env = loadEnvFile('cohere.env');
363
+ return !!(env.COHERE_API_KEY || process.env.COHERE_API_KEY);
364
+ }
365
+ if (providerId === 'together') {
366
+ const env = loadEnvFile('together.env');
367
+ return !!(env.TOGETHER_API_KEY || process.env.TOGETHER_API_KEY);
368
+ }
369
+ if (providerId === 'stability') {
370
+ const env = loadEnvFile('stability.env');
371
+ return !!(env.STABILITY_API_KEY || process.env.STABILITY_API_KEY);
372
+ }
373
+ if (providerId === 'deepgram') {
374
+ const env = loadEnvFile('deepgram.env');
375
+ return !!(env.DEEPGRAM_API_KEY || process.env.DEEPGRAM_API_KEY);
376
+ }
377
+ if (providerId === 'assemblyai') {
378
+ const env = loadEnvFile('assemblyai.env');
379
+ return !!(env.ASSEMBLYAI_API_KEY || process.env.ASSEMBLYAI_API_KEY);
380
+ }
381
+ if (providerId === 'serper') {
382
+ const env = loadEnvFile('serper.env');
383
+ const envAlt = loadEnvFile('serpapi.env');
384
+ return !!(env.SERPER_API_KEY || envAlt.SERPAPI_API_KEY || envAlt.SERPER_API_KEY || process.env.SERPER_API_KEY);
237
385
  }
238
386
  return false;
239
387
  }
package/src/execute.ts CHANGED
@@ -403,6 +403,7 @@ const apiEndpoints: Record<string, Record<string, { url: string; method: string;
403
403
  run_shell: { url: 'https://api.e2b.dev/v1/sandboxes', method: 'POST' },
404
404
  },
405
405
  apilayer: {
406
+ // Unified APILayer APIs (apilayer.com)
406
407
  exchange_rates: { url: 'https://api.apilayer.com/exchangerates_data/latest', method: 'GET' },
407
408
  market_data: { url: 'http://api.marketstack.com/v1/eod', method: 'GET' },
408
409
  aviation: { url: 'http://api.aviationstack.com/v1/flights', method: 'GET' },
@@ -417,6 +418,34 @@ const apiEndpoints: Record<string, Record<string, { url: string; method: string;
417
418
  image_crop: { url: 'https://api.apilayer.com/smart_crop/url', method: 'POST' },
418
419
  skills: { url: 'https://api.promptapi.com/skills', method: 'GET' },
419
420
  form_submit: { url: 'https://api.apilayer.com/form_api/{endpoint}', method: 'POST' },
421
+
422
+ // Legacy APIs (separate domains, each with own key)
423
+ // FINANCE
424
+ fixer_convert: { url: 'http://data.fixer.io/api/convert', method: 'GET' },
425
+ fixer_latest: { url: 'http://data.fixer.io/api/latest', method: 'GET' },
426
+ currencylayer_live: { url: 'http://api.currencylayer.com/live', method: 'GET' },
427
+ currencylayer_convert: { url: 'http://api.currencylayer.com/convert', method: 'GET' },
428
+ coinlayer_live: { url: 'http://api.coinlayer.com/live', method: 'GET' },
429
+ exchangeratehost_latest: { url: 'https://api.exchangerate.host/latest', method: 'GET' },
430
+
431
+ // GEOLOCATION
432
+ weatherstack_current: { url: 'http://api.weatherstack.com/current', method: 'GET' },
433
+ weatherstack_forecast: { url: 'http://api.weatherstack.com/forecast', method: 'GET' },
434
+ ipstack_lookup: { url: 'http://api.ipstack.com/{ip}', method: 'GET' },
435
+ ipapi_lookup: { url: 'https://ipapi.co/{ip}/json/', method: 'GET' },
436
+ positionstack_forward: { url: 'http://api.positionstack.com/v1/forward', method: 'GET' },
437
+ positionstack_reverse: { url: 'http://api.positionstack.com/v1/reverse', method: 'GET' },
438
+ languagelayer_detect: { url: 'https://api.languagelayer.com/detect', method: 'POST' },
439
+
440
+ // SCRAPING
441
+ scrapestack_scrape: { url: 'http://api.scrapestack.com/scrape', method: 'GET' },
442
+ serpstack_search: { url: 'http://api.serpstack.com/search', method: 'GET' },
443
+
444
+ // NEWS
445
+ mediastack_news: { url: 'http://api.mediastack.com/v1/news', method: 'GET' },
446
+
447
+ // DEVTOOLS
448
+ userstack_detect: { url: 'http://api.userstack.com/detect', method: 'GET' },
420
449
  },
421
450
  };
422
451
 
@@ -1912,11 +1941,287 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
1912
1941
  'Content-Type': 'application/json',
1913
1942
  },
1914
1943
  body: JSON.stringify(formData || {}),
1915
- }, { provider: 'apilayer', action: 'form_submit' });
1944
+ }, { provider: 'apilayer', 'action': 'form_submit' });
1916
1945
  const data = await response.json() as Record<string, unknown>;
1917
1946
  if (!response.ok) return createErrorResult('apilayer', 'form_submit', 'Request failed', statusToErrorCode(response.status));
1918
1947
  return { success: true, provider: 'apilayer', action: 'form_submit', data };
1919
1948
  },
1949
+
1950
+ // ========== LEGACY APIs (separate domains, each with own key) ==========
1951
+
1952
+ // FINANCE
1953
+ fixer_convert: async (params, creds) => {
1954
+ const key = creds.FIXER_API_KEY || creds.api_key;
1955
+ const { from, to, amount, date } = params;
1956
+ if (!from || !to || !amount) return createErrorResult('apilayer', 'fixer_convert', 'Missing required params: from, to, amount', ERROR_CODES.INVALID_PARAMS);
1957
+
1958
+ const url = new URL('http://data.fixer.io/api/convert');
1959
+ url.searchParams.set('access_key', key);
1960
+ url.searchParams.set('from', from);
1961
+ url.searchParams.set('to', to);
1962
+ url.searchParams.set('amount', amount.toString());
1963
+ if (date) url.searchParams.set('date', date);
1964
+
1965
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'fixer_convert' });
1966
+ const data = await response.json() as Record<string, unknown>;
1967
+ if (!response.ok) return createErrorResult('apilayer', 'fixer_convert', 'Request failed', statusToErrorCode(response.status));
1968
+ return { success: true, provider: 'apilayer', action: 'fixer_convert', data };
1969
+ },
1970
+
1971
+ fixer_latest: async (params, creds) => {
1972
+ const key = creds.FIXER_API_KEY || creds.api_key;
1973
+ const { base = 'EUR', symbols } = params;
1974
+
1975
+ const url = new URL('http://data.fixer.io/api/latest');
1976
+ url.searchParams.set('access_key', key);
1977
+ url.searchParams.set('base', base);
1978
+ if (symbols) url.searchParams.set('symbols', symbols);
1979
+
1980
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'fixer_latest' });
1981
+ const data = await response.json() as Record<string, unknown>;
1982
+ if (!response.ok) return createErrorResult('apilayer', 'fixer_latest', 'Request failed', statusToErrorCode(response.status));
1983
+ return { success: true, provider: 'apilayer', action: 'fixer_latest', data };
1984
+ },
1985
+
1986
+ currencylayer_live: async (params, creds) => {
1987
+ const key = creds.CURRENCYLAYER_API_KEY || creds.api_key;
1988
+ const { currencies, source = 'USD' } = params;
1989
+
1990
+ const url = new URL('http://api.currencylayer.com/live');
1991
+ url.searchParams.set('access_key', key);
1992
+ url.searchParams.set('source', source);
1993
+ if (currencies) url.searchParams.set('currencies', currencies);
1994
+
1995
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'currencylayer_live' });
1996
+ const data = await response.json() as Record<string, unknown>;
1997
+ if (!response.ok) return createErrorResult('apilayer', 'currencylayer_live', 'Request failed', statusToErrorCode(response.status));
1998
+ return { success: true, provider: 'apilayer', action: 'currencylayer_live', data };
1999
+ },
2000
+
2001
+ currencylayer_convert: async (params, creds) => {
2002
+ const key = creds.CURRENCYLAYER_API_KEY || creds.api_key;
2003
+ const { from, to, amount, date } = params;
2004
+ if (!from || !to || !amount) return createErrorResult('apilayer', 'currencylayer_convert', 'Missing required params: from, to, amount', ERROR_CODES.INVALID_PARAMS);
2005
+
2006
+ const url = new URL('http://api.currencylayer.com/convert');
2007
+ url.searchParams.set('access_key', key);
2008
+ url.searchParams.set('from', from);
2009
+ url.searchParams.set('to', to);
2010
+ url.searchParams.set('amount', amount.toString());
2011
+ if (date) url.searchParams.set('date', date);
2012
+
2013
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'currencylayer_convert' });
2014
+ const data = await response.json() as Record<string, unknown>;
2015
+ if (!response.ok) return createErrorResult('apilayer', 'currencylayer_convert', 'Request failed', statusToErrorCode(response.status));
2016
+ return { success: true, provider: 'apilayer', action: 'currencylayer_convert', data };
2017
+ },
2018
+
2019
+ coinlayer_live: async (params, creds) => {
2020
+ const key = creds.COINLAYER_API_KEY || creds.api_key;
2021
+ const { symbols, target = 'USD' } = params;
2022
+
2023
+ const url = new URL('http://api.coinlayer.com/live');
2024
+ url.searchParams.set('access_key', key);
2025
+ url.searchParams.set('target', target);
2026
+ if (symbols) url.searchParams.set('symbols', symbols);
2027
+
2028
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'coinlayer_live' });
2029
+ const data = await response.json() as Record<string, unknown>;
2030
+ if (!response.ok) return createErrorResult('apilayer', 'coinlayer_live', 'Request failed', statusToErrorCode(response.status));
2031
+ return { success: true, provider: 'apilayer', action: 'coinlayer_live', data };
2032
+ },
2033
+
2034
+ exchangeratehost_latest: async (params, creds) => {
2035
+ const key = creds.EXCHANGERATEHOST_API_KEY || creds.api_key;
2036
+ const { base = 'EUR', symbols } = params;
2037
+
2038
+ const url = new URL('https://api.exchangerate.host/latest');
2039
+ url.searchParams.set('access_key', key);
2040
+ url.searchParams.set('base', base);
2041
+ if (symbols) url.searchParams.set('symbols', symbols);
2042
+
2043
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'exchangeratehost_latest' });
2044
+ const data = await response.json() as Record<string, unknown>;
2045
+ if (!response.ok) return createErrorResult('apilayer', 'exchangeratehost_latest', 'Request failed', statusToErrorCode(response.status));
2046
+ return { success: true, provider: 'apilayer', action: 'exchangeratehost_latest', data };
2047
+ },
2048
+
2049
+ // GEOLOCATION
2050
+ weatherstack_current: async (params, creds) => {
2051
+ const key = creds.WEATHERSTACK_API_KEY || creds.api_key;
2052
+ const { query, units = 'm' } = params;
2053
+ if (!query) return createErrorResult('apilayer', 'weatherstack_current', 'Missing required param: query (city name or coordinates)', ERROR_CODES.INVALID_PARAMS);
2054
+
2055
+ const url = new URL('http://api.weatherstack.com/current');
2056
+ url.searchParams.set('access_key', key);
2057
+ url.searchParams.set('query', query);
2058
+ url.searchParams.set('units', units);
2059
+
2060
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'weatherstack_current' });
2061
+ const data = await response.json() as Record<string, unknown>;
2062
+ if (!response.ok) return createErrorResult('apilayer', 'weatherstack_current', 'Request failed', statusToErrorCode(response.status));
2063
+ return { success: true, provider: 'apilayer', action: 'weatherstack_current', data };
2064
+ },
2065
+
2066
+ weatherstack_forecast: async (params, creds) => {
2067
+ const key = creds.WEATHERSTACK_API_KEY || creds.api_key;
2068
+ const { query, forecast_days = 1, units = 'm' } = params;
2069
+ if (!query) return createErrorResult('apilayer', 'weatherstack_forecast', 'Missing required param: query', ERROR_CODES.INVALID_PARAMS);
2070
+
2071
+ const url = new URL('http://api.weatherstack.com/forecast');
2072
+ url.searchParams.set('access_key', key);
2073
+ url.searchParams.set('query', query);
2074
+ url.searchParams.set('forecast_days', forecast_days.toString());
2075
+ url.searchParams.set('units', units);
2076
+
2077
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'weatherstack_forecast' });
2078
+ const data = await response.json() as Record<string, unknown>;
2079
+ if (!response.ok) return createErrorResult('apilayer', 'weatherstack_forecast', 'Request failed', statusToErrorCode(response.status));
2080
+ return { success: true, provider: 'apilayer', action: 'weatherstack_forecast', data };
2081
+ },
2082
+
2083
+ ipstack_lookup: async (params, creds) => {
2084
+ const key = creds.IPSTACK_API_KEY || creds.api_key;
2085
+ const { ip } = params;
2086
+ if (!ip) return createErrorResult('apilayer', 'ipstack_lookup', 'Missing required param: ip', ERROR_CODES.INVALID_PARAMS);
2087
+
2088
+ const url = new URL(`http://api.ipstack.com/${ip}`);
2089
+ url.searchParams.set('access_key', key);
2090
+
2091
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'ipstack_lookup' });
2092
+ const data = await response.json() as Record<string, unknown>;
2093
+ if (!response.ok) return createErrorResult('apilayer', 'ipstack_lookup', 'Request failed', statusToErrorCode(response.status));
2094
+ return { success: true, provider: 'apilayer', action: 'ipstack_lookup', data };
2095
+ },
2096
+
2097
+ ipapi_lookup: async (params, creds) => {
2098
+ const key = creds.IPAPI_API_KEY || creds.api_key;
2099
+ const { ip } = params;
2100
+ if (!ip) return createErrorResult('apilayer', 'ipapi_lookup', 'Missing required param: ip', ERROR_CODES.INVALID_PARAMS);
2101
+
2102
+ const url = `https://ipapi.co/${ip}/json/?key=${key}`;
2103
+
2104
+ const response = await fetchWithRetry(url, {}, { provider: 'apilayer', action: 'ipapi_lookup' });
2105
+ const data = await response.json() as Record<string, unknown>;
2106
+ if (!response.ok) return createErrorResult('apilayer', 'ipapi_lookup', 'Request failed', statusToErrorCode(response.status));
2107
+ return { success: true, provider: 'apilayer', action: 'ipapi_lookup', data };
2108
+ },
2109
+
2110
+ positionstack_forward: async (params, creds) => {
2111
+ const key = creds.POSITIONSTACK_API_KEY || creds.api_key;
2112
+ const { query, limit = 1 } = params;
2113
+ if (!query) return createErrorResult('apilayer', 'positionstack_forward', 'Missing required param: query (address)', ERROR_CODES.INVALID_PARAMS);
2114
+
2115
+ const url = new URL('http://api.positionstack.com/v1/forward');
2116
+ url.searchParams.set('access_key', key);
2117
+ url.searchParams.set('query', query);
2118
+ url.searchParams.set('limit', limit.toString());
2119
+
2120
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'positionstack_forward' });
2121
+ const data = await response.json() as Record<string, unknown>;
2122
+ if (!response.ok) return createErrorResult('apilayer', 'positionstack_forward', 'Request failed', statusToErrorCode(response.status));
2123
+ return { success: true, provider: 'apilayer', action: 'positionstack_forward', data };
2124
+ },
2125
+
2126
+ positionstack_reverse: async (params, creds) => {
2127
+ const key = creds.POSITIONSTACK_API_KEY || creds.api_key;
2128
+ const { query, limit = 1 } = params;
2129
+ if (!query) return createErrorResult('apilayer', 'positionstack_reverse', 'Missing required param: query (lat,lng)', ERROR_CODES.INVALID_PARAMS);
2130
+
2131
+ const url = new URL('http://api.positionstack.com/v1/reverse');
2132
+ url.searchParams.set('access_key', key);
2133
+ url.searchParams.set('query', query);
2134
+ url.searchParams.set('limit', limit.toString());
2135
+
2136
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'positionstack_reverse' });
2137
+ const data = await response.json() as Record<string, unknown>;
2138
+ if (!response.ok) return createErrorResult('apilayer', 'positionstack_reverse', 'Request failed', statusToErrorCode(response.status));
2139
+ return { success: true, provider: 'apilayer', action: 'positionstack_reverse', data };
2140
+ },
2141
+
2142
+ languagelayer_detect: async (params, creds) => {
2143
+ const key = creds.LANGUAGELAYER_API_KEY || creds.api_key;
2144
+ const { query } = params;
2145
+ if (!query) return createErrorResult('apilayer', 'languagelayer_detect', 'Missing required param: query (text to analyze)', ERROR_CODES.INVALID_PARAMS);
2146
+
2147
+ const response = await fetchWithRetry('https://api.languagelayer.com/detect', {
2148
+ method: 'POST',
2149
+ headers: {
2150
+ 'Content-Type': 'application/x-www-form-urlencoded',
2151
+ },
2152
+ body: new URLSearchParams({ access_key: key, query }).toString(),
2153
+ }, { provider: 'apilayer', action: 'languagelayer_detect' });
2154
+ const data = await response.json() as Record<string, unknown>;
2155
+ if (!response.ok) return createErrorResult('apilayer', 'languagelayer_detect', 'Request failed', statusToErrorCode(response.status));
2156
+ return { success: true, provider: 'apilayer', action: 'languagelayer_detect', data };
2157
+ },
2158
+
2159
+ // SCRAPING
2160
+ scrapestack_scrape: async (params, creds) => {
2161
+ const key = creds.SCRAPESTACK_API_KEY || creds.api_key;
2162
+ const { url: targetUrl } = params;
2163
+ if (!targetUrl) return createErrorResult('apilayer', 'scrapestack_scrape', 'Missing required param: url', ERROR_CODES.INVALID_PARAMS);
2164
+
2165
+ const url = new URL('http://api.scrapestack.com/scrape');
2166
+ url.searchParams.set('access_key', key);
2167
+ url.searchParams.set('url', targetUrl);
2168
+
2169
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'scrapestack_scrape' });
2170
+ const data = await response.text();
2171
+ if (!response.ok) return createErrorResult('apilayer', 'scrapestack_scrape', 'Request failed', statusToErrorCode(response.status));
2172
+ return { success: true, provider: 'apilayer', action: 'scrapestack_scrape', data: { html: data } };
2173
+ },
2174
+
2175
+ serpstack_search: async (params, creds) => {
2176
+ const key = creds.SERPSTACK_API_KEY || creds.api_key;
2177
+ const { query, num = 10 } = params;
2178
+ if (!query) return createErrorResult('apilayer', 'serpstack_search', 'Missing required param: query', ERROR_CODES.INVALID_PARAMS);
2179
+
2180
+ const url = new URL('http://api.serpstack.com/search');
2181
+ url.searchParams.set('access_key', key);
2182
+ url.searchParams.set('query', query);
2183
+ url.searchParams.set('num', num.toString());
2184
+
2185
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'serpstack_search' });
2186
+ const data = await response.json() as Record<string, unknown>;
2187
+ if (!response.ok) return createErrorResult('apilayer', 'serpstack_search', 'Request failed', statusToErrorCode(response.status));
2188
+ return { success: true, provider: 'apilayer', action: 'serpstack_search', data };
2189
+ },
2190
+
2191
+ // NEWS
2192
+ mediastack_news: async (params, creds) => {
2193
+ const key = creds.MEDIASTACK_API_KEY || creds.api_key;
2194
+ const { keywords, categories, countries, languages, limit = 25 } = params;
2195
+
2196
+ const url = new URL('http://api.mediastack.com/v1/news');
2197
+ url.searchParams.set('access_key', key);
2198
+ if (keywords) url.searchParams.set('keywords', keywords);
2199
+ if (categories) url.searchParams.set('categories', categories);
2200
+ if (countries) url.searchParams.set('countries', countries);
2201
+ if (languages) url.searchParams.set('languages', languages);
2202
+ url.searchParams.set('limit', limit.toString());
2203
+
2204
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'mediastack_news' });
2205
+ const data = await response.json() as Record<string, unknown>;
2206
+ if (!response.ok) return createErrorResult('apilayer', 'mediastack_news', 'Request failed', statusToErrorCode(response.status));
2207
+ return { success: true, provider: 'apilayer', action: 'mediastack_news', data };
2208
+ },
2209
+
2210
+ // DEVTOOLS
2211
+ userstack_detect: async (params, creds) => {
2212
+ const key = creds.USERSTACK_API_KEY || creds.api_key;
2213
+ const { ua } = params;
2214
+ if (!ua) return createErrorResult('apilayer', 'userstack_detect', 'Missing required param: ua (user agent string)', ERROR_CODES.INVALID_PARAMS);
2215
+
2216
+ const url = new URL('http://api.userstack.com/detect');
2217
+ url.searchParams.set('access_key', key);
2218
+ url.searchParams.set('ua', ua);
2219
+
2220
+ const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'userstack_detect' });
2221
+ const data = await response.json() as Record<string, unknown>;
2222
+ if (!response.ok) return createErrorResult('apilayer', 'userstack_detect', 'Request failed', statusToErrorCode(response.status));
2223
+ return { success: true, provider: 'apilayer', action: 'userstack_detect', data };
2224
+ },
1920
2225
  },
1921
2226
  };
1922
2227
 
@@ -0,0 +1,51 @@
1
+ #!/bin/bash
2
+
3
+ # Test APILayer Legacy APIs
4
+ # Quick smoke test to verify keys work
5
+
6
+ echo "🧪 Testing APILayer Legacy APIs..."
7
+ echo ""
8
+
9
+ # Load keys
10
+ source ~/.secrets/apilayer-legacy.env
11
+
12
+ # Finance
13
+ echo "1. Testing Fixer API..."
14
+ curl -s "http://data.fixer.io/api/latest?access_key=$FIXER_API_KEY&base=USD&symbols=EUR" | jq -r '.success' 2>/dev/null && echo " ✓ Fixer working" || echo " ✗ Fixer failed"
15
+
16
+ echo "2. Testing Currencylayer..."
17
+ curl -s "http://api.currencylayer.com/live?access_key=$CURRENCYLAYER_API_KEY&source=USD&currencies=EUR" | jq -r '.success' 2>/dev/null && echo " ✓ Currencylayer working" || echo " ✗ Currencylayer failed"
18
+
19
+ echo "3. Testing Coinlayer..."
20
+ curl -s "http://api.coinlayer.com/live?access_key=$COINLAYER_API_KEY&target=USD&symbols=BTC" | jq -r '.success' 2>/dev/null && echo " ✓ Coinlayer working" || echo " ✗ Coinlayer failed"
21
+
22
+ # Geolocation
23
+ echo "4. Testing Weatherstack..."
24
+ curl -s "http://api.weatherstack.com/current?access_key=$WEATHERSTACK_API_KEY&query=Stockholm" | jq -r '.current.temperature' 2>/dev/null && echo " ✓ Weatherstack working" || echo " ✗ Weatherstack failed"
25
+
26
+ echo "5. Testing IPstack..."
27
+ curl -s "http://api.ipstack.com/8.8.8.8?access_key=$IPSTACK_API_KEY" | jq -r '.country_name' 2>/dev/null && echo " ✓ IPstack working" || echo " ✗ IPstack failed"
28
+
29
+ echo "6. Testing IPapi..."
30
+ curl -s "https://ipapi.co/8.8.8.8/json/?key=$IPAPI_API_KEY" | jq -r '.country_name' 2>/dev/null && echo " ✓ IPapi working" || echo " ✗ IPapi failed"
31
+
32
+ echo "7. Testing Positionstack..."
33
+ curl -s "http://api.positionstack.com/v1/forward?access_key=$POSITIONSTACK_API_KEY&query=Stockholm&limit=1" | jq -r '.data[0].label' 2>/dev/null && echo " ✓ Positionstack working" || echo " ✗ Positionstack failed"
34
+
35
+ # Scraping
36
+ echo "8. Testing Scrapestack..."
37
+ curl -s "http://api.scrapestack.com/scrape?access_key=$SCRAPESTACK_API_KEY&url=https://example.com" | head -c 100 2>/dev/null && echo " ✓ Scrapestack working" || echo " ✗ Scrapestack failed"
38
+
39
+ echo "9. Testing Serpstack..."
40
+ curl -s "http://api.serpstack.com/search?access_key=$SERPSTACK_API_KEY&query=OpenAI" | jq -r '.organic_results[0].title' 2>/dev/null && echo " ✓ Serpstack working" || echo " ✗ Serpstack failed"
41
+
42
+ # News
43
+ echo "10. Testing Mediastack..."
44
+ curl -s "http://api.mediastack.com/v1/news?access_key=$MEDIASTACK_API_KEY&keywords=AI&limit=1" | jq -r '.data[0].title' 2>/dev/null && echo " ✓ Mediastack working" || echo " ✗ Mediastack failed"
45
+
46
+ # DevTools
47
+ echo "11. Testing Userstack..."
48
+ curl -s "http://api.userstack.com/detect?access_key=$USERSTACK_API_KEY&ua=Mozilla/5.0" | jq -r '.device.type' 2>/dev/null && echo " ✓ Userstack working" || echo " ✗ Userstack failed"
49
+
50
+ echo ""
51
+ echo "✅ Test complete!"
@@ -1,3 +0,0 @@
1
- export declare const activateWorkspace: any;
2
- export declare const createSessionForWorkspace: any;
3
- //# sourceMappingURL=adminActivate.d.ts.map
@@ -1,47 +0,0 @@
1
- import { mutation } from "./_generated/server";
2
- import { v } from "convex/values";
3
- export const activateWorkspace = mutation({
4
- args: { workspaceId: v.id("workspaces") },
5
- handler: async (ctx, { workspaceId }) => {
6
- const workspace = await ctx.db.get(workspaceId);
7
- if (!workspace) {
8
- return { success: false, error: "not_found" };
9
- }
10
- await ctx.db.patch(workspaceId, {
11
- status: "active",
12
- tier: "backer", // Give Hivr bees backer status
13
- weeklyUsageLimit: 999999,
14
- usageLimit: 999999,
15
- backerUntil: new Date("2026-12-31T23:59:59Z").getTime(), // Founding Backer until end of 2026
16
- updatedAt: Date.now(),
17
- });
18
- return { success: true };
19
- },
20
- });
21
- function generateToken() {
22
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
23
- let result = '';
24
- for (let i = 0; i < 32; i++) {
25
- result += chars.charAt(Math.floor(Math.random() * chars.length));
26
- }
27
- return result;
28
- }
29
- export const createSessionForWorkspace = mutation({
30
- args: { workspaceId: v.id("workspaces") },
31
- handler: async (ctx, { workspaceId }) => {
32
- const workspace = await ctx.db.get(workspaceId);
33
- if (!workspace || workspace.status !== "active") {
34
- return { success: false, error: "workspace_not_active" };
35
- }
36
- const sessionToken = "apiclaw_" + generateToken();
37
- await ctx.db.insert("agentSessions", {
38
- workspaceId,
39
- sessionToken,
40
- fingerprint: "hivr-bees",
41
- lastUsedAt: Date.now(),
42
- createdAt: Date.now(),
43
- });
44
- return { success: true, sessionToken };
45
- },
46
- });
47
- //# sourceMappingURL=adminActivate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adminActivate.js","sourceRoot":"","sources":["adminActivate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,MAAM,CAAC,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACxC,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;IACzC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACtC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC;QAChD,CAAC;QAED,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE;YAC9B,MAAM,EAAE,QAAQ;YAChB,IAAI,EAAE,QAAQ,EAAE,+BAA+B;YAC/C,gBAAgB,EAAE,MAAM;YACxB,UAAU,EAAE,MAAM;YAClB,WAAW,EAAE,IAAI,IAAI,CAAC,sBAAsB,CAAC,CAAC,OAAO,EAAE,EAAE,oCAAoC;YAC7F,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;CACF,CAAC,CAAC;AAEH,SAAS,aAAa;IACpB,MAAM,KAAK,GAAG,gEAAgE,CAAC;IAC/E,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE;IACzC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;QACtC,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;YAChD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QAC3D,CAAC;QAED,MAAM,YAAY,GAAG,UAAU,GAAG,aAAa,EAAE,CAAC;QAElD,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,eAAe,EAAE;YACnC,WAAW;YACX,YAAY;YACZ,WAAW,EAAE,WAAW;YACxB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAC;QAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IACzC,CAAC;CACF,CAAC,CAAC"}
@@ -1,3 +0,0 @@
1
- export declare const getTotalWorkspaces: any;
2
- export declare const listWorkspaces: any;
3
- //# sourceMappingURL=adminStats.d.ts.map