diff --git a/server/src/external/stripe/webhookHandlers/handleInvoiceFinalized.ts b/server/src/external/stripe/webhookHandlers/handleInvoiceFinalized.ts index 6f70a49cb..d418efb42 100644 --- a/server/src/external/stripe/webhookHandlers/handleInvoiceFinalized.ts +++ b/server/src/external/stripe/webhookHandlers/handleInvoiceFinalized.ts @@ -13,6 +13,7 @@ import { submitBillingDataToVercel, submitInvoiceToVercel, } from "@/external/vercel/misc/vercelInvoicing.js"; +import { logVercelWebhook } from "@/external/vercel/misc/vercelMiddleware.js"; import { CusService } from "@/internal/customers/CusService.js"; import { CusProductService } from "@/internal/customers/cusProducts/CusProductService.js"; import { FeatureService } from "@/internal/features/FeatureService.js"; @@ -59,9 +60,6 @@ export const handleInvoiceFinalized = async ({ const subId = invoiceToSubId({ invoice }); - console.log("subId", subId); - console.log("will Invoice Vercel", subId, invoice.amount_due > 0); - if (subId) { const stripeCli = createStripeCli({ org, env }); // Handle Vercel custom payment method invoices @@ -72,9 +70,6 @@ export const handleInvoiceFinalized = async ({ subscription.metadata?.vercel_installation_id; const vercelBillingPlanId = subscription.metadata?.vercel_billing_plan_id; - console.log("vercelInstallationId", vercelInstallationId); - console.log("vercelBillingPlanId", vercelBillingPlanId); - if ( vercelInstallationId && vercelBillingPlanId && @@ -86,15 +81,14 @@ export const handleInvoiceFinalized = async ({ // Only process if it's a custom payment method (Vercel) if (paymentMethod.type === "custom") { - console.info( - "🔵 Vercel invoice finalized, submitting to Vercel marketplace", - { - invoiceId: invoice.id, - subscriptionId: subscription.id, - vercelInstallationId, - amountDue: invoice.amount_due / 100, + logVercelWebhook({ + logger, + org, + event: { + type: "marketplace.invoice.finalized", + id: invoice.id, }, - ); + }); try { // Get customer and product @@ -132,10 +126,8 @@ export const handleInvoiceFinalized = async ({ product, }); - console.info("✅ Vercel billing data submitted"); - // Submit invoice to Vercel - const result = await submitInvoiceToVercel({ + await submitInvoiceToVercel({ installationId: vercelInstallationId, invoice, customer, @@ -144,14 +136,6 @@ export const handleInvoiceFinalized = async ({ features, }); - console.info( - "✅ Vercel invoice submitted, waiting for payment confirmation webhook", - { - vercelInvoiceId: result.invoiceId, - stripeInvoiceId: invoice.id, - }, - ); - // Do NOT report payment to Stripe here - we've only submitted the invoice to Vercel // Vercel will process payment asynchronously and send marketplace.invoice.paid webhook // handleMarketplaceInvoicePaid will then: @@ -159,9 +143,11 @@ export const handleInvoiceFinalized = async ({ // 2. Report payment as "guaranteed" to Stripe // 3. Attach payment record to invoice (marks it as paid) } catch (error: any) { - console.error("❌ Failed to process Vercel invoice", { - error: error.message, - invoiceId: invoice.id, + logger.error("Failed to process Vercel invoice", { + data: { + error: error.message, + invoiceId: invoice.id, + }, }); } } diff --git a/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts b/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts index 078617a08..64d7c348b 100644 --- a/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts +++ b/server/src/external/stripe/webhookHandlers/handleInvoicePaid.ts @@ -233,11 +233,6 @@ export const handleInvoicePaid = async ({ ), ); - console.log( - "Invoice paid, filtered cus products:", - cusProducts.map((cp) => `${cp.product.name} - ${cp.product.id}`), - ); - if (cusProducts.length === 0) { cusProducts = activeCusProducts; } diff --git a/server/src/external/vercel/handlers/handleListBillingPlans.ts b/server/src/external/vercel/handlers/handleListBillingPlans.ts index 482aa0858..7bbdd41a2 100644 --- a/server/src/external/vercel/handlers/handleListBillingPlans.ts +++ b/server/src/external/vercel/handlers/handleListBillingPlans.ts @@ -61,15 +61,6 @@ function calculatePrepaidCosts({ // Calculate total cost for this feature const featureCost = subscriptionItemQuantity * unitAmount; totalPrepaidCost += featureCost; - - console.info("Calculated prepaid feature cost for billing plan", { - featureId: options.feature_id, - quantity: options.quantity, - billingUnits, - subscriptionItemQuantity, - unitAmount, - featureCost, - }); } } @@ -139,8 +130,8 @@ export const handleListBillingPlansPerInstall = createRoute({ metadata: z.string().optional(), }), handler: async (c) => { - const { orgId, env, integrationConfigurationId } = c.req.param(); - const { db, org, features, logger } = c.get("ctx"); + const { orgId, env } = c.req.param(); + const { db, org, logger } = c.get("ctx"); // Parse metadata from query params let metadata: Record = {}; diff --git a/server/src/external/vercel/handlers/installations/handleDeleteInstallation.ts b/server/src/external/vercel/handlers/installations/handleDeleteInstallation.ts index 287a2a854..677a23867 100644 --- a/server/src/external/vercel/handlers/installations/handleDeleteInstallation.ts +++ b/server/src/external/vercel/handlers/installations/handleDeleteInstallation.ts @@ -9,11 +9,6 @@ export const handleDeleteInstallation = createRoute({ const { db, org, logger } = ctx; try { - // 1. Delete all resources for this installation in parallel - logger.info("Deleting resources for installation", { - integrationConfigurationId, - }); - const resources = await VercelResourceService.listByInstallation({ db, installationId: integrationConfigurationId, @@ -32,19 +27,6 @@ export const handleDeleteInstallation = createRoute({ ), ); - const successCount = deleteResults.filter( - (r) => r.status === "fulfilled", - ).length; - const failCount = deleteResults.filter( - (r) => r.status === "rejected", - ).length; - - logger.info("Resources deletion complete", { - total: resources.length, - success: successCount, - failed: failCount, - }); - // 2. Delete the customer/installation await deleteCusById({ db: ctx.db, @@ -59,11 +41,6 @@ export const handleDeleteInstallation = createRoute({ error, integrationConfigurationId, }); - console.log( - "ERROR: Error deleting installation: --------------------------------", - ); - console.log(error); - console.log("--------------------------------"); } return c.json( { diff --git a/server/src/external/vercel/handlers/installations/handleGetInstallation.ts b/server/src/external/vercel/handlers/installations/handleGetInstallation.ts index 124099d10..fa29cd0fc 100644 --- a/server/src/external/vercel/handlers/installations/handleGetInstallation.ts +++ b/server/src/external/vercel/handlers/installations/handleGetInstallation.ts @@ -17,17 +17,6 @@ export const handleGetInstallation = createRoute({ env: ctx.env, }); - // const billingPlan = customer?.customer_products?.find((x) => - // isMainProduct({ - // product: { - // ...x.product, - // prices: x.customer_prices.map((y) => y.price) ?? {}, - // entitlements: x.customer_entitlements.map((y) => y.entitlement) ?? [], - // }, - // prices: x.customer_prices.map((y) => y.price) ?? [], - // }), - // ); - if (!customer) { return c.json( { @@ -41,6 +30,7 @@ export const handleGetInstallation = createRoute({ { notification: null, billingPlan: + // edge case: [0] = add-on [1] = main customer.customer_products?.[0] !== undefined ? (productToBillingPlan({ product: cusProductToProduct({ diff --git a/server/src/external/vercel/handlers/installations/handleUpsertInstallation.ts b/server/src/external/vercel/handlers/installations/handleUpsertInstallation.ts index a7d5ab5b2..6e219e3f2 100644 --- a/server/src/external/vercel/handlers/installations/handleUpsertInstallation.ts +++ b/server/src/external/vercel/handlers/installations/handleUpsertInstallation.ts @@ -24,17 +24,8 @@ import { productToBillingPlan } from "../handleListBillingPlans.js"; export const handleUpsertInstallation = createRoute({ handler: async (c) => { - console.log("Vercel Webhook Router: PUT /installations"); - console.log("Vercel Webhook Router: req.params", c.req.param()); - const body = await c.req.json(); - console.log("Vercel Webhook Router: req.body", body); - const ctx = c.get("ctx"); - console.log("Vercel Webhook Router: ctx.org", ctx.org); - console.log("Vercel Webhook Router: ctx.env", ctx.env); - console.log("Vercel Webhook Router: ctx.features", ctx.features); - const { integrationConfigurationId } = c.req.param(); let createdCustomer: Customer | null = null; @@ -50,7 +41,6 @@ export const handleUpsertInstallation = createRoute({ c.req.header("Authorization") as string, ); const claims = await verifyToken({ token, org: ctx.org, env: ctx.env }); - console.log("Vercel Webhook Router: claims", claims); if ( !verifyClaims({ @@ -81,13 +71,6 @@ export const handleUpsertInstallation = createRoute({ frozen_time: Math.floor(Date.now() / 1000), }); testClockId = testClock.id; - - ctx.logger.info( - "Created test clock for sandbox Vercel installation", - { - testClockId: testClock.id, - }, - ); } const stripeCustomer = await createStripeCustomer({ @@ -140,26 +123,15 @@ export const handleUpsertInstallation = createRoute({ }, }, }); - - if (customPaymentMethod) { - ctx.logger.info("✅ Created custom payment method for Vercel", { - paymentMethodId: customPaymentMethod.id, - customerId: stripeCustomer.id, - }); - } else { - ctx.logger.warn( - "⚠️ No custom payment method created - check org config", - ); - } } } } catch (_) { - console.log( + ctx.logger.error( "ERROR: Error creating customer: --------------------------------", ); - console.log(_); - console.log(ctx.org); - console.log("--------------------------------"); + ctx.logger.error(_); + ctx.logger.error(ctx.org); + ctx.logger.error("--------------------------------"); } if (createdCustomer) { diff --git a/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoicePaid.ts b/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoicePaid.ts index cb4e5c992..e174e5287 100644 --- a/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoicePaid.ts +++ b/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoicePaid.ts @@ -45,13 +45,6 @@ export const handleMarketplaceInvoicePaid = async ({ invoiceDate, } = payload; - logger.info("💰 marketplace.invoice.paid webhook received", { - vercelInvoiceId: invoiceId, - stripeInvoiceId: externalInvoiceId, - amount: invoiceTotal, - installationId, - }); - const stripeCli = createStripeCli({ org, env }); // 1. Get the invoice @@ -59,23 +52,12 @@ export const handleMarketplaceInvoicePaid = async ({ expand: ["subscription"], }); - logger.info("Retrieved Stripe invoice", { - invoiceId: invoice.id, - status: invoice.status, - amountDue: invoice.amount_due / 100, - }); - // 2. Check if already paid if (invoice.status === "paid") { logger.info("Invoice already marked as paid, skipping"); return; } - console.log( - "invoice.lines.data", - JSON.stringify(invoice.lines.data, null, 4), - ); - // 3. Get subscription and payment method const subscription = await stripeCli.subscriptions.retrieve( invoice.lines.data.find( @@ -85,22 +67,10 @@ export const handleMarketplaceInvoicePaid = async ({ )?.parent?.subscription_item_details?.subscription as string, ); - console.log("subscription", JSON.stringify(subscription, null, 4)); - const customPaymentMethod = await stripeCli.paymentMethods.retrieve( subscription.default_payment_method as string, ); - logger.info("Found custom payment method", { - paymentMethodId: customPaymentMethod.id, - type: customPaymentMethod.type, - }); - - // 4. Create cus_product BEFORE reporting payment - // This ensures the user gets access to the product when payment is confirmed - // and the invoice.paid webhook can find the cus_product - logger.info("Creating customer product before reporting payment"); - try { const partialCustomer = await CusService.getByStripeId({ db, @@ -108,9 +78,6 @@ export const handleMarketplaceInvoicePaid = async ({ }); if (!partialCustomer) { - logger.error("Customer not found for payment", { - stripeCustomerId: invoice.customer, - }); throw new Error("Customer not found"); } @@ -122,9 +89,6 @@ export const handleMarketplaceInvoicePaid = async ({ }); if (!customer) { - logger.error("Customer not found", { - internalCustomerId: partialCustomer.internal_id, - }); throw new Error("Customer not found"); } @@ -142,9 +106,6 @@ export const handleMarketplaceInvoicePaid = async ({ }); if (!product) { - logger.error("Product not found", { - billingPlanId: vercelBillingPlanId, - }); throw new Error("Product not found"); } @@ -158,12 +119,6 @@ export const handleMarketplaceInvoicePaid = async ({ const isRenewal = existingCusProducts.length > 0; - logger.info("Detected subscription type", { - isRenewal, - subscriptionId: subscription.id, - existingCusProductCount: existingCusProducts.length, - }); - // Fetch Vercel resource by ID from subscription metadata let optionsList: FeatureOptions[] = []; const vercelResourceId = subscription.metadata?.vercel_resource_id; @@ -178,11 +133,6 @@ export const handleMarketplaceInvoicePaid = async ({ }); if (resource?.metadata && Object.keys(resource.metadata).length > 0) { - logger.info("Parsing prepaid quantities from resource metadata", { - resourceId: resource.id, - metadata: resource.metadata, - }); - optionsList = parseVercelPrepaidQuantities({ metadata: resource.metadata, product, @@ -196,21 +146,9 @@ export const handleMarketplaceInvoicePaid = async ({ }); // Continue with empty optionsList } - } else { - logger.info( - "No resource ID in subscription metadata (legacy or installation-level billing)", - { - vercelResourceId, - }, - ); } if (isRenewal) { - // Process renewal - reset balances after payment confirmation - logger.info( - "Processing renewal - resetting balances after payment confirmation", - ); - // Call sendUsageAndReset which handles all balance resets const activeProduct = existingCusProducts[0]; @@ -223,14 +161,8 @@ export const handleMarketplaceInvoicePaid = async ({ stripeSubs: [subscription], logger, }); - - logger.info( - "✅ Renewal balance resets completed after payment confirmation", - ); } else { // New subscription - create cus_product - logger.info("New subscription - creating cus_product"); - await createFullCusProduct({ db, attachParams: attachToInsertParams( @@ -260,11 +192,6 @@ export const handleMarketplaceInvoicePaid = async ({ scenario: AttachScenario.New, logger, }); - - logger.info("✅ Customer product created", { - productId: product.id, - customerId: customer.id, - }); } } catch (error: any) { logger.error("❌ Failed to create customer product", { @@ -275,8 +202,6 @@ export const handleMarketplaceInvoicePaid = async ({ // 5. Report successful payment to Stripe via Payment Records API // This marks the payment as "guaranteed" and allows Stripe to mark the invoice as paid - logger.info("Reporting guaranteed payment to Stripe"); - const paymentRecord = await stripeCli.paymentRecords.reportPayment({ amount_requested: { value: invoice.amount_due, @@ -302,20 +227,11 @@ export const handleMarketplaceInvoicePaid = async ({ }, }); - logger.info("✅ Payment reported to Stripe", { - paymentRecordId: paymentRecord.id, - }); - // 6. Attach payment record to invoice try { await stripeCli.invoices.attachPayment(externalInvoiceId, { payment_record: paymentRecord.id, }); - - logger.info("✅ Payment record attached to invoice", { - invoiceId: externalInvoiceId, - paymentRecordId: paymentRecord.id, - }); } catch (error: any) { // Might already be attached from handleInvoicePaymentAttemptRequired if (error.code === "resource_already_exists") { @@ -324,8 +240,4 @@ export const handleMarketplaceInvoicePaid = async ({ throw error; } } - - logger.info( - "🎉 Vercel payment confirmed - invoice paid, subscription active", - ); }; diff --git a/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoidNotPaid.ts b/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoidNotPaid.ts index e79734973..c964782b4 100644 --- a/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoidNotPaid.ts +++ b/server/src/external/vercel/handlers/marketplace/handleMarketplaceInvoidNotPaid.ts @@ -33,13 +33,6 @@ export const handleMarketplaceInvoiceNotPaid = async ({ invoiceDate, } = payload; - logger.info("❌ marketplace.invoice.notpaid webhook received", { - vercelInvoiceId: invoiceId, - stripeInvoiceId: externalInvoiceId, - amount: invoiceTotal, - installationId, - }); - const stripeCli = createStripeCli({ org, env }); // 1. Get the invoice @@ -47,23 +40,12 @@ export const handleMarketplaceInvoiceNotPaid = async ({ expand: ["subscription"], }); - logger.info("Retrieved Stripe invoice", { - invoiceId: invoice.id, - status: invoice.status, - amountDue: invoice.amount_due / 100, - }); - // 2. Check if already paid if (invoice.status === "paid") { logger.info("Invoice already marked as not paid, skipping"); return; } - console.log( - "invoice.lines.data", - JSON.stringify(invoice.lines.data, null, 4), - ); - // 3. Get subscription and payment method const subscription = await stripeCli.subscriptions.retrieve( invoice.lines.data.find( @@ -73,17 +55,10 @@ export const handleMarketplaceInvoiceNotPaid = async ({ )?.parent?.subscription_item_details?.subscription as string, ); - console.log("subscription", JSON.stringify(subscription, null, 4)); - const customPaymentMethod = await stripeCli.paymentMethods.retrieve( subscription.default_payment_method as string, ); - logger.info("Found custom payment method", { - paymentMethodId: customPaymentMethod.id, - type: customPaymentMethod.type, - }); - try { const partialCustomer = await CusService.getByStripeId({ db, @@ -139,8 +114,6 @@ export const handleMarketplaceInvoiceNotPaid = async ({ // 5. Report failed payment to Stripe via Payment Records API // This marks the payment as "failed" and allows Stripe to mark the invoice as not paid - logger.info("Reporting failed payment to Stripe"); - const paymentRecord = await stripeCli.paymentRecords.reportPayment({ amount_requested: { value: invoice.amount_due, @@ -166,36 +139,18 @@ export const handleMarketplaceInvoiceNotPaid = async ({ }, }); - logger.info("✅ Payment reported to Stripe", { - paymentRecordId: paymentRecord.id, - }); - // 6. Attach payment record to invoice try { await stripeCli.invoices.attachPayment(externalInvoiceId, { payment_record: paymentRecord.id, }); - - logger.info("✅ Payment record attached to invoice", { - invoiceId: externalInvoiceId, - paymentRecordId: paymentRecord.id, - }); } catch (error: any) { // Might already be attached from handleMarketplaceInvoicePaid if (error.code === "resource_already_exists") { - logger.info("Payment record already attached to invoice"); } else { throw error; } } await stripeCli.subscriptions.cancel(subscription.id); - - logger.info("Cancelled subscription", { - subscriptionId: subscription.id, - }); - - logger.info( - "❌ Vercel payment failed - invoice not paid, subscription cancelled", - ); }; diff --git a/server/src/external/vercel/handlers/resources/handleCreateResource.ts b/server/src/external/vercel/handlers/resources/handleCreateResource.ts index 001d834b9..640920f31 100644 --- a/server/src/external/vercel/handlers/resources/handleCreateResource.ts +++ b/server/src/external/vercel/handlers/resources/handleCreateResource.ts @@ -32,13 +32,6 @@ export const handleCreateResource = createRoute({ const { db, org, features, logger } = c.get("ctx"); const { productId, name, metadata, billingPlanId } = c.req.valid("json"); - logger.info("Creating Vercel resource", { - productId, - name, - billingPlanId, - integrationConfigurationId, - }); - // 1. Get customer const customer = await CusService.getFull({ db, @@ -75,7 +68,7 @@ export const handleCreateResource = createRoute({ // 2. Create resource in database (enforces 1-resource limit) const resourceId = generateId("vre"); - const resource = await VercelResourceService.create({ + await VercelResourceService.create({ db, resource: { id: resourceId, @@ -88,10 +81,6 @@ export const handleCreateResource = createRoute({ }, }); - logger.info("Resource created in database", { - resourceId: resource.id, - }); - // 3. Create subscription (installation-level billing) const { product } = await createVercelSubscription({ db, diff --git a/server/src/external/vercel/handlers/resources/handleDeleteResource.ts b/server/src/external/vercel/handlers/resources/handleDeleteResource.ts index 9a8efd700..086fb934e 100644 --- a/server/src/external/vercel/handlers/resources/handleDeleteResource.ts +++ b/server/src/external/vercel/handlers/resources/handleDeleteResource.ts @@ -10,12 +10,7 @@ export const handleDeleteResource = createRoute({ handler: async (c) => { const { orgId, env, integrationConfigurationId, resourceId } = c.req.param(); - const { db, logger } = c.get("ctx"); - - logger.info("Deleting Vercel resource", { - integrationConfigurationId, - resourceId, - }); + const { db } = c.get("ctx"); await VercelResourceService.delete({ db, diff --git a/server/src/external/vercel/handlers/resources/handleGetResource.ts b/server/src/external/vercel/handlers/resources/handleGetResource.ts index 346685cf6..9b59f2582 100644 --- a/server/src/external/vercel/handlers/resources/handleGetResource.ts +++ b/server/src/external/vercel/handlers/resources/handleGetResource.ts @@ -10,12 +10,7 @@ export const handleGetResource = createRoute({ handler: async (c) => { const { orgId, env, integrationConfigurationId, resourceId } = c.req.param(); - const { db, logger } = c.get("ctx"); - - logger.info("Getting Vercel resource", { - integrationConfigurationId, - resourceId, - }); + const { db } = c.get("ctx"); const resource = await VercelResourceService.getByIdAndInstallation({ db, diff --git a/server/src/external/vercel/misc/vercelAuth.ts b/server/src/external/vercel/misc/vercelAuth.ts index 9d3ca648e..5052d800a 100644 --- a/server/src/external/vercel/misc/vercelAuth.ts +++ b/server/src/external/vercel/misc/vercelAuth.ts @@ -46,7 +46,6 @@ export async function verifyToken({ throw new AuthError("Invalid issuer"); } - console.log("Vercel auth claims", JSON.stringify(claims, null, 4)); return claims; } catch (err) { if (err instanceof JWTExpired) { @@ -117,26 +116,23 @@ export class AuthError extends Error {} * 5. Store validated claims in context */ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { - const { org, env, logger } = c.get("ctx"); + const { org, env } = c.get("ctx"); const authHeader = c.req.header("authorization"); const authType = c.req.header("x-vercel-auth"); // Validate required headers if (!authHeader) { - logger.warn("Missing Authorization header"); return c.json({ error: "Unauthorized", code: "missing_auth_header" }, 401); } if (!authType) { - logger.warn("Missing X-Vercel-Auth header"); return c.json( { error: "Unauthorized", code: "missing_auth_type_header" }, 401, ); } - if (authType !== "user" && authType !== "system") { - logger.warn("Invalid X-Vercel-Auth value", { authType }); + if (!["user", "system"].includes(authType)) { return c.json({ error: "Unauthorized", code: "invalid_auth_type" }, 401); } @@ -145,7 +141,6 @@ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { try { token = getAuthorizationToken(authHeader); } catch (error) { - logger.warn("Invalid Authorization header format"); return c.json( { error: "Unauthorized", code: "invalid_auth_header_format" }, 401, @@ -157,10 +152,6 @@ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { try { claims = await verifyToken({ token, org, env }); } catch (error: any) { - logger.warn("JWT verification failed", { - error: error.message, - authType, - }); return c.json( { error: "Unauthorized", @@ -186,12 +177,6 @@ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { if (authType === "user") { // User auth: always validate installation_id matches URL param if (claims.installation_id !== integrationConfigurationId) { - logger.warn("Installation ID mismatch for user auth", { - claim_installation_id: claims.installation_id, - url_installation_id: integrationConfigurationId, - path, - all_params: c.req.param(), - }); return c.json( { error: "Forbidden", code: "installation_id_mismatch" }, 403, @@ -201,12 +186,6 @@ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { // System auth: validate installation_id only if not null if (claims.installation_id !== null) { if (claims.installation_id !== integrationConfigurationId) { - logger.warn("Installation ID mismatch for system auth", { - claim_installation_id: claims.installation_id, - url_installation_id: integrationConfigurationId, - path, - all_params: c.req.param(), - }); return c.json( { error: "Forbidden", code: "installation_id_mismatch" }, 403, @@ -216,13 +195,6 @@ export const vercelOidcAuthMiddleware = async (c: any, next: any) => { // If installation_id is null, we only validate JWKS (already done above) } } - - logger.debug("OIDC auth successful", { - authType, - installation_id: claims.installation_id, - user_id: claims.user_id, - }); - // Store claims in context for downstream handlers c.set("vercelClaims", claims); diff --git a/server/src/external/vercel/misc/vercelInvoicing.ts b/server/src/external/vercel/misc/vercelInvoicing.ts index 2d266c8b5..40d99a58f 100644 --- a/server/src/external/vercel/misc/vercelInvoicing.ts +++ b/server/src/external/vercel/misc/vercelInvoicing.ts @@ -166,8 +166,8 @@ export const submitInvoiceToVercel = async ({ ? { test: { validate: true, - // result: "paid", - result: "notpaid", + result: "paid", + // result: "notpaid", }, } : {}), @@ -213,11 +213,6 @@ export const parseVercelPrepaidQuantities = ({ ); if (!entitlement) { - console.warn("Feature not found in product, skipping prepaid quantity", { - featureId, - productId: product.id, - quantity, - }); continue; } @@ -228,16 +223,6 @@ export const parseVercelPrepaidQuantities = ({ }); if (!prepaidPrice) { - console.warn( - "Feature is not prepaid or has no price configured, skipping", - { - featureId, - featureName: entitlement.feature.name, - internalFeatureId: entitlement.internal_feature_id, - productId: product.id, - quantity, - }, - ); continue; } @@ -247,13 +232,6 @@ export const parseVercelPrepaidQuantities = ({ internal_feature_id: entitlement.internal_feature_id, quantity, }); - - console.info("Parsed prepaid quantity from Vercel metadata", { - featureId, - featureName: entitlement.feature.name, - quantity, - priceId: prepaidPrice.id, - }); } return optionsList; diff --git a/server/src/external/vercel/misc/vercelMiddleware.ts b/server/src/external/vercel/misc/vercelMiddleware.ts index 8da40edeb..39b67f7c5 100644 --- a/server/src/external/vercel/misc/vercelMiddleware.ts +++ b/server/src/external/vercel/misc/vercelMiddleware.ts @@ -1,5 +1,7 @@ -import { AppEnv } from "@autumn/shared"; +import { AppEnv, type Organization } from "@autumn/shared"; +import chalk from "chalk"; import type { Context, Next } from "hono"; +import type { Logger } from "@/external/logtail/logtailUtils.js"; import type { HonoEnv } from "@/honoUtils/HonoEnv.js"; import { FeatureService } from "@/internal/features/FeatureService.js"; import { OrgService } from "@/internal/orgs/OrgService.js"; @@ -27,3 +29,26 @@ export const vercelSeederMiddleware = async ( await next(); }; + +export const logVercelWebhook = ({ + logger, + org, + event, +}: { + logger: Logger; + org: Organization; + event: any; +}) => { + logger.info( + `${chalk.magenta("VERCEL").padEnd(18)} ${event.type.padEnd(30)} ${org.slug} | ${event.id}`, + ); +}; + +export const vercelLogMiddleware = async (c: Context, next: Next) => { + const { db, logger, org } = c.get("ctx"); + const body = await c.req.json(); + + logVercelWebhook({ logger, org, event: body }); + + await next(); +}; diff --git a/server/src/external/vercel/misc/vercelSignatureMiddleware.ts b/server/src/external/vercel/misc/vercelSignatureMiddleware.ts index 23aa37d96..805f8d0aa 100644 --- a/server/src/external/vercel/misc/vercelSignatureMiddleware.ts +++ b/server/src/external/vercel/misc/vercelSignatureMiddleware.ts @@ -72,7 +72,5 @@ export const vercelSignatureMiddleware = async (c: any, next: any) => { return c.json({ error: "Unauthorized", code: "invalid_signature" }, 401); } - logger.debug("Webhook signature validated", { env }); - await next(); }; diff --git a/server/src/external/vercel/misc/vercelSubscriptions.ts b/server/src/external/vercel/misc/vercelSubscriptions.ts index c6fac6632..009e2f88d 100644 --- a/server/src/external/vercel/misc/vercelSubscriptions.ts +++ b/server/src/external/vercel/misc/vercelSubscriptions.ts @@ -65,11 +65,6 @@ export const createVercelSubscription = async ({ metadata?: Record; resourceId?: string; }): Promise<{ subscription: Stripe.Subscription; product: FullProduct }> => { - logger.info("Creating Vercel subscription", { - billingPlanId, - integrationConfigurationId, - }); - // 1. Check for existing subscription (only allow one per installation) const existingSubscription = stripeCustomer.subscriptions?.data.find( (s) => s.metadata.vercel_installation_id === integrationConfigurationId, @@ -121,23 +116,13 @@ export const createVercelSubscription = async ({ }); } - logger.info("Found custom payment method", { - paymentMethodId: customPaymentMethod.id, - type: customPaymentMethod.type, - }); - // 4. Parse prepaid quantities from metadata if provided let optionsList; if (metadata && Object.keys(metadata).length > 0) { - logger.info("Parsing prepaid quantities from metadata", { - metadata, - productId: product.id, - }); optionsList = parseVercelPrepaidQuantities({ metadata, product, prices: product.prices, - logger, }); } @@ -176,15 +161,6 @@ export const createVercelSubscription = async ({ logger, }); - logger.info("Subscription created with custom payment method", { - subscriptionId: subscription.id, - status: subscription.status, - latestInvoiceId: - typeof subscription.latest_invoice === "string" - ? subscription.latest_invoice - : subscription.latest_invoice?.id, - }); - // Subscription will be 'incomplete' initially with an 'open' invoice // Payment flow: // 1. invoice.finalized webhook → handleInvoiceFinalized submits invoice to Vercel diff --git a/server/src/external/vercel/services/VercelResourceService.ts b/server/src/external/vercel/services/VercelResourceService.ts index 7b308ed80..e88d82a80 100644 --- a/server/src/external/vercel/services/VercelResourceService.ts +++ b/server/src/external/vercel/services/VercelResourceService.ts @@ -28,7 +28,7 @@ export class VercelResourceService { db, installationId: resource.installation_id, orgId: resource.org_id, - env: resource.env, + env: resource.env as AppEnv, }); if (existing) { @@ -136,7 +136,7 @@ export class VercelResourceService { if (!resource) { throw new RecaseError({ message: `Resource ${resourceId} not found for installation ${installationId}`, - code: ErrCode.NotFound, + code: ErrCode.VercelResourceNotFound, statusCode: StatusCodes.NOT_FOUND, }); } diff --git a/server/src/external/vercel/vercelWebhookRouter.ts b/server/src/external/vercel/vercelWebhookRouter.ts index 2de7c96f0..10d35ff50 100644 --- a/server/src/external/vercel/vercelWebhookRouter.ts +++ b/server/src/external/vercel/vercelWebhookRouter.ts @@ -14,7 +14,10 @@ import { handleGetResource } from "./handlers/resources/handleGetResource.js"; import { handleUpdateResource } from "./handlers/resources/handleUpdateResource.js"; import { captureRawBody } from "./misc/rawBodyMiddleware.js"; import { vercelOidcAuthMiddleware } from "./misc/vercelAuth.js"; -import { vercelSeederMiddleware } from "./misc/vercelMiddleware.js"; +import { + vercelLogMiddleware, + vercelSeederMiddleware, +} from "./misc/vercelMiddleware.js"; import { vercelSignatureMiddleware } from "./misc/vercelSignatureMiddleware.js"; export const vercelWebhookRouter = new Hono(); @@ -95,10 +98,9 @@ vercelWebhookRouter.post( vercelSeederMiddleware, captureRawBody, vercelSignatureMiddleware, + vercelLogMiddleware, async (c) => { const { db, org, env, logger } = c.get("ctx"); - const params = c.req.param(); - const headers = c.req.header(); let body: any; try { body = await c.req.json(); @@ -106,16 +108,6 @@ vercelWebhookRouter.post( body = {}; } - logger.info("Vercel webhook received", { - method: "POST", - eventType: body.type, - params, - headers, - body, - }); - console.log("Vercel webhook headers", JSON.stringify(headers, null, 4)); - console.log("Vercel webhook received", "POST", params, body); - const eventType = body.type; try { diff --git a/shared/enums/ErrCode.ts b/shared/enums/ErrCode.ts index 62bf555bf..9d692aaa8 100644 --- a/shared/enums/ErrCode.ts +++ b/shared/enums/ErrCode.ts @@ -166,4 +166,5 @@ export const ErrCode = { // Vercel VercelSubscriptionAlreadyExists: "vercel_subscription_already_exists", VercelSubscriptionNotFound: "vercel_subscription_not_found", + VercelResourceNotFound: "vercel_resource_not_found", };