@chatcops/server 0.2.0
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/dist/adapters/cloudflare.d.ts +3 -0
- package/dist/adapters/cloudflare.d.ts.map +1 -0
- package/dist/adapters/cloudflare.js +60 -0
- package/dist/adapters/cloudflare.js.map +1 -0
- package/dist/adapters/express.d.ts +5 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +43 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/vercel.d.ts +3 -0
- package/dist/adapters/vercel.d.ts.map +1 -0
- package/dist/adapters/vercel.js +61 -0
- package/dist/adapters/vercel.js.map +1 -0
- package/dist/analytics/index.d.ts +2 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +2 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/server.d.ts +8 -0
- package/dist/analytics/server.d.ts.map +1 -0
- package/dist/analytics/server.js +14 -0
- package/dist/analytics/server.js.map +1 -0
- package/dist/config.d.ts +62 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -0
- package/dist/examples/cloudflare-worker.d.ts +5 -0
- package/dist/examples/cloudflare-worker.d.ts.map +1 -0
- package/dist/examples/cloudflare-worker.js +20 -0
- package/dist/examples/cloudflare-worker.js.map +1 -0
- package/dist/examples/express-server.d.ts +2 -0
- package/dist/examples/express-server.d.ts.map +1 -0
- package/dist/examples/express-server.js +30 -0
- package/dist/examples/express-server.js.map +1 -0
- package/dist/examples/vercel-api.d.ts +6 -0
- package/dist/examples/vercel-api.d.ts.map +1 -0
- package/dist/examples/vercel-api.js +17 -0
- package/dist/examples/vercel-api.js.map +1 -0
- package/dist/handler.d.ts +7 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +108 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/rate-limit.d.ts +15 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +40 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/webhook.d.ts +10 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +55 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,oBAAoB,IAGtC,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAyDnE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createChatHandler } from '../handler.js';
|
|
2
|
+
export function chatcopsCloudflareHandler(config) {
|
|
3
|
+
const { handleChat } = createChatHandler(config);
|
|
4
|
+
return async function handler(request) {
|
|
5
|
+
// Handle CORS preflight
|
|
6
|
+
if (request.method === 'OPTIONS') {
|
|
7
|
+
return new Response(null, {
|
|
8
|
+
status: 204,
|
|
9
|
+
headers: {
|
|
10
|
+
'Access-Control-Allow-Origin': config.cors,
|
|
11
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
12
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
13
|
+
'Access-Control-Max-Age': '86400',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (request.method !== 'POST') {
|
|
18
|
+
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
|
19
|
+
status: 405,
|
|
20
|
+
headers: { 'Content-Type': 'application/json' },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const clientIp = request.headers.get('cf-connecting-ip') ?? 'unknown';
|
|
24
|
+
let body;
|
|
25
|
+
try {
|
|
26
|
+
body = await request.json();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return new Response(JSON.stringify({ error: 'Invalid JSON body' }), {
|
|
30
|
+
status: 400,
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const { readable, writable } = new TransformStream();
|
|
35
|
+
const writer = writable.getWriter();
|
|
36
|
+
const encoder = new TextEncoder();
|
|
37
|
+
(async () => {
|
|
38
|
+
try {
|
|
39
|
+
for await (const chunk of handleChat(body, clientIp)) {
|
|
40
|
+
await writer.write(encoder.encode(`data: ${chunk}\n\n`));
|
|
41
|
+
}
|
|
42
|
+
await writer.write(encoder.encode('data: [DONE]\n\n'));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
await writer.write(encoder.encode(`data: ${JSON.stringify({ error: 'internal_error' })}\n\n`));
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await writer.close();
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
return new Response(readable, {
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'text/event-stream',
|
|
54
|
+
'Cache-Control': 'no-cache',
|
|
55
|
+
'Access-Control-Allow-Origin': config.cors,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cloudflare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare.js","sourceRoot":"","sources":["../../src/adapters/cloudflare.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,UAAU,yBAAyB,CAAC,MAA4B;IACpE,MAAM,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAEjD,OAAO,KAAK,UAAU,OAAO,CAAC,OAAgB;QAC5C,wBAAwB;QACxB,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE;oBACP,6BAA6B,EAAE,MAAM,CAAC,IAAI;oBAC1C,8BAA8B,EAAE,eAAe;oBAC/C,8BAA8B,EAAE,cAAc;oBAC9C,wBAAwB,EAAE,OAAO;iBAClC;aACF,CAAC,CAAC;QACL,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC9B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,EAAE;gBACnE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,SAAS,CAAC;QACtE,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;gBAClE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAElC,CAAC,KAAK,IAAI,EAAE;YACV,IAAI,CAAC;gBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;oBACrD,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC;gBAC3D,CAAC;gBACD,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACzD,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YACjG,CAAC;oBAAS,CAAC;gBACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QAEL,OAAO,IAAI,QAAQ,CAAC,QAAQ,EAAE;YAC5B,OAAO,EAAE;gBACP,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,6BAA6B,EAAE,MAAM,CAAC,IAAI;aAC3C;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
2
|
+
import type { ChatCopsServerConfig } from '../config.js';
|
|
3
|
+
export declare function chatcopsMiddleware(config: ChatCopsServerConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
4
|
+
export declare function chatcopsAnalyticsHandler(config: ChatCopsServerConfig): (_req: Request, res: Response) => void;
|
|
5
|
+
//# sourceMappingURL=express.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/adapters/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,IAGvB,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,mBAkCtF;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,oBAAoB,IAE3D,MAAM,OAAO,EAAE,KAAK,QAAQ,UAGrC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createChatHandler } from '../handler.js';
|
|
2
|
+
export function chatcopsMiddleware(config) {
|
|
3
|
+
const { handleChat, getAnalytics } = createChatHandler(config);
|
|
4
|
+
return async function chatcopsHandler(req, res, next) {
|
|
5
|
+
// Handle CORS preflight
|
|
6
|
+
if (req.method === 'OPTIONS') {
|
|
7
|
+
res.setHeader('Access-Control-Allow-Origin', config.cors);
|
|
8
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
9
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
10
|
+
res.setHeader('Access-Control-Max-Age', '86400');
|
|
11
|
+
res.status(204).end();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (req.method !== 'POST') {
|
|
15
|
+
res.status(405).json({ error: 'Method not allowed' });
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const clientIp = req.ip ?? req.socket.remoteAddress ?? 'unknown';
|
|
19
|
+
res.setHeader('Content-Type', 'text/event-stream');
|
|
20
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
21
|
+
res.setHeader('Connection', 'keep-alive');
|
|
22
|
+
res.setHeader('Access-Control-Allow-Origin', config.cors);
|
|
23
|
+
try {
|
|
24
|
+
for await (const chunk of handleChat(req.body, clientIp)) {
|
|
25
|
+
res.write(`data: ${chunk}\n\n`);
|
|
26
|
+
}
|
|
27
|
+
res.write('data: [DONE]\n\n');
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
res.write(`data: ${JSON.stringify({ error: 'internal_error' })}\n\n`);
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
res.end();
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function chatcopsAnalyticsHandler(config) {
|
|
38
|
+
const { getAnalytics } = createChatHandler(config);
|
|
39
|
+
return (_req, res) => {
|
|
40
|
+
res.json(getAnalytics());
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/adapters/express.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,UAAU,kBAAkB,CAAC,MAA4B;IAC7D,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAE/D,OAAO,KAAK,UAAU,eAAe,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;QACnF,wBAAwB;QACxB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,eAAe,CAAC,CAAC;YAC/D,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;YAC9D,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;YACjD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,SAAS,CAAC;QAEjE,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC;QACnD,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAC;QAC3C,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAC1C,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;gBACzD,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC;YAClC,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC;QACxE,CAAC;gBAAS,CAAC;YACT,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAA4B;IACnE,MAAM,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACnD,OAAO,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;QACtC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../src/adapters/vercel.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,oBAAoB,IAGlC,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAyD/D"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { createChatHandler } from '../handler.js';
|
|
2
|
+
export function chatcopsVercelHandler(config) {
|
|
3
|
+
const { handleChat } = createChatHandler(config);
|
|
4
|
+
return async function handler(req) {
|
|
5
|
+
// Handle CORS preflight
|
|
6
|
+
if (req.method === 'OPTIONS') {
|
|
7
|
+
return new Response(null, {
|
|
8
|
+
status: 204,
|
|
9
|
+
headers: {
|
|
10
|
+
'Access-Control-Allow-Origin': config.cors,
|
|
11
|
+
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
|
12
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
13
|
+
'Access-Control-Max-Age': '86400',
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (req.method !== 'POST') {
|
|
18
|
+
return new Response(JSON.stringify({ error: 'Method not allowed' }), {
|
|
19
|
+
status: 405,
|
|
20
|
+
headers: { 'Content-Type': 'application/json' },
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const clientIp = req.headers.get('x-forwarded-for')?.split(',')[0]?.trim() ?? 'unknown';
|
|
24
|
+
let body;
|
|
25
|
+
try {
|
|
26
|
+
body = await req.json();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return new Response(JSON.stringify({ error: 'Invalid JSON body' }), {
|
|
30
|
+
status: 400,
|
|
31
|
+
headers: { 'Content-Type': 'application/json' },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const encoder = new TextEncoder();
|
|
35
|
+
const stream = new ReadableStream({
|
|
36
|
+
async start(controller) {
|
|
37
|
+
try {
|
|
38
|
+
for await (const chunk of handleChat(body, clientIp)) {
|
|
39
|
+
controller.enqueue(encoder.encode(`data: ${chunk}\n\n`));
|
|
40
|
+
}
|
|
41
|
+
controller.enqueue(encoder.encode('data: [DONE]\n\n'));
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ error: 'internal_error' })}\n\n`));
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
controller.close();
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
return new Response(stream, {
|
|
52
|
+
headers: {
|
|
53
|
+
'Content-Type': 'text/event-stream',
|
|
54
|
+
'Cache-Control': 'no-cache',
|
|
55
|
+
'Connection': 'keep-alive',
|
|
56
|
+
'Access-Control-Allow-Origin': config.cors,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=vercel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../src/adapters/vercel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,MAAM,UAAU,qBAAqB,CAAC,MAA4B;IAChE,MAAM,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAEjD,OAAO,KAAK,UAAU,OAAO,CAAC,GAAY;QACxC,wBAAwB;QACxB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE;oBACP,6BAA6B,EAAE,MAAM,CAAC,IAAI;oBAC1C,8BAA8B,EAAE,eAAe;oBAC/C,8BAA8B,EAAE,cAAc;oBAC9C,wBAAwB,EAAE,OAAO;iBAClC;aACF,CAAC,CAAC;QACL,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC1B,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,EAAE;gBACnE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;QACxF,IAAI,IAAa,CAAC;QAClB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE;gBAClE,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;YAChC,KAAK,CAAC,KAAK,CAAC,UAAU;gBACpB,IAAI,CAAC;oBACH,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,CAAC;wBACrD,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC;oBAC3D,CAAC;oBACD,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;gBACzD,CAAC;gBAAC,MAAM,CAAC;oBACP,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;gBACjG,CAAC;wBAAS,CAAC;oBACT,UAAU,CAAC,KAAK,EAAE,CAAC;gBACrB,CAAC;YACH,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;YAC1B,OAAO,EAAE;gBACP,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,YAAY,EAAE,YAAY;gBAC1B,6BAA6B,EAAE,MAAM,CAAC,IAAI;aAC3C;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type AnalyticsStats } from '@chatcops/core';
|
|
2
|
+
export declare class ServerAnalytics {
|
|
3
|
+
private collector;
|
|
4
|
+
constructor();
|
|
5
|
+
track(event: string, data?: Record<string, unknown>): void;
|
|
6
|
+
getStats(): AnalyticsStats;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/analytics/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEzE,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAqB;;IAMtC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI1D,QAAQ,IAAI,cAAc;CAG3B"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AnalyticsCollector } from '@chatcops/core';
|
|
2
|
+
export class ServerAnalytics {
|
|
3
|
+
collector;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.collector = new AnalyticsCollector();
|
|
6
|
+
}
|
|
7
|
+
track(event, data) {
|
|
8
|
+
this.collector.track(event, data);
|
|
9
|
+
}
|
|
10
|
+
getStats() {
|
|
11
|
+
return this.collector.getStats();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/analytics/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAuB,MAAM,gBAAgB,CAAC;AAEzE,MAAM,OAAO,eAAe;IAClB,SAAS,CAAqB;IAEtC;QACE,IAAI,CAAC,SAAS,GAAG,IAAI,kBAAkB,EAAE,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAa,EAAE,IAA8B;QACjD,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;IACnC,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { ChatTool, KnowledgeSource, WebhookConfig, ProviderConfig, LocaleStrings } from '@chatcops/core';
|
|
3
|
+
export interface ChatCopsServerConfig {
|
|
4
|
+
provider: ProviderConfig;
|
|
5
|
+
systemPrompt: string;
|
|
6
|
+
tools?: ChatTool[];
|
|
7
|
+
knowledge?: KnowledgeSource[];
|
|
8
|
+
rateLimit?: {
|
|
9
|
+
maxRequests: number;
|
|
10
|
+
windowMs: number;
|
|
11
|
+
};
|
|
12
|
+
webhooks?: WebhookConfig[];
|
|
13
|
+
analytics?: boolean;
|
|
14
|
+
cors: string;
|
|
15
|
+
i18n?: {
|
|
16
|
+
defaultLocale: string;
|
|
17
|
+
locales: Record<string, LocaleStrings>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
export declare const chatRequestSchema: z.ZodObject<{
|
|
21
|
+
conversationId: z.ZodString;
|
|
22
|
+
message: z.ZodString;
|
|
23
|
+
pageContext: z.ZodOptional<z.ZodObject<{
|
|
24
|
+
url: z.ZodString;
|
|
25
|
+
title: z.ZodString;
|
|
26
|
+
description: z.ZodOptional<z.ZodString>;
|
|
27
|
+
contentSnippet: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, "strip", z.ZodTypeAny, {
|
|
29
|
+
url: string;
|
|
30
|
+
title: string;
|
|
31
|
+
description?: string | undefined;
|
|
32
|
+
contentSnippet?: string | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
url: string;
|
|
35
|
+
title: string;
|
|
36
|
+
description?: string | undefined;
|
|
37
|
+
contentSnippet?: string | undefined;
|
|
38
|
+
}>>;
|
|
39
|
+
locale: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
conversationId: string;
|
|
42
|
+
message: string;
|
|
43
|
+
pageContext?: {
|
|
44
|
+
url: string;
|
|
45
|
+
title: string;
|
|
46
|
+
description?: string | undefined;
|
|
47
|
+
contentSnippet?: string | undefined;
|
|
48
|
+
} | undefined;
|
|
49
|
+
locale?: string | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
conversationId: string;
|
|
52
|
+
message: string;
|
|
53
|
+
pageContext?: {
|
|
54
|
+
url: string;
|
|
55
|
+
title: string;
|
|
56
|
+
description?: string | undefined;
|
|
57
|
+
contentSnippet?: string | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
locale?: string | undefined;
|
|
60
|
+
}>;
|
|
61
|
+
export type ValidatedChatRequest = z.infer<typeof chatRequestSchema>;
|
|
62
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE9G,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,eAAe,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACtD,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;KAAE,CAAC;CAC1E;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU5B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const chatRequestSchema = z.object({
|
|
3
|
+
conversationId: z.string().min(1).max(128),
|
|
4
|
+
message: z.string().min(1).max(10000),
|
|
5
|
+
pageContext: z.object({
|
|
6
|
+
url: z.string().url(),
|
|
7
|
+
title: z.string().max(500),
|
|
8
|
+
description: z.string().max(1000).optional(),
|
|
9
|
+
contentSnippet: z.string().max(2000).optional(),
|
|
10
|
+
}).optional(),
|
|
11
|
+
locale: z.string().max(10).optional(),
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAexB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC1C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACrC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;QACrB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC;QAC1B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;QAC5C,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;KAChD,CAAC,CAAC,QAAQ,EAAE;IACb,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-worker.d.ts","sourceRoot":"","sources":["../../src/examples/cloudflare-worker.ts"],"names":[],"mappings":";mBAQuB,OAAO,OAAO,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;;AAD/E,wBAaE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Cloudflare Worker
|
|
3
|
+
*
|
|
4
|
+
* Set env vars: ANTHROPIC_API_KEY
|
|
5
|
+
*/
|
|
6
|
+
import { chatcopsCloudflareHandler } from '@chatcops/server';
|
|
7
|
+
export default {
|
|
8
|
+
async fetch(request, env) {
|
|
9
|
+
const handler = chatcopsCloudflareHandler({
|
|
10
|
+
provider: {
|
|
11
|
+
type: 'claude',
|
|
12
|
+
apiKey: env.ANTHROPIC_API_KEY,
|
|
13
|
+
},
|
|
14
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
15
|
+
cors: '*',
|
|
16
|
+
});
|
|
17
|
+
return handler(request);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=cloudflare-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflare-worker.js","sourceRoot":"","sources":["../../src/examples/cloudflare-worker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,eAAe;IACb,KAAK,CAAC,KAAK,CAAC,OAAgB,EAAE,GAA2B;QACvD,MAAM,OAAO,GAAG,yBAAyB,CAAC;YACxC,QAAQ,EAAE;gBACR,IAAI,EAAE,QAAQ;gBACd,MAAM,EAAE,GAAG,CAAC,iBAAiB;aAC9B;YACD,YAAY,EAAE,8BAA8B;YAC5C,IAAI,EAAE,GAAG;SACV,CAAC,CAAC;QAEH,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-server.d.ts","sourceRoot":"","sources":["../../src/examples/express-server.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Express server with ChatCops
|
|
3
|
+
*
|
|
4
|
+
* Run:
|
|
5
|
+
* npm install express @chatcops/server
|
|
6
|
+
* ANTHROPIC_API_KEY=sk-... npx tsx express-server.ts
|
|
7
|
+
*/
|
|
8
|
+
import express from 'express';
|
|
9
|
+
import { chatcopsMiddleware } from '@chatcops/server';
|
|
10
|
+
const app = express();
|
|
11
|
+
app.use(express.json());
|
|
12
|
+
app.post('/chat', chatcopsMiddleware({
|
|
13
|
+
provider: {
|
|
14
|
+
type: 'claude',
|
|
15
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
16
|
+
model: 'claude-haiku-4-5-20251001',
|
|
17
|
+
},
|
|
18
|
+
systemPrompt: `You are a helpful customer support assistant for Acme Inc.
|
|
19
|
+
Be friendly, concise, and helpful. If a user wants to get in touch,
|
|
20
|
+
ask for their name, email, and project details to capture as a lead.`,
|
|
21
|
+
cors: '*',
|
|
22
|
+
rateLimit: { maxRequests: 30, windowMs: 60_000 },
|
|
23
|
+
analytics: true,
|
|
24
|
+
}));
|
|
25
|
+
const PORT = process.env.PORT ?? 3001;
|
|
26
|
+
app.listen(PORT, () => {
|
|
27
|
+
console.log(`ChatCops server running on http://localhost:${PORT}`);
|
|
28
|
+
console.log(`Test with: curl -X POST http://localhost:${PORT}/chat -H "Content-Type: application/json" -d '{"conversationId":"test","message":"Hello!"}'`);
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=express-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"express-server.js","sourceRoot":"","sources":["../../src/examples/express-server.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;AACtB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACnC,QAAQ,EAAE;QACR,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAkB;QACtC,KAAK,EAAE,2BAA2B;KACnC;IACD,YAAY,EAAE;;qEAEqD;IACnE,IAAI,EAAE,GAAG;IACT,SAAS,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IAChD,SAAS,EAAE,IAAI;CAChB,CAAC,CAAC,CAAC;AAEJ,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;AACtC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,+CAA+C,IAAI,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,4CAA4C,IAAI,6FAA6F,CAAC,CAAC;AAC7J,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-api.d.ts","sourceRoot":"","sources":["../../src/examples/vercel-api.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM;;CAAsB,CAAC;;AAE1C,wBAOG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example: Vercel API Route
|
|
3
|
+
*
|
|
4
|
+
* Place this file at: api/chat.ts
|
|
5
|
+
* Set env vars: ANTHROPIC_API_KEY
|
|
6
|
+
*/
|
|
7
|
+
import { chatcopsVercelHandler } from '@chatcops/server';
|
|
8
|
+
export const config = { runtime: 'edge' };
|
|
9
|
+
export default chatcopsVercelHandler({
|
|
10
|
+
provider: {
|
|
11
|
+
type: 'claude',
|
|
12
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
13
|
+
},
|
|
14
|
+
systemPrompt: 'You are a helpful assistant.',
|
|
15
|
+
cors: '*',
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=vercel-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel-api.js","sourceRoot":"","sources":["../../src/examples/vercel-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,MAAM,CAAC,MAAM,MAAM,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAE1C,eAAe,qBAAqB,CAAC;IACnC,QAAQ,EAAE;QACR,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAkB;KACvC;IACD,YAAY,EAAE,8BAA8B;IAC5C,IAAI,EAAE,GAAG;CACV,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChatCopsServerConfig } from './config.js';
|
|
2
|
+
export declare function createChatHandler(config: ChatCopsServerConfig): {
|
|
3
|
+
handleChat: (body: unknown, clientIp?: string) => AsyncGenerator<string>;
|
|
4
|
+
getAnalytics: () => import("@chatcops/core").AnalyticsStats | null;
|
|
5
|
+
cleanup: () => void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAwB,MAAM,aAAa,CAAC;AAK9E,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,oBAAoB;uBAYpD,OAAO,aACF,MAAM,KAChB,cAAc,CAAC,MAAM,CAAC;;;EA6G1B"}
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { createProvider, ConversationManager, AnalyticsCollector, toolToDefinition, } from '@chatcops/core';
|
|
2
|
+
import { chatRequestSchema } from './config.js';
|
|
3
|
+
import { RateLimiter } from './rate-limit.js';
|
|
4
|
+
import { WebhookDispatcher } from './webhook.js';
|
|
5
|
+
export function createChatHandler(config) {
|
|
6
|
+
const providerPromise = createProvider(config.provider);
|
|
7
|
+
const conversations = new ConversationManager();
|
|
8
|
+
const rateLimiter = config.rateLimit ? new RateLimiter(config.rateLimit) : new RateLimiter();
|
|
9
|
+
const analytics = config.analytics ? new AnalyticsCollector() : null;
|
|
10
|
+
const webhooks = config.webhooks?.length ? new WebhookDispatcher(config.webhooks) : null;
|
|
11
|
+
const toolDefs = config.tools?.map(toolToDefinition) ?? [];
|
|
12
|
+
// Periodic cleanup
|
|
13
|
+
const cleanupInterval = setInterval(() => rateLimiter.cleanup(), 60_000);
|
|
14
|
+
async function* handleChat(body, clientIp) {
|
|
15
|
+
const provider = await providerPromise;
|
|
16
|
+
// Validate request
|
|
17
|
+
const parsed = chatRequestSchema.safeParse(body);
|
|
18
|
+
if (!parsed.success) {
|
|
19
|
+
yield JSON.stringify({ error: 'Invalid request', details: parsed.error.flatten() });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const req = parsed.data;
|
|
23
|
+
// Rate limit
|
|
24
|
+
if (clientIp) {
|
|
25
|
+
const limit = rateLimiter.check(clientIp);
|
|
26
|
+
if (!limit.allowed) {
|
|
27
|
+
yield JSON.stringify({ error: 'rate_limit', retryAfter: limit.retryAfter });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Get or create conversation
|
|
32
|
+
const conversation = await conversations.getOrCreate(req.conversationId);
|
|
33
|
+
// Track analytics
|
|
34
|
+
if (analytics && conversation.messages.length === 0) {
|
|
35
|
+
analytics.track('conversation:started', { conversationId: req.conversationId });
|
|
36
|
+
}
|
|
37
|
+
analytics?.track('message:sent', { conversationId: req.conversationId });
|
|
38
|
+
// Add user message
|
|
39
|
+
const userMessage = {
|
|
40
|
+
id: crypto.randomUUID(),
|
|
41
|
+
role: 'user',
|
|
42
|
+
content: req.message,
|
|
43
|
+
timestamp: Date.now(),
|
|
44
|
+
};
|
|
45
|
+
await conversations.addMessage(req.conversationId, userMessage);
|
|
46
|
+
// Build system prompt
|
|
47
|
+
let systemPrompt = config.systemPrompt;
|
|
48
|
+
// Add knowledge context
|
|
49
|
+
if (config.knowledge?.length) {
|
|
50
|
+
const contexts = await Promise.all(config.knowledge.map((k) => k.getContext(req.message)));
|
|
51
|
+
const combined = contexts.filter(Boolean).join('\n\n');
|
|
52
|
+
if (combined) {
|
|
53
|
+
systemPrompt += '\n\n' + combined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Add page context
|
|
57
|
+
if (req.pageContext) {
|
|
58
|
+
systemPrompt += `\n\nThe user is currently on: ${req.pageContext.url} (${req.pageContext.title})`;
|
|
59
|
+
if (req.pageContext.description) {
|
|
60
|
+
systemPrompt += `\nPage description: ${req.pageContext.description}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Add locale info
|
|
64
|
+
if (req.locale) {
|
|
65
|
+
systemPrompt += `\n\nRespond in the user's language. Current locale: ${req.locale}`;
|
|
66
|
+
}
|
|
67
|
+
// Get conversation messages for context
|
|
68
|
+
const messages = await conversations.getMessages(req.conversationId);
|
|
69
|
+
// Stream response
|
|
70
|
+
let fullResponse = '';
|
|
71
|
+
try {
|
|
72
|
+
for await (const chunk of provider.chat({
|
|
73
|
+
messages,
|
|
74
|
+
systemPrompt,
|
|
75
|
+
tools: toolDefs.length > 0 ? toolDefs : undefined,
|
|
76
|
+
})) {
|
|
77
|
+
fullResponse += chunk;
|
|
78
|
+
yield JSON.stringify({ content: chunk });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
console.error('[chatcops] Provider error:', err);
|
|
83
|
+
yield JSON.stringify({ error: 'provider_error' });
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// Save assistant message
|
|
87
|
+
if (fullResponse) {
|
|
88
|
+
const assistantMessage = {
|
|
89
|
+
id: crypto.randomUUID(),
|
|
90
|
+
role: 'assistant',
|
|
91
|
+
content: fullResponse,
|
|
92
|
+
timestamp: Date.now(),
|
|
93
|
+
};
|
|
94
|
+
await conversations.addMessage(req.conversationId, assistantMessage);
|
|
95
|
+
analytics?.track('message:received', { conversationId: req.conversationId });
|
|
96
|
+
}
|
|
97
|
+
yield JSON.stringify({ done: true });
|
|
98
|
+
}
|
|
99
|
+
function cleanup() {
|
|
100
|
+
clearInterval(cleanupInterval);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
handleChat,
|
|
104
|
+
getAnalytics: () => analytics?.getStats() ?? null,
|
|
105
|
+
cleanup,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { createChatHandler } from './handler.js';
|
|
2
|
+
export type { ChatCopsServerConfig, ValidatedChatRequest } from './config.js';
|
|
3
|
+
export { chatRequestSchema } from './config.js';
|
|
4
|
+
export { RateLimiter } from './rate-limit.js';
|
|
5
|
+
export type { RateLimitConfig } from './rate-limit.js';
|
|
6
|
+
export { WebhookDispatcher } from './webhook.js';
|
|
7
|
+
export { chatcopsMiddleware, chatcopsAnalyticsHandler } from './adapters/express.js';
|
|
8
|
+
export { chatcopsVercelHandler } from './adapters/vercel.js';
|
|
9
|
+
export { chatcopsCloudflareHandler } from './adapters/cloudflare.js';
|
|
10
|
+
export { ServerAnalytics } from './analytics/server.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createChatHandler } from './handler.js';
|
|
2
|
+
export { chatRequestSchema } from './config.js';
|
|
3
|
+
export { RateLimiter } from './rate-limit.js';
|
|
4
|
+
export { WebhookDispatcher } from './webhook.js';
|
|
5
|
+
export { chatcopsMiddleware, chatcopsAnalyticsHandler } from './adapters/express.js';
|
|
6
|
+
export { chatcopsVercelHandler } from './adapters/vercel.js';
|
|
7
|
+
export { chatcopsCloudflareHandler } from './adapters/cloudflare.js';
|
|
8
|
+
export { ServerAnalytics } from './analytics/server.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RateLimitConfig {
|
|
2
|
+
maxRequests: number;
|
|
3
|
+
windowMs: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class RateLimiter {
|
|
6
|
+
private store;
|
|
7
|
+
private config;
|
|
8
|
+
constructor(config?: Partial<RateLimitConfig>);
|
|
9
|
+
check(key: string): {
|
|
10
|
+
allowed: boolean;
|
|
11
|
+
retryAfter?: number;
|
|
12
|
+
};
|
|
13
|
+
cleanup(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAOD,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,MAAM,CAAkB;gBAEpB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAU7C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAkB7D,OAAO,IAAI,IAAI;CAQhB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const DEFAULT_CONFIG = {
|
|
2
|
+
maxRequests: 30,
|
|
3
|
+
windowMs: 60_000,
|
|
4
|
+
};
|
|
5
|
+
export class RateLimiter {
|
|
6
|
+
store = new Map();
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
10
|
+
if (this.config.maxRequests <= 0) {
|
|
11
|
+
throw new Error('maxRequests must be greater than 0');
|
|
12
|
+
}
|
|
13
|
+
if (this.config.windowMs <= 0) {
|
|
14
|
+
throw new Error('windowMs must be greater than 0');
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
check(key) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const entry = this.store.get(key);
|
|
20
|
+
if (!entry || now >= entry.resetAt) {
|
|
21
|
+
this.store.set(key, { count: 1, resetAt: now + this.config.windowMs });
|
|
22
|
+
return { allowed: true };
|
|
23
|
+
}
|
|
24
|
+
if (entry.count >= this.config.maxRequests) {
|
|
25
|
+
const retryAfter = Math.ceil((entry.resetAt - now) / 1000);
|
|
26
|
+
return { allowed: false, retryAfter };
|
|
27
|
+
}
|
|
28
|
+
entry.count++;
|
|
29
|
+
return { allowed: true };
|
|
30
|
+
}
|
|
31
|
+
cleanup() {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
for (const [key, entry] of this.store) {
|
|
34
|
+
if (now >= entry.resetAt) {
|
|
35
|
+
this.store.delete(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=rate-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.js","sourceRoot":"","sources":["../src/rate-limit.ts"],"names":[],"mappings":"AAUA,MAAM,cAAc,GAAoB;IACtC,WAAW,EAAE,EAAE;IACf,QAAQ,EAAE,MAAM;CACjB,CAAC;AAEF,MAAM,OAAO,WAAW;IACd,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAC1C,MAAM,CAAkB;IAEhC,YAAY,MAAiC;QAC3C,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;QAC/C,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAW;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,CAAC,KAAK,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;YACvE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3B,CAAC;QAED,IAAI,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YAC3D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QACxC,CAAC;QAED,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACtC,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;gBACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WebhookConfig } from '@chatcops/core';
|
|
2
|
+
export declare class WebhookDispatcher {
|
|
3
|
+
private configs;
|
|
4
|
+
private maxRetries;
|
|
5
|
+
constructor(configs: WebhookConfig[]);
|
|
6
|
+
dispatch(event: string, data: unknown): Promise<void>;
|
|
7
|
+
private send;
|
|
8
|
+
private sign;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AASpD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,UAAU,CAAK;gBAEX,OAAO,EAAE,aAAa,EAAE;IAO9B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAQ7C,IAAI;YAkCJ,IAAI;CAcnB"}
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export class WebhookDispatcher {
|
|
2
|
+
configs;
|
|
3
|
+
maxRetries = 3;
|
|
4
|
+
constructor(configs) {
|
|
5
|
+
for (const config of configs) {
|
|
6
|
+
new URL(config.url); // throws on invalid URL
|
|
7
|
+
}
|
|
8
|
+
this.configs = configs;
|
|
9
|
+
}
|
|
10
|
+
async dispatch(event, data) {
|
|
11
|
+
const matching = this.configs.filter((c) => c.events.includes(event) || c.events.includes('*'));
|
|
12
|
+
await Promise.allSettled(matching.map((config) => this.send(config, event, data)));
|
|
13
|
+
}
|
|
14
|
+
async send(config, event, data) {
|
|
15
|
+
const payload = {
|
|
16
|
+
event,
|
|
17
|
+
data,
|
|
18
|
+
timestamp: Date.now(),
|
|
19
|
+
};
|
|
20
|
+
if (config.secret) {
|
|
21
|
+
payload.signature = await this.sign(JSON.stringify(payload), config.secret);
|
|
22
|
+
}
|
|
23
|
+
for (let attempt = 0; attempt < this.maxRetries; attempt++) {
|
|
24
|
+
try {
|
|
25
|
+
const response = await fetch(config.url, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
...(payload.signature ? { 'X-ChatCops-Signature': payload.signature } : {}),
|
|
30
|
+
},
|
|
31
|
+
body: JSON.stringify(payload),
|
|
32
|
+
});
|
|
33
|
+
if (response.ok)
|
|
34
|
+
return;
|
|
35
|
+
if (response.status >= 400 && response.status < 500)
|
|
36
|
+
return; // Don't retry client errors
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// Retry on network errors
|
|
40
|
+
}
|
|
41
|
+
if (attempt < this.maxRetries - 1) {
|
|
42
|
+
await new Promise((r) => setTimeout(r, Math.pow(2, attempt) * 1000));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async sign(payload, secret) {
|
|
47
|
+
const encoder = new TextEncoder();
|
|
48
|
+
const key = await crypto.subtle.importKey('raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
49
|
+
const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));
|
|
50
|
+
return Array.from(new Uint8Array(signature))
|
|
51
|
+
.map((b) => b.toString(16).padStart(2, '0'))
|
|
52
|
+
.join('');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@chatcops/server",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Server-side handler and adapters for ChatCops",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./express": {
|
|
14
|
+
"types": "./dist/adapters/express.d.ts",
|
|
15
|
+
"import": "./dist/adapters/express.js"
|
|
16
|
+
},
|
|
17
|
+
"./vercel": {
|
|
18
|
+
"types": "./dist/adapters/vercel.d.ts",
|
|
19
|
+
"import": "./dist/adapters/vercel.js"
|
|
20
|
+
},
|
|
21
|
+
"./cloudflare": {
|
|
22
|
+
"types": "./dist/adapters/cloudflare.d.ts",
|
|
23
|
+
"import": "./dist/adapters/cloudflare.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsc",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@chatcops/core": "workspace:*",
|
|
38
|
+
"zod": "^3.24.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"express": "^4.0.0 || ^5.0.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"express": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"typescript": "^5.7.0",
|
|
50
|
+
"vitest": "^3.0.0",
|
|
51
|
+
"@types/express": "^5.0.0"
|
|
52
|
+
},
|
|
53
|
+
"publishConfig": {
|
|
54
|
+
"access": "public"
|
|
55
|
+
},
|
|
56
|
+
"license": "MIT"
|
|
57
|
+
}
|