@techysy/10router 1.5.1 → 1.6.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 (662) hide show
  1. package/app/.next-cli-build/BUILD_ID +1 -1
  2. package/app/.next-cli-build/app-path-routes-manifest.json +6 -6
  3. package/app/.next-cli-build/build-manifest.json +2 -2
  4. package/app/.next-cli-build/prerender-manifest.json +18 -18
  5. package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page.js +1 -1
  6. package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
  7. package/app/.next-cli-build/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
  8. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +2 -2
  9. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
  10. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
  11. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
  12. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
  13. package/app/.next-cli-build/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
  14. package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page.js +1 -1
  15. package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
  16. package/app/.next-cli-build/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
  17. package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page.js +1 -1
  18. package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
  19. package/app/.next-cli-build/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
  20. package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js +1 -1
  21. package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
  22. package/app/.next-cli-build/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
  23. package/app/.next-cli-build/server/app/(dashboard)/dashboard/experimental/page.js +1 -1
  24. package/app/.next-cli-build/server/app/(dashboard)/dashboard/experimental/page.js.nft.json +1 -1
  25. package/app/.next-cli-build/server/app/(dashboard)/dashboard/experimental/page_client-reference-manifest.js +1 -1
  26. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js +2 -2
  27. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page.js.nft.json +1 -1
  28. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/[id]/page_client-reference-manifest.js +1 -1
  29. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page.js +1 -1
  30. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page.js.nft.json +1 -1
  31. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/[kind]/page_client-reference-manifest.js +1 -1
  32. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js +1 -1
  33. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page.js.nft.json +1 -1
  34. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/combo/[id]/page_client-reference-manifest.js +1 -1
  35. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page.js +1 -1
  36. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page.js.nft.json +1 -1
  37. package/app/.next-cli-build/server/app/(dashboard)/dashboard/media-providers/web/page_client-reference-manifest.js +1 -1
  38. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page.js +1 -1
  39. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page.js.nft.json +1 -1
  40. package/app/.next-cli-build/server/app/(dashboard)/dashboard/mitm/page_client-reference-manifest.js +1 -1
  41. package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js +1 -1
  42. package/app/.next-cli-build/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
  43. package/app/.next-cli-build/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
  44. package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page.js +1 -1
  45. package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
  46. package/app/.next-cli-build/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
  47. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page.js +3 -3
  48. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
  49. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
  50. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page.js +1 -1
  51. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
  52. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
  53. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page.js +1 -1
  54. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
  55. package/app/.next-cli-build/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
  56. package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page.js +1 -1
  57. package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
  58. package/app/.next-cli-build/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
  59. package/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page.js +1 -1
  60. package/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page.js.nft.json +1 -1
  61. package/app/.next-cli-build/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
  62. package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page.js +1 -1
  63. package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
  64. package/app/.next-cli-build/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
  65. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page.js +1 -1
  66. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page.js.nft.json +1 -1
  67. package/app/.next-cli-build/server/app/(dashboard)/dashboard/skills/page_client-reference-manifest.js +1 -1
  68. package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page.js +1 -1
  69. package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page.js.nft.json +1 -1
  70. package/app/.next-cli-build/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
  71. package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page.js +1 -1
  72. package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page.js.nft.json +1 -1
  73. package/app/.next-cli-build/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
  74. package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page.js +1 -1
  75. package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
  76. package/app/.next-cli-build/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
  77. package/app/.next-cli-build/server/app/_global-error/page.js.nft.json +1 -1
  78. package/app/.next-cli-build/server/app/_global-error/page_client-reference-manifest.js +1 -1
  79. package/app/.next-cli-build/server/app/_global-error.html +1 -1
  80. package/app/.next-cli-build/server/app/_global-error.rsc +1 -1
  81. package/app/.next-cli-build/server/app/_global-error.segments/_full.segment.rsc +1 -1
  82. package/app/.next-cli-build/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  83. package/app/.next-cli-build/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  84. package/app/.next-cli-build/server/app/_not-found/page.js +1 -1
  85. package/app/.next-cli-build/server/app/_not-found/page.js.nft.json +1 -1
  86. package/app/.next-cli-build/server/app/_not-found/page_client-reference-manifest.js +1 -1
  87. package/app/.next-cli-build/server/app/_not-found.html +2 -2
  88. package/app/.next-cli-build/server/app/_not-found.rsc +6 -6
  89. package/app/.next-cli-build/server/app/_not-found.segments/_full.segment.rsc +6 -6
  90. package/app/.next-cli-build/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +6 -6
  91. package/app/.next-cli-build/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  92. package/app/.next-cli-build/server/app/api/auth/login/route.js +1 -1
  93. package/app/.next-cli-build/server/app/api/auth/login/route.js.nft.json +1 -1
  94. package/app/.next-cli-build/server/app/api/auth/logout/route.js.nft.json +1 -1
  95. package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js +1 -1
  96. package/app/.next-cli-build/server/app/api/auth/oidc/callback/route.js.nft.json +1 -1
  97. package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js +1 -1
  98. package/app/.next-cli-build/server/app/api/auth/oidc/start/route.js.nft.json +1 -1
  99. package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js +1 -1
  100. package/app/.next-cli-build/server/app/api/auth/oidc/test/route.js.nft.json +1 -1
  101. package/app/.next-cli-build/server/app/api/auth/reset-password/route.js +1 -1
  102. package/app/.next-cli-build/server/app/api/auth/reset-password/route.js.nft.json +1 -1
  103. package/app/.next-cli-build/server/app/api/auth/saml/acs/route.js +1 -1
  104. package/app/.next-cli-build/server/app/api/auth/saml/acs/route.js.nft.json +1 -1
  105. package/app/.next-cli-build/server/app/api/auth/saml/metadata/route.js +1 -1
  106. package/app/.next-cli-build/server/app/api/auth/saml/metadata/route.js.nft.json +1 -1
  107. package/app/.next-cli-build/server/app/api/auth/saml/start/route.js +1 -1
  108. package/app/.next-cli-build/server/app/api/auth/saml/start/route.js.nft.json +1 -1
  109. package/app/.next-cli-build/server/app/api/auth/saml/test/route.js +1 -1
  110. package/app/.next-cli-build/server/app/api/auth/saml/test/route.js.nft.json +1 -1
  111. package/app/.next-cli-build/server/app/api/auth/status/route.js +1 -1
  112. package/app/.next-cli-build/server/app/api/auth/status/route.js.nft.json +1 -1
  113. package/app/.next-cli-build/server/app/api/auth/verify-password/route.js +1 -1
  114. package/app/.next-cli-build/server/app/api/auth/verify-password/route.js.nft.json +1 -1
  115. package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js +1 -1
  116. package/app/.next-cli-build/server/app/api/cli-tools/all-statuses/route.js.nft.json +1 -1
  117. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js +1 -1
  118. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
  119. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js +1 -1
  120. package/app/.next-cli-build/server/app/api/cli-tools/antigravity-mitm/route.js.nft.json +1 -1
  121. package/app/.next-cli-build/server/app/api/cli-tools/claude-profiles/route.js +1 -1
  122. package/app/.next-cli-build/server/app/api/cli-tools/claude-profiles/route.js.nft.json +1 -1
  123. package/app/.next-cli-build/server/app/api/cli-tools/claude-settings/route.js.nft.json +1 -1
  124. package/app/.next-cli-build/server/app/api/cli-tools/cline-settings/route.js.nft.json +1 -1
  125. package/app/.next-cli-build/server/app/api/cli-tools/codex-profiles/route.js.nft.json +1 -1
  126. package/app/.next-cli-build/server/app/api/cli-tools/codex-settings/route.js.nft.json +1 -1
  127. package/app/.next-cli-build/server/app/api/cli-tools/copilot-settings/route.js.nft.json +1 -1
  128. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-registry/route.js.nft.json +1 -1
  129. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js +1 -1
  130. package/app/.next-cli-build/server/app/api/cli-tools/cowork-mcp-tools/route.js.nft.json +1 -1
  131. package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js +1 -1
  132. package/app/.next-cli-build/server/app/api/cli-tools/cowork-settings/route.js.nft.json +1 -1
  133. package/app/.next-cli-build/server/app/api/cli-tools/deepseek-tui-settings/route.js.nft.json +1 -1
  134. package/app/.next-cli-build/server/app/api/cli-tools/devin-settings/route.js.nft.json +1 -1
  135. package/app/.next-cli-build/server/app/api/cli-tools/droid-settings/route.js.nft.json +1 -1
  136. package/app/.next-cli-build/server/app/api/cli-tools/grok-build-settings/route.js.nft.json +1 -1
  137. package/app/.next-cli-build/server/app/api/cli-tools/hermes-settings/route.js.nft.json +1 -1
  138. package/app/.next-cli-build/server/app/api/cli-tools/jcode-settings/route.js.nft.json +1 -1
  139. package/app/.next-cli-build/server/app/api/cli-tools/kilo-settings/route.js.nft.json +1 -1
  140. package/app/.next-cli-build/server/app/api/cli-tools/openclaw-settings/route.js.nft.json +1 -1
  141. package/app/.next-cli-build/server/app/api/cli-tools/opencode-settings/route.js.nft.json +1 -1
  142. package/app/.next-cli-build/server/app/api/combos/[id]/route.js +1 -1
  143. package/app/.next-cli-build/server/app/api/combos/[id]/route.js.nft.json +1 -1
  144. package/app/.next-cli-build/server/app/api/combos/route.js +1 -1
  145. package/app/.next-cli-build/server/app/api/combos/route.js.nft.json +1 -1
  146. package/app/.next-cli-build/server/app/api/external-quota/[source]/route.js +1 -1
  147. package/app/.next-cli-build/server/app/api/external-quota/[source]/route.js.nft.json +1 -1
  148. package/app/.next-cli-build/server/app/api/gateway-probe/route.js.nft.json +1 -1
  149. package/app/.next-cli-build/server/app/api/headroom/extras/route.js.nft.json +1 -1
  150. package/app/.next-cli-build/server/app/api/headroom/proxy/[...path]/route.js +1 -1
  151. package/app/.next-cli-build/server/app/api/headroom/proxy/[...path]/route.js.nft.json +1 -1
  152. package/app/.next-cli-build/server/app/api/headroom/restart/route.js +1 -1
  153. package/app/.next-cli-build/server/app/api/headroom/restart/route.js.nft.json +1 -1
  154. package/app/.next-cli-build/server/app/api/headroom/start/route.js +1 -1
  155. package/app/.next-cli-build/server/app/api/headroom/start/route.js.nft.json +1 -1
  156. package/app/.next-cli-build/server/app/api/headroom/status/route.js +1 -1
  157. package/app/.next-cli-build/server/app/api/headroom/status/route.js.nft.json +1 -1
  158. package/app/.next-cli-build/server/app/api/headroom/stop/route.js.nft.json +1 -1
  159. package/app/.next-cli-build/server/app/api/health/route.js.nft.json +1 -1
  160. package/app/.next-cli-build/server/app/api/init/route.js.nft.json +1 -1
  161. package/app/.next-cli-build/server/app/api/keys/[id]/route.js +1 -1
  162. package/app/.next-cli-build/server/app/api/keys/[id]/route.js.nft.json +1 -1
  163. package/app/.next-cli-build/server/app/api/keys/rotate/route.js +1 -1
  164. package/app/.next-cli-build/server/app/api/keys/rotate/route.js.nft.json +1 -1
  165. package/app/.next-cli-build/server/app/api/keys/route.js +1 -1
  166. package/app/.next-cli-build/server/app/api/keys/route.js.nft.json +1 -1
  167. package/app/.next-cli-build/server/app/api/locale/route.js.nft.json +1 -1
  168. package/app/.next-cli-build/server/app/api/mcp/[plugin]/message/route.js.nft.json +1 -1
  169. package/app/.next-cli-build/server/app/api/mcp/[plugin]/sse/route.js.nft.json +1 -1
  170. package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js +1 -1
  171. package/app/.next-cli-build/server/app/api/media-providers/tts/deepgram/voices/route.js.nft.json +1 -1
  172. package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js +1 -1
  173. package/app/.next-cli-build/server/app/api/media-providers/tts/elevenlabs/voices/route.js.nft.json +1 -1
  174. package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js +1 -1
  175. package/app/.next-cli-build/server/app/api/media-providers/tts/inworld/voices/route.js.nft.json +1 -1
  176. package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js +1 -1
  177. package/app/.next-cli-build/server/app/api/media-providers/tts/minimax/voices/route.js.nft.json +1 -1
  178. package/app/.next-cli-build/server/app/api/media-providers/tts/voices/route.js +1 -1
  179. package/app/.next-cli-build/server/app/api/media-providers/tts/voices/route.js.nft.json +1 -1
  180. package/app/.next-cli-build/server/app/api/models/alias/route.js +1 -1
  181. package/app/.next-cli-build/server/app/api/models/alias/route.js.nft.json +1 -1
  182. package/app/.next-cli-build/server/app/api/models/availability/route.js +1 -1
  183. package/app/.next-cli-build/server/app/api/models/availability/route.js.nft.json +1 -1
  184. package/app/.next-cli-build/server/app/api/models/caps/route.js +1 -1
  185. package/app/.next-cli-build/server/app/api/models/caps/route.js.nft.json +1 -1
  186. package/app/.next-cli-build/server/app/api/models/custom/bulk/route.js.nft.json +1 -1
  187. package/app/.next-cli-build/server/app/api/models/custom/route.js +1 -1
  188. package/app/.next-cli-build/server/app/api/models/custom/route.js.nft.json +1 -1
  189. package/app/.next-cli-build/server/app/api/models/disabled/route.js +1 -1
  190. package/app/.next-cli-build/server/app/api/models/disabled/route.js.nft.json +1 -1
  191. package/app/.next-cli-build/server/app/api/models/route.js +1 -1
  192. package/app/.next-cli-build/server/app/api/models/route.js.nft.json +1 -1
  193. package/app/.next-cli-build/server/app/api/models/test/route.js +1 -1
  194. package/app/.next-cli-build/server/app/api/models/test/route.js.nft.json +1 -1
  195. package/app/.next-cli-build/server/app/api/network/egress-region/route.js.nft.json +1 -1
  196. package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js +1 -1
  197. package/app/.next-cli-build/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
  198. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/route.js +1 -1
  199. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/bulk-import/route.js.nft.json +1 -1
  200. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/checkin/route.js.nft.json +1 -1
  201. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/claim-compensation/route.js.nft.json +1 -1
  202. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/export/route.js +1 -1
  203. package/app/.next-cli-build/server/app/api/oauth/codebuddy-cn/export/route.js.nft.json +1 -1
  204. package/app/.next-cli-build/server/app/api/oauth/codex/bulk-import/route.js +1 -1
  205. package/app/.next-cli-build/server/app/api/oauth/codex/bulk-import/route.js.nft.json +1 -1
  206. package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js +1 -1
  207. package/app/.next-cli-build/server/app/api/oauth/codex/import-token/route.js.nft.json +1 -1
  208. package/app/.next-cli-build/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
  209. package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js +1 -1
  210. package/app/.next-cli-build/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
  211. package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js +1 -1
  212. package/app/.next-cli-build/server/app/api/oauth/gitlab/pat/route.js.nft.json +1 -1
  213. package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js +1 -1
  214. package/app/.next-cli-build/server/app/api/oauth/iflow/cookie/route.js.nft.json +1 -1
  215. package/app/.next-cli-build/server/app/api/oauth/kiro/api-key/route.js +1 -1
  216. package/app/.next-cli-build/server/app/api/oauth/kiro/api-key/route.js.nft.json +1 -1
  217. package/app/.next-cli-build/server/app/api/oauth/kiro/auto-import/route.js.nft.json +1 -1
  218. package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js +1 -1
  219. package/app/.next-cli-build/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
  220. package/app/.next-cli-build/server/app/api/oauth/kiro/import-cli-proxy/route.js +1 -1
  221. package/app/.next-cli-build/server/app/api/oauth/kiro/import-cli-proxy/route.js.nft.json +1 -1
  222. package/app/.next-cli-build/server/app/api/oauth/kiro/social-authorize/route.js +1 -1
  223. package/app/.next-cli-build/server/app/api/oauth/kiro/social-authorize/route.js.nft.json +1 -1
  224. package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js +1 -1
  225. package/app/.next-cli-build/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
  226. package/app/.next-cli-build/server/app/api/oauth/qoder/checkin/route.js.nft.json +1 -1
  227. package/app/.next-cli-build/server/app/api/oauth/qoder-cn/checkin/route.js.nft.json +1 -1
  228. package/app/.next-cli-build/server/app/api/oauth/transfer/export/route.js +1 -1
  229. package/app/.next-cli-build/server/app/api/oauth/transfer/export/route.js.nft.json +1 -1
  230. package/app/.next-cli-build/server/app/api/oauth/transfer/import/route.js +1 -1
  231. package/app/.next-cli-build/server/app/api/oauth/transfer/import/route.js.nft.json +1 -1
  232. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/api-key/route.js +1 -1
  233. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/api-key/route.js.nft.json +1 -1
  234. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/auto-import/route.js +1 -1
  235. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/auto-import/route.js.nft.json +1 -1
  236. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/desktop-kill/route.js.nft.json +1 -1
  237. package/app/.next-cli-build/server/app/api/oauth/xiaomi-mimo/desktop-status/route.js.nft.json +1 -1
  238. package/app/.next-cli-build/server/app/api/oauth/zed/auto-import/route.js.nft.json +1 -1
  239. package/app/.next-cli-build/server/app/api/oauth/zed/import/route.js +1 -1
  240. package/app/.next-cli-build/server/app/api/oauth/zed/import/route.js.nft.json +1 -1
  241. package/app/.next-cli-build/server/app/api/pricing/route.js +1 -1
  242. package/app/.next-cli-build/server/app/api/pricing/route.js.nft.json +1 -1
  243. package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js +1 -1
  244. package/app/.next-cli-build/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
  245. package/app/.next-cli-build/server/app/api/provider-nodes/route.js +1 -1
  246. package/app/.next-cli-build/server/app/api/provider-nodes/route.js.nft.json +1 -1
  247. package/app/.next-cli-build/server/app/api/provider-nodes/validate/route.js +1 -1
  248. package/app/.next-cli-build/server/app/api/provider-nodes/validate/route.js.nft.json +1 -1
  249. package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js +1 -1
  250. package/app/.next-cli-build/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
  251. package/app/.next-cli-build/server/app/api/providers/[id]/route.js +1 -1
  252. package/app/.next-cli-build/server/app/api/providers/[id]/route.js.nft.json +1 -1
  253. package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js +1 -1
  254. package/app/.next-cli-build/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
  255. package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js +1 -1
  256. package/app/.next-cli-build/server/app/api/providers/[id]/test-models/route.js.nft.json +1 -1
  257. package/app/.next-cli-build/server/app/api/providers/client/route.js +1 -1
  258. package/app/.next-cli-build/server/app/api/providers/client/route.js.nft.json +1 -1
  259. package/app/.next-cli-build/server/app/api/providers/kilo/free-models/route.js.nft.json +1 -1
  260. package/app/.next-cli-build/server/app/api/providers/route.js +1 -1
  261. package/app/.next-cli-build/server/app/api/providers/route.js.nft.json +1 -1
  262. package/app/.next-cli-build/server/app/api/providers/suggested-models/route.js.nft.json +1 -1
  263. package/app/.next-cli-build/server/app/api/providers/test-batch/route.js +1 -1
  264. package/app/.next-cli-build/server/app/api/providers/test-batch/route.js.nft.json +1 -1
  265. package/app/.next-cli-build/server/app/api/providers/validate/route.js +1 -1
  266. package/app/.next-cli-build/server/app/api/providers/validate/route.js.nft.json +1 -1
  267. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js +1 -1
  268. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/route.js.nft.json +1 -1
  269. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js +1 -1
  270. package/app/.next-cli-build/server/app/api/proxy-pools/[id]/test/route.js.nft.json +1 -1
  271. package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js +1 -1
  272. package/app/.next-cli-build/server/app/api/proxy-pools/cloudflare-deploy/route.js.nft.json +1 -1
  273. package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js +1 -1
  274. package/app/.next-cli-build/server/app/api/proxy-pools/deno-deploy/route.js.nft.json +1 -1
  275. package/app/.next-cli-build/server/app/api/proxy-pools/route.js +1 -1
  276. package/app/.next-cli-build/server/app/api/proxy-pools/route.js.nft.json +1 -1
  277. package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js +1 -1
  278. package/app/.next-cli-build/server/app/api/proxy-pools/vercel-deploy/route.js.nft.json +1 -1
  279. package/app/.next-cli-build/server/app/api/pxpipe/health/route.js.nft.json +1 -1
  280. package/app/.next-cli-build/server/app/api/pxpipe/install/route.js.nft.json +1 -1
  281. package/app/.next-cli-build/server/app/api/pxpipe/logs/route.js.nft.json +1 -1
  282. package/app/.next-cli-build/server/app/api/pxpipe/restart/route.js.nft.json +1 -1
  283. package/app/.next-cli-build/server/app/api/pxpipe/start/route.js +1 -1
  284. package/app/.next-cli-build/server/app/api/pxpipe/start/route.js.nft.json +1 -1
  285. package/app/.next-cli-build/server/app/api/pxpipe/stats/route.js.nft.json +1 -1
  286. package/app/.next-cli-build/server/app/api/pxpipe/status/route.js +1 -1
  287. package/app/.next-cli-build/server/app/api/pxpipe/status/route.js.nft.json +1 -1
  288. package/app/.next-cli-build/server/app/api/pxpipe/stop/route.js.nft.json +1 -1
  289. package/app/.next-cli-build/server/app/api/security/status/route.js +1 -1
  290. package/app/.next-cli-build/server/app/api/security/status/route.js.nft.json +1 -1
  291. package/app/.next-cli-build/server/app/api/settings/database/import-usage/route.js +1 -1
  292. package/app/.next-cli-build/server/app/api/settings/database/import-usage/route.js.nft.json +1 -1
  293. package/app/.next-cli-build/server/app/api/settings/database/route.js +1 -1
  294. package/app/.next-cli-build/server/app/api/settings/database/route.js.nft.json +1 -1
  295. package/app/.next-cli-build/server/app/api/settings/proxy-test/route.js.nft.json +1 -1
  296. package/app/.next-cli-build/server/app/api/settings/require-login/route.js +1 -1
  297. package/app/.next-cli-build/server/app/api/settings/require-login/route.js.nft.json +1 -1
  298. package/app/.next-cli-build/server/app/api/settings/route.js +2 -2
  299. package/app/.next-cli-build/server/app/api/settings/route.js.nft.json +1 -1
  300. package/app/.next-cli-build/server/app/api/shutdown/route.js.nft.json +1 -1
  301. package/app/.next-cli-build/server/app/api/tags/route.js.nft.json +1 -1
  302. package/app/.next-cli-build/server/app/api/translator/console-logs/route.js +1 -1
  303. package/app/.next-cli-build/server/app/api/translator/console-logs/route.js.nft.json +1 -1
  304. package/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js +2 -2
  305. package/app/.next-cli-build/server/app/api/translator/console-logs/stream/route.js.nft.json +1 -1
  306. package/app/.next-cli-build/server/app/api/translator/load/route.js.nft.json +1 -1
  307. package/app/.next-cli-build/server/app/api/translator/save/route.js.nft.json +1 -1
  308. package/app/.next-cli-build/server/app/api/translator/send/route.js +1 -1
  309. package/app/.next-cli-build/server/app/api/translator/send/route.js.nft.json +1 -1
  310. package/app/.next-cli-build/server/app/api/translator/translate/route.js +1 -1
  311. package/app/.next-cli-build/server/app/api/translator/translate/route.js.nft.json +1 -1
  312. package/app/.next-cli-build/server/app/api/tunnel/disable/route.js +1 -1
  313. package/app/.next-cli-build/server/app/api/tunnel/disable/route.js.nft.json +1 -1
  314. package/app/.next-cli-build/server/app/api/tunnel/enable/route.js +1 -1
  315. package/app/.next-cli-build/server/app/api/tunnel/enable/route.js.nft.json +1 -1
  316. package/app/.next-cli-build/server/app/api/tunnel/status/route.js +1 -1
  317. package/app/.next-cli-build/server/app/api/tunnel/status/route.js.nft.json +1 -1
  318. package/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js +1 -1
  319. package/app/.next-cli-build/server/app/api/tunnel/tailscale-check/route.js.nft.json +1 -1
  320. package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js +1 -1
  321. package/app/.next-cli-build/server/app/api/tunnel/tailscale-disable/route.js.nft.json +1 -1
  322. package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js +1 -1
  323. package/app/.next-cli-build/server/app/api/tunnel/tailscale-enable/route.js.nft.json +1 -1
  324. package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js +1 -1
  325. package/app/.next-cli-build/server/app/api/tunnel/tailscale-install/route.js.nft.json +1 -1
  326. package/app/.next-cli-build/server/app/api/usage/[connectionId]/claude-reset/route.js +1 -1
  327. package/app/.next-cli-build/server/app/api/usage/[connectionId]/claude-reset/route.js.nft.json +1 -1
  328. package/app/.next-cli-build/server/app/api/usage/[connectionId]/codex-reset-credits/route.js +1 -1
  329. package/app/.next-cli-build/server/app/api/usage/[connectionId]/codex-reset-credits/route.js.nft.json +1 -1
  330. package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js +1 -1
  331. package/app/.next-cli-build/server/app/api/usage/[connectionId]/route.js.nft.json +1 -1
  332. package/app/.next-cli-build/server/app/api/usage/chart/route.js +1 -1
  333. package/app/.next-cli-build/server/app/api/usage/chart/route.js.nft.json +1 -1
  334. package/app/.next-cli-build/server/app/api/usage/dashboard/route.js +1 -1
  335. package/app/.next-cli-build/server/app/api/usage/dashboard/route.js.nft.json +1 -1
  336. package/app/.next-cli-build/server/app/api/usage/history/route.js +1 -1
  337. package/app/.next-cli-build/server/app/api/usage/history/route.js.nft.json +1 -1
  338. package/app/.next-cli-build/server/app/api/usage/logs/route.js +1 -1
  339. package/app/.next-cli-build/server/app/api/usage/logs/route.js.nft.json +1 -1
  340. package/app/.next-cli-build/server/app/api/usage/providers/route.js +1 -1
  341. package/app/.next-cli-build/server/app/api/usage/providers/route.js.nft.json +1 -1
  342. package/app/.next-cli-build/server/app/api/usage/quotas/route.js +1 -1
  343. package/app/.next-cli-build/server/app/api/usage/quotas/route.js.nft.json +1 -1
  344. package/app/.next-cli-build/server/app/api/usage/request-details/route.js +1 -1
  345. package/app/.next-cli-build/server/app/api/usage/request-details/route.js.nft.json +1 -1
  346. package/app/.next-cli-build/server/app/api/usage/request-logs/route.js +1 -1
  347. package/app/.next-cli-build/server/app/api/usage/request-logs/route.js.nft.json +1 -1
  348. package/app/.next-cli-build/server/app/api/usage/stats/route.js +1 -1
  349. package/app/.next-cli-build/server/app/api/usage/stats/route.js.nft.json +1 -1
  350. package/app/.next-cli-build/server/app/api/usage/stream/route.js +1 -1
  351. package/app/.next-cli-build/server/app/api/usage/stream/route.js.nft.json +1 -1
  352. package/app/.next-cli-build/server/app/api/v1/api/chat/route.js +1 -1
  353. package/app/.next-cli-build/server/app/api/v1/api/chat/route.js.nft.json +1 -1
  354. package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js +1 -1
  355. package/app/.next-cli-build/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
  356. package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js +1 -1
  357. package/app/.next-cli-build/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
  358. package/app/.next-cli-build/server/app/api/v1/audio/voices/route.js +1 -1
  359. package/app/.next-cli-build/server/app/api/v1/audio/voices/route.js.nft.json +1 -1
  360. package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js +1 -1
  361. package/app/.next-cli-build/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
  362. package/app/.next-cli-build/server/app/api/v1/embeddings/route.js +1 -1
  363. package/app/.next-cli-build/server/app/api/v1/embeddings/route.js.nft.json +1 -1
  364. package/app/.next-cli-build/server/app/api/v1/images/generations/route.js +2 -2
  365. package/app/.next-cli-build/server/app/api/v1/images/generations/route.js.nft.json +1 -1
  366. package/app/.next-cli-build/server/app/api/v1/messages/count_tokens/route.js.nft.json +1 -1
  367. package/app/.next-cli-build/server/app/api/v1/messages/route.js +1 -1
  368. package/app/.next-cli-build/server/app/api/v1/messages/route.js.nft.json +1 -1
  369. package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js +1 -1
  370. package/app/.next-cli-build/server/app/api/v1/models/[kind]/route.js.nft.json +1 -1
  371. package/app/.next-cli-build/server/app/api/v1/models/info/route.js +1 -1
  372. package/app/.next-cli-build/server/app/api/v1/models/info/route.js.nft.json +1 -1
  373. package/app/.next-cli-build/server/app/api/v1/models/route.js +1 -1
  374. package/app/.next-cli-build/server/app/api/v1/models/route.js.nft.json +1 -1
  375. package/app/.next-cli-build/server/app/api/v1/rerank/route.js +1 -1
  376. package/app/.next-cli-build/server/app/api/v1/rerank/route.js.nft.json +1 -1
  377. package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js +1 -1
  378. package/app/.next-cli-build/server/app/api/v1/responses/compact/route.js.nft.json +1 -1
  379. package/app/.next-cli-build/server/app/api/v1/responses/route.js +1 -1
  380. package/app/.next-cli-build/server/app/api/v1/responses/route.js.nft.json +1 -1
  381. package/app/.next-cli-build/server/app/api/v1/route.js +1 -1
  382. package/app/.next-cli-build/server/app/api/v1/route.js.nft.json +1 -1
  383. package/app/.next-cli-build/server/app/api/v1/search/route.js +1 -1
  384. package/app/.next-cli-build/server/app/api/v1/search/route.js.nft.json +1 -1
  385. package/app/.next-cli-build/server/app/api/v1/systemone/route.js +1 -1
  386. package/app/.next-cli-build/server/app/api/v1/systemone/route.js.nft.json +1 -1
  387. package/app/.next-cli-build/server/app/api/v1/videos/[id]/route.js +1 -1
  388. package/app/.next-cli-build/server/app/api/v1/videos/[id]/route.js.nft.json +1 -1
  389. package/app/.next-cli-build/server/app/api/v1/videos/edits/route.js +1 -1
  390. package/app/.next-cli-build/server/app/api/v1/videos/edits/route.js.nft.json +1 -1
  391. package/app/.next-cli-build/server/app/api/v1/videos/extensions/route.js +1 -1
  392. package/app/.next-cli-build/server/app/api/v1/videos/extensions/route.js.nft.json +1 -1
  393. package/app/.next-cli-build/server/app/api/v1/videos/generations/route.js +1 -1
  394. package/app/.next-cli-build/server/app/api/v1/videos/generations/route.js.nft.json +1 -1
  395. package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js +1 -1
  396. package/app/.next-cli-build/server/app/api/v1/web/fetch/route.js.nft.json +1 -1
  397. package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js +1 -1
  398. package/app/.next-cli-build/server/app/api/v1beta/models/[...path]/route.js.nft.json +1 -1
  399. package/app/.next-cli-build/server/app/api/v1beta/models/route.js +1 -1
  400. package/app/.next-cli-build/server/app/api/v1beta/models/route.js.nft.json +1 -1
  401. package/app/.next-cli-build/server/app/api/version/route.js +1 -1
  402. package/app/.next-cli-build/server/app/api/version/route.js.nft.json +1 -1
  403. package/app/.next-cli-build/server/app/api/version/shell-update/route.js.nft.json +1 -1
  404. package/app/.next-cli-build/server/app/api/version/shutdown/route.js +1 -1
  405. package/app/.next-cli-build/server/app/api/version/shutdown/route.js.nft.json +1 -1
  406. package/app/.next-cli-build/server/app/api/version/update/route.js +1 -1
  407. package/app/.next-cli-build/server/app/api/version/update/route.js.nft.json +1 -1
  408. package/app/.next-cli-build/server/app/callback/page.js +1 -1
  409. package/app/.next-cli-build/server/app/callback/page.js.nft.json +1 -1
  410. package/app/.next-cli-build/server/app/callback/page_client-reference-manifest.js +1 -1
  411. package/app/.next-cli-build/server/app/callback.html +2 -2
  412. package/app/.next-cli-build/server/app/callback.rsc +6 -6
  413. package/app/.next-cli-build/server/app/callback.segments/_full.segment.rsc +6 -6
  414. package/app/.next-cli-build/server/app/callback.segments/_tree.segment.rsc +2 -2
  415. package/app/.next-cli-build/server/app/callback.segments/callback/__PAGE__.segment.rsc +6 -6
  416. package/app/.next-cli-build/server/app/dashboard/basic-chat.html +2 -2
  417. package/app/.next-cli-build/server/app/dashboard/basic-chat.rsc +8 -8
  418. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +8 -8
  419. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_full.segment.rsc +8 -8
  420. package/app/.next-cli-build/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +2 -2
  421. package/app/.next-cli-build/server/app/dashboard/cli-tools.html +2 -2
  422. package/app/.next-cli-build/server/app/dashboard/cli-tools.rsc +8 -8
  423. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +8 -8
  424. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_full.segment.rsc +8 -8
  425. package/app/.next-cli-build/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +2 -2
  426. package/app/.next-cli-build/server/app/dashboard/combos.html +2 -2
  427. package/app/.next-cli-build/server/app/dashboard/combos.rsc +8 -8
  428. package/app/.next-cli-build/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +8 -8
  429. package/app/.next-cli-build/server/app/dashboard/combos.segments/_full.segment.rsc +8 -8
  430. package/app/.next-cli-build/server/app/dashboard/combos.segments/_tree.segment.rsc +2 -2
  431. package/app/.next-cli-build/server/app/dashboard/endpoint.html +2 -2
  432. package/app/.next-cli-build/server/app/dashboard/endpoint.rsc +8 -8
  433. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +8 -8
  434. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_full.segment.rsc +8 -8
  435. package/app/.next-cli-build/server/app/dashboard/endpoint.segments/_tree.segment.rsc +2 -2
  436. package/app/.next-cli-build/server/app/dashboard/experimental.html +2 -2
  437. package/app/.next-cli-build/server/app/dashboard/experimental.rsc +8 -8
  438. package/app/.next-cli-build/server/app/dashboard/experimental.segments/!KGRhc2hib2FyZCk/dashboard/experimental/__PAGE__.segment.rsc +8 -8
  439. package/app/.next-cli-build/server/app/dashboard/experimental.segments/_full.segment.rsc +8 -8
  440. package/app/.next-cli-build/server/app/dashboard/experimental.segments/_tree.segment.rsc +2 -2
  441. package/app/.next-cli-build/server/app/dashboard/media-providers/web.html +2 -2
  442. package/app/.next-cli-build/server/app/dashboard/media-providers/web.rsc +8 -8
  443. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/web/__PAGE__.segment.rsc +8 -8
  444. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_full.segment.rsc +8 -8
  445. package/app/.next-cli-build/server/app/dashboard/media-providers/web.segments/_tree.segment.rsc +2 -2
  446. package/app/.next-cli-build/server/app/dashboard/mitm.html +2 -2
  447. package/app/.next-cli-build/server/app/dashboard/mitm.rsc +8 -8
  448. package/app/.next-cli-build/server/app/dashboard/mitm.segments/!KGRhc2hib2FyZCk/dashboard/mitm/__PAGE__.segment.rsc +8 -8
  449. package/app/.next-cli-build/server/app/dashboard/mitm.segments/_full.segment.rsc +8 -8
  450. package/app/.next-cli-build/server/app/dashboard/mitm.segments/_tree.segment.rsc +2 -2
  451. package/app/.next-cli-build/server/app/dashboard/profile.html +2 -2
  452. package/app/.next-cli-build/server/app/dashboard/profile.rsc +8 -8
  453. package/app/.next-cli-build/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +8 -8
  454. package/app/.next-cli-build/server/app/dashboard/profile.segments/_full.segment.rsc +8 -8
  455. package/app/.next-cli-build/server/app/dashboard/profile.segments/_tree.segment.rsc +2 -2
  456. package/app/.next-cli-build/server/app/dashboard/providers/new.html +2 -2
  457. package/app/.next-cli-build/server/app/dashboard/providers/new.rsc +8 -8
  458. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +8 -8
  459. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_full.segment.rsc +8 -8
  460. package/app/.next-cli-build/server/app/dashboard/providers/new.segments/_tree.segment.rsc +2 -2
  461. package/app/.next-cli-build/server/app/dashboard/providers.html +2 -2
  462. package/app/.next-cli-build/server/app/dashboard/providers.rsc +8 -8
  463. package/app/.next-cli-build/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +8 -8
  464. package/app/.next-cli-build/server/app/dashboard/providers.segments/_full.segment.rsc +8 -8
  465. package/app/.next-cli-build/server/app/dashboard/providers.segments/_tree.segment.rsc +2 -2
  466. package/app/.next-cli-build/server/app/dashboard/proxy-pools.html +2 -2
  467. package/app/.next-cli-build/server/app/dashboard/proxy-pools.rsc +8 -8
  468. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +8 -8
  469. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +8 -8
  470. package/app/.next-cli-build/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +2 -2
  471. package/app/.next-cli-build/server/app/dashboard/pxpipe.html +2 -2
  472. package/app/.next-cli-build/server/app/dashboard/pxpipe.rsc +8 -8
  473. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +8 -8
  474. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_full.segment.rsc +8 -8
  475. package/app/.next-cli-build/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +2 -2
  476. package/app/.next-cli-build/server/app/dashboard/quota.html +2 -2
  477. package/app/.next-cli-build/server/app/dashboard/quota.rsc +9 -9
  478. package/app/.next-cli-build/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +9 -9
  479. package/app/.next-cli-build/server/app/dashboard/quota.segments/_full.segment.rsc +9 -9
  480. package/app/.next-cli-build/server/app/dashboard/quota.segments/_tree.segment.rsc +2 -2
  481. package/app/.next-cli-build/server/app/dashboard/settings/pricing/page.js +1 -1
  482. package/app/.next-cli-build/server/app/dashboard/settings/pricing/page.js.nft.json +1 -1
  483. package/app/.next-cli-build/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
  484. package/app/.next-cli-build/server/app/dashboard/settings/pricing.html +2 -2
  485. package/app/.next-cli-build/server/app/dashboard/settings/pricing.rsc +6 -6
  486. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +6 -6
  487. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +2 -2
  488. package/app/.next-cli-build/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +6 -6
  489. package/app/.next-cli-build/server/app/dashboard/skills.html +2 -2
  490. package/app/.next-cli-build/server/app/dashboard/skills.rsc +8 -8
  491. package/app/.next-cli-build/server/app/dashboard/skills.segments/!KGRhc2hib2FyZCk/dashboard/skills/__PAGE__.segment.rsc +8 -8
  492. package/app/.next-cli-build/server/app/dashboard/skills.segments/_full.segment.rsc +8 -8
  493. package/app/.next-cli-build/server/app/dashboard/skills.segments/_tree.segment.rsc +2 -2
  494. package/app/.next-cli-build/server/app/dashboard/token-saver.html +2 -2
  495. package/app/.next-cli-build/server/app/dashboard/token-saver.rsc +8 -8
  496. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +8 -8
  497. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_full.segment.rsc +8 -8
  498. package/app/.next-cli-build/server/app/dashboard/token-saver.segments/_tree.segment.rsc +2 -2
  499. package/app/.next-cli-build/server/app/dashboard/translator.html +2 -2
  500. package/app/.next-cli-build/server/app/dashboard/translator.rsc +8 -8
  501. package/app/.next-cli-build/server/app/dashboard/translator.segments/!KGRhc2hib2FyZCk/dashboard/translator/__PAGE__.segment.rsc +8 -8
  502. package/app/.next-cli-build/server/app/dashboard/translator.segments/_full.segment.rsc +8 -8
  503. package/app/.next-cli-build/server/app/dashboard/translator.segments/_tree.segment.rsc +2 -2
  504. package/app/.next-cli-build/server/app/dashboard/usage.html +2 -2
  505. package/app/.next-cli-build/server/app/dashboard/usage.rsc +8 -8
  506. package/app/.next-cli-build/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +8 -8
  507. package/app/.next-cli-build/server/app/dashboard/usage.segments/_full.segment.rsc +8 -8
  508. package/app/.next-cli-build/server/app/dashboard/usage.segments/_tree.segment.rsc +2 -2
  509. package/app/.next-cli-build/server/app/dashboard.html +2 -2
  510. package/app/.next-cli-build/server/app/dashboard.rsc +8 -8
  511. package/app/.next-cli-build/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +8 -8
  512. package/app/.next-cli-build/server/app/dashboard.segments/_full.segment.rsc +8 -8
  513. package/app/.next-cli-build/server/app/dashboard.segments/_tree.segment.rsc +2 -2
  514. package/app/.next-cli-build/server/app/favicon.ico/route.js.nft.json +1 -1
  515. package/app/.next-cli-build/server/app/index.html +1 -1
  516. package/app/.next-cli-build/server/app/index.rsc +6 -6
  517. package/app/.next-cli-build/server/app/index.segments/__PAGE__.segment.rsc +6 -6
  518. package/app/.next-cli-build/server/app/index.segments/_full.segment.rsc +6 -6
  519. package/app/.next-cli-build/server/app/index.segments/_tree.segment.rsc +2 -2
  520. package/app/.next-cli-build/server/app/landing/page.js +1 -1
  521. package/app/.next-cli-build/server/app/landing/page.js.nft.json +1 -1
  522. package/app/.next-cli-build/server/app/landing/page_client-reference-manifest.js +1 -1
  523. package/app/.next-cli-build/server/app/landing.html +2 -2
  524. package/app/.next-cli-build/server/app/landing.rsc +7 -7
  525. package/app/.next-cli-build/server/app/landing.segments/_full.segment.rsc +7 -7
  526. package/app/.next-cli-build/server/app/landing.segments/_tree.segment.rsc +2 -2
  527. package/app/.next-cli-build/server/app/landing.segments/landing/__PAGE__.segment.rsc +7 -7
  528. package/app/.next-cli-build/server/app/login/page.js +1 -1
  529. package/app/.next-cli-build/server/app/login/page.js.nft.json +1 -1
  530. package/app/.next-cli-build/server/app/login/page_client-reference-manifest.js +1 -1
  531. package/app/.next-cli-build/server/app/login.html +2 -2
  532. package/app/.next-cli-build/server/app/login.rsc +7 -7
  533. package/app/.next-cli-build/server/app/login.segments/_full.segment.rsc +7 -7
  534. package/app/.next-cli-build/server/app/login.segments/_tree.segment.rsc +2 -2
  535. package/app/.next-cli-build/server/app/login.segments/login/__PAGE__.segment.rsc +7 -7
  536. package/app/.next-cli-build/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  537. package/app/.next-cli-build/server/app/page.js +1 -1
  538. package/app/.next-cli-build/server/app/page.js.nft.json +1 -1
  539. package/app/.next-cli-build/server/app/page_client-reference-manifest.js +1 -1
  540. package/app/.next-cli-build/server/app-paths-manifest.json +6 -6
  541. package/app/.next-cli-build/server/chunks/1329.js +1 -1
  542. package/app/.next-cli-build/server/chunks/1806.js +1 -1
  543. package/app/.next-cli-build/server/chunks/{9417.js → 1819.js} +2 -2
  544. package/app/.next-cli-build/server/chunks/1884.js +1 -1
  545. package/app/.next-cli-build/server/chunks/2132.js +1 -1
  546. package/app/.next-cli-build/server/chunks/2154.js +1 -0
  547. package/app/.next-cli-build/server/chunks/2557.js +4 -4
  548. package/app/.next-cli-build/server/chunks/2812.js +1 -1
  549. package/app/.next-cli-build/server/chunks/318.js +10 -8
  550. package/app/.next-cli-build/server/chunks/3217.js +1 -0
  551. package/app/.next-cli-build/server/chunks/3267.js +1 -0
  552. package/app/.next-cli-build/server/chunks/3500.js +2 -2
  553. package/app/.next-cli-build/server/chunks/3535.js +1 -1
  554. package/app/.next-cli-build/server/chunks/3792.js +1 -1
  555. package/app/.next-cli-build/server/chunks/3943.js +1 -1
  556. package/app/.next-cli-build/server/chunks/3962.js +1 -1
  557. package/app/.next-cli-build/server/chunks/4123.js +1 -1
  558. package/app/.next-cli-build/server/chunks/4386.js +1 -0
  559. package/app/.next-cli-build/server/chunks/447.js +1 -0
  560. package/app/.next-cli-build/server/chunks/4575.js +1 -1
  561. package/app/.next-cli-build/server/chunks/4692.js +1 -1
  562. package/app/.next-cli-build/server/chunks/4775.js +1 -1
  563. package/app/.next-cli-build/server/chunks/{2112.js → 4906.js} +1 -1
  564. package/app/.next-cli-build/server/chunks/4927.js +4 -4
  565. package/app/.next-cli-build/server/chunks/5210.js +15 -13
  566. package/app/.next-cli-build/server/chunks/539.js +1 -1
  567. package/app/.next-cli-build/server/chunks/5598.js +1 -0
  568. package/app/.next-cli-build/server/chunks/5615.js +1 -1
  569. package/app/.next-cli-build/server/chunks/5625.js +1 -0
  570. package/app/.next-cli-build/server/chunks/5663.js +1 -0
  571. package/app/.next-cli-build/server/chunks/5757.js +1 -1
  572. package/app/.next-cli-build/server/chunks/5781.js +1 -1
  573. package/app/.next-cli-build/server/chunks/6070.js +1 -1
  574. package/app/.next-cli-build/server/chunks/615.js +1 -1
  575. package/app/.next-cli-build/server/chunks/6306.js +1 -1
  576. package/app/.next-cli-build/server/chunks/6326.js +1 -1
  577. package/app/.next-cli-build/server/chunks/6492.js +1 -1
  578. package/app/.next-cli-build/server/chunks/6763.js +1 -1
  579. package/app/.next-cli-build/server/chunks/6790.js +1 -1
  580. package/app/.next-cli-build/server/chunks/6877.js +1 -1
  581. package/app/.next-cli-build/server/chunks/6922.js +1 -1
  582. package/app/.next-cli-build/server/chunks/6956.js +1 -1
  583. package/app/.next-cli-build/server/chunks/6960.js +2 -2
  584. package/app/.next-cli-build/server/chunks/7067.js +1 -1
  585. package/app/.next-cli-build/server/chunks/7122.js +1 -1
  586. package/app/.next-cli-build/server/chunks/7247.js +1 -1
  587. package/app/.next-cli-build/server/chunks/7274.js +4 -4
  588. package/app/.next-cli-build/server/chunks/7322.js +2 -2
  589. package/app/.next-cli-build/server/chunks/7729.js +1 -0
  590. package/app/.next-cli-build/server/chunks/8145.js +1 -1
  591. package/app/.next-cli-build/server/chunks/8172.js +2 -2
  592. package/app/.next-cli-build/server/chunks/8318.js +1 -1
  593. package/app/.next-cli-build/server/chunks/8370.js +2 -2
  594. package/app/.next-cli-build/server/chunks/8499.js +3 -3
  595. package/app/.next-cli-build/server/chunks/8595.js +1 -1
  596. package/app/.next-cli-build/server/chunks/8689.js +1 -1
  597. package/app/.next-cli-build/server/chunks/8749.js +1 -1
  598. package/app/.next-cli-build/server/chunks/8775.js +1 -1
  599. package/app/.next-cli-build/server/chunks/8895.js +8 -8
  600. package/app/.next-cli-build/server/chunks/8920.js +1 -1
  601. package/app/.next-cli-build/server/chunks/9046.js +1 -1
  602. package/app/.next-cli-build/server/chunks/9154.js +1 -1
  603. package/app/.next-cli-build/server/chunks/9489.js +3 -2
  604. package/app/.next-cli-build/server/chunks/9601.js +1 -1
  605. package/app/.next-cli-build/server/chunks/9609.js +1 -1
  606. package/app/.next-cli-build/server/chunks/9628.js +1 -1
  607. package/app/.next-cli-build/server/chunks/976.js +1 -1
  608. package/app/.next-cli-build/server/instrumentation.js.nft.json +1 -1
  609. package/app/.next-cli-build/server/middleware-build-manifest.js +1 -1
  610. package/app/.next-cli-build/server/middleware.js +5 -5
  611. package/app/.next-cli-build/server/middleware.js.nft.json +1 -1
  612. package/app/.next-cli-build/server/pages/404.html +2 -2
  613. package/app/.next-cli-build/server/pages/500.html +1 -1
  614. package/app/.next-cli-build/static/chunks/1243-72ef45af27dc7a4a.js +3 -0
  615. package/app/.next-cli-build/static/chunks/1321-77ba328dd4d69fdb.js +1 -0
  616. package/app/.next-cli-build/static/chunks/5497-ec8a6308121a2b70.js +7 -0
  617. package/app/.next-cli-build/static/chunks/{9749-80768075d38162d1.js → 9749-1f31c98804847f2a.js} +8 -8
  618. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/combos/page-8f6aadfc8bf2eb7b.js +1 -0
  619. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/experimental/{page-7ee730e7a1ddb6e5.js → page-01bf0e3f4117f6c1.js} +1 -1
  620. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/media-providers/[kind]/[id]/{page-bce04d7851a6bf65.js → page-6db03f8140121a40.js} +10 -10
  621. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/profile/{page-7c9d46f8c09d480e.js → page-73d4979c8eec774c.js} +1 -1
  622. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/providers/[id]/page-a6b07fa9d0712cee.js +14 -0
  623. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/providers/{page-ceb259d31ded818a.js → page-1e4e3f6f20152da1.js} +1 -1
  624. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/quota/page-c77260f73f62aa0e.js +1 -0
  625. package/app/.next-cli-build/static/chunks/app/(dashboard)/layout-db46cbc3bf22d61a.js +1 -0
  626. package/app/.next-cli-build/static/chunks/app/landing/page-c6c3a32dd06bc907.js +1 -0
  627. package/app/.next-cli-build/static/css/17275fac82e1641e.css +1 -0
  628. package/app/package.json +71 -71
  629. package/app/public/donate/alipay.svg +1 -0
  630. package/app/public/donate/ifdian.svg +1 -0
  631. package/app/public/donate/wechat.svg +1 -0
  632. package/app/public/i18n/changelog/en.md +513 -477
  633. package/app/public/i18n/changelog/zh-CN.md +511 -475
  634. package/app/public/i18n/changelog/zh-TW.md +513 -477
  635. package/app/public/i18n/literals/zh-CN.json +2107 -2063
  636. package/app/public/i18n/literals/zh-TW.json +951 -907
  637. package/app/public/providers/alitp-intl.png +0 -0
  638. package/app/public/providers/alitp.png +0 -0
  639. package/app/public/providers/inception.png +0 -0
  640. package/app/src/mitm/server.js +12 -12
  641. package/app/src/shared/services/quotaAutoPing.js +345 -313
  642. package/app/src/sse/services/codebuddyCheckin.js +687 -890
  643. package/app/src/sse/services/minimaxCheckin.js +340 -0
  644. package/package.json +61 -61
  645. package/app/.next-cli-build/server/chunks/3599.js +0 -1
  646. package/app/.next-cli-build/server/chunks/6593.js +0 -1
  647. package/app/.next-cli-build/server/chunks/7070.js +0 -1
  648. package/app/.next-cli-build/server/chunks/7252.js +0 -1
  649. package/app/.next-cli-build/server/chunks/8672.js +0 -1
  650. package/app/.next-cli-build/server/chunks/8972.js +0 -1
  651. package/app/.next-cli-build/server/chunks/939.js +0 -1
  652. package/app/.next-cli-build/static/chunks/1243-acdc1dcbfcd9336d.js +0 -3
  653. package/app/.next-cli-build/static/chunks/1321-f4736e33b06bb9d6.js +0 -1
  654. package/app/.next-cli-build/static/chunks/5497-f54b1274c2141bf0.js +0 -7
  655. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/combos/page-14745e08d1edafb2.js +0 -1
  656. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/providers/[id]/page-244e20b305c911c6.js +0 -14
  657. package/app/.next-cli-build/static/chunks/app/(dashboard)/dashboard/quota/page-c70550b49f94cbc4.js +0 -1
  658. package/app/.next-cli-build/static/chunks/app/(dashboard)/layout-cefb3cbfe469dd51.js +0 -1
  659. package/app/.next-cli-build/static/chunks/app/landing/page-38924391f8649361.js +0 -1
  660. package/app/.next-cli-build/static/css/cd8cdc4426ba0a3b.css +0 -1
  661. /package/app/.next-cli-build/static/{4BxfiRlz5UJXZcUl6uinS → 1q0xTGDYtD52dGw4uiY4-}/_buildManifest.js +0 -0
  662. /package/app/.next-cli-build/static/{4BxfiRlz5UJXZcUl6uinS → 1q0xTGDYtD52dGw4uiY4-}/_ssgManifest.js +0 -0
@@ -1,890 +1,687 @@
1
- // CodeBuddy auto daily check-in (CN) + daily active-session probe (intl).
2
- //
3
- // CN: checks every active codebuddy-cn connection into the CodeBuddy CN
4
- // "billing meter" (daily-checkin) so free daily quota is renewed without user
5
- // action. The scheduler ticks ALL DAY (~every 2h + jitter): an account is
6
- // attempted only until the day's check-in is confirmed (status endpoint or a
7
- // successful POST), then it is memoized for the rest of the local day — no
8
- // more repeated "已签到" churn across the day.
9
- //
10
- // intl: CodeBuddy's activity campaign grants daily credits (Free 30 / Pro 50)
11
- // to accounts with ≥1 valid conversation request that day (official docs:
12
- // "当天有对话请求即视为活跃用户"). There is no claim endpoint, so the intl
13
- // pass sends one minimal stream chat request per active codebuddy-intl
14
- // connection per day on a free-tier model (rateMultiplier 0, ~0 credit cost),
15
- // memoized the same way. Experimental, separate settings toggle.
16
- //
17
- // Fail-open everywhere: a tick error or a single connection failure never
18
- // rejects the whole run or kills the server.
19
-
20
- import * as log from "../utils/logger.js";
21
- import { isNeedsReauthCooling } from "open-sse/services/accountFallback.js";
22
-
23
- const DAILY_CHECKIN_URL = "https://www.codebuddy.cn/v2/billing/meter/daily-checkin";
24
- const STATUS_URL = "https://www.codebuddy.cn/v2/billing/meter/checkin-activity-status";
25
-
26
- // CodeBuddy CN compensation & gift claim endpoints (no /v2 prefix, same host & auth).
27
- const COMPENSATION_STATUS_URL = "https://www.codebuddy.cn/billing/meter/compensation-status";
28
- const CLAIM_COMPENSATION_URL = "https://www.codebuddy.cn/billing/meter/claim-compensation";
29
- const GIFT_STATUS_URL = "https://www.codebuddy.cn/billing/meter/check-gift-claimed";
30
- const CLAIM_GIFT_URL = "https://www.codebuddy.cn/billing/meter/claim-gift";
31
-
32
- // intl daily active-session probe. Free-tier model (rateMultiplier 0) so the
33
- // request itself costs ~0 credits; body shape mirrors executors/codebuddy-intl
34
- // (stream-only gateway: leading system prompt + user content as typed blocks,
35
- // otherwise 11101 invalid request).
36
- const INTL_CHAT_URL = "https://www.codebuddy.ai/v2/chat/completions";
37
- const INTL_PROBE_MODEL = "hy4-preview";
38
- const INTL_PROBE_MAX_TOKENS = 16;
39
-
40
- // All-day cadence: retry every ~2h (plus jitter) until each account is done
41
- // for the day; the per-day memo keeps already-done accounts fully idle.
42
- const TICK_MS = 2 * 60 * 60 * 1000;
43
- const TICK_JITTER_MS = 10 * 60 * 1000;
44
-
45
- let started = false;
46
- let timerHandle = null;
47
-
48
- // connId -> local "YYYY-MM-DD" the account was last confirmed done. Persisted
49
- // in settings as `codeBuddyDailyDone` (lazy-loaded into this cache) so a
50
- // restart doesn't re-verify already-done accounts until the day rolls over;
51
- // entries are pruned to today on every write. The manual check-in route never
52
- // touches this memo.
53
- let doneMap = null;
54
- let compensationDoneMap = null;
55
-
56
- async function getDoneMap() {
57
- if (doneMap) return doneMap;
58
- const settings = await loadSettingsSafe();
59
- const raw = settings?.codeBuddyDailyDone;
60
- doneMap = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
61
- return doneMap;
62
- }
63
-
64
- async function getCompensationDoneMap() {
65
- if (compensationDoneMap) return compensationDoneMap;
66
- const settings = await loadSettingsSafe();
67
- const raw = settings?.codeBuddyCompensationDone;
68
- compensationDoneMap = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
69
- return compensationDoneMap;
70
- }
71
-
72
- // Write the in-memory memo back to settings, pruned to today. Called by the
73
- // scheduler after each pass (the ticks only mutate the passed memo object).
74
- async function persistDoneMap() {
75
- if (!doneMap) return;
76
- const today = dayKey();
77
- const pruned = {};
78
- for (const [id, day] of Object.entries(doneMap)) {
79
- if (day === today) pruned[id] = day;
80
- }
81
- try {
82
- const { updateSettings } = await import("../../lib/localDb.js");
83
- await updateSettings({ codeBuddyDailyDone: pruned });
84
- for (const k of Object.keys(doneMap)) delete doneMap[k];
85
- Object.assign(doneMap, pruned);
86
- } catch (err) {
87
- // Persist is best-effort — the in-memory cache still prevents same-process
88
- // repeats; a failed write just means one extra status check after restart.
89
- log.warn("CB_CN_CHECKIN", "Persist daily-done map failed (swallowed)", {
90
- error: err?.message ?? String(err),
91
- });
92
- }
93
- }
94
-
95
- async function persistCompensationDoneMap() {
96
- if (!compensationDoneMap) return;
97
- const today = dayKey();
98
- const pruned = {};
99
- for (const [id, day] of Object.entries(compensationDoneMap)) {
100
- if (day === today) pruned[id] = day;
101
- }
102
- try {
103
- const { updateSettings } = await import("../../lib/localDb.js");
104
- await updateSettings({ codeBuddyCompensationDone: pruned });
105
- for (const k of Object.keys(compensationDoneMap)) delete compensationDoneMap[k];
106
- Object.assign(compensationDoneMap, pruned);
107
- } catch (err) {
108
- log.warn("CB_CN_COMP", "Persist compensation-done map failed (swallowed)", {
109
- error: err?.message ?? String(err),
110
- });
111
- }
112
- }
113
-
114
- // ─── Pure helpers (unit-testable, no I/O) ──────────────────────────────────
115
-
116
- function decodeJwt(jwt) {
117
- try {
118
- const seg = String(jwt).split(".")[1];
119
- const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
120
- const pad = b64 + "=".repeat((4 - (b64.length % 4)) % 4);
121
- return JSON.parse(Buffer.from(pad, "base64").toString("utf8"));
122
- } catch {
123
- return null;
124
- }
125
- }
126
-
127
- function isCodeBuddyCnRealm(iss) {
128
- return (
129
- typeof iss === "string" &&
130
- (iss.includes("codebuddy.cn") || iss.includes("copilot.tencent.com"))
131
- );
132
- }
133
-
134
- // intl tokens are issued by the codebuddy.ai side; matching the "codebuddy"
135
- // family keeps a workbuddy/other realm out without over-fitting the realm URL.
136
- function isCodeBuddyRealm(iss) {
137
- return typeof iss === "string" && iss.includes("codebuddy");
138
- }
139
-
140
- function dayKey(nowMs = Date.now()) {
141
- const d = new Date(nowMs);
142
- const p = (n) => String(n).padStart(2, "0");
143
- return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
144
- }
145
-
146
- /**
147
- * Eligibility: an active codebuddy-cn OAuth connection whose access token is
148
- * signed by a CodeBuddy CN Keycloak realm (has an access token at all).
149
- * @param {object} conn
150
- * @returns {boolean}
151
- */
152
- export function isEligibleCbcnConnection(conn) {
153
- if (!conn || !conn.accessToken) return false;
154
- if (conn.provider !== "codebuddy-cn") return false;
155
- if (conn.isActive === false) return false;
156
- // Needs-reauth cooling: the token set is known-dead. A check-in would 401,
157
- // its refresh re-marks the account and re-extends the cooldown window forever.
158
- if (isNeedsReauthCooling(conn)) return false;
159
- const claims = decodeJwt(conn.accessToken) || {};
160
- return isCodeBuddyCnRealm(claims.iss || "");
161
- }
162
-
163
- /**
164
- * Eligibility for the intl daily active-session probe.
165
- * @param {object} conn
166
- * @returns {boolean}
167
- */
168
- export function isEligibleCbIntlConnection(conn) {
169
- if (!conn || !conn.accessToken) return false;
170
- if (conn.provider !== "codebuddy-intl") return false;
171
- if (conn.isActive === false) return false;
172
- // Same needs-reauth cooling skip as the CN check-in — see above.
173
- if (isNeedsReauthCooling(conn)) return false;
174
- const claims = decodeJwt(conn.accessToken) || {};
175
- return isCodeBuddyRealm(claims.iss || "");
176
- }
177
-
178
- function isIdempotentAlready(msg) {
179
- if (typeof msg !== "string") return false;
180
- // CN "今天已签到" / generic "repeat/already" markers from the CodeBuddy gateway.
181
- return /已签到|签到过|重复签到|already|repeat/i.test(msg);
182
- }
183
-
184
- /**
185
- * Map a daily-checkin HTTP result to a stable status string.
186
- * @param {{ httpStatus: number, code?: number|string, msg?: string }} res
187
- * @returns {"checked-in"|"already"|"failed"}
188
- */
189
- export function mapDailyCheckinStatus({ httpStatus, code, msg } = {}) {
190
- if (httpStatus >= 200 && httpStatus < 300) return "checked-in";
191
- // HTTP 400 + known idempotent codes/messages ⇒ already signed in today.
192
- if (httpStatus === 400) {
193
- if (code === 10001 || code === "10001" || isIdempotentAlready(msg)) return "already";
194
- }
195
- return "failed";
196
- }
197
-
198
- /**
199
- * Delay (ms) until the next all-day tick: fixed ~2h cadence plus jitter so
200
- * many instances don't tick in lockstep. `rand` is injectable for tests.
201
- * @param {number} [nowMs]
202
- * @param {() => number} [rand] 0..1 uniform
203
- * @returns {number}
204
- */
205
- export function msUntilNextTick(nowMs = Date.now(), rand = Math.random) {
206
- const jitter = Math.floor(rand() * TICK_JITTER_MS);
207
- return Math.max(TICK_MS + jitter, 1000);
208
- }
209
-
210
- function isNonServerRuntime() {
211
- if (typeof window !== "undefined") return true;
212
- const phase = process.env.NEXT_PHASE || "";
213
- if (phase === "phase-production-build" || phase === "phase-export" || phase === "phase-static") {
214
- return true;
215
- }
216
- if (process.env.NEXT_RUNTIME === "edge") return true;
217
- return false;
218
- }
219
-
220
- // ─── Dynamic I/O (lazy imports to avoid circular/coupling at eval time) ────
221
-
222
- async function loadActiveConnections() {
223
- const { getProviderConnections } = await import("../../lib/db/repos/connectionsRepo.js");
224
- return getProviderConnections({ provider: "codebuddy-cn" });
225
- }
226
-
227
- async function loadIntlConnections() {
228
- const { getProviderConnections } = await import("../../lib/db/repos/connectionsRepo.js");
229
- return getProviderConnections({ provider: "codebuddy-intl" });
230
- }
231
-
232
- async function loadSettingsSafe() {
233
- try {
234
- const { getSettings } = await import("../../lib/localDb.js");
235
- return await getSettings();
236
- } catch {
237
- return {};
238
- }
239
- }
240
-
241
- // Reuse the existing proactive refresh pipeline (refreshes + persists the new
242
- // access token) exactly like backgroundTokenRefresh on a 401.
243
- async function refreshOne(provider, connection) {
244
- const { checkAndRefreshToken } = await import("./tokenRefresh.js");
245
- const creds = await checkAndRefreshToken(provider, connection, { force: true });
246
- return creds?.accessToken ? creds : null;
247
- }
248
-
249
- function proxyOptionsOf(conn) {
250
- return conn?.proxyOptions || {
251
- enabled: conn?.connectionProxyEnabled,
252
- url: conn?.connectionProxyUrl,
253
- noProxy: conn?.connectionNoProxy,
254
- };
255
- }
256
-
257
- function cnHeaders(accessToken, uid) {
258
- return {
259
- Authorization: `Bearer ${accessToken}`,
260
- "X-User-Id": String(uid),
261
- "Content-Type": "application/json",
262
- Accept: "application/json",
263
- };
264
- }
265
-
266
- // One account check-in POST (no 401 retry here — caller decides) → raw result.
267
- async function postCnApi(url, accessToken, uid, proxyOptions) {
268
- const { proxyAwareFetch } = await import("open-sse/utils/proxyFetch.js");
269
- const res = await proxyAwareFetch(
270
- url,
271
- { method: "POST", headers: cnHeaders(accessToken, uid), body: "{}" },
272
- proxyOptions
273
- );
274
- const text = await res.text();
275
- let body = null;
276
- try {
277
- body = text ? JSON.parse(text) : null;
278
- } catch {
279
- body = null;
280
- }
281
- return {
282
- httpStatus: res.status,
283
- code: body?.code ?? body?.error_code,
284
- msg: body?.msg ?? body?.message,
285
- data: body?.data,
286
- rawBody: body,
287
- };
288
- }
289
-
290
- async function postDailyCheckin(accessToken, uid, proxyOptions) {
291
- return postCnApi(DAILY_CHECKIN_URL, accessToken, uid, proxyOptions);
292
- }
293
-
294
- async function postStatus(accessToken, uid, proxyOptions) {
295
- const { proxyAwareFetch } = await import("open-sse/utils/proxyFetch.js");
296
- const res = await proxyAwareFetch(
297
- STATUS_URL,
298
- { method: "POST", headers: cnHeaders(accessToken, uid), body: "{}" },
299
- proxyOptions
300
- );
301
- const text = await res.text();
302
- let body = null;
303
- try {
304
- body = text ? JSON.parse(text) : null;
305
- } catch {
306
- body = null;
307
- }
308
- return { httpStatus: res.status, body };
309
- }
310
-
311
- // Is the account already signed in today? Used by the scheduled pass so we
312
- // don't re-check-in accounts that already renewed.
313
- function isCheckedInToday(status) {
314
- const data = status?.body?.data || {};
315
- return status.httpStatus === 200 && (data.today_checked_in === true || data.checked_in === true);
316
- }
317
-
318
- /**
319
- * Check in one connection (with a single 401 → refresh → retry). Fail-open.
320
- * @param {object} conn
321
- * @param {{ refreshConnection?: Function }} deps
322
- * @returns {Promise<{status: string, error?: string}>}
323
- */
324
- async function checkinOne(conn, deps) {
325
- const refresh = deps?.refreshConnection || ((c) => refreshOne("codebuddy-cn", c));
326
- let accessToken = conn.accessToken;
327
- const claims = decodeJwt(accessToken) || {};
328
- const uid = claims.sub || conn.id;
329
- const proxyOptions = proxyOptionsOf(conn);
330
-
331
- for (let attempt = 0; attempt < 2; attempt++) {
332
- try {
333
- const result = await postDailyCheckin(accessToken, uid, proxyOptions);
334
- const status = mapDailyCheckinStatus(result);
335
- if (status !== "failed") return { status };
336
- // 401 (invalid/expired token) → refresh once and retry.
337
- if (result.httpStatus === 401 && attempt === 0) {
338
- log.info("CB_CN_CHECKIN", "401 on daily-check-in, refreshing token once", {
339
- id: conn.id,
340
- });
341
- const refreshed = await refresh(conn);
342
- if (refreshed?.accessToken) accessToken = refreshed.accessToken;
343
- else return { status: "failed", error: "refresh_failed" };
344
- continue;
345
- }
346
- return { status, error: result.msg || `http_${result.httpStatus}` };
347
- } catch (err) {
348
- return { status: "failed", error: err?.message || String(err) };
349
- }
350
- }
351
- return { status: "failed", error: "unexpected" };
352
- }
353
-
354
- // Prefer status-check to skip already-checked-in accounts.
355
- async function checkinIfNotDone(conn, deps) {
356
- const proxyOptions = proxyOptionsOf(conn);
357
- const claims = decodeJwt(conn.accessToken) || {};
358
- const uid = claims.sub || conn.id;
359
- try {
360
- const status = await postStatus(conn.accessToken, uid, proxyOptions);
361
- if (isCheckedInToday(status)) return { status: "already" };
362
- } catch {
363
- // Status check is best-effort — fall through to a plain check-in.
364
- }
365
- return checkinOne(conn, deps);
366
- }
367
-
368
- // One intl active-session probe (with a single 401 → refresh → retry).
369
- async function probeOne(conn, deps) {
370
- const refresh = deps?.refreshConnection || ((c) => refreshOne("codebuddy-intl", c));
371
- let accessToken = conn.accessToken;
372
- const proxyOptions = proxyOptionsOf(conn);
373
-
374
- for (let attempt = 0; attempt < 2; attempt++) {
375
- try {
376
- const result = await postIntlProbe(accessToken, proxyOptions);
377
- if (result.httpStatus >= 200 && result.httpStatus < 300) return { status: "session-ok" };
378
- if (result.httpStatus === 401 && attempt === 0) {
379
- log.info("CB_INTL_SESSION", "401 on active-session probe, refreshing token once", {
380
- id: conn.id,
381
- });
382
- const refreshed = await refresh(conn);
383
- if (refreshed?.accessToken) accessToken = refreshed.accessToken;
384
- else return { status: "failed", error: "refresh_failed" };
385
- continue;
386
- }
387
- return { status: "failed", error: result.msg || `http_${result.httpStatus}` };
388
- } catch (err) {
389
- return { status: "failed", error: err?.message || String(err) };
390
- }
391
- }
392
- return { status: "failed", error: "unexpected" };
393
- }
394
-
395
- async function postIntlProbe(accessToken, proxyOptions) {
396
- const { proxyAwareFetch } = await import("open-sse/utils/proxyFetch.js");
397
- const { default: registry } = await import("open-sse/providers/registry/codebuddy-intl.js");
398
- const headers = {
399
- ...(registry?.transport?.headers || {}),
400
- Authorization: `Bearer ${accessToken}`,
401
- "Content-Type": "application/json",
402
- Accept: "text/event-stream",
403
- };
404
- const body = JSON.stringify({
405
- model: INTL_PROBE_MODEL,
406
- stream: true,
407
- max_tokens: INTL_PROBE_MAX_TOKENS,
408
- messages: [
409
- { role: "system", content: "You are CodeBuddy Code." },
410
- { role: "user", content: [{ type: "text", text: "hi" }] },
411
- ],
412
- });
413
- const res = await proxyAwareFetch(
414
- INTL_CHAT_URL,
415
- { method: "POST", headers, body },
416
- proxyOptions
417
- );
418
- // Stream-only gateway: 2xx means a valid session was established — drain and
419
- // discard the SSE body (a few tokens on a rateMultiplier-0 model).
420
- let msg = "";
421
- if (res.ok && res.body) {
422
- try {
423
- await res.text();
424
- } catch {
425
- /* drain best-effort */
426
- }
427
- } else {
428
- try {
429
- const text = await res.text();
430
- msg = (text || "").slice(0, 200);
431
- } catch {
432
- /* ignore */
433
- }
434
- }
435
- return { httpStatus: res.status, msg };
436
- }
437
-
438
- /**
439
- * One CN tick: list active codebuddy-cn connections and check each in. Fail-open
440
- * (never rejects on a single account error). With `memo` (plain object), accounts
441
- * confirmed done for the local day are skipped entirely (no network) and
442
- * successful outcomes are recorded. The manual check-in route passes no memo.
443
- *
444
- * @param {{ loadConnections?: Function, refreshConnection?: Function,
445
- * checkinConnection?: Function, skipIfCheckedToday?: boolean,
446
- * memo?: Record<string, string> }} [deps]
447
- * @returns {Promise<Array<{id: string, name: string, status: string, error?: string}>>}
448
- */
449
- export async function runCodebuddyCheckinTick(deps = {}) {
450
- const results = [];
451
- const load = deps.loadConnections || loadActiveConnections;
452
- let connections = [];
453
- try {
454
- connections = await load();
455
- } catch (err) {
456
- log.warn("CB_CN_CHECKIN", "Tick: failed to load codebuddy-cn connections (swallowed)", {
457
- error: err?.message ?? String(err),
458
- });
459
- return results;
460
- }
461
-
462
- const eligible = (Array.isArray(connections) ? connections : []).filter(isEligibleCbcnConnection);
463
- if (eligible.length === 0) {
464
- log.debug("CB_CN_CHECKIN", "Tick: no eligible codebuddy-cn connections", {
465
- total: Array.isArray(connections) ? connections.length : 0,
466
- });
467
- return results;
468
- }
469
-
470
- log.info("CB_CN_CHECKIN", "Daily check-in pass started", {
471
- eligible: eligible.length,
472
- ids: eligible.map((c) => c.id).filter(Boolean),
473
- });
474
-
475
- const memo = deps.memo || null;
476
- const today = dayKey();
477
- const checkin = deps.checkinConnection || (deps.skipIfCheckedToday ? checkinIfNotDone : checkinOne);
478
-
479
- for (const conn of eligible) {
480
- try {
481
- if (memo && memo[conn.id] === today) {
482
- log.debug("CB_CN_CHECKIN", `${conn.name || conn.id}: 已确认今日完成,跳过`, {
483
- id: conn.id,
484
- });
485
- continue;
486
- }
487
- const outcome = await checkin(conn, deps);
488
- if (memo && (outcome.status === "checked-in" || outcome.status === "already")) {
489
- memo[conn.id] = today;
490
- }
491
- results.push({
492
- id: conn.id,
493
- name: conn.name || conn.id,
494
- status: outcome.status,
495
- ...(outcome.error ? { error: outcome.error } : {}),
496
- });
497
- const statusLabel =
498
- outcome.status === "checked-in"
499
- ? "签到成功"
500
- : outcome.status === "already"
501
- ? "今日已签到"
502
- : `失败${outcome.error ? `(${outcome.error})` : ""}`;
503
- log.info("CB_CN_CHECKIN", `${conn.name || conn.id}: ${statusLabel}`, {
504
- id: conn.id,
505
- });
506
- } catch (err) {
507
- results.push({ id: conn.id, name: conn.name || conn.id, status: "failed" });
508
- log.warn("CB_CN_CHECKIN", "Connection check-in failed (swallowed)", {
509
- id: conn?.id,
510
- error: err?.message ?? String(err),
511
- });
512
- }
513
- }
514
- return results;
515
- }
516
-
517
- /**
518
- * One intl tick: one free-tier chat request per active codebuddy-intl
519
- * connection so the day's "活跃赠送" credits are granted. Same memo/fail-open
520
- * contract as the CN tick.
521
- *
522
- * @param {{ loadConnections?: Function, refreshConnection?: Function,
523
- * probeConnection?: Function, memo?: Record<string, string> }} [deps]
524
- * @returns {Promise<Array<{id: string, name: string, status: string, error?: string}>>}
525
- */
526
- export async function runCodebuddyIntlSessionTick(deps = {}) {
527
- const results = [];
528
- const load = deps.loadConnections || loadIntlConnections;
529
- let connections = [];
530
- try {
531
- connections = await load();
532
- } catch (err) {
533
- log.warn("CB_INTL_SESSION", "Tick: failed to load codebuddy-intl connections (swallowed)", {
534
- error: err?.message ?? String(err),
535
- });
536
- return results;
537
- }
538
-
539
- const eligible = (Array.isArray(connections) ? connections : []).filter(isEligibleCbIntlConnection);
540
- if (eligible.length === 0) {
541
- log.debug("CB_INTL_SESSION", "Tick: no eligible codebuddy-intl connections", {
542
- total: Array.isArray(connections) ? connections.length : 0,
543
- });
544
- return results;
545
- }
546
-
547
- log.info("CB_INTL_SESSION", "Daily active-session pass started", {
548
- eligible: eligible.length,
549
- ids: eligible.map((c) => c.id).filter(Boolean),
550
- });
551
-
552
- const memo = deps.memo || null;
553
- const today = dayKey();
554
-
555
- for (const conn of eligible) {
556
- try {
557
- if (memo && memo[conn.id] === today) {
558
- log.debug("CB_INTL_SESSION", `${conn.name || conn.id}: 已确认今日完成,跳过`, {
559
- id: conn.id,
560
- });
561
- continue;
562
- }
563
- const outcome = deps.probeConnection
564
- ? await deps.probeConnection(conn)
565
- : await probeOne(conn, deps);
566
- if (memo && outcome.status === "session-ok") {
567
- memo[conn.id] = today;
568
- }
569
- results.push({
570
- id: conn.id,
571
- name: conn.name || conn.id,
572
- status: outcome.status,
573
- ...(outcome.error ? { error: outcome.error } : {}),
574
- });
575
- log.info(
576
- "CB_INTL_SESSION",
577
- `${conn.name || conn.id}: ${outcome.status === "session-ok" ? "活跃会话完成" : `失败(${outcome.error || outcome.status})`}`,
578
- { id: conn.id }
579
- );
580
- } catch (err) {
581
- results.push({ id: conn.id, name: conn.name || conn.id, status: "failed" });
582
- log.warn("CB_INTL_SESSION", "Connection probe failed (swallowed)", {
583
- id: conn?.id,
584
- error: err?.message ?? String(err),
585
- });
586
- }
587
- }
588
- return results;
589
- }
590
-
591
- /**
592
- * Claim compensation and first-month gifts for one connection (with single 401 -> refresh -> retry).
593
- * @param {object} conn
594
- * @param {{ refreshConnection?: Function }} [deps]
595
- * @returns {Promise<{status: string, claimedAmount?: number, details?: Array, error?: string}>}
596
- */
597
- export async function claimCompensationOne(conn, deps) {
598
- const refresh = deps?.refreshConnection || ((c) => refreshOne("codebuddy-cn", c));
599
- let accessToken = conn.accessToken;
600
- const claims = decodeJwt(accessToken) || {};
601
- const uid = claims.sub || conn.id;
602
- const proxyOptions = proxyOptionsOf(conn);
603
-
604
- for (let attempt = 0; attempt < 2; attempt++) {
605
- try {
606
- // 1. Check compensation status
607
- const compStatusRes = await postCnApi(COMPENSATION_STATUS_URL, accessToken, uid, proxyOptions);
608
- if (compStatusRes.httpStatus === 401 && attempt === 0) {
609
- log.info("CB_CN_COMP", "401 on compensation status, refreshing token once", { id: conn.id });
610
- const refreshed = await refresh(conn);
611
- if (refreshed?.accessToken) {
612
- accessToken = refreshed.accessToken;
613
- continue;
614
- }
615
- return { status: "failed", error: "refresh_failed" };
616
- }
617
-
618
- // 2. Check gift status (best effort)
619
- let giftStatusRes = null;
620
- try {
621
- giftStatusRes = await postCnApi(GIFT_STATUS_URL, accessToken, uid, proxyOptions);
622
- if (giftStatusRes.httpStatus === 401 && attempt === 0) {
623
- log.info("CB_CN_COMP", "401 on gift status, refreshing token once", { id: conn.id });
624
- const refreshed = await refresh(conn);
625
- if (refreshed?.accessToken) {
626
- accessToken = refreshed.accessToken;
627
- continue;
628
- }
629
- }
630
- } catch {
631
- // gift check error is non-fatal
632
- }
633
-
634
- if (compStatusRes.httpStatus !== 200) {
635
- return { status: "failed", error: compStatusRes.msg || `http_${compStatusRes.httpStatus}` };
636
- }
637
-
638
- const compData = compStatusRes.data || {};
639
- const giftData = giftStatusRes?.data || {};
640
-
641
- let totalClaimed = 0;
642
- const claimedItems = [];
643
- let anyClaimFailed = false;
644
- let lastClaimError = null;
645
-
646
- // Claim compensation if active and not claimed
647
- if (compData.active === true && !compData.claimed) {
648
- const claimRes = await postCnApi(CLAIM_COMPENSATION_URL, accessToken, uid, proxyOptions);
649
- if (claimRes.httpStatus === 200 && (claimRes.code === 0 || claimRes.code === "0")) {
650
- const amount = Number(compData.credit_num) || 0;
651
- totalClaimed += amount;
652
- claimedItems.push({ type: "compensation", amount, endTime: compData.end_time });
653
- } else {
654
- anyClaimFailed = true;
655
- lastClaimError = claimRes.msg || `http_${claimRes.httpStatus}`;
656
- }
657
- }
658
-
659
- // Claim gift if active and not claimed
660
- if (giftData.active === true && !giftData.claimed) {
661
- const claimGiftRes = await postCnApi(CLAIM_GIFT_URL, accessToken, uid, proxyOptions);
662
- if (claimGiftRes.httpStatus === 200 && (claimGiftRes.code === 0 || claimGiftRes.code === "0")) {
663
- const amount = Number(giftData.credit_num) || 0;
664
- totalClaimed += amount;
665
- claimedItems.push({ type: "gift", amount, endTime: giftData.end_time });
666
- } else {
667
- anyClaimFailed = true;
668
- lastClaimError = claimGiftRes.msg || `http_${claimGiftRes.httpStatus}`;
669
- }
670
- }
671
-
672
- if (totalClaimed > 0) {
673
- return {
674
- status: "claimed",
675
- claimedAmount: totalClaimed,
676
- details: claimedItems,
677
- };
678
- }
679
-
680
- if (anyClaimFailed) {
681
- return { status: "failed", error: lastClaimError || "claim_failed" };
682
- }
683
-
684
- if (compData.claimed === true || giftData.claimed === true) {
685
- return { status: "already", claimedAmount: 0 };
686
- }
687
-
688
- if (compData.active === false && (!giftData || giftData.active === false)) {
689
- return { status: "no-activity", claimedAmount: 0 };
690
- }
691
-
692
- return { status: "already", claimedAmount: 0 };
693
- } catch (err) {
694
- return { status: "failed", error: err?.message || String(err) };
695
- }
696
- }
697
-
698
- return { status: "failed", error: "unexpected" };
699
- }
700
-
701
- /**
702
- * One CN compensation pass: list active codebuddy-cn connections and claim any
703
- * active temporary compensation or gifts. Fail-open.
704
- *
705
- * @param {{ loadConnections?: Function, refreshConnection?: Function,
706
- * claimConnection?: Function, memo?: Record<string, string> }} [deps]
707
- * @returns {Promise<Array<{id: string, name: string, status: string, claimedAmount?: number, details?: Array, error?: string}>>}
708
- */
709
- export async function runCodebuddyCompensationTick(deps = {}) {
710
- const results = [];
711
- const load = deps.loadConnections || loadActiveConnections;
712
- let connections = [];
713
- try {
714
- connections = await load();
715
- } catch (err) {
716
- log.warn("CB_CN_COMP", "Tick: failed to load codebuddy-cn connections (swallowed)", {
717
- error: err?.message ?? String(err),
718
- });
719
- return results;
720
- }
721
-
722
- const eligible = (Array.isArray(connections) ? connections : []).filter(isEligibleCbcnConnection);
723
- if (eligible.length === 0) {
724
- log.debug("CB_CN_COMP", "Tick: no eligible codebuddy-cn connections", {
725
- total: Array.isArray(connections) ? connections.length : 0,
726
- });
727
- return results;
728
- }
729
-
730
- log.info("CB_CN_COMP", "Compensation pass started", {
731
- eligible: eligible.length,
732
- ids: eligible.map((c) => c.id).filter(Boolean),
733
- });
734
-
735
- const memo = deps.memo || null;
736
- const today = dayKey();
737
- const claimFn = deps.claimConnection || claimCompensationOne;
738
-
739
- for (const conn of eligible) {
740
- try {
741
- if (memo && memo[conn.id] === today) {
742
- log.debug("CB_CN_COMP", `${conn.name || conn.id}: 已确认今日完成,跳过`, {
743
- id: conn.id,
744
- });
745
- continue;
746
- }
747
- const outcome = await claimFn(conn, deps);
748
- if (
749
- memo &&
750
- (outcome.status === "claimed" || outcome.status === "already" || outcome.status === "no-activity")
751
- ) {
752
- memo[conn.id] = today;
753
- }
754
- results.push({
755
- id: conn.id,
756
- name: conn.name || conn.id,
757
- status: outcome.status,
758
- claimedAmount: outcome.claimedAmount || 0,
759
- ...(outcome.details ? { details: outcome.details } : {}),
760
- ...(outcome.error ? { error: outcome.error } : {}),
761
- });
762
- const statusLabel =
763
- outcome.status === "claimed"
764
- ? `领取成功 +${outcome.claimedAmount || 0} 积分`
765
- : outcome.status === "already"
766
- ? "已领取"
767
- : outcome.status === "no-activity"
768
- ? "暂无活动"
769
- : `失败${outcome.error ? `(${outcome.error})` : ""}`;
770
- log.info("CB_CN_COMP", `${conn.name || conn.id}: ${statusLabel}`, {
771
- id: conn.id,
772
- });
773
- } catch (err) {
774
- results.push({ id: conn.id, name: conn.name || conn.id, status: "failed", error: err?.message || String(err) });
775
- log.warn("CB_CN_COMP", "Connection compensation claim failed (swallowed)", {
776
- id: conn?.id,
777
- error: err?.message ?? String(err),
778
- });
779
- }
780
- }
781
- return results;
782
- }
783
-
784
- // ─── Scheduler ─────────────────────────────────────────────────────────────
785
-
786
- // Run one guarded pass, reading both enable flags each fire so toggling off
787
- // stops further work without a restart (fail-open, never throws).
788
- async function safeTick(how) {
789
- try {
790
- const settings = await loadSettingsSafe();
791
- const done = await getDoneMap();
792
- if (settings.codeBuddyCheckin === true) {
793
- await runCodebuddyCheckinTick({ skipIfCheckedToday: true, memo: done });
794
- await persistDoneMap();
795
- } else {
796
- log.debug("CB_CN_CHECKIN", `Scheduled ${how}: setting off, skipping`);
797
- }
798
- if (settings.codeBuddyCompensation === true) {
799
- const compDone = await getCompensationDoneMap();
800
- await runCodebuddyCompensationTick({ memo: compDone });
801
- await persistCompensationDoneMap();
802
- } else {
803
- log.debug("CB_CN_COMP", `Scheduled ${how}: setting off, skipping`);
804
- }
805
- if (settings.codeBuddyIntlSession === true) {
806
- await runCodebuddyIntlSessionTick({ memo: done });
807
- await persistDoneMap();
808
- } else {
809
- log.debug("CB_INTL_SESSION", `Scheduled ${how}: setting off, skipping`);
810
- }
811
- } catch (err) {
812
- log.warn("CB_CN_CHECKIN", `Scheduled ${how} rejected (swallowed)`, {
813
- error: err?.message ?? String(err),
814
- });
815
- }
816
- }
817
-
818
- function scheduleNext() {
819
- if (!started) return;
820
- const delayMs = msUntilNextTick();
821
- clearTimer();
822
- timerHandle = setTimeout(() => {
823
- safeTick("tick").finally(() => scheduleNext());
824
- }, delayMs);
825
- if (timerHandle.unref) timerHandle.unref();
826
- log.info("CB_CN_CHECKIN", "Next all-day check-in tick scheduled", {
827
- delayMs: Math.round(delayMs / 1000),
828
- });
829
- }
830
-
831
- function clearTimer() {
832
- if (timerHandle) {
833
- clearTimeout(timerHandle);
834
- timerHandle = null;
835
- }
836
- }
837
-
838
- /**
839
- * Start the scheduler. Runs an immediate boot pass (status-check + check-in of
840
- * not-yet-done accounts) then ticks all day every ~2h. Safe to call repeatedly
841
- * (idempotent).
842
- * @param {{ skipBoot?: boolean }} [opts]
843
- * @returns {boolean} true if started this call
844
- */
845
- export function startCodebuddyCheckin(opts = {}) {
846
- if (started) return false;
847
- if (isNonServerRuntime()) {
848
- log.debug("CB_CN_CHECKIN", "Skip start outside long-running server runtime");
849
- return false;
850
- }
851
- started = true;
852
-
853
- // Boot pass (only acts when a setting is on & accounts not yet done today).
854
- if (opts.skipBoot !== true) {
855
- safeTick("boot");
856
- }
857
- scheduleNext();
858
-
859
- log.info("CB_CN_CHECKIN", "Scheduler started (all-day cadence)");
860
- return true;
861
- }
862
-
863
- export function stopCodebuddyCheckin() {
864
- clearTimer();
865
- if (started) {
866
- started = false;
867
- log.info("CB_CN_CHECKIN", "Scheduler stopped");
868
- }
869
- }
870
-
871
- export const __internals = {
872
- decodeJwt,
873
- isCodeBuddyCnRealm,
874
- isIdempotentAlready,
875
- DAILY_CHECKIN_URL,
876
- STATUS_URL,
877
- COMPENSATION_STATUS_URL,
878
- CLAIM_COMPENSATION_URL,
879
- GIFT_STATUS_URL,
880
- CLAIM_GIFT_URL,
881
- INTL_CHAT_URL,
882
- INTL_PROBE_MODEL,
883
- dayKey,
884
- msUntilNextTick,
885
- getDoneMap,
886
- persistDoneMap,
887
- getCompensationDoneMap,
888
- persistCompensationDoneMap,
889
- isEligibleCbIntlConnection,
890
- };
1
+ // CodeBuddy auto daily check-in (CN). The intl daily active-session probe was
2
+ // removed 2026-10: CodeBuddy withdrew that campaign, so the pass had nothing
3
+ // left to earn while still spending a request per account per day.
4
+ //
5
+ // Checks every active codebuddy-cn connection into the CodeBuddy CN
6
+ // "billing meter" (daily-checkin) so free daily quota is renewed without user
7
+ // action. The scheduler ticks ALL DAY (~every 2h + jitter): an account is
8
+ // attempted only until the day's check-in is confirmed (status endpoint or a
9
+ // successful POST), then it is memoized for the rest of the local day — no
10
+ // more repeated "已签到" churn across the day.
11
+ //
12
+ // Fail-open everywhere: a tick error or a single connection failure never
13
+ // rejects the whole run or kills the server.
14
+
15
+ import * as log from "../utils/logger.js";
16
+ import { isNeedsReauthCooling } from "open-sse/services/accountFallback.js";
17
+
18
+ const DAILY_CHECKIN_URL = "https://www.codebuddy.cn/v2/billing/meter/daily-checkin";
19
+ const STATUS_URL = "https://www.codebuddy.cn/v2/billing/meter/checkin-activity-status";
20
+
21
+ // CodeBuddy CN compensation & gift claim endpoints (no /v2 prefix, same host & auth).
22
+ const COMPENSATION_STATUS_URL = "https://www.codebuddy.cn/billing/meter/compensation-status";
23
+ const CLAIM_COMPENSATION_URL = "https://www.codebuddy.cn/billing/meter/claim-compensation";
24
+ const GIFT_STATUS_URL = "https://www.codebuddy.cn/billing/meter/check-gift-claimed";
25
+ const CLAIM_GIFT_URL = "https://www.codebuddy.cn/billing/meter/claim-gift";
26
+
27
+ // All-day cadence: retry every ~2h (plus jitter) until each account is done
28
+ // for the day; the per-day memo keeps already-done accounts fully idle.
29
+ const TICK_MS = 2 * 60 * 60 * 1000;
30
+ const TICK_JITTER_MS = 10 * 60 * 1000;
31
+
32
+ let started = false;
33
+ let timerHandle = null;
34
+
35
+ // connId -> local "YYYY-MM-DD" the account was last confirmed done. Persisted
36
+ // in settings as `codeBuddyDailyDone` (lazy-loaded into this cache) so a
37
+ // restart doesn't re-verify already-done accounts until the day rolls over;
38
+ // entries are pruned to today on every write. The manual check-in route never
39
+ // touches this memo.
40
+ let doneMap = null;
41
+ let compensationDoneMap = null;
42
+
43
+ async function getDoneMap() {
44
+ if (doneMap) return doneMap;
45
+ const settings = await loadSettingsSafe();
46
+ const raw = settings?.codeBuddyDailyDone;
47
+ doneMap = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
48
+ return doneMap;
49
+ }
50
+
51
+ async function getCompensationDoneMap() {
52
+ if (compensationDoneMap) return compensationDoneMap;
53
+ const settings = await loadSettingsSafe();
54
+ const raw = settings?.codeBuddyCompensationDone;
55
+ compensationDoneMap = raw && typeof raw === "object" && !Array.isArray(raw) ? { ...raw } : {};
56
+ return compensationDoneMap;
57
+ }
58
+
59
+ // Write the in-memory memo back to settings, pruned to today. Called by the
60
+ // scheduler after each pass (the ticks only mutate the passed memo object).
61
+ async function persistDoneMap() {
62
+ if (!doneMap) return;
63
+ const today = dayKey();
64
+ const pruned = {};
65
+ for (const [id, day] of Object.entries(doneMap)) {
66
+ if (day === today) pruned[id] = day;
67
+ }
68
+ try {
69
+ const { updateSettings } = await import("../../lib/localDb.js");
70
+ await updateSettings({ codeBuddyDailyDone: pruned });
71
+ for (const k of Object.keys(doneMap)) delete doneMap[k];
72
+ Object.assign(doneMap, pruned);
73
+ } catch (err) {
74
+ // Persist is best-effort — the in-memory cache still prevents same-process
75
+ // repeats; a failed write just means one extra status check after restart.
76
+ log.warn("CB_CN_CHECKIN", "Persist daily-done map failed (swallowed)", {
77
+ error: err?.message ?? String(err),
78
+ });
79
+ }
80
+ }
81
+
82
+ async function persistCompensationDoneMap() {
83
+ if (!compensationDoneMap) return;
84
+ const today = dayKey();
85
+ const pruned = {};
86
+ for (const [id, day] of Object.entries(compensationDoneMap)) {
87
+ if (day === today) pruned[id] = day;
88
+ }
89
+ try {
90
+ const { updateSettings } = await import("../../lib/localDb.js");
91
+ await updateSettings({ codeBuddyCompensationDone: pruned });
92
+ for (const k of Object.keys(compensationDoneMap)) delete compensationDoneMap[k];
93
+ Object.assign(compensationDoneMap, pruned);
94
+ } catch (err) {
95
+ log.warn("CB_CN_COMP", "Persist compensation-done map failed (swallowed)", {
96
+ error: err?.message ?? String(err),
97
+ });
98
+ }
99
+ }
100
+
101
+ // ─── Pure helpers (unit-testable, no I/O) ──────────────────────────────────
102
+
103
+ function decodeJwt(jwt) {
104
+ try {
105
+ const seg = String(jwt).split(".")[1];
106
+ const b64 = seg.replace(/-/g, "+").replace(/_/g, "/");
107
+ const pad = b64 + "=".repeat((4 - (b64.length % 4)) % 4);
108
+ return JSON.parse(Buffer.from(pad, "base64").toString("utf8"));
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ function isCodeBuddyCnRealm(iss) {
115
+ return (
116
+ typeof iss === "string" &&
117
+ (iss.includes("codebuddy.cn") || iss.includes("copilot.tencent.com"))
118
+ );
119
+ }
120
+
121
+ function dayKey(nowMs = Date.now()) {
122
+ const d = new Date(nowMs);
123
+ const p = (n) => String(n).padStart(2, "0");
124
+ return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
125
+ }
126
+
127
+ /**
128
+ * Eligibility: an active codebuddy-cn OAuth connection whose access token is
129
+ * signed by a CodeBuddy CN Keycloak realm (has an access token at all).
130
+ * @param {object} conn
131
+ * @returns {boolean}
132
+ */
133
+ export function isEligibleCbcnConnection(conn) {
134
+ if (!conn || !conn.accessToken) return false;
135
+ if (conn.provider !== "codebuddy-cn") return false;
136
+ if (conn.isActive === false) return false;
137
+ // Needs-reauth cooling: the token set is known-dead. A check-in would 401,
138
+ // its refresh re-marks the account and re-extends the cooldown window forever.
139
+ if (isNeedsReauthCooling(conn)) return false;
140
+ const claims = decodeJwt(conn.accessToken) || {};
141
+ return isCodeBuddyCnRealm(claims.iss || "");
142
+ }
143
+
144
+ function isIdempotentAlready(msg) {
145
+ if (typeof msg !== "string") return false;
146
+ // CN "今天已签到" / generic "repeat/already" markers from the CodeBuddy gateway.
147
+ return /已签到|签到过|重复签到|already|repeat/i.test(msg);
148
+ }
149
+
150
+ /**
151
+ * Map a daily-checkin HTTP result to a stable status string.
152
+ * @param {{ httpStatus: number, code?: number|string, msg?: string }} res
153
+ * @returns {"checked-in"|"already"|"failed"}
154
+ */
155
+ export function mapDailyCheckinStatus({ httpStatus, code, msg } = {}) {
156
+ if (httpStatus >= 200 && httpStatus < 300) return "checked-in";
157
+ // HTTP 400 + known idempotent codes/messages ⇒ already signed in today.
158
+ if (httpStatus === 400) {
159
+ if (code === 10001 || code === "10001" || isIdempotentAlready(msg)) return "already";
160
+ }
161
+ return "failed";
162
+ }
163
+
164
+ /**
165
+ * Delay (ms) until the next all-day tick: fixed ~2h cadence plus jitter so
166
+ * many instances don't tick in lockstep. `rand` is injectable for tests.
167
+ * @param {number} [nowMs]
168
+ * @param {() => number} [rand] 0..1 uniform
169
+ * @returns {number}
170
+ */
171
+ export function msUntilNextTick(nowMs = Date.now(), rand = Math.random) {
172
+ const jitter = Math.floor(rand() * TICK_JITTER_MS);
173
+ return Math.max(TICK_MS + jitter, 1000);
174
+ }
175
+
176
+ function isNonServerRuntime() {
177
+ if (typeof window !== "undefined") return true;
178
+ const phase = process.env.NEXT_PHASE || "";
179
+ if (phase === "phase-production-build" || phase === "phase-export" || phase === "phase-static") {
180
+ return true;
181
+ }
182
+ if (process.env.NEXT_RUNTIME === "edge") return true;
183
+ return false;
184
+ }
185
+
186
+ // ─── Dynamic I/O (lazy imports to avoid circular/coupling at eval time) ────
187
+
188
+ async function loadActiveConnections() {
189
+ const { getProviderConnections } = await import("../../lib/db/repos/connectionsRepo.js");
190
+ return getProviderConnections({ provider: "codebuddy-cn" });
191
+ }
192
+
193
+ async function loadSettingsSafe() {
194
+ try {
195
+ const { getSettings } = await import("../../lib/localDb.js");
196
+ return await getSettings();
197
+ } catch {
198
+ return {};
199
+ }
200
+ }
201
+
202
+ // Reuse the existing proactive refresh pipeline (refreshes + persists the new
203
+ // access token) exactly like backgroundTokenRefresh on a 401.
204
+ async function refreshOne(provider, connection) {
205
+ const { checkAndRefreshToken } = await import("./tokenRefresh.js");
206
+ const creds = await checkAndRefreshToken(provider, connection, { force: true });
207
+ return creds?.accessToken ? creds : null;
208
+ }
209
+
210
+ function proxyOptionsOf(conn) {
211
+ return conn?.proxyOptions || {
212
+ enabled: conn?.connectionProxyEnabled,
213
+ url: conn?.connectionProxyUrl,
214
+ noProxy: conn?.connectionNoProxy,
215
+ };
216
+ }
217
+
218
+ function cnHeaders(accessToken, uid) {
219
+ return {
220
+ Authorization: `Bearer ${accessToken}`,
221
+ "X-User-Id": String(uid),
222
+ "Content-Type": "application/json",
223
+ Accept: "application/json",
224
+ };
225
+ }
226
+
227
+ // One account check-in POST (no 401 retry here — caller decides) → raw result.
228
+ async function postCnApi(url, accessToken, uid, proxyOptions) {
229
+ const { proxyAwareFetch } = await import("open-sse/utils/proxyFetch.js");
230
+ const res = await proxyAwareFetch(
231
+ url,
232
+ { method: "POST", headers: cnHeaders(accessToken, uid), body: "{}" },
233
+ proxyOptions
234
+ );
235
+ const text = await res.text();
236
+ let body = null;
237
+ try {
238
+ body = text ? JSON.parse(text) : null;
239
+ } catch {
240
+ body = null;
241
+ }
242
+ return {
243
+ httpStatus: res.status,
244
+ code: body?.code ?? body?.error_code,
245
+ msg: body?.msg ?? body?.message,
246
+ data: body?.data,
247
+ rawBody: body,
248
+ };
249
+ }
250
+
251
+ async function postDailyCheckin(accessToken, uid, proxyOptions) {
252
+ return postCnApi(DAILY_CHECKIN_URL, accessToken, uid, proxyOptions);
253
+ }
254
+
255
+ async function postStatus(accessToken, uid, proxyOptions) {
256
+ const { proxyAwareFetch } = await import("open-sse/utils/proxyFetch.js");
257
+ const res = await proxyAwareFetch(
258
+ STATUS_URL,
259
+ { method: "POST", headers: cnHeaders(accessToken, uid), body: "{}" },
260
+ proxyOptions
261
+ );
262
+ const text = await res.text();
263
+ let body = null;
264
+ try {
265
+ body = text ? JSON.parse(text) : null;
266
+ } catch {
267
+ body = null;
268
+ }
269
+ return { httpStatus: res.status, body };
270
+ }
271
+
272
+ // Is the account already signed in today? Used by the scheduled pass so we
273
+ // don't re-check-in accounts that already renewed.
274
+ function isCheckedInToday(status) {
275
+ const data = status?.body?.data || {};
276
+ return status.httpStatus === 200 && (data.today_checked_in === true || data.checked_in === true);
277
+ }
278
+
279
+ /**
280
+ * Check in one connection (with a single 401 → refresh → retry). Fail-open.
281
+ * @param {object} conn
282
+ * @param {{ refreshConnection?: Function }} deps
283
+ * @returns {Promise<{status: string, error?: string}>}
284
+ */
285
+ async function checkinOne(conn, deps) {
286
+ const refresh = deps?.refreshConnection || ((c) => refreshOne("codebuddy-cn", c));
287
+ let accessToken = conn.accessToken;
288
+ const claims = decodeJwt(accessToken) || {};
289
+ const uid = claims.sub || conn.id;
290
+ const proxyOptions = proxyOptionsOf(conn);
291
+
292
+ for (let attempt = 0; attempt < 2; attempt++) {
293
+ try {
294
+ const result = await postDailyCheckin(accessToken, uid, proxyOptions);
295
+ const status = mapDailyCheckinStatus(result);
296
+ if (status !== "failed") return { status };
297
+ // 401 (invalid/expired token) → refresh once and retry.
298
+ if (result.httpStatus === 401 && attempt === 0) {
299
+ log.info("CB_CN_CHECKIN", "401 on daily-check-in, refreshing token once", {
300
+ id: conn.id,
301
+ });
302
+ const refreshed = await refresh(conn);
303
+ if (refreshed?.accessToken) accessToken = refreshed.accessToken;
304
+ else return { status: "failed", error: "refresh_failed" };
305
+ continue;
306
+ }
307
+ return { status, error: result.msg || `http_${result.httpStatus}` };
308
+ } catch (err) {
309
+ return { status: "failed", error: err?.message || String(err) };
310
+ }
311
+ }
312
+ return { status: "failed", error: "unexpected" };
313
+ }
314
+
315
+ // Prefer status-check to skip already-checked-in accounts.
316
+ async function checkinIfNotDone(conn, deps) {
317
+ const proxyOptions = proxyOptionsOf(conn);
318
+ const claims = decodeJwt(conn.accessToken) || {};
319
+ const uid = claims.sub || conn.id;
320
+ try {
321
+ const status = await postStatus(conn.accessToken, uid, proxyOptions);
322
+ if (isCheckedInToday(status)) return { status: "already" };
323
+ } catch {
324
+ // Status check is best-effort — fall through to a plain check-in.
325
+ }
326
+ return checkinOne(conn, deps);
327
+ }
328
+
329
+ export async function runCodebuddyCheckinTick(deps = {}) {
330
+ const results = [];
331
+ const load = deps.loadConnections || loadActiveConnections;
332
+ let connections = [];
333
+ try {
334
+ connections = await load();
335
+ } catch (err) {
336
+ log.warn("CB_CN_CHECKIN", "Tick: failed to load codebuddy-cn connections (swallowed)", {
337
+ error: err?.message ?? String(err),
338
+ });
339
+ return results;
340
+ }
341
+
342
+ const eligible = (Array.isArray(connections) ? connections : []).filter(isEligibleCbcnConnection);
343
+ if (eligible.length === 0) {
344
+ log.debug("CB_CN_CHECKIN", "Tick: no eligible codebuddy-cn connections", {
345
+ total: Array.isArray(connections) ? connections.length : 0,
346
+ });
347
+ return results;
348
+ }
349
+
350
+ log.info("CB_CN_CHECKIN", "Daily check-in pass started", {
351
+ eligible: eligible.length,
352
+ ids: eligible.map((c) => c.id).filter(Boolean),
353
+ });
354
+
355
+ const memo = deps.memo || null;
356
+ const today = dayKey();
357
+ const checkin = deps.checkinConnection || (deps.skipIfCheckedToday ? checkinIfNotDone : checkinOne);
358
+
359
+ for (const conn of eligible) {
360
+ try {
361
+ if (memo && memo[conn.id] === today) {
362
+ log.debug("CB_CN_CHECKIN", `${conn.name || conn.id}: 已确认今日完成,跳过`, {
363
+ id: conn.id,
364
+ });
365
+ continue;
366
+ }
367
+ const outcome = await checkin(conn, deps);
368
+ if (memo && (outcome.status === "checked-in" || outcome.status === "already")) {
369
+ memo[conn.id] = today;
370
+ }
371
+ results.push({
372
+ id: conn.id,
373
+ name: conn.name || conn.id,
374
+ status: outcome.status,
375
+ ...(outcome.error ? { error: outcome.error } : {}),
376
+ });
377
+ const statusLabel =
378
+ outcome.status === "checked-in"
379
+ ? "签到成功"
380
+ : outcome.status === "already"
381
+ ? "今日已签到"
382
+ : `失败${outcome.error ? `(${outcome.error})` : ""}`;
383
+ log.info("CB_CN_CHECKIN", `${conn.name || conn.id}: ${statusLabel}`, {
384
+ id: conn.id,
385
+ });
386
+ } catch (err) {
387
+ results.push({ id: conn.id, name: conn.name || conn.id, status: "failed" });
388
+ log.warn("CB_CN_CHECKIN", "Connection check-in failed (swallowed)", {
389
+ id: conn?.id,
390
+ error: err?.message ?? String(err),
391
+ });
392
+ }
393
+ }
394
+ return results;
395
+ }
396
+
397
+ /**
398
+ * Claim compensation and first-month gifts for one connection (with single 401 -> refresh -> retry).
399
+ * @param {object} conn
400
+ * @param {{ refreshConnection?: Function }} [deps]
401
+ * @returns {Promise<{status: string, claimedAmount?: number, details?: Array, error?: string}>}
402
+ */
403
+ export async function claimCompensationOne(conn, deps) {
404
+ const refresh = deps?.refreshConnection || ((c) => refreshOne("codebuddy-cn", c));
405
+ let accessToken = conn.accessToken;
406
+ const claims = decodeJwt(accessToken) || {};
407
+ const uid = claims.sub || conn.id;
408
+ const proxyOptions = proxyOptionsOf(conn);
409
+
410
+ for (let attempt = 0; attempt < 2; attempt++) {
411
+ try {
412
+ // 1. Check compensation status
413
+ const compStatusRes = await postCnApi(COMPENSATION_STATUS_URL, accessToken, uid, proxyOptions);
414
+ if (compStatusRes.httpStatus === 401 && attempt === 0) {
415
+ log.info("CB_CN_COMP", "401 on compensation status, refreshing token once", { id: conn.id });
416
+ const refreshed = await refresh(conn);
417
+ if (refreshed?.accessToken) {
418
+ accessToken = refreshed.accessToken;
419
+ continue;
420
+ }
421
+ return { status: "failed", error: "refresh_failed" };
422
+ }
423
+
424
+ // 2. Check gift status (best effort)
425
+ let giftStatusRes = null;
426
+ try {
427
+ giftStatusRes = await postCnApi(GIFT_STATUS_URL, accessToken, uid, proxyOptions);
428
+ if (giftStatusRes.httpStatus === 401 && attempt === 0) {
429
+ log.info("CB_CN_COMP", "401 on gift status, refreshing token once", { id: conn.id });
430
+ const refreshed = await refresh(conn);
431
+ if (refreshed?.accessToken) {
432
+ accessToken = refreshed.accessToken;
433
+ continue;
434
+ }
435
+ }
436
+ } catch {
437
+ // gift check error is non-fatal
438
+ }
439
+
440
+ if (compStatusRes.httpStatus !== 200) {
441
+ return { status: "failed", error: compStatusRes.msg || `http_${compStatusRes.httpStatus}` };
442
+ }
443
+
444
+ const compData = compStatusRes.data || {};
445
+ const giftData = giftStatusRes?.data || {};
446
+
447
+ let totalClaimed = 0;
448
+ const claimedItems = [];
449
+ let anyClaimFailed = false;
450
+ let lastClaimError = null;
451
+
452
+ // Claim compensation if active and not claimed
453
+ if (compData.active === true && !compData.claimed) {
454
+ const claimRes = await postCnApi(CLAIM_COMPENSATION_URL, accessToken, uid, proxyOptions);
455
+ if (claimRes.httpStatus === 200 && (claimRes.code === 0 || claimRes.code === "0")) {
456
+ const amount = Number(compData.credit_num) || 0;
457
+ totalClaimed += amount;
458
+ claimedItems.push({ type: "compensation", amount, endTime: compData.end_time });
459
+ } else {
460
+ anyClaimFailed = true;
461
+ lastClaimError = claimRes.msg || `http_${claimRes.httpStatus}`;
462
+ }
463
+ }
464
+
465
+ // Claim gift if active and not claimed
466
+ if (giftData.active === true && !giftData.claimed) {
467
+ const claimGiftRes = await postCnApi(CLAIM_GIFT_URL, accessToken, uid, proxyOptions);
468
+ if (claimGiftRes.httpStatus === 200 && (claimGiftRes.code === 0 || claimGiftRes.code === "0")) {
469
+ const amount = Number(giftData.credit_num) || 0;
470
+ totalClaimed += amount;
471
+ claimedItems.push({ type: "gift", amount, endTime: giftData.end_time });
472
+ } else {
473
+ anyClaimFailed = true;
474
+ lastClaimError = claimGiftRes.msg || `http_${claimGiftRes.httpStatus}`;
475
+ }
476
+ }
477
+
478
+ if (totalClaimed > 0) {
479
+ return {
480
+ status: "claimed",
481
+ claimedAmount: totalClaimed,
482
+ details: claimedItems,
483
+ };
484
+ }
485
+
486
+ if (anyClaimFailed) {
487
+ return { status: "failed", error: lastClaimError || "claim_failed" };
488
+ }
489
+
490
+ if (compData.claimed === true || giftData.claimed === true) {
491
+ return { status: "already", claimedAmount: 0 };
492
+ }
493
+
494
+ if (compData.active === false && (!giftData || giftData.active === false)) {
495
+ return { status: "no-activity", claimedAmount: 0 };
496
+ }
497
+
498
+ return { status: "already", claimedAmount: 0 };
499
+ } catch (err) {
500
+ return { status: "failed", error: err?.message || String(err) };
501
+ }
502
+ }
503
+
504
+ return { status: "failed", error: "unexpected" };
505
+ }
506
+
507
+ /**
508
+ * One CN compensation pass: list active codebuddy-cn connections and claim any
509
+ * active temporary compensation or gifts. Fail-open.
510
+ *
511
+ * @param {{ loadConnections?: Function, refreshConnection?: Function,
512
+ * claimConnection?: Function, memo?: Record<string, string> }} [deps]
513
+ * @returns {Promise<Array<{id: string, name: string, status: string, claimedAmount?: number, details?: Array, error?: string}>>}
514
+ */
515
+ export async function runCodebuddyCompensationTick(deps = {}) {
516
+ const results = [];
517
+ const load = deps.loadConnections || loadActiveConnections;
518
+ let connections = [];
519
+ try {
520
+ connections = await load();
521
+ } catch (err) {
522
+ log.warn("CB_CN_COMP", "Tick: failed to load codebuddy-cn connections (swallowed)", {
523
+ error: err?.message ?? String(err),
524
+ });
525
+ return results;
526
+ }
527
+
528
+ const eligible = (Array.isArray(connections) ? connections : []).filter(isEligibleCbcnConnection);
529
+ if (eligible.length === 0) {
530
+ log.debug("CB_CN_COMP", "Tick: no eligible codebuddy-cn connections", {
531
+ total: Array.isArray(connections) ? connections.length : 0,
532
+ });
533
+ return results;
534
+ }
535
+
536
+ log.info("CB_CN_COMP", "Compensation pass started", {
537
+ eligible: eligible.length,
538
+ ids: eligible.map((c) => c.id).filter(Boolean),
539
+ });
540
+
541
+ const memo = deps.memo || null;
542
+ const today = dayKey();
543
+ const claimFn = deps.claimConnection || claimCompensationOne;
544
+
545
+ for (const conn of eligible) {
546
+ try {
547
+ if (memo && memo[conn.id] === today) {
548
+ log.debug("CB_CN_COMP", `${conn.name || conn.id}: 已确认今日完成,跳过`, {
549
+ id: conn.id,
550
+ });
551
+ continue;
552
+ }
553
+ const outcome = await claimFn(conn, deps);
554
+ if (
555
+ memo &&
556
+ (outcome.status === "claimed" || outcome.status === "already" || outcome.status === "no-activity")
557
+ ) {
558
+ memo[conn.id] = today;
559
+ }
560
+ results.push({
561
+ id: conn.id,
562
+ name: conn.name || conn.id,
563
+ status: outcome.status,
564
+ claimedAmount: outcome.claimedAmount || 0,
565
+ ...(outcome.details ? { details: outcome.details } : {}),
566
+ ...(outcome.error ? { error: outcome.error } : {}),
567
+ });
568
+ const statusLabel =
569
+ outcome.status === "claimed"
570
+ ? `领取成功 +${outcome.claimedAmount || 0} 积分`
571
+ : outcome.status === "already"
572
+ ? "已领取"
573
+ : outcome.status === "no-activity"
574
+ ? "暂无活动"
575
+ : `失败${outcome.error ? `(${outcome.error})` : ""}`;
576
+ log.info("CB_CN_COMP", `${conn.name || conn.id}: ${statusLabel}`, {
577
+ id: conn.id,
578
+ });
579
+ } catch (err) {
580
+ results.push({ id: conn.id, name: conn.name || conn.id, status: "failed", error: err?.message || String(err) });
581
+ log.warn("CB_CN_COMP", "Connection compensation claim failed (swallowed)", {
582
+ id: conn?.id,
583
+ error: err?.message ?? String(err),
584
+ });
585
+ }
586
+ }
587
+ return results;
588
+ }
589
+
590
+ // ─── Scheduler ─────────────────────────────────────────────────────────────
591
+
592
+ // Run one guarded pass, reading both enable flags each fire so toggling off
593
+ // stops further work without a restart (fail-open, never throws).
594
+ async function safeTick(how) {
595
+ try {
596
+ const settings = await loadSettingsSafe();
597
+ const done = await getDoneMap();
598
+ if (settings.codeBuddyCheckin === true) {
599
+ await runCodebuddyCheckinTick({ skipIfCheckedToday: true, memo: done });
600
+ await persistDoneMap();
601
+ } else {
602
+ log.debug("CB_CN_CHECKIN", `Scheduled ${how}: setting off, skipping`);
603
+ }
604
+ if (settings.codeBuddyCompensation === true) {
605
+ const compDone = await getCompensationDoneMap();
606
+ await runCodebuddyCompensationTick({ memo: compDone });
607
+ await persistCompensationDoneMap();
608
+ } else {
609
+ log.debug("CB_CN_COMP", `Scheduled ${how}: setting off, skipping`);
610
+ }
611
+ } catch (err) {
612
+ log.warn("CB_CN_CHECKIN", `Scheduled ${how} rejected (swallowed)`, {
613
+ error: err?.message ?? String(err),
614
+ });
615
+ }
616
+ }
617
+
618
+ function scheduleNext() {
619
+ if (!started) return;
620
+ const delayMs = msUntilNextTick();
621
+ clearTimer();
622
+ timerHandle = setTimeout(() => {
623
+ safeTick("tick").finally(() => scheduleNext());
624
+ }, delayMs);
625
+ if (timerHandle.unref) timerHandle.unref();
626
+ log.info("CB_CN_CHECKIN", "Next all-day check-in tick scheduled", {
627
+ delayMs: Math.round(delayMs / 1000),
628
+ });
629
+ }
630
+
631
+ function clearTimer() {
632
+ if (timerHandle) {
633
+ clearTimeout(timerHandle);
634
+ timerHandle = null;
635
+ }
636
+ }
637
+
638
+ /**
639
+ * Start the scheduler. Runs an immediate boot pass (status-check + check-in of
640
+ * not-yet-done accounts) then ticks all day every ~2h. Safe to call repeatedly
641
+ * (idempotent).
642
+ * @param {{ skipBoot?: boolean }} [opts]
643
+ * @returns {boolean} true if started this call
644
+ */
645
+ export function startCodebuddyCheckin(opts = {}) {
646
+ if (started) return false;
647
+ if (isNonServerRuntime()) {
648
+ log.debug("CB_CN_CHECKIN", "Skip start outside long-running server runtime");
649
+ return false;
650
+ }
651
+ started = true;
652
+
653
+ // Boot pass (only acts when a setting is on & accounts not yet done today).
654
+ if (opts.skipBoot !== true) {
655
+ safeTick("boot");
656
+ }
657
+ scheduleNext();
658
+
659
+ log.info("CB_CN_CHECKIN", "Scheduler started (all-day cadence)");
660
+ return true;
661
+ }
662
+
663
+ export function stopCodebuddyCheckin() {
664
+ clearTimer();
665
+ if (started) {
666
+ started = false;
667
+ log.info("CB_CN_CHECKIN", "Scheduler stopped");
668
+ }
669
+ }
670
+
671
+ export const __internals = {
672
+ decodeJwt,
673
+ isCodeBuddyCnRealm,
674
+ isIdempotentAlready,
675
+ DAILY_CHECKIN_URL,
676
+ STATUS_URL,
677
+ COMPENSATION_STATUS_URL,
678
+ CLAIM_COMPENSATION_URL,
679
+ GIFT_STATUS_URL,
680
+ CLAIM_GIFT_URL,
681
+ dayKey,
682
+ msUntilNextTick,
683
+ getDoneMap,
684
+ persistDoneMap,
685
+ getCompensationDoneMap,
686
+ persistCompensationDoneMap,
687
+ };