orbitchat 3.5.3 → 3.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/bin/orbitchat.js +59 -13
  2. package/dist/assets/ChartRenderer-BK9VmJeQ.js +80 -0
  3. package/dist/assets/{MermaidRenderer-CrwrWA79.js → MermaidRenderer-qzVgEt2x.js} +5 -5
  4. package/dist/assets/{MusicRenderer-DsCYCPzj.js → MusicRenderer-D7rL8A6g.js} +2 -2
  5. package/dist/assets/{SVGRenderer-4l9fyX1s.js → SVGRenderer-BEKEOm3s.js} +1 -1
  6. package/dist/assets/{_basePickBy-C7S27-r4.js → _basePickBy-DjEbiWID.js} +1 -1
  7. package/dist/assets/{_baseUniq-7f9rjySx.js → _baseUniq-BJ_CGYjc.js} +1 -1
  8. package/dist/assets/{architectureDiagram-2XIMDMQ5-RDQYD3py.js → architectureDiagram-2XIMDMQ5-Os-EdwOr.js} +1 -1
  9. package/dist/assets/{blockDiagram-WCTKOSBZ-Bvd59nkz.js → blockDiagram-WCTKOSBZ-dOlyr0sT.js} +1 -1
  10. package/dist/assets/{c4Diagram-IC4MRINW-BspB3C3a.js → c4Diagram-IC4MRINW-Bo18Ckoj.js} +1 -1
  11. package/dist/assets/channel-u3m7-f_Y.js +1 -0
  12. package/dist/assets/{chunk-4BX2VUAB-CF_0yBPD.js → chunk-4BX2VUAB-Bd4J2y84.js} +1 -1
  13. package/dist/assets/{chunk-55IACEB6-DH0Z48MR.js → chunk-55IACEB6-D31lfA_a.js} +1 -1
  14. package/dist/assets/{chunk-FMBD7UC4-D0VfP_qK.js → chunk-FMBD7UC4-D7f0j4zs.js} +1 -1
  15. package/dist/assets/{chunk-JSJVCQXG-BWDXqKOo.js → chunk-JSJVCQXG-i60xlQfX.js} +1 -1
  16. package/dist/assets/{chunk-KX2RTZJC-neUa6q9l.js → chunk-KX2RTZJC-DOMFBwQb.js} +1 -1
  17. package/dist/assets/{chunk-NQ4KR5QH-B2DKcXKz.js → chunk-NQ4KR5QH-Z6JCXOAb.js} +1 -1
  18. package/dist/assets/{chunk-QZHKN3VN-CB8rRoOU.js → chunk-QZHKN3VN-EGcB7IW2.js} +1 -1
  19. package/dist/assets/{chunk-WL4C6EOR-BWSVDtLk.js → chunk-WL4C6EOR-Dtoe_nFJ.js} +1 -1
  20. package/dist/assets/classDiagram-VBA2DB6C-CK4JEESe.js +1 -0
  21. package/dist/assets/classDiagram-v2-RAHNMMFH-CK4JEESe.js +1 -0
  22. package/dist/assets/clone-lXpWKNyV.js +1 -0
  23. package/dist/assets/{cose-bilkent-S5V4N54A-BkQN7T_Z.js → cose-bilkent-S5V4N54A-DwaP6XDY.js} +1 -1
  24. package/dist/assets/{dagre-KLK3FWXG-2aRZ42WU.js → dagre-KLK3FWXG-3iS8nwUM.js} +1 -1
  25. package/dist/assets/{diagram-E7M64L7V-B0nhOFG7.js → diagram-E7M64L7V-DWn04JQu.js} +1 -1
  26. package/dist/assets/{diagram-IFDJBPK2-B9V7kAOO.js → diagram-IFDJBPK2-CeCAfVij.js} +1 -1
  27. package/dist/assets/{diagram-P4PSJMXO-CFFdtr8I.js → diagram-P4PSJMXO-mjl_7jtT.js} +1 -1
  28. package/dist/assets/{erDiagram-INFDFZHY-B5ffop2h.js → erDiagram-INFDFZHY-Dl81qwyk.js} +1 -1
  29. package/dist/assets/{flowDiagram-PKNHOUZH-BWbYNUvl.js → flowDiagram-PKNHOUZH-Du4oI4VY.js} +1 -1
  30. package/dist/assets/{ganttDiagram-A5KZAMGK-Chhnbfig.js → ganttDiagram-A5KZAMGK-B4O-QXYi.js} +1 -1
  31. package/dist/assets/{gitGraphDiagram-K3NZZRJ6-V8UBDhXq.js → gitGraphDiagram-K3NZZRJ6-Cju5-Jsp.js} +1 -1
  32. package/dist/assets/{graph-CX33kXjo.js → graph-BRWBJHvn.js} +1 -1
  33. package/dist/assets/{index-6t_LHUnB.js → index-C8kIMiLQ.js} +124 -124
  34. package/dist/assets/{index-DUcrCaMk.js → index-O3Qu_V1p.js} +1 -1
  35. package/dist/assets/{infoDiagram-LFFYTUFH-D39liguC.js → infoDiagram-LFFYTUFH-BtIElN3U.js} +1 -1
  36. package/dist/assets/{ishikawaDiagram-PHBUUO56-DP_IEmay.js → ishikawaDiagram-PHBUUO56-BKL_bByI.js} +1 -1
  37. package/dist/assets/{journeyDiagram-4ABVD52K-DZtCCP2H.js → journeyDiagram-4ABVD52K-B7azS9rj.js} +1 -1
  38. package/dist/assets/{kanban-definition-K7BYSVSG-BJjJciwh.js → kanban-definition-K7BYSVSG-jcg_PkQS.js} +1 -1
  39. package/dist/assets/{layout-xvakIQ0I.js → layout-M6cSIos1.js} +1 -1
  40. package/dist/assets/{mindmap-definition-YRQLILUH-BFYkJYKW.js → mindmap-definition-YRQLILUH-Cf0IOJrc.js} +1 -1
  41. package/dist/assets/{pieDiagram-SKSYHLDU-B4LgWQ3r.js → pieDiagram-SKSYHLDU-DZkXQWf1.js} +1 -1
  42. package/dist/assets/{quadrantDiagram-337W2JSQ-SbaxPO9C.js → quadrantDiagram-337W2JSQ-CBv4NF9N.js} +1 -1
  43. package/dist/assets/{requirementDiagram-Z7DCOOCP-cHZA8avY.js → requirementDiagram-Z7DCOOCP-DBFzO_Ft.js} +1 -1
  44. package/dist/assets/{sankeyDiagram-WA2Y5GQK-BOvJicIs.js → sankeyDiagram-WA2Y5GQK-CSP7f-pA.js} +1 -1
  45. package/dist/assets/{sequenceDiagram-2WXFIKYE-Dk9q2HeF.js → sequenceDiagram-2WXFIKYE-BTC0RRGS.js} +1 -1
  46. package/dist/assets/{stateDiagram-RAJIS63D--PnsFKDS.js → stateDiagram-RAJIS63D-CAh_mwJy.js} +1 -1
  47. package/dist/assets/stateDiagram-v2-FVOUBMTO-DnFZfFm4.js +1 -0
  48. package/dist/assets/{timeline-definition-YZTLITO2-yQqhjBjA.js → timeline-definition-YZTLITO2-BLdeBeSr.js} +1 -1
  49. package/dist/assets/treemap-KZPCXAKY-LlRSRQLF.js +162 -0
  50. package/dist/assets/{vennDiagram-LZ73GAT5-DtcZ-nWZ.js → vennDiagram-LZ73GAT5-_Bk0EQ8g.js} +1 -1
  51. package/dist/assets/{xychartDiagram-JWTSCODW-CcHyoLw8.js → xychartDiagram-JWTSCODW-CB8cW01V.js} +1 -1
  52. package/dist/index.html +1 -1
  53. package/package.json +1 -6
  54. package/dist/assets/ChartRenderer-DqtgMzkG.js +0 -80
  55. package/dist/assets/channel-CyC077Do.js +0 -1
  56. package/dist/assets/classDiagram-VBA2DB6C-SQx6yVWX.js +0 -1
  57. package/dist/assets/classDiagram-v2-RAHNMMFH-SQx6yVWX.js +0 -1
  58. package/dist/assets/clone-DThclz6H.js +0 -1
  59. package/dist/assets/stateDiagram-v2-FVOUBMTO-IRiLaZKp.js +0 -1
  60. package/dist/assets/treemap-KZPCXAKY-ChqK5F5-.js +0 -162
package/bin/orbitchat.js CHANGED
@@ -10,7 +10,7 @@
10
10
  import express from 'express';
11
11
  import fs from 'fs';
12
12
  import path from 'path';
13
- import { execSync } from 'child_process';
13
+ import { execFileSync } from 'child_process';
14
14
  import { fileURLToPath } from 'url';
15
15
  import { dirname } from 'path';
16
16
  import { createProxyMiddleware } from 'http-proxy-middleware';
@@ -96,6 +96,7 @@ function deepMerge(target, source) {
96
96
  if (!isObject(target) || !isObject(source)) return source;
97
97
  const output = { ...target };
98
98
  Object.keys(source).forEach(key => {
99
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') return;
99
100
  if (isObject(target[key]) && isObject(source[key])) {
100
101
  output[key] = deepMerge(target[key], source[key]);
101
102
  } else if (source[key] !== undefined) {
@@ -280,17 +281,35 @@ function createServer(distPath, config, serverConfig = {}) {
280
281
  });
281
282
  }
282
283
 
283
- // Guest rate limiting
284
+ // Guest rate limiting — only applies to unauthenticated requests.
285
+ // Exempt read-only endpoints, file operations, and adapter info to avoid
286
+ // hitting limits during normal page load and file upload workflows.
284
287
  if (serverConfig.rateLimit?.enabled !== false) {
285
288
  const rl = serverConfig.rateLimit || {};
289
+ const rateLimitWindowMs = rl.windowMs || 60000;
290
+ const retryAfterSeconds = Math.ceil(rateLimitWindowMs / 1000);
291
+
292
+ const isExemptPath = (req) =>
293
+ req.method === 'OPTIONS' ||
294
+ req.path === '/adapters' ||
295
+ req.path.startsWith('/files') ||
296
+ req.path.startsWith('/admin/adapters') ||
297
+ req.path.startsWith('/admin/chat-history');
298
+
286
299
  const apiLimiter = rateLimit({
287
- windowMs: rl.windowMs || 60000, max: rl.maxRequests || 30,
288
- skip: (req) => req.method === 'OPTIONS' || req.path === '/adapters',
289
- handler: (req, res) => res.status(429).json({ error: 'Too many requests' }),
300
+ windowMs: rateLimitWindowMs, max: rl.maxRequests || 60,
301
+ skip: isExemptPath,
302
+ handler: (_req, res) => {
303
+ res.setHeader('Retry-After', retryAfterSeconds);
304
+ res.status(429).json({ error: 'Too many requests' });
305
+ },
290
306
  });
291
307
  const chatLimiter = rateLimit({
292
308
  windowMs: rl.chat?.windowMs || 60000, max: rl.chat?.maxRequests || 10,
293
- handler: (req, res) => res.status(429).json({ error: 'Chat rate limit exceeded' }),
309
+ handler: (_req, res) => {
310
+ res.setHeader('Retry-After', Math.ceil((rl.chat?.windowMs || 60000) / 1000));
311
+ res.status(429).json({ error: 'Chat rate limit exceeded' });
312
+ },
294
313
  });
295
314
  app.use('/api', (req, res, next) => { if (req.headers.authorization) return next(); apiLimiter(req, res, next); });
296
315
  app.use('/api', (req, res, next) => {
@@ -401,12 +420,25 @@ function createServer(distPath, config, serverConfig = {}) {
401
420
  app.use(express.json());
402
421
  if (!apiOnly && distPath) {
403
422
  app.use(express.static(distPath, { index: false }));
404
- app.get(/(.*)/, (req, res) => {
405
- if (req.path.startsWith('/api/')) return res.status(404).json({ error: 'Not found' });
406
- const indexPath = path.join(distPath, 'index.html');
407
- let content = fs.readFileSync(indexPath, 'utf8');
423
+
424
+ // Pre-build the index.html template once at startup instead of reading on every request
425
+ const indexPath = path.join(distPath, 'index.html');
426
+ let indexTemplate = null;
427
+ try {
428
+ indexTemplate = fs.readFileSync(indexPath, 'utf8');
429
+ } catch (err) {
430
+ console.error(`[orbitchat] Failed to read ${indexPath}:`, err.message);
431
+ }
432
+
433
+ // Escape </script> sequences in JSON to prevent XSS when injecting into HTML
434
+ const safeConfigJson = JSON.stringify(config).replace(/<\/(script)/gi, '<\\/$1');
435
+
436
+ // Pre-compute the transformed HTML
437
+ let cachedHtml = null;
438
+ if (indexTemplate) {
439
+ let content = indexTemplate;
408
440
  content = content.replace(/<script id="orbit-chat-config" type="application\/json">[\s\S]*?<\/script>/, '<!-- Config injected -->');
409
- const configScript = `<script>window.ORBIT_CHAT_CONFIG = ${JSON.stringify(config)};</script>`;
441
+ const configScript = `<script>window.ORBIT_CHAT_CONFIG = ${safeConfigJson};</script>`;
410
442
  content = content.replace(/<head>/i, '<head>\n ' + configScript);
411
443
  if (config.application?.name) content = content.replace(/<title>.*?<\/title>/i, `<title>${config.application.name}</title>`);
412
444
  if (config.application?.favicon?.trim()) {
@@ -417,8 +449,14 @@ function createServer(distPath, config, serverConfig = {}) {
417
449
  content = content.replace(/<head>/i, `<head>\n ${iconTag}`);
418
450
  }
419
451
  }
452
+ cachedHtml = content;
453
+ }
454
+
455
+ app.get(/(.*)/, (req, res) => {
456
+ if (req.path.startsWith('/api/')) return res.status(404).json({ error: 'Not found' });
457
+ if (!cachedHtml) return res.status(500).send('index.html not found');
420
458
  res.setHeader('Content-Type', 'text/html');
421
- res.send(content);
459
+ res.send(cachedHtml);
422
460
  });
423
461
  }
424
462
  return app;
@@ -478,7 +516,15 @@ function main() {
478
516
 
479
517
  const server = app.listen(serverConfig.port, serverConfig.host, () => {
480
518
  console.debug(`🚀 ORBIT Chat is running at http://${serverConfig.host}:${serverConfig.port}`);
481
- if (serverConfig.open) execSync(`open http://${serverConfig.host}:${serverConfig.port}`);
519
+ if (serverConfig.open) {
520
+ const url = `http://${serverConfig.host}:${serverConfig.port}`;
521
+ try {
522
+ // Use execFileSync to avoid shell injection — arguments are passed directly
523
+ execFileSync('open', [url], { stdio: 'ignore' });
524
+ } catch {
525
+ console.debug(`Open your browser at ${url}`);
526
+ }
527
+ }
482
528
  });
483
529
  // http-proxy may register multiple close listeners when routing across many adapters.
484
530
  // Raise the listener cap to avoid noisy false-positive MaxListeners warnings.