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