diff --git a/.gitignore b/.gitignore index 04c01ba..b947077 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ node_modules/ -dist/ \ No newline at end of file +dist/ diff --git a/src/functions/create-auction.ts b/src/functions/create-auction.ts index 6f31f4f..a0890ee 100644 --- a/src/functions/create-auction.ts +++ b/src/functions/create-auction.ts @@ -2,8 +2,9 @@ import { apis, baseURL } from "../constants/apis.constant"; import type { AuctionResult, TopsortAuction } from "../interfaces/auctions.interface"; import type { Config } from "../interfaces/shared.interface"; import APIClient from "../lib/api-client"; +import { withValidation } from "../lib/with-validation"; -export async function createAuction(body: TopsortAuction, config: Config): Promise { +async function handler(config: Config, body: TopsortAuction): Promise { let url: URL; try { url = new URL(`${config.host || baseURL}/${apis.auctions}`); @@ -14,3 +15,5 @@ export async function createAuction(body: TopsortAuction, config: Config): Promi const result = await APIClient.post(url.toString(), body, config); return result as AuctionResult; } + +export const createAuction = withValidation(handler); diff --git a/src/functions/report-event.ts b/src/functions/report-event.ts index 3d3dd47..6aed220 100644 --- a/src/functions/report-event.ts +++ b/src/functions/report-event.ts @@ -2,6 +2,7 @@ import { apis, baseURL } from "../constants/apis.constant"; import type { TopsortEvent } from "../interfaces/events.interface"; import type { Config } from "../interfaces/shared.interface"; import APIClient from "../lib/api-client"; +import { withValidation } from "../lib/with-validation"; /** * Reports an event to the Topsort API. @@ -9,16 +10,16 @@ import APIClient from "../lib/api-client"; * @example * ```js * const event = { eventType: "test", eventData: {} }; - * const config = { token: "my-token" }; + * const config = { apiKey: "api-key" }; * const result = await reportEvent(event, config); - * console.log(result); // { "ok": true, "retry": false } + * console.log(result); // { "ok": true } * ``` * * @param event - The event to report. - * @param config - The configuration object containing URL and token. - * @returns {Promise<{ok: boolean}>} The result of the report, indicating success and if a retry is needed. + * @param config - The configuration object containing the API Key and optionally, the Host. + * @returns {Promise<{ok: boolean}>} The result of the report, indicating success. */ -export async function reportEvent(event: TopsortEvent, config: Config): Promise<{ ok: boolean }> { +async function handler(config: Config, event: TopsortEvent): Promise<{ ok: boolean }> { let url: URL; try { url = new URL(`${config.host || baseURL}/${apis.events}`); @@ -32,3 +33,5 @@ export async function reportEvent(event: TopsortEvent, config: Config): Promise< ok: true, }; } + +export const reportEvent = withValidation(handler); diff --git a/src/index.ts b/src/index.ts index 7a474c4..9cb3479 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export * from "./functions/report-event"; -export * from "./functions/create-auction"; +export { reportEvent } from "./functions/report-event"; +export { createAuction } from "./functions/create-auction"; export * from "./interfaces/events.interface"; diff --git a/src/lib/validate-config.ts b/src/lib/validate-config.ts new file mode 100644 index 0000000..722b72a --- /dev/null +++ b/src/lib/validate-config.ts @@ -0,0 +1,8 @@ +import type { Config } from "../interfaces/shared.interface"; +import AppError from "./app-error"; + +export function validateConfig(config: Config): void { + if (!config.apiKey) { + throw new AppError(401, "API Key is required.", {}); + } +} diff --git a/src/lib/with-validation.ts b/src/lib/with-validation.ts new file mode 100644 index 0000000..ae5e0b2 --- /dev/null +++ b/src/lib/with-validation.ts @@ -0,0 +1,11 @@ +import type { Config } from "../interfaces/shared.interface"; +import { validateConfig } from "./validate-config"; + +export function withValidation( + fn: (config: T, ...args: Args) => Promise, +): (config: T, ...args: Args) => Promise { + return async (config: T, ...args: Args): Promise => { + validateConfig(config); + return fn(config, ...args); + }; +} diff --git a/src/tests/doctest.testx.ts b/src/tests/doctest.testx.ts deleted file mode 100644 index 39a7946..0000000 --- a/src/tests/doctest.testx.ts +++ /dev/null @@ -1,78 +0,0 @@ -// import * as path from "node:path"; -// import { describe, it, expect, beforeAll, afterAll, afterEach } from "bun:test"; -// import { generateTestCases } from "../lib/generate-test-cases"; -// import { reportEvent } from "../functions/report-event"; -// import { apis, baseURL } from "../constants/apis.constant"; -// import APIClient from "../lib/api-client"; -// import { setupServer } from "msw/node"; -// import { handlers } from "../constants/handlers.constant"; - -// const server = setupServer(handlers.test); -// const filePath = path.resolve(__dirname, "../functions/report-event.ts"); - -// interface TestCaseInterface { -// code: string; -// expected: unknown; -// } - -// let testCases: TestCaseInterface[] = []; - -// beforeAll(async () => { -// server.listen(); -// testCases = await generateTestCases(filePath); -// console.log("Test cases:", testCases); -// }); - -// afterEach(() => server.resetHandlers()); -// afterAll(() => server.close()); - -// describe("doctest", () => { -// console.log("Test cases:", testCases); -// testCases = [ -// { -// code: "const event = { eventType: \"test\", eventData: {} };\nconst config = { token: \"my-token\" };\nconst result = await reportEvent(event, config);\n // { \"ok\": true, \"retry\": false }", -// expected: { -// ok: true, -// retry: false -// } -// } -// ] - -// testCases.forEach((testCase, index) => { -// it(`example ${index + 1}`, async () => { -// const code = ` -// (async () => { -// const event = { eventType: "test", eventData: {} }; -// const config = { token: "my-token", apiKey: "test-api-key" }; -// const result = await reportEvent(event, config); -// return result; -// })(); -// `; - -// const func = new Function("require", "exports", "module", "__filename", "__dirname", "reportEvent", "apis", "baseURL", "APIClient", code); -// const exports: unknown = {}; -// const module = { exports }; - -// // Mock require function -// const customRequire = (moduleName: string): unknown => { -// if (moduleName === "../functions/report-event") { -// return { reportEvent }; -// } -// if (moduleName === "../constants/apis.constant") { -// return { apis, baseURL }; -// } -// if (moduleName === "../lib/api-client") { -// return APIClient; -// } -// throw new Error(`Module not found: ${moduleName}`); -// }; - -// const result = await func(customRequire, exports, module, __filename, __dirname, reportEvent, apis, baseURL, APIClient); - -// console.log("Result:", result); // Debugging line - -// expect(result).toBeDefined(); -// expect(result).toEqual(testCase.expected); -// }); -// }); -// }); diff --git a/src/tests/report-event.test.ts b/src/tests/report-event.test.ts index 34652a8..b186b21 100644 --- a/src/tests/report-event.test.ts +++ b/src/tests/report-event.test.ts @@ -15,7 +15,7 @@ describe("reportEvent", () => { it("should handle permanent error", async () => { returnStatus(400, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + await expect(reportEvent({ apiKey: "apiKey" }, {} as TopsortEvent)).rejects.toEqual({ status: 400, statusText: "", body: {}, @@ -24,7 +24,7 @@ describe("reportEvent", () => { it("should handle authentication error", async () => { returnStatus(401, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + await expect(reportEvent({ apiKey: "apiKey" }, {} as TopsortEvent)).rejects.toEqual({ status: 401, statusText: "", body: {}, @@ -33,7 +33,7 @@ describe("reportEvent", () => { it("should handle retryable error", async () => { returnStatus(429, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + await expect(reportEvent({ apiKey: "apiKey" }, {} as TopsortEvent)).rejects.toEqual({ status: 429, statusText: "", body: {}, @@ -42,7 +42,7 @@ describe("reportEvent", () => { it("should handle server error", async () => { returnStatus(500, server, `${baseURL}/${apis.events}`); - await expect(reportEvent({} as TopsortEvent, { apiKey: "apiKey" })).rejects.toEqual({ + await expect(reportEvent({ apiKey: "apiKey" }, {} as TopsortEvent)).rejects.toEqual({ status: 500, statusText: "", body: {}, @@ -52,10 +52,13 @@ describe("reportEvent", () => { it("should handle custom url", async () => { returnStatus(200, server, `https://demo.api.topsort.com/${apis.events}`); await expect( - reportEvent({} as TopsortEvent, { - apiKey: "apiKey", - host: "https://demo.api.topsort.com", - }), + reportEvent( + { + apiKey: "apiKey", + host: "https://demo.api.topsort.com", + }, + {} as TopsortEvent, + ), ).resolves.toEqual({ ok: true }); }); });