@cartanova/qgrid-cli 2.10.10 → 2.11.1

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 (302) 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-Be2qCZmI.css +1 -0
  204. package/bundle/web-dist/client/assets/index-C96h3feE.js +32 -0
  205. package/bundle/web-dist/client/assets/logs-DBM6U0QD.js +1 -0
  206. package/bundle/web-dist/client/assets/monit-BBjXa7vB.js +1 -0
  207. package/bundle/web-dist/client/assets/routes-Crz_PQzi.js +5 -0
  208. package/bundle/web-dist/client/assets/{services.generated-NP-ValHd.js → services.generated-B5lc3aIC.js} +5 -5
  209. package/bundle/web-dist/client/assets/settings-Cdwm3OBB.js +1 -0
  210. package/bundle/web-dist/client/assets/show-DBUhALT1.js +2 -0
  211. package/bundle/web-dist/client/assets/tokens-CVQAVJTo.js +1 -0
  212. package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
  213. package/bundle/web-dist/client/assets/use-oauth-login-flow-BfxYI4Oh.js +1 -0
  214. package/bundle/web-dist/client/assets/use-update-token-mutation-qKBC2sn7.js +1 -0
  215. package/bundle/web-dist/client/assets/{vendor-tanstack-DJRQAbrY.js → vendor-tanstack-DRPs09ai.js} +1 -1
  216. package/bundle/web-dist/client/index.html +5 -5
  217. package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
  218. package/bundle/web-dist/server/assets/{lazyRouteComponent-CgBdabgd.js → lazyRouteComponent-AKiHfZWp.js} +129 -2
  219. package/bundle/web-dist/server/assets/{logs-BMyR98rU.js → logs-B7QmGJq3.js} +18 -14
  220. package/bundle/web-dist/server/assets/{monit-ZPt66W5M.js → monit-DFt7x3bh.js} +13 -12
  221. package/bundle/web-dist/server/assets/{plus-BZ9I0VgC.js → plus-DaYQRpBt.js} +1 -1
  222. package/bundle/web-dist/server/assets/{react-dom-Ds75e4Jl.js → react-dom-Cv23mm1K.js} +2 -129
  223. package/bundle/web-dist/server/assets/{refresh-cw-CztCFis-.js → refresh-cw-BpXNsAy-.js} +1 -1
  224. package/bundle/web-dist/server/assets/{request-model-DjGldb-h.js → request-model-eHE6YbaF.js} +1 -1
  225. package/bundle/web-dist/server/assets/{routes-Ct-k7nBA.js → routes-_Y-PJfgO.js} +110 -39
  226. package/bundle/web-dist/server/assets/{services.generated-BA4AcAf5.js → services.generated-CMJ8AHbO.js} +582 -172
  227. package/bundle/web-dist/server/assets/{settings-CBUZ47Xx.js → settings-JwJKxn2e.js} +14 -14
  228. package/bundle/web-dist/server/assets/{show-LSFIzvO2.js → show-BEv6z1v_.js} +90 -60
  229. package/bundle/web-dist/server/assets/{tokens-DxrBW512.js → tokens-CNT4mI-f.js} +162 -50
  230. package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
  231. package/bundle/web-dist/server/assets/use-oauth-login-flow-jkAkT3X6.js +2345 -0
  232. package/bundle/web-dist/server/assets/{use-update-token-mutation-pkArIzCP.js → use-update-token-mutation-Sm6kh02m.js} +1 -1
  233. package/bundle/web-dist/server/entry-server.generated.js +1644 -21655
  234. package/dist/cli.js +9 -9
  235. package/package.json +4 -11
  236. package/postinstall.mjs +12 -0
  237. package/skills/qgrid/SKILL.md +1 -0
  238. package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
  239. package/skills/qgrid/references/decision-rationale.md +23 -0
  240. package/skills/qgrid/references/grok-runtime.md +89 -0
  241. package/skills/qgrid/references/provider-runtime-differences.md +30 -29
  242. package/skills/qgrid/references/repo-map.md +10 -0
  243. package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
  244. package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
  245. package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
  246. package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
  247. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
  248. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
  249. package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
  250. package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
  251. package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
  252. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
  253. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
  254. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
  255. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
  256. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
  257. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
  258. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
  259. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
  260. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
  261. package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
  262. package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
  263. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
  264. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
  265. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
  266. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
  267. package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
  268. package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
  269. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
  270. package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
  271. package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
  272. package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
  273. 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
  274. 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
  275. 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
  276. 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
  277. 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
  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/index.DdgEv5B1.js +0 -46
  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/rpc.MzXet3jl.js +0 -119
  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/test.DNmyFkvJ.js +0 -3044
  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/utils.BX5Fg8C4.js +0 -59
  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/index.js +0 -28
  283. package/bundle/dist/testing/setup-mocks.js +0 -16
  284. package/bundle/src/testing/setup-mocks.ts +0 -44
  285. package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
  286. package/bundle/web-dist/client/assets/index-DZwzUfI-.js +0 -106
  287. package/bundle/web-dist/client/assets/logs-Cog79DU5.js +0 -1
  288. package/bundle/web-dist/client/assets/monit-2auznBys.js +0 -1
  289. package/bundle/web-dist/client/assets/routes-B0lTeLK-.js +0 -5
  290. package/bundle/web-dist/client/assets/settings-D8ZxZGSJ.js +0 -1
  291. package/bundle/web-dist/client/assets/show-CFSERlnM.js +0 -2
  292. package/bundle/web-dist/client/assets/tokens-CZXUyI7O.js +0 -1
  293. package/bundle/web-dist/client/assets/use-oauth-login-flow-hboOs3wG.js +0 -1
  294. package/bundle/web-dist/client/assets/use-update-token-mutation-BQHS0byG.js +0 -1
  295. package/bundle/web-dist/server/assets/use-oauth-login-flow-Gn8flMK5.js +0 -178
  296. package/dist/cli.d.ts +0 -10
  297. /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
  298. /package/bundle/web-dist/client/assets/{plus-B62CuqT8.js → plus-BsQdY7PS.js} +0 -0
  299. /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
  300. /package/bundle/web-dist/client/assets/{refresh-cw-NNcU0Cmq.js → refresh-cw-D9IUmT23.js} +0 -0
  301. /package/bundle/web-dist/client/assets/{request-model-CojtinqK.js → request-model-Bpp_rkK8.js} +0 -0
  302. /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
+ });