@cartanova/qgrid-cli 2.10.9 → 2.11.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 (318) hide show
  1. package/bundle/dist/_virtual/_rolldown/runtime.js +1 -10
  2. package/bundle/dist/application/monit/log-buffer.js +12 -6
  3. package/bundle/dist/application/monit/monit.frame.js +11 -3
  4. package/bundle/dist/application/monit/monit.types.js +1 -1
  5. package/bundle/dist/application/qgrid/conv-routing.js +9 -6
  6. package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
  7. package/bundle/dist/application/qgrid/oauth.js +31 -4
  8. package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
  9. package/bundle/dist/application/qgrid/qgrid-response-format.js +22 -20
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +43 -34
  11. package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
  12. package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
  13. package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
  14. package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
  15. package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
  16. package/bundle/dist/application/qgrid/token-death.js +1 -1
  17. package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
  18. package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
  19. package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
  20. package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
  21. package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
  22. package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
  23. package/bundle/dist/application/request-log/request-log.model.js +83 -69
  24. package/bundle/dist/application/request-log/request-log.types.js +8 -2
  25. package/bundle/dist/application/request-log/zod-code-format.js +1 -1
  26. package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
  27. package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
  28. package/bundle/dist/application/setting/setting.constant.js +1 -1
  29. package/bundle/dist/application/setting/setting.model.js +2 -2
  30. package/bundle/dist/application/setting/setting.store.js +2 -2
  31. package/bundle/dist/application/setting/setting.types.js +1 -1
  32. package/bundle/dist/application/sonamu.generated.js +40 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +2 -1
  34. package/bundle/dist/application/token/token.model.js +26 -9
  35. package/bundle/dist/application/token/token.types.js +20 -3
  36. package/bundle/dist/i18n/en.js +15 -1
  37. package/bundle/dist/i18n/ko.js +15 -1
  38. package/bundle/dist/i18n/sd.generated.js +2 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/migrations/20261018215031_alter_request_logs_add1_alter1.js +15 -0
  41. package/bundle/dist/server-bootstrap.js +4 -2
  42. package/bundle/dist/server-error-handler.js +1 -1
  43. package/bundle/dist/sonamu.config.js +37 -8
  44. package/bundle/dist/startup-migrations.js +17 -7
  45. package/bundle/dist/testing/global.js +1 -1
  46. package/bundle/dist/testing/schema-bench.js +0 -0
  47. package/bundle/dist/testing/test-database-name.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  49. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  50. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  51. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  52. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  53. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  54. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  55. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  56. package/bundle/dist/utils/providers/common/effort.js +3 -3
  57. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  58. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  59. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  60. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  61. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  62. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  63. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  64. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  65. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  66. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  67. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  68. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  69. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  70. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  71. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  72. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  73. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  74. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  75. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  76. package/bundle/dist/utils/providers/grok/index.js +11 -0
  77. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  78. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  79. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  80. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  81. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  82. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  83. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  84. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  85. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  86. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  87. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  88. package/bundle/dist/utils/quiet-hours.js +1 -1
  89. package/bundle/dist/utils/slack-notify.js +14 -8
  90. package/bundle/dist/utils/subset-loaders.js +4 -5
  91. package/bundle/src/application/monit/log-buffer.ts +23 -9
  92. package/bundle/src/application/monit/monit.frame.ts +22 -5
  93. package/bundle/src/application/monit/monit.types.ts +6 -0
  94. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  95. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  96. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  97. package/bundle/src/application/qgrid/oauth.ts +51 -15
  98. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  99. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +33 -0
  101. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +87 -40
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  103. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  104. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  105. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  106. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  107. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  108. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  109. package/bundle/src/application/qgrid/token-death.ts +4 -0
  110. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  111. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  112. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  113. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  114. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  115. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  116. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  117. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  118. package/bundle/src/application/request-log/request-log.entity.json +8 -0
  119. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  120. package/bundle/src/application/request-log/request-log.model.ts +279 -145
  121. package/bundle/src/application/request-log/request-log.types.ts +17 -0
  122. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  123. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  124. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  125. package/bundle/src/application/setting/setting.constant.ts +9 -0
  126. package/bundle/src/application/setting/setting.model.ts +12 -2
  127. package/bundle/src/application/setting/setting.store.ts +5 -1
  128. package/bundle/src/application/setting/setting.types.ts +8 -0
  129. package/bundle/src/application/sonamu.generated.http +135 -0
  130. package/bundle/src/application/sonamu.generated.sso.ts +3 -0
  131. package/bundle/src/application/sonamu.generated.ts +29 -0
  132. package/bundle/src/application/token/token.identity.test.ts +20 -0
  133. package/bundle/src/application/token/token.model.ts +66 -7
  134. package/bundle/src/application/token/token.types.ts +24 -1
  135. package/bundle/src/i18n/en.ts +19 -0
  136. package/bundle/src/i18n/ko.ts +21 -0
  137. package/bundle/src/i18n/sd.generated.ts +24 -2
  138. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  139. package/bundle/src/migrations/20261018215031_alter_request_logs_add1_alter1.ts +15 -0
  140. package/bundle/src/server-bootstrap.ts +4 -2
  141. package/bundle/src/server-error-handler.ts +1 -0
  142. package/bundle/src/sonamu.config.ts +69 -7
  143. package/bundle/src/startup-migrations.ts +27 -9
  144. package/bundle/src/testing/global.ts +20 -0
  145. package/bundle/src/testing/schema-bench.ts +105 -30
  146. package/bundle/src/testing/test-database-name.ts +2 -0
  147. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  148. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  149. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  150. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  151. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  152. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  153. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  154. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  155. package/bundle/src/utils/providers/common/effort.ts +9 -2
  156. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  157. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  158. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  159. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  160. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  161. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  162. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  163. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  164. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  165. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  166. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  167. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  168. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  169. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  170. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  171. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  172. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  173. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  174. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  175. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  176. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  177. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  178. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  179. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  180. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  181. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  182. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  183. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  184. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  185. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  186. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  187. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  188. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  189. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  190. package/bundle/src/utils/providers/grok/index.ts +20 -0
  191. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  192. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  193. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  194. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  195. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  196. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  197. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  198. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  199. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  200. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  201. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  202. package/bundle/src/utils/quiet-hours.ts +12 -1
  203. package/bundle/src/utils/slack-notify.ts +44 -13
  204. package/bundle/src/utils/subset-loaders.ts +7 -7
  205. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  206. package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
  207. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  208. package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
  209. package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
  210. package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
  211. package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
  212. package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
  213. package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
  214. package/bundle/web-dist/client/assets/{services.generated-BsieU37H.js → services.generated-CefiDXEv.js} +5 -5
  215. package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
  216. package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
  217. package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
  218. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  219. package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
  220. package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
  221. package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
  222. package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
  223. package/bundle/web-dist/client/index.html +6 -6
  224. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  225. package/bundle/web-dist/server/assets/{lazyRouteComponent-Dtd0NR4r.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
  226. package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
  227. package/bundle/web-dist/server/assets/{monit-DvzribSE.js → monit-B2hqorPe.js} +385 -126
  228. package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
  229. package/bundle/web-dist/server/assets/{react-dom-B4a6-uuR.js → react-dom-BIYQzBqG.js} +2 -129
  230. package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
  231. package/bundle/web-dist/server/assets/{request-model-CbqfnQOJ.js → request-model-I6OdODSH.js} +15 -6
  232. package/bundle/web-dist/server/assets/{routes-BAPWTizT.js → routes-B95YlUv2.js} +760 -213
  233. package/bundle/web-dist/server/assets/{services.generated-CEbGjsI0.js → services.generated-DQATJ6qf.js} +12821 -12194
  234. package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
  235. package/bundle/web-dist/server/assets/{show-CxVZTAdv.js → show-Bxaj3rhH.js} +1355 -419
  236. package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
  237. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  238. package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
  239. package/bundle/web-dist/server/assets/{use-update-token-mutation-CfYmk_4_.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
  240. package/bundle/web-dist/server/entry-server.generated.js +4303 -22810
  241. package/dist/cli.js +9 -9
  242. package/package.json +4 -11
  243. package/postinstall.mjs +12 -0
  244. package/skills/qgrid/SKILL.md +1 -0
  245. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  246. package/skills/qgrid/references/decision-rationale.md +24 -1
  247. package/skills/qgrid/references/grok-runtime.md +89 -0
  248. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  249. package/skills/qgrid/references/repo-map.md +10 -0
  250. package/skills/qgrid/references/request-log-run-lifecycle.md +1 -1
  251. package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
  252. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  253. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  254. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  255. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  256. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  257. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  258. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  259. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  260. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  262. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  263. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  264. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  265. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  266. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  267. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  268. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  269. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  270. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  271. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  272. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  273. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  274. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  275. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  276. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  277. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  278. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  279. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  280. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  281. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  282. package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
  283. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
  284. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
  285. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
  286. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
  287. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
  288. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
  289. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
  290. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
  291. package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
  292. package/bundle/dist/testing/setup-mocks.js +0 -16
  293. package/bundle/src/testing/setup-mocks.ts +0 -44
  294. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  295. package/bundle/web-dist/client/assets/index-CrXKu_J8.js +0 -106
  296. package/bundle/web-dist/client/assets/logs-B2SmWJXA.js +0 -1
  297. package/bundle/web-dist/client/assets/monit-D-JwXXoA.js +0 -1
  298. package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
  299. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
  300. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
  301. package/bundle/web-dist/client/assets/routes-C5r4gTvY.js +0 -5
  302. package/bundle/web-dist/client/assets/settings-D3tDSAck.js +0 -1
  303. package/bundle/web-dist/client/assets/show-Cah_kUKC.js +0 -2
  304. package/bundle/web-dist/client/assets/tokens-DU2Iyxxd.js +0 -1
  305. package/bundle/web-dist/client/assets/use-oauth-login-flow-D0UaR9_e.js +0 -1
  306. package/bundle/web-dist/client/assets/use-update-token-mutation-DAq0F8p-.js +0 -1
  307. package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  308. package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
  309. package/bundle/web-dist/server/assets/logs-l91avYif.js +0 -509
  310. package/bundle/web-dist/server/assets/plus-KZrECewT.js +0 -19
  311. package/bundle/web-dist/server/assets/refresh-cw-BND93JrF.js +0 -23
  312. package/bundle/web-dist/server/assets/settings-BZR5HSAL.js +0 -461
  313. package/bundle/web-dist/server/assets/tokens-D1hb4eKk.js +0 -448
  314. package/bundle/web-dist/server/assets/use-oauth-login-flow-Cvdy0zF8.js +0 -178
  315. package/dist/cli.d.ts +0 -10
  316. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  317. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  318. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -8,7 +8,21 @@ import {
8
8
  type ImageGenerationMetadata,
9
9
  type ImageGenerationOptions,
10
10
  type QgridContent,
11
+ type ReasoningSummary,
12
+ type Verbosity,
11
13
  } from "../../../application/qgrid/qgrid.types";
14
+ import {
15
+ type GrokImageEditRequest,
16
+ type GrokImageGenerateRequest,
17
+ type GrokImageResponse,
18
+ type GrokSpeechResult,
19
+ type GrokSttResponse,
20
+ type GrokTranscribeRequest,
21
+ type GrokTtsRequest,
22
+ type GrokVideoStart,
23
+ type GrokVideoStartRequest,
24
+ type GrokVideoStatus,
25
+ } from "../grok/grok-types";
12
26
  import { type JsonValue, type TokenUsageBreakdown, type UserInput } from "./provider-types";
13
27
 
14
28
  // qgrid provider 내부 표준 usage. provider 전용 cache write 세부 필드는 여기서 확장해 보존한다.
@@ -16,8 +30,38 @@ export type ProviderTokenUsageBreakdown = TokenUsageBreakdown & {
16
30
  cacheCreationInputTokens?: number;
17
31
  cacheCreationInputTokens5m?: number;
18
32
  cacheCreationInputTokens1h?: number;
33
+ // Live context size reported by the provider (Grok `usage.context_details`), distinct from
34
+ // the cumulative input token count.
35
+ contextTokens?: number;
36
+ };
37
+
38
+ // Native provider tools. Function tools follow the Responses API shape; built-in tools are
39
+ // executed server-side by the provider (Grok `web_search` / `x_search`).
40
+ export type ProviderFunctionToolDefinition = {
41
+ type: "function";
42
+ name: string;
43
+ description?: string;
44
+ parameters: JsonValue;
45
+ strict?: boolean;
19
46
  };
20
47
 
48
+ export type ProviderBuiltinToolDefinition = { type: "web_search" } | { type: "x_search" };
49
+
50
+ export type ToolDefinition = ProviderFunctionToolDefinition | ProviderBuiltinToolDefinition;
51
+
52
+ // A native function call returned by the provider (not the qgrid tool-emulation envelope).
53
+ export interface ProviderToolCall {
54
+ toolCallId: string;
55
+ toolName: string;
56
+ // Raw JSON argument string as returned by the provider.
57
+ input: string;
58
+ }
59
+
60
+ export interface XaiProviderMetadata {
61
+ costInUsdTicks?: number;
62
+ contextWindow?: number;
63
+ }
64
+
21
65
  // 공개 thread 좌표의 provider 결과 부분. 이름은 호환성을 위해 유지한다.
22
66
  export interface ReuseThreadCoord {
23
67
  workerId: number;
@@ -58,8 +102,8 @@ export interface GenerateRequest {
58
102
  stopAfterOutputMessage?: (text: string, phase?: string) => boolean;
59
103
  effort?: string;
60
104
  thinking?: boolean;
61
- verbosity?: string;
62
- reasoningSummary?: string;
105
+ verbosity?: Verbosity;
106
+ reasoningSummary?: ReasoningSummary;
63
107
  serviceTier?: string;
64
108
  // provider 실행 제한(ms). Queue selection 이후의 active provider request 전체에 적용한다.
65
109
  timeoutMs?: number;
@@ -78,6 +122,11 @@ export interface GenerateRequest {
78
122
  // 이 플래그가 있으면 OpenAI prompt-cache affinity 라우팅을 건너뛴다.
79
123
  imageGeneration?: boolean | "auto";
80
124
  imageGenerationOptions?: ImageGenerationOptions;
125
+ // Opaque provider namespaces (for example `providerOptions.xai`). Each dispatcher validates its
126
+ // own namespace; other providers ignore it.
127
+ providerOptions?: { [key: string]: JsonValue | undefined };
128
+ // Native tools for providers that accept them on the wire (Grok).
129
+ tools?: ToolDefinition[];
81
130
  }
82
131
 
83
132
  export interface GenerateResult {
@@ -97,6 +146,11 @@ export interface GenerateResult {
97
146
  threadCoord: ReuseThreadCoord;
98
147
  // 이미지 turn 에서만 채워짐(OpenAI 경로). 완성 이미지가 없으면 undefined.
99
148
  images?: GeneratedImage[];
149
+ // Origin of costUsd; "provider" when the provider reported the cost itself.
150
+ costSource?: CostSource;
151
+ providerMetadata?: { xai?: XaiProviderMetadata };
152
+ // Native function calls returned by providers that accept `GenerateRequest.tools`.
153
+ toolCalls?: ProviderToolCall[];
100
154
  }
101
155
 
102
156
  // 스트림 콜백 컨테이너. 계층별로 onComplete payload 만 다르고, 스트림 이벤트 shape 는 동일하다.
@@ -117,3 +171,45 @@ export interface ProviderDispatcher {
117
171
  start(): Promise<void>;
118
172
  stop(): Promise<void>;
119
173
  }
174
+
175
+ // Token selection hints for media/voice requests. There is no cache affinity; a caller may still
176
+ // pin an exact token.
177
+ export interface MediaTokenSelection {
178
+ preferredTokenId?: number;
179
+ requirePreferredToken?: boolean;
180
+ }
181
+
182
+ export interface MediaDispatchResult<T> {
183
+ result: T;
184
+ tokenId: number;
185
+ tokenName: string;
186
+ }
187
+
188
+ // Optional capability: image and video generation. Video polling always goes to the token that
189
+ // started the job.
190
+ export interface MediaDispatcher {
191
+ generateImages(
192
+ request: GrokImageGenerateRequest & MediaTokenSelection,
193
+ ): Promise<MediaDispatchResult<GrokImageResponse>>;
194
+ editImages(
195
+ request: GrokImageEditRequest & MediaTokenSelection,
196
+ ): Promise<MediaDispatchResult<GrokImageResponse>>;
197
+ startVideo(
198
+ request: GrokVideoStartRequest & MediaTokenSelection,
199
+ ): Promise<MediaDispatchResult<GrokVideoStart>>;
200
+ getVideo(
201
+ tokenId: number,
202
+ requestId: string,
203
+ signal?: AbortSignal,
204
+ ): Promise<MediaDispatchResult<GrokVideoStatus>>;
205
+ }
206
+
207
+ // Optional capability: speech-to-text and text-to-speech.
208
+ export interface VoiceDispatcher {
209
+ transcribe(
210
+ request: GrokTranscribeRequest & MediaTokenSelection,
211
+ ): Promise<MediaDispatchResult<GrokSttResponse>>;
212
+ speak(
213
+ request: GrokTtsRequest & { signal?: AbortSignal } & MediaTokenSelection,
214
+ ): Promise<MediaDispatchResult<GrokSpeechResult>>;
215
+ }
@@ -1,11 +1,54 @@
1
- export type JsonValue =
1
+ import { z } from "zod";
2
+
3
+ // qgrid provider route prefix (`<provider>/<model>`). 새 provider 는 여기에만 추가한다.
4
+ export const PROVIDER_IDS = ["openai", "anthropic", "grok"] as const;
5
+
6
+ export type ProviderId = (typeof PROVIDER_IDS)[number];
7
+
8
+ export function isProviderId(value: string | undefined): value is ProviderId {
9
+ return PROVIDER_IDS.some((id) => id === value);
10
+ }
11
+
12
+ export type JsonValue = number | string | boolean | JsonValue[] | JsonObject | null;
13
+
14
+ export interface JsonObject {
15
+ [key: string]: JsonValue | undefined;
16
+ }
17
+
18
+ /** JsonValue accepted read-only, for callers that pass `as const` or frozen JSON. */
19
+ export type ReadonlyJsonValue =
2
20
  | number
3
21
  | string
4
22
  | boolean
5
- | JsonValue[]
6
- | { [key: string]: JsonValue | undefined }
23
+ | readonly ReadonlyJsonValue[]
24
+ | ReadonlyJsonObject
7
25
  | null;
8
26
 
27
+ export interface ReadonlyJsonObject {
28
+ readonly [key: string]: ReadonlyJsonValue | undefined;
29
+ }
30
+
31
+ /** Decodes parsed JSON text (for example `JSON.parse` output) into `JsonValue`. */
32
+ export const jsonValueSchema: z.ZodType<JsonValue> = z.json();
33
+
34
+ // Shallow: accepts any non-null, non-array object, including null-prototype objects.
35
+ const anyJsonObject = z.looseObject({});
36
+
37
+ /** Narrows an already-decoded JSON value to its object member. */
38
+ export function isJsonObject(value: JsonValue | undefined): value is JsonObject {
39
+ return anyJsonObject.safeParse(value).success;
40
+ }
41
+
42
+ /** The string member of a decoded JSON value, or undefined for any other member. */
43
+ export function jsonString(value: JsonValue | undefined): string | undefined {
44
+ return z.string().safeParse(value).data;
45
+ }
46
+
47
+ /** The number member of a decoded JSON value, or undefined for any other member. */
48
+ export function jsonNumber(value: JsonValue | undefined): number | undefined {
49
+ return z.number().safeParse(value).data;
50
+ }
51
+
9
52
  export type UserInput =
10
53
  | { type: "text"; text: string; text_elements: TextElement[] }
11
54
  | { type: "image"; url: string }
@@ -2,6 +2,7 @@ import { Buffer } from "node:buffer";
2
2
 
3
3
  import { describe, expect, it, vi } from "vitest";
4
4
 
5
+ import { type JsonObject } from "./provider-types";
5
6
  import {
6
7
  ANTHROPIC_SCHEMA_ARGV_MAX_UTF8_BYTES,
7
8
  CALLER_SCHEMA_LIMITS,
@@ -116,7 +117,10 @@ describe("caller schema validation", () => {
116
117
  });
117
118
 
118
119
  it("rejects non-serializable direct dispatch schemas", () => {
119
- expect(() => serializeAndValidateDispatchSchema(() => {}, "anthropic")).toThrow(
120
+ const cyclic: JsonObject = { type: "object" };
121
+ cyclic.self = cyclic;
122
+
123
+ expect(() => serializeAndValidateDispatchSchema(cyclic, "anthropic")).toThrow(
120
124
  "dispatch schema must be JSON-serializable",
121
125
  );
122
126
  });
@@ -1,6 +1,8 @@
1
1
  import { Buffer } from "node:buffer";
2
2
 
3
- import { type JsonValue } from "./provider-types";
3
+ import { z } from "zod";
4
+
5
+ import { isJsonObject, type JsonValue } from "./provider-types";
4
6
 
5
7
  /**
6
8
  * Caller-provided schemas are serialized, copied, and recursively normalized before dispatch.
@@ -43,38 +45,45 @@ export function parseAndValidateCallerSchemas(input: CallerSchemasInput): JsonVa
43
45
  nodes: 0,
44
46
  schemas: 0,
45
47
  };
48
+
46
49
  let outputSchema: JsonValue | undefined;
47
50
 
48
51
  if (input.jsonSchema !== undefined) {
49
52
  addUtf8Bytes(Buffer.byteLength(input.jsonSchema, "utf8"), "jsonSchema", state);
50
53
 
51
- let parsed: unknown;
54
+ let parsed: JsonValue;
55
+
52
56
  try {
57
+ // JSON.parse without a reviver yields only JSON values.
53
58
  parsed = JSON.parse(input.jsonSchema);
54
59
  } catch {
55
60
  throw new CallerSchemaValidationError("jsonSchema must contain valid JSON");
56
61
  }
57
62
 
58
- if (!isRecord(parsed) || parsed.type !== "object") {
63
+ if (!isJsonObject(parsed) || parsed.type !== "object") {
59
64
  throw new CallerSchemaValidationError('jsonSchema top-level type must be "object"');
60
65
  }
61
66
 
62
- addComplexity(parsed, "jsonSchema", state);
67
+ complexityWalk("jsonSchema", state, false).parse(parsed);
63
68
  state.schemas += 1;
64
- outputSchema = parsed as JsonValue;
69
+ outputSchema = parsed;
65
70
  }
66
71
 
67
72
  for (const [index, tool] of (input.tools ?? []).entries()) {
68
73
  addToolMetadataUtf8Bytes(tool, index, state);
69
74
 
70
75
  const path = `tools[${index}].inputSchema`;
71
- addComplexity(tool.inputSchema, path, state, true);
76
+ complexityWalk(path, state, true).parse(tool.inputSchema);
72
77
 
73
- const serialized = stringifyJsonOrThrow(tool.inputSchema, path);
78
+ const serialized = callerJsonText.safeParse(tool.inputSchema);
79
+
80
+ if (!serialized.success) {
81
+ throw new CallerSchemaValidationError(`${path} must be JSON-serializable`);
82
+ }
74
83
 
75
84
  // buildToolCallSchema embeds this serialization inside another JSON string. Charge the
76
85
  // escaped outer-string representation before that composed description is materialized.
77
- addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(serialized), path, state);
86
+ addUtf8Bytes(jsonStringContentUtf8ByteUpperBound(serialized.data), path, state);
78
87
  state.schemas += 1;
79
88
  }
80
89
 
@@ -82,7 +91,7 @@ export function parseAndValidateCallerSchemas(input: CallerSchemasInput): JsonVa
82
91
  }
83
92
 
84
93
  export function serializeAndValidateDispatchSchema(
85
- schema: unknown,
94
+ schema: JsonValue | undefined,
86
95
  provider?: string,
87
96
  ): string | undefined {
88
97
  if (schema === undefined) return undefined;
@@ -90,11 +99,13 @@ export function serializeAndValidateDispatchSchema(
90
99
  const serialized = stringifyJsonOrThrow(schema, "dispatch schema");
91
100
 
92
101
  const byteLength = Buffer.byteLength(serialized, "utf8");
102
+
93
103
  if (byteLength > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) {
94
104
  throw new CallerSchemaValidationError(
95
105
  `dispatch schema exceeds UTF-8 byte limit of ${CALLER_SCHEMA_LIMITS.maxUtf8Bytes}`,
96
106
  );
97
107
  }
108
+
98
109
  if (provider === "anthropic") {
99
110
  assertAnthropicSchemaArgvSize(serialized);
100
111
  }
@@ -110,21 +121,47 @@ export function assertAnthropicSchemaArgvSize(jsonSchema: string): void {
110
121
  }
111
122
  }
112
123
 
113
- function stringifyJsonOrThrow(value: unknown, subject: string): string {
124
+ /**
125
+ * Decodes an opaque caller value (QgridTool.inputSchema is z.unknown() at the API boundary) into
126
+ * its JSON text. Cycles, BigInt, and values with no JSON form (bare undefined, functions) fail.
127
+ */
128
+ const callerJsonText = z.unknown().transform((value, context): string => {
114
129
  let serialized: string | undefined;
130
+
131
+ try {
132
+ serialized = JSON.stringify(value);
133
+ } catch {
134
+ serialized = undefined;
135
+ }
136
+
137
+ if (serialized === undefined) {
138
+ context.addIssue({ code: "custom", message: "value is not JSON-serializable" });
139
+
140
+ return z.NEVER;
141
+ }
142
+
143
+ return serialized;
144
+ });
145
+
146
+ function stringifyJsonOrThrow(value: JsonValue, subject: string): string {
147
+ let serialized: string | undefined;
148
+
115
149
  try {
116
150
  serialized = JSON.stringify(value);
117
151
  } catch {
118
152
  throw new CallerSchemaValidationError(`${subject} must be JSON-serializable`);
119
153
  }
154
+
120
155
  if (serialized === undefined) {
121
156
  throw new CallerSchemaValidationError(`${subject} must be JSON-serializable`);
122
157
  }
158
+
123
159
  return serialized;
124
160
  }
125
161
 
126
162
  function addUtf8Bytes(byteLength: number, path: string, state: ComplexityState): void {
127
163
  state.utf8Bytes += byteLength;
164
+
128
165
  if (state.utf8Bytes > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) {
129
166
  throwLimitError(path, "UTF-8 byte", CALLER_SCHEMA_LIMITS.maxUtf8Bytes, state);
130
167
  }
@@ -162,6 +199,7 @@ function addToolMetadataUtf8Bytes(
162
199
  jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_NAME_SEPARATOR) +
163
200
  jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_INPUT_SCHEMA_PREFIX) +
164
201
  (index === 0 ? 0 : jsonStringContentUtf8ByteUpperBound(TOOL_DESCRIPTION_ENTRY_SEPARATOR) + 1);
202
+
165
203
  addUtf8Bytes(framingBytes, toolPath, state);
166
204
  }
167
205
 
@@ -181,12 +219,15 @@ function jsonStringContentUtf8ByteUpperBound(value: string): number {
181
219
  bytes += 2;
182
220
  continue;
183
221
  }
222
+
184
223
  if (codeUnit <= 0x1f) {
185
224
  bytes += 6;
186
225
  continue;
187
226
  }
227
+
188
228
  if (codeUnit >= 0xd800 && codeUnit <= 0xdbff) {
189
229
  const nextCodeUnit = value.charCodeAt(index + 1);
230
+
190
231
  if (nextCodeUnit >= 0xdc00 && nextCodeUnit <= 0xdfff) {
191
232
  bytes += 4;
192
233
  index += 1;
@@ -194,8 +235,10 @@ function jsonStringContentUtf8ByteUpperBound(value: string): number {
194
235
  // Well-formed JSON.stringify escapes lone surrogates as `\uXXXX`.
195
236
  bytes += 6;
196
237
  }
238
+
197
239
  continue;
198
240
  }
241
+
199
242
  if (codeUnit >= 0xdc00 && codeUnit <= 0xdfff) {
200
243
  bytes += 6;
201
244
  continue;
@@ -207,60 +250,87 @@ function jsonStringContentUtf8ByteUpperBound(value: string): number {
207
250
  return bytes;
208
251
  }
209
252
 
210
- function addComplexity(
211
- root: unknown,
212
- path: string,
213
- state: ComplexityState,
214
- precheckUtf8Bytes = false,
215
- ): void {
216
- const rawUtf8Bytes = { value: 0 };
217
- if (precheckUtf8Bytes && typeof root === "string") {
218
- addRawUtf8LowerBound(root, path, state, rawUtf8Bytes);
219
- }
220
- addNode(path, state);
221
- if (root === null || typeof root !== "object") return;
253
+ /**
254
+ * Bounded, iterative walk over a caller schema, run before anything materializes its
255
+ * serialization. Values are read one at a time, in key order, so a limit stops the walk before
256
+ * later values (including getters) are touched. That rules out decoding each value with a schema
257
+ * first; nodes are classified by identity instead: Object(value) === value holds exactly for
258
+ * objects, arrays, and functions.
259
+ */
260
+ function complexityWalk(path: string, state: ComplexityState, precheckUtf8Bytes: boolean) {
261
+ return z.unknown().transform((root): void => {
262
+ const rawUtf8Bytes = { value: 0 };
263
+
264
+ if (precheckUtf8Bytes && isPrimitiveText(root)) {
265
+ addRawUtf8LowerBound(root, path, state, rawUtf8Bytes);
266
+ }
267
+
268
+ addNode(path, state);
269
+
270
+ if (root === null || root === undefined || Object(root) !== root) return;
271
+
272
+ const rootObject: object = Object(root);
273
+ const stack: Array<{ value: object; depth: number }> = [{ value: rootObject, depth: 0 }];
274
+
275
+ while (stack.length > 0) {
276
+ const current = stack.pop()!;
222
277
 
223
- const stack: Array<{ value: Record<string, unknown> | unknown[]; depth: number }> = [
224
- { value: root as Record<string, unknown> | unknown[], depth: 0 },
225
- ];
278
+ if (Array.isArray(current.value)) {
279
+ for (let index = 0; index < current.value.length; index += 1) {
280
+ const depth = current.depth + 1;
281
+ assertDepthWithinLimit(depth, path);
282
+ addNode(path, state);
283
+
284
+ const child: unknown = current.value[index];
285
+
286
+ if (precheckUtf8Bytes && isPrimitiveText(child)) {
287
+ addRawUtf8LowerBound(child, path, state, rawUtf8Bytes);
288
+ }
289
+
290
+ if (child !== null && child !== undefined && Object(child) === child) {
291
+ stack.push({ value: Object(child), depth });
292
+ }
293
+ }
294
+
295
+ continue;
296
+ }
297
+
298
+ for (const key in current.value) {
299
+ if (!Object.hasOwn(current.value, key)) continue;
300
+
301
+ if (precheckUtf8Bytes) {
302
+ addRawUtf8LowerBound(key, path, state, rawUtf8Bytes);
303
+ }
226
304
 
227
- while (stack.length > 0) {
228
- const current = stack.pop()!;
229
- if (Array.isArray(current.value)) {
230
- for (let index = 0; index < current.value.length; index += 1) {
231
305
  const depth = current.depth + 1;
232
306
  assertDepthWithinLimit(depth, path);
233
307
  addNode(path, state);
234
308
 
235
- const child = current.value[index];
236
- if (precheckUtf8Bytes && typeof child === "string") {
309
+ // Same read as current.value[key] for an own property: data value, or the getter's result.
310
+ const descriptor = Object.getOwnPropertyDescriptor(current.value, key);
311
+
312
+ const child: unknown = descriptor?.get
313
+ ? descriptor.get.call(current.value)
314
+ : descriptor?.value;
315
+
316
+ if (precheckUtf8Bytes && isPrimitiveText(child)) {
237
317
  addRawUtf8LowerBound(child, path, state, rawUtf8Bytes);
238
318
  }
239
- if (child !== null && typeof child === "object") {
240
- stack.push({ value: child as Record<string, unknown> | unknown[], depth });
319
+
320
+ if (child !== null && child !== undefined && Object(child) === child) {
321
+ stack.push({ value: Object(child), depth });
241
322
  }
242
323
  }
243
- continue;
244
324
  }
325
+ });
326
+ }
245
327
 
246
- for (const key in current.value) {
247
- if (!Object.hasOwn(current.value, key)) continue;
248
- if (precheckUtf8Bytes) {
249
- addRawUtf8LowerBound(key, path, state, rawUtf8Bytes);
250
- }
251
- const depth = current.depth + 1;
252
- assertDepthWithinLimit(depth, path);
253
- addNode(path, state);
254
-
255
- const child = current.value[key];
256
- if (precheckUtf8Bytes && typeof child === "string") {
257
- addRawUtf8LowerBound(child, path, state, rawUtf8Bytes);
258
- }
259
- if (child !== null && typeof child === "object") {
260
- stack.push({ value: child as Record<string, unknown> | unknown[], depth });
261
- }
262
- }
263
- }
328
+ /**
329
+ * String test for the bounded walk. A failed zod parse builds a ZodError (which serializes the
330
+ * input), so the walk uses identity: a primitive whose String() form is itself is a string.
331
+ */
332
+ function isPrimitiveText(value: unknown): value is string {
333
+ return Object(value) !== value && String(value) === value;
264
334
  }
265
335
 
266
336
  function addRawUtf8LowerBound(
@@ -270,6 +340,7 @@ function addRawUtf8LowerBound(
270
340
  rawUtf8Bytes: { value: number },
271
341
  ): void {
272
342
  rawUtf8Bytes.value += Buffer.byteLength(value, "utf8");
343
+
273
344
  if (state.utf8Bytes + rawUtf8Bytes.value > CALLER_SCHEMA_LIMITS.maxUtf8Bytes) {
274
345
  throwLimitError(path, "UTF-8 byte", CALLER_SCHEMA_LIMITS.maxUtf8Bytes, state);
275
346
  }
@@ -285,6 +356,7 @@ function assertDepthWithinLimit(depth: number, path: string): void {
285
356
 
286
357
  function addNode(path: string, state: ComplexityState): void {
287
358
  state.nodes += 1;
359
+
288
360
  if (state.nodes > CALLER_SCHEMA_LIMITS.maxNodes) {
289
361
  throwLimitError(path, "node", CALLER_SCHEMA_LIMITS.maxNodes, state);
290
362
  }
@@ -302,7 +374,3 @@ function throwLimitError(
302
374
  : `caller schemas exceed aggregate ${kind} limit of ${limit}`,
303
375
  );
304
376
  }
305
-
306
- function isRecord(value: unknown): value is Record<string, unknown> {
307
- return value !== null && typeof value === "object" && !Array.isArray(value);
308
- }
@@ -6,6 +6,7 @@ export class SmoothWeightedRoundRobin {
6
6
  if (!Number.isInteger(weight) || weight < 1 || weight > 100) {
7
7
  throw new RangeError("weight must be an integer between 1 and 100");
8
8
  }
9
+
9
10
  if (this.weights.get(tokenId) === weight) return;
10
11
  this.weights.set(tokenId, weight);
11
12
  this.resetScores();
@@ -25,6 +26,7 @@ export class SmoothWeightedRoundRobin {
25
26
  const candidates = [...eligibleTokenIds]
26
27
  .filter((tokenId) => this.weights.has(tokenId))
27
28
  .toSorted((a, b) => a - b);
29
+
28
30
  if (candidates.length === 0) return null;
29
31
 
30
32
  let selected = candidates[0]!;
@@ -36,6 +38,7 @@ export class SmoothWeightedRoundRobin {
36
38
  totalWeight += weight;
37
39
  const score = (this.currentScores.get(tokenId) ?? 0) + weight;
38
40
  this.currentScores.set(tokenId, score);
41
+
39
42
  if (score > selectedScore) {
40
43
  selected = tokenId;
41
44
  selectedScore = score;
@@ -43,6 +46,7 @@ export class SmoothWeightedRoundRobin {
43
46
  });
44
47
 
45
48
  this.currentScores.set(selected, selectedScore - totalWeight);
49
+
46
50
  return selected;
47
51
  }
48
52
  }