(config: MemberProfileRoutesConfig)
| 78 | * Returns a router for user profile routes (/api/me/member-profile) |
| 79 | */ |
| 80 | export function createMemberProfileRouter(config: MemberProfileRoutesConfig): Router { |
| 81 | const { workos, memberDb, brandDb, orgDb, invalidateMemberContextCache } = config; |
| 82 | const router = Router(); |
| 83 | |
| 84 | // GET /api/me/member-profile - Get current user's organization's member profile |
| 85 | router.get('/', requireAuth, async (req, res) => { |
| 86 | const startTime = Date.now(); |
| 87 | logger.info({ userId: req.user?.id, org: req.query.org }, 'GET /api/me/member-profile started'); |
| 88 | try { |
| 89 | const user = req.user!; |
| 90 | const requestedOrgId = req.query.org as string | undefined; |
| 91 | |
| 92 | // Dev mode: handle dev organizations without WorkOS |
| 93 | const devUser = isDevModeEnabled() ? Object.values(DEV_USERS).find(du => du.id === user.id) : null; |
| 94 | const devOrgId = devUser ? (requestedOrgId?.startsWith('org_dev_') ? requestedOrgId : (devUser.organizationId || 'org_dev_company_001')) : null; |
| 95 | if (devUser && devOrgId) { |
| 96 | const localOrg = await orgDb.getOrganization(devOrgId); |
| 97 | if (!localOrg) { |
| 98 | return res.status(404).json({ |
| 99 | error: 'Organization not found', |
| 100 | message: 'The requested organization does not exist', |
| 101 | }); |
| 102 | } |
| 103 | const profile = await memberDb.getProfileByOrgId(devOrgId); |
| 104 | if (profile?.primary_brand_domain) { |
| 105 | profile.resolved_brand = await resolveBrand(brandDb, profile.primary_brand_domain); |
| 106 | } |
| 107 | logger.info({ userId: user.id, orgId: devOrgId, hasProfile: !!profile, durationMs: Date.now() - startTime }, 'GET /api/me/member-profile completed (dev mode)'); |
| 108 | return res.json({ |
| 109 | profile: profile || null, |
| 110 | organization_id: devOrgId, |
| 111 | organization_name: localOrg.name, |
| 112 | has_api_access: hasApiAccess(resolveMembershipTier(localOrg)), |
| 113 | }); |
| 114 | } |
| 115 | |
| 116 | // Get user's organization memberships |
| 117 | let memberships = await workos!.userManagement.listOrganizationMemberships({ |
| 118 | userId: user.id, |
| 119 | }); |
| 120 | |
| 121 | // Auto-link any verified-domain orgs the user isn't yet in. |
| 122 | // Helper short-circuits when the user is already a cached member. |
| 123 | const linked = await autoLinkByVerifiedDomain(workos!, user.id, user.email); |
| 124 | if (linked) { |
| 125 | memberships = await workos!.userManagement.listOrganizationMemberships({ |
| 126 | userId: user.id, |
| 127 | }); |
| 128 | } |
| 129 | |
| 130 | if (memberships.data.length === 0) { |
| 131 | logger.info({ userId: user.id, durationMs: Date.now() - startTime }, 'GET /api/me/member-profile: no organization'); |
| 132 | return res.status(404).json({ |
| 133 | error: 'No organization', |
| 134 | message: 'User is not a member of any organization', |
| 135 | }); |
| 136 | } |
| 137 |
no test coverage detected