@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,178 +0,0 @@
1
- /**
2
- * GitHub OAuth Callback Handler
3
- * Receives GET redirect from GitHub, exchanges code for token, redirects to frontend
4
- *
5
- * GET /api/github/oauth/callback (No auth - GitHub redirect)
6
- * Query: ?code=...&state=...
7
- */
8
-
9
- const { wrapHandler, executeQuery } = require('./helpers');
10
- const crypto = require('crypto');
11
- const https = require('https');
12
-
13
- const FRONTEND_URL = process.env.FRONTEND_URL || 'https://app.mindmeld.dev';
14
-
15
- function redirect(url) {
16
- return {
17
- statusCode: 302,
18
- headers: {
19
- 'Location': url,
20
- 'Access-Control-Allow-Origin': '*'
21
- },
22
- body: ''
23
- };
24
- }
25
-
26
- function httpsRequest(options, postData) {
27
- return new Promise((resolve, reject) => {
28
- const req = https.request(options, (res) => {
29
- let data = '';
30
- res.on('data', chunk => data += chunk);
31
- res.on('end', () => {
32
- try {
33
- resolve({ statusCode: res.statusCode, body: JSON.parse(data) });
34
- } catch (e) {
35
- // GitHub token endpoint may return form-encoded
36
- const parsed = {};
37
- data.split('&').forEach(pair => {
38
- const [key, val] = pair.split('=');
39
- if (key) parsed[decodeURIComponent(key)] = decodeURIComponent(val || '');
40
- });
41
- resolve({ statusCode: res.statusCode, body: parsed });
42
- }
43
- });
44
- });
45
- req.on('error', reject);
46
- if (postData) req.write(postData);
47
- req.end();
48
- });
49
- }
50
-
51
- function encryptToken(token, key) {
52
- const iv = crypto.randomBytes(16);
53
- const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key, 'hex'), iv);
54
- let encrypted = cipher.update(token, 'utf8', 'hex');
55
- encrypted += cipher.final('hex');
56
- return iv.toString('hex') + ':' + encrypted;
57
- }
58
-
59
- async function githubOAuthCallback({ queryStringParameters }) {
60
- try {
61
- const code = queryStringParameters.code;
62
- const state = queryStringParameters.state;
63
-
64
- if (!code || !state) {
65
- console.error('Missing code or state in callback');
66
- return redirect(`${FRONTEND_URL}/onboarding?error=missing_params`);
67
- }
68
-
69
- // Look up state token in DB to identify user
70
- const stateResult = await executeQuery(`
71
- SELECT email_address FROM rapport.github_oauth_states
72
- WHERE state_token = $1 AND used = FALSE
73
- AND created_at > NOW() - INTERVAL '15 minutes'
74
- `, [state]);
75
-
76
- if (stateResult.rowCount === 0) {
77
- console.error('Invalid or expired state token');
78
- return redirect(`${FRONTEND_URL}/onboarding?error=invalid_state`);
79
- }
80
-
81
- const email = stateResult.rows[0].email_address;
82
-
83
- // Mark state as used
84
- await executeQuery(`
85
- UPDATE rapport.github_oauth_states SET used = TRUE
86
- WHERE state_token = $1
87
- `, [state]);
88
-
89
- // Exchange code for access token
90
- const tokenPayload = JSON.stringify({
91
- client_id: process.env.GITHUB_OAUTH_CLIENT_ID,
92
- client_secret: process.env.GITHUB_OAUTH_CLIENT_SECRET,
93
- code: code
94
- });
95
-
96
- const tokenResponse = await httpsRequest({
97
- hostname: 'github.com',
98
- path: '/login/oauth/access_token',
99
- method: 'POST',
100
- headers: {
101
- 'Content-Type': 'application/json',
102
- 'Accept': 'application/json',
103
- 'Content-Length': Buffer.byteLength(tokenPayload)
104
- }
105
- }, tokenPayload);
106
-
107
- const accessToken = tokenResponse.body.access_token;
108
- if (!accessToken) {
109
- console.error('GitHub token exchange failed:', tokenResponse.body);
110
- return redirect(`${FRONTEND_URL}/onboarding?error=token_exchange_failed`);
111
- }
112
-
113
- const tokenScope = tokenResponse.body.scope || '';
114
-
115
- // Get GitHub user info
116
- const userResponse = await httpsRequest({
117
- hostname: 'api.github.com',
118
- path: '/user',
119
- method: 'GET',
120
- headers: {
121
- 'Authorization': `Bearer ${accessToken}`,
122
- 'User-Agent': 'MindMeld-App',
123
- 'Accept': 'application/json'
124
- }
125
- });
126
-
127
- if (userResponse.statusCode !== 200) {
128
- console.error('GitHub user fetch failed:', userResponse.statusCode);
129
- return redirect(`${FRONTEND_URL}/onboarding?error=github_user_failed`);
130
- }
131
-
132
- const githubUser = userResponse.body;
133
-
134
- // Encrypt the access token
135
- const encryptionKey = process.env.GITHUB_TOKEN_ENCRYPTION_KEY;
136
- if (!encryptionKey) {
137
- console.error('GITHUB_TOKEN_ENCRYPTION_KEY not configured');
138
- return redirect(`${FRONTEND_URL}/onboarding?error=config_error`);
139
- }
140
- const encryptedToken = encryptToken(accessToken, encryptionKey);
141
-
142
- // Upsert GitHub connection
143
- await executeQuery(`
144
- INSERT INTO rapport.github_connections (
145
- email_address, github_username, github_user_id,
146
- access_token_encrypted, token_scope, connected_at
147
- ) VALUES ($1, $2, $3, $4, $5, NOW())
148
- ON CONFLICT (email_address) DO UPDATE SET
149
- github_username = EXCLUDED.github_username,
150
- github_user_id = EXCLUDED.github_user_id,
151
- access_token_encrypted = EXCLUDED.access_token_encrypted,
152
- token_scope = EXCLUDED.token_scope,
153
- connected_at = NOW(),
154
- revoked = FALSE
155
- `, [email, githubUser.login, githubUser.id, encryptedToken, tokenScope]);
156
-
157
- // Determine redirect: enterprise users go to enterprise onboarding
158
- const tierResult = await executeQuery(`
159
- SELECT c.subscription_tier FROM rapport.users u
160
- JOIN rapport.clients c ON c.client_id = u.client_id
161
- WHERE u.email_address = $1 LIMIT 1
162
- `, [email]);
163
-
164
- const tier = tierResult.rows[0]?.subscription_tier;
165
- if (tier === 'enterprise') {
166
- return redirect(`${FRONTEND_URL}/enterprise/onboarding?step=4&github=connected`);
167
- }
168
-
169
- // Standard users - redirect to onboarding step 2
170
- return redirect(`${FRONTEND_URL}/onboarding?step=2`);
171
-
172
- } catch (error) {
173
- console.error('GitHub OAuth Callback Error:', error);
174
- return redirect(`${FRONTEND_URL}/onboarding?error=server_error`);
175
- }
176
- }
177
-
178
- exports.handler = wrapHandler(githubOAuthCallback);
@@ -1,59 +0,0 @@
1
- /**
2
- * GitHub OAuth Start Handler
3
- * Generates GitHub OAuth authorization URL
4
- *
5
- * GET /api/github/oauth/start (CognitoAuthorizer)
6
- */
7
-
8
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
9
- const crypto = require('crypto');
10
-
11
- async function githubOAuthStart({ requestContext }) {
12
- try {
13
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
14
-
15
- if (!email) {
16
- return createErrorResponse(401, 'Authentication required');
17
- }
18
-
19
- const clientId = process.env.GITHUB_OAUTH_CLIENT_ID;
20
- if (!clientId) {
21
- return createErrorResponse(500, 'GitHub OAuth not configured');
22
- }
23
-
24
- // Generate unique state token and store in DB for CSRF verification
25
- const stateToken = crypto.randomBytes(32).toString('hex');
26
-
27
- // Clean up old unused states for this user, then insert new one
28
- await executeQuery(`
29
- DELETE FROM rapport.github_oauth_states
30
- WHERE email_address = $1 OR created_at < NOW() - INTERVAL '15 minutes'
31
- `, [email]);
32
-
33
- await executeQuery(`
34
- INSERT INTO rapport.github_oauth_states (state_token, email_address)
35
- VALUES ($1, $2)
36
- `, [stateToken, email]);
37
-
38
- const callbackUrl = process.env.GITHUB_OAUTH_CALLBACK_URL || 'https://api.mindmeld.dev/api/github/oauth/callback';
39
-
40
- const params = new URLSearchParams({
41
- client_id: clientId,
42
- redirect_uri: callbackUrl,
43
- scope: 'repo',
44
- state: stateToken
45
- });
46
-
47
- const authorization_url = `https://github.com/login/oauth/authorize?${params.toString()}`;
48
-
49
- return createSuccessResponse(
50
- { authorization_url },
51
- 'OAuth URL generated'
52
- );
53
- } catch (error) {
54
- console.error('GitHub OAuth Start Error:', error);
55
- return createErrorResponse(500, 'Failed to generate OAuth URL');
56
- }
57
- }
58
-
59
- exports.handler = wrapHandler(githubOAuthStart);
@@ -1,76 +0,0 @@
1
- /**
2
- * GitHub Patterns Review Handler
3
- * Processes user's approve/reject decisions on discovered patterns
4
- *
5
- * PUT /api/github/patterns/review (CognitoAuthorizer)
6
- * Body: { project_id, approvals: [{ discovery_id, approved }] }
7
- */
8
-
9
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse, verifyProjectAccess } = require('./helpers');
10
-
11
- async function githubPatternsReview({ body, requestContext }) {
12
- try {
13
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
14
-
15
- if (!email) {
16
- return createErrorResponse(401, 'Authentication required');
17
- }
18
-
19
- const { project_id, approvals } = body;
20
- if (!project_id || !approvals || !Array.isArray(approvals)) {
21
- return createErrorResponse(400, 'project_id and approvals array are required');
22
- }
23
-
24
- // Verify user has access to project (collaborator or company member)
25
- const projectAccess = await verifyProjectAccess(project_id, email);
26
- if (!projectAccess) {
27
- return createErrorResponse(403, 'Access denied to project');
28
- }
29
-
30
- let patterns_created = 0;
31
- let patterns_rejected = 0;
32
-
33
- for (const { discovery_id, approved } of approvals) {
34
- if (!discovery_id) continue;
35
- // Skip frontend-generated placeholder IDs (disc_0, disc_1, etc.)
36
- // These occur when the discover endpoint didn't return DB-generated UUIDs
37
- if (discovery_id.startsWith('disc_')) continue;
38
-
39
- if (approved) {
40
- // Update discovery status to approved
41
- await executeQuery(`
42
- UPDATE rapport.onboarding_discoveries
43
- SET status = 'approved', reviewed_at = NOW()
44
- WHERE discovery_id = $1 AND project_id = $2
45
- `, [discovery_id, project_id]);
46
-
47
- patterns_created++;
48
- } else {
49
- // Reject
50
- await executeQuery(`
51
- UPDATE rapport.onboarding_discoveries
52
- SET status = 'rejected', reviewed_at = NOW()
53
- WHERE discovery_id = $1 AND project_id = $2
54
- `, [discovery_id, project_id]);
55
-
56
- patterns_rejected++;
57
- }
58
- }
59
-
60
- // Mark onboarding as completed
61
- await executeQuery(`
62
- UPDATE rapport.projects SET onboarding_completed = TRUE
63
- WHERE project_id = $1
64
- `, [project_id]);
65
-
66
- return createSuccessResponse(
67
- { patterns_created, patterns_rejected },
68
- 'Patterns reviewed successfully'
69
- );
70
- } catch (error) {
71
- console.error('GitHub Patterns Review Error:', error);
72
- return createErrorResponse(500, 'Failed to process pattern reviews');
73
- }
74
- }
75
-
76
- exports.handler = wrapHandler(githubPatternsReview);
@@ -1,105 +0,0 @@
1
- /**
2
- * GitHub Repos List Handler
3
- * Lists user's GitHub repositories
4
- *
5
- * GET /api/github/repos (CognitoAuthorizer)
6
- */
7
-
8
- const { wrapHandler, executeQuery, createSuccessResponse, createErrorResponse } = require('./helpers');
9
- const crypto = require('crypto');
10
- const https = require('https');
11
-
12
- function httpsGet(options) {
13
- return new Promise((resolve, reject) => {
14
- const req = https.request(options, (res) => {
15
- let data = '';
16
- res.on('data', chunk => data += chunk);
17
- res.on('end', () => {
18
- try {
19
- resolve({ statusCode: res.statusCode, body: JSON.parse(data) });
20
- } catch (e) {
21
- resolve({ statusCode: res.statusCode, body: data });
22
- }
23
- });
24
- });
25
- req.on('error', reject);
26
- req.end();
27
- });
28
- }
29
-
30
- function decryptToken(encryptedData, key) {
31
- const [ivHex, encrypted] = encryptedData.split(':');
32
- const iv = Buffer.from(ivHex, 'hex');
33
- const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key, 'hex'), iv);
34
- let decrypted = decipher.update(encrypted, 'hex', 'utf8');
35
- decrypted += decipher.final('utf8');
36
- return decrypted;
37
- }
38
-
39
- async function githubReposList({ requestContext }) {
40
- try {
41
- const email = requestContext.authorizer?.claims?.email || requestContext.authorizer?.jwt?.claims?.email;
42
-
43
- if (!email) {
44
- return createErrorResponse(401, 'Authentication required');
45
- }
46
-
47
- // Get stored connection
48
- const connResult = await executeQuery(`
49
- SELECT access_token_encrypted FROM rapport.github_connections
50
- WHERE email_address = $1 AND revoked = FALSE
51
- `, [email]);
52
-
53
- if (connResult.rowCount === 0) {
54
- return createErrorResponse(404, 'No GitHub connection found. Please connect GitHub first.');
55
- }
56
-
57
- // Decrypt token
58
- const encryptionKey = process.env.GITHUB_TOKEN_ENCRYPTION_KEY;
59
- const accessToken = decryptToken(connResult.rows[0].access_token_encrypted, encryptionKey);
60
-
61
- // Fetch repos from GitHub
62
- const reposResponse = await httpsGet({
63
- hostname: 'api.github.com',
64
- path: '/user/repos?sort=updated&per_page=30&type=owner',
65
- method: 'GET',
66
- headers: {
67
- 'Authorization': `Bearer ${accessToken}`,
68
- 'User-Agent': 'MindMeld-App',
69
- 'Accept': 'application/json'
70
- }
71
- });
72
-
73
- if (reposResponse.statusCode !== 200) {
74
- console.error('GitHub repos fetch failed:', reposResponse.statusCode);
75
- return createErrorResponse(502, 'Failed to fetch repositories from GitHub');
76
- }
77
-
78
- // Update last_used_at
79
- await executeQuery(`
80
- UPDATE rapport.github_connections SET last_used_at = NOW()
81
- WHERE email_address = $1
82
- `, [email]);
83
-
84
- // Map to minimal repo info
85
- const repos = reposResponse.body.map(repo => ({
86
- name: repo.name,
87
- full_name: repo.full_name,
88
- language: repo.language,
89
- default_branch: repo.default_branch,
90
- private: repo.private,
91
- html_url: repo.html_url,
92
- updated_at: repo.updated_at
93
- }));
94
-
95
- return createSuccessResponse(
96
- { repos },
97
- 'Repositories fetched successfully'
98
- );
99
- } catch (error) {
100
- console.error('GitHub Repos List Error:', error);
101
- return createErrorResponse(500, 'Failed to list repositories');
102
- }
103
- }
104
-
105
- exports.handler = wrapHandler(githubReposList);
@@ -1,55 +0,0 @@
1
- /**
2
- * Health Check Handler
3
- * Returns system health status for monitoring
4
- *
5
- * GET /api/health
6
- * Auth: None (public endpoint for external monitors)
7
- */
8
-
9
- const { executeQuery } = require('./helpers');
10
-
11
- exports.handler = async (event) => {
12
- const headers = {
13
- 'Content-Type': 'application/json',
14
- 'Access-Control-Allow-Origin': '*',
15
- 'Access-Control-Allow-Methods': 'GET,OPTIONS',
16
- 'Access-Control-Allow-Headers': 'Content-Type'
17
- };
18
-
19
- const result = {
20
- status: 'ok',
21
- timestamp: new Date().toISOString(),
22
- version: process.env.STACK_VERSION || '1.0.0',
23
- checks: {}
24
- };
25
-
26
- // Database connectivity
27
- try {
28
- const start = Date.now();
29
- await executeQuery('SELECT 1 AS ok');
30
- result.checks.database = {
31
- status: 'ok',
32
- latency_ms: Date.now() - start
33
- };
34
- } catch (err) {
35
- result.status = 'degraded';
36
- result.checks.database = {
37
- status: 'error',
38
- message: 'Database connection failed'
39
- };
40
- console.error('[Health] Database check failed:', err.message);
41
- }
42
-
43
- // Stripe configuration
44
- result.checks.stripe = {
45
- status: process.env.STRIPE_SECRET_KEY ? 'configured' : 'not_configured'
46
- };
47
-
48
- const statusCode = result.status === 'ok' ? 200 : 503;
49
-
50
- return {
51
- statusCode,
52
- headers,
53
- body: JSON.stringify(result)
54
- };
55
- };
@@ -1,201 +0,0 @@
1
- /**
2
- * Unified Audit Logger
3
- *
4
- * Provides consistent audit logging across all handlers.
5
- * Simplified from EquilateralAgents pattern — no agent chains or impersonation.
6
- *
7
- * Usage:
8
- * const { logModificationEvent, AuditEventType, EntityType } = require('./helpers');
9
- * await logModificationEvent(AuditEventType.DATA_CREATE, EntityType.PROJECT, projectId, {
10
- * requestContext, client_id, after_state: { project_name }
11
- * });
12
- */
13
-
14
- const { executeQuery } = require('./dbOperations');
15
- const crypto = require('crypto');
16
-
17
- const AuditEventType = {
18
- // Authentication
19
- AUTH_LOGIN: 'AUTH_LOGIN',
20
- AUTH_LOGOUT: 'AUTH_LOGOUT',
21
- AUTH_FAILED: 'AUTH_FAILED',
22
-
23
- // Access
24
- ACCESS_VIEW: 'ACCESS_VIEW',
25
- ACCESS_DENIED: 'ACCESS_DENIED',
26
-
27
- // Modification
28
- DATA_CREATE: 'DATA_CREATE',
29
- DATA_UPDATE: 'DATA_UPDATE',
30
- DATA_DELETE: 'DATA_DELETE',
31
- DATA_ARCHIVE: 'DATA_ARCHIVE',
32
-
33
- // Admin
34
- ADMIN_USER_UPDATE: 'ADMIN_USER_UPDATE',
35
- ADMIN_PERMISSION_CHANGE: 'ADMIN_PERMISSION_CHANGE',
36
-
37
- // System
38
- SYSTEM_ERROR: 'SYSTEM_ERROR',
39
- SYSTEM_CONFIG_CHANGE: 'SYSTEM_CONFIG_CHANGE',
40
- };
41
-
42
- const EntityType = {
43
- USER: 'USER',
44
- CLIENT: 'CLIENT',
45
- PROJECT: 'PROJECT',
46
- STANDARD: 'STANDARD',
47
- KNOWLEDGE: 'KNOWLEDGE',
48
- INVARIANT: 'INVARIANT',
49
- SESSION: 'SESSION',
50
- SYSTEM: 'SYSTEM',
51
- };
52
-
53
- /**
54
- * Generate a correlation ID for request tracing
55
- */
56
- function generateCorrelationId() {
57
- const timestamp = Date.now().toString(36);
58
- const random = crypto.randomBytes(4).toString('hex');
59
- return `COR_${timestamp}_${random}`;
60
- }
61
-
62
- /**
63
- * Extract request context from lambdaWrapper's requestContext
64
- */
65
- function extractRequestContext(requestContext) {
66
- return {
67
- request_id: requestContext?.requestId || null,
68
- ip_address: requestContext?.identity?.sourceIp || null,
69
- user_agent: requestContext?.identity?.userAgent || null,
70
- user_email: requestContext?.authorizer?.claims?.email
71
- || requestContext?.authorizer?.jwt?.claims?.email
72
- || null,
73
- };
74
- }
75
-
76
- /**
77
- * Core audit event logger — INSERT into rapport.unified_audit_log
78
- * Non-throwing: logs errors but never breaks business logic.
79
- */
80
- async function logAuditEvent(params) {
81
- const {
82
- event_type,
83
- entity_type,
84
- entity_id = null,
85
- actor_email = null,
86
- actor_type = 'USER',
87
- client_id = null,
88
- company_id = null,
89
- details = {},
90
- before_state = null,
91
- after_state = null,
92
- correlation_id = null,
93
- request_id = null,
94
- ip_address = null,
95
- user_agent = null,
96
- outcome = 'SUCCESS',
97
- error_message = null,
98
- } = params;
99
-
100
- try {
101
- const query = `
102
- INSERT INTO rapport.unified_audit_log (
103
- event_type, entity_type, entity_id,
104
- actor_email, actor_type,
105
- client_id, company_id,
106
- details, before_state, after_state,
107
- correlation_id, request_id,
108
- ip_address, user_agent,
109
- outcome, error_message,
110
- created_at
111
- ) VALUES (
112
- $1, $2, $3, $4, $5, $6, $7,
113
- $8, $9, $10, $11, $12, $13, $14,
114
- $15, $16, NOW()
115
- )
116
- RETURNING audit_id
117
- `;
118
-
119
- const result = await executeQuery(query, [
120
- event_type,
121
- entity_type,
122
- entity_id,
123
- actor_email,
124
- actor_type,
125
- client_id,
126
- company_id,
127
- JSON.stringify(details),
128
- before_state ? JSON.stringify(before_state) : null,
129
- after_state ? JSON.stringify(after_state) : null,
130
- correlation_id || generateCorrelationId(),
131
- request_id,
132
- ip_address,
133
- user_agent,
134
- outcome,
135
- error_message,
136
- ]);
137
-
138
- return result.rows[0]?.audit_id;
139
- } catch (error) {
140
- console.error('[AuditLogger] Failed to log audit event:', error.message);
141
- console.error('[AuditLogger] Event:', JSON.stringify({ event_type, entity_type, entity_id }));
142
- return null;
143
- }
144
- }
145
-
146
- /**
147
- * Log a data modification event (create, update, delete, archive)
148
- */
149
- async function logModificationEvent(event_type, entity_type, entity_id, opts = {}) {
150
- const { requestContext, client_id = null, company_id = null, before_state = null, after_state = null, details = {} } = opts;
151
- const ctx = extractRequestContext(requestContext);
152
-
153
- return logAuditEvent({
154
- event_type,
155
- entity_type,
156
- entity_id,
157
- actor_email: ctx.user_email,
158
- actor_type: 'USER',
159
- client_id,
160
- company_id,
161
- before_state,
162
- after_state,
163
- details,
164
- request_id: ctx.request_id,
165
- ip_address: ctx.ip_address,
166
- user_agent: ctx.user_agent,
167
- outcome: 'SUCCESS',
168
- });
169
- }
170
-
171
- /**
172
- * Log a data access event (read operations)
173
- */
174
- async function logAccessEvent(entity_type, entity_id, opts = {}) {
175
- const { requestContext, client_id = null, details = {} } = opts;
176
- const ctx = extractRequestContext(requestContext);
177
-
178
- return logAuditEvent({
179
- event_type: AuditEventType.ACCESS_VIEW,
180
- entity_type,
181
- entity_id,
182
- actor_email: ctx.user_email,
183
- actor_type: 'USER',
184
- client_id,
185
- details,
186
- request_id: ctx.request_id,
187
- ip_address: ctx.ip_address,
188
- user_agent: ctx.user_agent,
189
- outcome: 'SUCCESS',
190
- });
191
- }
192
-
193
- module.exports = {
194
- AuditEventType,
195
- EntityType,
196
- logAuditEvent,
197
- logModificationEvent,
198
- logAccessEvent,
199
- extractRequestContext,
200
- generateCorrelationId,
201
- };