Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# dependencies (bun install)
node_modules
nul

# output
out
Expand Down
17 changes: 17 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"proseWrap": "preserve",
"htmlWhitespaceSensitivity": "css",
"endOfLine": "lf",
"embeddedLanguageFormatting": "auto"
}
15 changes: 7 additions & 8 deletions proto/event/v1/event.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ message RegisterEventResponse {
string random = 1;
}

message StreamEventRequest {
EventType type = 1;
string userId = 2;
oneof data {
SDKCall sdkCall = 3;
AITokenUsage aiTokenUsage = 4;
}
}
message StreamEventRequest {
EventType type = 1;
string userId = 2;
oneof data {
AITokenUsage aiTokenUsage = 4;
}
}

message AITokenUsage {
string model = 1;
Expand Down
24 changes: 12 additions & 12 deletions src/__tests__/unit/http/createdCheckout.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ describe("handleLemonSqueezyWebhook", () => {
"MISSING_WEBHOOK_SECRET",
"Webhook secret not configured",
undefined,
{},
{}
);
});

Expand Down Expand Up @@ -194,7 +194,7 @@ describe("handleLemonSqueezyWebhook", () => {
"INVALID_SIGNATURE",
"Invalid webhook signature",
undefined,
{},
{}
);
});

Expand Down Expand Up @@ -225,7 +225,7 @@ describe("handleLemonSqueezyWebhook", () => {
"INVALID_JSON",
"Invalid JSON payload",
expect.any(Error),
{},
{}
);
});

Expand Down Expand Up @@ -255,7 +255,7 @@ describe("handleLemonSqueezyWebhook", () => {
expect((res as any).statusCode).toBe(200);
expect((res as any).body).toContain("Event ignored");
expect(
storageModule.StorageAdapterFactory.getStorageAdapter,
storageModule.StorageAdapterFactory.getStorageAdapter
).not.toHaveBeenCalled();
expect(paymentConstructorCalls.length).toBe(0);
});
Expand Down Expand Up @@ -295,7 +295,7 @@ describe("handleLemonSqueezyWebhook", () => {
"MISSING_USER_ID",
"Missing user_id in webhook payload",
undefined,
{},
{}
);
});

Expand Down Expand Up @@ -336,7 +336,7 @@ describe("handleLemonSqueezyWebhook", () => {
"MISSING_API_KEY_ID",
"Missing apiKeyId in webhook payload",
undefined,
{ userId: "user-123" },
{ userId: "user-123" }
);
});

Expand All @@ -346,7 +346,7 @@ describe("handleLemonSqueezyWebhook", () => {

const adapterAddMock = vi.fn().mockResolvedValue(undefined);
vi.mocked(
storageModule.StorageAdapterFactory.getStorageAdapter,
storageModule.StorageAdapterFactory.getStorageAdapter
).mockResolvedValue({
add: adapterAddMock,
} as any);
Expand Down Expand Up @@ -394,10 +394,10 @@ describe("handleLemonSqueezyWebhook", () => {
});

expect(
storageModule.StorageAdapterFactory.getStorageAdapter,
storageModule.StorageAdapterFactory.getStorageAdapter
).toHaveBeenCalledTimes(1);
const adapterCall = vi.mocked(
storageModule.StorageAdapterFactory.getStorageAdapter,
storageModule.StorageAdapterFactory.getStorageAdapter
).mock.calls[0];
expect(adapterCall[1]).toBe("api-key-456");

Expand All @@ -414,7 +414,7 @@ describe("handleLemonSqueezyWebhook", () => {
const dbError = new Error("DB error");
const adapterAddMock = vi.fn().mockRejectedValue(dbError);
vi.mocked(
storageModule.StorageAdapterFactory.getStorageAdapter,
storageModule.StorageAdapterFactory.getStorageAdapter
).mockResolvedValue({
add: adapterAddMock,
} as any);
Expand Down Expand Up @@ -464,7 +464,7 @@ describe("handleLemonSqueezyWebhook", () => {
"DATABASE_ERROR",
"Database error while storing payment",
dbError,
{ userId: "user-123", apiKeyId: "api-key-456" },
{ userId: "user-123", apiKeyId: "api-key-456" }
);
});

Expand Down Expand Up @@ -492,7 +492,7 @@ describe("handleLemonSqueezyWebhook", () => {
"UNEXPECTED_ERROR",
"Unexpected error in webhook handler",
expect.any(Error),
{},
{}
);
});
});
10 changes: 5 additions & 5 deletions src/__tests__/unit/interceptors/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,24 @@ describe("authInterceptor", () => {

// Empty Authorization should be rejected
await expect(interceptor(next)(makeReq() as any)).rejects.toThrow(
"Missing Authorization header",
"Missing Authorization header"
);

// Authorization that does not start with Bearer should be rejected
await expect(
interceptor(next)(makeReq("Token abcdef") as any),
interceptor(next)(makeReq("Token abcdef") as any)
).rejects.toThrow(
'Authorization header must be in format "Bearer <api_key>"',
'Authorization header must be in format "Bearer <api_key>"'
);

// Authorization with invalid API key format (not starting with scrn_) should be rejected
await expect(
interceptor(next)(makeReq("Bearer " + "a".repeat(37)) as any),
interceptor(next)(makeReq("Bearer " + "a".repeat(37)) as any)
).rejects.toThrow("Invalid API key: Invalid API key format");

// Authorization with invalid API key format (wrong length) should be rejected
await expect(
interceptor(next)(makeReq("Bearer scrn_short") as any),
interceptor(next)(makeReq("Bearer scrn_short") as any)
).rejects.toThrow("Invalid API key: Invalid API key format");
});

Expand Down
20 changes: 10 additions & 10 deletions src/__tests__/unit/storage/postgres/addAiTokenUsage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {

// Find GPT-4 aggregated record
const gpt4Record = aiTokenUsageInsertCall[0].find(
(r: any) => r.model === "gpt-4",
(r: any) => r.model === "gpt-4"
);
expect(gpt4Record).toEqual({
id: expect.any(String),
Expand All @@ -161,7 +161,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {

// Find Claude aggregated record
const claudeRecord = aiTokenUsageInsertCall[0].find(
(r: any) => r.model === "claude-3-opus",
(r: any) => r.model === "claude-3-opus"
);
expect(claudeRecord).toEqual({
id: expect.any(String),
Expand Down Expand Up @@ -313,12 +313,12 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {

// Verify aggregation: should have 2 gpt-4 records and 1 claude record
const gpt4Records = aiTokenUsageInsertCall[0].filter(
(r: any) => r.model === "gpt-4",
(r: any) => r.model === "gpt-4"
);
expect(gpt4Records).toHaveLength(2);

const claudeRecords = aiTokenUsageInsertCall[0].filter(
(r: any) => r.model === "claude-3-sonnet",
(r: any) => r.model === "claude-3-sonnet"
);
expect(claudeRecords).toHaveLength(1);

Expand Down Expand Up @@ -419,7 +419,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {
{ id: "user-1" },
{ id: "user-2" },
{ id: "user-3" },
]),
])
);
});

Expand Down Expand Up @@ -491,7 +491,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {
mockTransaction.returning.mockResolvedValueOnce([]);

await expect(
handleAddAiTokenUsage(events, "api-key-123"),
handleAddAiTokenUsage(events, "api-key-123")
).rejects.toThrow("Event insert returned no IDs");
});

Expand Down Expand Up @@ -527,7 +527,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {
mockTransaction.returning.mockResolvedValueOnce([{ id: "event-1" }]);

await expect(
handleAddAiTokenUsage(events, "api-key-123"),
handleAddAiTokenUsage(events, "api-key-123")
).rejects.toThrow("Expected 2 event IDs but got 1");
});
});
Expand All @@ -552,7 +552,7 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {
mockDb.transaction.mockRejectedValueOnce(new Error("Transaction failed"));

await expect(
handleAddAiTokenUsage(events, "api-key-123"),
handleAddAiTokenUsage(events, "api-key-123")
).rejects.toThrow("Transaction failed");
});

Expand All @@ -573,11 +573,11 @@ describe("handleAddAiTokenUsage - Aggregation and Batch Insert", () => {
];

mockTransaction.returning.mockRejectedValueOnce(
new Error("Insert failed"),
new Error("Insert failed")
);

await expect(
handleAddAiTokenUsage(events, "api-key-123"),
handleAddAiTokenUsage(events, "api-key-123")
).rejects.toThrow();
});
});
Expand Down
16 changes: 8 additions & 8 deletions src/__tests__/unit/storage/postgres/addKey.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"Missing data field",
"Missing data field"
);
});

Expand All @@ -119,7 +119,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"Invalid or missing 'name'",
"Invalid or missing 'name'"
);
});

Expand All @@ -146,7 +146,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"Invalid or missing 'key'",
"Invalid or missing 'key'"
);
});

Expand Down Expand Up @@ -175,7 +175,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"API key cannot be empty",
"API key cannot be empty"
);
});

Expand All @@ -202,7 +202,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"Timestamp is undefined or empty",
"Timestamp is undefined or empty"
);
});
});
Expand All @@ -216,7 +216,7 @@ describe("PostgresAdapter - addKey handler", () => {
});

mockTransaction.returning.mockRejectedValueOnce(
new Error("Database connection error"),
new Error("Database connection error")
);

const adapter = new PostgresAdapter(addKeyEvent);
Expand All @@ -236,7 +236,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(addKeyEvent);
const serialized = addKeyEvent.serialize();
await expect(adapter.add(serialized)).rejects.toThrow(
"API key insert returned no record",
"API key insert returned no record"
);
});

Expand All @@ -252,7 +252,7 @@ describe("PostgresAdapter - addKey handler", () => {
const adapter = new PostgresAdapter(addKeyEvent);
const serialized = addKeyEvent.serialize();
await expect(adapter.add(serialized)).rejects.toThrow(
"API key insert returned object without id field",
"API key insert returned object without id field"
);
});
});
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/unit/storage/postgres/addPayment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ describe("PostgresAdapter - addPayment handler", () => {
const adapter = new PostgresAdapter(invalidEvent as any);
const serialized = invalidEvent.serialize() as any;
await expect(adapter.add(serialized)).rejects.toThrow(
"Timestamp is undefined or empty",
"Timestamp is undefined or empty"
);
});
});
Expand All @@ -176,7 +176,7 @@ describe("PostgresAdapter - addPayment handler", () => {

mockTransaction.returning.mockResolvedValueOnce([]);
mockTransaction.returning.mockRejectedValueOnce(
new Error("Event insert failed"),
new Error("Event insert failed")
);

const adapter = new PostgresAdapter(paymentEvent);
Expand All @@ -195,7 +195,7 @@ describe("PostgresAdapter - addPayment handler", () => {
const adapter = new PostgresAdapter(paymentEvent);
const serialized = paymentEvent.serialize();
await expect(adapter.add(serialized)).rejects.toThrow(
"Event insert returned no ID",
"Event insert returned no ID"
);
});
});
Expand Down
Loading
Loading