From 677025416b90a62acc1e1cb987c0f37ae7c04ad6 Mon Sep 17 00:00:00 2001 From: Jayadeep Bejoy Date: Sat, 20 Dec 2025 04:33:58 +0400 Subject: [PATCH 1/4] refactor(serialize): Moved serialization out of the db adapters --- AGENTS.md | 2 +- src/interface/event/Event.ts | 2 +- src/interface/storage/SQLStorageAdapter.ts | 13 ------------- src/interface/storage/Storage.ts | 7 +++---- src/routes/gRPC/auth/createAPIKey.ts | 2 +- src/routes/gRPC/payment/createCheckoutLink.ts | 5 +++-- src/routes/http/createdCheckout.ts | 3 +-- .../postgres/handlers/priceRequestPayment.ts | 5 +++-- src/storage/adapter/postgres/postgres.ts | 13 +++++++------ src/utils/eventHelpers.ts | 2 +- 10 files changed, 21 insertions(+), 33 deletions(-) delete mode 100644 src/interface/storage/SQLStorageAdapter.ts diff --git a/AGENTS.md b/AGENTS.md index ba8e902..010b1b2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Commands -- **Test all**: `bun test` or `vitest` +- **Test all**: `bun test` - **Test single file**: `vitest src/__tests__/unit/path/to/test.test.ts` - **Test with UI**: `bun run test:ui` - **Dev server**: `bun run dev:backend` (auto-reload on port 8069) diff --git a/src/interface/event/Event.ts b/src/interface/event/Event.ts index 603e582..eea077d 100644 --- a/src/interface/event/Event.ts +++ b/src/interface/event/Event.ts @@ -59,7 +59,7 @@ type EventMetadataMap = { REQUEST_SDK_CALL: BaseEventMetadata<"REQUEST_SDK_CALL"> & { userId: UserId }; }; -type EventStorageAdapterMap = { +export type EventStorageAdapterMap = { SQL: { [K in keyof EventDataMap]: EventMetadataMap[K]; }[Type]; diff --git a/src/interface/storage/SQLStorageAdapter.ts b/src/interface/storage/SQLStorageAdapter.ts deleted file mode 100644 index bd948d2..0000000 --- a/src/interface/storage/SQLStorageAdapter.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { EventType } from "../event/Event"; - -/** - * SQLStorageAdapter - Base interface for SQL-based storage implementations - * This is database-agnostic and can be implemented by PostgreSQL, SQLite, MySQL, etc. - */ -export interface SQLStorageAdapter { - readonly name: "POSTGRES" | "SQLITE" | "MYSQL"; - readonly connectionObject: unknown; - readonly event: EventType; - - add(): Promise; -} diff --git a/src/interface/storage/Storage.ts b/src/interface/storage/Storage.ts index 2f37e17..f2e3efb 100644 --- a/src/interface/storage/Storage.ts +++ b/src/interface/storage/Storage.ts @@ -1,4 +1,4 @@ -import type { EventType } from "../event/Event"; +import type { EventStorageAdapterMap, EventType } from "../event/Event"; /** * Storage - Consumes events @@ -6,8 +6,7 @@ import type { EventType } from "../event/Event"; export interface StorageAdapterType { name: string; connectionObject: unknown; - event: EventType; - add(): Promise<{ id: string } | void>; - price(): Promise; + add(serialized: EventStorageAdapterMap): Promise<{ id: string } | void>; + price(serialized: EventStorageAdapterMap): Promise; } diff --git a/src/routes/gRPC/auth/createAPIKey.ts b/src/routes/gRPC/auth/createAPIKey.ts index 34ccd2b..da592ae 100644 --- a/src/routes/gRPC/auth/createAPIKey.ts +++ b/src/routes/gRPC/auth/createAPIKey.ts @@ -81,7 +81,7 @@ export async function createAPIKey( try { const adapter = await StorageAdapterFactory.getStorageAdapter(addKeyEvent); - keyEventData = await adapter.add(); + keyEventData = await adapter.add(addKeyEvent.serialize()); if (!keyEventData) { throw APIKeyError.creationFailed("No ID returned"); } diff --git a/src/routes/gRPC/payment/createCheckoutLink.ts b/src/routes/gRPC/payment/createCheckoutLink.ts index 528ab36..bb7f516 100644 --- a/src/routes/gRPC/payment/createCheckoutLink.ts +++ b/src/routes/gRPC/payment/createCheckoutLink.ts @@ -100,8 +100,9 @@ export async function createCheckoutLink( // Get custom price from storage let custom_price: number; try { + const event = new RequestPayment(validatedData.userId, null); const storageAdapter = await StorageAdapterFactory.getStorageAdapter( - new RequestPayment(validatedData.userId, null), + event, ); if (!storageAdapter) { @@ -110,7 +111,7 @@ export async function createCheckoutLink( ); } - custom_price = await storageAdapter.price(); + custom_price = await storageAdapter.price(event.serialize()); if ( typeof custom_price !== "number" || diff --git a/src/routes/http/createdCheckout.ts b/src/routes/http/createdCheckout.ts index 8f40b5e..388c244 100644 --- a/src/routes/http/createdCheckout.ts +++ b/src/routes/http/createdCheckout.ts @@ -3,7 +3,6 @@ import type { Http2ServerRequest, Http2ServerResponse } from "node:http2"; import crypto from "node:crypto"; import { lemonSqueezySetup } from "@lemonsqueezy/lemonsqueezy.js"; import { Payment } from "../../events/RawEvents/Payment.ts"; -import { PostgresAdapter } from "../../storage/adapter/postgres/postgres.ts"; import { StorageAdapterFactory } from "../../factory/StorageAdapterFactory.ts"; import { logger } from "../../errors/logger.ts"; @@ -256,7 +255,7 @@ export async function handleLemonSqueezyWebhook( apiKeyId, ); - await adapter.add(); + await adapter.add(paymentEvent.serialize()); logger.logOperationInfo( OPERATION, diff --git a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts index a01ba93..d834ba1 100644 --- a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts +++ b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts @@ -24,8 +24,9 @@ export async function handlePriceRequestPayment( { userId: event_data.userId }, ); + const event = new RequestSDKCall(event_data.userId, null); const storageAdapter = await StorageAdapterFactory.getStorageAdapter( - new RequestSDKCall(event_data.userId, null), + event ); if (!storageAdapter) { @@ -34,7 +35,7 @@ export async function handlePriceRequestPayment( ); } - const price = await storageAdapter.price(); + const price = await storageAdapter.price(event.serialize()); if (typeof price !== "number" || isNaN(price)) { throw StorageError.priceCalculationFailed( diff --git a/src/storage/adapter/postgres/postgres.ts b/src/storage/adapter/postgres/postgres.ts index d6e03be..8b7a416 100644 --- a/src/storage/adapter/postgres/postgres.ts +++ b/src/storage/adapter/postgres/postgres.ts @@ -11,25 +11,24 @@ import { handleAddAiTokenUsage, } from "./handlers"; import { logger } from "../../../errors/logger"; +import type { EventStorageAdapterMap } from "../../../interface/event/Event"; export class PostgresAdapter implements StorageAdapterType { name: string; connectionObject; - event: EventType; apiKeyId?: string; constructor(event: EventType, apiKeyId?: string) { this.name = event.type; this.connectionObject = getPostgresDB(); - this.event = event; this.apiKeyId = apiKeyId; } - async add(): Promise<{ id: string } | void> { + async add(serialized: EventStorageAdapterMap) { let event_data; try { - const { SQL } = this.event.serialize(); + const { SQL } = serialized; event_data = SQL; if (!event_data) { @@ -82,11 +81,13 @@ export class PostgresAdapter implements StorageAdapterType { } } - async price(): Promise { + async price( + serialized: EventStorageAdapterMap, + ): Promise { let event_data; try { - const { SQL } = this.event.serialize(); + const { SQL } = serialized; event_data = SQL; if (!event_data) { diff --git a/src/utils/eventHelpers.ts b/src/utils/eventHelpers.ts index 887da9b..8fbbdc9 100644 --- a/src/utils/eventHelpers.ts +++ b/src/utils/eventHelpers.ts @@ -88,7 +88,7 @@ export async function storeEvent( event, apiKeyId, ); - await adapter.add(); + await adapter.add(event.serialize()); } catch (error) { throw EventError.serializationError( "Failed to store event", From 375a678819e94b5b0aee5da8cf0295195eb78145 Mon Sep 17 00:00:00 2001 From: Jayadeep Bejoy Date: Sat, 20 Dec 2025 04:39:42 +0400 Subject: [PATCH 2/4] test(serialization) --- .../unit/http/createdCheckout.test.ts | 24 ++++++++++++ .../unit/storage/postgres/addKey.test.ts | 38 ++++++++++++++----- .../unit/storage/postgres/addPayment.test.ts | 27 ++++++++----- .../unit/storage/postgres/addSdkCall.test.ts | 21 ++++++---- .../postgres/priceRequestSdkCall.test.ts | 29 +++++++++----- 5 files changed, 104 insertions(+), 35 deletions(-) diff --git a/src/__tests__/unit/http/createdCheckout.test.ts b/src/__tests__/unit/http/createdCheckout.test.ts index 372881f..c3d00a9 100644 --- a/src/__tests__/unit/http/createdCheckout.test.ts +++ b/src/__tests__/unit/http/createdCheckout.test.ts @@ -21,12 +21,24 @@ class PaymentMock { public userId: string; public data: unknown; public readonly type = "PAYMENT" as const; + public reported_timestamp = { toISO: () => "2024-01-01T00:00:00.000Z" }; constructor(userId: string, data: unknown) { this.userId = userId; this.data = data; paymentConstructorCalls.push({ userId, data }); } + + serialize() { + return { + SQL: { + type: this.type, + userId: this.userId, + reported_timestamp: this.reported_timestamp, + data: this.data, + }, + }; + } } // Mock modules @@ -50,12 +62,24 @@ vi.mock("../../../events/RawEvents/Payment.ts", () => ({ public userId: string; public data: unknown; public readonly type = "PAYMENT" as const; + public reported_timestamp = { toISO: () => "2024-01-01T00:00:00.000Z" }; constructor(userId: string, data: unknown) { this.userId = userId; this.data = data; paymentConstructorCalls.push({ userId, data }); } + + serialize() { + return { + SQL: { + type: this.type, + userId: this.userId, + reported_timestamp: this.reported_timestamp, + data: this.data, + }, + }; + } }, })); diff --git a/src/__tests__/unit/storage/postgres/addKey.test.ts b/src/__tests__/unit/storage/postgres/addKey.test.ts index 65b14dc..36eb400 100644 --- a/src/__tests__/unit/storage/postgres/addKey.test.ts +++ b/src/__tests__/unit/storage/postgres/addKey.test.ts @@ -44,7 +44,8 @@ describe("PostgresAdapter - addKey handler", () => { ]); const adapter = new PostgresAdapter(addKeyEvent); - const result = await adapter.add(); + const serialized = addKeyEvent.serialize(); + const result = await adapter.add(serialized); expect(result).toEqual({ id: "api-key-id-123" }); }); @@ -63,7 +64,8 @@ describe("PostgresAdapter - addKey handler", () => { ]); const adapter = new PostgresAdapter(addKeyEvent); - await adapter.add(); + const serialized = addKeyEvent.serialize(); + await adapter.add(serialized); const insertCall = mockTransaction.values.mock.calls[0][0]; expect(insertCall.name).toBe(keyData.name); @@ -88,7 +90,10 @@ describe("PostgresAdapter - addKey handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow("Missing data field"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( + "Missing data field", + ); }); it("throws error when name is missing", async () => { @@ -112,7 +117,10 @@ describe("PostgresAdapter - addKey handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow("Invalid or missing 'name'"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( + "Invalid or missing 'name'", + ); }); it("throws error when key is missing", async () => { @@ -136,7 +144,10 @@ describe("PostgresAdapter - addKey handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow("Invalid or missing 'key'"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( + "Invalid or missing 'key'", + ); }); it("throws error when key is empty string", async () => { @@ -162,7 +173,10 @@ describe("PostgresAdapter - addKey handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow("API key cannot be empty"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( + "API key cannot be empty", + ); }); it("throws error when timestamp is empty", async () => { @@ -186,7 +200,8 @@ describe("PostgresAdapter - addKey handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow( + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( "Timestamp is undefined or empty", ); }); @@ -205,7 +220,8 @@ describe("PostgresAdapter - addKey handler", () => { ); const adapter = new PostgresAdapter(addKeyEvent); - await expect(adapter.add()).rejects.toThrow(); + const serialized = addKeyEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow(); }); it("handles empty API key ID response", async () => { @@ -218,7 +234,8 @@ describe("PostgresAdapter - addKey handler", () => { mockTransaction.returning.mockResolvedValueOnce([]); const adapter = new PostgresAdapter(addKeyEvent); - await expect(adapter.add()).rejects.toThrow( + const serialized = addKeyEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow( "API key insert returned no record", ); }); @@ -233,7 +250,8 @@ describe("PostgresAdapter - addKey handler", () => { mockTransaction.returning.mockResolvedValueOnce([{}]); const adapter = new PostgresAdapter(addKeyEvent); - await expect(adapter.add()).rejects.toThrow( + const serialized = addKeyEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow( "API key insert returned object without id field", ); }); diff --git a/src/__tests__/unit/storage/postgres/addPayment.test.ts b/src/__tests__/unit/storage/postgres/addPayment.test.ts index 57d3487..7ab9511 100644 --- a/src/__tests__/unit/storage/postgres/addPayment.test.ts +++ b/src/__tests__/unit/storage/postgres/addPayment.test.ts @@ -42,7 +42,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-123" }]); const adapter = new PostgresAdapter(paymentEvent, "api-key-123"); - await adapter.add(); + const serialized = paymentEvent.serialize(); + await adapter.add(serialized); const eventInsertCall = mockTransaction.values.mock.calls[1][0]; expect(eventInsertCall.api_keyId).toBe("api-key-123"); @@ -56,7 +57,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-456" }]); const adapter = new PostgresAdapter(paymentEvent); - await adapter.add(); + const serialized = paymentEvent.serialize(); + await adapter.add(serialized); const eventInsertCall = mockTransaction.values.mock.calls[1][0]; expect(eventInsertCall.api_keyId).toBeUndefined(); @@ -70,7 +72,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-3" }]); const adapter = new PostgresAdapter(paymentEvent); - await adapter.add(); + const serialized = paymentEvent.serialize(); + await adapter.add(serialized); const paymentInsertCall = mockTransaction.values.mock.calls[2][0]; expect(paymentInsertCall.creditAmount).toBe(15000); @@ -85,7 +88,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-pos" }]); const adapter = new PostgresAdapter(paymentEvent); - await adapter.add(); + const serialized = paymentEvent.serialize(); + await adapter.add(serialized); const paymentInsertCall = mockTransaction.values.mock.calls[2][0]; expect(paymentInsertCall.creditAmount).toBe(1); @@ -111,7 +115,8 @@ describe("PostgresAdapter - addPayment handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow(/positive/); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow(/positive/); }); it("throws error when creditAmount is negative", async () => { @@ -131,7 +136,8 @@ describe("PostgresAdapter - addPayment handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow(/positive/); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow(/positive/); }); it("throws error when timestamp is empty", async () => { @@ -155,7 +161,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([]); const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.add()).rejects.toThrow( + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( "Timestamp is undefined or empty", ); }); @@ -173,7 +180,8 @@ describe("PostgresAdapter - addPayment handler", () => { ); const adapter = new PostgresAdapter(paymentEvent); - await expect(adapter.add()).rejects.toThrow(); + const serialized = paymentEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow(); }); it("handles empty event ID response", async () => { @@ -185,7 +193,8 @@ describe("PostgresAdapter - addPayment handler", () => { mockTransaction.returning.mockResolvedValueOnce([]); const adapter = new PostgresAdapter(paymentEvent); - await expect(adapter.add()).rejects.toThrow( + const serialized = paymentEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow( "Event insert returned no ID", ); }); diff --git a/src/__tests__/unit/storage/postgres/addSdkCall.test.ts b/src/__tests__/unit/storage/postgres/addSdkCall.test.ts index a331d09..387b634 100644 --- a/src/__tests__/unit/storage/postgres/addSdkCall.test.ts +++ b/src/__tests__/unit/storage/postgres/addSdkCall.test.ts @@ -45,7 +45,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { ]); const adapter = new PostgresAdapter(sdkCallEvent, "api-key-123"); - await adapter.add(); + const serialized = sdkCallEvent.serialize(); + await adapter.add(serialized); const eventInsertCall = mockTransaction.values.mock.calls[1][0]; expect(eventInsertCall.api_keyId).toBe("api-key-123"); @@ -60,7 +61,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-456" }]); const adapter = new PostgresAdapter(sdkCallEvent, "api-key-456"); - await adapter.add(); + const serialized = sdkCallEvent.serialize(); + await adapter.add(serialized); const sdkCallInsertCall = mockTransaction.values.mock.calls[2][0]; expect(sdkCallInsertCall.debitAmount).toBe(2500); @@ -75,7 +77,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-1" }]); const adapter = new PostgresAdapter(sdkCallEvent, "api-key-1"); - await adapter.add(); + const serialized = sdkCallEvent.serialize(); + await adapter.add(serialized); const eventInsertCall = mockTransaction.values.mock.calls[1][0]; expect(eventInsertCall).toHaveProperty("reported_timestamp"); @@ -91,7 +94,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { mockTransaction.returning.mockResolvedValueOnce([{ id: "event-id-pos" }]); const adapter = new PostgresAdapter(sdkCallEvent, "api-key-pos"); - await adapter.add(); + const serialized = sdkCallEvent.serialize(); + await adapter.add(serialized); const insertedValues = mockTransaction.values.mock.calls.map( (c: any) => c[0], @@ -117,7 +121,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { ); const adapter = new PostgresAdapter(sdkCallEvent, "api-key"); - await expect(adapter.add()).rejects.toThrow(); + const serialized = sdkCallEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow(); }); it("handles empty event ID response", async () => { @@ -129,7 +134,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { mockTransaction.returning.mockResolvedValueOnce([]); const adapter = new PostgresAdapter(sdkCallEvent, "api-key"); - await expect(adapter.add()).rejects.toThrow( + const serialized = sdkCallEvent.serialize(); + await expect(adapter.add(serialized)).rejects.toThrow( "Event insert returned no ID", ); }); @@ -155,7 +161,8 @@ describe("PostgresAdapter - addSdkCall handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any, "api-key"); - await expect(adapter.add()).rejects.toThrow( + const serialized = invalidEvent.serialize() as any; + await expect(adapter.add(serialized)).rejects.toThrow( "Timestamp is undefined or empty", ); }); diff --git a/src/__tests__/unit/storage/postgres/priceRequestSdkCall.test.ts b/src/__tests__/unit/storage/postgres/priceRequestSdkCall.test.ts index 47facb8..38bfcef 100644 --- a/src/__tests__/unit/storage/postgres/priceRequestSdkCall.test.ts +++ b/src/__tests__/unit/storage/postgres/priceRequestSdkCall.test.ts @@ -33,7 +33,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce([{ price: "1500" }]); const adapter = new PostgresAdapter(requestEvent); - const price = await adapter.price(); + const serialized = requestEvent.serialize(); + const price = await adapter.price(serialized); expect(price).toBe(1500); }); @@ -47,7 +48,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce([]); const adapter = new PostgresAdapter(requestEvent); - const price = await adapter.price(); + const serialized = requestEvent.serialize(); + const price = await adapter.price(serialized); expect(price).toBe(0); }); @@ -61,7 +63,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce([{ price: null }]); const adapter = new PostgresAdapter(requestEvent); - const price = await adapter.price(); + const serialized = requestEvent.serialize(); + const price = await adapter.price(serialized); expect(price).toBe(0); }); @@ -75,7 +78,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce([{ price: "12345" }]); const adapter = new PostgresAdapter(requestEvent); - const price = await adapter.price(); + const serialized = requestEvent.serialize(); + const price = await adapter.price(serialized); expect(typeof price).toBe("number"); expect(price).toBe(12345); @@ -99,7 +103,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.price()).rejects.toThrow("Missing userId"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.price(serialized)).rejects.toThrow("Missing userId"); }); it("throws error when userId is empty string", async () => { @@ -119,7 +124,10 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { }; const adapter = new PostgresAdapter(invalidEvent as any); - await expect(adapter.price()).rejects.toThrow("Invalid userId format"); + const serialized = invalidEvent.serialize() as any; + await expect(adapter.price(serialized)).rejects.toThrow( + "Invalid userId format", + ); }); }); @@ -135,7 +143,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { ); const adapter = new PostgresAdapter(requestEvent); - await expect(adapter.price()).rejects.toThrow(); + const serialized = requestEvent.serialize(); + await expect(adapter.price(serialized)).rejects.toThrow(); }); it("handles null query result", async () => { @@ -147,7 +156,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce(null); const adapter = new PostgresAdapter(requestEvent); - await expect(adapter.price()).rejects.toThrow( + const serialized = requestEvent.serialize(); + await expect(adapter.price(serialized)).rejects.toThrow( "Price query returned null", ); }); @@ -161,7 +171,8 @@ describe("PostgresAdapter - priceRequestSdkCall handler", () => { mockDb.groupBy.mockResolvedValueOnce({ price: "1500" }); const adapter = new PostgresAdapter(requestEvent); - await expect(adapter.price()).rejects.toThrow( + const serialized = requestEvent.serialize(); + await expect(adapter.price(serialized)).rejects.toThrow( "Query result is not an array", ); }); From e27e0103c31c53abf5720b4ec81859e20aa36578 Mon Sep 17 00:00:00 2001 From: Jayadeep Bejoy Date: Sat, 20 Dec 2025 05:04:33 +0400 Subject: [PATCH 3/4] refactor(types) --- src/events/AIEvents/AITokenUsage.ts | 9 +- src/events/RawEvents/AddKey.ts | 5 +- src/events/RawEvents/Payment.ts | 7 +- src/events/RawEvents/SDKCall.ts | 9 +- src/events/RequestEvents/RequestPayment.ts | 7 +- src/events/RequestEvents/RequestSDKCall.ts | 7 +- src/factory/StorageAdapterFactory.ts | 4 +- src/interface/event/Event.ts | 104 +++++++++++------- src/interface/storage/Storage.ts | 10 +- src/routes/gRPC/events/streamEvents.ts | 4 +- .../postgres/handlers/addAiTokenUsage.ts | 10 +- .../adapter/postgres/handlers/addKey.ts | 4 +- .../adapter/postgres/handlers/addPayment.ts | 7 +- .../adapter/postgres/handlers/addSdkCall.ts | 7 +- .../postgres/handlers/priceRequestPayment.ts | 7 +- .../postgres/handlers/priceRequestSdkCall.ts | 7 +- src/storage/adapter/postgres/postgres.ts | 15 ++- src/utils/eventHelpers.ts | 19 ++-- 18 files changed, 124 insertions(+), 118 deletions(-) diff --git a/src/events/AIEvents/AITokenUsage.ts b/src/events/AIEvents/AITokenUsage.ts index 939110b..86d8966 100644 --- a/src/events/AIEvents/AITokenUsage.ts +++ b/src/events/AIEvents/AITokenUsage.ts @@ -1,15 +1,14 @@ -import type { AITokenUsageEventType } from "../../interface/event/Event"; +import type { AITokenUsageEvent, AITokenUsageEventData } from "../../interface/event/Event"; import { DateTime } from "luxon"; -import type { EventUnion } from "../../interface/event/Event"; -import { type UserId } from "../../config/identifiers"; +import type { UserId } from "../../config/identifiers"; -export class AITokenUsage implements AITokenUsageEventType { +export class AITokenUsage implements AITokenUsageEvent { public reported_timestamp: DateTime; public readonly type = "AI_TOKEN_USAGE" as const; constructor( public userId: UserId, - public data: EventUnion<"AI_TOKEN_USAGE">, + public data: AITokenUsageEventData, ) { this.reported_timestamp = DateTime.utc(); } diff --git a/src/events/RawEvents/AddKey.ts b/src/events/RawEvents/AddKey.ts index e57f2e8..d6a01c3 100644 --- a/src/events/RawEvents/AddKey.ts +++ b/src/events/RawEvents/AddKey.ts @@ -1,8 +1,7 @@ -import type { AddKeyEventType } from "../../interface/event/Event"; +import type { AddKeyEvent, AddKeyEventData } from "../../interface/event/Event"; import { DateTime } from "luxon"; -import type { AddKeyEventData } from "../../interface/event/Event"; -export class AddKey implements AddKeyEventType { +export class AddKey implements AddKeyEvent { public reported_timestamp: DateTime; public readonly type = "ADD_KEY" as const; diff --git a/src/events/RawEvents/Payment.ts b/src/events/RawEvents/Payment.ts index 5101a5f..edd7314 100644 --- a/src/events/RawEvents/Payment.ts +++ b/src/events/RawEvents/Payment.ts @@ -1,9 +1,8 @@ -import type { PaymentEventType } from "../../interface/event/Event"; +import type { PaymentEvent, PaymentEventData } from "../../interface/event/Event"; import { DateTime } from "luxon"; -import type { PaymentEventData } from "../../interface/event/Event"; -import { type UserId } from "../../config/identifiers"; +import type { UserId } from "../../config/identifiers"; -export class Payment implements PaymentEventType { +export class Payment implements PaymentEvent { public reported_timestamp: DateTime; public readonly type = "PAYMENT" as const; diff --git a/src/events/RawEvents/SDKCall.ts b/src/events/RawEvents/SDKCall.ts index 9a085be..fd55b26 100644 --- a/src/events/RawEvents/SDKCall.ts +++ b/src/events/RawEvents/SDKCall.ts @@ -1,15 +1,14 @@ -import type { SDKCallEventType } from "../../interface/event/Event"; +import type { SDKCallEvent, SDKCallEventData } from "../../interface/event/Event"; import { DateTime } from "luxon"; -import type { EventUnion } from "../../interface/event/Event"; -import { type UserId } from "../../config/identifiers"; +import type { UserId } from "../../config/identifiers"; -export class SDKCall implements SDKCallEventType { +export class SDKCall implements SDKCallEvent { public reported_timestamp: DateTime; public readonly type = "SDK_CALL" as const; constructor( public userId: UserId, - public data: EventUnion<"SDK_CALL">, + public data: SDKCallEventData, ) { this.reported_timestamp = DateTime.utc(); } diff --git a/src/events/RequestEvents/RequestPayment.ts b/src/events/RequestEvents/RequestPayment.ts index 742d351..af034e7 100644 --- a/src/events/RequestEvents/RequestPayment.ts +++ b/src/events/RequestEvents/RequestPayment.ts @@ -1,15 +1,16 @@ import type { - RequestPaymentEventType, + RequestPaymentEvent, RequestPaymentEventData, } from "../../interface/event/Event"; import { DateTime } from "luxon"; +import type { UserId } from "../../config/identifiers"; -export class RequestPayment implements RequestPaymentEventType { +export class RequestPayment implements RequestPaymentEvent { public reported_timestamp: DateTime; public readonly type = "REQUEST_PAYMENT" as const; constructor( - public userId: string, + public userId: UserId, public data: RequestPaymentEventData, ) { this.reported_timestamp = DateTime.utc(); diff --git a/src/events/RequestEvents/RequestSDKCall.ts b/src/events/RequestEvents/RequestSDKCall.ts index 9a03dad..b22e7d1 100644 --- a/src/events/RequestEvents/RequestSDKCall.ts +++ b/src/events/RequestEvents/RequestSDKCall.ts @@ -1,15 +1,16 @@ import type { RequestSDKCallEventData, - RequestSDKCallEventType, + RequestSDKCallEvent, } from "../../interface/event/Event"; import { DateTime } from "luxon"; +import type { UserId } from "../../config/identifiers"; -export class RequestSDKCall implements RequestSDKCallEventType { +export class RequestSDKCall implements RequestSDKCallEvent { public reported_timestamp: DateTime; public readonly type = "REQUEST_SDK_CALL" as const; constructor( - public userId: string, + public userId: UserId, public data: RequestSDKCallEventData, ) { this.reported_timestamp = DateTime.utc(); diff --git a/src/factory/StorageAdapterFactory.ts b/src/factory/StorageAdapterFactory.ts index 9e9874a..3b4062b 100644 --- a/src/factory/StorageAdapterFactory.ts +++ b/src/factory/StorageAdapterFactory.ts @@ -1,4 +1,4 @@ -import type { EventType } from "../interface/event/Event.ts"; +import type { Event } from "../interface/event/Event.ts"; import { PostgresAdapter } from "../storage/adapter/postgres/postgres.ts"; /** @@ -15,7 +15,7 @@ export class StorageAdapterFactory { * @param apiKeyId - Optional API key ID to associate with the event * @returns The storage adapter instance for the event type */ - public static async getStorageAdapter(event: EventType, apiKeyId?: string) { + public static async getStorageAdapter(event: Event, apiKeyId?: string) { switch (event.type) { case "SDK_CALL": { return new PostgresAdapter(event, apiKeyId); diff --git a/src/interface/event/Event.ts b/src/interface/event/Event.ts index eea077d..8fc7327 100644 --- a/src/interface/event/Event.ts +++ b/src/interface/event/Event.ts @@ -1,6 +1,9 @@ -import { DateTime } from "luxon"; -import { type UserId } from "../../config/identifiers"; +import type { DateTime } from "luxon"; +import type { UserId } from "../../config/identifiers"; +/** + * Event payload data structures + */ export type SDKCallEventData = { sdkCallType: "RAW" | "MIDDLEWARE_CALL"; debitAmount: number; @@ -29,7 +32,18 @@ export type RequestPaymentEventData = null; export type RequestSDKCallEventData = null; /** - * Mapping of event types to their data structures + * Event kind discriminator + */ +export type EventKind = + | "SDK_CALL" + | "AI_TOKEN_USAGE" + | "ADD_KEY" + | "PAYMENT" + | "REQUEST_PAYMENT" + | "REQUEST_SDK_CALL"; + +/** + * Mapping of event kinds to their data structures */ export type EventDataMap = { SDK_CALL: SDKCallEventData; @@ -40,84 +54,98 @@ export type EventDataMap = { REQUEST_SDK_CALL: RequestSDKCallEventData; }; -export type EventUnion = { - [K in keyof EventDataMap]: EventDataMap[K]; -}[T]; +/** + * Get event data type for a specific event kind + */ +export type EventData = EventDataMap[K]; -export type BaseEventMetadata = { - type: T; +/** + * Base SQL record structure for all events + */ +type BaseSqlRecord = { + type: K; reported_timestamp: DateTime; - data: EventDataMap[T]; + data: EventData; }; -type EventMetadataMap = { - ADD_KEY: BaseEventMetadata<"ADD_KEY">; - SDK_CALL: BaseEventMetadata<"SDK_CALL"> & { userId: UserId }; - AI_TOKEN_USAGE: BaseEventMetadata<"AI_TOKEN_USAGE"> & { userId: UserId }; - PAYMENT: BaseEventMetadata<"PAYMENT"> & { userId: UserId }; - REQUEST_PAYMENT: BaseEventMetadata<"REQUEST_PAYMENT"> & { userId: UserId }; - REQUEST_SDK_CALL: BaseEventMetadata<"REQUEST_SDK_CALL"> & { userId: UserId }; +/** + * SQL record structure for events that require userId + */ +type SqlRecordWithUserId = BaseSqlRecord & { + userId: UserId; }; -export type EventStorageAdapterMap = { - SQL: { - [K in keyof EventDataMap]: EventMetadataMap[K]; - }[Type]; +/** + * Mapping of event kinds to their SQL record structures + */ +type SqlRecordMap = { + ADD_KEY: BaseSqlRecord<"ADD_KEY">; + SDK_CALL: SqlRecordWithUserId<"SDK_CALL">; + AI_TOKEN_USAGE: SqlRecordWithUserId<"AI_TOKEN_USAGE">; + PAYMENT: SqlRecordWithUserId<"PAYMENT">; + REQUEST_PAYMENT: SqlRecordWithUserId<"REQUEST_PAYMENT">; + REQUEST_SDK_CALL: SqlRecordWithUserId<"REQUEST_SDK_CALL">; }; -type EventStorageAdapterUnion = { - [K in keyof EventDataMap]: EventStorageAdapterMap; -}[T]; +/** + * Get SQL record type for a specific event kind + */ +export type SqlRecord = SqlRecordMap[K]; + +/** + * Serialized event format (wrapped in SQL adapter envelope) + */ +export type SerializedEvent = { + SQL: SqlRecord; +}; /** - * Base Event interface - all events in the system extend this + * Base Event interface - all events in the system implement this */ -export interface EventType< - Type extends keyof EventDataMap = keyof EventDataMap, -> { - type: Type; +export interface Event { + readonly type: K; readonly reported_timestamp: DateTime; - readonly data: EventDataMap[Type]; + readonly data: EventData; - serialize(): EventStorageAdapterUnion; + serialize(): SerializedEvent; } /** * SDK Call Event */ -export interface SDKCallEventType extends EventType<"SDK_CALL"> { +export interface SDKCallEvent extends Event<"SDK_CALL"> { readonly userId: UserId; } /** * AI Token Usage Event */ -export interface AITokenUsageEventType extends EventType<"AI_TOKEN_USAGE"> { +export interface AITokenUsageEvent extends Event<"AI_TOKEN_USAGE"> { readonly userId: UserId; } /** * Add Key Event */ -export interface AddKeyEventType extends EventType<"ADD_KEY"> {} +export interface AddKeyEvent extends Event<"ADD_KEY"> {} /** * Payment Event */ -export interface PaymentEventType extends EventType<"PAYMENT"> { +export interface PaymentEvent extends Event<"PAYMENT"> { readonly userId: UserId; } /** * Payment Request Event */ -export interface RequestPaymentEventType extends EventType<"REQUEST_PAYMENT"> { - readonly userId: string; +export interface RequestPaymentEvent extends Event<"REQUEST_PAYMENT"> { + readonly userId: UserId; } /** * SDK Call Request Event */ -export interface RequestSDKCallEventType extends EventType<"REQUEST_SDK_CALL"> { - readonly userId: string; +export interface RequestSDKCallEvent extends Event<"REQUEST_SDK_CALL"> { + readonly userId: UserId; } diff --git a/src/interface/storage/Storage.ts b/src/interface/storage/Storage.ts index f2e3efb..01685b0 100644 --- a/src/interface/storage/Storage.ts +++ b/src/interface/storage/Storage.ts @@ -1,12 +1,12 @@ -import type { EventStorageAdapterMap, EventType } from "../event/Event"; +import type { SerializedEvent, EventKind } from "../event/Event"; /** - * Storage - Consumes events + * Storage Adapter - consumes and persists events */ -export interface StorageAdapterType { +export interface StorageAdapter { name: string; connectionObject: unknown; - add(serialized: EventStorageAdapterMap): Promise<{ id: string } | void>; - price(serialized: EventStorageAdapterMap): Promise; + add(serialized: SerializedEvent): Promise<{ id: string } | void>; + price(serialized: SerializedEvent): Promise; } diff --git a/src/routes/gRPC/events/streamEvents.ts b/src/routes/gRPC/events/streamEvents.ts index b83fc97..a80df2e 100644 --- a/src/routes/gRPC/events/streamEvents.ts +++ b/src/routes/gRPC/events/streamEvents.ts @@ -2,7 +2,7 @@ import type { StreamEventRequest, StreamEventResponse, } from "../../../gen/event/v1/event_pb"; -import type { EventType, EventDataMap } from "../../../interface/event/Event"; +import type { Event, EventKind } from "../../../interface/event/Event"; import { StreamEventResponseSchema } from "../../../gen/event/v1/event_pb"; import { create } from "@bufbuild/protobuf"; import { EventError } from "../../../errors/event"; @@ -23,7 +23,7 @@ export async function streamEvents( context: HandlerContext, ): Promise { let eventsProcessed = 0; - const events: Array> = []; + const events: Array> = []; try { // Extract API key ID from context diff --git a/src/storage/adapter/postgres/handlers/addAiTokenUsage.ts b/src/storage/adapter/postgres/handlers/addAiTokenUsage.ts index aa10290..a5284f0 100644 --- a/src/storage/adapter/postgres/handlers/addAiTokenUsage.ts +++ b/src/storage/adapter/postgres/handlers/addAiTokenUsage.ts @@ -5,8 +5,8 @@ import { aiTokenUsageEventsTable, } from "../../../db/postgres/schema"; import { StorageError } from "../../../../errors/storage"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; -import { type UserId } from "../../../../config/identifiers"; +import { type SqlRecord } from "../../../../interface/event/Event"; +import type { UserId } from "../../../../config/identifiers"; import { logger } from "../../../../errors/logger"; const OPERATION = "AddAiTokenUsage"; @@ -22,11 +22,7 @@ type AggregatedEvent = { }; export async function handleAddAiTokenUsage( - events: Array< - BaseEventMetadata<"AI_TOKEN_USAGE"> & { - userId: UserId; - } - >, + events: Array>, apiKeyId: string, ): Promise<{ id: string } | void> { const connectionObject = getPostgresDB(); diff --git a/src/storage/adapter/postgres/handlers/addKey.ts b/src/storage/adapter/postgres/handlers/addKey.ts index f67dd3a..aec8ee5 100644 --- a/src/storage/adapter/postgres/handlers/addKey.ts +++ b/src/storage/adapter/postgres/handlers/addKey.ts @@ -1,13 +1,13 @@ import { getPostgresDB } from "../../../db/postgres/db"; import { apiKeysTable } from "../../../db/postgres/schema"; import { StorageError } from "../../../../errors/storage"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; +import { type SqlRecord } from "../../../../interface/event/Event"; import { logger } from "../../../../errors/logger"; const OPERATION = "AddKey"; export async function handleAddKey( - event_data: BaseEventMetadata<"ADD_KEY">, + event_data: SqlRecord<"ADD_KEY">, ): Promise<{ id: string } | void> { const connectionObject = getPostgresDB(); diff --git a/src/storage/adapter/postgres/handlers/addPayment.ts b/src/storage/adapter/postgres/handlers/addPayment.ts index 2339558..01e03f7 100644 --- a/src/storage/adapter/postgres/handlers/addPayment.ts +++ b/src/storage/adapter/postgres/handlers/addPayment.ts @@ -5,16 +5,13 @@ import { paymentEventsTable, } from "../../../db/postgres/schema"; import { StorageError } from "../../../../errors/storage"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; -import { type UserId } from "../../../../config/identifiers"; +import { type SqlRecord } from "../../../../interface/event/Event"; import { logger } from "../../../../errors/logger"; const OPERATION = "AddPayment"; export async function handleAddPayment( - event_data: BaseEventMetadata<"PAYMENT"> & { - userId: UserId; - }, + event_data: SqlRecord<"PAYMENT">, apiKeyId?: string, ): Promise<{ id: string } | void> { const connectionObject = getPostgresDB(); diff --git a/src/storage/adapter/postgres/handlers/addSdkCall.ts b/src/storage/adapter/postgres/handlers/addSdkCall.ts index 22e4995..e9c52b2 100644 --- a/src/storage/adapter/postgres/handlers/addSdkCall.ts +++ b/src/storage/adapter/postgres/handlers/addSdkCall.ts @@ -5,16 +5,13 @@ import { sdkCallEventsTable, } from "../../../db/postgres/schema"; import { StorageError } from "../../../../errors/storage"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; -import { type UserId } from "../../../../config/identifiers"; +import { type SqlRecord } from "../../../../interface/event/Event"; import { logger } from "../../../../errors/logger"; const OPERATION = "AddSdkCall"; export async function handleAddSdkCall( - event_data: BaseEventMetadata<"SDK_CALL"> & { - userId: UserId; - }, + event_data: SqlRecord<"SDK_CALL">, apiKeyId: string, ): Promise<{ id: string } | void> { const connectionObject = getPostgresDB(); diff --git a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts index d834ba1..e44876f 100644 --- a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts +++ b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts @@ -1,16 +1,13 @@ import { StorageError } from "../../../../errors/storage"; import { RequestSDKCall } from "../../../../events/RequestEvents/RequestSDKCall"; import { StorageAdapterFactory } from "../../../../factory"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; -import { type UserId } from "../../../../config/identifiers"; +import { type SqlRecord } from "../../../../interface/event/Event"; import { logger } from "../../../../errors/logger"; const OPERATION = "PriceRequestPayment"; export async function handlePriceRequestPayment( - event_data: BaseEventMetadata<"REQUEST_PAYMENT"> & { - userId: UserId; - }, + event_data: SqlRecord<"REQUEST_PAYMENT">, ): Promise { try { if (!event_data.userId) { diff --git a/src/storage/adapter/postgres/handlers/priceRequestSdkCall.ts b/src/storage/adapter/postgres/handlers/priceRequestSdkCall.ts index ab6db02..1b69af6 100644 --- a/src/storage/adapter/postgres/handlers/priceRequestSdkCall.ts +++ b/src/storage/adapter/postgres/handlers/priceRequestSdkCall.ts @@ -2,16 +2,13 @@ import { getPostgresDB } from "../../../db/postgres/db"; import { sdkCallEventsTable, eventsTable } from "../../../db/postgres/schema"; import { StorageError } from "../../../../errors/storage"; import { eq, sum } from "drizzle-orm"; -import { type BaseEventMetadata } from "../../../../interface/event/Event"; -import { type UserId } from "../../../../config/identifiers"; +import { type SqlRecord } from "../../../../interface/event/Event"; import { logger } from "../../../../errors/logger"; const OPERATION = "PriceRequestSdkCall"; export async function handlePriceRequestSdkCall( - event_data: BaseEventMetadata<"REQUEST_SDK_CALL"> & { - userId: UserId; - }, + event_data: SqlRecord<"REQUEST_SDK_CALL">, ): Promise { const connectionObject = getPostgresDB(); diff --git a/src/storage/adapter/postgres/postgres.ts b/src/storage/adapter/postgres/postgres.ts index 8b7a416..fa5f916 100644 --- a/src/storage/adapter/postgres/postgres.ts +++ b/src/storage/adapter/postgres/postgres.ts @@ -1,5 +1,5 @@ -import { type StorageAdapterType } from "../../../interface/storage/Storage"; -import { type EventType } from "../../../interface/event/Event"; +import { type StorageAdapter } from "../../../interface/storage/Storage"; +import { type Event } from "../../../interface/event/Event"; import { getPostgresDB } from "../../db/postgres/db"; import { StorageError } from "../../../errors/storage"; import { @@ -10,21 +10,20 @@ import { handlePriceRequestSdkCall, handleAddAiTokenUsage, } from "./handlers"; -import { logger } from "../../../errors/logger"; -import type { EventStorageAdapterMap } from "../../../interface/event/Event"; +import type { SerializedEvent, EventKind } from "../../../interface/event/Event"; -export class PostgresAdapter implements StorageAdapterType { +export class PostgresAdapter implements StorageAdapter { name: string; connectionObject; apiKeyId?: string; - constructor(event: EventType, apiKeyId?: string) { + constructor(event: Event, apiKeyId?: string) { this.name = event.type; this.connectionObject = getPostgresDB(); this.apiKeyId = apiKeyId; } - async add(serialized: EventStorageAdapterMap) { + async add(serialized: SerializedEvent) { let event_data; try { @@ -82,7 +81,7 @@ export class PostgresAdapter implements StorageAdapterType { } async price( - serialized: EventStorageAdapterMap, + serialized: SerializedEvent, ): Promise { let event_data; diff --git a/src/utils/eventHelpers.ts b/src/utils/eventHelpers.ts index 8fbbdc9..d9fa79c 100644 --- a/src/utils/eventHelpers.ts +++ b/src/utils/eventHelpers.ts @@ -4,7 +4,7 @@ import { AuthError } from "../errors/auth"; import { EventError } from "../errors/event"; import { eventSchema } from "../zod/event"; import { ZodError } from "zod"; -import type { EventType } from "../interface/event/Event"; +import type { Event, SqlRecord } from "../interface/event/Event"; import { SDKCall } from "../events/RawEvents/SDKCall"; import { AITokenUsage } from "../events/AIEvents/AITokenUsage"; import { StorageAdapterFactory } from "../factory"; @@ -58,7 +58,7 @@ export function createEventInstance(eventSkeleton: { type: string; userId: string; data: any; -}): EventType { +}): Event { try { switch (eventSkeleton.type) { case "SDK_CALL": @@ -80,7 +80,7 @@ export function createEventInstance(eventSkeleton: { * Store the event using the appropriate storage adapter */ export async function storeEvent( - event: EventType, + event: Event, apiKeyId: string, ): Promise { try { @@ -101,7 +101,7 @@ export async function storeEvent( * Store multiple events in a batch - groups by type and uses batch operations when possible */ export async function storeEventsBatch( - events: EventType[], + events: Event[], apiKeyId: string, ): Promise { if (events.length === 0) { @@ -109,7 +109,7 @@ export async function storeEventsBatch( } // Group events by type - const eventsByType = new Map(); + const eventsByType = new Map(); for (const event of events) { const type = event.type; if (!eventsByType.has(type)) { @@ -123,11 +123,7 @@ export async function storeEventsBatch( try { if (type === "AI_TOKEN_USAGE") { // Batch process AI_TOKEN_USAGE events - const serializedEvents: Array< - import("../interface/event/Event").BaseEventMetadata<"AI_TOKEN_USAGE"> & { - userId: string; - } - > = []; + const serializedEvents: Array> = []; for (const event of typeEvents) { const { SQL } = event.serialize(); @@ -141,7 +137,7 @@ export async function storeEventsBatch( `Expected AI_TOKEN_USAGE but got ${SQL.type}`, ); } - serializedEvents.push(SQL as any); + serializedEvents.push(SQL as SqlRecord<"AI_TOKEN_USAGE">); } await handleAddAiTokenUsage(serializedEvents, apiKeyId); @@ -159,3 +155,4 @@ export async function storeEventsBatch( } } } + From 40381ee7ba341f2735aeb3044240c3c57133124e Mon Sep 17 00:00:00 2001 From: Jayadeep Bejoy Date: Sat, 20 Dec 2025 05:07:53 +0400 Subject: [PATCH 4/4] refactor(formatting) Signed-off-by: Jayadeep Bejoy --- package.json | 3 ++- src/events/AIEvents/AITokenUsage.ts | 5 ++++- src/events/RawEvents/Payment.ts | 5 ++++- src/events/RawEvents/SDKCall.ts | 5 ++++- src/routes/gRPC/payment/createCheckoutLink.ts | 5 ++--- .../adapter/postgres/handlers/priceRequestPayment.ts | 4 +--- src/storage/adapter/postgres/postgres.ts | 9 +++++---- src/utils/eventHelpers.ts | 1 - 8 files changed, 22 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 3e04974..3e75e4c 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "test": "vitest", "test:ui": "vitest --ui", "start": "bun run src/server.ts", - "init_key": "bun run src/utils/generateInitialAPIKey.ts" + "init_key": "bun run src/utils/generateInitialAPIKey.ts", + "format": "bunx prettier --write ." }, "devDependencies": { "@types/bun": "latest", diff --git a/src/events/AIEvents/AITokenUsage.ts b/src/events/AIEvents/AITokenUsage.ts index 86d8966..00e7e61 100644 --- a/src/events/AIEvents/AITokenUsage.ts +++ b/src/events/AIEvents/AITokenUsage.ts @@ -1,4 +1,7 @@ -import type { AITokenUsageEvent, AITokenUsageEventData } from "../../interface/event/Event"; +import type { + AITokenUsageEvent, + AITokenUsageEventData, +} from "../../interface/event/Event"; import { DateTime } from "luxon"; import type { UserId } from "../../config/identifiers"; diff --git a/src/events/RawEvents/Payment.ts b/src/events/RawEvents/Payment.ts index edd7314..1ccfba9 100644 --- a/src/events/RawEvents/Payment.ts +++ b/src/events/RawEvents/Payment.ts @@ -1,4 +1,7 @@ -import type { PaymentEvent, PaymentEventData } from "../../interface/event/Event"; +import type { + PaymentEvent, + PaymentEventData, +} from "../../interface/event/Event"; import { DateTime } from "luxon"; import type { UserId } from "../../config/identifiers"; diff --git a/src/events/RawEvents/SDKCall.ts b/src/events/RawEvents/SDKCall.ts index fd55b26..005cd9b 100644 --- a/src/events/RawEvents/SDKCall.ts +++ b/src/events/RawEvents/SDKCall.ts @@ -1,4 +1,7 @@ -import type { SDKCallEvent, SDKCallEventData } from "../../interface/event/Event"; +import type { + SDKCallEvent, + SDKCallEventData, +} from "../../interface/event/Event"; import { DateTime } from "luxon"; import type { UserId } from "../../config/identifiers"; diff --git a/src/routes/gRPC/payment/createCheckoutLink.ts b/src/routes/gRPC/payment/createCheckoutLink.ts index bb7f516..29c4e24 100644 --- a/src/routes/gRPC/payment/createCheckoutLink.ts +++ b/src/routes/gRPC/payment/createCheckoutLink.ts @@ -101,9 +101,8 @@ export async function createCheckoutLink( let custom_price: number; try { const event = new RequestPayment(validatedData.userId, null); - const storageAdapter = await StorageAdapterFactory.getStorageAdapter( - event, - ); + const storageAdapter = + await StorageAdapterFactory.getStorageAdapter(event); if (!storageAdapter) { throw PaymentError.storageAdapterFailed( diff --git a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts index e44876f..0e5ca04 100644 --- a/src/storage/adapter/postgres/handlers/priceRequestPayment.ts +++ b/src/storage/adapter/postgres/handlers/priceRequestPayment.ts @@ -22,9 +22,7 @@ export async function handlePriceRequestPayment( ); const event = new RequestSDKCall(event_data.userId, null); - const storageAdapter = await StorageAdapterFactory.getStorageAdapter( - event - ); + const storageAdapter = await StorageAdapterFactory.getStorageAdapter(event); if (!storageAdapter) { throw StorageError.unknown( diff --git a/src/storage/adapter/postgres/postgres.ts b/src/storage/adapter/postgres/postgres.ts index fa5f916..dac6a64 100644 --- a/src/storage/adapter/postgres/postgres.ts +++ b/src/storage/adapter/postgres/postgres.ts @@ -10,7 +10,10 @@ import { handlePriceRequestSdkCall, handleAddAiTokenUsage, } from "./handlers"; -import type { SerializedEvent, EventKind } from "../../../interface/event/Event"; +import type { + SerializedEvent, + EventKind, +} from "../../../interface/event/Event"; export class PostgresAdapter implements StorageAdapter { name: string; @@ -80,9 +83,7 @@ export class PostgresAdapter implements StorageAdapter { } } - async price( - serialized: SerializedEvent, - ): Promise { + async price(serialized: SerializedEvent): Promise { let event_data; try { diff --git a/src/utils/eventHelpers.ts b/src/utils/eventHelpers.ts index d9fa79c..ed3f071 100644 --- a/src/utils/eventHelpers.ts +++ b/src/utils/eventHelpers.ts @@ -155,4 +155,3 @@ export async function storeEventsBatch( } } } -