@nordsym/apiclaw 1.7.3 → 1.7.5

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 (219) hide show
  1. package/convex/_generated/api.d.ts +115 -0
  2. package/convex/_generated/api.js +23 -0
  3. package/convex/_generated/dataModel.d.ts +60 -0
  4. package/convex/_generated/server.d.ts +143 -0
  5. package/convex/_generated/server.js +93 -0
  6. package/convex/adminActivate.d.ts +3 -0
  7. package/convex/adminActivate.d.ts.map +1 -0
  8. package/convex/adminActivate.js +47 -0
  9. package/convex/adminActivate.js.map +1 -0
  10. package/convex/adminActivate.ts +54 -0
  11. package/convex/adminStats.d.ts +3 -0
  12. package/convex/adminStats.d.ts.map +1 -0
  13. package/convex/adminStats.js +42 -0
  14. package/convex/adminStats.js.map +1 -0
  15. package/convex/adminStats.ts +44 -0
  16. package/convex/agents.d.ts +76 -0
  17. package/convex/agents.d.ts.map +1 -0
  18. package/convex/agents.js +699 -0
  19. package/convex/agents.js.map +1 -0
  20. package/convex/agents.ts +814 -0
  21. package/convex/analytics.d.ts +5 -0
  22. package/convex/analytics.d.ts.map +1 -0
  23. package/convex/analytics.js +166 -0
  24. package/convex/analytics.js.map +1 -0
  25. package/convex/analytics.ts +186 -0
  26. package/convex/billing.d.ts +88 -0
  27. package/convex/billing.d.ts.map +1 -0
  28. package/convex/billing.js +655 -0
  29. package/convex/billing.js.map +1 -0
  30. package/convex/billing.ts +791 -0
  31. package/convex/capabilities.d.ts +9 -0
  32. package/convex/capabilities.d.ts.map +1 -0
  33. package/convex/capabilities.js +145 -0
  34. package/convex/capabilities.js.map +1 -0
  35. package/convex/capabilities.ts +157 -0
  36. package/convex/chains.d.ts +68 -0
  37. package/convex/chains.d.ts.map +1 -0
  38. package/convex/chains.js +1105 -0
  39. package/convex/chains.js.map +1 -0
  40. package/convex/chains.ts +1318 -0
  41. package/convex/credits.d.ts +25 -0
  42. package/convex/credits.d.ts.map +1 -0
  43. package/convex/credits.js +186 -0
  44. package/convex/credits.js.map +1 -0
  45. package/convex/credits.ts +211 -0
  46. package/convex/crons.d.ts +3 -0
  47. package/convex/crons.d.ts.map +1 -0
  48. package/convex/crons.js +17 -0
  49. package/convex/crons.js.map +1 -0
  50. package/convex/crons.ts +28 -0
  51. package/convex/directCall.d.ts +72 -0
  52. package/convex/directCall.d.ts.map +1 -0
  53. package/convex/directCall.js +627 -0
  54. package/convex/directCall.js.map +1 -0
  55. package/convex/directCall.ts +678 -0
  56. package/convex/earnProgress.d.ts +58 -0
  57. package/convex/earnProgress.d.ts.map +1 -0
  58. package/convex/earnProgress.js +649 -0
  59. package/convex/earnProgress.js.map +1 -0
  60. package/convex/earnProgress.ts +753 -0
  61. package/convex/email.d.ts +14 -0
  62. package/convex/email.d.ts.map +1 -0
  63. package/convex/email.js +300 -0
  64. package/convex/email.js.map +1 -0
  65. package/convex/email.ts +329 -0
  66. package/convex/feedback.d.ts +7 -0
  67. package/convex/feedback.d.ts.map +1 -0
  68. package/convex/feedback.js +227 -0
  69. package/convex/feedback.js.map +1 -0
  70. package/convex/feedback.ts +265 -0
  71. package/convex/http.d.ts +3 -0
  72. package/convex/http.d.ts.map +1 -0
  73. package/convex/http.js +1405 -0
  74. package/convex/http.js.map +1 -0
  75. package/convex/http.ts +1577 -0
  76. package/convex/inbound.d.ts +2 -0
  77. package/convex/inbound.d.ts.map +1 -0
  78. package/convex/inbound.js +32 -0
  79. package/convex/inbound.js.map +1 -0
  80. package/convex/inbound.ts +32 -0
  81. package/convex/logs.d.ts +48 -0
  82. package/convex/logs.d.ts.map +1 -0
  83. package/convex/logs.js +592 -0
  84. package/convex/logs.js.map +1 -0
  85. package/convex/logs.ts +662 -0
  86. package/convex/mou.d.ts +6 -0
  87. package/convex/mou.d.ts.map +1 -0
  88. package/convex/mou.js +82 -0
  89. package/convex/mou.js.map +1 -0
  90. package/convex/mou.ts +91 -0
  91. package/convex/providerKeys.d.ts +31 -0
  92. package/convex/providerKeys.d.ts.map +1 -0
  93. package/convex/providerKeys.js +257 -0
  94. package/convex/providerKeys.js.map +1 -0
  95. package/convex/providerKeys.ts +289 -0
  96. package/convex/providers.d.ts +32 -0
  97. package/convex/providers.d.ts.map +1 -0
  98. package/convex/providers.js +814 -0
  99. package/convex/providers.js.map +1 -0
  100. package/convex/providers.ts +909 -0
  101. package/convex/purchases.d.ts +7 -0
  102. package/convex/purchases.d.ts.map +1 -0
  103. package/convex/purchases.js +157 -0
  104. package/convex/purchases.js.map +1 -0
  105. package/convex/purchases.ts +183 -0
  106. package/convex/ratelimit.d.ts +4 -0
  107. package/convex/ratelimit.d.ts.map +1 -0
  108. package/convex/ratelimit.js +91 -0
  109. package/convex/ratelimit.js.map +1 -0
  110. package/convex/ratelimit.ts +104 -0
  111. package/convex/schema.ts +805 -0
  112. package/convex/searchLogs.d.ts +4 -0
  113. package/convex/searchLogs.d.ts.map +1 -0
  114. package/convex/searchLogs.js +129 -0
  115. package/convex/searchLogs.js.map +1 -0
  116. package/convex/searchLogs.ts +146 -0
  117. package/convex/seedAPILayerAPIs.d.ts +7 -0
  118. package/convex/seedAPILayerAPIs.d.ts.map +1 -0
  119. package/convex/seedAPILayerAPIs.js +177 -0
  120. package/convex/seedAPILayerAPIs.js.map +1 -0
  121. package/convex/seedAPILayerAPIs.ts +191 -0
  122. package/convex/seedDirectCallConfigs.d.ts +2 -0
  123. package/convex/seedDirectCallConfigs.d.ts.map +1 -0
  124. package/convex/seedDirectCallConfigs.js +324 -0
  125. package/convex/seedDirectCallConfigs.js.map +1 -0
  126. package/convex/seedDirectCallConfigs.ts +336 -0
  127. package/convex/seedPratham.d.ts +6 -0
  128. package/convex/seedPratham.d.ts.map +1 -0
  129. package/convex/seedPratham.js +150 -0
  130. package/convex/seedPratham.js.map +1 -0
  131. package/convex/seedPratham.ts +161 -0
  132. package/convex/spendAlerts.d.ts +36 -0
  133. package/convex/spendAlerts.d.ts.map +1 -0
  134. package/convex/spendAlerts.js +380 -0
  135. package/convex/spendAlerts.js.map +1 -0
  136. package/convex/spendAlerts.ts +442 -0
  137. package/convex/stripeActions.d.ts +19 -0
  138. package/convex/stripeActions.d.ts.map +1 -0
  139. package/convex/stripeActions.js +411 -0
  140. package/convex/stripeActions.js.map +1 -0
  141. package/convex/stripeActions.ts +512 -0
  142. package/convex/teams.d.ts +21 -0
  143. package/convex/teams.d.ts.map +1 -0
  144. package/convex/teams.js +215 -0
  145. package/convex/teams.js.map +1 -0
  146. package/convex/teams.ts +243 -0
  147. package/convex/telemetry.d.ts +4 -0
  148. package/convex/telemetry.d.ts.map +1 -0
  149. package/convex/telemetry.js +74 -0
  150. package/convex/telemetry.js.map +1 -0
  151. package/convex/telemetry.ts +81 -0
  152. package/convex/tsconfig.json +25 -0
  153. package/convex/updateAPIStatus.d.ts +6 -0
  154. package/convex/updateAPIStatus.d.ts.map +1 -0
  155. package/convex/updateAPIStatus.js +40 -0
  156. package/convex/updateAPIStatus.js.map +1 -0
  157. package/convex/updateAPIStatus.ts +45 -0
  158. package/convex/usage.d.ts +27 -0
  159. package/convex/usage.d.ts.map +1 -0
  160. package/convex/usage.js +229 -0
  161. package/convex/usage.js.map +1 -0
  162. package/convex/usage.ts +260 -0
  163. package/convex/waitlist.d.ts +4 -0
  164. package/convex/waitlist.d.ts.map +1 -0
  165. package/convex/waitlist.js +49 -0
  166. package/convex/waitlist.js.map +1 -0
  167. package/convex/waitlist.ts +55 -0
  168. package/convex/webhooks.d.ts +12 -0
  169. package/convex/webhooks.d.ts.map +1 -0
  170. package/convex/webhooks.js +410 -0
  171. package/convex/webhooks.js.map +1 -0
  172. package/convex/webhooks.ts +494 -0
  173. package/convex/workspaces.d.ts +31 -0
  174. package/convex/workspaces.d.ts.map +1 -0
  175. package/convex/workspaces.js +975 -0
  176. package/convex/workspaces.js.map +1 -0
  177. package/convex/workspaces.ts +1130 -0
  178. package/dist/bin.js +0 -0
  179. package/dist/index.js +9 -0
  180. package/dist/index.js.map +1 -1
  181. package/package.json +1 -1
  182. package/src/index.ts +10 -0
  183. package/dist/chain-types.d.ts +0 -187
  184. package/dist/chain-types.d.ts.map +0 -1
  185. package/dist/chain-types.js +0 -33
  186. package/dist/chain-types.js.map +0 -1
  187. package/dist/registry/apis.json.bak +0 -248811
  188. package/dist/src/bin.js +0 -17
  189. package/dist/src/capability-router.js +0 -240
  190. package/dist/src/chainExecutor.js +0 -451
  191. package/dist/src/chainResolver.js +0 -518
  192. package/dist/src/cli/commands/doctor.js +0 -324
  193. package/dist/src/cli/commands/mcp-install.js +0 -255
  194. package/dist/src/cli/commands/restore.js +0 -259
  195. package/dist/src/cli/commands/setup.js +0 -205
  196. package/dist/src/cli/commands/uninstall.js +0 -188
  197. package/dist/src/cli/index.js +0 -111
  198. package/dist/src/cli.js +0 -302
  199. package/dist/src/confirmation.js +0 -240
  200. package/dist/src/credentials.js +0 -357
  201. package/dist/src/credits.js +0 -260
  202. package/dist/src/crypto.js +0 -66
  203. package/dist/src/discovery.js +0 -504
  204. package/dist/src/enterprise/env.js +0 -123
  205. package/dist/src/enterprise/script-generator.js +0 -460
  206. package/dist/src/execute-dynamic.js +0 -473
  207. package/dist/src/execute.js +0 -1727
  208. package/dist/src/index.js +0 -2062
  209. package/dist/src/metered.js +0 -80
  210. package/dist/src/open-apis.js +0 -276
  211. package/dist/src/proxy.js +0 -28
  212. package/dist/src/session.js +0 -86
  213. package/dist/src/stripe.js +0 -407
  214. package/dist/src/telemetry.js +0 -49
  215. package/dist/src/types.js +0 -2
  216. package/dist/src/utils/backup.js +0 -181
  217. package/dist/src/utils/config.js +0 -220
  218. package/dist/src/utils/os.js +0 -105
  219. package/dist/src/utils/paths.js +0 -159
@@ -0,0 +1,805 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+
4
+ export default defineSchema({
5
+ // Credits per agent
6
+ agentCredits: defineTable({
7
+ agentId: v.string(),
8
+ balanceUsd: v.number(),
9
+ currency: v.string(),
10
+ createdAt: v.number(),
11
+ updatedAt: v.number(),
12
+ }).index("by_agentId", ["agentId"]),
13
+
14
+ // Purchases (API access bought by agents)
15
+ purchases: defineTable({
16
+ agentId: v.string(),
17
+ providerId: v.string(),
18
+ amountUsd: v.number(),
19
+ creditsGranted: v.number(),
20
+ status: v.string(), // active, exhausted, refunded
21
+ credentials: v.optional(v.any()),
22
+ createdAt: v.number(),
23
+ })
24
+ .index("by_agentId", ["agentId"])
25
+ .index("by_providerId", ["providerId"])
26
+ .index("by_agentId_providerId", ["agentId", "providerId"]),
27
+
28
+ // Usage tracking per purchase
29
+ usage: defineTable({
30
+ purchaseId: v.id("purchases"),
31
+ providerId: v.string(),
32
+ unitsUsed: v.number(),
33
+ unitsRemaining: v.number(),
34
+ costIncurredUsd: v.number(),
35
+ lastUsedAt: v.number(),
36
+ })
37
+ .index("by_purchaseId", ["purchaseId"])
38
+ .index("by_providerId", ["providerId"]),
39
+
40
+ // ============================================
41
+ // WORKSPACE TABLES (MCP Agent Authentication)
42
+ // ============================================
43
+
44
+ // Workspaces (agent owner accounts)
45
+ workspaces: defineTable({
46
+ email: v.string(),
47
+ workspaceName: v.optional(v.string()), // Display name (e.g., "APILayer", "My Team")
48
+ passwordHash: v.optional(v.string()),
49
+ status: v.string(), // "pending" | "active" | "suspended"
50
+ tier: v.string(), // "free" | "pro" | "enterprise" | "backer"
51
+ usageCount: v.number(), // total API calls made (lifetime)
52
+ usageLimit: v.number(), // max API calls for tier
53
+ // Weekly usage (resets every Monday 00:00 UTC)
54
+ weeklyUsageCount: v.optional(v.number()), // calls this week
55
+ weeklyUsageLimit: v.optional(v.number()), // 50 for free, unlimited for backer
56
+ lastWeeklyResetAt: v.optional(v.number()), // timestamp of last reset
57
+ // Hourly rate limit
58
+ hourlyUsageCount: v.optional(v.number()), // calls this hour
59
+ lastHourlyResetAt: v.optional(v.number()), // timestamp of last hourly reset
60
+ // Backer status (Founding Backer = unlimited until end of 2026)
61
+ backerUntil: v.optional(v.number()), // timestamp when backer status expires
62
+ // Main agent identification
63
+ mainAgentId: v.optional(v.string()), // UUID, auto-generated on first call
64
+ mainAgentName: v.optional(v.string()), // Auto-generated name (e.g., "Crimson Phoenix")
65
+ // AI Backend tracking
66
+ aiBackend: v.optional(v.string()), // "claude-3-opus", "gpt-4", etc.
67
+ aiBackendLastSeen: v.optional(v.number()), // timestamp of last AI backend header
68
+ // Stripe billing fields
69
+ stripeCustomerId: v.optional(v.string()),
70
+ stripeSubscriptionId: v.optional(v.string()),
71
+ billingPlan: v.optional(v.string()), // "free" | "usage_based" | "starter" | "pro" | "scale"
72
+ creditBalance: v.optional(v.number()), // prepaid credits in cents
73
+ lastBillingDate: v.optional(v.number()),
74
+ // Payment method fields
75
+ hasPaymentMethod: v.optional(v.boolean()),
76
+ paymentMethodType: v.optional(v.string()),
77
+ cardBrand: v.optional(v.string()),
78
+ cardLast4: v.optional(v.string()),
79
+ // Referral fields
80
+ referralCode: v.optional(v.string()), // CLAW-XXXXXX format
81
+ referredBy: v.optional(v.id("workspaces")), // who referred this user
82
+ // Budget & Spend Alerts (PRD 2.6)
83
+ budgetCap: v.optional(v.number()), // Monthly budget cap in USD cents (null = unlimited)
84
+ budgetAlertSentAt: v.optional(v.number()), // When 80% alert was last sent (resets monthly)
85
+ pauseOnBudgetExceeded: v.optional(v.boolean()), // If true, block execution when budget exceeded
86
+ monthlySpendCents: v.optional(v.number()), // Current month's spend in cents
87
+ lastSpendResetAt: v.optional(v.number()), // When monthly spend was last reset
88
+ // Activity tracking
89
+ lastActiveAt: v.optional(v.number()), // Last API call timestamp (main agent)
90
+ createdAt: v.number(),
91
+ updatedAt: v.number(),
92
+ })
93
+ .index("by_email", ["email"])
94
+ .index("by_stripeCustomerId", ["stripeCustomerId"])
95
+ .index("by_stripeSubscriptionId", ["stripeSubscriptionId"])
96
+ .index("by_status", ["status"])
97
+ .index("by_referralCode", ["referralCode"])
98
+ .index("by_mainAgentId", ["mainAgentId"]),
99
+
100
+ // Invoices (Stripe invoice records)
101
+ invoices: defineTable({
102
+ workspaceId: v.id("workspaces"),
103
+ stripeInvoiceId: v.string(),
104
+ amount: v.number(), // in cents
105
+ status: v.string(), // "paid" | "pending" | "failed" | "void"
106
+ periodStart: v.number(),
107
+ periodEnd: v.number(),
108
+ callCount: v.number(),
109
+ pdfUrl: v.optional(v.string()),
110
+ createdAt: v.number(),
111
+ })
112
+ .index("by_workspaceId", ["workspaceId"])
113
+ .index("by_stripeInvoiceId", ["stripeInvoiceId"])
114
+ .index("by_workspaceId_createdAt", ["workspaceId", "createdAt"]),
115
+
116
+ // Usage records (daily aggregation for billing)
117
+ usageRecords: defineTable({
118
+ workspaceId: v.id("workspaces"),
119
+ date: v.string(), // "2026-02-28" format
120
+ callCount: v.number(),
121
+ reportedToStripe: v.boolean(),
122
+ stripeUsageRecordId: v.optional(v.string()),
123
+ createdAt: v.number(),
124
+ updatedAt: v.number(),
125
+ })
126
+ .index("by_workspaceId", ["workspaceId"])
127
+ .index("by_date", ["date"])
128
+ .index("by_workspaceId_date", ["workspaceId", "date"])
129
+ .index("by_reportedToStripe", ["reportedToStripe"]),
130
+
131
+ // Agent sessions (for MCP server authentication)
132
+ agentSessions: defineTable({
133
+ workspaceId: v.id("workspaces"),
134
+ sessionToken: v.string(),
135
+ fingerprint: v.optional(v.string()), // machine fingerprint
136
+ customName: v.optional(v.string()), // user-defined name
137
+ lastUsedAt: v.number(),
138
+ createdAt: v.number(),
139
+ })
140
+ .index("by_sessionToken", ["sessionToken"])
141
+ .index("by_workspaceId", ["workspaceId"]),
142
+
143
+ // Agents — one per unique (fingerprint, mcpClient) pair
144
+ // An agent = an MCP client installation, NOT a login session
145
+ agents: defineTable({
146
+ fingerprint: v.string(), // hostname:username
147
+ mcpClient: v.string(), // "claude-desktop" | "claude-code" | "cursor" | "windsurf" | "cline" | "continue" | "unknown"
148
+ workspaceId: v.id("workspaces"), // always linked — auto-created on first call
149
+ name: v.optional(v.string()), // auto-generated or user-set
150
+ aiBackend: v.optional(v.string()), // "claude-3-opus" etc
151
+ platform: v.optional(v.string()), // "darwin" | "linux" | "win32"
152
+ callCount: v.number(),
153
+ firstSeenAt: v.number(),
154
+ lastActiveAt: v.number(),
155
+ })
156
+ .index("by_fingerprint_client", ["fingerprint", "mcpClient"])
157
+ .index("by_workspaceId", ["workspaceId"])
158
+ .index("by_lastActiveAt", ["lastActiveAt"])
159
+ .index("by_mcpClient", ["mcpClient"]),
160
+
161
+ // Subagent tracking (tasks spawned by main agent)
162
+ subagents: defineTable({
163
+ workspaceId: v.id("workspaces"),
164
+ subagentId: v.string(), // from X-APIClaw-Subagent header
165
+ name: v.optional(v.string()), // optional display name
166
+ description: v.optional(v.string()), // user-provided description
167
+ aiBackend: v.optional(v.string()), // "claude-3-opus", "gpt-4", etc.
168
+ isRegistered: v.optional(v.boolean()), // true if pre-registered (not implicit)
169
+ callCount: v.number(),
170
+ firstSeenAt: v.number(),
171
+ lastActiveAt: v.number(),
172
+ })
173
+ .index("by_workspaceId", ["workspaceId"])
174
+ .index("by_workspaceId_subagentId", ["workspaceId", "subagentId"])
175
+ .index("by_lastActiveAt", ["lastActiveAt"]),
176
+
177
+ // Search logs (analytics for workspace searches)
178
+ searchLogs: defineTable({
179
+ workspaceId: v.id("workspaces"),
180
+ subagentId: v.optional(v.string()),
181
+ query: v.string(),
182
+ resultCount: v.number(),
183
+ hasResults: v.boolean(),
184
+ matchedProviders: v.optional(v.array(v.string())),
185
+ responseTimeMs: v.number(),
186
+ timestamp: v.number(),
187
+ })
188
+ .index("by_workspaceId", ["workspaceId"])
189
+ .index("by_timestamp", ["timestamp"])
190
+ .index("by_hasResults", ["hasResults"])
191
+ .index("by_workspaceId_timestamp", ["workspaceId", "timestamp"]),
192
+
193
+ // Workspace team members (invite-based access)
194
+ workspaceMembers: defineTable({
195
+ workspaceId: v.id("workspaces"),
196
+ email: v.string(),
197
+ role: v.union(v.literal("owner"), v.literal("admin"), v.literal("member")),
198
+ invitedBy: v.optional(v.string()), // email of inviter
199
+ inviteToken: v.optional(v.string()),
200
+ status: v.union(v.literal("pending"), v.literal("active"), v.literal("revoked")),
201
+ createdAt: v.number(),
202
+ acceptedAt: v.optional(v.number()),
203
+ })
204
+ .index("by_workspaceId", ["workspaceId"])
205
+ .index("by_email", ["email"])
206
+ .index("by_inviteToken", ["inviteToken"])
207
+ .index("by_workspaceId_email", ["workspaceId", "email"]),
208
+
209
+ // Magic links for workspace email verification
210
+ workspaceMagicLinks: defineTable({
211
+ email: v.string(),
212
+ token: v.string(),
213
+ sessionFingerprint: v.optional(v.string()),
214
+ expiresAt: v.number(),
215
+ usedAt: v.optional(v.number()),
216
+ createdAt: v.number(),
217
+ })
218
+ .index("by_token", ["token"])
219
+ .index("by_email", ["email"]),
220
+
221
+ // Credit top-ups (from Stripe payments)
222
+ creditTopups: defineTable({
223
+ agentId: v.string(),
224
+ stripePaymentIntentId: v.optional(v.string()),
225
+ stripeSessionId: v.optional(v.string()),
226
+ amountUsd: v.number(),
227
+ creditsGranted: v.number(),
228
+ packageType: v.string(), // starter, growth, scale
229
+ status: v.string(), // pending, completed, failed
230
+ createdAt: v.number(),
231
+ completedAt: v.optional(v.number()),
232
+ })
233
+ .index("by_agentId", ["agentId"])
234
+ .index("by_stripeSessionId", ["stripeSessionId"])
235
+ .index("by_stripePaymentIntentId", ["stripePaymentIntentId"]),
236
+
237
+ // ============================================
238
+ // PROVIDER TABLES (for provider dashboard)
239
+ // ============================================
240
+
241
+ // API Providers (companies/individuals offering APIs)
242
+ providers: defineTable({
243
+ email: v.string(),
244
+ name: v.string(),
245
+ company: v.optional(v.string()),
246
+ website: v.optional(v.string()),
247
+ avatarUrl: v.optional(v.string()),
248
+ stripeConnectId: v.optional(v.string()), // for payouts
249
+ stripeOnboardingComplete: v.optional(v.boolean()),
250
+ status: v.string(), // pending, approved, rejected, suspended
251
+ createdAt: v.number(),
252
+ updatedAt: v.number(),
253
+ approvedAt: v.optional(v.number()),
254
+ })
255
+ .index("by_email", ["email"])
256
+ .index("by_stripeConnectId", ["stripeConnectId"])
257
+ .index("by_status", ["status"]),
258
+
259
+ // APIs listed by providers (self-service onboarding)
260
+ providerAPIs: defineTable({
261
+ providerId: v.optional(v.id("providers")), // legacy — prefer workspaceId
262
+ workspaceId: v.optional(v.id("workspaces")), // new — workspace owns this API
263
+ name: v.string(),
264
+ description: v.string(),
265
+ category: v.string(),
266
+ openApiUrl: v.optional(v.string()),
267
+ docsUrl: v.optional(v.string()),
268
+ pricingModel: v.string(), // free, freemium, paid
269
+ pricingNotes: v.optional(v.string()),
270
+ status: v.string(), // active, paused
271
+ createdAt: v.number(),
272
+ approvedAt: v.optional(v.number()),
273
+ // Analytics
274
+ discoveryCount: v.optional(v.number()),
275
+ lastDiscoveredAt: v.optional(v.number()),
276
+ })
277
+ .index("by_providerId", ["providerId"])
278
+ .index("by_workspaceId", ["workspaceId"])
279
+ .index("by_category", ["category"])
280
+ .index("by_status", ["status"])
281
+ .index("by_status_category", ["status", "category"]),
282
+
283
+ // APIs listed by providers (for full dashboard)
284
+ apis: defineTable({
285
+ providerId: v.id("providers"),
286
+ name: v.string(),
287
+ description: v.string(),
288
+ category: v.string(),
289
+ icon: v.optional(v.string()), // emoji or URL
290
+ baseUrl: v.string(),
291
+ docsUrl: v.optional(v.string()),
292
+ authType: v.string(), // api_key, oauth, basic, bearer
293
+ pricingModel: v.string(), // free, per_call, monthly, credits
294
+ pricePerCall: v.optional(v.number()), // in USD cents
295
+ monthlyPrice: v.optional(v.number()), // in USD cents
296
+ rateLimitPerMinute: v.optional(v.number()),
297
+ regions: v.optional(v.array(v.string())),
298
+ tags: v.optional(v.array(v.string())),
299
+ status: v.string(), // active, paused, pending_review
300
+ isPublic: v.boolean(),
301
+ // Credentials (encrypted in production)
302
+ credentialTemplate: v.optional(v.any()),
303
+ createdAt: v.number(),
304
+ updatedAt: v.number(),
305
+ })
306
+ .index("by_providerId", ["providerId"])
307
+ .index("by_category", ["category"])
308
+ .index("by_status", ["status"]),
309
+
310
+ // API Calls / Usage logs (for analytics)
311
+ apiCalls: defineTable({
312
+ apiId: v.id("apis"),
313
+ providerId: v.id("providers"),
314
+ agentId: v.string(),
315
+ endpoint: v.optional(v.string()),
316
+ method: v.optional(v.string()),
317
+ statusCode: v.optional(v.number()),
318
+ latencyMs: v.optional(v.number()),
319
+ costUsd: v.number(), // cost in USD (fractional)
320
+ region: v.optional(v.string()),
321
+ timestamp: v.number(),
322
+ })
323
+ .index("by_apiId", ["apiId"])
324
+ .index("by_providerId", ["providerId"])
325
+ .index("by_agentId", ["agentId"])
326
+ .index("by_timestamp", ["timestamp"])
327
+ .index("by_providerId_timestamp", ["providerId", "timestamp"]),
328
+
329
+ // Provider Payouts
330
+ payouts: defineTable({
331
+ providerId: v.id("providers"),
332
+ amountUsd: v.number(),
333
+ status: v.string(), // pending, processing, completed, failed
334
+ stripePayoutId: v.optional(v.string()),
335
+ periodStart: v.number(),
336
+ periodEnd: v.number(),
337
+ createdAt: v.number(),
338
+ completedAt: v.optional(v.number()),
339
+ })
340
+ .index("by_providerId", ["providerId"])
341
+ .index("by_status", ["status"]),
342
+
343
+ // Magic link tokens for email auth
344
+ magicLinks: defineTable({
345
+ email: v.string(),
346
+ token: v.string(),
347
+ expiresAt: v.number(),
348
+ usedAt: v.optional(v.number()),
349
+ createdAt: v.number(),
350
+ })
351
+ .index("by_token", ["token"])
352
+ .index("by_email", ["email"]),
353
+
354
+ // Sessions for authenticated providers
355
+ sessions: defineTable({
356
+ providerId: v.id("providers"),
357
+ token: v.string(),
358
+ expiresAt: v.number(),
359
+ createdAt: v.number(),
360
+ })
361
+ .index("by_token", ["token"])
362
+ .index("by_providerId", ["providerId"]),
363
+
364
+ // Rate limiting
365
+ rateLimits: defineTable({
366
+ key: v.string(),
367
+ identifier: v.string(),
368
+ action: v.string(),
369
+ count: v.number(),
370
+ hourBucket: v.number(),
371
+ createdAt: v.number(),
372
+ })
373
+ .index("by_key", ["key"])
374
+ .index("by_identifier", ["identifier"]),
375
+
376
+ // Usage analytics
377
+ analytics: defineTable({
378
+ event: v.string(), // "discovery", "instant", "search_query"
379
+ provider: v.optional(v.string()),
380
+ query: v.optional(v.string()),
381
+ identifier: v.string(),
382
+ workspaceId: v.optional(v.id("workspaces")), // Claimed workspace (null = anonymous)
383
+ metadata: v.optional(v.any()),
384
+ timestamp: v.number(),
385
+ })
386
+ .index("by_event", ["event"])
387
+ .index("by_timestamp", ["timestamp"])
388
+ .index("by_provider", ["provider"])
389
+ .index("by_workspaceId", ["workspaceId"])
390
+ .index("by_identifier", ["identifier"]),
391
+
392
+ // MCP Server telemetry (anonymous usage tracking)
393
+ telemetry: defineTable({
394
+ type: v.string(), // "startup", "search", "execute", "discovery"
395
+ query: v.optional(v.string()),
396
+ apiId: v.optional(v.string()),
397
+ resultCount: v.optional(v.number()),
398
+ responseTimeMs: v.optional(v.number()),
399
+ version: v.string(),
400
+ platform: v.string(),
401
+ nodeVersion: v.string(),
402
+ timestamp: v.number(),
403
+ })
404
+ .index("by_type", ["type"])
405
+ .index("by_timestamp", ["timestamp"]),
406
+
407
+ // ============================================
408
+ // SELF-SERVICE DIRECT CALL TABLES
409
+ // ============================================
410
+
411
+ // Provider Direct Call configuration (master key, limits, pricing)
412
+ providerDirectCall: defineTable({
413
+ providerId: v.id("providers"),
414
+ apiId: v.optional(v.id("providerAPIs")),
415
+ baseUrl: v.string(),
416
+ authType: v.string(), // "bearer" | "basic" | "api_key" | "none"
417
+ authHeader: v.string(), // e.g. "Authorization", "X-API-Key"
418
+ authPrefix: v.string(), // e.g. "Bearer ", "Basic ", ""
419
+ encryptedMasterKey: v.string(),
420
+ rateLimitPerUser: v.number(), // requests per minute per user
421
+ rateLimitPerDay: v.number(), // requests per day per user
422
+ pricePerRequest: v.number(), // in USD cents
423
+ status: v.string(), // "draft" | "testing" | "live"
424
+ // Customer key passthrough settings
425
+ allowCustomerKeys: v.optional(v.boolean()), // Allow agents to pass their own API key (default: true)
426
+ requireCustomerKeys: v.optional(v.boolean()), // Require customer key, no master key fallback (default: false)
427
+ createdAt: v.number(),
428
+ updatedAt: v.number(),
429
+ publishedAt: v.optional(v.number()),
430
+ })
431
+ .index("by_providerId", ["providerId"])
432
+ .index("by_apiId", ["apiId"])
433
+ .index("by_status", ["status"]),
434
+
435
+ // Actions defined by providers for their Direct Call APIs
436
+ providerActions: defineTable({
437
+ directCallId: v.id("providerDirectCall"),
438
+ name: v.string(), // machine name, e.g. "send_sms"
439
+ displayName: v.string(), // human-friendly, e.g. "Send SMS"
440
+ description: v.string(),
441
+ method: v.string(), // "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
442
+ path: v.string(), // e.g. "/v1/messages" or "/users/{userId}"
443
+ params: v.array(v.object({
444
+ name: v.string(),
445
+ type: v.string(), // "string" | "number" | "boolean" | "object"
446
+ required: v.boolean(),
447
+ description: v.string(),
448
+ default: v.optional(v.any()),
449
+ in: v.string(), // "body" | "query" | "path"
450
+ })),
451
+ responseMapping: v.array(v.object({
452
+ name: v.string(),
453
+ path: v.string(), // JSON path, e.g. "data.id" or "results[0].name"
454
+ })),
455
+ enabled: v.boolean(),
456
+ // Confirmation settings for costly actions
457
+ requiresConfirmation: v.optional(v.boolean()), // If true, requires user confirmation before executing
458
+ estimatedCost: v.optional(v.string()), // Human-readable cost estimate, e.g. "~2-5 SEK per invoice"
459
+ createdAt: v.number(),
460
+ updatedAt: v.number(),
461
+ })
462
+ .index("by_directCallId", ["directCallId"])
463
+ .index("by_directCallId_name", ["directCallId", "name"]),
464
+
465
+ // Usage logs for Direct Call actions
466
+ usageLog: defineTable({
467
+ userId: v.string(),
468
+ providerId: v.id("providers"),
469
+ directCallId: v.id("providerDirectCall"),
470
+ actionName: v.string(),
471
+ timestamp: v.number(),
472
+ success: v.boolean(),
473
+ latencyMs: v.number(),
474
+ creditsUsed: v.number(), // in USD cents
475
+ errorMessage: v.optional(v.string()),
476
+ })
477
+ .index("by_userId", ["userId"])
478
+ .index("by_providerId", ["providerId"])
479
+ .index("by_directCallId", ["directCallId"])
480
+ .index("by_timestamp", ["timestamp"])
481
+ .index("by_userId_providerId", ["userId", "providerId"])
482
+ .index("by_userId_timestamp", ["userId", "timestamp"]),
483
+
484
+ // ============================================
485
+ // API LOGS (workspace/consumer view)
486
+ // ============================================
487
+
488
+ apiLogs: defineTable({
489
+ workspaceId: v.id("workspaces"),
490
+ sessionToken: v.string(),
491
+ subagentId: v.optional(v.string()),
492
+ provider: v.string(),
493
+ action: v.string(),
494
+ status: v.union(v.literal("success"), v.literal("error")),
495
+ latencyMs: v.number(),
496
+ errorMessage: v.optional(v.string()),
497
+ direction: v.optional(v.string()), // "outbound" (I called) or "inbound" (someone called my API)
498
+ callerWorkspaceId: v.optional(v.string()), // who made the call (for inbound logs)
499
+ createdAt: v.number(),
500
+ })
501
+ .index("by_workspaceId", ["workspaceId"])
502
+ .index("by_createdAt", ["createdAt"])
503
+ .index("by_workspaceId_createdAt", ["workspaceId", "createdAt"])
504
+ .index("by_subagentId", ["subagentId"])
505
+ .index("by_provider", ["provider"]),
506
+
507
+ // ============================================
508
+ // WAITLIST (for Direct Call provider leads)
509
+ // ============================================
510
+
511
+ waitlist: defineTable({
512
+ email: v.string(),
513
+ type: v.string(), // "provider" | "agent" | "general"
514
+ source: v.optional(v.string()), // "landing", "docs", etc.
515
+ createdAt: v.number(),
516
+ })
517
+ .index("by_email", ["email"])
518
+ .index("by_type", ["type"]),
519
+
520
+ // ============================================
521
+ // CAPABILITY LAYER (abstraction over providers)
522
+ // ============================================
523
+
524
+ // Capability definitions (sms, email, invoice, search, etc.)
525
+ capabilities: defineTable({
526
+ id: v.string(), // "sms", "email", "invoice"
527
+ name: v.string(), // "SMS Messaging"
528
+ description: v.string(),
529
+ category: v.string(), // "communication", "business", "ai"
530
+ standardParams: v.array(v.object({
531
+ name: v.string(),
532
+ type: v.string(), // "string" | "number" | "boolean"
533
+ required: v.boolean(),
534
+ description: v.string(),
535
+ default: v.optional(v.any()),
536
+ })),
537
+ createdAt: v.number(),
538
+ updatedAt: v.number(),
539
+ })
540
+ .index("by_capability_id", ["id"])
541
+ .index("by_category", ["category"]),
542
+
543
+ // Provider → Capability mappings (which providers offer which capabilities)
544
+ providerCapabilities: defineTable({
545
+ providerId: v.string(), // "46elks", "twilio"
546
+ capabilityId: v.string(), // "sms"
547
+ priority: v.number(), // 1 = primary, 2 = fallback
548
+ regions: v.array(v.string()), // ["SE", "EU", "US"]
549
+ pricePerUnit: v.number(), // in smallest currency unit (cents/öre)
550
+ currency: v.string(), // "SEK", "USD"
551
+ avgLatencyMs: v.number(),
552
+ paramMapping: v.any(), // Record<string, string> - capability param → provider param
553
+ enabled: v.boolean(),
554
+ healthStatus: v.string(), // "healthy" | "degraded" | "down"
555
+ lastHealthCheck: v.optional(v.number()),
556
+ createdAt: v.number(),
557
+ updatedAt: v.number(),
558
+ })
559
+ .index("by_providerId", ["providerId"])
560
+ .index("by_capabilityId", ["capabilityId"])
561
+ .index("by_capabilityId_enabled", ["capabilityId", "enabled"])
562
+ .index("by_healthStatus", ["healthStatus"]),
563
+
564
+ // Capability usage logs (for analytics and billing)
565
+ capabilityLogs: defineTable({
566
+ capabilityId: v.string(),
567
+ providerId: v.string(),
568
+ userId: v.string(),
569
+ action: v.string(),
570
+ success: v.boolean(),
571
+ fallbackUsed: v.boolean(),
572
+ fallbackReason: v.optional(v.string()),
573
+ latencyMs: v.number(),
574
+ cost: v.number(),
575
+ currency: v.string(),
576
+ timestamp: v.number(),
577
+ })
578
+ .index("by_capabilityId", ["capabilityId"])
579
+ .index("by_providerId", ["providerId"])
580
+ .index("by_userId", ["userId"])
581
+ .index("by_timestamp", ["timestamp"]),
582
+
583
+ // ============================================
584
+ // WEBHOOKS
585
+ // ============================================
586
+
587
+ webhooks: defineTable({
588
+ workspaceId: v.id("workspaces"),
589
+ url: v.string(),
590
+ events: v.array(v.string()),
591
+ secret: v.string(), // For signature verification
592
+ enabled: v.boolean(),
593
+ lastTriggeredAt: v.optional(v.number()),
594
+ lastStatus: v.optional(v.string()), // "success" | "failed"
595
+ failCount: v.number(),
596
+ createdAt: v.number(),
597
+ })
598
+ .index("by_workspaceId", ["workspaceId"]),
599
+
600
+ // ============================================
601
+ // BYOK - BRING YOUR OWN KEY
602
+ // ============================================
603
+
604
+ // User-provided API keys for providers
605
+ providerKeys: defineTable({
606
+ workspaceId: v.id("workspaces"),
607
+ provider: v.string(), // "brave_search", "openrouter", etc.
608
+ encryptedKey: v.string(), // Base64 encoded for MVP
609
+ keyHint: v.string(), // Last 4 chars for display
610
+ isCustom: v.boolean(), // true if custom provider (not built-in)
611
+ customConfig: v.optional(v.object({
612
+ baseUrl: v.string(),
613
+ authType: v.string(), // "bearer", "api_key", "basic"
614
+ authHeader: v.optional(v.string()), // e.g. "X-API-Key"
615
+ })),
616
+ createdAt: v.number(),
617
+ updatedAt: v.number(),
618
+ })
619
+ .index("by_workspaceId", ["workspaceId"])
620
+ .index("by_provider", ["workspaceId", "provider"]),
621
+
622
+ // ============================================
623
+ // EARN PROGRESS TRACKING
624
+ // ============================================
625
+
626
+ earnProgress: defineTable({
627
+ workspaceId: v.id("workspaces"),
628
+
629
+ // Usage tasks
630
+ firstDirectCall: v.boolean(),
631
+ firstDirectCallAt: v.optional(v.number()),
632
+
633
+ apisUsed: v.array(v.string()), // Track unique provider/action combos
634
+ apisUsedComplete: v.boolean(),
635
+
636
+ agentListed: v.boolean(),
637
+ agentListedAt: v.optional(v.number()),
638
+
639
+ apiListed: v.boolean(),
640
+ apiListedAt: v.optional(v.number()),
641
+
642
+ byokSetup: v.boolean(),
643
+ byokSetupAt: v.optional(v.number()),
644
+
645
+ // Growth tasks
646
+ githubStarred: v.boolean(),
647
+ githubStarredAt: v.optional(v.number()),
648
+
649
+ twitterFollowed: v.boolean(),
650
+ twitterFollowedAt: v.optional(v.number()),
651
+
652
+ // Referrals (tracked separately but stored here for convenience)
653
+ referralCount: v.number(),
654
+
655
+ // Calculated total
656
+ totalEarned: v.number(),
657
+
658
+ createdAt: v.number(),
659
+ updatedAt: v.number(),
660
+ })
661
+ .index("by_workspaceId", ["workspaceId"]),
662
+
663
+ // ============================================
664
+ // FEEDBACK SYSTEM
665
+ // ============================================
666
+
667
+ // ============================================
668
+ // CHAIN ORCHESTRATION TABLES
669
+ // ============================================
670
+
671
+ // Chain executions (main orchestration record)
672
+ chains: defineTable({
673
+ workspaceId: v.id("workspaces"),
674
+ // Chain definition
675
+ steps: v.array(v.any()), // Array of step definitions (raw, unresolved)
676
+ // Execution state
677
+ status: v.union(
678
+ v.literal("pending"),
679
+ v.literal("running"),
680
+ v.literal("completed"),
681
+ v.literal("failed"),
682
+ v.literal("paused")
683
+ ),
684
+ currentStep: v.number(), // Index of current step (0-based)
685
+ // Results storage
686
+ results: v.any(), // Record<stepId, result>
687
+ // Error tracking
688
+ error: v.optional(v.object({
689
+ stepId: v.string(),
690
+ code: v.string(),
691
+ message: v.string(),
692
+ retryAfter: v.optional(v.number()),
693
+ })),
694
+ // Execution options
695
+ continueOnError: v.optional(v.boolean()),
696
+ timeout: v.optional(v.number()), // ms
697
+ // Resume capability
698
+ resumeToken: v.optional(v.string()),
699
+ canResume: v.optional(v.boolean()),
700
+ // Cost tracking
701
+ totalCostCents: v.optional(v.number()),
702
+ totalLatencyMs: v.optional(v.number()),
703
+ // Timestamps
704
+ createdAt: v.number(),
705
+ startedAt: v.optional(v.number()),
706
+ completedAt: v.optional(v.number()),
707
+ })
708
+ .index("by_workspaceId", ["workspaceId"])
709
+ .index("by_status", ["status"])
710
+ .index("by_workspaceId_status", ["workspaceId", "status"])
711
+ .index("by_resumeToken", ["resumeToken"]),
712
+
713
+ // Chain templates (reusable chain definitions)
714
+ chainTemplates: defineTable({
715
+ workspaceId: v.id("workspaces"),
716
+ name: v.string(),
717
+ description: v.optional(v.string()),
718
+ // Input schema for the template
719
+ inputs: v.optional(v.any()), // JSON Schema for inputs
720
+ // Chain definition
721
+ chain: v.array(v.any()), // Array of step definitions
722
+ // Usage tracking
723
+ useCount: v.optional(v.number()),
724
+ lastUsedAt: v.optional(v.number()),
725
+ // Timestamps
726
+ createdAt: v.number(),
727
+ updatedAt: v.number(),
728
+ })
729
+ .index("by_workspaceId", ["workspaceId"])
730
+ .index("by_name", ["workspaceId", "name"]),
731
+
732
+ // Chain step executions (detailed trace per step)
733
+ chainExecutions: defineTable({
734
+ chainId: v.id("chains"),
735
+ stepId: v.string(), // The id from step definition
736
+ stepIndex: v.number(), // Position in chain
737
+ // Execution state
738
+ status: v.union(
739
+ v.literal("pending"),
740
+ v.literal("running"),
741
+ v.literal("completed"),
742
+ v.literal("failed"),
743
+ v.literal("skipped")
744
+ ),
745
+ // I/O
746
+ input: v.optional(v.any()), // Resolved params sent to provider
747
+ output: v.optional(v.any()), // Result from provider
748
+ // Metrics
749
+ latencyMs: v.optional(v.number()),
750
+ costCents: v.optional(v.number()),
751
+ // Error info
752
+ error: v.optional(v.object({
753
+ code: v.string(),
754
+ message: v.string(),
755
+ retryCount: v.optional(v.number()),
756
+ })),
757
+ // Parallel execution tracking
758
+ parallelGroup: v.optional(v.string()), // Group ID if part of parallel batch
759
+ // Timestamps
760
+ createdAt: v.number(),
761
+ startedAt: v.optional(v.number()),
762
+ completedAt: v.optional(v.number()),
763
+ })
764
+ .index("by_chainId", ["chainId"])
765
+ .index("by_chainId_stepId", ["chainId", "stepId"])
766
+ .index("by_chainId_stepIndex", ["chainId", "stepIndex"]),
767
+
768
+ // User feedback with voting
769
+ feedback: defineTable({
770
+ workspaceId: v.id("workspaces"),
771
+ type: v.union(v.literal("bug"), v.literal("feature"), v.literal("general")),
772
+ content: v.string(),
773
+ votes: v.number(),
774
+ votedBy: v.array(v.string()), // workspace IDs that voted
775
+ status: v.union(v.literal("new"), v.literal("reviewing"), v.literal("planned"), v.literal("shipped")),
776
+ createdAt: v.number(),
777
+ })
778
+ .index("by_workspaceId", ["workspaceId"])
779
+ .index("by_type", ["type"])
780
+ .index("by_status", ["status"])
781
+ .index("by_votes", ["votes"])
782
+ .index("by_createdAt", ["createdAt"]),
783
+
784
+ // ============================================
785
+ // MOU SIGNATURES
786
+ // ============================================
787
+
788
+ mouDocuments: defineTable({
789
+ partnerId: v.string(), // e.g., "apilayer"
790
+ partnerName: v.string(),
791
+ partnerEmail: v.string(),
792
+ partnerRepresentative: v.optional(v.string()),
793
+ documentHtml: v.optional(v.string()),
794
+ sections: v.optional(v.any()), // Alternative document format
795
+ status: v.string(), // "pending" | "signed"
796
+ signedAt: v.optional(v.number()),
797
+ signatureDataUrl: v.optional(v.string()), // base64 signature image
798
+ signerName: v.optional(v.string()),
799
+ signerTitle: v.optional(v.string()),
800
+ signerIp: v.optional(v.string()),
801
+ createdAt: v.number(),
802
+ })
803
+ .index("by_partnerId", ["partnerId"])
804
+ .index("by_status", ["status"]),
805
+ });