@nordsym/apiclaw 1.7.2 → 1.7.4

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 (230) 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 +38 -0
  82. package/convex/logs.d.ts.map +1 -0
  83. package/convex/logs.js +487 -0
  84. package/convex/logs.js.map +1 -0
  85. package/convex/logs.ts +550 -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 +802 -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/capability-router.js +1 -1
  180. package/dist/capability-router.js.map +1 -1
  181. package/dist/execute.d.ts +2 -0
  182. package/dist/execute.d.ts.map +1 -1
  183. package/dist/execute.js +18 -4
  184. package/dist/execute.js.map +1 -1
  185. package/dist/http-api.js +1 -1
  186. package/dist/http-api.js.map +1 -1
  187. package/dist/index.js +1 -1
  188. package/dist/index.js.map +1 -1
  189. package/dist/mcp-analytics.d.ts +32 -0
  190. package/dist/mcp-analytics.d.ts.map +1 -0
  191. package/dist/mcp-analytics.js +130 -0
  192. package/dist/mcp-analytics.js.map +1 -0
  193. package/package.json +1 -1
  194. package/dist/chain-types.d.ts +0 -187
  195. package/dist/chain-types.d.ts.map +0 -1
  196. package/dist/chain-types.js +0 -33
  197. package/dist/chain-types.js.map +0 -1
  198. package/dist/registry/apis.json.bak +0 -248811
  199. package/dist/src/bin.js +0 -17
  200. package/dist/src/capability-router.js +0 -240
  201. package/dist/src/chainExecutor.js +0 -451
  202. package/dist/src/chainResolver.js +0 -518
  203. package/dist/src/cli/commands/doctor.js +0 -324
  204. package/dist/src/cli/commands/mcp-install.js +0 -255
  205. package/dist/src/cli/commands/restore.js +0 -259
  206. package/dist/src/cli/commands/setup.js +0 -205
  207. package/dist/src/cli/commands/uninstall.js +0 -188
  208. package/dist/src/cli/index.js +0 -111
  209. package/dist/src/cli.js +0 -302
  210. package/dist/src/confirmation.js +0 -240
  211. package/dist/src/credentials.js +0 -357
  212. package/dist/src/credits.js +0 -260
  213. package/dist/src/crypto.js +0 -66
  214. package/dist/src/discovery.js +0 -504
  215. package/dist/src/enterprise/env.js +0 -123
  216. package/dist/src/enterprise/script-generator.js +0 -460
  217. package/dist/src/execute-dynamic.js +0 -473
  218. package/dist/src/execute.js +0 -1727
  219. package/dist/src/index.js +0 -2062
  220. package/dist/src/metered.js +0 -80
  221. package/dist/src/open-apis.js +0 -276
  222. package/dist/src/proxy.js +0 -28
  223. package/dist/src/session.js +0 -86
  224. package/dist/src/stripe.js +0 -407
  225. package/dist/src/telemetry.js +0 -49
  226. package/dist/src/types.js +0 -2
  227. package/dist/src/utils/backup.js +0 -181
  228. package/dist/src/utils/config.js +0 -220
  229. package/dist/src/utils/os.js +0 -105
  230. package/dist/src/utils/paths.js +0 -159
@@ -0,0 +1,802 @@
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()), // from X-APIClaw-Subagent header
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
+ createdAt: v.number(),
498
+ })
499
+ .index("by_workspaceId", ["workspaceId"])
500
+ .index("by_createdAt", ["createdAt"])
501
+ .index("by_workspaceId_createdAt", ["workspaceId", "createdAt"])
502
+ .index("by_subagentId", ["subagentId"]),
503
+
504
+ // ============================================
505
+ // WAITLIST (for Direct Call provider leads)
506
+ // ============================================
507
+
508
+ waitlist: defineTable({
509
+ email: v.string(),
510
+ type: v.string(), // "provider" | "agent" | "general"
511
+ source: v.optional(v.string()), // "landing", "docs", etc.
512
+ createdAt: v.number(),
513
+ })
514
+ .index("by_email", ["email"])
515
+ .index("by_type", ["type"]),
516
+
517
+ // ============================================
518
+ // CAPABILITY LAYER (abstraction over providers)
519
+ // ============================================
520
+
521
+ // Capability definitions (sms, email, invoice, search, etc.)
522
+ capabilities: defineTable({
523
+ id: v.string(), // "sms", "email", "invoice"
524
+ name: v.string(), // "SMS Messaging"
525
+ description: v.string(),
526
+ category: v.string(), // "communication", "business", "ai"
527
+ standardParams: v.array(v.object({
528
+ name: v.string(),
529
+ type: v.string(), // "string" | "number" | "boolean"
530
+ required: v.boolean(),
531
+ description: v.string(),
532
+ default: v.optional(v.any()),
533
+ })),
534
+ createdAt: v.number(),
535
+ updatedAt: v.number(),
536
+ })
537
+ .index("by_capability_id", ["id"])
538
+ .index("by_category", ["category"]),
539
+
540
+ // Provider → Capability mappings (which providers offer which capabilities)
541
+ providerCapabilities: defineTable({
542
+ providerId: v.string(), // "46elks", "twilio"
543
+ capabilityId: v.string(), // "sms"
544
+ priority: v.number(), // 1 = primary, 2 = fallback
545
+ regions: v.array(v.string()), // ["SE", "EU", "US"]
546
+ pricePerUnit: v.number(), // in smallest currency unit (cents/öre)
547
+ currency: v.string(), // "SEK", "USD"
548
+ avgLatencyMs: v.number(),
549
+ paramMapping: v.any(), // Record<string, string> - capability param → provider param
550
+ enabled: v.boolean(),
551
+ healthStatus: v.string(), // "healthy" | "degraded" | "down"
552
+ lastHealthCheck: v.optional(v.number()),
553
+ createdAt: v.number(),
554
+ updatedAt: v.number(),
555
+ })
556
+ .index("by_providerId", ["providerId"])
557
+ .index("by_capabilityId", ["capabilityId"])
558
+ .index("by_capabilityId_enabled", ["capabilityId", "enabled"])
559
+ .index("by_healthStatus", ["healthStatus"]),
560
+
561
+ // Capability usage logs (for analytics and billing)
562
+ capabilityLogs: defineTable({
563
+ capabilityId: v.string(),
564
+ providerId: v.string(),
565
+ userId: v.string(),
566
+ action: v.string(),
567
+ success: v.boolean(),
568
+ fallbackUsed: v.boolean(),
569
+ fallbackReason: v.optional(v.string()),
570
+ latencyMs: v.number(),
571
+ cost: v.number(),
572
+ currency: v.string(),
573
+ timestamp: v.number(),
574
+ })
575
+ .index("by_capabilityId", ["capabilityId"])
576
+ .index("by_providerId", ["providerId"])
577
+ .index("by_userId", ["userId"])
578
+ .index("by_timestamp", ["timestamp"]),
579
+
580
+ // ============================================
581
+ // WEBHOOKS
582
+ // ============================================
583
+
584
+ webhooks: defineTable({
585
+ workspaceId: v.id("workspaces"),
586
+ url: v.string(),
587
+ events: v.array(v.string()),
588
+ secret: v.string(), // For signature verification
589
+ enabled: v.boolean(),
590
+ lastTriggeredAt: v.optional(v.number()),
591
+ lastStatus: v.optional(v.string()), // "success" | "failed"
592
+ failCount: v.number(),
593
+ createdAt: v.number(),
594
+ })
595
+ .index("by_workspaceId", ["workspaceId"]),
596
+
597
+ // ============================================
598
+ // BYOK - BRING YOUR OWN KEY
599
+ // ============================================
600
+
601
+ // User-provided API keys for providers
602
+ providerKeys: defineTable({
603
+ workspaceId: v.id("workspaces"),
604
+ provider: v.string(), // "brave_search", "openrouter", etc.
605
+ encryptedKey: v.string(), // Base64 encoded for MVP
606
+ keyHint: v.string(), // Last 4 chars for display
607
+ isCustom: v.boolean(), // true if custom provider (not built-in)
608
+ customConfig: v.optional(v.object({
609
+ baseUrl: v.string(),
610
+ authType: v.string(), // "bearer", "api_key", "basic"
611
+ authHeader: v.optional(v.string()), // e.g. "X-API-Key"
612
+ })),
613
+ createdAt: v.number(),
614
+ updatedAt: v.number(),
615
+ })
616
+ .index("by_workspaceId", ["workspaceId"])
617
+ .index("by_provider", ["workspaceId", "provider"]),
618
+
619
+ // ============================================
620
+ // EARN PROGRESS TRACKING
621
+ // ============================================
622
+
623
+ earnProgress: defineTable({
624
+ workspaceId: v.id("workspaces"),
625
+
626
+ // Usage tasks
627
+ firstDirectCall: v.boolean(),
628
+ firstDirectCallAt: v.optional(v.number()),
629
+
630
+ apisUsed: v.array(v.string()), // Track unique provider/action combos
631
+ apisUsedComplete: v.boolean(),
632
+
633
+ agentListed: v.boolean(),
634
+ agentListedAt: v.optional(v.number()),
635
+
636
+ apiListed: v.boolean(),
637
+ apiListedAt: v.optional(v.number()),
638
+
639
+ byokSetup: v.boolean(),
640
+ byokSetupAt: v.optional(v.number()),
641
+
642
+ // Growth tasks
643
+ githubStarred: v.boolean(),
644
+ githubStarredAt: v.optional(v.number()),
645
+
646
+ twitterFollowed: v.boolean(),
647
+ twitterFollowedAt: v.optional(v.number()),
648
+
649
+ // Referrals (tracked separately but stored here for convenience)
650
+ referralCount: v.number(),
651
+
652
+ // Calculated total
653
+ totalEarned: v.number(),
654
+
655
+ createdAt: v.number(),
656
+ updatedAt: v.number(),
657
+ })
658
+ .index("by_workspaceId", ["workspaceId"]),
659
+
660
+ // ============================================
661
+ // FEEDBACK SYSTEM
662
+ // ============================================
663
+
664
+ // ============================================
665
+ // CHAIN ORCHESTRATION TABLES
666
+ // ============================================
667
+
668
+ // Chain executions (main orchestration record)
669
+ chains: defineTable({
670
+ workspaceId: v.id("workspaces"),
671
+ // Chain definition
672
+ steps: v.array(v.any()), // Array of step definitions (raw, unresolved)
673
+ // Execution state
674
+ status: v.union(
675
+ v.literal("pending"),
676
+ v.literal("running"),
677
+ v.literal("completed"),
678
+ v.literal("failed"),
679
+ v.literal("paused")
680
+ ),
681
+ currentStep: v.number(), // Index of current step (0-based)
682
+ // Results storage
683
+ results: v.any(), // Record<stepId, result>
684
+ // Error tracking
685
+ error: v.optional(v.object({
686
+ stepId: v.string(),
687
+ code: v.string(),
688
+ message: v.string(),
689
+ retryAfter: v.optional(v.number()),
690
+ })),
691
+ // Execution options
692
+ continueOnError: v.optional(v.boolean()),
693
+ timeout: v.optional(v.number()), // ms
694
+ // Resume capability
695
+ resumeToken: v.optional(v.string()),
696
+ canResume: v.optional(v.boolean()),
697
+ // Cost tracking
698
+ totalCostCents: v.optional(v.number()),
699
+ totalLatencyMs: v.optional(v.number()),
700
+ // Timestamps
701
+ createdAt: v.number(),
702
+ startedAt: v.optional(v.number()),
703
+ completedAt: v.optional(v.number()),
704
+ })
705
+ .index("by_workspaceId", ["workspaceId"])
706
+ .index("by_status", ["status"])
707
+ .index("by_workspaceId_status", ["workspaceId", "status"])
708
+ .index("by_resumeToken", ["resumeToken"]),
709
+
710
+ // Chain templates (reusable chain definitions)
711
+ chainTemplates: defineTable({
712
+ workspaceId: v.id("workspaces"),
713
+ name: v.string(),
714
+ description: v.optional(v.string()),
715
+ // Input schema for the template
716
+ inputs: v.optional(v.any()), // JSON Schema for inputs
717
+ // Chain definition
718
+ chain: v.array(v.any()), // Array of step definitions
719
+ // Usage tracking
720
+ useCount: v.optional(v.number()),
721
+ lastUsedAt: v.optional(v.number()),
722
+ // Timestamps
723
+ createdAt: v.number(),
724
+ updatedAt: v.number(),
725
+ })
726
+ .index("by_workspaceId", ["workspaceId"])
727
+ .index("by_name", ["workspaceId", "name"]),
728
+
729
+ // Chain step executions (detailed trace per step)
730
+ chainExecutions: defineTable({
731
+ chainId: v.id("chains"),
732
+ stepId: v.string(), // The id from step definition
733
+ stepIndex: v.number(), // Position in chain
734
+ // Execution state
735
+ status: v.union(
736
+ v.literal("pending"),
737
+ v.literal("running"),
738
+ v.literal("completed"),
739
+ v.literal("failed"),
740
+ v.literal("skipped")
741
+ ),
742
+ // I/O
743
+ input: v.optional(v.any()), // Resolved params sent to provider
744
+ output: v.optional(v.any()), // Result from provider
745
+ // Metrics
746
+ latencyMs: v.optional(v.number()),
747
+ costCents: v.optional(v.number()),
748
+ // Error info
749
+ error: v.optional(v.object({
750
+ code: v.string(),
751
+ message: v.string(),
752
+ retryCount: v.optional(v.number()),
753
+ })),
754
+ // Parallel execution tracking
755
+ parallelGroup: v.optional(v.string()), // Group ID if part of parallel batch
756
+ // Timestamps
757
+ createdAt: v.number(),
758
+ startedAt: v.optional(v.number()),
759
+ completedAt: v.optional(v.number()),
760
+ })
761
+ .index("by_chainId", ["chainId"])
762
+ .index("by_chainId_stepId", ["chainId", "stepId"])
763
+ .index("by_chainId_stepIndex", ["chainId", "stepIndex"]),
764
+
765
+ // User feedback with voting
766
+ feedback: defineTable({
767
+ workspaceId: v.id("workspaces"),
768
+ type: v.union(v.literal("bug"), v.literal("feature"), v.literal("general")),
769
+ content: v.string(),
770
+ votes: v.number(),
771
+ votedBy: v.array(v.string()), // workspace IDs that voted
772
+ status: v.union(v.literal("new"), v.literal("reviewing"), v.literal("planned"), v.literal("shipped")),
773
+ createdAt: v.number(),
774
+ })
775
+ .index("by_workspaceId", ["workspaceId"])
776
+ .index("by_type", ["type"])
777
+ .index("by_status", ["status"])
778
+ .index("by_votes", ["votes"])
779
+ .index("by_createdAt", ["createdAt"]),
780
+
781
+ // ============================================
782
+ // MOU SIGNATURES
783
+ // ============================================
784
+
785
+ mouDocuments: defineTable({
786
+ partnerId: v.string(), // e.g., "apilayer"
787
+ partnerName: v.string(),
788
+ partnerEmail: v.string(),
789
+ partnerRepresentative: v.optional(v.string()),
790
+ documentHtml: v.optional(v.string()),
791
+ sections: v.optional(v.any()), // Alternative document format
792
+ status: v.string(), // "pending" | "signed"
793
+ signedAt: v.optional(v.number()),
794
+ signatureDataUrl: v.optional(v.string()), // base64 signature image
795
+ signerName: v.optional(v.string()),
796
+ signerTitle: v.optional(v.string()),
797
+ signerIp: v.optional(v.string()),
798
+ createdAt: v.number(),
799
+ })
800
+ .index("by_partnerId", ["partnerId"])
801
+ .index("by_status", ["status"]),
802
+ });