@nordsym/apiclaw 2.1.0 → 2.2.1

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 (185) 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/funnel-client.d.ts +24 -0
  5. package/dist/funnel-client.d.ts.map +1 -0
  6. package/dist/funnel-client.js +131 -0
  7. package/dist/funnel-client.js.map +1 -0
  8. package/dist/funnel.test.d.ts +2 -0
  9. package/dist/funnel.test.d.ts.map +1 -0
  10. package/dist/funnel.test.js +145 -0
  11. package/dist/funnel.test.js.map +1 -0
  12. package/dist/gateway-client.d.ts.map +1 -1
  13. package/dist/gateway-client.js +24 -2
  14. package/dist/gateway-client.js.map +1 -1
  15. package/dist/index.bundled.js +61263 -0
  16. package/dist/index.js +161 -74
  17. package/dist/index.js.map +1 -1
  18. package/dist/postinstall.d.ts +0 -5
  19. package/dist/postinstall.d.ts.map +1 -1
  20. package/dist/postinstall.js +24 -3
  21. package/dist/postinstall.js.map +1 -1
  22. package/dist/registration-guard.d.ts +29 -0
  23. package/dist/registration-guard.d.ts.map +1 -0
  24. package/dist/registration-guard.js +87 -0
  25. package/dist/registration-guard.js.map +1 -0
  26. package/package.json +7 -2
  27. package/.claude/settings.local.json +0 -9
  28. package/.env.prod +0 -1
  29. package/apiclaw-README.md +0 -494
  30. package/convex/_generated/api.d.ts +0 -137
  31. package/convex/_generated/api.js +0 -23
  32. package/convex/_generated/dataModel.d.ts +0 -60
  33. package/convex/_generated/server.d.ts +0 -143
  34. package/convex/_generated/server.js +0 -93
  35. package/convex/adminActivate.ts +0 -53
  36. package/convex/adminStats.ts +0 -306
  37. package/convex/agents.ts +0 -939
  38. package/convex/analytics.ts +0 -187
  39. package/convex/apiKeys.ts +0 -220
  40. package/convex/backfillAnalytics.ts +0 -272
  41. package/convex/backfillSearchLogs.ts +0 -35
  42. package/convex/billing.ts +0 -834
  43. package/convex/capabilities.ts +0 -157
  44. package/convex/chains.ts +0 -1318
  45. package/convex/credits.ts +0 -211
  46. package/convex/crons.ts +0 -50
  47. package/convex/debugFilestackLogs.ts +0 -16
  48. package/convex/debugGetToken.ts +0 -18
  49. package/convex/directCall.ts +0 -713
  50. package/convex/earnProgress.ts +0 -753
  51. package/convex/email.ts +0 -329
  52. package/convex/feedback.ts +0 -265
  53. package/convex/http.ts +0 -3430
  54. package/convex/inbound.ts +0 -32
  55. package/convex/logs.ts +0 -701
  56. package/convex/migrateFilestack.ts +0 -81
  57. package/convex/migratePartnersProd.ts +0 -174
  58. package/convex/migratePratham.ts +0 -126
  59. package/convex/migrateProviderWorkspaces.ts +0 -175
  60. package/convex/mou.ts +0 -91
  61. package/convex/providerKeys.ts +0 -289
  62. package/convex/providers.ts +0 -1135
  63. package/convex/purchases.ts +0 -183
  64. package/convex/ratelimit.ts +0 -104
  65. package/convex/schema.ts +0 -869
  66. package/convex/searchLogs.ts +0 -265
  67. package/convex/seedAPILayerAPIs.ts +0 -191
  68. package/convex/seedDirectCallConfigs.ts +0 -336
  69. package/convex/seedPratham.ts +0 -149
  70. package/convex/spendAlerts.ts +0 -442
  71. package/convex/stripeActions.ts +0 -607
  72. package/convex/teams.ts +0 -243
  73. package/convex/telemetry.ts +0 -81
  74. package/convex/tsconfig.json +0 -25
  75. package/convex/updateAPIStatus.ts +0 -44
  76. package/convex/usage.ts +0 -260
  77. package/convex/usageReports.ts +0 -357
  78. package/convex/waitlist.ts +0 -55
  79. package/convex/webhooks.ts +0 -494
  80. package/convex/workspaceSettings.ts +0 -143
  81. package/convex/workspaces.ts +0 -1331
  82. package/convex.json +0 -3
  83. package/direct-test.mjs +0 -51
  84. package/email-templates/filestack-provider-outreach.html +0 -162
  85. package/email-templates/partnership-template.html +0 -116
  86. package/email-templates/pratham-draft-preview.txt +0 -57
  87. package/email-templates/pratham-partnership-draft.html +0 -141
  88. package/reports/APIClaw-Session-Report-2026-04-05.pdf +0 -0
  89. package/reports/pipeline/PIPELINE-REPORT.json +0 -153
  90. package/reports/pipeline/acquire_apisguru.json +0 -17
  91. package/reports/pipeline/capabilities.json +0 -38
  92. package/reports/pipeline/discover_azure_recursive.json +0 -1551
  93. package/reports/pipeline/discover_github.json +0 -25
  94. package/reports/pipeline/discover_github_repos.json +0 -49
  95. package/reports/pipeline/discover_swaggerhub.json +0 -24
  96. package/reports/pipeline/discover_well_known.json +0 -23
  97. package/reports/pipeline/fetch_specs.json +0 -19
  98. package/reports/pipeline/generate_providers.json +0 -14
  99. package/reports/pipeline/match_registry.json +0 -11
  100. package/reports/pipeline/parse_specs.json +0 -17
  101. package/reports/pipeline/promote_candidates.json +0 -34
  102. package/reports/pipeline/validate.json +0 -30
  103. package/reports/pipeline/validate_smoke_details.json +0 -3835
  104. package/reports/session-report-2026-04-05.html +0 -433
  105. package/seed-apis-direct.mjs +0 -106
  106. package/src/access-control.ts +0 -174
  107. package/src/adapters/base.ts +0 -364
  108. package/src/adapters/claude-desktop.ts +0 -41
  109. package/src/adapters/cline.ts +0 -88
  110. package/src/adapters/continue.ts +0 -91
  111. package/src/adapters/cursor.ts +0 -43
  112. package/src/adapters/custom.ts +0 -188
  113. package/src/adapters/detect.ts +0 -202
  114. package/src/adapters/index.ts +0 -47
  115. package/src/adapters/windsurf.ts +0 -44
  116. package/src/bin-http.ts +0 -45
  117. package/src/bin.ts +0 -34
  118. package/src/capability-router.ts +0 -331
  119. package/src/chainExecutor.ts +0 -730
  120. package/src/chainResolver.test.ts +0 -246
  121. package/src/chainResolver.ts +0 -658
  122. package/src/cli/commands/demo.ts +0 -109
  123. package/src/cli/commands/doctor.ts +0 -435
  124. package/src/cli/commands/index.ts +0 -9
  125. package/src/cli/commands/login.ts +0 -203
  126. package/src/cli/commands/mcp-install.ts +0 -373
  127. package/src/cli/commands/restore.ts +0 -333
  128. package/src/cli/commands/setup.ts +0 -297
  129. package/src/cli/commands/uninstall.ts +0 -240
  130. package/src/cli/index.ts +0 -148
  131. package/src/cli.ts +0 -370
  132. package/src/confirmation.ts +0 -296
  133. package/src/credentials.ts +0 -455
  134. package/src/credits.ts +0 -329
  135. package/src/crypto.ts +0 -75
  136. package/src/discovery.ts +0 -568
  137. package/src/enterprise/env.ts +0 -156
  138. package/src/enterprise/index.ts +0 -7
  139. package/src/enterprise/script-generator.ts +0 -481
  140. package/src/execute-dynamic.ts +0 -617
  141. package/src/execute.ts +0 -2386
  142. package/src/gateway-client.ts +0 -192
  143. package/src/hivr-whitelist.ts +0 -110
  144. package/src/http-api.ts +0 -286
  145. package/src/http-server-minimal.ts +0 -154
  146. package/src/index.ts +0 -2611
  147. package/src/intelligent-gateway.ts +0 -339
  148. package/src/mcp-analytics.ts +0 -156
  149. package/src/metered.ts +0 -149
  150. package/src/open-apis-generated.ts +0 -157
  151. package/src/open-apis.ts +0 -558
  152. package/src/postinstall.ts +0 -18
  153. package/src/product-whitelist.ts +0 -246
  154. package/src/proxy.ts +0 -36
  155. package/src/session.ts +0 -129
  156. package/src/stripe.ts +0 -497
  157. package/src/telemetry.ts +0 -71
  158. package/src/test.ts +0 -135
  159. package/src/types/convex-api.d.ts +0 -20
  160. package/src/types/convex-api.ts +0 -21
  161. package/src/types.ts +0 -109
  162. package/src/ui/colors.ts +0 -219
  163. package/src/ui/errors.ts +0 -394
  164. package/src/ui/index.ts +0 -17
  165. package/src/ui/prompts.ts +0 -390
  166. package/src/ui/spinner.ts +0 -325
  167. package/src/utils/backup.ts +0 -224
  168. package/src/utils/config.ts +0 -318
  169. package/src/utils/os.ts +0 -124
  170. package/src/utils/paths.ts +0 -203
  171. package/src/webhook.ts +0 -107
  172. package/test-10-working.cjs +0 -97
  173. package/test-14-final.cjs +0 -96
  174. package/test-actual-handlers.ts +0 -92
  175. package/test-apilayer-all-14.ts +0 -249
  176. package/test-apilayer-fixed.ts +0 -248
  177. package/test-direct-endpoints.ts +0 -174
  178. package/test-exact-endpoints.ts +0 -144
  179. package/test-final.ts +0 -83
  180. package/test-full-routing.ts +0 -100
  181. package/test-handlers-correct.ts +0 -217
  182. package/test-numverify-key.ts +0 -41
  183. package/test-via-handlers.ts +0 -92
  184. package/test-worldnews.mjs +0 -26
  185. 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
- });