History

Parse WorkOS membership events with typed helpers

Rhys Sullivan committed 8 months ago

Commit 77bb45a1 parent 28def291 file · +38 −6Browse files

Unified · Split

executor/packages/database/src/auth/event_handlers.ts+38−6
@@ -16,6 +16,7 @@ import { · 15 unmodified lines
16} from "./memberships";16} from "./memberships";
17import { ensureUniqueOrganizationSlug } from "./naming";17import { ensureUniqueOrganizationSlug } from "./naming";
18import { seedWorkspaceMembersFromOrganization } from "./workspace_membership_projection";18import { seedWorkspaceMembersFromOrganization } from "./workspace_membership_projection";
19import { asPayload } from "../lib/object";
19 20
20type WorkosMembershipEventData = {21type WorkosMembershipEventData = {
21 id: string;22 id: string;
@@ -27,6 +28,30 @@ type WorkosMembershipEventData = { · 5 unmodified lines
27 status?: string;28 status?: string;
28};29};
29 30
31type ResolvedMembershipTarget = {
32 account: Doc<"accounts"> | null;
33 organization: Doc<"organizations"> | null;
34 fallbackRole?: Doc<"workspaceMembers">["role"];
35};
36
37function parseMembershipEventData(value: unknown): WorkosMembershipEventData | null {
38 const record = asPayload(value);
39 if (typeof record.id !== "string" || record.id.trim().length === 0) {
40 return null;
41 }
42
43 const role = asPayload(record.role);
44 return {
45 id: record.id,
46 user_id: typeof record.user_id === "string" ? record.user_id : undefined,
47 userId: typeof record.userId === "string" ? record.userId : undefined,
48 organization_id: typeof record.organization_id === "string" ? record.organization_id : undefined,
49 organizationId: typeof record.organizationId === "string" ? record.organizationId : undefined,
50 role: typeof role.slug === "string" ? { slug: role.slug } : undefined,
51 status: typeof record.status === "string" ? record.status : undefined,
52 };
53}
54
30function deriveOrganizationRoleFromWorkosSlug(workosRoleSlug?: string): Doc<"organizationMembers">["role"] {55function deriveOrganizationRoleFromWorkosSlug(workosRoleSlug?: string): Doc<"organizationMembers">["role"] {
31 return workosRoleSlug === "admin" ? "admin" : "member";56 return workosRoleSlug === "admin" ? "admin" : "member";
32}57}
@@ -34,7 +59,7 @@ function deriveOrganizationRoleFromWorkosSlug(workosRoleSlug?: string): Doc<"org · 1 unmodified line
34async function resolveMembershipAccountAndOrganization(59async function resolveMembershipAccountAndOrganization(
35 ctx: Pick<MutationCtx, "db">,60 ctx: Pick<MutationCtx, "db">,
36 data: WorkosMembershipEventData,61 data: WorkosMembershipEventData,
37) {62): Promise<ResolvedMembershipTarget> {
38 const workosUserId = data.user_id ?? data.userId;63 const workosUserId = data.user_id ?? data.userId;
39 const workosOrgId = data.organization_id ?? data.organizationId;64 const workosOrgId = data.organization_id ?? data.organizationId;
40 65
@@ -48,7 +73,6 @@ async function resolveMembershipAccountAndOrganization( · 7 unmodified lines
48 return {73 return {
49 account,74 account,
50 organization,75 organization,
51 fallbackRole: undefined as Doc<"workspaceMembers">["role"] | undefined,
52 };76 };
53 }77 }
54 }78 }
@@ -61,7 +85,6 @@ async function resolveMembershipAccountAndOrganization( · 6 unmodified lines
61 return {85 return {
62 account: null,86 account: null,
63 organization: null,87 organization: null,
64 fallbackRole: undefined as Doc<"workspaceMembers">["role"] | undefined,
65 };88 };
66 }89 }
67 90
@@ -251,7 +274,10 @@ export const workosEventHandlers = { · 183 unmodified lines
251 274
252 "organization_membership.created": async (ctx, event) => {275 "organization_membership.created": async (ctx, event) => {
253 const now = Date.now();276 const now = Date.now();
254 const data = event.data as WorkosMembershipEventData;277 const data = parseMembershipEventData(event.data);
278 if (!data) {
279 return;
280 }
255 const { account, organization } = await resolveMembershipAccountAndOrganization(ctx, data);281 const { account, organization } = await resolveMembershipAccountAndOrganization(ctx, data);
256 if (!account || !organization) return;282 if (!account || !organization) return;
257 283
@@ -279,7 +305,10 @@ export const workosEventHandlers = { · 21 unmodified lines
279 305
280 "organization_membership.updated": async (ctx, event) => {306 "organization_membership.updated": async (ctx, event) => {
281 const now = Date.now();307 const now = Date.now();
282 const data = event.data as WorkosMembershipEventData;308 const data = parseMembershipEventData(event.data);
309 if (!data) {
310 return;
311 }
283 const { account, organization } = await resolveMembershipAccountAndOrganization(ctx, data);312 const { account, organization } = await resolveMembershipAccountAndOrganization(ctx, data);
284 313
285 if (!account || !organization) {314 if (!account || !organization) {
@@ -310,7 +339,10 @@ export const workosEventHandlers = { · 24 unmodified lines
310 339
311 "organization_membership.deleted": async (ctx, event) => {340 "organization_membership.deleted": async (ctx, event) => {
312 const now = Date.now();341 const now = Date.now();
313 const data = event.data as WorkosMembershipEventData;342 const data = parseMembershipEventData(event.data);
343 if (!data) {
344 return;
345 }
314 const { account, organization, fallbackRole } = await resolveMembershipAccountAndOrganization(ctx, data);346 const { account, organization, fallbackRole } = await resolveMembershipAccountAndOrganization(ctx, data);
315 if (!account || !organization) {347 if (!account || !organization) {
316 return;348 return;