@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,512 @@
1
+ import Stripe from "stripe";
2
+ import { httpAction } from "./_generated/server";
3
+ import { api } from "./_generated/api";
4
+
5
+ // Initialize Stripe (will use env var at runtime)
6
+ function getStripe(): Stripe {
7
+ const key = process.env.STRIPE_SECRET_KEY;
8
+ if (!key) {
9
+ throw new Error("STRIPE_SECRET_KEY not configured");
10
+ }
11
+ return new Stripe(key);
12
+ }
13
+
14
+ // CORS headers
15
+ const corsHeaders = {
16
+ "Access-Control-Allow-Origin": "*",
17
+ "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
18
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, stripe-signature",
19
+ };
20
+
21
+ function jsonResponse(data: unknown, status = 200) {
22
+ return new Response(JSON.stringify(data), {
23
+ status,
24
+ headers: { "Content-Type": "application/json", ...corsHeaders },
25
+ });
26
+ }
27
+
28
+ /**
29
+ * Create Stripe Checkout Session
30
+ * POST /api/billing/checkout
31
+ */
32
+ export const createCheckoutSession = httpAction(async (ctx, request) => {
33
+ try {
34
+ const body = await request.json();
35
+ const { workspaceId, returnUrl, mode = "setup" } = body;
36
+
37
+ if (!workspaceId) {
38
+ return jsonResponse({ error: "workspaceId required" }, 400);
39
+ }
40
+
41
+ const stripe = getStripe();
42
+
43
+ // Get workspace
44
+ const workspace = await ctx.runQuery(api.billing.getWorkspace, {
45
+ id: workspaceId,
46
+ });
47
+
48
+ if (!workspace) {
49
+ return jsonResponse({ error: "Workspace not found" }, 404);
50
+ }
51
+
52
+ let customerId = workspace.stripeCustomerId;
53
+
54
+ // Create Stripe customer if doesn't exist
55
+ if (!customerId) {
56
+ const customer = await stripe.customers.create({
57
+ email: workspace.email,
58
+ metadata: {
59
+ workspaceId: workspaceId,
60
+ source: "apiclaw",
61
+ },
62
+ });
63
+ customerId = customer.id;
64
+
65
+ // Link customer to workspace
66
+ await ctx.runMutation(api.billing.linkCustomer, {
67
+ workspaceId: workspaceId,
68
+ stripeCustomerId: customerId,
69
+ });
70
+ }
71
+
72
+ const baseUrl = returnUrl || "https://apiclaw.nordsym.com";
73
+
74
+ // Create checkout session
75
+ if (mode === "setup") {
76
+ // Setup mode - just save card for future billing
77
+ const session = await stripe.checkout.sessions.create({
78
+ customer: customerId,
79
+ mode: "setup",
80
+ payment_method_types: ["card"],
81
+ success_url: `${baseUrl}/billing?session_id={CHECKOUT_SESSION_ID}&success=true`,
82
+ cancel_url: `${baseUrl}/billing?canceled=true`,
83
+ metadata: {
84
+ workspaceId: workspaceId,
85
+ },
86
+ });
87
+
88
+ return jsonResponse({
89
+ checkoutUrl: session.url,
90
+ sessionId: session.id,
91
+ });
92
+ } else if (mode === "subscription") {
93
+ // Create metered subscription
94
+ const priceId = process.env.STRIPE_PRICE_ID_USAGE;
95
+ if (!priceId) {
96
+ return jsonResponse({ error: "Usage price not configured" }, 500);
97
+ }
98
+
99
+ const session = await stripe.checkout.sessions.create({
100
+ customer: customerId,
101
+ mode: "subscription",
102
+ line_items: [
103
+ {
104
+ price: priceId,
105
+ },
106
+ ],
107
+ success_url: `${baseUrl}/billing?session_id={CHECKOUT_SESSION_ID}&success=true`,
108
+ cancel_url: `${baseUrl}/billing?canceled=true`,
109
+ metadata: {
110
+ workspaceId: workspaceId,
111
+ },
112
+ });
113
+
114
+ return jsonResponse({
115
+ checkoutUrl: session.url,
116
+ sessionId: session.id,
117
+ });
118
+ } else {
119
+ return jsonResponse({ error: "Invalid mode. Use 'setup' or 'subscription'" }, 400);
120
+ }
121
+ } catch (e: any) {
122
+ console.error("Checkout error:", e);
123
+ return jsonResponse({ error: e.message || "Failed to create checkout" }, 500);
124
+ }
125
+ });
126
+
127
+ /**
128
+ * Create Stripe Billing Portal Session
129
+ * POST /api/billing/portal
130
+ */
131
+ export const createPortalSession = httpAction(async (ctx, request) => {
132
+ try {
133
+ const body = await request.json();
134
+ const { workspaceId, returnUrl } = body;
135
+
136
+ if (!workspaceId) {
137
+ return jsonResponse({ error: "workspaceId required" }, 400);
138
+ }
139
+
140
+ const stripe = getStripe();
141
+
142
+ // Get workspace
143
+ const workspace = await ctx.runQuery(api.billing.getWorkspace, {
144
+ id: workspaceId,
145
+ });
146
+
147
+ if (!workspace) {
148
+ return jsonResponse({ error: "Workspace not found" }, 404);
149
+ }
150
+
151
+ if (!workspace.stripeCustomerId) {
152
+ return jsonResponse(
153
+ { error: "No billing account. Add a payment method first." },
154
+ 400
155
+ );
156
+ }
157
+
158
+ const session = await stripe.billingPortal.sessions.create({
159
+ customer: workspace.stripeCustomerId,
160
+ return_url: returnUrl || "https://apiclaw.com/workspace?tab=settings&portal=success",
161
+ });
162
+
163
+ return jsonResponse({
164
+ portalUrl: session.url,
165
+ });
166
+ } catch (e: any) {
167
+ console.error("Portal error:", e);
168
+ return jsonResponse({ error: e.message || "Failed to create portal session" }, 500);
169
+ }
170
+ });
171
+
172
+ /**
173
+ * Stripe Webhook Handler
174
+ * POST /api/webhooks/stripe
175
+ */
176
+ export const handleStripeWebhook = httpAction(async (ctx, request) => {
177
+ const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET;
178
+ if (!webhookSecret) {
179
+ console.error("STRIPE_WEBHOOK_SECRET not configured");
180
+ return jsonResponse({ error: "Webhook not configured" }, 500);
181
+ }
182
+
183
+ const stripe = getStripe();
184
+ const signature = request.headers.get("stripe-signature");
185
+
186
+ if (!signature) {
187
+ return jsonResponse({ error: "Missing stripe-signature header" }, 400);
188
+ }
189
+
190
+ let event: Stripe.Event;
191
+
192
+ try {
193
+ const body = await request.text();
194
+ event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
195
+ } catch (err: any) {
196
+ console.error("Webhook signature verification failed:", err.message);
197
+ return jsonResponse({ error: `Webhook Error: ${err.message}` }, 400);
198
+ }
199
+
200
+ // Handle the event
201
+ try {
202
+ switch (event.type) {
203
+ case "checkout.session.completed": {
204
+ const session = event.data.object as Stripe.Checkout.Session;
205
+ await handleCheckoutComplete(ctx, session);
206
+ break;
207
+ }
208
+
209
+ case "customer.subscription.created":
210
+ case "customer.subscription.updated": {
211
+ const subscription = event.data.object as Stripe.Subscription;
212
+ await handleSubscriptionUpdate(ctx, subscription);
213
+ break;
214
+ }
215
+
216
+ case "customer.subscription.deleted": {
217
+ const subscription = event.data.object as Stripe.Subscription;
218
+ await handleSubscriptionCanceled(ctx, subscription);
219
+ break;
220
+ }
221
+
222
+ case "invoice.paid": {
223
+ const invoice = event.data.object as Stripe.Invoice;
224
+ await handleInvoicePaid(ctx, invoice);
225
+ break;
226
+ }
227
+
228
+ case "invoice.payment_failed": {
229
+ const invoice = event.data.object as Stripe.Invoice;
230
+ await handlePaymentFailed(ctx, invoice);
231
+ break;
232
+ }
233
+
234
+ case "setup_intent.succeeded": {
235
+ const setupIntent = event.data.object as Stripe.SetupIntent;
236
+ await handleSetupSuccess(ctx, setupIntent);
237
+ break;
238
+ }
239
+
240
+ case "payment_method.attached": {
241
+ const paymentMethod = event.data.object as Stripe.PaymentMethod;
242
+ await handlePaymentMethodAttached(ctx, paymentMethod);
243
+ break;
244
+ }
245
+
246
+ case "payment_method.detached": {
247
+ const paymentMethod = event.data.object as Stripe.PaymentMethod;
248
+ await handlePaymentMethodDetached(ctx, paymentMethod);
249
+ break;
250
+ }
251
+
252
+ default:
253
+ console.log(`Unhandled event type: ${event.type}`);
254
+ }
255
+
256
+ return jsonResponse({ received: true, type: event.type });
257
+ } catch (e: any) {
258
+ console.error(`Error handling ${event.type}:`, e);
259
+ // Return 200 to prevent Stripe retries for business logic errors
260
+ return jsonResponse({ received: true, error: e.message });
261
+ }
262
+ });
263
+
264
+ // ============================================
265
+ // Webhook Event Handlers
266
+ // ============================================
267
+
268
+ async function handleCheckoutComplete(
269
+ ctx: any,
270
+ session: Stripe.Checkout.Session
271
+ ) {
272
+ const workspaceId = session.metadata?.workspaceId;
273
+ if (!workspaceId) {
274
+ console.log("No workspaceId in checkout session metadata");
275
+ return;
276
+ }
277
+
278
+ // If subscription mode, the subscription webhook will handle it
279
+ if (session.mode === "subscription" && session.subscription) {
280
+ console.log("Subscription checkout completed, waiting for subscription webhook");
281
+ return;
282
+ }
283
+
284
+ // If setup mode, upgrade to usage-based billing
285
+ if (session.mode === "setup") {
286
+ await ctx.runMutation(api.billing.updateSubscription, {
287
+ workspaceId: workspaceId,
288
+ billingPlan: "usage_based",
289
+ });
290
+ console.log(`Workspace ${workspaceId} upgraded to usage-based billing`);
291
+ }
292
+ }
293
+
294
+ async function handleSubscriptionUpdate(
295
+ ctx: any,
296
+ subscription: Stripe.Subscription
297
+ ) {
298
+ const customerId =
299
+ typeof subscription.customer === "string"
300
+ ? subscription.customer
301
+ : subscription.customer.id;
302
+
303
+ // Get workspace by customer ID
304
+ const workspace = await ctx.runQuery(api.billing.getByStripeCustomerId, {
305
+ stripeCustomerId: customerId,
306
+ });
307
+
308
+ if (!workspace) {
309
+ console.log(`No workspace found for customer ${customerId}`);
310
+ return;
311
+ }
312
+
313
+ // Determine plan from subscription
314
+ const plan = subscription.status === "active" ? "usage_based" : "free";
315
+
316
+ await ctx.runMutation(api.billing.updateSubscription, {
317
+ workspaceId: workspace._id,
318
+ stripeSubscriptionId: subscription.id,
319
+ billingPlan: plan,
320
+ });
321
+
322
+ console.log(`Subscription ${subscription.id} updated for workspace ${workspace._id}`);
323
+ }
324
+
325
+ async function handleSubscriptionCanceled(
326
+ ctx: any,
327
+ subscription: Stripe.Subscription
328
+ ) {
329
+ const customerId =
330
+ typeof subscription.customer === "string"
331
+ ? subscription.customer
332
+ : subscription.customer.id;
333
+
334
+ const workspace = await ctx.runQuery(api.billing.getByStripeCustomerId, {
335
+ stripeCustomerId: customerId,
336
+ });
337
+
338
+ if (!workspace) {
339
+ console.log(`No workspace found for customer ${customerId}`);
340
+ return;
341
+ }
342
+
343
+ // Downgrade to free and reset usage
344
+ await ctx.runMutation(api.billing.updateSubscription, {
345
+ workspaceId: workspace._id,
346
+ stripeSubscriptionId: undefined,
347
+ billingPlan: "free",
348
+ });
349
+
350
+ // Reset usage count to 0 for clean slate on free tier
351
+ await ctx.runMutation(api.billing.resetUsageOnCancellation, {
352
+ workspaceId: workspace._id,
353
+ });
354
+
355
+ console.log(`Workspace ${workspace._id} downgraded to free (subscription canceled)`);
356
+ }
357
+
358
+ async function handleInvoicePaid(ctx: any, invoice: Stripe.Invoice) {
359
+ const customerId =
360
+ typeof invoice.customer === "string"
361
+ ? invoice.customer
362
+ : invoice.customer?.id;
363
+
364
+ if (!customerId) return;
365
+
366
+ const workspace = await ctx.runQuery(api.billing.getByStripeCustomerId, {
367
+ stripeCustomerId: customerId,
368
+ });
369
+
370
+ if (!workspace) {
371
+ console.log(`No workspace found for customer ${customerId}`);
372
+ return;
373
+ }
374
+
375
+ // Calculate call count from line items (for metered billing)
376
+ let callCount = 0;
377
+ if (invoice.lines?.data) {
378
+ for (const line of invoice.lines.data) {
379
+ if (line.quantity) {
380
+ callCount += line.quantity;
381
+ }
382
+ }
383
+ }
384
+
385
+ await ctx.runMutation(api.billing.processPayment, {
386
+ stripeInvoiceId: invoice.id,
387
+ workspaceId: workspace._id,
388
+ amount: invoice.amount_paid,
389
+ periodStart: invoice.period_start * 1000,
390
+ periodEnd: invoice.period_end * 1000,
391
+ callCount,
392
+ pdfUrl: invoice.invoice_pdf || undefined,
393
+ });
394
+
395
+ console.log(`Invoice ${invoice.id} processed for workspace ${workspace._id}`);
396
+ }
397
+
398
+ async function handlePaymentFailed(ctx: any, invoice: Stripe.Invoice) {
399
+ const customerId =
400
+ typeof invoice.customer === "string"
401
+ ? invoice.customer
402
+ : invoice.customer?.id;
403
+
404
+ if (!customerId) return;
405
+
406
+ // Update invoice status to failed
407
+ await ctx.runMutation(api.billing.updateInvoiceStatus, {
408
+ stripeInvoiceId: invoice.id,
409
+ status: "failed",
410
+ });
411
+
412
+ console.log(`Payment failed for invoice ${invoice.id}`);
413
+
414
+ // TODO: Send notification to user about failed payment
415
+ }
416
+
417
+ async function handleSetupSuccess(
418
+ ctx: any,
419
+ setupIntent: Stripe.SetupIntent
420
+ ) {
421
+ // Card saved successfully
422
+ const customerId =
423
+ typeof setupIntent.customer === "string"
424
+ ? setupIntent.customer
425
+ : setupIntent.customer?.id;
426
+
427
+ if (!customerId) return;
428
+
429
+ const workspace = await ctx.runQuery(api.billing.getByStripeCustomerId, {
430
+ stripeCustomerId: customerId,
431
+ });
432
+
433
+ if (!workspace) {
434
+ console.log(`No workspace found for customer ${customerId}`);
435
+ return;
436
+ }
437
+
438
+ // Upgrade to usage-based if still on free
439
+ if (!workspace.billingPlan || workspace.billingPlan === "free") {
440
+ await ctx.runMutation(api.billing.updateSubscription, {
441
+ workspaceId: workspace._id,
442
+ billingPlan: "usage_based",
443
+ });
444
+ console.log(`Workspace ${workspace._id} upgraded after setup intent`);
445
+ }
446
+ }
447
+
448
+ async function handlePaymentMethodAttached(
449
+ ctx: any,
450
+ paymentMethod: Stripe.PaymentMethod
451
+ ) {
452
+ // Payment method attached to customer
453
+ const customerId =
454
+ typeof paymentMethod.customer === "string"
455
+ ? paymentMethod.customer
456
+ : paymentMethod.customer?.id;
457
+
458
+ if (!customerId) {
459
+ console.log("Payment method attached but no customer ID");
460
+ return;
461
+ }
462
+
463
+ const workspace = await ctx.runQuery(api.billing.getByStripeCustomerId, {
464
+ stripeCustomerId: customerId,
465
+ });
466
+
467
+ if (!workspace) {
468
+ console.log(`No workspace found for customer ${customerId}`);
469
+ return;
470
+ }
471
+
472
+ // Sync payment method info
473
+ await ctx.runMutation(api.billing.updatePaymentMethodInfo, {
474
+ workspaceId: workspace._id,
475
+ hasPaymentMethod: true,
476
+ paymentMethodType: paymentMethod.type,
477
+ cardBrand: paymentMethod.card?.brand,
478
+ cardLast4: paymentMethod.card?.last4,
479
+ });
480
+
481
+ console.log(`Payment method attached for workspace ${workspace._id}`);
482
+ }
483
+
484
+ async function handlePaymentMethodDetached(
485
+ ctx: any,
486
+ paymentMethod: Stripe.PaymentMethod
487
+ ) {
488
+ // When a payment method is detached, we need to check if customer still has payment methods
489
+ // Since customer info isn't available on detached event, we log it
490
+ console.log(`Payment method ${paymentMethod.id} detached`);
491
+
492
+ // Note: In a production system, you might want to:
493
+ // 1. Query Stripe for remaining payment methods
494
+ // 2. If no payment methods remain, downgrade the workspace
495
+ // For now, we rely on subscription cancellation to handle downgrades
496
+ }
497
+
498
+ // ============================================
499
+ // OPTIONS handlers for CORS
500
+ // ============================================
501
+
502
+ export const checkoutOptions = httpAction(async () => {
503
+ return new Response(null, { headers: corsHeaders });
504
+ });
505
+
506
+ export const portalOptions = httpAction(async () => {
507
+ return new Response(null, { headers: corsHeaders });
508
+ });
509
+
510
+ export const webhookOptions = httpAction(async () => {
511
+ return new Response(null, { headers: corsHeaders });
512
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Get team members for a workspace
3
+ */
4
+ export declare const getMembers: any;
5
+ /**
6
+ * Invite a member to the workspace (creates pending invite)
7
+ */
8
+ export declare const inviteMember: any;
9
+ /**
10
+ * Accept an invite
11
+ */
12
+ export declare const acceptInvite: any;
13
+ /**
14
+ * Remove a member from the workspace
15
+ */
16
+ export declare const removeMember: any;
17
+ /**
18
+ * Get invite details (public, for invite acceptance page)
19
+ */
20
+ export declare const getInviteDetails: any;
21
+ //# sourceMappingURL=teams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teams.d.ts","sourceRoot":"","sources":["teams.ts"],"names":[],"mappings":"AAoBA;;GAEG;AACH,eAAO,MAAM,UAAU,KAuCrB,CAAC;AAMH;;GAEG;AACH,eAAO,MAAM,YAAY,KAoEvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,KA2BvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY,KAwCvB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,gBAAgB,KAqB3B,CAAC"}