@xopcai/xopc 0.0.81 → 0.0.82

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 (44) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agents-DOONGaKz.js → agents-Cqh1ts38.js} +1 -1
  4. package/dist/gateway/static/root/assets/{apps-page-Ci17oA_o.js → apps-page-pJ27dsqn.js} +1 -1
  5. package/dist/gateway/static/root/assets/{channels-settings-CARdL-ys.js → channels-settings-wTiWStg9.js} +1 -1
  6. package/dist/gateway/static/root/assets/{channels-status-swr-CUU3faST.js → channels-status-swr-D1KYmOmi.js} +1 -1
  7. package/dist/gateway/static/root/assets/{cron-api-BVQ2n75R.js → cron-api-Y2wfSJVI.js} +1 -1
  8. package/dist/gateway/static/root/assets/{cron-page-x582Y6D5.js → cron-page-B97KU_RG.js} +1 -1
  9. package/dist/gateway/static/root/assets/{dist-XT96cQdR.js → dist-CboA_Css.js} +1 -1
  10. package/dist/gateway/static/root/assets/{extension-debug-page-Czzfrtt5.js → extension-debug-page-DN_zNmpo.js} +1 -1
  11. package/dist/gateway/static/root/assets/{extension-page-B_c5UIqX.js → extension-page-BUXtOzv5.js} +1 -1
  12. package/dist/gateway/static/root/assets/{extension-settings-page-Ckvjgw0_.js → extension-settings-page-C2dX4KCW.js} +1 -1
  13. package/dist/gateway/static/root/assets/{field-primitives-DQpT8iVa.js → field-primitives-B9rOLqdm.js} +1 -1
  14. package/dist/gateway/static/root/assets/{heartbeat-config-api-DKqOuQ0V.js → heartbeat-config-api-DvfiRVrc.js} +1 -1
  15. package/dist/gateway/static/root/assets/{index-Bq3Lg4bG.js → index-DQuaMye9.js} +79 -79
  16. package/dist/gateway/static/root/assets/{logs-page-B3CwJNBq.js → logs-page-BQuBpHcc.js} +1 -1
  17. package/dist/gateway/static/root/assets/{sessions-page-BCNnhz9g.js → sessions-page-BeiFm0Ms.js} +1 -1
  18. package/dist/gateway/static/root/assets/{settings-form-section-CjjEpVYM.js → settings-form-section-2Yu-FASs.js} +1 -1
  19. package/dist/gateway/static/root/assets/{settings-page-B7_PjiHL.js → settings-page-RPAz_Wg_.js} +1 -1
  20. package/dist/gateway/static/root/assets/{skills-page-VrL9TeVF.js → skills-page-Wu4aNWDx.js} +1 -1
  21. package/dist/gateway/static/root/assets/{utils-DQehHvlm.js → utils-D2Gn2qod.js} +1 -1
  22. package/dist/gateway/static/root/assets/{voice-api-key-field-k4FWwgkk.js → voice-api-key-field-BxIGhhEL.js} +1 -1
  23. package/dist/gateway/static/root/index.html +1 -1
  24. package/dist/package.js +1 -1
  25. package/dist/src/agent/service/process-direct-streaming.js +12 -0
  26. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  27. package/dist/src/gateway/hono/app.js +62 -11
  28. package/dist/src/gateway/hono/app.js.map +1 -1
  29. package/dist/src/gateway/hono/middleware/auth.js +27 -3
  30. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  31. package/dist/src/gateway/hono/middleware/logger.d.ts +5 -1
  32. package/dist/src/gateway/hono/middleware/logger.js +41 -5
  33. package/dist/src/gateway/hono/middleware/logger.js.map +1 -1
  34. package/dist/src/gateway/hono/routes/exposure.js +2 -1
  35. package/dist/src/gateway/hono/routes/exposure.js.map +1 -1
  36. package/dist/src/gateway/hono/sse.d.ts +1 -0
  37. package/dist/src/gateway/hono/sse.js +1 -0
  38. package/dist/src/gateway/hono/sse.js.map +1 -1
  39. package/dist/src/gateway/service.js +1 -1
  40. package/dist/src/share/share-rate-limit.js +23 -2
  41. package/dist/src/share/share-rate-limit.js.map +1 -1
  42. package/dist/src/tunnel/tunnel-rate-limit.js +13 -1
  43. package/dist/src/tunnel/tunnel-rate-limit.js.map +1 -1
  44. package/package.json +1 -1
@@ -33,9 +33,9 @@ import { AgentService } from "../agent/service.js";
33
33
  import { ChannelManager } from "../channels/manager.js";
34
34
  import { ConfigHotReloader } from "../config/reload.js";
35
35
  import "../config/index.js";
36
- import { resolveEffectiveGatewayPort } from "./host.js";
37
36
  import { CronService } from "../cron/service.js";
38
37
  import "../cron/index.js";
38
+ import { resolveEffectiveGatewayPort } from "./host.js";
39
39
  import { computeBundledExtensionExtensionsPatch } from "../extensions/bundled-extension-activation.js";
40
40
  import { getExtensionLockfileManager } from "../extensions/lockfile.js";
41
41
  import { installExtensionFromStoreZip, peekExtensionIdFromStoreZip } from "../extensions/install.js";
@@ -1,5 +1,9 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
1
3
  import { createFixedWindowRateLimiter } from "../infra/rate-limit.js";
2
4
  //#region src/share/share-rate-limit.ts
5
+ init_logger();
6
+ const log = createLogger("ShareRateLimit");
3
7
  /** Per-IP rate limiter for public share download routes. */
4
8
  const SHORT_WINDOW_MAX = 60;
5
9
  const SHORT_WINDOW_MS = 6e4;
@@ -17,7 +21,16 @@ function consumeSharePublicLimit(clientIp) {
17
21
  shortLimiters.set(clientIp, shortLimiter);
18
22
  }
19
23
  const shortResult = shortLimiter.consume();
20
- if (!shortResult.allowed) return shortResult;
24
+ if (!shortResult.allowed) {
25
+ log.warn({
26
+ clientIp,
27
+ limit: SHORT_WINDOW_MAX,
28
+ windowSec: Math.round(SHORT_WINDOW_MS / 1e3),
29
+ retryAfterSec: Math.ceil(shortResult.retryAfterMs / 1e3),
30
+ reason: "short_window_exceeded"
31
+ }, `Share public rate limit exceeded: ${SHORT_WINDOW_MAX} req/${SHORT_WINDOW_MS / 1e3}s per IP`);
32
+ return shortResult;
33
+ }
21
34
  let longLimiter = longLimiters.get(clientIp);
22
35
  if (!longLimiter) {
23
36
  longLimiter = createFixedWindowRateLimiter({
@@ -26,7 +39,15 @@ function consumeSharePublicLimit(clientIp) {
26
39
  });
27
40
  longLimiters.set(clientIp, longLimiter);
28
41
  }
29
- return longLimiter.consume();
42
+ const longResult = longLimiter.consume();
43
+ if (!longResult.allowed) log.warn({
44
+ clientIp,
45
+ limit: LONG_WINDOW_MAX,
46
+ windowSec: Math.round(LONG_WINDOW_MS / 1e3),
47
+ retryAfterSec: Math.ceil(longResult.retryAfterMs / 1e3),
48
+ reason: "long_window_exceeded"
49
+ }, `Share public rate limit exceeded: ${LONG_WINDOW_MAX} req/${LONG_WINDOW_MS / 6e4}min per IP`);
50
+ return longResult;
30
51
  }
31
52
  /** @internal */
32
53
  function resetSharePublicLimitsForTests() {
@@ -1 +1 @@
1
- {"version":3,"file":"share-rate-limit.js","names":[],"sources":["../../../src/share/share-rate-limit.ts"],"sourcesContent":["import { createFixedWindowRateLimiter, type RateLimitResult } from '../infra/rate-limit.js';\n\n/** Per-IP rate limiter for public share download routes. */\nconst SHORT_WINDOW_MAX = 60;\nconst SHORT_WINDOW_MS = 60_000;\n\nconst LONG_WINDOW_MAX = 300;\nconst LONG_WINDOW_MS = 15 * 60_000;\n\nconst shortLimiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\nconst longLimiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\nexport function consumeSharePublicLimit(clientIp: string): RateLimitResult {\n let shortLimiter = shortLimiters.get(clientIp);\n if (!shortLimiter) {\n shortLimiter = createFixedWindowRateLimiter({ maxRequests: SHORT_WINDOW_MAX, windowMs: SHORT_WINDOW_MS });\n shortLimiters.set(clientIp, shortLimiter);\n }\n const shortResult = shortLimiter.consume();\n if (!shortResult.allowed) return shortResult;\n\n let longLimiter = longLimiters.get(clientIp);\n if (!longLimiter) {\n longLimiter = createFixedWindowRateLimiter({ maxRequests: LONG_WINDOW_MAX, windowMs: LONG_WINDOW_MS });\n longLimiters.set(clientIp, longLimiter);\n }\n return longLimiter.consume();\n}\n\n/** @internal */\nexport function resetSharePublicLimitsForTests(): void {\n shortLimiters.clear();\n longLimiters.clear();\n}\n"],"mappings":";;;AAGA,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AAExB,MAAM,kBAAkB;AACxB,MAAM,iBAAiB,KAAK;AAE5B,MAAM,gCAAgB,IAAI,KAA8D;AACxF,MAAM,+BAAe,IAAI,KAA8D;AAEvF,SAAgB,wBAAwB,UAAmC;CACzE,IAAI,eAAe,cAAc,IAAI,SAAS;AAC9C,KAAI,CAAC,cAAc;AACjB,iBAAe,6BAA6B;GAAE,aAAa;GAAkB,UAAU;GAAiB,CAAC;AACzG,gBAAc,IAAI,UAAU,aAAa;;CAE3C,MAAM,cAAc,aAAa,SAAS;AAC1C,KAAI,CAAC,YAAY,QAAS,QAAO;CAEjC,IAAI,cAAc,aAAa,IAAI,SAAS;AAC5C,KAAI,CAAC,aAAa;AAChB,gBAAc,6BAA6B;GAAE,aAAa;GAAiB,UAAU;GAAgB,CAAC;AACtG,eAAa,IAAI,UAAU,YAAY;;AAEzC,QAAO,YAAY,SAAS;;;AAI9B,SAAgB,iCAAuC;AACrD,eAAc,OAAO;AACrB,cAAa,OAAO"}
1
+ {"version":3,"file":"share-rate-limit.js","names":[],"sources":["../../../src/share/share-rate-limit.ts"],"sourcesContent":["import { createFixedWindowRateLimiter, type RateLimitResult } from '../infra/rate-limit.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('ShareRateLimit');\n\n/** Per-IP rate limiter for public share download routes. */\nconst SHORT_WINDOW_MAX = 60;\nconst SHORT_WINDOW_MS = 60_000;\n\nconst LONG_WINDOW_MAX = 300;\nconst LONG_WINDOW_MS = 15 * 60_000;\n\nconst shortLimiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\nconst longLimiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\nexport function consumeSharePublicLimit(clientIp: string): RateLimitResult {\n let shortLimiter = shortLimiters.get(clientIp);\n if (!shortLimiter) {\n shortLimiter = createFixedWindowRateLimiter({ maxRequests: SHORT_WINDOW_MAX, windowMs: SHORT_WINDOW_MS });\n shortLimiters.set(clientIp, shortLimiter);\n }\n const shortResult = shortLimiter.consume();\n if (!shortResult.allowed) {\n log.warn(\n {\n clientIp,\n limit: SHORT_WINDOW_MAX,\n windowSec: Math.round(SHORT_WINDOW_MS / 1000),\n retryAfterSec: Math.ceil(shortResult.retryAfterMs / 1000),\n reason: 'short_window_exceeded',\n },\n `Share public rate limit exceeded: ${SHORT_WINDOW_MAX} req/${SHORT_WINDOW_MS / 1000}s per IP`,\n );\n return shortResult;\n }\n\n let longLimiter = longLimiters.get(clientIp);\n if (!longLimiter) {\n longLimiter = createFixedWindowRateLimiter({ maxRequests: LONG_WINDOW_MAX, windowMs: LONG_WINDOW_MS });\n longLimiters.set(clientIp, longLimiter);\n }\n const longResult = longLimiter.consume();\n if (!longResult.allowed) {\n log.warn(\n {\n clientIp,\n limit: LONG_WINDOW_MAX,\n windowSec: Math.round(LONG_WINDOW_MS / 1000),\n retryAfterSec: Math.ceil(longResult.retryAfterMs / 1000),\n reason: 'long_window_exceeded',\n },\n `Share public rate limit exceeded: ${LONG_WINDOW_MAX} req/${LONG_WINDOW_MS / 60000}min per IP`,\n );\n }\n return longResult;\n}\n\n/** @internal */\nexport function resetSharePublicLimitsForTests(): void {\n shortLimiters.clear();\n longLimiters.clear();\n}\n"],"mappings":";;;;aACkD;AAElD,MAAM,MAAM,aAAa,iBAAiB;;AAG1C,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;AAExB,MAAM,kBAAkB;AACxB,MAAM,iBAAiB,KAAK;AAE5B,MAAM,gCAAgB,IAAI,KAA8D;AACxF,MAAM,+BAAe,IAAI,KAA8D;AAEvF,SAAgB,wBAAwB,UAAmC;CACzE,IAAI,eAAe,cAAc,IAAI,SAAS;AAC9C,KAAI,CAAC,cAAc;AACjB,iBAAe,6BAA6B;GAAE,aAAa;GAAkB,UAAU;GAAiB,CAAC;AACzG,gBAAc,IAAI,UAAU,aAAa;;CAE3C,MAAM,cAAc,aAAa,SAAS;AAC1C,KAAI,CAAC,YAAY,SAAS;AACxB,MAAI,KACF;GACE;GACA,OAAO;GACP,WAAW,KAAK,MAAM,kBAAkB,IAAK;GAC7C,eAAe,KAAK,KAAK,YAAY,eAAe,IAAK;GACzD,QAAQ;GACT,EACD,qCAAqC,iBAAiB,OAAO,kBAAkB,IAAK,UACrF;AACD,SAAO;;CAGT,IAAI,cAAc,aAAa,IAAI,SAAS;AAC5C,KAAI,CAAC,aAAa;AAChB,gBAAc,6BAA6B;GAAE,aAAa;GAAiB,UAAU;GAAgB,CAAC;AACtG,eAAa,IAAI,UAAU,YAAY;;CAEzC,MAAM,aAAa,YAAY,SAAS;AACxC,KAAI,CAAC,WAAW,QACd,KAAI,KACF;EACE;EACA,OAAO;EACP,WAAW,KAAK,MAAM,iBAAiB,IAAK;EAC5C,eAAe,KAAK,KAAK,WAAW,eAAe,IAAK;EACxD,QAAQ;EACT,EACD,qCAAqC,gBAAgB,OAAO,iBAAiB,IAAM,YACpF;AAEH,QAAO;;;AAIT,SAAgB,iCAAuC;AACrD,eAAc,OAAO;AACrB,cAAa,OAAO"}
@@ -1,6 +1,10 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
1
3
  import { createFixedWindowRateLimiter } from "../infra/rate-limit.js";
2
4
  import { createHash } from "node:crypto";
3
5
  //#region src/tunnel/tunnel-rate-limit.ts
6
+ init_logger();
7
+ const log = createLogger("TunnelRateLimit");
4
8
  /** Mutating tunnel API calls per gateway token (consent / start / stop / release). */
5
9
  const TUNNEL_MUTATION_MAX = 12;
6
10
  const TUNNEL_MUTATION_WINDOW_MS = 5 * 6e4;
@@ -18,7 +22,15 @@ function consumeTunnelMutationLimit(token) {
18
22
  });
19
23
  limiters.set(key, limiter);
20
24
  }
21
- return limiter.consume();
25
+ const result = limiter.consume();
26
+ if (!result.allowed) log.warn({
27
+ tokenPrefix: token.slice(0, 8),
28
+ limit: TUNNEL_MUTATION_MAX,
29
+ windowSec: Math.round(TUNNEL_MUTATION_WINDOW_MS / 1e3),
30
+ retryAfterSec: Math.ceil(result.retryAfterMs / 1e3),
31
+ reason: "tunnel_mutation_limit"
32
+ }, `Tunnel mutation rate limit exceeded: ${TUNNEL_MUTATION_MAX} mutations per ${TUNNEL_MUTATION_WINDOW_MS / 6e4}min`);
33
+ return result;
22
34
  }
23
35
  /** @internal Test helper */
24
36
  function resetTunnelMutationLimitsForTests() {
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel-rate-limit.js","names":[],"sources":["../../../src/tunnel/tunnel-rate-limit.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport { createFixedWindowRateLimiter, type RateLimitResult } from '../infra/rate-limit.js';\n\n/** Mutating tunnel API calls per gateway token (consent / start / stop / release). */\nconst TUNNEL_MUTATION_MAX = 12;\nconst TUNNEL_MUTATION_WINDOW_MS = 5 * 60_000;\n\nconst limiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\nfunction limiterKeyFromToken(token: string): string {\n return createHash('sha256').update(token, 'utf8').digest('hex').slice(0, 16);\n}\n\nexport function consumeTunnelMutationLimit(token: string): RateLimitResult {\n const key = limiterKeyFromToken(token);\n let limiter = limiters.get(key);\n if (!limiter) {\n limiter = createFixedWindowRateLimiter({\n maxRequests: TUNNEL_MUTATION_MAX,\n windowMs: TUNNEL_MUTATION_WINDOW_MS,\n });\n limiters.set(key, limiter);\n }\n return limiter.consume();\n}\n\n/** @internal Test helper */\nexport function resetTunnelMutationLimitsForTests(): void {\n limiters.clear();\n}\n"],"mappings":";;;;AAKA,MAAM,sBAAsB;AAC5B,MAAM,4BAA4B,IAAI;AAEtC,MAAM,2BAAW,IAAI,KAA8D;AAEnF,SAAS,oBAAoB,OAAuB;AAClD,QAAO,WAAW,SAAS,CAAC,OAAO,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG;;AAG9E,SAAgB,2BAA2B,OAAgC;CACzE,MAAM,MAAM,oBAAoB,MAAM;CACtC,IAAI,UAAU,SAAS,IAAI,IAAI;AAC/B,KAAI,CAAC,SAAS;AACZ,YAAU,6BAA6B;GACrC,aAAa;GACb,UAAU;GACX,CAAC;AACF,WAAS,IAAI,KAAK,QAAQ;;AAE5B,QAAO,QAAQ,SAAS;;;AAI1B,SAAgB,oCAA0C;AACxD,UAAS,OAAO"}
1
+ {"version":3,"file":"tunnel-rate-limit.js","names":[],"sources":["../../../src/tunnel/tunnel-rate-limit.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport { createFixedWindowRateLimiter, type RateLimitResult } from '../infra/rate-limit.js';\nimport { createLogger } from '../utils/logger.js';\n\nconst log = createLogger('TunnelRateLimit');\n\n/** Mutating tunnel API calls per gateway token (consent / start / stop / release). */\nconst TUNNEL_MUTATION_MAX = 12;\nconst TUNNEL_MUTATION_WINDOW_MS = 5 * 60_000;\n\nconst limiters = new Map<string, ReturnType<typeof createFixedWindowRateLimiter>>();\n\nfunction limiterKeyFromToken(token: string): string {\n return createHash('sha256').update(token, 'utf8').digest('hex').slice(0, 16);\n}\n\nexport function consumeTunnelMutationLimit(token: string): RateLimitResult {\n const key = limiterKeyFromToken(token);\n let limiter = limiters.get(key);\n if (!limiter) {\n limiter = createFixedWindowRateLimiter({\n maxRequests: TUNNEL_MUTATION_MAX,\n windowMs: TUNNEL_MUTATION_WINDOW_MS,\n });\n limiters.set(key, limiter);\n }\n const result = limiter.consume();\n if (!result.allowed) {\n log.warn(\n {\n tokenPrefix: token.slice(0, 8),\n limit: TUNNEL_MUTATION_MAX,\n windowSec: Math.round(TUNNEL_MUTATION_WINDOW_MS / 1000),\n retryAfterSec: Math.ceil(result.retryAfterMs / 1000),\n reason: 'tunnel_mutation_limit',\n },\n `Tunnel mutation rate limit exceeded: ${TUNNEL_MUTATION_MAX} mutations per ${TUNNEL_MUTATION_WINDOW_MS / 60000}min`,\n );\n }\n return result;\n}\n\n/** @internal Test helper */\nexport function resetTunnelMutationLimitsForTests(): void {\n limiters.clear();\n}\n"],"mappings":";;;;;aAGkD;AAElD,MAAM,MAAM,aAAa,kBAAkB;;AAG3C,MAAM,sBAAsB;AAC5B,MAAM,4BAA4B,IAAI;AAEtC,MAAM,2BAAW,IAAI,KAA8D;AAEnF,SAAS,oBAAoB,OAAuB;AAClD,QAAO,WAAW,SAAS,CAAC,OAAO,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG;;AAG9E,SAAgB,2BAA2B,OAAgC;CACzE,MAAM,MAAM,oBAAoB,MAAM;CACtC,IAAI,UAAU,SAAS,IAAI,IAAI;AAC/B,KAAI,CAAC,SAAS;AACZ,YAAU,6BAA6B;GACrC,aAAa;GACb,UAAU;GACX,CAAC;AACF,WAAS,IAAI,KAAK,QAAQ;;CAE5B,MAAM,SAAS,QAAQ,SAAS;AAChC,KAAI,CAAC,OAAO,QACV,KAAI,KACF;EACE,aAAa,MAAM,MAAM,GAAG,EAAE;EAC9B,OAAO;EACP,WAAW,KAAK,MAAM,4BAA4B,IAAK;EACvD,eAAe,KAAK,KAAK,OAAO,eAAe,IAAK;EACpD,QAAQ;EACT,EACD,wCAAwC,oBAAoB,iBAAiB,4BAA4B,IAAM,KAChH;AAEH,QAAO;;;AAIT,SAAgB,oCAA0C;AACxD,UAAS,OAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.81",
3
+ "version": "0.0.82",
4
4
  "description": "The OPC workstation that grows with you: AI assistant for One Person Companies — CLI, gateway, multi-channel (Telegram/WeChat), 20+ LLM providers via pi-ai, extensions and skills.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",