@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.
Files changed (57) hide show
  1. package/dist/adapters/cloudflare.d.ts +3 -0
  2. package/dist/adapters/cloudflare.d.ts.map +1 -0
  3. package/dist/adapters/cloudflare.js +60 -0
  4. package/dist/adapters/cloudflare.js.map +1 -0
  5. package/dist/adapters/express.d.ts +5 -0
  6. package/dist/adapters/express.d.ts.map +1 -0
  7. package/dist/adapters/express.js +43 -0
  8. package/dist/adapters/express.js.map +1 -0
  9. package/dist/adapters/index.d.ts +4 -0
  10. package/dist/adapters/index.d.ts.map +1 -0
  11. package/dist/adapters/index.js +4 -0
  12. package/dist/adapters/index.js.map +1 -0
  13. package/dist/adapters/vercel.d.ts +3 -0
  14. package/dist/adapters/vercel.d.ts.map +1 -0
  15. package/dist/adapters/vercel.js +61 -0
  16. package/dist/adapters/vercel.js.map +1 -0
  17. package/dist/analytics/index.d.ts +2 -0
  18. package/dist/analytics/index.d.ts.map +1 -0
  19. package/dist/analytics/index.js +2 -0
  20. package/dist/analytics/index.js.map +1 -0
  21. package/dist/analytics/server.d.ts +8 -0
  22. package/dist/analytics/server.d.ts.map +1 -0
  23. package/dist/analytics/server.js +14 -0
  24. package/dist/analytics/server.js.map +1 -0
  25. package/dist/config.d.ts +62 -0
  26. package/dist/config.d.ts.map +1 -0
  27. package/dist/config.js +13 -0
  28. package/dist/config.js.map +1 -0
  29. package/dist/examples/cloudflare-worker.d.ts +5 -0
  30. package/dist/examples/cloudflare-worker.d.ts.map +1 -0
  31. package/dist/examples/cloudflare-worker.js +20 -0
  32. package/dist/examples/cloudflare-worker.js.map +1 -0
  33. package/dist/examples/express-server.d.ts +2 -0
  34. package/dist/examples/express-server.d.ts.map +1 -0
  35. package/dist/examples/express-server.js +30 -0
  36. package/dist/examples/express-server.js.map +1 -0
  37. package/dist/examples/vercel-api.d.ts +6 -0
  38. package/dist/examples/vercel-api.d.ts.map +1 -0
  39. package/dist/examples/vercel-api.js +17 -0
  40. package/dist/examples/vercel-api.js.map +1 -0
  41. package/dist/handler.d.ts +7 -0
  42. package/dist/handler.d.ts.map +1 -0
  43. package/dist/handler.js +108 -0
  44. package/dist/handler.js.map +1 -0
  45. package/dist/index.d.ts +11 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +9 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/rate-limit.d.ts +15 -0
  50. package/dist/rate-limit.d.ts.map +1 -0
  51. package/dist/rate-limit.js +40 -0
  52. package/dist/rate-limit.js.map +1 -0
  53. package/dist/webhook.d.ts +10 -0
  54. package/dist/webhook.d.ts.map +1 -0
  55. package/dist/webhook.js +55 -0
  56. package/dist/webhook.js.map +1 -0
  57. package/package.json +57 -0
@@ -0,0 +1,3 @@
1
+ import type { ChatCopsServerConfig } from '../config.js';
2
+ export declare function chatcopsCloudflareHandler(config: ChatCopsServerConfig): (request: Request) => Promise<Response>;
3
+ //# sourceMappingURL=cloudflare.d.ts.map
@@ -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,4 @@
1
+ export { chatcopsMiddleware, chatcopsAnalyticsHandler } from './express.js';
2
+ export { chatcopsVercelHandler } from './vercel.js';
3
+ export { chatcopsCloudflareHandler } from './cloudflare.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -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,4 @@
1
+ export { chatcopsMiddleware, chatcopsAnalyticsHandler } from './express.js';
2
+ export { chatcopsVercelHandler } from './vercel.js';
3
+ export { chatcopsCloudflareHandler } from './cloudflare.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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,3 @@
1
+ import type { ChatCopsServerConfig } from '../config.js';
2
+ export declare function chatcopsVercelHandler(config: ChatCopsServerConfig): (req: Request) => Promise<Response>;
3
+ //# sourceMappingURL=vercel.d.ts.map
@@ -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,2 @@
1
+ export { ServerAnalytics } from './server.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -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,2 @@
1
+ export { ServerAnalytics } from './server.js';
2
+ //# sourceMappingURL=index.js.map
@@ -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"}
@@ -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,5 @@
1
+ declare const _default: {
2
+ fetch(request: Request, env: Record<string, string>): Promise<Response>;
3
+ };
4
+ export default _default;
5
+ //# sourceMappingURL=cloudflare-worker.d.ts.map
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=express-server.d.ts.map
@@ -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,6 @@
1
+ export declare const config: {
2
+ runtime: string;
3
+ };
4
+ declare const _default: (req: Request) => Promise<Response>;
5
+ export default _default;
6
+ //# sourceMappingURL=vercel-api.d.ts.map
@@ -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"}
@@ -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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"}
@@ -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"}
@@ -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
+ }