kyd-shared-badge 0.3.2 → 0.3.4
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 +1 -1
- package/src/ambient-ai.d.ts +1 -0
- package/src/lib/auth-verify.ts +41 -41
- package/src/lib/chat-store.ts +4 -0
- package/src/lib/context.ts +24 -20
- package/src/lib/rate-limit.ts +2 -2
- package/src/lib/routes.ts +18 -19
package/package.json
CHANGED
package/src/ambient-ai.d.ts
CHANGED
package/src/lib/auth-verify.ts
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import { NextRequest } from 'next/server';
|
|
2
|
-
import { getServerSession } from 'next-auth';
|
|
3
|
-
import { authOptions } from '@/lib/auth';
|
|
4
|
-
import { jwtVerify, createRemoteJWKSet } from 'jose';
|
|
1
|
+
// import { NextRequest } from 'next/server';
|
|
2
|
+
// import { getServerSession } from 'next-auth';
|
|
3
|
+
// import { authOptions } from '@/lib/auth';
|
|
4
|
+
// import { jwtVerify, createRemoteJWKSet } from 'jose';
|
|
5
5
|
|
|
6
|
-
export type VerifiedUser = {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
6
|
+
// export type VerifiedUser = {
|
|
7
|
+
// userId: string;
|
|
8
|
+
// companyId?: string | null;
|
|
9
|
+
// idToken: string;
|
|
10
|
+
// };
|
|
11
11
|
|
|
12
|
-
// Verifies Cognito ID Token from the server session or Authorization header.
|
|
13
|
-
// Returns userId (sub) and optional companyId claim if present.
|
|
14
|
-
export async function verifyCognito(req: NextRequest): Promise<VerifiedUser> {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
// // Verifies Cognito ID Token from the server session or Authorization header.
|
|
13
|
+
// // Returns userId (sub) and optional companyId claim if present.
|
|
14
|
+
// export async function verifyCognito(req: NextRequest): Promise<VerifiedUser> {
|
|
15
|
+
// // Try to get id_token from NextAuth session first
|
|
16
|
+
// const session = await getServerSession(authOptions as any);
|
|
17
|
+
// let idToken: string | undefined;
|
|
18
|
+
// if (session.id_token) {
|
|
19
|
+
// idToken = session.id_token as string;
|
|
20
|
+
// }
|
|
21
|
+
// if (!idToken) {
|
|
22
|
+
// const authz = req.headers.get('authorization') || req.headers.get('Authorization');
|
|
23
|
+
// if (authz && authz.toLowerCase().startsWith('bearer ')) {
|
|
24
|
+
// idToken = authz.slice(7).trim();
|
|
25
|
+
// }
|
|
26
|
+
// }
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
// if (!idToken) {
|
|
29
|
+
// throw new Response(JSON.stringify({ error: 'Not authenticated' }), { status: 401 }) as unknown as Error;
|
|
30
|
+
// }
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
// const region = process.env.AWS_REGION!;
|
|
33
|
+
// const userPoolId = process.env.COGNITO_USER_POOL_ID!;
|
|
34
|
+
// const issuer = `https://cognito-idp.${region}.amazonaws.com/${userPoolId}`;
|
|
35
|
+
// const jwks = createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`));
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
37
|
+
// try {
|
|
38
|
+
// const { payload } = await jwtVerify(idToken, jwks, { issuer });
|
|
39
|
+
// const sub = String(payload.sub || '');
|
|
40
|
+
// if (!sub) throw new Error('Invalid token');
|
|
41
|
+
// const companyId = (payload as any)['custom:companyId'] || (payload as any).companyId || null;
|
|
42
|
+
// return { userId: sub, companyId, idToken };
|
|
43
|
+
// } catch (e) {
|
|
44
|
+
// throw new Response(JSON.stringify({ error: 'Invalid token' }), { status: 401 }) as unknown as Error;
|
|
45
|
+
// }
|
|
46
|
+
// }
|
|
47
47
|
|
|
48
48
|
|
package/src/lib/chat-store.ts
CHANGED
|
@@ -28,8 +28,11 @@ export type MessageItem = {
|
|
|
28
28
|
role: Role;
|
|
29
29
|
content: string;
|
|
30
30
|
createdAt: string;
|
|
31
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
32
|
redactions?: any;
|
|
33
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
32
34
|
toolCalls?: any;
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
36
|
evidenceJson?: any;
|
|
34
37
|
};
|
|
35
38
|
|
|
@@ -59,6 +62,7 @@ export async function createSession(params: { userId: string; companyId?: string
|
|
|
59
62
|
return sessionId;
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
66
|
export async function putMessage(params: { sessionId: string; role: Role; content: string; evidenceJson?: any }): Promise<void> {
|
|
63
67
|
const now = new Date().toISOString();
|
|
64
68
|
const item: MessageItem = {
|
package/src/lib/context.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
5
5
|
import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb';
|
|
6
6
|
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
7
|
-
import { mkdir, writeFile } from 'fs/promises';
|
|
7
|
+
// import { mkdir, writeFile } from 'fs/promises';
|
|
8
8
|
import { GraphInsightsPayload } from '../types';
|
|
9
9
|
|
|
10
10
|
const region = process.env.AWS_REGION!;
|
|
@@ -18,7 +18,7 @@ export async function aggregateUserData(userId: string, enterpriseMode?: boolean
|
|
|
18
18
|
// Minimal: load user record. Optionally, in enterprise mode, you could also fetch link overlay.
|
|
19
19
|
const userResp = await doc.send(new GetCommand({ TableName: usersTableName, Key: { userId } }));
|
|
20
20
|
const user = userResp.Item || {};
|
|
21
|
-
const merged = { ...user }
|
|
21
|
+
const merged = { ...user }
|
|
22
22
|
if (enterpriseMode && companyId) {
|
|
23
23
|
// Optionally merge enterprise overlay later; keeping simple for MVP.
|
|
24
24
|
merged.companyId = companyId;
|
|
@@ -50,10 +50,11 @@ export async function aggregateUserData(userId: string, enterpriseMode?: boolean
|
|
|
50
50
|
return merged;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
54
|
export function cleanDeveloperProfile(data: any): any {
|
|
54
55
|
if (Array.isArray(data)) return data.map(cleanDeveloperProfile);
|
|
55
56
|
if (data === null || typeof data !== 'object') return data;
|
|
56
|
-
const cleaned
|
|
57
|
+
const cleaned = {};
|
|
57
58
|
const keysToRemove = new Set([
|
|
58
59
|
'accessToken','refreshToken','access_token','refresh_token','id_token',
|
|
59
60
|
'stripeCustomerId','password','secret',
|
|
@@ -78,11 +79,13 @@ export function cleanDeveloperProfile(data: any): any {
|
|
|
78
79
|
delete v['additional_watchlists'];
|
|
79
80
|
delete v['risk_profile_domains'];
|
|
80
81
|
}
|
|
82
|
+
// @ts-expect-error - ignoring
|
|
81
83
|
cleaned[key] = v;
|
|
82
84
|
}
|
|
83
85
|
return cleaned;
|
|
84
86
|
}
|
|
85
87
|
|
|
88
|
+
// // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
86
89
|
export function buildAllContextPrompt(cleanedData: any, reportGraphData: GraphInsightsPayload | undefined, options?: { concise?: boolean, debugName?: string }): string {
|
|
87
90
|
const instructions = [
|
|
88
91
|
'You are KYD, a trust and risk analyst.',
|
|
@@ -116,29 +119,30 @@ export function buildAllContextPrompt(cleanedData: any, reportGraphData: GraphIn
|
|
|
116
119
|
return out;
|
|
117
120
|
}
|
|
118
121
|
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
119
123
|
async function getJsonFromS3(bucket: string, key: string): Promise<any> {
|
|
120
124
|
const res = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
|
|
121
|
-
const text = await
|
|
125
|
+
const text = await res.Body?.transformToString('utf-8');
|
|
122
126
|
return JSON.parse(text || '{}');
|
|
123
127
|
}
|
|
124
128
|
|
|
125
129
|
|
|
126
|
-
async function maybeWriteDebugContext(cleanedData: any, promptText: string, nameHint?: string): Promise<void> {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
130
|
+
// async function maybeWriteDebugContext(cleanedData: any, promptText: string, nameHint?: string): Promise<void> {
|
|
131
|
+
// try {
|
|
132
|
+
// const dir = './debug';
|
|
133
|
+
// await mkdir(dir, { recursive: true });
|
|
134
|
+
// const sanitize = (s: string) => s.replace(/[^a-zA-Z0-9_\-.]/g, '_').slice(0, 64) || 'context';
|
|
135
|
+
// const base = sanitize(nameHint || 'context');
|
|
136
|
+
// const ts = new Date().toISOString().replace(/[:.]/g, '-');
|
|
137
|
+
// const jsonPath = `${dir}/kyd-${base}-${ts}.json`;
|
|
138
|
+
// const txtPath = `${dir}/kyd-${base}-${ts}.txt`;
|
|
139
|
+
// const jsonPretty = JSON.stringify(cleanedData, null, 2);
|
|
140
|
+
// await writeFile(jsonPath, jsonPretty, 'utf8');
|
|
141
|
+
// await writeFile(txtPath, promptText, 'utf8');
|
|
142
|
+
// } catch (e) {
|
|
143
|
+
// console.error('Context debug write failed', e);
|
|
144
|
+
// }
|
|
145
|
+
// }
|
|
142
146
|
|
|
143
147
|
|
|
144
148
|
export async function getReportGraphData(badgeId: string): Promise<GraphInsightsPayload | undefined> {
|
package/src/lib/rate-limit.ts
CHANGED
|
@@ -9,9 +9,9 @@ const doc = DynamoDBDocumentClient.from(ddb);
|
|
|
9
9
|
|
|
10
10
|
export async function checkAndConsumeToken(userId: string, capacityPerMinute: number = 10): Promise<boolean> {
|
|
11
11
|
const now = Date.now();
|
|
12
|
-
const key = { userId }
|
|
12
|
+
const key = { userId };
|
|
13
13
|
const resp = await doc.send(new GetCommand({ TableName: tableName, Key: key }));
|
|
14
|
-
const item =
|
|
14
|
+
const item = resp.Item || { userId, tokens: capacityPerMinute, refillAt: now };
|
|
15
15
|
let tokens: number = typeof item.tokens === 'number' ? item.tokens : capacityPerMinute;
|
|
16
16
|
let refillAt: number = typeof item.refillAt === 'number' ? item.refillAt : now;
|
|
17
17
|
if (now >= refillAt + 60_000) {
|
package/src/lib/routes.ts
CHANGED
|
@@ -43,33 +43,32 @@ export async function chatStreamRoute(req: NextRequest, userId: string, companyI
|
|
|
43
43
|
messages: [...history, { role: 'user' as const, content }],
|
|
44
44
|
maxTokens: 1024,
|
|
45
45
|
temperature: 0.2,
|
|
46
|
-
onFinish: async ({ text }: { text: string }) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
},
|
|
46
|
+
// onFinish: async ({ text }: { text: string }) => {
|
|
47
|
+
// // Attempt to capture evidence block if present (UI also parses, but cache server-side)
|
|
48
|
+
// const evidence = tryParseEvidenceServer(text);
|
|
49
|
+
// await putMessage({ sessionId, role: 'assistant', content: text, evidenceJson: evidence || undefined });
|
|
50
|
+
// },
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
return result.toTextStreamResponse();
|
|
54
|
-
} catch (e
|
|
55
|
-
if (e instanceof Response) return e;
|
|
54
|
+
} catch (e) {
|
|
56
55
|
console.error('chat error', e);
|
|
57
56
|
return new Response('An error occurred. Please try again.', { status: 500 });
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
function tryParseEvidenceServer(text: string): any | null {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
60
|
+
// function tryParseEvidenceServer(text: string): any | null {
|
|
61
|
+
// try {
|
|
62
|
+
// const start = text.indexOf('```json');
|
|
63
|
+
// const end = text.indexOf('```', start + 7);
|
|
64
|
+
// const raw = start >= 0 && end > start ? text.slice(start + 7, end).trim() : text.trim();
|
|
65
|
+
// const obj = JSON.parse(raw);
|
|
66
|
+
// if (obj && obj.type === 'evidence' && Array.isArray(obj.claims)) return obj;
|
|
67
|
+
// } catch {}
|
|
68
|
+
// return null;
|
|
69
|
+
// }
|
|
71
70
|
|
|
72
|
-
export async function
|
|
71
|
+
export async function createSessionRoute(req: NextRequest, userId: string, companyId?: string) {
|
|
73
72
|
try {
|
|
74
73
|
// const user = await verifyCognito(req);
|
|
75
74
|
const body = await req.json().catch(() => ({}));
|
|
@@ -81,7 +80,7 @@ export async function POST(req: NextRequest, userId: string, companyId?: string)
|
|
|
81
80
|
promptVersion: body?.promptVersion,
|
|
82
81
|
});
|
|
83
82
|
return Response.json({ sessionId });
|
|
84
|
-
} catch (e
|
|
83
|
+
} catch (e) {
|
|
85
84
|
console.error(e);
|
|
86
85
|
if (e instanceof Response) return e;
|
|
87
86
|
return Response.json({ error: 'Failed to create session' }, { status: 500 });
|