fixed some error with eventsRouter?

This commit is contained in:
John Yeo
2025-01-30 16:00:00 +00:00
parent 2135bd5648
commit 85fa92bea2
9 changed files with 181 additions and 82 deletions

103
server/src/external/autumn/autumnCli.ts vendored Normal file
View File

@@ -0,0 +1,103 @@
export class Autumn {
private apiKey: string;
public headers: Record<string, string>;
public baseUrl: string;
constructor() {
this.apiKey = process.env.AUTUMN_API_KEY || "";
this.headers = {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
};
this.baseUrl = "https://api.useautumn.com/v1";
}
async get(path: string) {
const response = await fetch(`${this.baseUrl}${path}`, {
headers: this.headers,
});
return response.json();
}
async post(path: string, body: any) {
const response = await fetch(`${this.baseUrl}${path}`, {
method: "POST",
headers: this.headers,
body: JSON.stringify(body),
});
return response.json();
}
async createCustomer({
id,
email,
name,
fingerprint,
}: {
id: string;
email: string;
name: string;
fingerprint?: string;
}) {
const data = await this.post("/customers", {
id,
email,
name,
fingerprint,
});
return data;
}
async attach({
customerId,
productId,
options,
}: {
customerId: string;
productId: string;
options?: any;
}) {
const data = await this.post(`/attach`, {
customer_id: customerId,
product_id: productId,
options,
});
return data;
}
async sendEvent({
customerId,
eventName,
properties,
}: {
customerId: string;
eventName: string;
properties?: any;
}) {
const data = await this.post(`/events`, {
customer_id: customerId,
event_name: eventName,
properties,
});
return data;
}
async entitled({
customerId,
featureId,
quantity,
}: {
customerId: string;
featureId: string;
quantity?: number;
}) {
const data = await this.get(
`/entitled?customer_id=${customerId}&feature_id=${featureId}&quantity=${quantity}`
);
return data;
}
}

View File

@@ -0,0 +1 @@

View File

@@ -26,6 +26,10 @@ export const createNewCustomer = async ({
customer: CreateCustomer;
nextResetAt?: number;
}) => {
console.log("Creating new customer");
console.log("Org ID:", orgId);
console.log("Customer data:", customer);
const org = await OrgService.getFullOrg({
sb,
orgId,
@@ -33,6 +37,9 @@ export const createNewCustomer = async ({
const customerData: Customer = {
...customer,
name: customer.name || "",
email: customer.email || "",
internal_id: generateId("cus"),
org_id: orgId,
created_at: Date.now(),

View File

@@ -32,6 +32,7 @@ import { ProductService } from "@/internal/products/ProductService.js";
import { handleChangeProduct } from "@/internal/customers/change-product/handleChangeProduct.js";
import chalk from "chalk";
import { AttachParams } from "@/internal/customers/products/AttachParams.js";
import { Autumn } from "@/external/autumn/autumnCli.js";
export const attachRouter = Router();

View File

@@ -1,6 +1,7 @@
import { Router } from "express";
import {
AppEnv,
CreateEventSchema,
Customer,
ErrCode,
Event,
@@ -28,33 +29,7 @@ const getEventAndCustomer = async (req: any) => {
const orgId = req.orgId;
const env = req.env;
let newEvent: Event;
let customer: Customer;
try {
// 1. Validate request body
EventSchema.omit({
id: true,
org_id: true,
env: true,
properties: true,
}).parse(req.body);
newEvent = {
id: generateId("evt"),
org_id: orgId,
env: env,
timestamp: Date.now(),
properties: body.properties || {},
event_name: body.event_name,
customer_id: body.customer_id,
};
} catch (error: any) {
throw new RecaseError({
message: "Invalid request body -> " + formatZodError(error),
code: ErrCode.InvalidEvent,
statusCode: StatusCodes.BAD_REQUEST,
});
}
// 2. Check if customer ID is valid
customer = await CusService.getCustomer({
@@ -64,6 +39,23 @@ const getEventAndCustomer = async (req: any) => {
env: env,
});
const parsedEvent = CreateEventSchema.parse(req.body);
const newEvent: Event = {
...parsedEvent,
properties: parsedEvent.properties || {},
timestamp: Date.now(),
id: generateId("evt"),
org_id: orgId,
env: env,
internal_customer_id: customer.internal_id,
};
// console.log("Customer:", customer);
// console.log("Org ID:", req.orgId);
if (!customer) {
customer = await createNewCustomer({
sb: req.sb,
@@ -137,26 +129,6 @@ eventsRouter.post("", async (req: any, res: any) => {
features: affectedFeatures,
event,
});
// await inngest.send({
// name: "autumn/update-balance",
// data: {
// customer,
// features: affectedFeatures,
// },
// });
// await updateBalanceTask.trigger(
// {
// customer,
// features: affectedFeatures,
// },
// {
// queue: {
// name: "customer",
// concurrencyLimit: 1,
// },
// concurrencyKey: customer.internal_id,
// }
// );
} else {
console.log("No affected features found");
}

View File

@@ -4,6 +4,8 @@ import Stripe from "stripe";
import { generateId } from "@/utils/genUtils.js";
import RecaseError from "@/utils/errorUtils.js";
import { ErrCode } from "@/errors/errCodes.js";
import { Autumn } from "@/external/autumn/autumnCli.js";
import { CusService } from "../CusService.js";
export class InvoiceService {
static async createInvoice({
@@ -83,28 +85,44 @@ export class InvoiceService {
status: status || (stripeInvoice.status as InvoiceStatus | null),
};
// Check if invoice already exists
// TODO: Fix This
const existingInvoice = await this.getInvoiceByStripeId({
sb,
stripeInvoiceId: stripeInvoice.id,
});
// // Check if invoice already exists
// // TODO: Fix This
// const existingInvoice = await this.getInvoiceByStripeId({
// sb,
// stripeInvoiceId: stripeInvoice.id,
// });
if (existingInvoice) {
console.log("Invoice already exists");
return;
}
// if (existingInvoice) {
// console.log("Invoice already exists");
// return;
// }
const { error } = await sb.from("invoices").upsert(invoice, {
onConflict: "stripe_id",
});
// // const { error } = await sb
// // .from("invoices")
// // .upsert(invoice, {
// // onConflict: "stripe_id",
// // })
// // .select();
const { error } = await sb.from("invoices").insert(invoice);
// const customer = await CusService.getByInternalId({
// sb,
// internalId: invoice.internal_customer_id,
// });
// const autumn = new Autumn();
// await autumn.sendEvent({
// customerId: invoice.internal_customer_id,
// eventName: "monthly_revenue",
// properties: {
// value: stripeInvoice.total / 100,
// },
// });
if (error) {
console.log("Failed to create invoice from stripe", error);
throw new RecaseError({
code: ErrCode.CreateInvoiceFailed,
message: error.message,
});
return;
}
}
}

View File

@@ -1,5 +1,5 @@
import { ErrCode } from "@/errors/errCodes.js";
import { createClerkCli, createClerkOrg } from "@/external/clerkUtils.js";
import { createClerkCli } from "@/external/clerkUtils.js";
import {
checkKeyValid,
createWebhookEndpoint,
@@ -8,12 +8,8 @@ import { encryptData } from "@/utils/encryptUtils.js";
import RecaseError, { handleRequestError } from "@/utils/errorUtils.js";
import express from "express";
import Stripe from "stripe";
import { CusService } from "../customers/CusService.js";
import { OrgService } from "./OrgService.js";
import { Customer, Organization, Product } from "@autumn/shared";
import { createStripeCli } from "@/external/stripe/utils.js";
import { Client } from "pg";
import { ProductService } from "../products/ProductService.js";
import { AppEnv } from "@autumn/shared";
export const orgRouter = express.Router();

View File

@@ -60,7 +60,6 @@ export const handleRequestError = ({
res.status(400).json({
message: formatZodError(error),
code: ErrCode.InvalidInputs,
data: formatZodError(error),
});
} else {
console.log(`Unknown error | ${action}`, error);

View File

@@ -1,25 +1,27 @@
import { z } from "zod";
export const EventSchema = z.object({
// Submitted by the client
customer_id: z.string().nonempty(),
event_name: z.string().nonempty(),
properties: z.record(z.string(), z.any()),
idempotency_key: z.string().nullish(),
// Internal usage
id: z.string(),
env: z.string(),
org_id: z.string(),
// Submitted by the client
customer_id: z.string().nonempty(),
event_name: z.string().nonempty(),
// Optional
properties: z.record(z.string(), z.any()),
idempotency_key: z.string().optional(),
timestamp: z.number().optional(),
timestamp: z.number(),
internal_customer_id: z.string(),
});
export const CreateEventSchema = EventSchema.omit({
id: true,
env: true,
org_id: true,
export const CreateEventSchema = z.object({
customer_id: z.string().nonempty(),
event_name: z.string().nonempty(),
properties: z.record(z.string(), z.any()).nullish(),
idempotency_key: z.string().nullish(),
});
export type Event = z.infer<typeof EventSchema>;
export type CreateEvent = z.infer<typeof CreateEventSchema>;