diff --git a/coverage/summary.json b/coverage/summary.json index 6444615..91543fa 100644 --- a/coverage/summary.json +++ b/coverage/summary.json @@ -1,18 +1,18 @@ { - "generatedAt": "2026-05-13T18:36:10.133Z", - "commit": "9800fed", + "generatedAt": "2026-05-18T11:31:45.093Z", + "commit": "80c702e", "repo": { - "statements": 95.86, - "branches": 88.91, + "statements": 95.87, + "branches": 89.02, "functions": 100, - "lines": 95.86, + "lines": 95.87, "counts": { - "lf": 3113, - "lh": 2984, - "brf": 487, - "brh": 433, - "fnf": 142, - "fnh": 142 + "lf": 3121, + "lh": 2992, + "brf": 492, + "brh": 438, + "fnf": 147, + "fnh": 147 } }, "byPackage": { @@ -44,6 +44,20 @@ "fnh": 29 } }, + "@repo/core-analytics": { + "statements": 100, + "branches": 100, + "functions": 100, + "lines": 100, + "counts": { + "lf": 8, + "lh": 8, + "brf": 5, + "brh": 5, + "fnf": 5, + "fnh": 5 + } + }, "@repo/marketing-pages": { "statements": 95.64, "branches": 83.93, diff --git a/packages/core-analytics/src/analytics.interface.ts b/packages/core-analytics/src/analytics.interface.ts new file mode 100644 index 0000000..5ecc7fe --- /dev/null +++ b/packages/core-analytics/src/analytics.interface.ts @@ -0,0 +1,21 @@ +export type AnalyticsAttributeValue = string | number | boolean; + +export type AnalyticsUser = { + id: string; +}; + +export interface IAnalytics { + track( + event: string, + attributes?: Record, + ): void; + identify( + user: AnalyticsUser, + attributes?: Record, + ): void; + pageView( + path: string, + attributes?: Record, + ): void; + flush(): Promise; +} diff --git a/packages/core-analytics/src/index.ts b/packages/core-analytics/src/index.ts index 8e2040a..2d491a2 100644 --- a/packages/core-analytics/src/index.ts +++ b/packages/core-analytics/src/index.ts @@ -1,2 +1,6 @@ -// placeholder — populated by story 01-scaffold-core-analytics-package -export {}; +export type { + AnalyticsAttributeValue, + AnalyticsUser, + IAnalytics, +} from "./analytics.interface"; +export { NoopAnalytics } from "./noop-analytics"; diff --git a/packages/core-analytics/src/noop-analytics.test.ts b/packages/core-analytics/src/noop-analytics.test.ts new file mode 100644 index 0000000..c302e1b --- /dev/null +++ b/packages/core-analytics/src/noop-analytics.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest"; +import { NoopAnalytics } from "@/noop-analytics"; + +describe("NoopAnalytics", () => { + it("track() does not throw with event name only", () => { + const analytics = new NoopAnalytics(); + expect(() => analytics.track("page_viewed")).not.toThrow(); + }); + + it("track() does not throw with event name and attributes", () => { + const analytics = new NoopAnalytics(); + expect(() => + analytics.track("button_clicked", { + label: "signup", + count: 1, + active: true, + }), + ).not.toThrow(); + }); + + it("identify() does not throw with user only", () => { + const analytics = new NoopAnalytics(); + expect(() => analytics.identify({ id: "user-123" })).not.toThrow(); + }); + + it("identify() does not throw with user and attributes", () => { + const analytics = new NoopAnalytics(); + expect(() => + analytics.identify({ id: "user-123" }, { plan: "pro", trial: false }), + ).not.toThrow(); + }); + + it("pageView() does not throw with path only", () => { + const analytics = new NoopAnalytics(); + expect(() => analytics.pageView("/dashboard")).not.toThrow(); + }); + + it("pageView() does not throw with path and attributes", () => { + const analytics = new NoopAnalytics(); + expect(() => + analytics.pageView("/dashboard", { referrer: "/home", duration: 120 }), + ).not.toThrow(); + }); + + it("flush() resolves without throwing", async () => { + const analytics = new NoopAnalytics(); + await expect(analytics.flush()).resolves.toBeUndefined(); + }); + + it("flush() returns a Promise", () => { + const analytics = new NoopAnalytics(); + expect(analytics.flush()).toBeInstanceOf(Promise); + }); +}); diff --git a/packages/core-analytics/src/noop-analytics.ts b/packages/core-analytics/src/noop-analytics.ts new file mode 100644 index 0000000..03d9d78 --- /dev/null +++ b/packages/core-analytics/src/noop-analytics.ts @@ -0,0 +1,23 @@ +import type { + AnalyticsAttributeValue, + AnalyticsUser, + IAnalytics, +} from "./analytics.interface"; + +export class NoopAnalytics implements IAnalytics { + track( + _event: string, + _attributes?: Record, + ): void {} + identify( + _user: AnalyticsUser, + _attributes?: Record, + ): void {} + pageView( + _path: string, + _attributes?: Record, + ): void {} + flush(): Promise { + return Promise.resolve(); + } +}