Skip to content

Commit

Permalink
feat: add event props to api
Browse files Browse the repository at this point in the history
  • Loading branch information
mxkaske committed Dec 24, 2024
1 parent bb4bec7 commit a03ea00
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 19 deletions.
14 changes: 11 additions & 3 deletions apps/server/src/v1/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { verifyKey } from "@unkey/api";
import type { Context, Next } from "hono";

import { type EventProps, setupAnalytics } from "@openstatus/analytics";
import {
type EventProps,
parseInputToProps,
setupAnalytics,
} from "@openstatus/analytics";
import { db, eq } from "@openstatus/db";
import { selectWorkspaceSchema, workspace } from "@openstatus/db/src/schema";
import { getPlanConfig } from "@openstatus/db/src/schema/plan/utils";
Expand Down Expand Up @@ -46,20 +50,24 @@ export async function secureMiddleware(
await next();
}

export function trackMiddleware(event: EventProps) {
export function trackMiddleware(event: EventProps, eventProps?: string[]) {
return async (c: Context<{ Variables: Variables }, "/*">, next: Next) => {
await next();

// REMINDER: only track the event if the request was successful
// REMINDER: use setTimeout to avoid blocking the response
if (c.finalized) {
// We have checked the request to be valid already
const json = (await c.req.json()) as unknown;
const additionalProps = parseInputToProps(json, eventProps);

setTimeout(async () => {
const analytics = await setupAnalytics({
userId: `api_${c.get("workspaceId")}`,
workspaceId: c.get("workspaceId"),
plan: c.get("workspacePlan").id,
});
await analytics.track(event);
await analytics.track({ ...event, additionalProps });
}, 0);
}
};
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/v1/monitors/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const postRoute = createRoute({
tags: ["monitor"],
description: "Create a monitor",
path: "/",
middleware: [trackMiddleware(Events.CreateMonitor)],
middleware: [trackMiddleware(Events.CreateMonitor, ["url", "jobType"])],
request: {
body: {
description: "The monitor to create",
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/v1/pages/post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const postRoute = createRoute({
tags: ["page"],
description: "Create a status page",
path: "/",
middleware: [trackMiddleware(Events.CreatePage)],
middleware: [trackMiddleware(Events.CreatePage, ["slug"])],
request: {
body: {
description: "The status page to create",
Expand Down
1 change: 1 addition & 0 deletions packages/analytics/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./events";
export * from "./server";
export * from "./utils";
18 changes: 18 additions & 0 deletions packages/analytics/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export function parseInputToProps(
json: unknown,
eventProps?: string[],
): Record<string, unknown> {
if (typeof json !== "object" || json === null) return {};

if (!eventProps) return {};

return eventProps.reduce(
(acc, prop) => {
if (prop in json) {
acc[prop] = json[prop as keyof typeof json];
}
return acc;
},
{} as Record<string, unknown>,
);
}
16 changes: 2 additions & 14 deletions packages/api/src/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ZodError } from "zod";
import {
type EventProps,
type IdentifyProps,
parseInputToProps,
setupAnalytics,
} from "@openstatus/analytics";
import { db, eq, schema } from "@openstatus/db";
Expand Down Expand Up @@ -211,20 +212,7 @@ const enforceUserIsAuthed = t.middleware(async (opts) => {

const analytics = await setupAnalytics(identify);
const rawInput = await getRawInput();

const additionalProps =
typeof rawInput === "object" && rawInput !== null
? meta.trackProps?.reduce(
(acc, prop) => {
// REMINDER: Yet, prop can only be a property of the rawInput, not a nested one
if (prop in rawInput) {
acc[prop] = rawInput[prop as keyof typeof rawInput];
}
return acc;
},
{} as Record<string, unknown>,
)
: {};
const additionalProps = parseInputToProps(rawInput, meta.trackProps);

await analytics.track({ ...meta.track, ...additionalProps });
}
Expand Down

0 comments on commit a03ea00

Please sign in to comment.