@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
@@ -0,0 +1,446 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { GrokProtocolError } from "./grok-backend-protocol";
4
+ import { GROK_BUILD_VERSION } from "./grok-constants";
5
+ import { GrokHttpError } from "./grok-direct-client";
6
+ import { GrokInvalidRequestError } from "./grok-dispatcher";
7
+ import {
8
+ decodeGrokImages,
9
+ GrokContentPolicyError,
10
+ GrokMediaClient,
11
+ GrokMediaDeliveryError,
12
+ GrokMediaTimeoutError,
13
+ summarizeGrokVideoStatus,
14
+ } from "./grok-media-client";
15
+
16
+ interface Sent {
17
+ url: string;
18
+ method: string | undefined;
19
+ headers: Record<string, string>;
20
+ body: unknown;
21
+ }
22
+
23
+ const JPEG = Buffer.from([0xff, 0xd8, 0xff, 0xe0, 1, 2, 3, 4]);
24
+ const PNG = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
25
+
26
+ function fakeFetch(respond: (sent: Sent, init: RequestInit | undefined) => Promise<Response>) {
27
+ const calls: Sent[] = [];
28
+ const impl: typeof fetch = async (input, init) => {
29
+ const headers: Record<string, string> = {};
30
+ new Headers(init?.headers).forEach((value, key) => {
31
+ headers[key] = value;
32
+ });
33
+ const sent: Sent = {
34
+ url: String(input),
35
+ method: init?.method,
36
+ headers,
37
+ body: typeof init?.body === "string" ? JSON.parse(init.body) : init?.body,
38
+ };
39
+ calls.push(sent);
40
+ return respond(sent, init);
41
+ };
42
+ return { impl, calls };
43
+ }
44
+
45
+ function json(value: unknown, status = 200): Response {
46
+ return new Response(JSON.stringify(value), {
47
+ status,
48
+ headers: { "content-type": "application/json" },
49
+ });
50
+ }
51
+
52
+ function hang(init: RequestInit | undefined): Promise<Response> {
53
+ return new Promise((_, reject) => {
54
+ init?.signal?.addEventListener("abort", () => reject(init.signal?.reason));
55
+ });
56
+ }
57
+
58
+ function codedError(code: string): TypeError {
59
+ return new TypeError("fetch failed", { cause: Object.assign(new Error(code), { code }) });
60
+ }
61
+
62
+ const imageResponse = {
63
+ data: [{ b64_json: JPEG.toString("base64"), mime_type: "image/jpeg" }],
64
+ usage: { cost_in_usd_ticks: 500_000_000 },
65
+ };
66
+
67
+ const AUTH = { bearer: "jwt", sessionId: "sess-1" };
68
+
69
+ describe("GrokMediaClient images", () => {
70
+ it("sends the U0-verified generation body with the media fingerprint", async () => {
71
+ const { impl, calls } = fakeFetch(async () => json(imageResponse));
72
+ const client = new GrokMediaClient({ fetch: impl });
73
+ const result = await client.generateImages(AUTH, {
74
+ model: "",
75
+ prompt: "red square",
76
+ aspectRatio: "1:1",
77
+ });
78
+ expect(calls).toHaveLength(1);
79
+ const [sent] = calls;
80
+ expect(sent?.url).toBe("https://api.x.ai/v1/images/generations");
81
+ expect(sent?.method).toBe("POST");
82
+ expect(sent?.headers).toEqual({
83
+ "content-type": "application/json",
84
+ "user-agent": `xai-grok-build/${GROK_BUILD_VERSION}`,
85
+ authorization: "Bearer jwt",
86
+ "x-grok-session-id": "sess-1",
87
+ "x-grok-client-version": GROK_BUILD_VERSION,
88
+ "x-grok-client-identifier": "grok-shell",
89
+ });
90
+ expect(sent?.headers["content-encoding"]).toBeUndefined();
91
+ expect(sent?.headers["x-xai-token-auth"]).toBeUndefined();
92
+ // Key order matters for byte-level parity with grok-build.
93
+ expect(JSON.stringify(sent?.body)).toBe(
94
+ JSON.stringify({
95
+ model: "grok-imagine-image-quality",
96
+ prompt: "red square",
97
+ n: 1,
98
+ aspect_ratio: "1:1",
99
+ resolution: "1k",
100
+ response_format: "b64_json",
101
+ }),
102
+ );
103
+ expect(result.usage?.cost_in_usd_ticks).toBe(500_000_000);
104
+ });
105
+
106
+ it("maps SDK option names and keeps response_format b64_json", async () => {
107
+ const { impl, calls } = fakeFetch(async () => json(imageResponse));
108
+ await new GrokMediaClient({ fetch: impl }).generateImages(AUTH, {
109
+ model: "grok-imagine-image-pro",
110
+ prompt: "p",
111
+ n: 3,
112
+ resolution: "2k",
113
+ quality: "high",
114
+ outputFormat: "png",
115
+ });
116
+ expect(calls[0]?.body).toEqual({
117
+ model: "grok-imagine-image-pro",
118
+ prompt: "p",
119
+ n: 3,
120
+ resolution: "2k",
121
+ response_format: "b64_json",
122
+ quality: "high",
123
+ output_format: "png",
124
+ });
125
+ });
126
+
127
+ it("decodes b64 bytes with mime type, sniffing when mime_type is absent", () => {
128
+ const decoded = decodeGrokImages({
129
+ data: [
130
+ { b64_json: JPEG.toString("base64"), mime_type: "image/jpeg", respect_moderation: true },
131
+ { b64_json: PNG.toString("base64"), revised_prompt: "a red square" },
132
+ ],
133
+ usage: { cost_in_usd_ticks: 7 },
134
+ });
135
+ expect(Buffer.from(decoded.images[0]!.bytes).equals(JPEG)).toBe(true);
136
+ expect(decoded.images[0]).toMatchObject({ mediaType: "image/jpeg", respectModeration: true });
137
+ expect(Buffer.from(decoded.images[1]!.bytes).equals(PNG)).toBe(true);
138
+ expect(decoded.images[1]).toMatchObject({ mediaType: "image/png", revisedPrompt: "a red square" });
139
+ expect(decoded.costInUsdTicks).toBe(7);
140
+ });
141
+
142
+ it("rejects n outside 1..3 before any request", async () => {
143
+ const { impl, calls } = fakeFetch(async () => json(imageResponse));
144
+ const client = new GrokMediaClient({ fetch: impl });
145
+ await expect(client.generateImages(AUTH, { model: "", prompt: "p", n: 4 })).rejects.toThrow(
146
+ RangeError,
147
+ );
148
+ await expect(client.generateImages(AUTH, { model: "", prompt: "p", n: 0 })).rejects.toThrow(
149
+ RangeError,
150
+ );
151
+ expect(calls).toHaveLength(0);
152
+ });
153
+
154
+ it("turns respect_moderation false into a content-policy error", async () => {
155
+ const { impl } = fakeFetch(async () =>
156
+ json({ data: [{ b64_json: JPEG.toString("base64"), respect_moderation: false }] }),
157
+ );
158
+ await expect(
159
+ new GrokMediaClient({ fetch: impl }).generateImages(AUTH, { model: "", prompt: "p" }),
160
+ ).rejects.toBeInstanceOf(GrokContentPolicyError);
161
+ });
162
+
163
+ it("rejects invalid base64 and malformed bodies as protocol errors", async () => {
164
+ const bad = fakeFetch(async () => json({ data: [{ b64_json: "not base64!" }] }));
165
+ await expect(
166
+ new GrokMediaClient({ fetch: bad.impl }).generateImages(AUTH, { model: "", prompt: "p" }),
167
+ ).rejects.toBeInstanceOf(GrokProtocolError);
168
+ const empty = fakeFetch(async () => json({ data: [] }));
169
+ await expect(
170
+ new GrokMediaClient({ fetch: empty.impl }).generateImages(AUTH, { model: "", prompt: "p" }),
171
+ ).rejects.toBeInstanceOf(GrokProtocolError);
172
+ });
173
+
174
+ it("wraps 403 into GrokHttpError kind entitlement", async () => {
175
+ const { impl, calls } = fakeFetch(async () =>
176
+ json({ code: "forbidden", error: "Imagine is not available on this tier" }, 403),
177
+ );
178
+ const error = await new GrokMediaClient({ fetch: impl })
179
+ .generateImages(AUTH, { model: "", prompt: "p" })
180
+ .catch((e: unknown) => e);
181
+ expect(error).toBeInstanceOf(GrokHttpError);
182
+ expect(error).toMatchObject({
183
+ status: 403,
184
+ classification: { kind: "entitlement", message: "Imagine is not available on this tier" },
185
+ });
186
+ expect(calls).toHaveLength(1);
187
+ });
188
+
189
+ it("aborts on the read timeout and on the total timeout", async () => {
190
+ const stalled = fakeFetch(async (_, init) => hang(init));
191
+ const readError = await new GrokMediaClient({
192
+ fetch: stalled.impl,
193
+ timeouts: { imageReadMs: 20, imageTotalMs: 1_000 },
194
+ })
195
+ .generateImages(AUTH, { model: "", prompt: "p" })
196
+ .catch((e: unknown) => e);
197
+ expect(readError).toBeInstanceOf(GrokMediaTimeoutError);
198
+ expect(readError).toMatchObject({ phase: "read", timeoutMs: 20 });
199
+ expect(stalled.calls).toHaveLength(1);
200
+
201
+ // A body that keeps trickling resets the read timer but not the total budget.
202
+ const trickle = fakeFetch(async (_, init) => {
203
+ const body = new ReadableStream<Uint8Array>({
204
+ start(controller) {
205
+ const timer = setInterval(() => controller.enqueue(new Uint8Array([32])), 5);
206
+ init?.signal?.addEventListener("abort", () => {
207
+ clearInterval(timer);
208
+ controller.error(init.signal?.reason);
209
+ });
210
+ },
211
+ });
212
+ return new Response(body, { status: 200 });
213
+ });
214
+ const totalError = await new GrokMediaClient({
215
+ fetch: trickle.impl,
216
+ timeouts: { imageReadMs: 30, imageTotalMs: 80 },
217
+ })
218
+ .generateImages(AUTH, { model: "", prompt: "p" })
219
+ .catch((e: unknown) => e);
220
+ expect(totalError).toBeInstanceOf(GrokMediaTimeoutError);
221
+ expect(totalError).toMatchObject({ phase: "total" });
222
+ expect(trickle.calls).toHaveLength(1);
223
+ });
224
+
225
+ it("propagates the caller's abort reason", async () => {
226
+ const { impl } = fakeFetch(async (_, init) => hang(init));
227
+ const controller = new AbortController();
228
+ const pending = new GrokMediaClient({ fetch: impl }).generateImages(AUTH, {
229
+ model: "",
230
+ prompt: "p",
231
+ signal: controller.signal,
232
+ });
233
+ const reason = new Error("client went away");
234
+ controller.abort(reason);
235
+ await expect(pending).rejects.toBe(reason);
236
+ });
237
+
238
+ it("sends edits as JSON with image/images url objects", async () => {
239
+ const { impl, calls } = fakeFetch(async () => json(imageResponse));
240
+ const client = new GrokMediaClient({ fetch: impl });
241
+ await client.editImages(AUTH, {
242
+ model: "",
243
+ prompt: "make it blue",
244
+ images: ["data:image/png;base64,AAAA"],
245
+ });
246
+ await client.editImages(AUTH, {
247
+ model: "grok-imagine-image",
248
+ prompt: "merge",
249
+ aspectRatio: "16:9",
250
+ images: ["https://example.com/a.png", "https://example.com/b.png"],
251
+ });
252
+ expect(calls.map((c) => c.url)).toEqual([
253
+ "https://api.x.ai/v1/images/edits",
254
+ "https://api.x.ai/v1/images/edits",
255
+ ]);
256
+ expect(calls[0]?.headers["content-type"]).toBe("application/json");
257
+ expect(calls[0]?.body).toEqual({
258
+ model: "grok-imagine-image-quality",
259
+ prompt: "make it blue",
260
+ n: 1,
261
+ resolution: "1k",
262
+ response_format: "b64_json",
263
+ image: { url: "data:image/png;base64,AAAA" },
264
+ });
265
+ expect(calls[1]?.body).toEqual({
266
+ model: "grok-imagine-image",
267
+ prompt: "merge",
268
+ n: 1,
269
+ aspect_ratio: "16:9",
270
+ resolution: "1k",
271
+ response_format: "b64_json",
272
+ images: [{ url: "https://example.com/a.png" }, { url: "https://example.com/b.png" }],
273
+ });
274
+ await expect(client.editImages(AUTH, { model: "", prompt: "p", images: [] })).rejects.toThrow(
275
+ GrokInvalidRequestError,
276
+ );
277
+ expect(calls).toHaveLength(2);
278
+ });
279
+ });
280
+
281
+ describe("GrokMediaClient retry safety", () => {
282
+ it("does not re-issue a POST that failed after send", async () => {
283
+ const { impl, calls } = fakeFetch(async () => {
284
+ throw codedError("ECONNRESET");
285
+ });
286
+ const error = await new GrokMediaClient({ fetch: impl })
287
+ .generateImages(AUTH, { model: "", prompt: "p" })
288
+ .catch((e: unknown) => e);
289
+ expect(error).toBeInstanceOf(GrokMediaDeliveryError);
290
+ expect(error).not.toBeInstanceOf(GrokHttpError);
291
+ expect(calls).toHaveLength(1);
292
+ });
293
+
294
+ it("treats a body read failure after the response as delivered", async () => {
295
+ const { impl, calls } = fakeFetch(async () => {
296
+ const body = new ReadableStream<Uint8Array>({
297
+ pull(controller) {
298
+ controller.error(codedError("ECONNREFUSED"));
299
+ },
300
+ });
301
+ return new Response(body, { status: 200 });
302
+ });
303
+ const error = await new GrokMediaClient({ fetch: impl })
304
+ .startVideo(AUTH, { model: "", prompt: "p" })
305
+ .catch((e: unknown) => e);
306
+ expect(error).toBeInstanceOf(GrokMediaDeliveryError);
307
+ expect(calls).toHaveLength(1);
308
+ });
309
+
310
+ it("surfaces a pre-send connect failure as a transient GrokHttpError", async () => {
311
+ const { impl, calls } = fakeFetch(async () => {
312
+ throw codedError("ECONNREFUSED");
313
+ });
314
+ const error = await new GrokMediaClient({ fetch: impl })
315
+ .startVideo(AUTH, { model: "", prompt: "p" })
316
+ .catch((e: unknown) => e);
317
+ expect(error).toBeInstanceOf(GrokHttpError);
318
+ expect(error).toMatchObject({ status: 0, classification: { kind: "transient" } });
319
+ expect(calls).toHaveLength(1);
320
+ });
321
+
322
+ it("maps any GET network failure to a transient GrokHttpError", async () => {
323
+ const { impl } = fakeFetch(async () => {
324
+ throw codedError("ECONNRESET");
325
+ });
326
+ const error = await new GrokMediaClient({ fetch: impl })
327
+ .getVideo(AUTH, "req-1")
328
+ .catch((e: unknown) => e);
329
+ expect(error).toBeInstanceOf(GrokHttpError);
330
+ expect(error).toMatchObject({ classification: { kind: "transient" } });
331
+ });
332
+ });
333
+
334
+ describe("GrokMediaClient video", () => {
335
+ it("starts a video with grok-build field names and returns the request id", async () => {
336
+ const { impl, calls } = fakeFetch(async () => json({ request_id: "req-1" }));
337
+ const client = new GrokMediaClient({ fetch: impl });
338
+ const started = await client.startVideo(AUTH, {
339
+ model: "",
340
+ prompt: "a cat",
341
+ duration: 6,
342
+ aspectRatio: "16:9",
343
+ resolution: "720p",
344
+ image: "https://example.com/first.png",
345
+ lastFrame: "https://example.com/last.png",
346
+ referenceImages: ["https://example.com/ref.png"],
347
+ mode: "reference-to-video",
348
+ });
349
+ expect(started.request_id).toBe("req-1");
350
+ const [sent] = calls;
351
+ expect(sent?.url).toBe("https://api.x.ai/v1/videos/generations");
352
+ expect(sent?.headers["user-agent"]).toBe(`xai-grok-build/${GROK_BUILD_VERSION}`);
353
+ expect(JSON.stringify(sent?.body)).toBe(
354
+ JSON.stringify({
355
+ model: "grok-imagine-video-1.5",
356
+ prompt: "a cat",
357
+ image: { url: "https://example.com/first.png" },
358
+ duration: 6,
359
+ aspect_ratio: "16:9",
360
+ resolution: "720p",
361
+ reference_images: [{ url: "https://example.com/ref.png" }],
362
+ last_frame: { url: "https://example.com/last.png" },
363
+ }),
364
+ );
365
+ });
366
+
367
+ it("rejects reference-to-video without references and bad durations without a request", async () => {
368
+ const { impl, calls } = fakeFetch(async () => json({ request_id: "x" }));
369
+ const client = new GrokMediaClient({ fetch: impl });
370
+ await expect(
371
+ client.startVideo(AUTH, { model: "", prompt: "p", mode: "reference-to-video" }),
372
+ ).rejects.toThrow(GrokInvalidRequestError);
373
+ await expect(client.startVideo(AUTH, { model: "", prompt: "p", duration: 16 })).rejects.toThrow(
374
+ GrokInvalidRequestError,
375
+ );
376
+ expect(calls).toHaveLength(0);
377
+ });
378
+
379
+ it("polls GET /videos/{id} and returns the upstream URL unchanged", async () => {
380
+ const url = "https://vidgen.x.ai/output/abc.mp4?sig=XYZ&exp=1";
381
+ const replies = [
382
+ new Response("", { status: 202 }),
383
+ json({ status: "pending", progress: 40 }),
384
+ json({ status: "done", video: { url, duration: 6 }, usage: { cost_in_usd_ticks: 9 } }),
385
+ ];
386
+ const { impl, calls } = fakeFetch(async () => replies.shift() ?? json({}, 500));
387
+ const client = new GrokMediaClient({ fetch: impl });
388
+ const first = await client.getVideo(AUTH, "req/1");
389
+ const second = await client.getVideo(AUTH, "req/1");
390
+ const done = await client.getVideo(AUTH, "req/1");
391
+ expect(calls[0]?.url).toBe("https://api.x.ai/v1/videos/req%2F1");
392
+ expect(calls[0]?.method).toBe("GET");
393
+ expect(calls[0]?.body).toBeUndefined();
394
+ expect(calls[0]?.headers["x-grok-session-id"]).toBe("sess-1");
395
+ expect(first.status).toBe("pending");
396
+ expect(summarizeGrokVideoStatus(second)).toEqual({ status: "pending", mimeType: "video/mp4" });
397
+ expect(summarizeGrokVideoStatus(done)).toEqual({
398
+ status: "done",
399
+ url,
400
+ mimeType: "video/mp4",
401
+ usageTicks: 9,
402
+ });
403
+ });
404
+
405
+ it("summarizes failures, expiry, nested file_output and moderation", async () => {
406
+ expect(
407
+ summarizeGrokVideoStatus({ status: "failed", error: { code: "x", message: "boom" } }),
408
+ ).toMatchObject({ status: "failed", error: "boom" });
409
+ expect(summarizeGrokVideoStatus({ status: "expired" })).toMatchObject({ status: "failed" });
410
+ expect(summarizeGrokVideoStatus({ status: "done" })).toMatchObject({ status: "failed" });
411
+ expect(
412
+ summarizeGrokVideoStatus({
413
+ status: "done",
414
+ video: { file_output: { public_url: "https://files.x.ai/v.mp4" } },
415
+ }),
416
+ ).toMatchObject({ status: "done", url: "https://files.x.ai/v.mp4" });
417
+ // A top-level file_output is not where @ai-sdk/xai looks for the URL.
418
+ expect(
419
+ summarizeGrokVideoStatus({
420
+ status: "done",
421
+ file_output: { public_url: "https://files.x.ai/v.mp4" },
422
+ }),
423
+ ).toMatchObject({ status: "failed" });
424
+
425
+ const { impl } = fakeFetch(async () =>
426
+ json({ status: "done", video: { url: "https://x/v.mp4", respect_moderation: false } }),
427
+ );
428
+ await expect(
429
+ new GrokMediaClient({ fetch: impl }).getVideo(AUTH, "req-1"),
430
+ ).rejects.toBeInstanceOf(GrokContentPolicyError);
431
+ });
432
+
433
+ it("classifies a poll 401 and a poll timeout", async () => {
434
+ const unauthorized = fakeFetch(async () => json({ error: "expired token" }, 401));
435
+ await expect(
436
+ new GrokMediaClient({ fetch: unauthorized.impl }).getVideo(AUTH, "req-1"),
437
+ ).rejects.toMatchObject({ classification: { kind: "auth" } });
438
+ const stalled = fakeFetch(async (_, init) => hang(init));
439
+ await expect(
440
+ new GrokMediaClient({ fetch: stalled.impl, timeouts: { videoPollMs: 20 } }).getVideo(
441
+ AUTH,
442
+ "req-1",
443
+ ),
444
+ ).rejects.toBeInstanceOf(GrokMediaTimeoutError);
445
+ });
446
+ });