@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,215 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+ // ============================================
4
+ // HELPER FUNCTIONS
5
+ // ============================================
6
+ function generateToken() {
7
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
8
+ let result = "";
9
+ for (let i = 0; i < 32; i++) {
10
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
11
+ }
12
+ return result;
13
+ }
14
+ // ============================================
15
+ // TEAM QUERIES
16
+ // ============================================
17
+ /**
18
+ * Get team members for a workspace
19
+ */
20
+ export const getMembers = query({
21
+ args: { token: v.string() },
22
+ handler: async (ctx, { token }) => {
23
+ const session = await ctx.db
24
+ .query("agentSessions")
25
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
26
+ .first();
27
+ if (!session)
28
+ return [];
29
+ const workspace = await ctx.db.get(session.workspaceId);
30
+ if (!workspace)
31
+ return [];
32
+ const members = await ctx.db
33
+ .query("workspaceMembers")
34
+ .withIndex("by_workspaceId", (q) => q.eq("workspaceId", session.workspaceId))
35
+ .collect();
36
+ // Add owner as first member
37
+ return [
38
+ {
39
+ email: workspace.email,
40
+ role: "owner",
41
+ status: "active",
42
+ isOwner: true,
43
+ createdAt: workspace.createdAt,
44
+ },
45
+ ...members.map((m) => ({
46
+ id: m._id,
47
+ email: m.email,
48
+ role: m.role,
49
+ status: m.status,
50
+ isOwner: false,
51
+ invitedBy: m.invitedBy,
52
+ createdAt: m.createdAt,
53
+ acceptedAt: m.acceptedAt,
54
+ })),
55
+ ];
56
+ },
57
+ });
58
+ // ============================================
59
+ // TEAM MUTATIONS
60
+ // ============================================
61
+ /**
62
+ * Invite a member to the workspace (creates pending invite)
63
+ */
64
+ export const inviteMember = mutation({
65
+ args: {
66
+ token: v.string(),
67
+ email: v.string(),
68
+ role: v.union(v.literal("admin"), v.literal("member")),
69
+ },
70
+ handler: async (ctx, { token, email, role }) => {
71
+ const session = await ctx.db
72
+ .query("agentSessions")
73
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
74
+ .first();
75
+ if (!session)
76
+ throw new Error("Invalid session");
77
+ const workspace = await ctx.db.get(session.workspaceId);
78
+ if (!workspace)
79
+ throw new Error("Workspace not found");
80
+ // Normalize email
81
+ const normalizedEmail = email.toLowerCase().trim();
82
+ // Can't invite yourself
83
+ if (normalizedEmail === workspace.email.toLowerCase()) {
84
+ throw new Error("Cannot invite yourself");
85
+ }
86
+ // Check if already member
87
+ const existing = await ctx.db
88
+ .query("workspaceMembers")
89
+ .withIndex("by_workspaceId_email", (q) => q.eq("workspaceId", session.workspaceId).eq("email", normalizedEmail))
90
+ .first();
91
+ if (existing) {
92
+ if (existing.status === "active") {
93
+ throw new Error("Already a team member");
94
+ }
95
+ if (existing.status === "pending") {
96
+ throw new Error("Invite already pending");
97
+ }
98
+ // If revoked, we can re-invite - update existing record
99
+ const inviteToken = generateToken();
100
+ await ctx.db.patch(existing._id, {
101
+ role,
102
+ invitedBy: workspace.email,
103
+ inviteToken,
104
+ status: "pending",
105
+ createdAt: Date.now(),
106
+ acceptedAt: undefined,
107
+ });
108
+ return { id: existing._id, inviteToken };
109
+ }
110
+ // Generate invite token
111
+ const inviteToken = generateToken();
112
+ const id = await ctx.db.insert("workspaceMembers", {
113
+ workspaceId: session.workspaceId,
114
+ email: normalizedEmail,
115
+ role,
116
+ invitedBy: workspace.email,
117
+ inviteToken,
118
+ status: "pending",
119
+ createdAt: Date.now(),
120
+ });
121
+ return { id, inviteToken };
122
+ },
123
+ });
124
+ /**
125
+ * Accept an invite
126
+ */
127
+ export const acceptInvite = mutation({
128
+ args: { inviteToken: v.string() },
129
+ handler: async (ctx, { inviteToken }) => {
130
+ const member = await ctx.db
131
+ .query("workspaceMembers")
132
+ .withIndex("by_inviteToken", (q) => q.eq("inviteToken", inviteToken))
133
+ .first();
134
+ if (!member)
135
+ throw new Error("Invalid invite token");
136
+ if (member.status !== "pending")
137
+ throw new Error("Invite already used or revoked");
138
+ await ctx.db.patch(member._id, {
139
+ status: "active",
140
+ acceptedAt: Date.now(),
141
+ inviteToken: undefined, // Clear token after use
142
+ });
143
+ // Get workspace info for response
144
+ const workspace = await ctx.db.get(member.workspaceId);
145
+ return {
146
+ success: true,
147
+ workspaceId: member.workspaceId,
148
+ workspaceEmail: workspace?.email,
149
+ role: member.role,
150
+ };
151
+ },
152
+ });
153
+ /**
154
+ * Remove a member from the workspace
155
+ */
156
+ export const removeMember = mutation({
157
+ args: {
158
+ token: v.string(),
159
+ memberEmail: v.string(),
160
+ },
161
+ handler: async (ctx, { token, memberEmail }) => {
162
+ const session = await ctx.db
163
+ .query("agentSessions")
164
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
165
+ .first();
166
+ if (!session)
167
+ throw new Error("Invalid session");
168
+ const workspace = await ctx.db.get(session.workspaceId);
169
+ if (!workspace)
170
+ throw new Error("Workspace not found");
171
+ const normalizedEmail = memberEmail.toLowerCase().trim();
172
+ // Cannot remove owner
173
+ if (normalizedEmail === workspace.email.toLowerCase()) {
174
+ throw new Error("Cannot remove workspace owner");
175
+ }
176
+ const member = await ctx.db
177
+ .query("workspaceMembers")
178
+ .withIndex("by_workspaceId_email", (q) => q.eq("workspaceId", session.workspaceId).eq("email", normalizedEmail))
179
+ .first();
180
+ if (!member)
181
+ throw new Error("Member not found");
182
+ // Set status to revoked instead of deleting
183
+ await ctx.db.patch(member._id, {
184
+ status: "revoked",
185
+ inviteToken: undefined,
186
+ });
187
+ return { success: true };
188
+ },
189
+ });
190
+ /**
191
+ * Get invite details (public, for invite acceptance page)
192
+ */
193
+ export const getInviteDetails = query({
194
+ args: { inviteToken: v.string() },
195
+ handler: async (ctx, { inviteToken }) => {
196
+ const member = await ctx.db
197
+ .query("workspaceMembers")
198
+ .withIndex("by_inviteToken", (q) => q.eq("inviteToken", inviteToken))
199
+ .first();
200
+ if (!member)
201
+ return null;
202
+ if (member.status !== "pending")
203
+ return null;
204
+ const workspace = await ctx.db.get(member.workspaceId);
205
+ if (!workspace)
206
+ return null;
207
+ return {
208
+ email: member.email,
209
+ role: member.role,
210
+ invitedBy: member.invitedBy,
211
+ workspaceEmail: workspace.email,
212
+ };
213
+ },
214
+ });
215
+ //# sourceMappingURL=teams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.js","sourceRoot":"","sources":["teams.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,243 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, query } from "./_generated/server";
3
+
4
+ // ============================================
5
+ // HELPER FUNCTIONS
6
+ // ============================================
7
+
8
+ function generateToken(): string {
9
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
10
+ let result = "";
11
+ for (let i = 0; i < 32; i++) {
12
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
13
+ }
14
+ return result;
15
+ }
16
+
17
+ // ============================================
18
+ // TEAM QUERIES
19
+ // ============================================
20
+
21
+ /**
22
+ * Get team members for a workspace
23
+ */
24
+ export const getMembers = query({
25
+ args: { token: v.string() },
26
+ handler: async (ctx, { token }) => {
27
+ const session = await ctx.db
28
+ .query("agentSessions")
29
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
30
+ .first();
31
+
32
+ if (!session) return [];
33
+
34
+ const workspace = await ctx.db.get(session.workspaceId);
35
+ if (!workspace) return [];
36
+
37
+ const members = await ctx.db
38
+ .query("workspaceMembers")
39
+ .withIndex("by_workspaceId", (q) => q.eq("workspaceId", session.workspaceId))
40
+ .collect();
41
+
42
+ // Add owner as first member
43
+ return [
44
+ {
45
+ email: workspace.email,
46
+ role: "owner" as const,
47
+ status: "active" as const,
48
+ isOwner: true,
49
+ createdAt: workspace.createdAt,
50
+ },
51
+ ...members.map((m) => ({
52
+ id: m._id,
53
+ email: m.email,
54
+ role: m.role,
55
+ status: m.status,
56
+ isOwner: false,
57
+ invitedBy: m.invitedBy,
58
+ createdAt: m.createdAt,
59
+ acceptedAt: m.acceptedAt,
60
+ })),
61
+ ];
62
+ },
63
+ });
64
+
65
+ // ============================================
66
+ // TEAM MUTATIONS
67
+ // ============================================
68
+
69
+ /**
70
+ * Invite a member to the workspace (creates pending invite)
71
+ */
72
+ export const inviteMember = mutation({
73
+ args: {
74
+ token: v.string(),
75
+ email: v.string(),
76
+ role: v.union(v.literal("admin"), v.literal("member")),
77
+ },
78
+ handler: async (ctx, { token, email, role }) => {
79
+ const session = await ctx.db
80
+ .query("agentSessions")
81
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
82
+ .first();
83
+
84
+ if (!session) throw new Error("Invalid session");
85
+
86
+ const workspace = await ctx.db.get(session.workspaceId);
87
+ if (!workspace) throw new Error("Workspace not found");
88
+
89
+ // Normalize email
90
+ const normalizedEmail = email.toLowerCase().trim();
91
+
92
+ // Can't invite yourself
93
+ if (normalizedEmail === workspace.email.toLowerCase()) {
94
+ throw new Error("Cannot invite yourself");
95
+ }
96
+
97
+ // Check if already member
98
+ const existing = await ctx.db
99
+ .query("workspaceMembers")
100
+ .withIndex("by_workspaceId_email", (q) =>
101
+ q.eq("workspaceId", session.workspaceId).eq("email", normalizedEmail)
102
+ )
103
+ .first();
104
+
105
+ if (existing) {
106
+ if (existing.status === "active") {
107
+ throw new Error("Already a team member");
108
+ }
109
+ if (existing.status === "pending") {
110
+ throw new Error("Invite already pending");
111
+ }
112
+ // If revoked, we can re-invite - update existing record
113
+ const inviteToken = generateToken();
114
+ await ctx.db.patch(existing._id, {
115
+ role,
116
+ invitedBy: workspace.email,
117
+ inviteToken,
118
+ status: "pending",
119
+ createdAt: Date.now(),
120
+ acceptedAt: undefined,
121
+ });
122
+ return { id: existing._id, inviteToken };
123
+ }
124
+
125
+ // Generate invite token
126
+ const inviteToken = generateToken();
127
+
128
+ const id = await ctx.db.insert("workspaceMembers", {
129
+ workspaceId: session.workspaceId,
130
+ email: normalizedEmail,
131
+ role,
132
+ invitedBy: workspace.email,
133
+ inviteToken,
134
+ status: "pending",
135
+ createdAt: Date.now(),
136
+ });
137
+
138
+ return { id, inviteToken };
139
+ },
140
+ });
141
+
142
+ /**
143
+ * Accept an invite
144
+ */
145
+ export const acceptInvite = mutation({
146
+ args: { inviteToken: v.string() },
147
+ handler: async (ctx, { inviteToken }) => {
148
+ const member = await ctx.db
149
+ .query("workspaceMembers")
150
+ .withIndex("by_inviteToken", (q) => q.eq("inviteToken", inviteToken))
151
+ .first();
152
+
153
+ if (!member) throw new Error("Invalid invite token");
154
+ if (member.status !== "pending") throw new Error("Invite already used or revoked");
155
+
156
+ await ctx.db.patch(member._id, {
157
+ status: "active",
158
+ acceptedAt: Date.now(),
159
+ inviteToken: undefined, // Clear token after use
160
+ });
161
+
162
+ // Get workspace info for response
163
+ const workspace = await ctx.db.get(member.workspaceId);
164
+
165
+ return {
166
+ success: true,
167
+ workspaceId: member.workspaceId,
168
+ workspaceEmail: workspace?.email,
169
+ role: member.role,
170
+ };
171
+ },
172
+ });
173
+
174
+ /**
175
+ * Remove a member from the workspace
176
+ */
177
+ export const removeMember = mutation({
178
+ args: {
179
+ token: v.string(),
180
+ memberEmail: v.string(),
181
+ },
182
+ handler: async (ctx, { token, memberEmail }) => {
183
+ const session = await ctx.db
184
+ .query("agentSessions")
185
+ .withIndex("by_sessionToken", (q) => q.eq("sessionToken", token))
186
+ .first();
187
+
188
+ if (!session) throw new Error("Invalid session");
189
+
190
+ const workspace = await ctx.db.get(session.workspaceId);
191
+ if (!workspace) throw new Error("Workspace not found");
192
+
193
+ const normalizedEmail = memberEmail.toLowerCase().trim();
194
+
195
+ // Cannot remove owner
196
+ if (normalizedEmail === workspace.email.toLowerCase()) {
197
+ throw new Error("Cannot remove workspace owner");
198
+ }
199
+
200
+ const member = await ctx.db
201
+ .query("workspaceMembers")
202
+ .withIndex("by_workspaceId_email", (q) =>
203
+ q.eq("workspaceId", session.workspaceId).eq("email", normalizedEmail)
204
+ )
205
+ .first();
206
+
207
+ if (!member) throw new Error("Member not found");
208
+
209
+ // Set status to revoked instead of deleting
210
+ await ctx.db.patch(member._id, {
211
+ status: "revoked",
212
+ inviteToken: undefined,
213
+ });
214
+
215
+ return { success: true };
216
+ },
217
+ });
218
+
219
+ /**
220
+ * Get invite details (public, for invite acceptance page)
221
+ */
222
+ export const getInviteDetails = query({
223
+ args: { inviteToken: v.string() },
224
+ handler: async (ctx, { inviteToken }) => {
225
+ const member = await ctx.db
226
+ .query("workspaceMembers")
227
+ .withIndex("by_inviteToken", (q) => q.eq("inviteToken", inviteToken))
228
+ .first();
229
+
230
+ if (!member) return null;
231
+ if (member.status !== "pending") return null;
232
+
233
+ const workspace = await ctx.db.get(member.workspaceId);
234
+ if (!workspace) return null;
235
+
236
+ return {
237
+ email: member.email,
238
+ role: member.role,
239
+ invitedBy: member.invitedBy,
240
+ workspaceEmail: workspace.email,
241
+ };
242
+ },
243
+ });
@@ -0,0 +1,4 @@
1
+ export declare const track: any;
2
+ export declare const getStats: any;
3
+ export declare const getRecent: any;
4
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["telemetry.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,KAAK,KA2BhB,CAAC;AAEH,eAAO,MAAM,QAAQ,KAsCnB,CAAC;AAEH,eAAO,MAAM,SAAS,KAQpB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { mutation, query } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+ export const track = mutation({
4
+ args: {
5
+ event: v.object({
6
+ type: v.string(),
7
+ query: v.optional(v.string()),
8
+ apiId: v.optional(v.string()),
9
+ resultCount: v.optional(v.number()),
10
+ responseTimeMs: v.optional(v.number()),
11
+ version: v.optional(v.string()),
12
+ platform: v.optional(v.string()),
13
+ nodeVersion: v.optional(v.string()),
14
+ timestamp: v.optional(v.number()),
15
+ }),
16
+ },
17
+ handler: async (ctx, { event }) => {
18
+ await ctx.db.insert("telemetry", {
19
+ type: event.type,
20
+ query: event.query,
21
+ apiId: event.apiId,
22
+ resultCount: event.resultCount,
23
+ responseTimeMs: event.responseTimeMs,
24
+ version: event.version || "unknown",
25
+ platform: event.platform || "unknown",
26
+ nodeVersion: event.nodeVersion || "unknown",
27
+ timestamp: event.timestamp || Date.now(),
28
+ });
29
+ },
30
+ });
31
+ export const getStats = query({
32
+ args: {},
33
+ handler: async (ctx) => {
34
+ const events = await ctx.db.query("telemetry").collect();
35
+ const startups = events.filter(e => e.type === "startup").length;
36
+ const searches = events.filter(e => e.type === "search").length;
37
+ const executes = events.filter(e => e.type === "execute").length;
38
+ const uniqueUsers = new Set(events.map(e => `${e.platform}-${e.nodeVersion}`)).size;
39
+ const topQueries = events
40
+ .filter(e => e.type === "search" && e.query)
41
+ .reduce((acc, e) => {
42
+ acc[e.query] = (acc[e.query] || 0) + 1;
43
+ return acc;
44
+ }, {});
45
+ const topAPIs = events
46
+ .filter(e => e.type === "execute" && e.apiId)
47
+ .reduce((acc, e) => {
48
+ acc[e.apiId] = (acc[e.apiId] || 0) + 1;
49
+ return acc;
50
+ }, {});
51
+ return {
52
+ totalStartups: startups,
53
+ totalSearches: searches,
54
+ totalExecutes: executes,
55
+ estimatedUniqueUsers: uniqueUsers,
56
+ topQueries: Object.entries(topQueries)
57
+ .sort(([, a], [, b]) => b - a)
58
+ .slice(0, 10),
59
+ topAPIs: Object.entries(topAPIs)
60
+ .sort(([, a], [, b]) => b - a)
61
+ .slice(0, 10),
62
+ };
63
+ },
64
+ });
65
+ export const getRecent = query({
66
+ args: { limit: v.optional(v.number()) },
67
+ handler: async (ctx, { limit = 50 }) => {
68
+ return await ctx.db
69
+ .query("telemetry")
70
+ .order("desc")
71
+ .take(limit);
72
+ },
73
+ });
74
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["telemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { mutation, query } from "./_generated/server";
2
+ import { v } from "convex/values";
3
+
4
+ export const track = mutation({
5
+ args: {
6
+ event: v.object({
7
+ type: v.string(),
8
+ query: v.optional(v.string()),
9
+ apiId: v.optional(v.string()),
10
+ resultCount: v.optional(v.number()),
11
+ responseTimeMs: v.optional(v.number()),
12
+ version: v.optional(v.string()),
13
+ platform: v.optional(v.string()),
14
+ nodeVersion: v.optional(v.string()),
15
+ timestamp: v.optional(v.number()),
16
+ }),
17
+ },
18
+ handler: async (ctx, { event }) => {
19
+ await ctx.db.insert("telemetry", {
20
+ type: event.type,
21
+ query: event.query,
22
+ apiId: event.apiId,
23
+ resultCount: event.resultCount,
24
+ responseTimeMs: event.responseTimeMs,
25
+ version: event.version || "unknown",
26
+ platform: event.platform || "unknown",
27
+ nodeVersion: event.nodeVersion || "unknown",
28
+ timestamp: event.timestamp || Date.now(),
29
+ });
30
+ },
31
+ });
32
+
33
+ export const getStats = query({
34
+ args: {},
35
+ handler: async (ctx) => {
36
+ const events = await ctx.db.query("telemetry").collect();
37
+
38
+ const startups = events.filter(e => e.type === "startup").length;
39
+ const searches = events.filter(e => e.type === "search").length;
40
+ const executes = events.filter(e => e.type === "execute").length;
41
+
42
+ const uniqueUsers = new Set(events.map(e => `${e.platform}-${e.nodeVersion}`)).size;
43
+
44
+ const topQueries = events
45
+ .filter(e => e.type === "search" && e.query)
46
+ .reduce((acc, e) => {
47
+ acc[e.query!] = (acc[e.query!] || 0) + 1;
48
+ return acc;
49
+ }, {} as Record<string, number>);
50
+
51
+ const topAPIs = events
52
+ .filter(e => e.type === "execute" && e.apiId)
53
+ .reduce((acc, e) => {
54
+ acc[e.apiId!] = (acc[e.apiId!] || 0) + 1;
55
+ return acc;
56
+ }, {} as Record<string, number>);
57
+
58
+ return {
59
+ totalStartups: startups,
60
+ totalSearches: searches,
61
+ totalExecutes: executes,
62
+ estimatedUniqueUsers: uniqueUsers,
63
+ topQueries: Object.entries(topQueries)
64
+ .sort(([,a], [,b]) => b - a)
65
+ .slice(0, 10),
66
+ topAPIs: Object.entries(topAPIs)
67
+ .sort(([,a], [,b]) => b - a)
68
+ .slice(0, 10),
69
+ };
70
+ },
71
+ });
72
+
73
+ export const getRecent = query({
74
+ args: { limit: v.optional(v.number()) },
75
+ handler: async (ctx, { limit = 50 }) => {
76
+ return await ctx.db
77
+ .query("telemetry")
78
+ .order("desc")
79
+ .take(limit);
80
+ },
81
+ });
@@ -0,0 +1,25 @@
1
+ {
2
+ /* This TypeScript project config describes the environment that
3
+ * Convex functions run in and is used to typecheck them.
4
+ * You can modify it, but some settings are required to use Convex.
5
+ */
6
+ "compilerOptions": {
7
+ /* These settings are not required by Convex and can be modified. */
8
+ "allowJs": true,
9
+ "strict": true,
10
+ "moduleResolution": "Bundler",
11
+ "jsx": "react-jsx",
12
+ "skipLibCheck": true,
13
+ "allowSyntheticDefaultImports": true,
14
+
15
+ /* These compiler options are required by Convex */
16
+ "target": "ESNext",
17
+ "lib": ["ES2021", "dom"],
18
+ "forceConsistentCasingInFileNames": true,
19
+ "module": "ESNext",
20
+ "isolatedModules": true,
21
+ "noEmit": true
22
+ },
23
+ "include": ["./**/*"],
24
+ "exclude": ["./_generated"]
25
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Update providerAPIs status to reflect actual Direct Call status
3
+ * Run: npx convex run updateAPIStatus:update
4
+ */
5
+ export declare const update: any;
6
+ //# sourceMappingURL=updateAPIStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateAPIStatus.d.ts","sourceRoot":"","sources":["updateAPIStatus.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,MAAM,KAsCjB,CAAC"}