@equilateral_ai/mindmeld 3.5.3 → 4.0.1

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 (139) hide show
  1. package/hooks/session-start.js +312 -85
  2. package/package.json +20 -14
  3. package/scripts/init-project.js +9 -23
  4. package/src/client/dbShim.js +16 -0
  5. package/src/core/AuthManager.js +3 -2
  6. package/src/handlers/helpers/dbOperations.js +9 -46
  7. package/src/index.js +2 -217
  8. package/src/utils/piiMask.js +16 -0
  9. package/scripts/harvest.js +0 -601
  10. package/scripts/inject.js +0 -409
  11. package/scripts/mcp-bridge.js +0 -220
  12. package/scripts/repo-analyzer.js +0 -870
  13. package/scripts/standards.js +0 -285
  14. package/src/collaboration/CollaborationPrompt.js +0 -460
  15. package/src/core/AlertEngine.js +0 -813
  16. package/src/core/AlertNotifier.js +0 -363
  17. package/src/core/CorrelationAnalyzer.js +0 -931
  18. package/src/core/CrossReferenceEngine.js +0 -624
  19. package/src/core/CurationEngine.js +0 -688
  20. package/src/core/DeprecationScheduler.js +0 -183
  21. package/src/core/LoadBearingDetector.js +0 -242
  22. package/src/core/NotificationService.js +0 -1032
  23. package/src/core/RapportOrchestrator.js +0 -632
  24. package/src/core/RelevanceDetector.js +0 -694
  25. package/src/core/StandardLifecycle.js +0 -244
  26. package/src/core/StandardsIngestion.js +0 -991
  27. package/src/core/TeamLoadBearingDetector.js +0 -431
  28. package/src/core/parsers/adrParser.js +0 -479
  29. package/src/core/parsers/cursorRulesParser.js +0 -564
  30. package/src/core/parsers/eslintParser.js +0 -439
  31. package/src/database/dbOperations.js +0 -105
  32. package/src/handlers/activity/activityGetMe.js +0 -98
  33. package/src/handlers/activity/activityGetTeam.js +0 -175
  34. package/src/handlers/admin/adminSetup.js +0 -216
  35. package/src/handlers/alerts/alertsAcknowledge.js +0 -92
  36. package/src/handlers/alerts/alertsGet.js +0 -250
  37. package/src/handlers/analytics/activitySummaryGet.js +0 -234
  38. package/src/handlers/analytics/coachingGet.js +0 -361
  39. package/src/handlers/analytics/convergenceGet.js +0 -236
  40. package/src/handlers/analytics/developerScoreGet.js +0 -137
  41. package/src/handlers/collaborators/collaboratorAdd.js +0 -200
  42. package/src/handlers/collaborators/collaboratorInvite.js +0 -219
  43. package/src/handlers/collaborators/collaboratorList.js +0 -82
  44. package/src/handlers/collaborators/collaboratorRemove.js +0 -128
  45. package/src/handlers/collaborators/inviteAccept.js +0 -122
  46. package/src/handlers/company/companyUsersDelete.js +0 -141
  47. package/src/handlers/company/companyUsersGet.js +0 -90
  48. package/src/handlers/company/companyUsersPost.js +0 -267
  49. package/src/handlers/company/companyUsersPut.js +0 -76
  50. package/src/handlers/context/contextGet.js +0 -57
  51. package/src/handlers/context/invariantsGet.js +0 -74
  52. package/src/handlers/context/loopsGet.js +0 -82
  53. package/src/handlers/context/notesCreate.js +0 -74
  54. package/src/handlers/context/purposeGet.js +0 -78
  55. package/src/handlers/correlations/correlationsDeveloperGet.js +0 -227
  56. package/src/handlers/correlations/correlationsGet.js +0 -93
  57. package/src/handlers/correlations/correlationsProjectGet.js +0 -153
  58. package/src/handlers/enterprise/controlTowerGet.js +0 -224
  59. package/src/handlers/enterprise/enterpriseAuditGet.js +0 -108
  60. package/src/handlers/enterprise/enterpriseContributorsGet.js +0 -85
  61. package/src/handlers/enterprise/enterpriseKnowledgeCategoriesGet.js +0 -53
  62. package/src/handlers/enterprise/enterpriseKnowledgeCreate.js +0 -77
  63. package/src/handlers/enterprise/enterpriseKnowledgeDelete.js +0 -71
  64. package/src/handlers/enterprise/enterpriseKnowledgeGet.js +0 -87
  65. package/src/handlers/enterprise/enterpriseKnowledgeUpdate.js +0 -122
  66. package/src/handlers/enterprise/enterpriseOnboardingComplete.js +0 -77
  67. package/src/handlers/enterprise/enterpriseOnboardingInvite.js +0 -138
  68. package/src/handlers/enterprise/enterpriseOnboardingSetup.js +0 -128
  69. package/src/handlers/enterprise/enterpriseOnboardingStatus.js +0 -88
  70. package/src/handlers/github/githubConnectionStatus.js +0 -49
  71. package/src/handlers/github/githubDiscoverPatterns.js +0 -621
  72. package/src/handlers/github/githubOAuthCallback.js +0 -178
  73. package/src/handlers/github/githubOAuthStart.js +0 -59
  74. package/src/handlers/github/githubPatternsReview.js +0 -76
  75. package/src/handlers/github/githubReposList.js +0 -105
  76. package/src/handlers/health/healthGet.js +0 -55
  77. package/src/handlers/helpers/auditLogger.js +0 -201
  78. package/src/handlers/helpers/checkSuperAdmin.js +0 -84
  79. package/src/handlers/helpers/decisionFrames.js +0 -29
  80. package/src/handlers/helpers/errorHandler.js +0 -49
  81. package/src/handlers/helpers/index.js +0 -138
  82. package/src/handlers/helpers/lambdaWrapper.js +0 -60
  83. package/src/handlers/helpers/mindmeldMcpCore.js +0 -1103
  84. package/src/handlers/helpers/predictiveCache.js +0 -51
  85. package/src/handlers/helpers/projectAccess.js +0 -88
  86. package/src/handlers/helpers/responseUtil.js +0 -55
  87. package/src/handlers/helpers/subscriptionTiers.js +0 -1168
  88. package/src/handlers/mcp/mcpHandler.js +0 -569
  89. package/src/handlers/mcp/mindmeldMcpHandler.js +0 -124
  90. package/src/handlers/mcp/mindmeldMcpStreamHandler.js +0 -342
  91. package/src/handlers/notifications/getPreferences.js +0 -84
  92. package/src/handlers/notifications/sendNotification.js +0 -170
  93. package/src/handlers/notifications/updatePreferences.js +0 -316
  94. package/src/handlers/patterns/patternEvaluatePromotionPost.js +0 -173
  95. package/src/handlers/patterns/patternUsagePost.js +0 -182
  96. package/src/handlers/patterns/patternViolationPost.js +0 -185
  97. package/src/handlers/projects/projectCreate.js +0 -248
  98. package/src/handlers/projects/projectDelete.js +0 -82
  99. package/src/handlers/projects/projectGet.js +0 -95
  100. package/src/handlers/projects/projectUpdate.js +0 -117
  101. package/src/handlers/reports/aiLeverage.js +0 -210
  102. package/src/handlers/reports/engineeringInvestment.js +0 -132
  103. package/src/handlers/reports/riskForecast.js +0 -206
  104. package/src/handlers/reports/standardsRoi.js +0 -254
  105. package/src/handlers/scheduled/analyzeCorrelations.js +0 -178
  106. package/src/handlers/scheduled/analyzeGitHistory.js +0 -510
  107. package/src/handlers/scheduled/generateAlerts.js +0 -135
  108. package/src/handlers/scheduled/maturityUpdateJob.js +0 -166
  109. package/src/handlers/scheduled/refreshActivity.js +0 -21
  110. package/src/handlers/scheduled/scanCompliance.js +0 -334
  111. package/src/handlers/sessions/sessionEndPost.js +0 -180
  112. package/src/handlers/sessions/sessionStandardsPost.js +0 -171
  113. package/src/handlers/standards/catalogGet.js +0 -185
  114. package/src/handlers/standards/catalogSync.js +0 -120
  115. package/src/handlers/standards/discoveriesGet.js +0 -89
  116. package/src/handlers/standards/projectStandardsGet.js +0 -129
  117. package/src/handlers/standards/projectStandardsPut.js +0 -151
  118. package/src/handlers/standards/standardsAuditGet.js +0 -65
  119. package/src/handlers/standards/standardsParseUpload.js +0 -149
  120. package/src/handlers/standards/standardsRelevantPost.js +0 -405
  121. package/src/handlers/standards/standardsTransition.js +0 -161
  122. package/src/handlers/stripe/addonManagePost.js +0 -240
  123. package/src/handlers/stripe/billingPortalPost.js +0 -93
  124. package/src/handlers/stripe/enterpriseCheckoutPost.js +0 -272
  125. package/src/handlers/stripe/seatsUpdatePost.js +0 -185
  126. package/src/handlers/stripe/subscriptionCancelDelete.js +0 -169
  127. package/src/handlers/stripe/subscriptionCreatePost.js +0 -221
  128. package/src/handlers/stripe/subscriptionUpdatePut.js +0 -163
  129. package/src/handlers/stripe/webhookPost.js +0 -482
  130. package/src/handlers/user/apiTokenCreate.js +0 -71
  131. package/src/handlers/user/apiTokenList.js +0 -64
  132. package/src/handlers/user/userSplashAck.js +0 -91
  133. package/src/handlers/user/userSplashGet.js +0 -211
  134. package/src/handlers/users/cognitoPostConfirmation.js +0 -186
  135. package/src/handlers/users/cognitoPreSignUp.js +0 -114
  136. package/src/handlers/users/userEntitlementsGet.js +0 -89
  137. package/src/handlers/users/userGet.js +0 -118
  138. package/src/handlers/users/userProfilePut.js +0 -77
  139. 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);