@equilateral_ai/mindmeld 3.5.3 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/hooks/session-start.js +312 -85
  2. package/package.json +21 -13
  3. package/scripts/init-project.js +9 -23
  4. package/scripts/repo-analyzer.js +118 -2
  5. package/src/client/dbShim.js +16 -0
  6. package/src/core/AuthManager.js +3 -2
  7. package/src/handlers/helpers/dbOperations.js +9 -46
  8. package/src/index.js +2 -217
  9. package/src/utils/piiMask.js +16 -0
  10. package/scripts/inject.js +0 -409
  11. package/scripts/mcp-bridge.js +0 -220
  12. package/scripts/standards.js +0 -285
  13. package/src/collaboration/CollaborationPrompt.js +0 -460
  14. package/src/core/AlertEngine.js +0 -813
  15. package/src/core/AlertNotifier.js +0 -363
  16. package/src/core/CorrelationAnalyzer.js +0 -931
  17. package/src/core/CrossReferenceEngine.js +0 -624
  18. package/src/core/CurationEngine.js +0 -688
  19. package/src/core/DeprecationScheduler.js +0 -183
  20. package/src/core/LoadBearingDetector.js +0 -242
  21. package/src/core/NotificationService.js +0 -1032
  22. package/src/core/RapportOrchestrator.js +0 -632
  23. package/src/core/RelevanceDetector.js +0 -694
  24. package/src/core/StandardLifecycle.js +0 -244
  25. package/src/core/StandardsIngestion.js +0 -991
  26. package/src/core/TeamLoadBearingDetector.js +0 -431
  27. package/src/core/parsers/adrParser.js +0 -479
  28. package/src/core/parsers/cursorRulesParser.js +0 -564
  29. package/src/core/parsers/eslintParser.js +0 -439
  30. package/src/database/dbOperations.js +0 -105
  31. package/src/handlers/activity/activityGetMe.js +0 -98
  32. package/src/handlers/activity/activityGetTeam.js +0 -175
  33. package/src/handlers/admin/adminSetup.js +0 -216
  34. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  35. package/src/handlers/alerts/alertsGet.js +0 -250
  36. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  37. package/src/handlers/analytics/coachingGet.js +0 -361
  38. package/src/handlers/analytics/convergenceGet.js +0 -236
  39. package/src/handlers/analytics/developerScoreGet.js +0 -137
  40. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  41. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  42. package/src/handlers/collaborators/collaboratorList.js +0 -82
  43. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  44. package/src/handlers/collaborators/inviteAccept.js +0 -122
  45. package/src/handlers/company/companyUsersDelete.js +0 -141
  46. package/src/handlers/company/companyUsersGet.js +0 -90
  47. package/src/handlers/company/companyUsersPost.js +0 -267
  48. package/src/handlers/company/companyUsersPut.js +0 -76
  49. package/src/handlers/context/contextGet.js +0 -57
  50. package/src/handlers/context/invariantsGet.js +0 -74
  51. package/src/handlers/context/loopsGet.js +0 -82
  52. package/src/handlers/context/notesCreate.js +0 -74
  53. package/src/handlers/context/purposeGet.js +0 -78
  54. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  55. package/src/handlers/correlations/correlationsGet.js +0 -93
  56. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  57. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  58. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  59. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  60. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  61. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  62. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  63. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  64. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  65. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  66. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  67. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  68. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  69. package/src/handlers/github/githubConnectionStatus.js +0 -49
  70. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  71. package/src/handlers/github/githubOAuthCallback.js +0 -178
  72. package/src/handlers/github/githubOAuthStart.js +0 -59
  73. package/src/handlers/github/githubPatternsReview.js +0 -76
  74. package/src/handlers/github/githubReposList.js +0 -105
  75. package/src/handlers/health/healthGet.js +0 -55
  76. package/src/handlers/helpers/auditLogger.js +0 -201
  77. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  78. package/src/handlers/helpers/decisionFrames.js +0 -29
  79. package/src/handlers/helpers/errorHandler.js +0 -49
  80. package/src/handlers/helpers/index.js +0 -138
  81. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  82. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  83. package/src/handlers/helpers/predictiveCache.js +0 -51
  84. package/src/handlers/helpers/projectAccess.js +0 -88
  85. package/src/handlers/helpers/responseUtil.js +0 -55
  86. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  87. package/src/handlers/mcp/mcpHandler.js +0 -569
  88. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  89. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  90. package/src/handlers/notifications/getPreferences.js +0 -84
  91. package/src/handlers/notifications/sendNotification.js +0 -170
  92. package/src/handlers/notifications/updatePreferences.js +0 -316
  93. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  94. package/src/handlers/patterns/patternUsagePost.js +0 -182
  95. package/src/handlers/patterns/patternViolationPost.js +0 -185
  96. package/src/handlers/projects/projectCreate.js +0 -248
  97. package/src/handlers/projects/projectDelete.js +0 -82
  98. package/src/handlers/projects/projectGet.js +0 -95
  99. package/src/handlers/projects/projectUpdate.js +0 -117
  100. package/src/handlers/reports/aiLeverage.js +0 -210
  101. package/src/handlers/reports/engineeringInvestment.js +0 -132
  102. package/src/handlers/reports/riskForecast.js +0 -206
  103. package/src/handlers/reports/standardsRoi.js +0 -254
  104. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  105. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  106. package/src/handlers/scheduled/generateAlerts.js +0 -135
  107. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  108. package/src/handlers/scheduled/refreshActivity.js +0 -21
  109. package/src/handlers/scheduled/scanCompliance.js +0 -334
  110. package/src/handlers/sessions/sessionEndPost.js +0 -180
  111. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  112. package/src/handlers/standards/catalogGet.js +0 -185
  113. package/src/handlers/standards/catalogSync.js +0 -120
  114. package/src/handlers/standards/discoveriesGet.js +0 -89
  115. package/src/handlers/standards/projectStandardsGet.js +0 -129
  116. package/src/handlers/standards/projectStandardsPut.js +0 -151
  117. package/src/handlers/standards/standardsAuditGet.js +0 -65
  118. package/src/handlers/standards/standardsParseUpload.js +0 -149
  119. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  120. package/src/handlers/standards/standardsTransition.js +0 -161
  121. package/src/handlers/stripe/addonManagePost.js +0 -240
  122. package/src/handlers/stripe/billingPortalPost.js +0 -93
  123. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  124. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  125. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  126. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  127. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  128. package/src/handlers/stripe/webhookPost.js +0 -482
  129. package/src/handlers/user/apiTokenCreate.js +0 -71
  130. package/src/handlers/user/apiTokenList.js +0 -64
  131. package/src/handlers/user/userSplashAck.js +0 -91
  132. package/src/handlers/user/userSplashGet.js +0 -211
  133. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  134. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  135. package/src/handlers/users/userEntitlementsGet.js +0 -89
  136. package/src/handlers/users/userGet.js +0 -118
  137. package/src/handlers/users/userProfilePut.js +0 -77
  138. package/src/handlers/webhooks/githubWebhook.js +0 -215
@@ -1,128 +0,0 @@
1
- /**
2
- * Collaborator Remove Handler
3
- * Removes a collaborator from a project
4
- *
5
- * DELETE /api/collaborators?project_id=xxx&email=xxx
6
- * Auth: Cognito JWT required
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
10
-
11
- /**
12
- * Remove collaborator from project
13
- * Requires owner or admin role on project
14
- * Owners cannot be removed (must transfer ownership first)
15
- */
16
- async function removeCollaborator({ queryStringParameters: queryParams = {}, requestContext }) {
17
- try {
18
- const Request_ID = requestContext.requestId;
19
- const removerEmail = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
20
- const projectId = queryParams.project_id;
21
- const collaboratorEmail = queryParams.email;
22
-
23
- if (!removerEmail) {
24
- return createErrorResponse(401, 'Authentication required');
25
- }
26
-
27
- if (!projectId) {
28
- return createErrorResponse(400, 'projectId is required');
29
- }
30
-
31
- if (!collaboratorEmail) {
32
- return createErrorResponse(400, 'email is required');
33
- }
34
-
35
- // Decode email from URL (may be URL encoded)
36
- const targetEmail = decodeURIComponent(collaboratorEmail);
37
-
38
- // Check remover has permission and get billing info
39
- const accessQuery = `
40
- SELECT
41
- pc.role,
42
- c.client_id,
43
- c.billing_type
44
- FROM rapport.project_collaborators pc
45
- JOIN rapport.projects p ON pc.project_id = p.project_id
46
- JOIN rapport.clients c ON p.company_id = c.client_id
47
- WHERE pc.project_id = $1 AND pc.email_address = $2
48
- `;
49
- const accessCheck = await executeQuery(accessQuery, [projectId, removerEmail]);
50
-
51
- if (accessCheck.rowCount === 0) {
52
- return createErrorResponse(403, 'You do not have access to this project');
53
- }
54
-
55
- const { role: removerRole, client_id, billing_type } = accessCheck.rows[0];
56
- const isSelfRemoval = removerEmail.toLowerCase() === targetEmail.toLowerCase();
57
-
58
- // Allow self-removal for anyone except owner
59
- // Only owner/admin can remove others
60
- if (!isSelfRemoval && removerRole !== 'owner' && removerRole !== 'admin') {
61
- return createErrorResponse(403, 'Only project owners and admins can remove collaborators');
62
- }
63
-
64
- // Check target collaborator exists and get their role
65
- const targetQuery = `
66
- SELECT role FROM rapport.project_collaborators
67
- WHERE project_id = $1 AND email_address = $2
68
- `;
69
- const targetCheck = await executeQuery(targetQuery, [projectId, targetEmail]);
70
-
71
- if (targetCheck.rowCount === 0) {
72
- return createErrorResponse(404, 'Collaborator not found on this project');
73
- }
74
-
75
- const targetRole = targetCheck.rows[0].role;
76
-
77
- // Prevent removing owner
78
- if (targetRole === 'owner') {
79
- return createErrorResponse(400, 'Cannot remove project owner. Transfer ownership first.');
80
- }
81
-
82
- // Prevent admin from removing another admin (only owner can)
83
- if (targetRole === 'admin' && removerRole !== 'owner') {
84
- return createErrorResponse(403, 'Only project owner can remove admins');
85
- }
86
-
87
- // Remove collaborator
88
- const deleteQuery = `
89
- DELETE FROM rapport.project_collaborators
90
- WHERE project_id = $1 AND email_address = $2
91
- RETURNING project_id, email_address, role
92
- `;
93
-
94
- const result = await executeQuery(deleteQuery, [projectId, targetEmail]);
95
-
96
- // For enterprise invoice billing, decrement billable_users count
97
- if (billing_type === 'invoice' && client_id) {
98
- await executeQuery(`
99
- UPDATE rapport.clients
100
- SET billable_users = GREATEST(COALESCE(billable_users, 0) - 1, 0),
101
- last_updated = NOW()
102
- WHERE client_id = $1
103
- `, [client_id]);
104
- }
105
-
106
- return createSuccessResponse(
107
- {
108
- Records: [{
109
- ...result.rows[0],
110
- removed_by: removerEmail,
111
- removed_at: new Date().toISOString()
112
- }]
113
- },
114
- isSelfRemoval ? 'You have left the project' : 'Collaborator removed',
115
- {
116
- Total_Records: 1,
117
- Request_ID,
118
- Timestamp: new Date().toISOString()
119
- }
120
- );
121
-
122
- } catch (error) {
123
- console.error('Handler Error:', error);
124
- return handleError(error);
125
- }
126
- }
127
-
128
- exports.handler = wrapHandler(removeCollaborator);
@@ -1,122 +0,0 @@
1
- /**
2
- * Invite Accept Handler
3
- * Accepts a collaboration invitation via token
4
- *
5
- * POST /api/invites/accept
6
- * Body: { token }
7
- * Auth: Cognito JWT required (user must be logged in)
8
- */
9
-
10
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
11
-
12
- /**
13
- * Accept collaboration invitation
14
- * User must be authenticated and email must match invite
15
- */
16
- async function acceptInvite({ body: requestBody = {}, requestContext }) {
17
- try {
18
- const Request_ID = requestContext.requestId;
19
- const userEmail = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
20
- const { token } = requestBody;
21
-
22
- if (!userEmail) {
23
- return createErrorResponse(401, 'Authentication required. Please sign in first.');
24
- }
25
-
26
- if (!token) {
27
- return createErrorResponse(400, 'Invite token is required');
28
- }
29
-
30
- // Find invite by token
31
- const inviteQuery = `
32
- SELECT
33
- pc.project_id,
34
- pc.email_address,
35
- pc.role,
36
- pc.invited_by,
37
- pc.invited_at,
38
- pc.accepted_at,
39
- p.project_name,
40
- p.description,
41
- p.company_id
42
- FROM rapport.project_collaborators pc
43
- JOIN rapport.projects p ON p.project_id = pc.project_id
44
- WHERE pc.invite_token = $1
45
- `;
46
- const inviteCheck = await executeQuery(inviteQuery, [token]);
47
-
48
- if (inviteCheck.rowCount === 0) {
49
- return createErrorResponse(404, 'Invalid or expired invite token');
50
- }
51
-
52
- const invite = inviteCheck.rows[0];
53
-
54
- // Check if already accepted
55
- if (invite.accepted_at) {
56
- return createErrorResponse(400, 'This invitation has already been accepted');
57
- }
58
-
59
- // Verify email matches (case insensitive)
60
- if (invite.email_address.toLowerCase() !== userEmail.toLowerCase()) {
61
- return createErrorResponse(403,
62
- 'This invitation was sent to a different email address. ' +
63
- 'Please sign in with the email the invite was sent to.'
64
- );
65
- }
66
-
67
- // Check if invite is expired (7 days)
68
- const invitedAt = new Date(invite.invited_at);
69
- const now = new Date();
70
- const daysSinceInvite = (now - invitedAt) / (1000 * 60 * 60 * 24);
71
-
72
- if (daysSinceInvite > 7) {
73
- return createErrorResponse(410, 'This invitation has expired. Please ask for a new invite.');
74
- }
75
-
76
- // Accept the invite
77
- const acceptQuery = `
78
- UPDATE rapport.project_collaborators
79
- SET
80
- accepted_at = NOW(),
81
- invite_token = NULL,
82
- is_external = false
83
- WHERE project_id = $1 AND email_address = $2
84
- RETURNING project_id, email_address, role, accepted_at
85
- `;
86
- const acceptResult = await executeQuery(acceptQuery, [invite.project_id, invite.email_address]);
87
-
88
- // Ensure user exists in users table
89
- await executeQuery(`
90
- INSERT INTO rapport.users (email_address, client_id, active, created_at)
91
- VALUES ($1, $2, true, NOW())
92
- ON CONFLICT (email_address) DO UPDATE SET
93
- active = true,
94
- updated_at = NOW()
95
- `, [userEmail, invite.company_id]);
96
-
97
- return createSuccessResponse(
98
- {
99
- Records: [{
100
- project_id: invite.project_id,
101
- project_name: invite.project_name,
102
- description: invite.description,
103
- role: invite.role,
104
- accepted_at: acceptResult.rows[0].accepted_at,
105
- invited_by: invite.invited_by
106
- }]
107
- },
108
- `Welcome to ${invite.project_name}!`,
109
- {
110
- Total_Records: 1,
111
- Request_ID,
112
- Timestamp: new Date().toISOString()
113
- }
114
- );
115
-
116
- } catch (error) {
117
- console.error('Handler Error:', error);
118
- return handleError(error);
119
- }
120
- }
121
-
122
- exports.handler = wrapHandler(acceptInvite);
@@ -1,141 +0,0 @@
1
- /**
2
- * Company Users Remove Handler
3
- * Removes a user's entitlement from a company
4
- * If the user was admin-paid, decrements license count and updates Stripe subscription quantity
5
- *
6
- * DELETE /api/company/users?company_id=xxx&email=xxx
7
- * Auth: Cognito JWT required
8
- */
9
-
10
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
11
- const Stripe = require('stripe');
12
-
13
- const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
14
-
15
- /**
16
- * Remove user from company
17
- * Requires admin access to the company
18
- */
19
- async function removeCompanyUser({ queryStringParameters: queryParams = {}, requestContext }) {
20
- try {
21
- const Request_ID = requestContext.requestId;
22
- const callerEmail = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
23
- const companyId = queryParams.company_id;
24
- const targetEmail = queryParams.email;
25
-
26
- if (!callerEmail) {
27
- return createErrorResponse(401, 'Authentication required');
28
- }
29
-
30
- if (!companyId || !targetEmail) {
31
- return createErrorResponse(400, 'company_id and email query parameters are required');
32
- }
33
-
34
- // Prevent self-removal
35
- if (targetEmail === callerEmail) {
36
- return createErrorResponse(400, 'Cannot remove yourself from the company');
37
- }
38
-
39
- // Verify caller is admin of this company
40
- const adminQuery = `
41
- SELECT admin, client_id FROM rapport.user_entitlements
42
- WHERE email_address = $1 AND company_id = $2
43
- `;
44
- const adminCheck = await executeQuery(adminQuery, [callerEmail, companyId]);
45
-
46
- if (adminCheck.rowCount === 0 || !adminCheck.rows[0].admin) {
47
- return createErrorResponse(403, 'Admin access required to remove users');
48
- }
49
-
50
- const clientId = adminCheck.rows[0].client_id;
51
-
52
- // Check the target user's billing_type before deleting
53
- const targetQuery = `
54
- SELECT billing_type FROM rapport.user_entitlements
55
- WHERE email_address = $1 AND company_id = $2
56
- `;
57
- const targetResult = await executeQuery(targetQuery, [targetEmail, companyId]);
58
-
59
- if (targetResult.rowCount === 0) {
60
- return createErrorResponse(404, `User ${targetEmail} not found in this company`);
61
- }
62
-
63
- const billingType = targetResult.rows[0].billing_type;
64
-
65
- // If admin-paid, decrement license count and update Stripe
66
- let stripeUpdated = false;
67
- if (billingType === 'admin_paid') {
68
- // Get client's Stripe subscription
69
- const clientQuery = `
70
- SELECT stripe_subscription_id, license_count
71
- FROM rapport.clients WHERE client_id = $1
72
- `;
73
- const clientResult = await executeQuery(clientQuery, [clientId]);
74
- const clientRecord = clientResult.rows[0];
75
-
76
- if (clientRecord?.stripe_subscription_id) {
77
- // Decrement license_count (minimum 1 — the admin's own license)
78
- const updateResult = await executeQuery(`
79
- UPDATE rapport.clients
80
- SET license_count = GREATEST(COALESCE(license_count, 1) - 1, 1), last_updated = CURRENT_TIMESTAMP
81
- WHERE client_id = $1
82
- RETURNING license_count
83
- `, [clientId]);
84
- const newLicenseCount = updateResult.rows[0].license_count;
85
-
86
- // Update Stripe subscription quantity
87
- try {
88
- const subscription = await stripe.subscriptions.retrieve(clientRecord.stripe_subscription_id);
89
- const item = subscription.items.data[0];
90
- if (item) {
91
- await stripe.subscriptions.update(clientRecord.stripe_subscription_id, {
92
- items: [{ id: item.id, quantity: newLicenseCount }],
93
- proration_behavior: 'none'
94
- });
95
- stripeUpdated = true;
96
- console.log(`[License] Decreased Stripe quantity to ${newLicenseCount} for ${clientId}`);
97
- }
98
- } catch (stripeError) {
99
- console.error('[License] Stripe update failed on removal:', stripeError.message);
100
- // Revert license_count since Stripe failed
101
- await executeQuery(`
102
- UPDATE rapport.clients
103
- SET license_count = COALESCE(license_count, 0) + 1, last_updated = CURRENT_TIMESTAMP
104
- WHERE client_id = $1
105
- `, [clientId]);
106
- return createErrorResponse(500, 'Failed to update subscription. Please try again or contact support.');
107
- }
108
- }
109
- }
110
-
111
- // Delete the entitlement
112
- const deleteQuery = `
113
- DELETE FROM rapport.user_entitlements
114
- WHERE email_address = $1 AND company_id = $2
115
- RETURNING email_address
116
- `;
117
- const result = await executeQuery(deleteQuery, [targetEmail, companyId]);
118
-
119
- const message = billingType === 'admin_paid'
120
- ? `User ${targetEmail} removed and license released${stripeUpdated ? '' : ' (Stripe update pending)'}`
121
- : `User ${targetEmail} removed from company`;
122
-
123
- return createSuccessResponse(
124
- { Records: result.rows },
125
- message,
126
- {
127
- Total_Records: result.rowCount,
128
- Request_ID,
129
- Timestamp: new Date().toISOString(),
130
- license_released: billingType === 'admin_paid',
131
- stripe_updated: stripeUpdated
132
- }
133
- );
134
-
135
- } catch (error) {
136
- console.error('Handler Error:', error);
137
- return handleError(error);
138
- }
139
- }
140
-
141
- exports.handler = wrapHandler(removeCompanyUser);
@@ -1,90 +0,0 @@
1
- /**
2
- * Company Users List Handler
3
- * Lists all users (entitlements) for a company
4
- *
5
- * GET /api/company/users?company_id=xxx
6
- * Auth: Cognito JWT required
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, handleError } = require('./helpers');
10
-
11
- /**
12
- * List company users
13
- * Requires member access to the company
14
- */
15
- async function listCompanyUsers({ queryStringParameters: queryParams = {}, requestContext }) {
16
- try {
17
- const Request_ID = requestContext.requestId;
18
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
19
- const companyId = queryParams.company_id;
20
-
21
- if (!email) {
22
- return createErrorResponse(401, 'Authentication required');
23
- }
24
-
25
- if (!companyId) {
26
- return createErrorResponse(400, 'company_id query parameter is required');
27
- }
28
-
29
- // Verify caller has access to this company
30
- const accessQuery = `
31
- SELECT admin, member
32
- FROM rapport.user_entitlements
33
- WHERE email_address = $1 AND company_id = $2
34
- `;
35
- const accessCheck = await executeQuery(accessQuery, [email, companyId]);
36
-
37
- if (accessCheck.rowCount === 0) {
38
- return createErrorResponse(403, 'You do not have access to this company');
39
- }
40
-
41
- // Get all users for the company
42
- const query = `
43
- SELECT
44
- ue.email_address,
45
- ue.admin,
46
- ue.member,
47
- ue.client_id,
48
- ue.company_id,
49
- ue.billing_type,
50
- u.first_name,
51
- u.last_name,
52
- u.user_status,
53
- u.create_date,
54
- u.last_updated
55
- FROM rapport.user_entitlements ue
56
- LEFT JOIN rapport.users u ON u.email_address = ue.email_address
57
- WHERE ue.company_id = $1
58
- ORDER BY ue.admin DESC, u.create_date ASC
59
- `;
60
- const result = await executeQuery(query, [companyId]);
61
-
62
- const users = result.rows.map(row => ({
63
- email: row.email_address,
64
- display_name: [row.first_name, row.last_name].filter(Boolean).join(' ') || null,
65
- role: row.admin ? 'admin' : 'member',
66
- status: row.user_status || 'active',
67
- billing_type: row.billing_type || 'self_paid',
68
- created_at: row.create_date,
69
- last_active: row.last_updated,
70
- client_id: row.client_id,
71
- company_id: row.company_id,
72
- }));
73
-
74
- return createSuccessResponse(
75
- { Records: users },
76
- `Found ${users.length} user(s)`,
77
- {
78
- Total_Records: users.length,
79
- Request_ID,
80
- Timestamp: new Date().toISOString()
81
- }
82
- );
83
-
84
- } catch (error) {
85
- console.error('Handler Error:', error);
86
- return handleError(error);
87
- }
88
- }
89
-
90
- exports.handler = wrapHandler(listCompanyUsers);