@cartanova/qgrid-cli 2.10.10 → 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 (313) 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 +21 -19
  10. package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +40 -33
  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 -70
  24. package/bundle/dist/application/request-log/request-log.types.js +1 -1
  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 +32 -16
  33. package/bundle/dist/application/sonamu.generated.sso.js +1 -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 +1 -1
  39. package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
  40. package/bundle/dist/server-bootstrap.js +4 -2
  41. package/bundle/dist/server-error-handler.js +1 -1
  42. package/bundle/dist/sonamu.config.js +37 -8
  43. package/bundle/dist/startup-migrations.js +17 -7
  44. package/bundle/dist/testing/global.js +1 -1
  45. package/bundle/dist/testing/schema-bench.js +0 -0
  46. package/bundle/dist/testing/test-database-name.js +1 -1
  47. package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
  48. package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
  49. package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
  50. package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
  51. package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
  52. package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
  53. package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
  54. package/bundle/dist/utils/providers/common/credentials.js +5 -1
  55. package/bundle/dist/utils/providers/common/effort.js +3 -3
  56. package/bundle/dist/utils/providers/common/model-cost.js +69 -14
  57. package/bundle/dist/utils/providers/common/provider-types.js +29 -1
  58. package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
  59. package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
  60. package/bundle/dist/utils/providers/common/strictifier.js +62 -43
  61. package/bundle/dist/utils/providers/common/thinking.js +3 -2
  62. package/bundle/dist/utils/providers/common/ttft.js +1 -1
  63. package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
  64. package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
  65. package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
  66. package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
  67. package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
  68. package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
  69. package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
  70. package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
  71. package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
  72. package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
  73. package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
  74. package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
  75. package/bundle/dist/utils/providers/grok/index.js +11 -0
  76. package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
  77. package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
  78. package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
  79. package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
  80. package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
  81. package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
  82. package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
  83. package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
  84. package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
  85. package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
  86. package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
  87. package/bundle/dist/utils/quiet-hours.js +1 -1
  88. package/bundle/dist/utils/slack-notify.js +14 -8
  89. package/bundle/dist/utils/subset-loaders.js +4 -5
  90. package/bundle/src/application/monit/log-buffer.ts +23 -9
  91. package/bundle/src/application/monit/monit.frame.ts +22 -5
  92. package/bundle/src/application/monit/monit.types.ts +6 -0
  93. package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
  94. package/bundle/src/application/qgrid/conv-routing.ts +35 -9
  95. package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
  96. package/bundle/src/application/qgrid/oauth.ts +51 -15
  97. package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
  98. package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
  99. package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +19 -0
  100. package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +84 -40
  101. package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
  102. package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
  103. package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
  104. package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
  105. package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
  106. package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
  107. package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
  108. package/bundle/src/application/qgrid/token-death.ts +4 -0
  109. package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
  110. package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
  111. package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
  112. package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
  113. package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
  114. package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
  115. package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
  116. package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
  117. package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
  118. package/bundle/src/application/request-log/request-log.model.ts +277 -146
  119. package/bundle/src/application/request-log/request-log.types.ts +6 -0
  120. package/bundle/src/application/request-log/zod-code-format.ts +11 -0
  121. package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
  122. package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
  123. package/bundle/src/application/setting/setting.constant.ts +9 -0
  124. package/bundle/src/application/setting/setting.model.ts +12 -2
  125. package/bundle/src/application/setting/setting.store.ts +5 -1
  126. package/bundle/src/application/setting/setting.types.ts +8 -0
  127. package/bundle/src/application/sonamu.generated.http +133 -0
  128. package/bundle/src/application/sonamu.generated.sso.ts +2 -0
  129. package/bundle/src/application/sonamu.generated.ts +15 -0
  130. package/bundle/src/application/token/token.identity.test.ts +20 -0
  131. package/bundle/src/application/token/token.model.ts +66 -7
  132. package/bundle/src/application/token/token.types.ts +24 -1
  133. package/bundle/src/i18n/en.ts +19 -0
  134. package/bundle/src/i18n/ko.ts +21 -0
  135. package/bundle/src/i18n/sd.generated.ts +23 -2
  136. package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
  137. package/bundle/src/server-bootstrap.ts +4 -2
  138. package/bundle/src/server-error-handler.ts +1 -0
  139. package/bundle/src/sonamu.config.ts +69 -7
  140. package/bundle/src/startup-migrations.ts +27 -9
  141. package/bundle/src/testing/global.ts +20 -0
  142. package/bundle/src/testing/schema-bench.ts +105 -30
  143. package/bundle/src/testing/test-database-name.ts +2 -0
  144. package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
  145. package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
  146. package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
  147. package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
  148. package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
  149. package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
  150. package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
  151. package/bundle/src/utils/providers/common/credentials.ts +8 -0
  152. package/bundle/src/utils/providers/common/effort.ts +9 -2
  153. package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
  154. package/bundle/src/utils/providers/common/model-cost.ts +259 -158
  155. package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
  156. package/bundle/src/utils/providers/common/provider-types.ts +46 -3
  157. package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
  158. package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
  159. package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
  160. package/bundle/src/utils/providers/common/strictifier.ts +185 -59
  161. package/bundle/src/utils/providers/common/thinking.ts +2 -2
  162. package/bundle/src/utils/providers/common/ttft.ts +4 -2
  163. package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
  164. package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
  165. package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
  166. package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
  167. package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
  168. package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
  169. package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
  170. package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
  171. package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
  172. package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
  173. package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
  174. package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
  175. package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
  176. package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
  177. package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
  178. package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
  179. package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
  180. package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
  181. package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
  182. package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
  183. package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
  184. package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
  185. package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
  186. package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
  187. package/bundle/src/utils/providers/grok/index.ts +20 -0
  188. package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
  189. package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
  190. package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
  191. package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
  192. package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
  193. package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
  194. package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
  195. package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
  196. package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
  197. package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
  198. package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
  199. package/bundle/src/utils/quiet-hours.ts +12 -1
  200. package/bundle/src/utils/slack-notify.ts +44 -13
  201. package/bundle/src/utils/subset-loaders.ts +7 -7
  202. package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
  203. package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
  204. package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
  205. package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
  206. package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
  207. package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
  208. package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
  209. package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
  210. package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
  211. package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-CefiDXEv.js} +5 -5
  212. package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
  213. package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
  214. package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
  215. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  216. package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
  217. package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
  218. package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
  219. package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
  220. package/bundle/web-dist/client/index.html +6 -6
  221. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  222. package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
  223. package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
  224. package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-B2hqorPe.js} +385 -126
  225. package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
  226. package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-BIYQzBqG.js} +2 -129
  227. package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
  228. package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-I6OdODSH.js} +15 -6
  229. package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-B95YlUv2.js} +760 -213
  230. package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-DQATJ6qf.js} +12820 -12194
  231. package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
  232. package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-Bxaj3rhH.js} +1350 -418
  233. package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
  234. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  235. package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
  236. package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
  237. package/bundle/web-dist/server/entry-server.generated.js +4295 -22810
  238. package/dist/cli.js +9 -9
  239. package/package.json +4 -11
  240. package/postinstall.mjs +12 -0
  241. package/skills/qgrid/SKILL.md +1 -0
  242. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  243. package/skills/qgrid/references/decision-rationale.md +23 -0
  244. package/skills/qgrid/references/grok-runtime.md +89 -0
  245. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  246. package/skills/qgrid/references/repo-map.md +10 -0
  247. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  248. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  249. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  250. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  251. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  252. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  253. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  254. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  255. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  256. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  257. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  258. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  259. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  260. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  262. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  263. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  264. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  265. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  266. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  267. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  268. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  269. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  270. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  271. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  272. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  273. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  274. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  275. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  276. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  277. 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
  278. 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
  279. 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
  280. 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
  281. 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
  282. 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
  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/rpc.MzXet3jl.js +0 -119
  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/test.DNmyFkvJ.js +0 -3044
  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/utils.BX5Fg8C4.js +0 -59
  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/index.js +0 -28
  287. package/bundle/dist/testing/setup-mocks.js +0 -16
  288. package/bundle/src/testing/setup-mocks.ts +0 -44
  289. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  290. package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
  291. package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
  292. package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
  293. package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
  294. package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
  295. package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
  296. package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
  297. package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
  298. package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
  299. package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
  300. package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
  301. package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
  302. package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
  303. package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
  304. package/bundle/web-dist/server/assets/logs-BMyR98rU.js +0 -509
  305. package/bundle/web-dist/server/assets/plus-BZ9I0VgC.js +0 -19
  306. package/bundle/web-dist/server/assets/refresh-cw-CztCFis-.js +0 -23
  307. package/bundle/web-dist/server/assets/settings-CBUZ47Xx.js +0 -461
  308. package/bundle/web-dist/server/assets/tokens-DxrBW512.js +0 -448
  309. package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
  310. package/dist/cli.d.ts +0 -10
  311. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  312. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  313. /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
@@ -8,14 +8,23 @@
8
8
  * - recursive 처리 (nested objects, arrays, allOf/anyOf/oneOf)
9
9
  */
10
10
 
11
+ import { z } from "zod";
12
+
11
13
  import {
12
14
  SCHEMA_ARRAY_KEYWORDS,
13
15
  SCHEMA_MAP_KEYWORDS,
14
16
  SCHEMA_SINGLE_KEYWORDS,
15
17
  UNSUPPORTED_REFERENCE_KEYWORDS,
16
18
  } from "./json-schema-keywords";
19
+ import {
20
+ isJsonObject,
21
+ type JsonObject,
22
+ type JsonValue,
23
+ type ReadonlyJsonObject,
24
+ } from "./provider-types";
17
25
 
18
- export type JsonSchema = Record<string, unknown>;
26
+ /** An object-form JSON Schema node. Boolean schemas and malformed members stay plain JSON values. */
27
+ export type JsonSchema = JsonObject;
19
28
 
20
29
  export interface StrictifierOptions {
21
30
  provider?: string;
@@ -31,14 +40,24 @@ export class StrictifierError extends Error {
31
40
  }
32
41
  }
33
42
 
34
- export function strictify(schema: JsonSchema, options: StrictifierOptions = {}): JsonSchema {
43
+ export function strictify(input: ReadonlyJsonObject, options: StrictifierOptions = {}): JsonSchema {
44
+ // Work on the JSON the provider will receive: a fresh copy, with undefined members dropped as
45
+ // serialization drops them. JSON.parse without a reviver yields only JSON values.
46
+ const serialized: JsonValue = JSON.parse(JSON.stringify(input));
47
+
48
+ if (!isSchemaObject(serialized)) throw new StrictifierError("schema must be an object", "$");
49
+ const schema = serialized;
50
+
35
51
  if (options.provider === "openai" || options.provider === "anthropic") {
36
52
  assertNormalizationCompatibility(schema, options.provider);
37
53
  }
54
+
38
55
  const result = strictifyNode(schema, "$", options.provider);
56
+
39
57
  if (options.provider === "openai" || options.provider === "anthropic") {
40
58
  assertNormalizationCompatibility(result, options.provider);
41
59
  }
60
+
42
61
  return result;
43
62
  }
44
63
 
@@ -70,6 +89,7 @@ function positionEntries(keywords: readonly string[]): ReadonlyArray<readonly [s
70
89
 
71
90
  const SCHEMA_SCAN_MAP_KEYWORDS = positionEntries(SCHEMA_MAP_KEYWORDS);
72
91
  const SCHEMA_SCAN_ARRAY_KEYWORDS = positionEntries(SCHEMA_ARRAY_KEYWORDS);
92
+
73
93
  // items/additionalItems 는 tuple 분기에서 직접 다루므로 단일 위치 스캔에서 제외한다.
74
94
  const SCHEMA_SCAN_SINGLE_KEYWORDS = positionEntries(
75
95
  SCHEMA_SINGLE_KEYWORDS.filter((keyword) => keyword !== "items" && keyword !== "additionalItems"),
@@ -88,6 +108,7 @@ function assertNormalizationCompatibility(
88
108
  provider: "openai" | "anthropic",
89
109
  ): void {
90
110
  const references: Array<{ value: string; path: string }> = [];
111
+
91
112
  const stack: Array<{ node: JsonSchema; path: string; normalizable: boolean }> = [
92
113
  { node: schema, path: "$", normalizable: true },
93
114
  ];
@@ -103,19 +124,22 @@ function assertNormalizationCompatibility(
103
124
  collectSchemaReference(current, references);
104
125
 
105
126
  if (legacyTuple || prefixTuple) {
106
- const tuple = (legacyTuple ? itemsValue : prefixItemsValue) as unknown[];
127
+ const tuple = legacyTuple ? itemsValue : prefixTuple ? prefixItemsValue : [];
128
+
107
129
  if (provider === "anthropic" && tuple.length > 0) {
108
130
  throw new StrictifierError(
109
131
  "positional tuple schemas are not supported on Anthropic because Claude Code cannot preserve item positions",
110
132
  current.path,
111
133
  );
112
134
  }
135
+
113
136
  if (!current.normalizable) {
114
137
  throw new StrictifierError(
115
138
  "positional tuple schemas are not supported in this schema position",
116
139
  current.path,
117
140
  );
118
141
  }
142
+
119
143
  if (ownValue(current.node, "type") !== "array") {
120
144
  throw new StrictifierError(
121
145
  'positional tuple schemas must declare type "array"; express nullable tuples with anyOf',
@@ -126,7 +150,9 @@ function assertNormalizationCompatibility(
126
150
 
127
151
  for (const [keyword, keywordNormalizable] of SCHEMA_SCAN_MAP_KEYWORDS) {
128
152
  const schemas = ownValue(current.node, keyword);
153
+
129
154
  if (!isSchemaObject(schemas)) continue;
155
+
130
156
  for (const [name, child] of Object.entries(schemas)) {
131
157
  if (!isSchemaObject(child)) continue;
132
158
  stack.push({
@@ -138,6 +164,7 @@ function assertNormalizationCompatibility(
138
164
  }
139
165
 
140
166
  const dependencies = ownValue(current.node, "dependencies");
167
+
141
168
  if (isSchemaObject(dependencies)) {
142
169
  for (const [name, child] of Object.entries(dependencies)) {
143
170
  if (!isSchemaObject(child)) continue;
@@ -151,9 +178,12 @@ function assertNormalizationCompatibility(
151
178
 
152
179
  for (const [keyword, keywordNormalizable] of SCHEMA_SCAN_ARRAY_KEYWORDS) {
153
180
  const schemas = ownValue(current.node, keyword);
181
+
154
182
  if (!Array.isArray(schemas)) continue;
183
+
155
184
  for (let index = 0; index < schemas.length; index += 1) {
156
185
  const child = schemas[index];
186
+
157
187
  if (!isSchemaObject(child)) continue;
158
188
  stack.push({
159
189
  node: child,
@@ -164,6 +194,7 @@ function assertNormalizationCompatibility(
164
194
  }
165
195
 
166
196
  const items = ownValue(current.node, "items");
197
+
167
198
  if (isSchemaObject(items)) {
168
199
  stack.push({
169
200
  node: items,
@@ -173,6 +204,7 @@ function assertNormalizationCompatibility(
173
204
  } else if (Array.isArray(items)) {
174
205
  for (let index = 0; index < items.length; index += 1) {
175
206
  const child = items[index];
207
+
176
208
  if (!isSchemaObject(child)) continue;
177
209
  stack.push({
178
210
  node: child,
@@ -183,6 +215,7 @@ function assertNormalizationCompatibility(
183
215
  }
184
216
 
185
217
  const additionalItems = ownValue(current.node, "additionalItems");
218
+
186
219
  if (isSchemaObject(additionalItems)) {
187
220
  stack.push({
188
221
  node: additionalItems,
@@ -193,6 +226,7 @@ function assertNormalizationCompatibility(
193
226
 
194
227
  for (const [keyword, keywordNormalizable] of SCHEMA_SCAN_SINGLE_KEYWORDS) {
195
228
  const child = ownValue(current.node, keyword);
229
+
196
230
  if (!isSchemaObject(child)) continue;
197
231
  stack.push({
198
232
  node: child,
@@ -220,9 +254,12 @@ function collectSchemaReference(
220
254
  if (!Object.hasOwn(current.node, "$ref")) return;
221
255
 
222
256
  const reference = current.node.$ref;
223
- if (typeof reference !== "string") {
257
+ const referenceText = z.string().safeParse(reference);
258
+
259
+ if (!referenceText.success) {
224
260
  throw new StrictifierError("$ref must be a string", `${current.path}.$ref`);
225
261
  }
262
+
226
263
  if (!current.normalizable) {
227
264
  throw new StrictifierError(
228
265
  "schema references are not supported in this schema position",
@@ -230,7 +267,7 @@ function collectSchemaReference(
230
267
  );
231
268
  }
232
269
 
233
- references.push({ value: reference, path: `${current.path}.$ref` });
270
+ references.push({ value: referenceText.data, path: `${current.path}.$ref` });
234
271
  }
235
272
 
236
273
  function assertReferenceTargets(
@@ -239,28 +276,33 @@ function assertReferenceTargets(
239
276
  ): void {
240
277
  for (const reference of references) {
241
278
  const tokens = parseLocalJsonPointer(reference.value, reference.path);
279
+
242
280
  if (!isDefinitionRootPointer(tokens)) {
243
281
  throw new StrictifierError(
244
282
  "$ref target must be the document root or a definition root",
245
283
  reference.path,
246
284
  );
247
285
  }
286
+
248
287
  resolveDefinitionRoot(root, tokens, reference.path);
249
288
  }
250
289
  }
251
290
 
252
291
  function isDefinitionRootPointer(tokens: string[]): boolean {
253
292
  if (tokens.length === 0) return true;
293
+
254
294
  if (tokens.length % 2 !== 0) return false;
255
295
 
256
296
  for (let index = 0; index < tokens.length; index += 2) {
257
297
  if (tokens[index] !== "$defs" && tokens[index] !== "definitions") return false;
258
298
  }
299
+
259
300
  return true;
260
301
  }
261
302
 
262
303
  function parseLocalJsonPointer(reference: string, path: string): string[] {
263
304
  if (reference === "#") return [];
305
+
264
306
  if (!reference.startsWith("#/")) {
265
307
  throw new StrictifierError(
266
308
  "only local root-relative JSON Pointer $ref values are supported",
@@ -269,11 +311,13 @@ function parseLocalJsonPointer(reference: string, path: string): string[] {
269
311
  }
270
312
 
271
313
  let fragment: string;
314
+
272
315
  try {
273
316
  fragment = decodeURIComponent(reference.slice(1));
274
317
  } catch {
275
318
  throw new StrictifierError("$ref contains invalid percent encoding", path);
276
319
  }
320
+
277
321
  if (!fragment.startsWith("/")) {
278
322
  throw new StrictifierError(
279
323
  "only local root-relative JSON Pointer $ref values are supported",
@@ -289,31 +333,39 @@ function parseLocalJsonPointer(reference: string, path: string): string[] {
289
333
 
290
334
  function resolveDefinitionRoot(root: JsonSchema, tokens: string[], path: string): void {
291
335
  let current = root;
336
+
292
337
  for (let index = 0; index < tokens.length; index += 2) {
293
338
  const keyword = tokens[index]!;
294
339
  const name = tokens[index + 1]!;
295
340
  const definitions = ownValue(current, keyword);
341
+
296
342
  if (!isSchemaObject(definitions) || !Object.hasOwn(definitions, name)) {
297
343
  throw new StrictifierError("$ref does not resolve inside the caller schema", path);
298
344
  }
345
+
299
346
  const target = definitions[name];
347
+
300
348
  if (!isSchemaObject(target)) {
301
349
  throw new StrictifierError("$ref target must be an object schema", path);
302
350
  }
351
+
303
352
  current = target;
304
353
  }
305
354
  }
306
355
 
307
356
  function decodeJsonPointerToken(rawToken: string, path: string): string {
308
357
  let token = "";
358
+
309
359
  for (let index = 0; index < rawToken.length; index += 1) {
310
360
  const character = rawToken[index]!;
361
+
311
362
  if (character !== "~") {
312
363
  token += character;
313
364
  continue;
314
365
  }
315
366
 
316
367
  const escaped = rawToken[index + 1];
368
+
317
369
  if (escaped === "0") {
318
370
  token += "~";
319
371
  } else if (escaped === "1") {
@@ -321,17 +373,17 @@ function decodeJsonPointerToken(rawToken: string, path: string): string {
321
373
  } else {
322
374
  throw new StrictifierError("$ref contains an invalid JSON Pointer escape", path);
323
375
  }
376
+
324
377
  index += 1;
325
378
  }
379
+
326
380
  return token;
327
381
  }
328
382
 
329
383
  function strictifyNode(node: JsonSchema, path: string, provider?: string): JsonSchema {
330
- if (typeof node !== "object" || node === null) return node;
331
-
332
384
  const dialectNeutralNode = provider === "openai" ? omitKeys(node, ["$schema"]) : node;
333
385
  let result = strictifySchemaMaps(dialectNeutralNode, path, provider);
334
- const type = ownValue(result, "type") as string | undefined;
386
+ const type = ownValue(result, "type");
335
387
 
336
388
  if (type === "object" || Object.hasOwn(result, "properties")) {
337
389
  result = strictifyObject(result, path, provider);
@@ -344,6 +396,11 @@ function strictifyNode(node: JsonSchema, path: string, provider?: string): JsonS
344
396
  return strictifySchemaArrays(result, path, provider);
345
397
  }
346
398
 
399
+ /** Boolean and other non-object subschemas pass through unchanged. */
400
+ function strictifySubschema(schema: JsonValue, path: string, provider?: string): JsonValue {
401
+ return isSchemaObject(schema) ? strictifyNode(schema, path, provider) : schema;
402
+ }
403
+
347
404
  // 재작성 패스는 정의 맵만 재귀한다. properties 는 strictifyObject 가 별도로 처리하므로
348
405
  // 공유 위치 목록(SCHEMA_MAP_KEYWORDS)과 의도적으로 범위가 다르다.
349
406
  const DEFINITION_MAP_KEYWORDS = ["$defs", "definitions"] as const;
@@ -353,14 +410,15 @@ function strictifySchemaMaps(node: JsonSchema, path: string, provider?: string):
353
410
 
354
411
  for (const keyword of DEFINITION_MAP_KEYWORDS) {
355
412
  const schemas = ownValue(node, keyword);
413
+
356
414
  if (!isSchemaObject(schemas)) continue;
357
415
 
358
416
  result[keyword] = Object.fromEntries(
359
417
  Object.entries(schemas).map(([name, schema]) => [
360
418
  name,
361
- isSchemaObject(schema)
362
- ? strictifyNode(schema, `${path}.${keyword}.${name}`, provider)
363
- : schema,
419
+ schema === undefined
420
+ ? schema
421
+ : strictifySubschema(schema, `${path}.${keyword}.${name}`, provider),
364
422
  ]),
365
423
  );
366
424
  }
@@ -376,9 +434,15 @@ function strictifySchemaArrays(node: JsonSchema, path: string, provider?: string
376
434
 
377
435
  for (const keyword of COMBINATOR_KEYWORDS) {
378
436
  const schemas = ownValue(node, keyword);
437
+
379
438
  if (!schemas) continue;
380
- result[keyword] = (schemas as JsonSchema[]).map((schema, index) =>
381
- strictifyNode(schema, `${path}.${keyword}[${index}]`, provider),
439
+
440
+ if (!Array.isArray(schemas)) {
441
+ throw new StrictifierError(`${keyword} must be an array of schemas`, `${path}.${keyword}`);
442
+ }
443
+
444
+ result[keyword] = schemas.map((schema, index) =>
445
+ strictifySubschema(schema, `${path}.${keyword}[${index}]`, provider),
382
446
  );
383
447
  }
384
448
 
@@ -386,35 +450,48 @@ function strictifySchemaArrays(node: JsonSchema, path: string, provider?: string
386
450
  }
387
451
 
388
452
  function strictifyObject(node: JsonSchema, path: string, provider?: string): JsonSchema {
389
- const properties = ownValue(node, "properties") as Record<string, JsonSchema> | undefined;
453
+ const properties = ownValue(node, "properties");
454
+
390
455
  if (!properties) {
391
456
  return { ...node, additionalProperties: false };
392
457
  }
393
458
 
394
- const existingRequired = new Set((ownValue(node, "required") as string[] | undefined) ?? []);
459
+ if (!isSchemaObject(properties)) {
460
+ throw new StrictifierError("properties must be an object", `${path}.properties`);
461
+ }
462
+
463
+ const required = ownValue(node, "required");
464
+
465
+ const existingRequired = new Set(
466
+ Array.isArray(required) ? required.flatMap((key) => z.string().safeParse(key).data ?? []) : [],
467
+ );
468
+
395
469
  const allKeys = Object.keys(properties);
396
470
 
471
+ // Object.fromEntries defines own data properties, so names such as "__proto__" stay ordinary keys.
397
472
  const strictProps = Object.fromEntries(
398
- allKeys.map((key) => {
399
- const prop = properties[key]!;
400
- const strictProp = strictifyNode(prop, `${path}.${key}`, provider);
473
+ allKeys.flatMap((key) => {
474
+ const prop = properties[key];
401
475
 
402
- return [key, existingRequired.has(key) ? strictProp : makeNullable(strictProp)];
476
+ if (prop === undefined) return [];
477
+ const strictProp = strictifySubschema(prop, `${path}.${key}`, provider);
478
+
479
+ return [[key, existingRequired.has(key) ? strictProp : makeNullable(strictProp)]];
403
480
  }),
404
- ) as Record<string, JsonSchema>;
481
+ );
405
482
 
406
- const result: JsonSchema = {
483
+ return {
407
484
  ...node,
408
485
  type: "object",
409
486
  properties: strictProps,
410
487
  required: allKeys,
411
488
  additionalProperties: false,
412
489
  };
413
-
414
- return result;
415
490
  }
416
491
 
417
- const UNREACHABLE_TUPLE_TAIL_SCHEMA: JsonSchema = { type: "string" };
492
+ function unreachableTupleTailSchema(): JsonSchema {
493
+ return { type: "string" };
494
+ }
418
495
 
419
496
  function strictifyArray(node: JsonSchema, path: string, provider?: string): JsonSchema {
420
497
  if (
@@ -425,20 +502,21 @@ function strictifyArray(node: JsonSchema, path: string, provider?: string): Json
425
502
  }
426
503
 
427
504
  const result = { ...node };
428
- const items = ownValue(node, "items") as JsonSchema | JsonSchema[] | undefined;
505
+ const items = ownValue(node, "items");
429
506
 
430
507
  if (Array.isArray(items)) {
431
508
  result.items = items.map((schema, index) =>
432
- strictifyNode(schema, `${path}.items[${index}]`, provider),
509
+ strictifySubschema(schema, `${path}.items[${index}]`, provider),
433
510
  );
434
511
  } else if (items !== undefined) {
435
- result.items = strictifyNode(items, `${path}.items`, provider);
512
+ result.items = strictifySubschema(items, `${path}.items`, provider);
436
513
  }
437
514
 
438
- const prefixItems = ownValue(node, "prefixItems") as JsonSchema[] | undefined;
515
+ const prefixItems = ownValue(node, "prefixItems");
516
+
439
517
  if (Array.isArray(prefixItems)) {
440
518
  result.prefixItems = prefixItems.map((schema, index) =>
441
- strictifyNode(schema, `${path}.prefixItems[${index}]`, provider),
519
+ strictifySubschema(schema, `${path}.prefixItems[${index}]`, provider),
442
520
  );
443
521
  }
444
522
 
@@ -454,15 +532,18 @@ function normalizeTuple(
454
532
  const prefixItems = ownValue(node, "prefixItems");
455
533
  const legacyTuple = Array.isArray(items);
456
534
  const prefixTuple = Array.isArray(prefixItems);
535
+
457
536
  if (legacyTuple && prefixTuple) {
458
537
  throw new StrictifierError("items and prefixItems tuple forms cannot be combined", path);
459
538
  }
539
+
460
540
  if (prefixTuple && Object.hasOwn(node, "additionalItems")) {
461
541
  throw new StrictifierError("additionalItems cannot be combined with prefixItems", path);
462
542
  }
463
543
 
464
- const rawTuple = (legacyTuple ? items : prefixItems) as unknown[];
544
+ const rawTuple = legacyTuple ? items : prefixTuple ? prefixItems : [];
465
545
  const tuplePath = legacyTuple ? `${path}.items` : `${path}.prefixItems`;
546
+
466
547
  const tuple = rawTuple.map((schema, index) => {
467
548
  if (!isSchemaObject(schema)) {
468
549
  throw new StrictifierError(
@@ -470,21 +551,26 @@ function normalizeTuple(
470
551
  `${tuplePath}[${index}]`,
471
552
  );
472
553
  }
554
+
473
555
  const memberPath = `${tuplePath}[${index}]`;
474
556
  const member = strictifyNode(schema, memberPath, provider);
557
+
475
558
  if (!hasProviderSchemaEntryPoint(member)) {
476
559
  throw new StrictifierError(
477
560
  "tuple member must define a provider-representable schema",
478
561
  memberPath,
479
562
  );
480
563
  }
564
+
481
565
  return member;
482
566
  });
483
567
 
484
568
  const rawTail = legacyTuple ? ownValue(node, "additionalItems") : items;
569
+
485
570
  if (rawTail === true) {
486
571
  throw new StrictifierError("an unrestricted tuple rest is not supported", path);
487
572
  }
573
+
488
574
  if (rawTail !== undefined && rawTail !== false && !isSchemaObject(rawTail)) {
489
575
  throw new StrictifierError("tuple rest must be an object schema or false", path);
490
576
  }
@@ -492,22 +578,37 @@ function normalizeTuple(
492
578
  const tail = isSchemaObject(rawTail)
493
579
  ? strictifyNode(rawTail, legacyTuple ? `${path}.additionalItems` : `${path}.items`, provider)
494
580
  : undefined;
581
+
495
582
  if (tail !== undefined && !hasProviderSchemaEntryPoint(tail)) {
496
583
  throw new StrictifierError("an unrestricted tuple rest is not supported", path);
497
584
  }
585
+
498
586
  const tailMode = tail !== undefined ? "typed" : rawTail === false ? "closed" : "implicit";
499
587
  const bounds = normalizeTupleBounds(node, tuple.length, tailMode, path);
500
- const base = omitKeys(node, ["items", "prefixItems", "additionalItems", "minItems", "maxItems"]);
588
+
589
+ const result = omitKeys(node, [
590
+ "items",
591
+ "prefixItems",
592
+ "additionalItems",
593
+ "minItems",
594
+ "maxItems",
595
+ ]);
501
596
 
502
597
  // Anthropic 은 assertNormalizationCompatibility 가 비어 있지 않은 tuple 을 이미 거부했으므로
503
- // 여기 도달하는 tuple 은 빈 tuple 뿐이고, 그 경우 prefixItems spread 는 자연히 생략된다 —
598
+ // 여기 도달하는 tuple 은 빈 tuple 뿐이고, 그 경우 prefixItems 는 생략된다 —
504
599
  // provider 분기 없이 한 형태로 두 provider 모두를 표현한다.
505
- return {
506
- ...base,
507
- ...(tuple.length > 0 ? { prefixItems: tuple } : {}),
508
- items: tail ?? UNREACHABLE_TUPLE_TAIL_SCHEMA,
509
- ...bounds,
510
- };
600
+ if (tuple.length > 0) result.prefixItems = tuple;
601
+ result.items = tail ?? unreachableTupleTailSchema();
602
+ result.minItems = bounds.minItems;
603
+
604
+ if (bounds.maxItems !== undefined) result.maxItems = bounds.maxItems;
605
+
606
+ return result;
607
+ }
608
+
609
+ interface TupleBounds {
610
+ minItems: number;
611
+ maxItems?: number;
511
612
  }
512
613
 
513
614
  function normalizeTupleBounds(
@@ -515,9 +616,10 @@ function normalizeTupleBounds(
515
616
  tupleLength: number,
516
617
  tailMode: "typed" | "closed" | "implicit",
517
618
  path: string,
518
- ): { minItems: number; maxItems?: number } {
619
+ ): TupleBounds {
519
620
  const callerMinItems = integerBound(ownValue(node, "minItems"), "minItems", path);
520
621
  const callerMaxItems = integerBound(ownValue(node, "maxItems"), "maxItems", path);
622
+
521
623
  if (tailMode === "implicit" && callerMaxItems !== undefined && callerMaxItems > tupleLength) {
522
624
  throw new StrictifierError(
523
625
  "implicit tuple rest cannot be represented when maxItems exceeds the tuple length",
@@ -526,6 +628,7 @@ function normalizeTupleBounds(
526
628
  }
527
629
 
528
630
  const minItems = callerMinItems ?? (callerMaxItems === undefined ? tupleLength : 0);
631
+
529
632
  const maxItems =
530
633
  tailMode === "typed" ? callerMaxItems : Math.min(callerMaxItems ?? tupleLength, tupleLength);
531
634
 
@@ -533,25 +636,37 @@ function normalizeTupleBounds(
533
636
  throw new StrictifierError("tuple minItems cannot exceed maxItems", path);
534
637
  }
535
638
 
536
- return {
537
- minItems,
538
- ...(maxItems !== undefined ? { maxItems } : {}),
539
- };
639
+ const bounds: TupleBounds = { minItems };
640
+
641
+ if (maxItems !== undefined) bounds.maxItems = maxItems;
642
+
643
+ return bounds;
540
644
  }
541
645
 
542
- function integerBound(value: unknown, keyword: string, path: string): number | undefined {
646
+ const nonNegativeSafeInteger = z
647
+ .number()
648
+ .refine((value) => Number.isSafeInteger(value) && value >= 0);
649
+
650
+ function integerBound(
651
+ value: JsonValue | undefined,
652
+ keyword: string,
653
+ path: string,
654
+ ): number | undefined {
543
655
  if (value === undefined) return undefined;
544
- if (!Number.isSafeInteger(value) || (value as number) < 0) {
656
+ const bound = nonNegativeSafeInteger.safeParse(value);
657
+
658
+ if (!bound.success) {
545
659
  throw new StrictifierError(`${keyword} must be a non-negative safe integer`, path);
546
660
  }
547
- return value as number;
661
+
662
+ return bound.data;
548
663
  }
549
664
 
550
- function isSchemaObject(value: unknown): value is JsonSchema {
551
- return typeof value === "object" && value !== null && !Array.isArray(value);
665
+ function isSchemaObject(value: JsonValue | undefined): value is JsonSchema {
666
+ return isJsonObject(value);
552
667
  }
553
668
 
554
- function ownValue(schema: JsonSchema, keyword: string): unknown {
669
+ function ownValue(schema: JsonSchema, keyword: string): JsonValue | undefined {
555
670
  return Object.hasOwn(schema, keyword) ? schema[keyword] : undefined;
556
671
  }
557
672
 
@@ -570,27 +685,38 @@ function hasProviderSchemaEntryPoint(schema: JsonSchema): boolean {
570
685
 
571
686
  function omitKeys(node: JsonSchema, keys: readonly string[]): JsonSchema {
572
687
  const omitted = new Set(keys);
688
+
573
689
  return Object.fromEntries(Object.entries(node).filter(([key]) => !omitted.has(key)));
574
690
  }
575
691
 
576
- function makeNullable(schema: JsonSchema): JsonSchema {
692
+ function hasNullVariant(variants: JsonValue[]): boolean {
693
+ return variants.some(
694
+ (variant) => isSchemaObject(variant) && ownValue(variant, "type") === "null",
695
+ );
696
+ }
697
+
698
+ function makeNullable(schema: JsonValue): JsonValue {
699
+ const nullSchema: JsonSchema = { type: "null" };
700
+
701
+ if (!isSchemaObject(schema)) return { anyOf: [schema, nullSchema] };
702
+
577
703
  if (ownValue(schema, "type") === "null") return schema;
578
704
 
579
705
  const anyOf = ownValue(schema, "anyOf");
706
+
580
707
  if (anyOf) {
581
- const variants = anyOf as JsonSchema[];
582
- const hasNull = variants.some((v) => ownValue(v, "type") === "null");
583
- if (hasNull) return schema;
584
- return { anyOf: [...variants, { type: "null" }] };
708
+ if (!Array.isArray(anyOf)) throw new StrictifierError("anyOf must be an array of schemas", "$");
709
+
710
+ return hasNullVariant(anyOf) ? schema : { anyOf: [...anyOf, nullSchema] };
585
711
  }
586
712
 
587
713
  const oneOf = ownValue(schema, "oneOf");
714
+
588
715
  if (oneOf) {
589
- const variants = oneOf as JsonSchema[];
590
- const hasNull = variants.some((v) => ownValue(v, "type") === "null");
591
- if (hasNull) return schema;
592
- return { oneOf: [...variants, { type: "null" }] };
716
+ if (!Array.isArray(oneOf)) throw new StrictifierError("oneOf must be an array of schemas", "$");
717
+
718
+ return hasNullVariant(oneOf) ? schema : { oneOf: [...oneOf, nullSchema] };
593
719
  }
594
720
 
595
- return { anyOf: [schema, { type: "null" }] };
721
+ return { anyOf: [schema, nullSchema] };
596
722
  }
@@ -1,10 +1,10 @@
1
1
  import { BadRequestException } from "sonamu";
2
2
 
3
- import { type LocalizedString } from "../../../i18n/sd.generated";
3
+ import { SD } from "../../../i18n/sd.generated";
4
4
 
5
5
  export class ThinkingValidationError extends BadRequestException {
6
6
  constructor(message: string) {
7
- super(message as LocalizedString);
7
+ super(SD("error.detail")(message));
8
8
  this.name = "ThinkingValidationError";
9
9
  }
10
10
  }
@@ -1,9 +1,11 @@
1
- export function createTtftTracker(now: () => number = Date.now): {
1
+ export interface TtftTracker {
2
2
  markStart: () => void;
3
3
  recordFirstDelta: () => void;
4
4
  value: () => number | null;
5
5
  wrapDelta: (onDelta: (text: string) => void) => (text: string) => void;
6
- } {
6
+ }
7
+
8
+ export function createTtftTracker(now: () => number = Date.now): TtftTracker {
7
9
  let startedAt: number | null = null;
8
10
  let ttftMs: number | null = null;
9
11