Some checks failed
Deploy to Production / test (push) Failing after 30s
The web/ folder contains the REST API, WebSocket server, and OAuth routes — not a web frontend. Renaming to api/ clarifies this distinction since the actual web frontend lives in panel/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
92 lines
3.0 KiB
TypeScript
92 lines
3.0 KiB
TypeScript
/**
|
|
* @fileoverview Transaction listing endpoints for Aurora API.
|
|
* Provides read access to economy transaction history.
|
|
*/
|
|
|
|
import type { RouteContext, RouteModule } from "./types";
|
|
import { jsonResponse, withErrorHandling } from "./utils";
|
|
|
|
/**
|
|
* Transactions routes handler.
|
|
*
|
|
* Endpoints:
|
|
* - GET /api/transactions - List transactions with filters
|
|
*/
|
|
async function handler(ctx: RouteContext): Promise<Response | null> {
|
|
const { pathname, method, url } = ctx;
|
|
|
|
/**
|
|
* @route GET /api/transactions
|
|
* @description Returns economy transactions with optional filtering.
|
|
*
|
|
* @query userId - Filter by user ID (Discord snowflake)
|
|
* @query type - Filter by transaction type
|
|
* @query limit - Max results (default: 50)
|
|
* @query offset - Pagination offset (default: 0)
|
|
*
|
|
* @response 200 - `{ transactions: Transaction[] }`
|
|
* @response 500 - Error fetching transactions
|
|
*
|
|
* Transaction Types:
|
|
* - DAILY_REWARD - Daily claim reward
|
|
* - TRANSFER_IN - Received from another user
|
|
* - TRANSFER_OUT - Sent to another user
|
|
* - LOOTDROP_CLAIM - Claimed lootdrop
|
|
* - SHOP_BUY - Item purchase
|
|
* - QUEST_REWARD - Quest completion reward
|
|
*
|
|
* @example
|
|
* // Request
|
|
* GET /api/transactions?userId=123456789&type=DAILY_REWARD&limit=10
|
|
*
|
|
* // Response
|
|
* {
|
|
* "transactions": [
|
|
* {
|
|
* "id": "1",
|
|
* "userId": "123456789",
|
|
* "amount": "100",
|
|
* "type": "DAILY_REWARD",
|
|
* "description": "Daily reward (Streak: 3)",
|
|
* "createdAt": "2024-01-15T12:00:00Z"
|
|
* }
|
|
* ]
|
|
* }
|
|
*/
|
|
if (pathname === "/api/transactions" && method === "GET") {
|
|
return withErrorHandling(async () => {
|
|
const { transactions } = await import("@shared/db/schema");
|
|
const { DrizzleClient } = await import("@shared/db/DrizzleClient");
|
|
const { eq, desc } = await import("drizzle-orm");
|
|
|
|
const userId = url.searchParams.get("userId");
|
|
const type = url.searchParams.get("type");
|
|
const limit = url.searchParams.get("limit") ? parseInt(url.searchParams.get("limit")!) : 50;
|
|
const offset = url.searchParams.get("offset") ? parseInt(url.searchParams.get("offset")!) : 0;
|
|
|
|
let query = DrizzleClient.select().from(transactions);
|
|
|
|
if (userId) {
|
|
query = query.where(eq(transactions.userId, BigInt(userId))) as typeof query;
|
|
}
|
|
if (type) {
|
|
query = query.where(eq(transactions.type, type)) as typeof query;
|
|
}
|
|
|
|
const result = await query
|
|
.orderBy(desc(transactions.createdAt))
|
|
.limit(limit)
|
|
.offset(offset);
|
|
|
|
return jsonResponse({ transactions: result });
|
|
}, "fetch transactions");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export const transactionsRoutes: RouteModule = {
|
|
name: "transactions",
|
|
handler
|
|
};
|