@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
@@ -1,187 +0,0 @@
1
- import { mutation, query } from "./_generated/server";
2
- import { v } from "convex/values";
3
-
4
- // Log an analytics event
5
- export const log = mutation({
6
- args: {
7
- event: v.string(),
8
- provider: v.optional(v.string()),
9
- query: v.optional(v.string()),
10
- identifier: v.string(),
11
- workspaceId: v.optional(v.id("workspaces")),
12
- metadata: v.optional(v.any()),
13
- },
14
- handler: async (ctx, args) => {
15
- return await ctx.db.insert("analytics", {
16
- ...args,
17
- timestamp: Date.now(),
18
- });
19
- },
20
- });
21
-
22
- // Get stats for dashboard
23
- export const getStats = query({
24
- args: {
25
- hoursBack: v.optional(v.number()),
26
- },
27
- handler: async (ctx, args) => {
28
- const hoursBack = args.hoursBack || 24;
29
- const since = Date.now() - hoursBack * 3600000;
30
-
31
- const events = await ctx.db
32
- .query("analytics")
33
- .withIndex("by_timestamp")
34
- .filter((q) => q.gte(q.field("timestamp"), since))
35
- .collect();
36
-
37
- // Aggregate stats
38
- const stats = {
39
- totalEvents: events.length,
40
- discoveries: events.filter((e) => e.event === "discovery").length,
41
- instantCalls: events.filter((e) => e.event === "instant").length,
42
- uniqueUsers: new Set(events.map((e) => e.identifier)).size,
43
- byProvider: {} as Record<string, number>,
44
- topQueries: [] as { query: string; count: number }[],
45
- hourly: [] as { hour: string; count: number }[],
46
- };
47
-
48
- // By provider
49
- for (const event of events.filter((e) => e.provider)) {
50
- stats.byProvider[event.provider!] = (stats.byProvider[event.provider!] || 0) + 1;
51
- }
52
-
53
- // Top queries
54
- const queryCounts: Record<string, number> = {};
55
- for (const event of events.filter((e) => e.query)) {
56
- queryCounts[event.query!] = (queryCounts[event.query!] || 0) + 1;
57
- }
58
- stats.topQueries = Object.entries(queryCounts)
59
- .sort(([, a], [, b]) => b - a)
60
- .slice(0, 10)
61
- .map(([query, count]) => ({ query, count }));
62
-
63
- // Hourly breakdown
64
- const hourlyCounts: Record<string, number> = {};
65
- for (const event of events) {
66
- const hour = new Date(event.timestamp).toISOString().slice(0, 13);
67
- hourlyCounts[hour] = (hourlyCounts[hour] || 0) + 1;
68
- }
69
- stats.hourly = Object.entries(hourlyCounts)
70
- .sort(([a], [b]) => a.localeCompare(b))
71
- .map(([hour, count]) => ({ hour, count }));
72
-
73
- return stats;
74
- },
75
- });
76
-
77
- // Get recent events for live feed
78
- export const getRecent = query({
79
- args: {
80
- limit: v.optional(v.number()),
81
- },
82
- handler: async (ctx, args) => {
83
- const limit = args.limit || 50;
84
-
85
- return await ctx.db
86
- .query("analytics")
87
- .withIndex("by_timestamp")
88
- .order("desc")
89
- .take(limit);
90
- },
91
- });
92
-
93
- // Get provider breakdown for Agent Analytics (workspace-specific)
94
- export const getProviderBreakdown = query({
95
- args: {
96
- token: v.string(),
97
- periodDays: v.optional(v.number()),
98
- },
99
- handler: async (ctx, args) => {
100
- const periodDays = args.periodDays || 7;
101
- const since = Date.now() - periodDays * 24 * 3600000;
102
-
103
- // Verify session and get workspace
104
- const session = await ctx.db
105
- .query("agentSessions")
106
- .withIndex("by_sessionToken", (q) => q.eq("sessionToken", args.token))
107
- .first();
108
-
109
- if (!session) {
110
- return null;
111
- }
112
-
113
- // Get all API logs for this workspace
114
- const logs = await ctx.db
115
- .query("apiLogs")
116
- .withIndex("by_workspaceId_createdAt", (q) => q.eq("workspaceId", session.workspaceId))
117
- .filter((q) => q.gte(q.field("createdAt"), since))
118
- .collect();
119
-
120
- if (logs.length === 0) {
121
- return null; // Return null so frontend knows to show empty state, not preview
122
- }
123
-
124
- // Aggregate stats
125
- const totalCalls = logs.length;
126
- const successCount = logs.filter((l) => l.status === "success").length;
127
- const failureCount = logs.filter((l) => l.status === "error").length;
128
- const totalLatency = logs.reduce((sum, l) => sum + (l.latencyMs || 0), 0);
129
- const avgLatency = totalCalls > 0 ? Math.round(totalLatency / totalCalls) : 0;
130
-
131
- // Provider breakdown
132
- const byProvider: Record<string, { count: number; latency: number }> = {};
133
- for (const log of logs) {
134
- if (!byProvider[log.provider]) {
135
- byProvider[log.provider] = { count: 0, latency: 0 };
136
- }
137
- byProvider[log.provider].count++;
138
- byProvider[log.provider].latency += log.latencyMs || 0;
139
- }
140
-
141
- // Agent breakdown (by subagentId)
142
- const byAgent: Record<string, number> = {};
143
- for (const log of logs) {
144
- const agent = log.subagentId || "main";
145
- byAgent[agent] = (byAgent[agent] || 0) + 1;
146
- }
147
-
148
- // Action breakdown
149
- const byAction: Record<string, number> = {};
150
- for (const log of logs) {
151
- const key = `${log.provider}:${log.action}`;
152
- byAction[key] = (byAction[key] || 0) + 1;
153
- }
154
-
155
- // Time series (daily)
156
- const dailyCounts: Record<string, number> = {};
157
- for (const log of logs) {
158
- const day = new Date(log.createdAt).toISOString().slice(0, 10);
159
- dailyCounts[day] = (dailyCounts[day] || 0) + 1;
160
- }
161
-
162
- return {
163
- totalCalls,
164
- successCount,
165
- failureCount,
166
- successRate: totalCalls > 0 ? (successCount / totalCalls) * 100 : 0,
167
- avgLatency,
168
- byProvider: Object.entries(byProvider).map(([name, data]) => ({
169
- name,
170
- count: data.count,
171
- avgLatency: data.count > 0 ? Math.round(data.latency / data.count) : 0,
172
- })).sort((a, b) => b.count - a.count),
173
- byAgent: Object.entries(byAgent).map(([name, count]) => ({
174
- name,
175
- count,
176
- })).sort((a, b) => b.count - a.count),
177
- byAction: Object.entries(byAction).map(([name, count]) => ({
178
- name,
179
- count,
180
- })).sort((a, b) => b.count - a.count).slice(0, 10),
181
- timeSeries: Object.entries(dailyCounts)
182
- .sort(([a], [b]) => a.localeCompare(b))
183
- .map(([date, count]) => ({ date, count })),
184
- isPreview: false,
185
- };
186
- },
187
- });
package/convex/apiKeys.ts DELETED
@@ -1,220 +0,0 @@
1
- import { v } from "convex/values";
2
- import { mutation, query, internalQuery } from "./_generated/server";
3
-
4
- // ============================================
5
- // WORKSPACE API KEYS
6
- // Generate persistent API keys for programmatic access.
7
- // Users generate keys in the dashboard, then use them
8
- // in any agent config, automation, or script.
9
- // ============================================
10
-
11
- function generateRawKey(): string {
12
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
13
- let result = "";
14
- for (let i = 0; i < 48; i++) {
15
- result += chars.charAt(Math.floor(Math.random() * chars.length));
16
- }
17
- return `sk-claw-${result}`;
18
- }
19
-
20
- // Simple hash for key lookup (SHA-256 not available in Convex runtime, use deterministic hash)
21
- function hashKey(key: string): string {
22
- let hash = 0;
23
- for (let i = 0; i < key.length; i++) {
24
- const char = key.charCodeAt(i);
25
- hash = ((hash << 5) - hash + char) | 0;
26
- }
27
- // Create a longer hash by running multiple rounds with offsets
28
- let h1 = hash;
29
- let h2 = 0;
30
- for (let i = 0; i < key.length; i++) {
31
- h2 = ((h2 << 7) - h2 + key.charCodeAt(i) * 31) | 0;
32
- }
33
- let h3 = 0;
34
- for (let i = 0; i < key.length; i++) {
35
- h3 = ((h3 << 11) - h3 + key.charCodeAt(i) * 127) | 0;
36
- }
37
- return `${(h1 >>> 0).toString(36)}-${(h2 >>> 0).toString(36)}-${(h3 >>> 0).toString(36)}`;
38
- }
39
-
40
- function getKeyPrefix(key: string): string {
41
- return `sk-claw-...${key.slice(-4)}`;
42
- }
43
-
44
- // ============================================
45
- // GENERATE KEY
46
- // ============================================
47
-
48
- export const generateKey = mutation({
49
- args: {
50
- token: v.string(), // session token for auth
51
- name: v.string(), // user label
52
- },
53
- handler: async (ctx, args) => {
54
- // Auth via agentSession
55
- const session = await ctx.db
56
- .query("agentSessions")
57
- .withIndex("by_sessionToken", (q) => q.eq("sessionToken", args.token))
58
- .first();
59
-
60
- if (!session) {
61
- throw new Error("Invalid session");
62
- }
63
-
64
- const workspaceId = session.workspaceId;
65
-
66
- // Limit: max 5 active keys per workspace
67
- const existingKeys = await ctx.db
68
- .query("workspaceApiKeys")
69
- .withIndex("by_workspaceId", (q) => q.eq("workspaceId", workspaceId))
70
- .collect();
71
-
72
- const activeKeys = existingKeys.filter((k) => !k.revokedAt);
73
- if (activeKeys.length >= 5) {
74
- throw new Error("Maximum 5 active keys per workspace. Revoke an existing key first.");
75
- }
76
-
77
- // Check for duplicate name
78
- const nameExists = activeKeys.some(
79
- (k) => k.name.toLowerCase() === args.name.toLowerCase()
80
- );
81
- if (nameExists) {
82
- throw new Error(`A key named "${args.name}" already exists.`);
83
- }
84
-
85
- const rawKey = generateRawKey();
86
- const now = Date.now();
87
-
88
- await ctx.db.insert("workspaceApiKeys", {
89
- workspaceId,
90
- key: "", // We don't store the raw key
91
- keyHash: hashKey(rawKey),
92
- keyPrefix: getKeyPrefix(rawKey),
93
- name: args.name,
94
- createdAt: now,
95
- });
96
-
97
- // Return the raw key ONCE - it won't be retrievable again
98
- return {
99
- key: rawKey,
100
- keyPrefix: getKeyPrefix(rawKey),
101
- name: args.name,
102
- };
103
- },
104
- });
105
-
106
- // ============================================
107
- // LIST KEYS
108
- // ============================================
109
-
110
- export const listKeys = query({
111
- args: {
112
- token: v.string(),
113
- },
114
- handler: async (ctx, args) => {
115
- const session = await ctx.db
116
- .query("agentSessions")
117
- .withIndex("by_sessionToken", (q) => q.eq("sessionToken", args.token))
118
- .first();
119
-
120
- if (!session) {
121
- return { keys: [] };
122
- }
123
-
124
- const keys = await ctx.db
125
- .query("workspaceApiKeys")
126
- .withIndex("by_workspaceId", (q) => q.eq("workspaceId", session.workspaceId))
127
- .collect();
128
-
129
- return {
130
- keys: keys
131
- .filter((k) => !k.revokedAt)
132
- .map((k) => ({
133
- id: k._id,
134
- name: k.name,
135
- keyPrefix: k.keyPrefix,
136
- lastUsedAt: k.lastUsedAt,
137
- createdAt: k.createdAt,
138
- }))
139
- .sort((a, b) => b.createdAt - a.createdAt),
140
- };
141
- },
142
- });
143
-
144
- // ============================================
145
- // REVOKE KEY
146
- // ============================================
147
-
148
- export const revokeKey = mutation({
149
- args: {
150
- token: v.string(),
151
- keyId: v.id("workspaceApiKeys"),
152
- },
153
- handler: async (ctx, args) => {
154
- const session = await ctx.db
155
- .query("agentSessions")
156
- .withIndex("by_sessionToken", (q) => q.eq("sessionToken", args.token))
157
- .first();
158
-
159
- if (!session) {
160
- throw new Error("Invalid session");
161
- }
162
-
163
- const key = await ctx.db.get(args.keyId);
164
- if (!key || key.workspaceId !== session.workspaceId) {
165
- throw new Error("Key not found");
166
- }
167
-
168
- if (key.revokedAt) {
169
- throw new Error("Key already revoked");
170
- }
171
-
172
- await ctx.db.patch(args.keyId, { revokedAt: Date.now() });
173
- return { success: true };
174
- },
175
- });
176
-
177
- // ============================================
178
- // RESOLVE KEY (internal - used by gateway)
179
- // ============================================
180
-
181
- export const resolveKey = internalQuery({
182
- args: {
183
- rawKey: v.string(),
184
- },
185
- handler: async (ctx, args) => {
186
- const keyHash = hashKey(args.rawKey);
187
-
188
- const keyDoc = await ctx.db
189
- .query("workspaceApiKeys")
190
- .withIndex("by_keyHash", (q) => q.eq("keyHash", keyHash))
191
- .first();
192
-
193
- if (!keyDoc) {
194
- return null;
195
- }
196
-
197
- if (keyDoc.revokedAt) {
198
- return null;
199
- }
200
-
201
- return {
202
- workspaceId: keyDoc.workspaceId,
203
- keyId: keyDoc._id,
204
- name: keyDoc.name,
205
- };
206
- },
207
- });
208
-
209
- // ============================================
210
- // TOUCH KEY (internal - update lastUsedAt)
211
- // ============================================
212
-
213
- export const touchKey = mutation({
214
- args: {
215
- keyId: v.id("workspaceApiKeys"),
216
- },
217
- handler: async (ctx, args) => {
218
- await ctx.db.patch(args.keyId, { lastUsedAt: Date.now() });
219
- },
220
- });
@@ -1,272 +0,0 @@
1
- import { mutation } from "./_generated/server";
2
- import { Id } from "./_generated/dataModel";
3
-
4
- /**
5
- * Restore provider analytics lost during deployment migration
6
- * (brilliant-puffin-712 -> adventurous-avocet-799).
7
- */
8
- export const restoreProviderAnalytics = mutation({
9
- args: {},
10
- handler: async (ctx) => {
11
- const prathamWorkspaceId = "n17bf4raa01r0d4na0bsgg117x83y551" as Id<"workspaces">;
12
- const providerId = "k97fj3bpy1nvp6fd1vr51kbkxs84k5dn" as Id<"providers">;
13
-
14
- // Active workspace IDs on prod
15
- const callerWorkspaces = [
16
- "n17535f45yrzygtdbws0b1seax84et7k",
17
- "n17chyq6188vpwynyyy2qafhmx84cwem",
18
- "n174s7zpqdwvhnj7rkwwbxfm5d84a2zx",
19
- "n17ffc3dnscbsz8h86ez90ssth847krp",
20
- "n17bnymj0bqffvant7ejb23cw98478dg",
21
- "n171xw49cwcredajx25gyfgxrh846kym",
22
- "n1726f2x60v5197bvbp6ex0mqs847z9t",
23
- "n1768qpb9w8wqryceggrk3asc9842n2n",
24
- "n170g8xv4vk0gq4qehgaah2gm184289d",
25
- "n178829315bfdwpryfs20nmjf9821774",
26
- "n17b2tdjpkz67frrd05sg07be983z9ca",
27
- "n17azsjrv9mc4r0bge2s5gpxjd83zbd0",
28
- "n174g9na6rtf4wpd1a24qs0rjs83z8v4",
29
- "n17afk9th7baxmrsmq0v4nskx183zdq4",
30
- ];
31
-
32
- const subagentIds = ["main", "research", "builder", "analyst", "default"];
33
-
34
- // API actions with popularity weights
35
- const apiActions: { action: string; weight: number }[] = [
36
- { action: "exchange_rates", weight: 12 },
37
- { action: "weatherstack_current", weight: 10 },
38
- { action: "ipstack_lookup", weight: 9 },
39
- { action: "fixer_latest", weight: 8 },
40
- { action: "currencylayer_live", weight: 7 },
41
- { action: "mediastack_news", weight: 7 },
42
- { action: "market_data", weight: 6 },
43
- { action: "finance_news", weight: 6 },
44
- { action: "scrapestack_scrape", weight: 5 },
45
- { action: "serpstack_search", weight: 5 },
46
- { action: "ipapi_lookup", weight: 5 },
47
- { action: "coinlayer_live", weight: 4 },
48
- { action: "exchangeratehost_latest", weight: 4 },
49
- { action: "positionstack_forward", weight: 4 },
50
- { action: "weatherstack_forecast", weight: 3 },
51
- { action: "aviation", weight: 3 },
52
- { action: "vat_check", weight: 3 },
53
- { action: "languagelayer_detect", weight: 3 },
54
- { action: "userstack_detect", weight: 2 },
55
- { action: "verify_email", weight: 2 },
56
- { action: "screenshot", weight: 2 },
57
- { action: "scrape", weight: 2 },
58
- { action: "positionstack_reverse", weight: 2 },
59
- { action: "fixer_convert", weight: 2 },
60
- { action: "currencylayer_convert", weight: 1 },
61
- { action: "pdf_generate", weight: 1 },
62
- { action: "world_news", weight: 1 },
63
- ];
64
-
65
- // Deterministic RNG
66
- let s = 48271;
67
- const rng = () => { s = (s * 16807) % 2147483647; return (s - 1) / 2147483646; };
68
- const pick = <T>(a: T[]): T => a[Math.floor(rng() * a.length)];
69
- const weightedPick = (): string => {
70
- const total = apiActions.reduce((sum, x) => sum + x.weight, 0);
71
- let r = rng() * total;
72
- for (const x of apiActions) { r -= x.weight; if (r <= 0) return x.action; }
73
- return apiActions[0].action;
74
- };
75
-
76
- const now = Date.now();
77
- const DAY = 86400000;
78
- const HOUR = 3600000;
79
-
80
- let callCount = 0;
81
- let discoveryCount = 0;
82
- const discoveryMap = new Map<string, number>();
83
-
84
- for (let daysAgo = 30; daysAgo >= 0; daysAgo--) {
85
- const dayBase = now - daysAgo * DAY;
86
- const date = new Date(dayBase);
87
- const dow = date.getUTCDay();
88
- const isWeekend = dow === 0 || dow === 6;
89
- const ramp = 0.4 + 0.6 * ((30 - daysAgo) / 30);
90
-
91
- const dayDisc = Math.round((isWeekend ? 4 : 9) * ramp * (0.7 + rng() * 0.6));
92
- const dayCalls = Math.round((isWeekend ? 2 : 5) * ramp * (0.6 + rng() * 0.8));
93
-
94
- // Discovery events
95
- for (let i = 0; i < dayDisc; i++) {
96
- const action = weightedPick();
97
- const ts = dayBase + Math.floor(rng() * 16 + 6) * HOUR + Math.floor(rng() * 60) * 60000;
98
-
99
- discoveryMap.set(action, (discoveryMap.get(action) || 0) + 1);
100
- discoveryCount++;
101
-
102
- await ctx.db.insert("apiLogs", {
103
- workspaceId: prathamWorkspaceId,
104
- sessionToken: "",
105
- provider: "apilayer",
106
- action: `discover:${action}`,
107
- status: "success",
108
- latencyMs: Math.floor(40 + rng() * 180),
109
- direction: "inbound",
110
- callerWorkspaceId: pick(callerWorkspaces),
111
- subagentId: pick(subagentIds),
112
- createdAt: ts,
113
- });
114
- }
115
-
116
- // Call events
117
- for (let i = 0; i < dayCalls; i++) {
118
- const action = weightedPick();
119
- const ts = dayBase + Math.floor(rng() * 14 + 8) * HOUR + Math.floor(rng() * 60) * 60000;
120
- const ok = rng() > 0.04;
121
-
122
- await ctx.db.insert("apiLogs", {
123
- workspaceId: prathamWorkspaceId,
124
- sessionToken: "",
125
- provider: "apilayer",
126
- action,
127
- status: ok ? "success" : "error",
128
- latencyMs: Math.floor(120 + rng() * 800 + (rng() > 0.9 ? rng() * 2000 : 0)),
129
- direction: "inbound",
130
- callerWorkspaceId: pick(callerWorkspaces),
131
- subagentId: pick(subagentIds),
132
- errorMessage: ok ? undefined : pick(["rate_limit_exceeded", "timeout", "provider_error"]),
133
- createdAt: ts,
134
- });
135
- callCount++;
136
- }
137
- }
138
-
139
- // Update discoveryCount on providerAPIs
140
- const actionToApi: Record<string, string> = {
141
- exchange_rates: "ExchangeRate API", market_data: "Marketstack", aviation: "AviationStack",
142
- pdf_generate: "PDF Layer", screenshot: "Screenshot Layer", verify_email: "Email Verification API",
143
- verify_number: "Number Verification API", vat_check: "VAT Layer", world_news: "World News API",
144
- finance_news: "Finance News API", scrape: "Advanced Scraper API", image_crop: "Image Crop API",
145
- skills: "Skills API", form_submit: "Form API", fixer_convert: "Fixer API", fixer_latest: "Fixer API",
146
- currencylayer_live: "Currencylayer", currencylayer_convert: "Currencylayer",
147
- coinlayer_live: "Coinlayer", exchangeratehost_latest: "Exchangerate.host",
148
- weatherstack_current: "Weatherstack", weatherstack_forecast: "Weatherstack",
149
- ipstack_lookup: "IPstack", ipapi_lookup: "IPapi",
150
- positionstack_forward: "Positionstack", positionstack_reverse: "Positionstack",
151
- languagelayer_detect: "Languagelayer", scrapestack_scrape: "Scrapestack",
152
- serpstack_search: "Serpstack", mediastack_news: "Mediastack", userstack_detect: "Userstack",
153
- };
154
-
155
- const apiTotals = new Map<string, number>();
156
- for (const [action, count] of discoveryMap) {
157
- const name = actionToApi[action] || action;
158
- apiTotals.set(name, (apiTotals.get(name) || 0) + count);
159
- }
160
-
161
- const allApis = await ctx.db
162
- .query("providerAPIs")
163
- .withIndex("by_providerId", (q) => q.eq("providerId", providerId))
164
- .collect();
165
-
166
- let updated = 0;
167
- for (const api of allApis) {
168
- const total = apiTotals.get(api.name) || 0;
169
- if (total > 0) {
170
- await ctx.db.patch(api._id, {
171
- discoveryCount: total,
172
- lastDiscoveredAt: now - Math.floor(rng() * 2 * DAY),
173
- });
174
- updated++;
175
- }
176
- }
177
-
178
- return { calls: callCount, discoveries: discoveryCount, apisUpdated: updated };
179
- },
180
- });
181
-
182
- /**
183
- * Restore Filestack discovery analytics (discovery-only, not callable).
184
- */
185
- export const restoreFilestackAnalytics = mutation({
186
- args: {},
187
- handler: async (ctx) => {
188
- const filestackWorkspaceId = "n175gprvbbvygmhtg8cfk8jzbd83m0p8" as Id<"workspaces">;
189
- const filestackApiId = "k57cafdwd4zt66v9y5t23bqzwn8467wj" as Id<"providerAPIs">;
190
-
191
- const callerWorkspaces = [
192
- "n17535f45yrzygtdbws0b1seax84et7k",
193
- "n17chyq6188vpwynyyy2qafhmx84cwem",
194
- "n174s7zpqdwvhnj7rkwwbxfm5d84a2zx",
195
- "n17ffc3dnscbsz8h86ez90ssth847krp",
196
- "n17bnymj0bqffvant7ejb23cw98478dg",
197
- "n171xw49cwcredajx25gyfgxrh846kym",
198
- "n1726f2x60v5197bvbp6ex0mqs847z9t",
199
- "n178829315bfdwpryfs20nmjf9821774",
200
- "n17b2tdjpkz67frrd05sg07be983z9ca",
201
- "n17azsjrv9mc4r0bge2s5gpxjd83zbd0",
202
- ];
203
-
204
- const subagentIds = ["main", "research", "builder", "default"];
205
-
206
- // Filestack discovery actions (file-related searches that surface Filestack)
207
- const discoveryQueries = [
208
- "discover:file_upload",
209
- "discover:file_transform",
210
- "discover:file_storage",
211
- "discover:image_processing",
212
- "discover:file_conversion",
213
- "discover:cdn_delivery",
214
- ];
215
- const weights = [10, 6, 5, 8, 4, 3];
216
-
217
- let s = 73019;
218
- const rng = () => { s = (s * 16807) % 2147483647; return (s - 1) / 2147483646; };
219
- const pick = <T>(a: T[]): T => a[Math.floor(rng() * a.length)];
220
- const weightedQuery = (): string => {
221
- const total = weights.reduce((a, b) => a + b, 0);
222
- let r = rng() * total;
223
- for (let i = 0; i < weights.length; i++) {
224
- r -= weights[i];
225
- if (r <= 0) return discoveryQueries[i];
226
- }
227
- return discoveryQueries[0];
228
- };
229
-
230
- const now = Date.now();
231
- const DAY = 86400000;
232
- const HOUR = 3600000;
233
-
234
- let count = 0;
235
-
236
- for (let daysAgo = 30; daysAgo >= 0; daysAgo--) {
237
- const dayBase = now - daysAgo * DAY;
238
- const dow = new Date(dayBase).getUTCDay();
239
- const isWeekend = dow === 0 || dow === 6;
240
- const ramp = 0.5 + 0.5 * ((30 - daysAgo) / 30);
241
-
242
- // Filestack is niche -- fewer hits than APILayer
243
- const dayDisc = Math.round((isWeekend ? 1.5 : 3.5) * ramp * (0.6 + rng() * 0.8));
244
-
245
- for (let i = 0; i < dayDisc; i++) {
246
- const ts = dayBase + Math.floor(rng() * 15 + 7) * HOUR + Math.floor(rng() * 60) * 60000;
247
-
248
- await ctx.db.insert("apiLogs", {
249
- workspaceId: filestackWorkspaceId,
250
- sessionToken: "",
251
- provider: "filestack",
252
- action: weightedQuery(),
253
- status: "success",
254
- latencyMs: Math.floor(30 + rng() * 150),
255
- direction: "inbound",
256
- callerWorkspaceId: pick(callerWorkspaces),
257
- subagentId: pick(subagentIds),
258
- createdAt: ts,
259
- });
260
- count++;
261
- }
262
- }
263
-
264
- // Update discoveryCount on the single Filestack API to match
265
- await ctx.db.patch(filestackApiId, {
266
- discoveryCount: count,
267
- lastDiscoveredAt: now - Math.floor(rng() * DAY),
268
- });
269
-
270
- return { discoveries: count };
271
- },
272
- });