@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
package/convex/schema.ts DELETED
@@ -1,869 +0,0 @@
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" | "scale" | "usage_based" | "enterprise" | "partner"
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 paid tiers
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
- // Legacy field (no longer used)
61
- backerUntil: v.optional(v.number()),
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
- providerCostUsd: v.optional(v.float64()), // actual provider cost accumulated
122
- apiclawCostUsd: v.optional(v.float64()), // provider cost + 15% margin accumulated
123
- reportedToStripe: v.boolean(),
124
- stripeUsageRecordId: v.optional(v.string()),
125
- createdAt: v.number(),
126
- updatedAt: v.number(),
127
- })
128
- .index("by_workspaceId", ["workspaceId"])
129
- .index("by_date", ["date"])
130
- .index("by_workspaceId_date", ["workspaceId", "date"])
131
- .index("by_reportedToStripe", ["reportedToStripe"]),
132
-
133
- // Workspace API Keys (persistent keys for programmatic access)
134
- workspaceApiKeys: defineTable({
135
- workspaceId: v.id("workspaces"),
136
- key: v.string(), // "sk-claw-" + 48 random chars (hashed after creation)
137
- keyHash: v.string(), // SHA-256 hash for lookup (key itself not stored after first show)
138
- keyPrefix: v.string(), // "sk-claw-...last4" for display
139
- name: v.string(), // user label ("Production", "My Agent")
140
- lastUsedAt: v.optional(v.number()),
141
- createdAt: v.number(),
142
- revokedAt: v.optional(v.number()),
143
- })
144
- .index("by_keyHash", ["keyHash"])
145
- .index("by_workspaceId", ["workspaceId"]),
146
-
147
- // Agent sessions (for MCP server authentication)
148
- agentSessions: defineTable({
149
- workspaceId: v.id("workspaces"),
150
- sessionToken: v.string(),
151
- fingerprint: v.optional(v.string()), // machine fingerprint
152
- customName: v.optional(v.string()), // user-defined name
153
- lastUsedAt: v.number(),
154
- createdAt: v.number(),
155
- })
156
- .index("by_sessionToken", ["sessionToken"])
157
- .index("by_workspaceId", ["workspaceId"]),
158
-
159
- // Agents — one per unique (fingerprint, mcpClient) pair
160
- // An agent = an MCP client installation, NOT a login session
161
- agents: defineTable({
162
- fingerprint: v.string(), // hostname:username
163
- mcpClient: v.string(), // "claude-desktop" | "claude-code" | "cursor" | "windsurf" | "cline" | "continue" | "unknown"
164
- workspaceId: v.id("workspaces"), // always linked — auto-created on first call
165
- name: v.optional(v.string()), // auto-generated or user-set
166
- aiBackend: v.optional(v.string()), // "claude-3-opus" etc
167
- platform: v.optional(v.string()), // "darwin" | "linux" | "win32"
168
- callCount: v.number(),
169
- firstSeenAt: v.number(),
170
- lastActiveAt: v.number(),
171
- })
172
- .index("by_fingerprint_client", ["fingerprint", "mcpClient"])
173
- .index("by_workspaceId", ["workspaceId"])
174
- .index("by_lastActiveAt", ["lastActiveAt"])
175
- .index("by_mcpClient", ["mcpClient"]),
176
-
177
- // Subagent tracking (tasks spawned by main agent)
178
- subagents: defineTable({
179
- workspaceId: v.id("workspaces"),
180
- subagentId: v.string(), // from X-APIClaw-Subagent header
181
- name: v.optional(v.string()), // optional display name
182
- description: v.optional(v.string()), // user-provided description
183
- aiBackend: v.optional(v.string()), // "claude-3-opus", "gpt-4", etc.
184
- isRegistered: v.optional(v.boolean()), // true if pre-registered (not implicit)
185
- callCount: v.number(),
186
- firstSeenAt: v.number(),
187
- lastActiveAt: v.number(),
188
- })
189
- .index("by_workspaceId", ["workspaceId"])
190
- .index("by_workspaceId_subagentId", ["workspaceId", "subagentId"])
191
- .index("by_lastActiveAt", ["lastActiveAt"]),
192
-
193
- // Search logs (analytics for workspace searches)
194
- searchLogs: defineTable({
195
- workspaceId: v.id("workspaces"),
196
- subagentId: v.optional(v.string()),
197
- query: v.string(),
198
- resultCount: v.number(),
199
- hasResults: v.boolean(),
200
- matchedProviders: v.optional(v.array(v.string())),
201
- responseTimeMs: v.number(),
202
- timestamp: v.number(),
203
- })
204
- .index("by_workspaceId", ["workspaceId"])
205
- .index("by_timestamp", ["timestamp"])
206
- .index("by_hasResults", ["hasResults"])
207
- .index("by_workspaceId_timestamp", ["workspaceId", "timestamp"]),
208
-
209
- // Workspace team members (invite-based access)
210
- workspaceMembers: defineTable({
211
- workspaceId: v.id("workspaces"),
212
- email: v.string(),
213
- role: v.union(v.literal("owner"), v.literal("admin"), v.literal("member")),
214
- invitedBy: v.optional(v.string()), // email of inviter
215
- inviteToken: v.optional(v.string()),
216
- status: v.union(v.literal("pending"), v.literal("active"), v.literal("revoked")),
217
- createdAt: v.number(),
218
- acceptedAt: v.optional(v.number()),
219
- })
220
- .index("by_workspaceId", ["workspaceId"])
221
- .index("by_email", ["email"])
222
- .index("by_inviteToken", ["inviteToken"])
223
- .index("by_workspaceId_email", ["workspaceId", "email"]),
224
-
225
- // Magic links for workspace email verification
226
- workspaceMagicLinks: defineTable({
227
- email: v.string(),
228
- token: v.string(),
229
- sessionFingerprint: v.optional(v.string()),
230
- expiresAt: v.number(),
231
- usedAt: v.optional(v.number()),
232
- createdAt: v.number(),
233
- })
234
- .index("by_token", ["token"])
235
- .index("by_email", ["email"]),
236
-
237
- // Credit top-ups (from Stripe payments)
238
- creditTopups: defineTable({
239
- agentId: v.string(),
240
- stripePaymentIntentId: v.optional(v.string()),
241
- stripeSessionId: v.optional(v.string()),
242
- amountUsd: v.number(),
243
- creditsGranted: v.number(),
244
- packageType: v.string(), // starter, growth, scale
245
- status: v.string(), // pending, completed, failed
246
- createdAt: v.number(),
247
- completedAt: v.optional(v.number()),
248
- })
249
- .index("by_agentId", ["agentId"])
250
- .index("by_stripeSessionId", ["stripeSessionId"])
251
- .index("by_stripePaymentIntentId", ["stripePaymentIntentId"]),
252
-
253
- // ============================================
254
- // PROVIDER TABLES (for provider dashboard)
255
- // ============================================
256
-
257
- // API Providers (companies/individuals offering APIs)
258
- providers: defineTable({
259
- email: v.string(),
260
- name: v.string(),
261
- company: v.optional(v.string()),
262
- website: v.optional(v.string()),
263
- avatarUrl: v.optional(v.string()),
264
- stripeConnectId: v.optional(v.string()), // for payouts
265
- stripeOnboardingComplete: v.optional(v.boolean()),
266
- status: v.string(), // pending, approved, rejected, suspended
267
- workspaceId: v.optional(v.id("workspaces")), // Link to unified workspace identity
268
- createdAt: v.number(),
269
- updatedAt: v.number(),
270
- approvedAt: v.optional(v.number()),
271
- })
272
- .index("by_email", ["email"])
273
- .index("by_stripeConnectId", ["stripeConnectId"])
274
- .index("by_status", ["status"])
275
- .index("by_workspaceId", ["workspaceId"]),
276
-
277
- // APIs listed by providers (self-service onboarding)
278
- providerAPIs: defineTable({
279
- providerId: v.optional(v.id("providers")), // legacy — prefer workspaceId
280
- workspaceId: v.optional(v.id("workspaces")), // new — workspace owns this API
281
- name: v.string(),
282
- description: v.string(),
283
- category: v.string(),
284
- openApiUrl: v.optional(v.string()),
285
- docsUrl: v.optional(v.string()),
286
- pricingModel: v.string(), // free, freemium, paid
287
- pricingNotes: v.optional(v.string()),
288
- status: v.string(), // active, paused
289
- createdAt: v.number(),
290
- approvedAt: v.optional(v.number()),
291
- // Analytics
292
- discoveryCount: v.optional(v.number()),
293
- lastDiscoveredAt: v.optional(v.number()),
294
- })
295
- .index("by_providerId", ["providerId"])
296
- .index("by_workspaceId", ["workspaceId"])
297
- .index("by_category", ["category"])
298
- .index("by_status", ["status"])
299
- .index("by_status_category", ["status", "category"]),
300
-
301
- // APIs listed by providers (for full dashboard)
302
- apis: defineTable({
303
- providerId: v.id("providers"),
304
- workspaceId: v.optional(v.id("workspaces")), // Parallel workspace link
305
- name: v.string(),
306
- description: v.string(),
307
- category: v.string(),
308
- icon: v.optional(v.string()), // emoji or URL
309
- baseUrl: v.string(),
310
- docsUrl: v.optional(v.string()),
311
- authType: v.string(), // api_key, oauth, basic, bearer
312
- pricingModel: v.string(), // free, per_call, monthly, credits
313
- pricePerCall: v.optional(v.number()), // in USD cents
314
- monthlyPrice: v.optional(v.number()), // in USD cents
315
- rateLimitPerMinute: v.optional(v.number()),
316
- regions: v.optional(v.array(v.string())),
317
- tags: v.optional(v.array(v.string())),
318
- status: v.string(), // active, paused, pending_review
319
- isPublic: v.boolean(),
320
- // Credentials (encrypted in production)
321
- credentialTemplate: v.optional(v.any()),
322
- createdAt: v.number(),
323
- updatedAt: v.number(),
324
- })
325
- .index("by_providerId", ["providerId"])
326
- .index("by_workspaceId", ["workspaceId"])
327
- .index("by_category", ["category"])
328
- .index("by_status", ["status"]),
329
-
330
- // API Calls / Usage logs (for analytics)
331
- apiCalls: defineTable({
332
- apiId: v.id("apis"),
333
- providerId: v.id("providers"),
334
- workspaceId: v.optional(v.id("workspaces")), // Parallel workspace link
335
- agentId: v.string(),
336
- endpoint: v.optional(v.string()),
337
- method: v.optional(v.string()),
338
- statusCode: v.optional(v.number()),
339
- latencyMs: v.optional(v.number()),
340
- costUsd: v.number(), // cost in USD (fractional)
341
- region: v.optional(v.string()),
342
- timestamp: v.number(),
343
- })
344
- .index("by_apiId", ["apiId"])
345
- .index("by_providerId", ["providerId"])
346
- .index("by_workspaceId", ["workspaceId"])
347
- .index("by_agentId", ["agentId"])
348
- .index("by_timestamp", ["timestamp"])
349
- .index("by_providerId_timestamp", ["providerId", "timestamp"]),
350
-
351
- // Provider Payouts
352
- payouts: defineTable({
353
- providerId: v.id("providers"),
354
- workspaceId: v.optional(v.id("workspaces")), // Parallel workspace link
355
- amountUsd: v.number(),
356
- status: v.string(), // pending, processing, completed, failed
357
- stripePayoutId: v.optional(v.string()),
358
- periodStart: v.number(),
359
- periodEnd: v.number(),
360
- createdAt: v.number(),
361
- completedAt: v.optional(v.number()),
362
- })
363
- .index("by_providerId", ["providerId"])
364
- .index("by_workspaceId", ["workspaceId"])
365
- .index("by_status", ["status"]),
366
-
367
- // OTP codes for terminal-native email verification
368
- otpCodes: defineTable({
369
- email: v.string(),
370
- code: v.string(), // 6-digit code
371
- fingerprint: v.optional(v.string()),
372
- expiresAt: v.number(),
373
- usedAt: v.optional(v.number()),
374
- attempts: v.number(), // failed attempts counter
375
- createdAt: v.number(),
376
- })
377
- .index("by_email", ["email"])
378
- .index("by_email_code", ["email", "code"]),
379
-
380
- // Magic link tokens for email auth
381
- magicLinks: defineTable({
382
- email: v.string(),
383
- token: v.string(),
384
- expiresAt: v.number(),
385
- usedAt: v.optional(v.number()),
386
- createdAt: v.number(),
387
- })
388
- .index("by_token", ["token"])
389
- .index("by_email", ["email"]),
390
-
391
- // Sessions for authenticated providers
392
- sessions: defineTable({
393
- providerId: v.id("providers"),
394
- token: v.string(),
395
- expiresAt: v.number(),
396
- createdAt: v.number(),
397
- })
398
- .index("by_token", ["token"])
399
- .index("by_providerId", ["providerId"]),
400
-
401
- // Rate limiting
402
- rateLimits: defineTable({
403
- key: v.string(),
404
- identifier: v.string(),
405
- action: v.string(),
406
- count: v.number(),
407
- hourBucket: v.number(),
408
- createdAt: v.number(),
409
- })
410
- .index("by_key", ["key"])
411
- .index("by_identifier", ["identifier"]),
412
-
413
- // Usage analytics
414
- analytics: defineTable({
415
- event: v.string(), // "discovery", "instant", "search_query"
416
- provider: v.optional(v.string()),
417
- query: v.optional(v.string()),
418
- identifier: v.string(),
419
- workspaceId: v.optional(v.id("workspaces")), // Claimed workspace (null = anonymous)
420
- metadata: v.optional(v.any()),
421
- timestamp: v.number(),
422
- })
423
- .index("by_event", ["event"])
424
- .index("by_timestamp", ["timestamp"])
425
- .index("by_provider", ["provider"])
426
- .index("by_workspaceId", ["workspaceId"])
427
- .index("by_identifier", ["identifier"]),
428
-
429
- // MCP Server telemetry (anonymous usage tracking)
430
- telemetry: defineTable({
431
- type: v.string(), // "startup", "search", "execute", "discovery"
432
- query: v.optional(v.string()),
433
- apiId: v.optional(v.string()),
434
- resultCount: v.optional(v.number()),
435
- responseTimeMs: v.optional(v.number()),
436
- version: v.string(),
437
- platform: v.string(),
438
- nodeVersion: v.string(),
439
- timestamp: v.number(),
440
- })
441
- .index("by_type", ["type"])
442
- .index("by_timestamp", ["timestamp"]),
443
-
444
- // ============================================
445
- // SELF-SERVICE DIRECT CALL TABLES
446
- // ============================================
447
-
448
- // Provider Direct Call configuration (master key, limits, pricing)
449
- providerDirectCall: defineTable({
450
- providerId: v.id("providers"),
451
- workspaceId: v.optional(v.id("workspaces")), // Parallel workspace link
452
- apiId: v.optional(v.id("providerAPIs")),
453
- baseUrl: v.string(),
454
- authType: v.string(), // "bearer" | "basic" | "api_key" | "none"
455
- authHeader: v.string(), // e.g. "Authorization", "X-API-Key"
456
- authPrefix: v.string(), // e.g. "Bearer ", "Basic ", ""
457
- encryptedMasterKey: v.string(),
458
- rateLimitPerUser: v.number(), // requests per minute per user
459
- rateLimitPerDay: v.number(), // requests per day per user
460
- pricePerRequest: v.number(), // in USD cents
461
- status: v.string(), // "draft" | "testing" | "live"
462
- // Customer key passthrough settings
463
- allowCustomerKeys: v.optional(v.boolean()), // Allow agents to pass their own API key (default: true)
464
- requireCustomerKeys: v.optional(v.boolean()), // Require customer key, no master key fallback (default: false)
465
- createdAt: v.number(),
466
- updatedAt: v.number(),
467
- publishedAt: v.optional(v.number()),
468
- })
469
- .index("by_providerId", ["providerId"])
470
- .index("by_workspaceId", ["workspaceId"])
471
- .index("by_apiId", ["apiId"])
472
- .index("by_status", ["status"]),
473
-
474
- // Actions defined by providers for their Direct Call APIs
475
- providerActions: defineTable({
476
- directCallId: v.id("providerDirectCall"),
477
- name: v.string(), // machine name, e.g. "send_sms"
478
- displayName: v.string(), // human-friendly, e.g. "Send SMS"
479
- description: v.string(),
480
- method: v.string(), // "GET" | "POST" | "PUT" | "PATCH" | "DELETE"
481
- path: v.string(), // e.g. "/v1/messages" or "/users/{userId}"
482
- params: v.array(v.object({
483
- name: v.string(),
484
- type: v.string(), // "string" | "number" | "boolean" | "object"
485
- required: v.boolean(),
486
- description: v.string(),
487
- default: v.optional(v.any()),
488
- in: v.string(), // "body" | "query" | "path"
489
- })),
490
- responseMapping: v.array(v.object({
491
- name: v.string(),
492
- path: v.string(), // JSON path, e.g. "data.id" or "results[0].name"
493
- })),
494
- enabled: v.boolean(),
495
- // Confirmation settings for costly actions
496
- requiresConfirmation: v.optional(v.boolean()), // If true, requires user confirmation before executing
497
- estimatedCost: v.optional(v.string()), // Human-readable cost estimate, e.g. "~2-5 SEK per invoice"
498
- createdAt: v.number(),
499
- updatedAt: v.number(),
500
- })
501
- .index("by_directCallId", ["directCallId"])
502
- .index("by_directCallId_name", ["directCallId", "name"]),
503
-
504
- // Usage logs for Direct Call actions
505
- usageLog: defineTable({
506
- userId: v.string(),
507
- providerId: v.id("providers"),
508
- workspaceId: v.optional(v.id("workspaces")), // Parallel workspace link
509
- directCallId: v.id("providerDirectCall"),
510
- actionName: v.string(),
511
- timestamp: v.number(),
512
- success: v.boolean(),
513
- latencyMs: v.number(),
514
- creditsUsed: v.number(), // in USD cents
515
- errorMessage: v.optional(v.string()),
516
- })
517
- .index("by_userId", ["userId"])
518
- .index("by_providerId", ["providerId"])
519
- .index("by_workspaceId", ["workspaceId"])
520
- .index("by_directCallId", ["directCallId"])
521
- .index("by_timestamp", ["timestamp"])
522
- .index("by_userId_providerId", ["userId", "providerId"])
523
- .index("by_userId_timestamp", ["userId", "timestamp"]),
524
-
525
- // ============================================
526
- // API LOGS (workspace/consumer view)
527
- // ============================================
528
-
529
- apiLogs: defineTable({
530
- workspaceId: v.id("workspaces"),
531
- sessionToken: v.string(),
532
- subagentId: v.optional(v.string()),
533
- provider: v.string(),
534
- action: v.string(),
535
- status: v.union(v.literal("success"), v.literal("error")),
536
- latencyMs: v.number(),
537
- errorMessage: v.optional(v.string()),
538
- direction: v.optional(v.string()), // "outbound" (I called) or "inbound" (someone called my API)
539
- callerWorkspaceId: v.optional(v.string()), // who made the call (for inbound logs)
540
- createdAt: v.number(),
541
- })
542
- .index("by_workspaceId", ["workspaceId"])
543
- .index("by_createdAt", ["createdAt"])
544
- .index("by_workspaceId_createdAt", ["workspaceId", "createdAt"])
545
- .index("by_subagentId", ["subagentId"])
546
- .index("by_provider", ["provider"]),
547
-
548
- // ============================================
549
- // WAITLIST (for Direct Call provider leads)
550
- // ============================================
551
-
552
- waitlist: defineTable({
553
- email: v.string(),
554
- type: v.string(), // "provider" | "agent" | "general"
555
- source: v.optional(v.string()), // "landing", "docs", etc.
556
- createdAt: v.number(),
557
- })
558
- .index("by_email", ["email"])
559
- .index("by_type", ["type"]),
560
-
561
- // ============================================
562
- // CAPABILITY LAYER (abstraction over providers)
563
- // ============================================
564
-
565
- // Capability definitions (sms, email, invoice, search, etc.)
566
- capabilities: defineTable({
567
- id: v.string(), // "sms", "email", "invoice"
568
- name: v.string(), // "SMS Messaging"
569
- description: v.string(),
570
- category: v.string(), // "communication", "business", "ai"
571
- standardParams: v.array(v.object({
572
- name: v.string(),
573
- type: v.string(), // "string" | "number" | "boolean"
574
- required: v.boolean(),
575
- description: v.string(),
576
- default: v.optional(v.any()),
577
- })),
578
- createdAt: v.number(),
579
- updatedAt: v.number(),
580
- })
581
- .index("by_capability_id", ["id"])
582
- .index("by_category", ["category"]),
583
-
584
- // Provider → Capability mappings (which providers offer which capabilities)
585
- providerCapabilities: defineTable({
586
- providerId: v.string(), // "46elks", "twilio"
587
- capabilityId: v.string(), // "sms"
588
- priority: v.number(), // 1 = primary, 2 = fallback
589
- regions: v.array(v.string()), // ["SE", "EU", "US"]
590
- pricePerUnit: v.number(), // in smallest currency unit (cents/öre)
591
- currency: v.string(), // "SEK", "USD"
592
- avgLatencyMs: v.number(),
593
- paramMapping: v.any(), // Record<string, string> - capability param → provider param
594
- enabled: v.boolean(),
595
- healthStatus: v.string(), // "healthy" | "degraded" | "down"
596
- lastHealthCheck: v.optional(v.number()),
597
- createdAt: v.number(),
598
- updatedAt: v.number(),
599
- })
600
- .index("by_providerId", ["providerId"])
601
- .index("by_capabilityId", ["capabilityId"])
602
- .index("by_capabilityId_enabled", ["capabilityId", "enabled"])
603
- .index("by_healthStatus", ["healthStatus"]),
604
-
605
- // Capability usage logs (for analytics and billing)
606
- capabilityLogs: defineTable({
607
- capabilityId: v.string(),
608
- providerId: v.string(),
609
- userId: v.string(),
610
- action: v.string(),
611
- success: v.boolean(),
612
- fallbackUsed: v.boolean(),
613
- fallbackReason: v.optional(v.string()),
614
- latencyMs: v.number(),
615
- cost: v.number(),
616
- currency: v.string(),
617
- timestamp: v.number(),
618
- })
619
- .index("by_capabilityId", ["capabilityId"])
620
- .index("by_providerId", ["providerId"])
621
- .index("by_userId", ["userId"])
622
- .index("by_timestamp", ["timestamp"]),
623
-
624
- // ============================================
625
- // WEBHOOKS
626
- // ============================================
627
-
628
- webhooks: defineTable({
629
- workspaceId: v.id("workspaces"),
630
- url: v.string(),
631
- events: v.array(v.string()),
632
- secret: v.string(), // For signature verification
633
- enabled: v.boolean(),
634
- lastTriggeredAt: v.optional(v.number()),
635
- lastStatus: v.optional(v.string()), // "success" | "failed"
636
- failCount: v.number(),
637
- createdAt: v.number(),
638
- })
639
- .index("by_workspaceId", ["workspaceId"]),
640
-
641
- // ============================================
642
- // BYOK - BRING YOUR OWN KEY
643
- // ============================================
644
-
645
- // User-provided API keys for providers
646
- providerKeys: defineTable({
647
- workspaceId: v.id("workspaces"),
648
- provider: v.string(), // "brave_search", "openrouter", etc.
649
- encryptedKey: v.string(), // Base64 encoded for MVP
650
- keyHint: v.string(), // Last 4 chars for display
651
- isCustom: v.boolean(), // true if custom provider (not built-in)
652
- customConfig: v.optional(v.object({
653
- baseUrl: v.string(),
654
- authType: v.string(), // "bearer", "api_key", "basic"
655
- authHeader: v.optional(v.string()), // e.g. "X-API-Key"
656
- })),
657
- createdAt: v.number(),
658
- updatedAt: v.number(),
659
- })
660
- .index("by_workspaceId", ["workspaceId"])
661
- .index("by_provider", ["workspaceId", "provider"]),
662
-
663
- // ============================================
664
- // EARN PROGRESS TRACKING
665
- // ============================================
666
-
667
- earnProgress: defineTable({
668
- workspaceId: v.id("workspaces"),
669
-
670
- // Usage tasks
671
- firstDirectCall: v.boolean(),
672
- firstDirectCallAt: v.optional(v.number()),
673
-
674
- apisUsed: v.array(v.string()), // Track unique provider/action combos
675
- apisUsedComplete: v.boolean(),
676
-
677
- agentListed: v.boolean(),
678
- agentListedAt: v.optional(v.number()),
679
-
680
- apiListed: v.boolean(),
681
- apiListedAt: v.optional(v.number()),
682
-
683
- byokSetup: v.boolean(),
684
- byokSetupAt: v.optional(v.number()),
685
-
686
- // Growth tasks
687
- githubStarred: v.boolean(),
688
- githubStarredAt: v.optional(v.number()),
689
-
690
- twitterFollowed: v.boolean(),
691
- twitterFollowedAt: v.optional(v.number()),
692
-
693
- // Referrals (tracked separately but stored here for convenience)
694
- referralCount: v.number(),
695
-
696
- // Calculated total
697
- totalEarned: v.number(),
698
-
699
- createdAt: v.number(),
700
- updatedAt: v.number(),
701
- })
702
- .index("by_workspaceId", ["workspaceId"]),
703
-
704
- // ============================================
705
- // FEEDBACK SYSTEM
706
- // ============================================
707
-
708
- // ============================================
709
- // CHAIN ORCHESTRATION TABLES
710
- // ============================================
711
-
712
- // Chain executions (main orchestration record)
713
- chains: defineTable({
714
- workspaceId: v.id("workspaces"),
715
- // Chain definition
716
- steps: v.array(v.any()), // Array of step definitions (raw, unresolved)
717
- // Execution state
718
- status: v.union(
719
- v.literal("pending"),
720
- v.literal("running"),
721
- v.literal("completed"),
722
- v.literal("failed"),
723
- v.literal("paused")
724
- ),
725
- currentStep: v.number(), // Index of current step (0-based)
726
- // Results storage
727
- results: v.any(), // Record<stepId, result>
728
- // Error tracking
729
- error: v.optional(v.object({
730
- stepId: v.string(),
731
- code: v.string(),
732
- message: v.string(),
733
- retryAfter: v.optional(v.number()),
734
- })),
735
- // Execution options
736
- continueOnError: v.optional(v.boolean()),
737
- timeout: v.optional(v.number()), // ms
738
- // Resume capability
739
- resumeToken: v.optional(v.string()),
740
- canResume: v.optional(v.boolean()),
741
- // Cost tracking
742
- totalCostCents: v.optional(v.number()),
743
- totalLatencyMs: v.optional(v.number()),
744
- // Timestamps
745
- createdAt: v.number(),
746
- startedAt: v.optional(v.number()),
747
- completedAt: v.optional(v.number()),
748
- })
749
- .index("by_workspaceId", ["workspaceId"])
750
- .index("by_status", ["status"])
751
- .index("by_workspaceId_status", ["workspaceId", "status"])
752
- .index("by_resumeToken", ["resumeToken"]),
753
-
754
- // Chain templates (reusable chain definitions)
755
- chainTemplates: defineTable({
756
- workspaceId: v.id("workspaces"),
757
- name: v.string(),
758
- description: v.optional(v.string()),
759
- // Input schema for the template
760
- inputs: v.optional(v.any()), // JSON Schema for inputs
761
- // Chain definition
762
- chain: v.array(v.any()), // Array of step definitions
763
- // Usage tracking
764
- useCount: v.optional(v.number()),
765
- lastUsedAt: v.optional(v.number()),
766
- // Timestamps
767
- createdAt: v.number(),
768
- updatedAt: v.number(),
769
- })
770
- .index("by_workspaceId", ["workspaceId"])
771
- .index("by_name", ["workspaceId", "name"]),
772
-
773
- // Chain step executions (detailed trace per step)
774
- chainExecutions: defineTable({
775
- chainId: v.id("chains"),
776
- stepId: v.string(), // The id from step definition
777
- stepIndex: v.number(), // Position in chain
778
- // Execution state
779
- status: v.union(
780
- v.literal("pending"),
781
- v.literal("running"),
782
- v.literal("completed"),
783
- v.literal("failed"),
784
- v.literal("skipped")
785
- ),
786
- // I/O
787
- input: v.optional(v.any()), // Resolved params sent to provider
788
- output: v.optional(v.any()), // Result from provider
789
- // Metrics
790
- latencyMs: v.optional(v.number()),
791
- costCents: v.optional(v.number()),
792
- // Error info
793
- error: v.optional(v.object({
794
- code: v.string(),
795
- message: v.string(),
796
- retryCount: v.optional(v.number()),
797
- })),
798
- // Parallel execution tracking
799
- parallelGroup: v.optional(v.string()), // Group ID if part of parallel batch
800
- // Timestamps
801
- createdAt: v.number(),
802
- startedAt: v.optional(v.number()),
803
- completedAt: v.optional(v.number()),
804
- })
805
- .index("by_chainId", ["chainId"])
806
- .index("by_chainId_stepId", ["chainId", "stepId"])
807
- .index("by_chainId_stepIndex", ["chainId", "stepIndex"]),
808
-
809
- // User feedback with voting
810
- feedback: defineTable({
811
- workspaceId: v.id("workspaces"),
812
- type: v.union(v.literal("bug"), v.literal("feature"), v.literal("general")),
813
- content: v.string(),
814
- votes: v.number(),
815
- votedBy: v.array(v.string()), // workspace IDs that voted
816
- status: v.union(v.literal("new"), v.literal("reviewing"), v.literal("planned"), v.literal("shipped")),
817
- createdAt: v.number(),
818
- })
819
- .index("by_workspaceId", ["workspaceId"])
820
- .index("by_type", ["type"])
821
- .index("by_status", ["status"])
822
- .index("by_votes", ["votes"])
823
- .index("by_createdAt", ["createdAt"]),
824
-
825
- // ============================================
826
- // WORKSPACE SETTINGS (Gateway routing config)
827
- // ============================================
828
-
829
- workspaceSettings: defineTable({
830
- workspaceId: v.id("workspaces"),
831
- // Routing preferences
832
- routingMode: v.string(), // "best_price" | "highest_quality" | "fastest" | "balanced"
833
- defaultModel: v.optional(v.string()), // e.g. "anthropic/claude-sonnet-4-6"
834
- // Budget controls
835
- maxPricePerMTokens: v.optional(v.float64()), // max $/million tokens, null = no limit
836
- monthlyBudgetLimit: v.optional(v.float64()), // monthly budget in USD, null = no limit
837
- // Provider preferences
838
- preferredProviders: v.optional(v.array(v.string())), // e.g. ["groq", "mistral", "together"]
839
- blockedProviders: v.optional(v.array(v.string())), // providers to never use
840
- // Fallback
841
- allowOpenRouterFallback: v.optional(v.boolean()), // default true
842
- // Timestamps
843
- createdAt: v.number(),
844
- updatedAt: v.number(),
845
- })
846
- .index("by_workspaceId", ["workspaceId"]),
847
-
848
- // ============================================
849
- // MOU SIGNATURES
850
- // ============================================
851
-
852
- mouDocuments: defineTable({
853
- partnerId: v.string(), // e.g., "apilayer"
854
- partnerName: v.string(),
855
- partnerEmail: v.string(),
856
- partnerRepresentative: v.optional(v.string()),
857
- documentHtml: v.optional(v.string()),
858
- sections: v.optional(v.any()), // Alternative document format
859
- status: v.string(), // "pending" | "signed"
860
- signedAt: v.optional(v.number()),
861
- signatureDataUrl: v.optional(v.string()), // base64 signature image
862
- signerName: v.optional(v.string()),
863
- signerTitle: v.optional(v.string()),
864
- signerIp: v.optional(v.string()),
865
- createdAt: v.number(),
866
- })
867
- .index("by_partnerId", ["partnerId"])
868
- .index("by_status", ["status"]),
869
- });