@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,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
- };