Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
2.6 kB ยท 84 lines
TypeScript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485import { Events } from "@openstatus/analytics";import { sendOwnershipTransferred } from "@openstatus/emails";import { ListMembersInput, deleteMember, listMembers, transferOwnership,} from "@openstatus/services/member";import { z } from "zod";
import { createAfterResponse } from "../lib/after-response";import { toServiceCtx, toTRPCError } from "../service-adapter";import { createTRPCRouter, protectedProcedure } from "../trpc";import { syncCustomerEmailToNewOwner } from "./stripe/shared";
const afterResponse = createAfterResponse("ownership transfer follow-up");
export const memberRouter = createTRPCRouter({ list: protectedProcedure .input(ListMembersInput.optional()) .query(async ({ ctx, input }) => { try { return await listMembers({ ctx: toServiceCtx(ctx), input }); } catch (err) { toTRPCError(err); } }),
delete: protectedProcedure .meta({ track: Events.RemoveUser }) .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { try { await deleteMember({ ctx: toServiceCtx(ctx), input: { userId: input.id }, }); } catch (err) { toTRPCError(err); } }),
transferOwnership: protectedProcedure .meta({ track: Events.TransferOwnership }) .input(z.object({ id: z.number() })) .mutation(async ({ ctx, input }) => { let result: Awaited<ReturnType<typeof transferOwnership>>; try { result = await transferOwnership({ ctx: toServiceCtx(ctx), input: { userId: input.id }, }); } catch (err) { toTRPCError(err); }
// The transfer is committed; the follow-ups run after the response // and only log on failure. const { newOwnerEmail } = result; const formerOwnerEmail = ctx.user.email || null; const { workspace } = ctx;
afterResponse(() => sendOwnershipTransferred({ idempotencyKey: `ownership:${workspace.id}:${result.toUserId}:${Date.now()}`, workspaceName: workspace.name || workspace.slug, newOwner: newOwnerEmail, formerOwner: formerOwnerEmail || ctx.user.name || "A workspace owner", to: { new: newOwnerEmail, former: formerOwnerEmail }, }), );
const { stripeId } = workspace; if (stripeId && formerOwnerEmail) { afterResponse(() => syncCustomerEmailToNewOwner({ customerId: stripeId, formerOwnerEmail, newOwnerEmail, }), ); } }),});