kyd-shared-badge 0.3.14 → 0.3.16

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kyd-shared-badge",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "private": false,
5
5
  "main": "./src/index.ts",
6
6
  "module": "./src/index.ts",
@@ -8,46 +8,51 @@ import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
8
8
  import { GraphInsightsPayload } from '../types';
9
9
 
10
10
  const region = process.env.AWS_REGION!;
11
- const usersTableName = process.env.USER_TABLE_NAME || `UserTable${(process.env.NEXT_PUBLIC_STAGE || process.env.STAGE || 'dev').replace(/^./, c => c.toUpperCase())}`;
11
+ const usersTableName = process.env.USER_TABLE_NAME
12
12
  const doc = DynamoDBDocumentClient.from(new DynamoDBClient({ region }));
13
13
  const s3 = new S3Client({ region });
14
14
  const providerDataBucket = process.env.PROVIDER_DATA_BUCKET_NAME!;
15
15
  const badgeTableName = process.env.BADGE_TABLE_NAME!;
16
16
 
17
17
  export async function aggregateUserData(userId: string, enterpriseMode?: boolean, companyId?: string | null): Promise<any> {
18
- // Minimal: load user record. Optionally, in enterprise mode, you could also fetch link overlay.
19
- const userResp = await doc.send(new GetCommand({ TableName: usersTableName, Key: { userId } }));
18
+ let userResp;
19
+ if (enterpriseMode) {
20
+ const linkTableName = process.env.USER_COMPANY_LINK_TABLE_NAME
21
+ userResp = await doc.send(new GetCommand({ TableName: linkTableName, Key: { userId, companyId } }));
22
+ } else {
23
+ userResp = await doc.send(new GetCommand({ TableName: usersTableName, Key: { userId } }));
24
+ }
20
25
  const user = userResp.Item || {};
21
- const merged = { ...user }
26
+
22
27
  if (enterpriseMode && companyId) {
23
28
  // Optionally merge enterprise overlay later; keeping simple for MVP.
24
- merged.companyId = companyId;
29
+ user.companyId = companyId;
25
30
  }
26
31
 
27
32
  // For each provider_* entry, fetch filtered_data_key JSON from S3 and attach under <provider>_analysis
28
- const providerKeys = Object.keys(merged).filter(k => k.startsWith('provider_'));
33
+ const providerKeys = Object.keys(user).filter(k => k.startsWith('provider_'));
29
34
  const fetches = providerKeys.map(async (key) => {
30
35
  try {
31
- const providerData = merged[key];
36
+ const providerData = user[key];
32
37
  if (!providerData || typeof providerData !== 'object') return;
33
38
  const filteredKey = providerData['filtered_data_key'];
34
39
  if (!filteredKey || typeof filteredKey !== 'string') return;
35
40
  const obj = await getJsonFromS3(providerDataBucket, filteredKey);
36
41
  const providerName = key.replace(/^provider_/, '');
37
42
  const analysisKey = `${providerName}_analysis`;
38
- merged[analysisKey] = obj;
43
+ user[analysisKey] = obj;
39
44
  } catch (e) {
40
45
  console.error('Failed to load provider filtered data', e);
41
46
  // Non-fatal; annotate error
42
47
  try {
43
48
  const providerName = key.replace(/^provider_/, '');
44
- merged[`${providerName}_analysis`] = { error: 'Failed to load provider filtered data' };
49
+ user[`${providerName}_analysis`] = { error: 'Failed to load provider filtered data' };
45
50
  } catch {}
46
51
  }
47
52
  });
48
53
  await Promise.all(fetches);
49
54
 
50
- return merged;
55
+ return user;
51
56
  }
52
57
 
53
58
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -150,4 +155,9 @@ async function getJsonFromS3(bucket: string, key: string): Promise<any> {
150
155
  export async function getReportGraphData(badgeId: string): Promise<GraphInsightsPayload | undefined> {
151
156
  const badge = await doc.send(new GetCommand({ TableName: badgeTableName, Key: { badgeId } }));
152
157
  return badge.Item?.assessmentResult?.graph_insights as GraphInsightsPayload | undefined;
158
+ }
159
+
160
+ export async function getBadgeUserId(badgeId: string): Promise<string> {
161
+ const badge = await doc.send(new GetCommand({ TableName: badgeTableName, Key: { badgeId } }));
162
+ return badge.Item?.userId as string;
153
163
  }
package/src/lib/routes.ts CHANGED
@@ -6,7 +6,13 @@ import { streamText } from 'ai';
6
6
  import { bedrock } from '@ai-sdk/amazon-bedrock';
7
7
 
8
8
  import { getHistory, putMessage } from './chat-store';
9
- import { aggregateUserData, cleanDeveloperProfile, buildAllContextPrompt, getReportGraphData } from './context';
9
+ import {
10
+ aggregateUserData,
11
+ cleanDeveloperProfile,
12
+ buildAllContextPrompt,
13
+ getReportGraphData,
14
+ getBadgeUserId
15
+ } from './context';
10
16
  import { checkAndConsumeToken } from './rate-limit';
11
17
 
12
18
  import { createSession } from './chat-store';
@@ -29,7 +35,8 @@ export async function chatStreamRoute(req: NextRequest, userId: string, companyI
29
35
 
30
36
  await putMessage({ sessionId, role: 'user', content });
31
37
 
32
- const aggregated = await aggregateUserData(userId, !!companyId, companyId);
38
+ const badgeUserId = await getBadgeUserId(badgeId);
39
+ const aggregated = await aggregateUserData(badgeUserId, !!companyId, companyId);
33
40
  const cleaned = cleanDeveloperProfile(aggregated);
34
41
  const graphData = await getReportGraphData(badgeId);
35
42
  const system = buildAllContextPrompt(cleaned, graphData, { concise: true });