@witqq/agent-sdk 0.6.0 → 0.7.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 (122) hide show
  1. package/README.md +433 -6
  2. package/dist/auth/index.cjs +188 -1
  3. package/dist/auth/index.cjs.map +1 -1
  4. package/dist/auth/index.d.cts +154 -138
  5. package/dist/auth/index.d.ts +154 -138
  6. package/dist/auth/index.js +188 -2
  7. package/dist/auth/index.js.map +1 -1
  8. package/dist/backends/claude.cjs +341 -22
  9. package/dist/backends/claude.cjs.map +1 -1
  10. package/dist/backends/claude.d.cts +2 -1
  11. package/dist/backends/claude.d.ts +2 -1
  12. package/dist/backends/claude.js +341 -22
  13. package/dist/backends/claude.js.map +1 -1
  14. package/dist/backends/copilot.cjs +133 -25
  15. package/dist/backends/copilot.cjs.map +1 -1
  16. package/dist/backends/copilot.d.cts +2 -1
  17. package/dist/backends/copilot.d.ts +2 -1
  18. package/dist/backends/copilot.js +133 -25
  19. package/dist/backends/copilot.js.map +1 -1
  20. package/dist/backends/vercel-ai.cjs +66 -19
  21. package/dist/backends/vercel-ai.cjs.map +1 -1
  22. package/dist/backends/vercel-ai.d.cts +1 -1
  23. package/dist/backends/vercel-ai.d.ts +1 -1
  24. package/dist/backends/vercel-ai.js +66 -19
  25. package/dist/backends/vercel-ai.js.map +1 -1
  26. package/dist/chat/accumulator.cjs +147 -0
  27. package/dist/chat/accumulator.cjs.map +1 -0
  28. package/dist/chat/accumulator.d.cts +61 -0
  29. package/dist/chat/accumulator.d.ts +61 -0
  30. package/dist/chat/accumulator.js +145 -0
  31. package/dist/chat/accumulator.js.map +1 -0
  32. package/dist/chat/backends.cjs +3534 -0
  33. package/dist/chat/backends.cjs.map +1 -0
  34. package/dist/chat/backends.d.cts +62 -0
  35. package/dist/chat/backends.d.ts +62 -0
  36. package/dist/chat/backends.js +3501 -0
  37. package/dist/chat/backends.js.map +1 -0
  38. package/dist/chat/context.cjs +230 -0
  39. package/dist/chat/context.cjs.map +1 -0
  40. package/dist/chat/context.d.cts +167 -0
  41. package/dist/chat/context.d.ts +167 -0
  42. package/dist/chat/context.js +227 -0
  43. package/dist/chat/context.js.map +1 -0
  44. package/dist/chat/core.cjs +282 -0
  45. package/dist/chat/core.cjs.map +1 -0
  46. package/dist/chat/core.d.cts +435 -0
  47. package/dist/chat/core.d.ts +435 -0
  48. package/dist/chat/core.js +261 -0
  49. package/dist/chat/core.js.map +1 -0
  50. package/dist/chat/errors.cjs +251 -0
  51. package/dist/chat/errors.cjs.map +1 -0
  52. package/dist/chat/errors.d.cts +122 -0
  53. package/dist/chat/errors.d.ts +122 -0
  54. package/dist/chat/errors.js +243 -0
  55. package/dist/chat/errors.js.map +1 -0
  56. package/dist/chat/events.cjs +203 -0
  57. package/dist/chat/events.cjs.map +1 -0
  58. package/dist/chat/events.d.cts +241 -0
  59. package/dist/chat/events.d.ts +241 -0
  60. package/dist/chat/events.js +196 -0
  61. package/dist/chat/events.js.map +1 -0
  62. package/dist/chat/index.cjs +5359 -0
  63. package/dist/chat/index.cjs.map +1 -0
  64. package/dist/chat/index.d.cts +52 -0
  65. package/dist/chat/index.d.ts +52 -0
  66. package/dist/chat/index.js +5296 -0
  67. package/dist/chat/index.js.map +1 -0
  68. package/dist/chat/react.cjs +2739 -0
  69. package/dist/chat/react.cjs.map +1 -0
  70. package/dist/chat/react.d.cts +619 -0
  71. package/dist/chat/react.d.ts +619 -0
  72. package/dist/chat/react.js +2714 -0
  73. package/dist/chat/react.js.map +1 -0
  74. package/dist/chat/runtime.cjs +1030 -0
  75. package/dist/chat/runtime.cjs.map +1 -0
  76. package/dist/chat/runtime.d.cts +118 -0
  77. package/dist/chat/runtime.d.ts +118 -0
  78. package/dist/chat/runtime.js +1028 -0
  79. package/dist/chat/runtime.js.map +1 -0
  80. package/dist/chat/server.cjs +643 -0
  81. package/dist/chat/server.cjs.map +1 -0
  82. package/dist/chat/server.d.cts +287 -0
  83. package/dist/chat/server.d.ts +287 -0
  84. package/dist/chat/server.js +617 -0
  85. package/dist/chat/server.js.map +1 -0
  86. package/dist/chat/sessions.cjs +398 -0
  87. package/dist/chat/sessions.cjs.map +1 -0
  88. package/dist/chat/sessions.d.cts +239 -0
  89. package/dist/chat/sessions.d.ts +239 -0
  90. package/dist/chat/sessions.js +394 -0
  91. package/dist/chat/sessions.js.map +1 -0
  92. package/dist/chat/state.cjs +177 -0
  93. package/dist/chat/state.cjs.map +1 -0
  94. package/dist/chat/state.d.cts +92 -0
  95. package/dist/chat/state.d.ts +92 -0
  96. package/dist/chat/state.js +167 -0
  97. package/dist/chat/state.js.map +1 -0
  98. package/dist/chat/storage.cjs +240 -0
  99. package/dist/chat/storage.cjs.map +1 -0
  100. package/dist/chat/storage.d.cts +191 -0
  101. package/dist/chat/storage.d.ts +191 -0
  102. package/dist/chat/storage.js +236 -0
  103. package/dist/chat/storage.js.map +1 -0
  104. package/dist/errors-BDLbNu9w.d.cts +13 -0
  105. package/dist/errors-BDLbNu9w.d.ts +13 -0
  106. package/dist/in-process-transport-C2oPTYs6.d.ts +223 -0
  107. package/dist/in-process-transport-DG-w5G6k.d.cts +223 -0
  108. package/dist/index.cjs +25 -13
  109. package/dist/index.cjs.map +1 -1
  110. package/dist/index.d.cts +32 -4
  111. package/dist/index.d.ts +32 -4
  112. package/dist/index.js +25 -13
  113. package/dist/index.js.map +1 -1
  114. package/dist/transport-D1OaUgRk.d.ts +67 -0
  115. package/dist/transport-DX1Nhm4N.d.cts +67 -0
  116. package/dist/types-Bh5AhqD-.d.ts +141 -0
  117. package/dist/types-CGF7AEX1.d.cts +141 -0
  118. package/dist/{types-BvwNzZCj.d.cts → types-CqvUAYxt.d.cts} +21 -3
  119. package/dist/{types-BvwNzZCj.d.ts → types-CqvUAYxt.d.ts} +21 -3
  120. package/dist/types-DLZzlJxt.d.ts +39 -0
  121. package/dist/types-tE0CXwBl.d.cts +39 -0
  122. package/package.json +149 -2
@@ -0,0 +1,643 @@
1
+ 'use strict';
2
+
3
+ var fs = require('fs');
4
+ var path = require('path');
5
+
6
+ function _interopNamespace(e) {
7
+ if (e && e.__esModule) return e;
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
25
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
26
+
27
+ // src/chat/backends/transport.ts
28
+ var SSEChatTransport = class {
29
+ res;
30
+ _open;
31
+ _heartbeatTimer;
32
+ constructor(res, options) {
33
+ this.res = res;
34
+ this._open = true;
35
+ res.writeHead(200, {
36
+ "Content-Type": "text/event-stream",
37
+ "Cache-Control": "no-cache",
38
+ "Connection": "keep-alive",
39
+ "X-Accel-Buffering": "no"
40
+ });
41
+ if (options?.request) {
42
+ options.request.on("close", () => {
43
+ this._cleanup();
44
+ });
45
+ }
46
+ const heartbeatMs = options?.heartbeatMs;
47
+ if (heartbeatMs && heartbeatMs > 0) {
48
+ this._heartbeatTimer = setInterval(() => {
49
+ if (!this.isOpen) {
50
+ this._clearHeartbeat();
51
+ return;
52
+ }
53
+ this.res.write(": heartbeat\n\n");
54
+ }, heartbeatMs);
55
+ }
56
+ }
57
+ get isOpen() {
58
+ return this._open && !this.res.writableEnded;
59
+ }
60
+ send(event) {
61
+ if (!this.isOpen) return;
62
+ this.res.write(`data: ${JSON.stringify(event)}
63
+
64
+ `);
65
+ }
66
+ close() {
67
+ if (!this.isOpen) return;
68
+ this._open = false;
69
+ this._clearHeartbeat();
70
+ this.res.write(`data: [DONE]
71
+
72
+ `);
73
+ this.res.end();
74
+ }
75
+ error(err) {
76
+ if (!this.isOpen) return;
77
+ this._open = false;
78
+ this._clearHeartbeat();
79
+ const errorEvent = {
80
+ type: "error",
81
+ error: err.message,
82
+ recoverable: false
83
+ };
84
+ this.res.write(`data: ${JSON.stringify(errorEvent)}
85
+
86
+ `);
87
+ this.res.end();
88
+ }
89
+ _cleanup() {
90
+ this._open = false;
91
+ this._clearHeartbeat();
92
+ }
93
+ _clearHeartbeat() {
94
+ if (this._heartbeatTimer !== void 0) {
95
+ clearInterval(this._heartbeatTimer);
96
+ this._heartbeatTimer = void 0;
97
+ }
98
+ }
99
+ };
100
+ async function streamToTransport(events, transport) {
101
+ try {
102
+ let accumulatedText = "";
103
+ for await (const event of events) {
104
+ if (!transport.isOpen) break;
105
+ transport.send(event);
106
+ if (event.type === "message:delta") {
107
+ accumulatedText += event.text;
108
+ }
109
+ }
110
+ if (transport.isOpen) {
111
+ transport.send({ type: "done", finalOutput: accumulatedText || void 0 });
112
+ }
113
+ transport.close();
114
+ } catch (err) {
115
+ transport.error(err instanceof Error ? err : new Error(String(err)));
116
+ }
117
+ }
118
+
119
+ // src/chat/server/handler.ts
120
+ function createChatHandler(runtime, options) {
121
+ const prefix = options?.prefix ?? "";
122
+ const maxBodySize = options?.maxBodySize ?? 1048576;
123
+ const heartbeatMs = options?.heartbeatMs;
124
+ return async (req, res) => {
125
+ const url = req.url || "";
126
+ const method = req.method || "GET";
127
+ const rawPath = prefix ? url.slice(prefix.length) : url;
128
+ const path2 = rawPath.split("?")[0];
129
+ const sessionMatch = path2.match(/^\/sessions\/([^/]+)$/);
130
+ const archiveMatch = path2.match(/^\/sessions\/([^/]+)\/archive$/);
131
+ try {
132
+ if (method === "POST" && path2 === "/sessions/create") {
133
+ const body = await readBody(req, maxBodySize);
134
+ const session = await runtime.createSession({
135
+ title: body.title || `Chat ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}`,
136
+ config: body.config || {
137
+ model: runtime.currentModel || "",
138
+ backend: runtime.currentBackend
139
+ },
140
+ ...body.tags ? { tags: body.tags } : {},
141
+ ...body.custom ? { custom: body.custom } : {}
142
+ });
143
+ json(res, session);
144
+ return;
145
+ }
146
+ if (method === "POST" && archiveMatch) {
147
+ const id = decodeURIComponent(archiveMatch[1]);
148
+ await runtime.archiveSession(id);
149
+ json(res, { ok: true });
150
+ return;
151
+ }
152
+ if (method === "GET" && sessionMatch) {
153
+ const id = decodeURIComponent(sessionMatch[1]);
154
+ const session = await runtime.getSession(id);
155
+ if (!session) {
156
+ json(res, { error: "Not found" }, 404);
157
+ return;
158
+ }
159
+ json(res, session);
160
+ return;
161
+ }
162
+ if (method === "DELETE" && sessionMatch) {
163
+ const id = decodeURIComponent(sessionMatch[1]);
164
+ await runtime.deleteSession(id);
165
+ json(res, { ok: true });
166
+ return;
167
+ }
168
+ if (method === "GET" && path2 === "/sessions") {
169
+ const sessions = await runtime.listSessions();
170
+ json(res, sessions);
171
+ return;
172
+ }
173
+ if (method === "POST" && path2 === "/send") {
174
+ const body = await readBody(req, maxBodySize);
175
+ const sessionId = body.sessionId;
176
+ const message = body.message || body.content;
177
+ if (!sessionId || !message) {
178
+ json(res, { error: "sessionId and message are required" }, 400);
179
+ return;
180
+ }
181
+ const transport = new SSEChatTransport(res, {
182
+ heartbeatMs,
183
+ request: req
184
+ });
185
+ try {
186
+ const opts = {};
187
+ if (body.model) opts.model = body.model;
188
+ const stream = runtime.send(
189
+ sessionId,
190
+ message,
191
+ Object.keys(opts).length > 0 ? opts : void 0
192
+ );
193
+ await streamToTransport(stream, transport);
194
+ } catch (err) {
195
+ transport.error(err instanceof Error ? err : new Error(String(err)));
196
+ }
197
+ return;
198
+ }
199
+ if (method === "POST" && path2 === "/abort") {
200
+ runtime.abort();
201
+ json(res, { ok: true });
202
+ return;
203
+ }
204
+ if (method === "GET" && path2 === "/models") {
205
+ const models = await runtime.listModels();
206
+ json(res, models);
207
+ return;
208
+ }
209
+ if (method === "POST" && path2 === "/backend/switch") {
210
+ const body = await readBody(req, maxBodySize);
211
+ if (!body.backend || typeof body.backend !== "string") {
212
+ json(res, { error: "backend is required" }, 400);
213
+ return;
214
+ }
215
+ await runtime.switchBackend(body.backend);
216
+ json(res, { ok: true });
217
+ return;
218
+ }
219
+ if (method === "POST" && path2 === "/model/switch") {
220
+ const body = await readBody(req, maxBodySize);
221
+ if (!body.model || typeof body.model !== "string") {
222
+ json(res, { error: "model is required" }, 400);
223
+ return;
224
+ }
225
+ runtime.switchModel(body.model);
226
+ json(res, { ok: true });
227
+ return;
228
+ }
229
+ json(res, { error: "Not found" }, 404);
230
+ } catch (err) {
231
+ if (err instanceof BodyParseError) {
232
+ json(res, { error: err.message }, err.statusCode);
233
+ } else {
234
+ const message = err instanceof Error ? err.message : String(err);
235
+ json(res, { error: message }, 500);
236
+ }
237
+ }
238
+ };
239
+ }
240
+ var BodyParseError = class extends Error {
241
+ statusCode;
242
+ constructor(message, statusCode) {
243
+ super(message);
244
+ this.name = "BodyParseError";
245
+ this.statusCode = statusCode;
246
+ }
247
+ };
248
+ function readBody(req, maxSize) {
249
+ return new Promise((resolve2, reject) => {
250
+ let body = "";
251
+ let size = 0;
252
+ let exceeded = false;
253
+ req.on("data", (chunk) => {
254
+ if (exceeded) return;
255
+ const str = chunk.toString();
256
+ size += Buffer.byteLength(str);
257
+ if (size > maxSize) {
258
+ exceeded = true;
259
+ reject(new BodyParseError("Request body too large", 413));
260
+ return;
261
+ }
262
+ body += str;
263
+ });
264
+ req.on("end", () => {
265
+ if (exceeded) return;
266
+ try {
267
+ resolve2(JSON.parse(body || "{}"));
268
+ } catch {
269
+ reject(new BodyParseError("Invalid JSON in request body", 400));
270
+ }
271
+ });
272
+ if ("once" in req && typeof req.once === "function") {
273
+ req.once(
274
+ "error",
275
+ () => reject(new BodyParseError("Request error", 500))
276
+ );
277
+ }
278
+ });
279
+ }
280
+ function json(res, data, status = 200) {
281
+ res.writeHead(status, { "Content-Type": "application/json" });
282
+ res.end(JSON.stringify(data));
283
+ }
284
+
285
+ // src/chat/server/auth-handler.ts
286
+ function createAuthHandler(options) {
287
+ const { tokenStore, onAuth } = options;
288
+ const prefix = options.prefix ?? "";
289
+ const maxBodySize = options.maxBodySize ?? 1048576;
290
+ let pendingCopilot = null;
291
+ let pendingClaude = null;
292
+ return async (req, res) => {
293
+ const url = req.url || "";
294
+ const method = req.method || "GET";
295
+ const rawPath = prefix ? url.slice(prefix.length) : url;
296
+ const path2 = rawPath.split("?")[0];
297
+ try {
298
+ if (method === "POST" && path2 === "/auth/start") {
299
+ const body = await readBody2(req, maxBodySize);
300
+ const provider = body.provider;
301
+ if (!provider || !isValidProvider(provider)) {
302
+ json2(res, { error: "provider is required (copilot, claude, vercel-ai)" }, 400);
303
+ return;
304
+ }
305
+ pendingCopilot = null;
306
+ pendingClaude = null;
307
+ if (provider === "copilot") {
308
+ if (!options.createCopilotAuth) {
309
+ json2(res, { error: "Copilot auth not configured" }, 400);
310
+ return;
311
+ }
312
+ const auth = options.createCopilotAuth();
313
+ const flow = await auth.startDeviceFlow();
314
+ pendingCopilot = { waitForToken: flow.waitForToken };
315
+ json2(res, { userCode: flow.userCode, verificationUrl: flow.verificationUrl });
316
+ return;
317
+ }
318
+ if (provider === "claude") {
319
+ if (!options.createClaudeAuth) {
320
+ json2(res, { error: "Claude auth not configured" }, 400);
321
+ return;
322
+ }
323
+ const auth = options.createClaudeAuth();
324
+ const flow = auth.startOAuthFlow();
325
+ pendingClaude = { completeAuth: flow.completeAuth };
326
+ json2(res, { authorizeUrl: flow.authorizeUrl });
327
+ return;
328
+ }
329
+ json2(res, { ready: true });
330
+ return;
331
+ }
332
+ if (method === "POST" && path2 === "/auth/copilot/poll") {
333
+ if (!pendingCopilot) {
334
+ json2(res, { error: "No active Copilot flow" }, 400);
335
+ return;
336
+ }
337
+ const token = await pendingCopilot.waitForToken();
338
+ pendingCopilot = null;
339
+ await tokenStore.save("copilot", token);
340
+ if (onAuth) await onAuth("copilot", token);
341
+ json2(res, { ok: true, login: token.login });
342
+ return;
343
+ }
344
+ if (method === "POST" && path2 === "/auth/claude/complete") {
345
+ if (!pendingClaude) {
346
+ json2(res, { error: "No active Claude flow" }, 400);
347
+ return;
348
+ }
349
+ const body = await readBody2(req, maxBodySize);
350
+ const code = body.code;
351
+ if (!code || typeof code !== "string") {
352
+ json2(res, { error: "code is required" }, 400);
353
+ return;
354
+ }
355
+ const token = await pendingClaude.completeAuth(code);
356
+ pendingClaude = null;
357
+ await tokenStore.save("claude", token);
358
+ if (onAuth) await onAuth("claude", token);
359
+ json2(res, { ok: true });
360
+ return;
361
+ }
362
+ if (method === "POST" && path2 === "/auth/vercel/complete") {
363
+ const body = await readBody2(req, maxBodySize);
364
+ const apiKey = body.apiKey;
365
+ if (!apiKey || typeof apiKey !== "string") {
366
+ json2(res, { error: "apiKey is required" }, 400);
367
+ return;
368
+ }
369
+ const token = {
370
+ accessToken: apiKey,
371
+ tokenType: "bearer",
372
+ obtainedAt: Date.now()
373
+ };
374
+ const storeToken = body.baseUrl ? { ...token, baseUrl: body.baseUrl } : token;
375
+ await tokenStore.save("vercel-ai", storeToken);
376
+ if (onAuth) await onAuth("vercel-ai", storeToken);
377
+ json2(res, { ok: true });
378
+ return;
379
+ }
380
+ if (method === "GET" && path2 === "/tokens/saved") {
381
+ const saved = await tokenStore.list();
382
+ json2(res, { saved });
383
+ return;
384
+ }
385
+ if (method === "POST" && path2 === "/tokens/use") {
386
+ const body = await readBody2(req, maxBodySize);
387
+ const provider = body.provider;
388
+ if (!provider || !isValidProvider(provider)) {
389
+ json2(res, { error: "provider is required (copilot, claude, vercel-ai)" }, 400);
390
+ return;
391
+ }
392
+ const token = await tokenStore.load(provider);
393
+ if (!token) {
394
+ json2(res, { error: `No saved token for ${provider}` }, 404);
395
+ return;
396
+ }
397
+ if (onAuth) await onAuth(provider, token);
398
+ json2(res, { ok: true, provider });
399
+ return;
400
+ }
401
+ if (method === "POST" && path2 === "/tokens/clear") {
402
+ await tokenStore.clearAll();
403
+ if (options.onLogout) await options.onLogout();
404
+ json2(res, { ok: true });
405
+ return;
406
+ }
407
+ if (method === "POST" && path2 === "/auth/dispose") {
408
+ pendingCopilot = null;
409
+ pendingClaude = null;
410
+ if (options.onLogout) await options.onLogout();
411
+ json2(res, { ok: true });
412
+ return;
413
+ }
414
+ json2(res, { error: "Not found" }, 404);
415
+ } catch (err) {
416
+ const message = err instanceof Error ? err.message : String(err);
417
+ json2(res, { error: message }, 500);
418
+ }
419
+ };
420
+ }
421
+ function isValidProvider(p) {
422
+ return p === "copilot" || p === "claude" || p === "vercel-ai";
423
+ }
424
+ function readBody2(req, maxSize) {
425
+ return new Promise((resolve2) => {
426
+ let body = "";
427
+ let size = 0;
428
+ let exceeded = false;
429
+ req.on("data", (chunk) => {
430
+ if (exceeded) return;
431
+ const str = chunk.toString();
432
+ size += Buffer.byteLength(str);
433
+ if (size > maxSize) {
434
+ exceeded = true;
435
+ resolve2({});
436
+ return;
437
+ }
438
+ body += str;
439
+ });
440
+ req.on("end", () => {
441
+ if (exceeded) return;
442
+ try {
443
+ resolve2(JSON.parse(body || "{}"));
444
+ } catch {
445
+ resolve2({});
446
+ }
447
+ });
448
+ if ("once" in req && typeof req.once === "function") {
449
+ req.once("error", () => resolve2({}));
450
+ }
451
+ });
452
+ }
453
+ function json2(res, data, status = 200) {
454
+ res.writeHead(status, { "Content-Type": "application/json" });
455
+ res.end(JSON.stringify(data));
456
+ }
457
+
458
+ // src/chat/server/cors.ts
459
+ function corsMiddleware(options) {
460
+ const origin = options?.origin ?? "*";
461
+ const methods = options?.methods ?? ["GET", "POST", "DELETE", "OPTIONS"];
462
+ const headers = options?.headers ?? ["Content-Type"];
463
+ const maxAge = options?.maxAge ?? 86400;
464
+ const methodsValue = methods.join(", ");
465
+ const headersValue = headers.join(", ");
466
+ return (req, res) => {
467
+ let originValue;
468
+ if (Array.isArray(origin)) {
469
+ const reqOrigin = typeof req.headers?.origin === "string" ? req.headers.origin : "";
470
+ originValue = origin.includes(reqOrigin) ? reqOrigin : origin[0];
471
+ res.setHeader("Vary", "Origin");
472
+ } else {
473
+ originValue = origin;
474
+ }
475
+ res.setHeader("Access-Control-Allow-Origin", originValue);
476
+ res.setHeader("Access-Control-Allow-Methods", methodsValue);
477
+ res.setHeader("Access-Control-Allow-Headers", headersValue);
478
+ if (req.method === "OPTIONS") {
479
+ res.setHeader("Access-Control-Max-Age", String(maxAge));
480
+ res.writeHead(204);
481
+ res.end();
482
+ return true;
483
+ }
484
+ return false;
485
+ };
486
+ }
487
+ var MIME_TYPES = {
488
+ ".html": "text/html",
489
+ ".css": "text/css",
490
+ ".js": "application/javascript",
491
+ ".mjs": "application/javascript",
492
+ ".json": "application/json",
493
+ ".png": "image/png",
494
+ ".jpg": "image/jpeg",
495
+ ".jpeg": "image/jpeg",
496
+ ".gif": "image/gif",
497
+ ".svg": "image/svg+xml",
498
+ ".ico": "image/x-icon",
499
+ ".woff": "font/woff",
500
+ ".woff2": "font/woff2",
501
+ ".ttf": "font/ttf",
502
+ ".txt": "text/plain",
503
+ ".map": "application/json"
504
+ };
505
+ function createChatServer(options) {
506
+ const chatPrefix = options.chatPrefix ?? "/api/chat";
507
+ const authPrefix = options.authPrefix ?? "/api/auth";
508
+ const staticPrefix = options.staticPrefix ?? "/";
509
+ const staticDir = options.staticDir ? path__namespace.resolve(options.staticDir) : void 0;
510
+ const chatHandler = createChatHandler(options.runtime, {
511
+ prefix: chatPrefix,
512
+ ...options.chatHandlerOptions
513
+ });
514
+ const authHandler = options.auth ? createAuthHandler(options.auth) : void 0;
515
+ const cors = options.cors !== false ? corsMiddleware(options.cors) : void 0;
516
+ return async (req, res) => {
517
+ const url = req.url || "/";
518
+ const urlPath = url.split("?")[0];
519
+ if (cors) {
520
+ const corsReq = { method: req.method, headers: req.headers };
521
+ const corsRes = {
522
+ setHeader: (name, value) => res.setHeader(name, value),
523
+ writeHead: (statusCode) => res.writeHead(statusCode, {}),
524
+ end: () => res.end()
525
+ };
526
+ if (cors(corsReq, corsRes)) {
527
+ return;
528
+ }
529
+ }
530
+ if (urlPath.startsWith(chatPrefix + "/") || urlPath === chatPrefix) {
531
+ await chatHandler(req, res);
532
+ return;
533
+ }
534
+ if (authHandler && (urlPath.startsWith(authPrefix + "/") || urlPath === authPrefix)) {
535
+ const authReq = Object.create(req, {
536
+ url: { value: url.replace(authPrefix, ""), enumerable: true }
537
+ });
538
+ await authHandler(authReq, res);
539
+ return;
540
+ }
541
+ if (staticDir && req.method === "GET" && urlPath.startsWith(staticPrefix)) {
542
+ const relativePath = urlPath === staticPrefix || urlPath === staticPrefix + "/" ? "/index.html" : urlPath.slice(staticPrefix.length) || "/index.html";
543
+ const filePath = path__namespace.join(staticDir, relativePath);
544
+ if (!filePath.startsWith(staticDir + path__namespace.sep) && filePath !== staticDir) {
545
+ res.writeHead(403, { "Content-Type": "application/json" });
546
+ res.end(JSON.stringify({ error: "Forbidden" }));
547
+ return;
548
+ }
549
+ try {
550
+ const stat = fs__namespace.statSync(filePath);
551
+ if (stat.isFile()) {
552
+ const ext = path__namespace.extname(filePath).toLowerCase();
553
+ const contentType = MIME_TYPES[ext] || "application/octet-stream";
554
+ const content = fs__namespace.readFileSync(filePath);
555
+ res.writeHead(200, {
556
+ "Content-Type": contentType,
557
+ "Content-Length": String(content.length)
558
+ });
559
+ res.write(content.toString());
560
+ res.end();
561
+ return;
562
+ }
563
+ } catch {
564
+ }
565
+ }
566
+ json3(res, 404, { error: "Not found" });
567
+ };
568
+ }
569
+ function json3(res, status, body) {
570
+ const data = JSON.stringify(body);
571
+ res.writeHead(status, { "Content-Type": "application/json" });
572
+ res.end(data);
573
+ }
574
+ var InMemoryTokenStore = class {
575
+ tokens = /* @__PURE__ */ new Map();
576
+ async save(provider, token) {
577
+ this.tokens.set(provider, { ...token });
578
+ }
579
+ async load(provider) {
580
+ const t = this.tokens.get(provider);
581
+ return t ? { ...t } : null;
582
+ }
583
+ async clear(provider) {
584
+ this.tokens.delete(provider);
585
+ }
586
+ async clearAll() {
587
+ this.tokens.clear();
588
+ }
589
+ async list() {
590
+ return [...this.tokens.keys()];
591
+ }
592
+ };
593
+ var FileTokenStore = class {
594
+ dir;
595
+ constructor(options) {
596
+ this.dir = options.directory;
597
+ }
598
+ async save(provider, token) {
599
+ fs.mkdirSync(this.dir, { recursive: true });
600
+ fs.writeFileSync(this.filePath(provider), JSON.stringify(token));
601
+ }
602
+ async load(provider) {
603
+ try {
604
+ const data = fs.readFileSync(this.filePath(provider), "utf-8");
605
+ return JSON.parse(data);
606
+ } catch {
607
+ return null;
608
+ }
609
+ }
610
+ async clear(provider) {
611
+ try {
612
+ fs.unlinkSync(this.filePath(provider));
613
+ } catch {
614
+ }
615
+ }
616
+ async clearAll() {
617
+ if (!fs.existsSync(this.dir)) return;
618
+ for (const f of fs.readdirSync(this.dir)) {
619
+ if (f.endsWith("-token.json")) {
620
+ try {
621
+ fs.unlinkSync(path.join(this.dir, f));
622
+ } catch {
623
+ }
624
+ }
625
+ }
626
+ }
627
+ async list() {
628
+ if (!fs.existsSync(this.dir)) return [];
629
+ return fs.readdirSync(this.dir).filter((f) => f.endsWith("-token.json")).map((f) => f.replace(/-token\.json$/, ""));
630
+ }
631
+ filePath(provider) {
632
+ return path.join(this.dir, `${provider}-token.json`);
633
+ }
634
+ };
635
+
636
+ exports.FileTokenStore = FileTokenStore;
637
+ exports.InMemoryTokenStore = InMemoryTokenStore;
638
+ exports.corsMiddleware = corsMiddleware;
639
+ exports.createAuthHandler = createAuthHandler;
640
+ exports.createChatHandler = createChatHandler;
641
+ exports.createChatServer = createChatServer;
642
+ //# sourceMappingURL=server.cjs.map
643
+ //# sourceMappingURL=server.cjs.map