@synteq/cli 0.1.5 → 0.2.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 (387) hide show
  1. package/bin/run.js +61 -2
  2. package/dist/api/client.d.ts +29 -37
  3. package/dist/api/client.js +42 -49
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/api/factory.d.ts +3 -0
  6. package/dist/api/factory.js +1 -1
  7. package/dist/api/factory.js.map +1 -1
  8. package/dist/api/types.d.ts +14 -23
  9. package/dist/auth/scope.d.ts +19 -0
  10. package/dist/auth/scope.js +65 -0
  11. package/dist/auth/scope.js.map +1 -0
  12. package/dist/base/command.d.ts +1 -1
  13. package/dist/base/command.js +49 -0
  14. package/dist/base/command.js.map +1 -1
  15. package/dist/commands/account/index.d.ts +1 -0
  16. package/dist/commands/account/index.js +1 -0
  17. package/dist/commands/account/index.js.map +1 -1
  18. package/dist/commands/account/show.d.ts +1 -0
  19. package/dist/commands/account/show.js +1 -0
  20. package/dist/commands/account/show.js.map +1 -1
  21. package/dist/commands/api.d.ts +1 -0
  22. package/dist/commands/api.js +5 -4
  23. package/dist/commands/api.js.map +1 -1
  24. package/dist/commands/catalog.d.ts +1 -0
  25. package/dist/commands/catalog.js +6 -1
  26. package/dist/commands/catalog.js.map +1 -1
  27. package/dist/commands/config/index.d.ts +1 -0
  28. package/dist/commands/config/index.js +1 -0
  29. package/dist/commands/config/index.js.map +1 -1
  30. package/dist/commands/config/set-api-url.d.ts +1 -0
  31. package/dist/commands/config/set-api-url.js +38 -2
  32. package/dist/commands/config/set-api-url.js.map +1 -1
  33. package/dist/commands/config/show.d.ts +1 -0
  34. package/dist/commands/config/show.js +1 -0
  35. package/dist/commands/config/show.js.map +1 -1
  36. package/dist/commands/credits/add.d.ts +1 -0
  37. package/dist/commands/credits/add.js +1 -0
  38. package/dist/commands/credits/add.js.map +1 -1
  39. package/dist/commands/credits/index.d.ts +1 -0
  40. package/dist/commands/credits/index.js +1 -0
  41. package/dist/commands/credits/index.js.map +1 -1
  42. package/dist/commands/credits/list.d.ts +1 -0
  43. package/dist/commands/credits/list.js +1 -0
  44. package/dist/commands/credits/list.js.map +1 -1
  45. package/dist/commands/gpu/activity.d.ts +2 -0
  46. package/dist/commands/gpu/activity.js +7 -0
  47. package/dist/commands/gpu/activity.js.map +1 -1
  48. package/dist/commands/gpu/bandwidth.d.ts +2 -0
  49. package/dist/commands/gpu/bandwidth.js +5 -0
  50. package/dist/commands/gpu/bandwidth.js.map +1 -1
  51. package/dist/commands/gpu/boot-order.d.ts +2 -0
  52. package/dist/commands/gpu/boot-order.js +6 -0
  53. package/dist/commands/gpu/boot-order.js.map +1 -1
  54. package/dist/commands/gpu/console.d.ts +2 -0
  55. package/dist/commands/gpu/console.js +6 -0
  56. package/dist/commands/gpu/console.js.map +1 -1
  57. package/dist/commands/gpu/details.d.ts +3 -0
  58. package/dist/commands/gpu/details.js +10 -0
  59. package/dist/commands/gpu/details.js.map +1 -1
  60. package/dist/commands/gpu/index.d.ts +1 -0
  61. package/dist/commands/gpu/index.js +1 -0
  62. package/dist/commands/gpu/index.js.map +1 -1
  63. package/dist/commands/gpu/ip/add.d.ts +2 -0
  64. package/dist/commands/gpu/ip/add.js +7 -0
  65. package/dist/commands/gpu/ip/add.js.map +1 -1
  66. package/dist/commands/gpu/ip/list.d.ts +2 -0
  67. package/dist/commands/gpu/ip/list.js +5 -0
  68. package/dist/commands/gpu/ip/list.js.map +1 -1
  69. package/dist/commands/gpu/list.d.ts +1 -0
  70. package/dist/commands/gpu/list.js +1 -0
  71. package/dist/commands/gpu/list.js.map +1 -1
  72. package/dist/commands/gpu/order.d.ts +1 -0
  73. package/dist/commands/gpu/order.js +3 -0
  74. package/dist/commands/gpu/order.js.map +1 -1
  75. package/dist/commands/gpu/power.d.ts +2 -0
  76. package/dist/commands/gpu/power.js +7 -0
  77. package/dist/commands/gpu/power.js.map +1 -1
  78. package/dist/commands/gpu/reinstall.d.ts +2 -0
  79. package/dist/commands/gpu/reinstall.js +8 -0
  80. package/dist/commands/gpu/reinstall.js.map +1 -1
  81. package/dist/commands/gpu/resize.d.ts +2 -0
  82. package/dist/commands/gpu/resize.js +7 -0
  83. package/dist/commands/gpu/resize.js.map +1 -1
  84. package/dist/commands/gpu/stats.d.ts +2 -0
  85. package/dist/commands/gpu/stats.js +6 -0
  86. package/dist/commands/gpu/stats.js.map +1 -1
  87. package/dist/commands/help.d.ts +2 -0
  88. package/dist/commands/help.js +5 -0
  89. package/dist/commands/help.js.map +1 -1
  90. package/dist/commands/instant-metal/activity.d.ts +2 -0
  91. package/dist/commands/instant-metal/activity.js +7 -0
  92. package/dist/commands/instant-metal/activity.js.map +1 -1
  93. package/dist/commands/instant-metal/bandwidth.d.ts +2 -0
  94. package/dist/commands/instant-metal/bandwidth.js +5 -0
  95. package/dist/commands/instant-metal/bandwidth.js.map +1 -1
  96. package/dist/commands/instant-metal/boot-order.d.ts +2 -0
  97. package/dist/commands/instant-metal/boot-order.js +6 -0
  98. package/dist/commands/instant-metal/boot-order.js.map +1 -1
  99. package/dist/commands/instant-metal/console.d.ts +2 -0
  100. package/dist/commands/instant-metal/console.js +6 -0
  101. package/dist/commands/instant-metal/console.js.map +1 -1
  102. package/dist/commands/instant-metal/details.d.ts +3 -0
  103. package/dist/commands/instant-metal/details.js +10 -0
  104. package/dist/commands/instant-metal/details.js.map +1 -1
  105. package/dist/commands/instant-metal/index.d.ts +1 -0
  106. package/dist/commands/instant-metal/index.js +1 -0
  107. package/dist/commands/instant-metal/index.js.map +1 -1
  108. package/dist/commands/instant-metal/ip/add.d.ts +2 -0
  109. package/dist/commands/instant-metal/ip/add.js +7 -0
  110. package/dist/commands/instant-metal/ip/add.js.map +1 -1
  111. package/dist/commands/instant-metal/ip/list.d.ts +2 -0
  112. package/dist/commands/instant-metal/ip/list.js +5 -0
  113. package/dist/commands/instant-metal/ip/list.js.map +1 -1
  114. package/dist/commands/instant-metal/list.d.ts +1 -0
  115. package/dist/commands/instant-metal/list.js +1 -0
  116. package/dist/commands/instant-metal/list.js.map +1 -1
  117. package/dist/commands/instant-metal/order.d.ts +1 -0
  118. package/dist/commands/instant-metal/order.js +3 -0
  119. package/dist/commands/instant-metal/order.js.map +1 -1
  120. package/dist/commands/instant-metal/power.d.ts +2 -0
  121. package/dist/commands/instant-metal/power.js +7 -0
  122. package/dist/commands/instant-metal/power.js.map +1 -1
  123. package/dist/commands/instant-metal/reinstall.d.ts +2 -0
  124. package/dist/commands/instant-metal/reinstall.js +8 -0
  125. package/dist/commands/instant-metal/reinstall.js.map +1 -1
  126. package/dist/commands/instant-metal/resize.d.ts +2 -0
  127. package/dist/commands/instant-metal/resize.js +7 -0
  128. package/dist/commands/instant-metal/resize.js.map +1 -1
  129. package/dist/commands/instant-metal/stats.d.ts +2 -0
  130. package/dist/commands/instant-metal/stats.js +6 -0
  131. package/dist/commands/instant-metal/stats.js.map +1 -1
  132. package/dist/commands/login.d.ts +1 -0
  133. package/dist/commands/login.js +1 -0
  134. package/dist/commands/login.js.map +1 -1
  135. package/dist/commands/logout.d.ts +1 -0
  136. package/dist/commands/logout.js +1 -0
  137. package/dist/commands/logout.js.map +1 -1
  138. package/dist/commands/order/gpu.d.ts +1 -0
  139. package/dist/commands/order/gpu.js +3 -0
  140. package/dist/commands/order/gpu.js.map +1 -1
  141. package/dist/commands/order/instant-metal.d.ts +1 -0
  142. package/dist/commands/order/instant-metal.js +3 -0
  143. package/dist/commands/order/instant-metal.js.map +1 -1
  144. package/dist/commands/order/storage.d.ts +1 -0
  145. package/dist/commands/order/storage.js +2 -1
  146. package/dist/commands/order/storage.js.map +1 -1
  147. package/dist/commands/order/vps.d.ts +1 -0
  148. package/dist/commands/order/vps.js +3 -0
  149. package/dist/commands/order/vps.js.map +1 -1
  150. package/dist/commands/order.d.ts +1 -0
  151. package/dist/commands/order.js +1 -0
  152. package/dist/commands/order.js.map +1 -1
  153. package/dist/commands/os-images.d.ts +1 -0
  154. package/dist/commands/os-images.js +4 -1
  155. package/dist/commands/os-images.js.map +1 -1
  156. package/dist/commands/payments/index.d.ts +1 -0
  157. package/dist/commands/payments/index.js +1 -0
  158. package/dist/commands/payments/index.js.map +1 -1
  159. package/dist/commands/payments/methods/add.d.ts +1 -0
  160. package/dist/commands/payments/methods/add.js +1 -0
  161. package/dist/commands/payments/methods/add.js.map +1 -1
  162. package/dist/commands/payments/methods/delete.d.ts +1 -0
  163. package/dist/commands/payments/methods/delete.js +1 -0
  164. package/dist/commands/payments/methods/delete.js.map +1 -1
  165. package/dist/commands/payments/methods/index.d.ts +1 -0
  166. package/dist/commands/payments/methods/index.js +1 -0
  167. package/dist/commands/payments/methods/index.js.map +1 -1
  168. package/dist/commands/payments/methods/list.d.ts +1 -0
  169. package/dist/commands/payments/methods/list.js +1 -0
  170. package/dist/commands/payments/methods/list.js.map +1 -1
  171. package/dist/commands/payments/methods/set-default.d.ts +1 -0
  172. package/dist/commands/payments/methods/set-default.js +1 -0
  173. package/dist/commands/payments/methods/set-default.js.map +1 -1
  174. package/dist/commands/projects/index.d.ts +1 -0
  175. package/dist/commands/projects/index.js +1 -0
  176. package/dist/commands/projects/index.js.map +1 -1
  177. package/dist/commands/projects/list.d.ts +1 -0
  178. package/dist/commands/projects/list.js +1 -0
  179. package/dist/commands/projects/list.js.map +1 -1
  180. package/dist/commands/resources.d.ts +1 -0
  181. package/dist/commands/resources.js +33 -21
  182. package/dist/commands/resources.js.map +1 -1
  183. package/dist/commands/settings/index.d.ts +1 -0
  184. package/dist/commands/settings/index.js +1 -0
  185. package/dist/commands/settings/index.js.map +1 -1
  186. package/dist/commands/settings/render-mode.d.ts +1 -0
  187. package/dist/commands/settings/render-mode.js +1 -0
  188. package/dist/commands/settings/render-mode.js.map +1 -1
  189. package/dist/commands/ssh-key/add.d.ts +1 -0
  190. package/dist/commands/ssh-key/add.js +1 -0
  191. package/dist/commands/ssh-key/add.js.map +1 -1
  192. package/dist/commands/ssh-key/delete.d.ts +1 -0
  193. package/dist/commands/ssh-key/delete.js +1 -0
  194. package/dist/commands/ssh-key/delete.js.map +1 -1
  195. package/dist/commands/ssh-key/list.d.ts +1 -0
  196. package/dist/commands/ssh-key/list.js +1 -0
  197. package/dist/commands/ssh-key/list.js.map +1 -1
  198. package/dist/commands/storage/attach.d.ts +2 -1
  199. package/dist/commands/storage/attach.js +12 -11
  200. package/dist/commands/storage/attach.js.map +1 -1
  201. package/dist/commands/storage/detach.d.ts +1 -0
  202. package/dist/commands/storage/detach.js +3 -2
  203. package/dist/commands/storage/detach.js.map +1 -1
  204. package/dist/commands/storage/list.d.ts +1 -0
  205. package/dist/commands/storage/list.js +2 -1
  206. package/dist/commands/storage/list.js.map +1 -1
  207. package/dist/commands/storage/order.d.ts +2 -1
  208. package/dist/commands/storage/order.js +11 -10
  209. package/dist/commands/storage/order.js.map +1 -1
  210. package/dist/commands/storage/resize.d.ts +1 -0
  211. package/dist/commands/storage/resize.js +1 -0
  212. package/dist/commands/storage/resize.js.map +1 -1
  213. package/dist/commands/team/details.d.ts +1 -0
  214. package/dist/commands/team/details.js +1 -0
  215. package/dist/commands/team/details.js.map +1 -1
  216. package/dist/commands/team/invite.d.ts +1 -0
  217. package/dist/commands/team/invite.js +1 -0
  218. package/dist/commands/team/invite.js.map +1 -1
  219. package/dist/commands/team.d.ts +1 -0
  220. package/dist/commands/team.js +1 -0
  221. package/dist/commands/team.js.map +1 -1
  222. package/dist/commands/tickets/close.d.ts +1 -0
  223. package/dist/commands/tickets/close.js +1 -0
  224. package/dist/commands/tickets/close.js.map +1 -1
  225. package/dist/commands/tickets/create.d.ts +1 -0
  226. package/dist/commands/tickets/create.js +1 -0
  227. package/dist/commands/tickets/create.js.map +1 -1
  228. package/dist/commands/tickets/departments.d.ts +1 -0
  229. package/dist/commands/tickets/departments.js +1 -0
  230. package/dist/commands/tickets/departments.js.map +1 -1
  231. package/dist/commands/tickets/list.d.ts +1 -0
  232. package/dist/commands/tickets/list.js +1 -0
  233. package/dist/commands/tickets/list.js.map +1 -1
  234. package/dist/commands/tickets/open.d.ts +1 -0
  235. package/dist/commands/tickets/open.js +1 -0
  236. package/dist/commands/tickets/open.js.map +1 -1
  237. package/dist/commands/tickets/reopen.d.ts +11 -0
  238. package/dist/commands/tickets/reopen.js +34 -0
  239. package/dist/commands/tickets/reopen.js.map +1 -0
  240. package/dist/commands/tickets/reply.d.ts +1 -0
  241. package/dist/commands/tickets/reply.js +1 -0
  242. package/dist/commands/tickets/reply.js.map +1 -1
  243. package/dist/commands/transit.d.ts +1 -0
  244. package/dist/commands/transit.js +1 -0
  245. package/dist/commands/transit.js.map +1 -1
  246. package/dist/commands/tui/index.d.ts +1 -0
  247. package/dist/commands/tui/index.js +21 -0
  248. package/dist/commands/tui/index.js.map +1 -1
  249. package/dist/commands/vds/activity.d.ts +2 -0
  250. package/dist/commands/vds/activity.js +7 -0
  251. package/dist/commands/vds/activity.js.map +1 -1
  252. package/dist/commands/vds/bandwidth.d.ts +2 -0
  253. package/dist/commands/vds/bandwidth.js +5 -0
  254. package/dist/commands/vds/bandwidth.js.map +1 -1
  255. package/dist/commands/vds/boot-order.d.ts +2 -0
  256. package/dist/commands/vds/boot-order.js +6 -0
  257. package/dist/commands/vds/boot-order.js.map +1 -1
  258. package/dist/commands/vds/console.d.ts +2 -0
  259. package/dist/commands/vds/console.js +6 -0
  260. package/dist/commands/vds/console.js.map +1 -1
  261. package/dist/commands/vds/details.d.ts +3 -0
  262. package/dist/commands/vds/details.js +10 -0
  263. package/dist/commands/vds/details.js.map +1 -1
  264. package/dist/commands/vds/index.d.ts +1 -0
  265. package/dist/commands/vds/index.js +1 -0
  266. package/dist/commands/vds/index.js.map +1 -1
  267. package/dist/commands/vds/ip/add.d.ts +2 -0
  268. package/dist/commands/vds/ip/add.js +7 -0
  269. package/dist/commands/vds/ip/add.js.map +1 -1
  270. package/dist/commands/vds/ip/list.d.ts +2 -0
  271. package/dist/commands/vds/ip/list.js +5 -0
  272. package/dist/commands/vds/ip/list.js.map +1 -1
  273. package/dist/commands/vds/list.d.ts +1 -0
  274. package/dist/commands/vds/list.js +1 -0
  275. package/dist/commands/vds/list.js.map +1 -1
  276. package/dist/commands/vds/order.d.ts +2 -0
  277. package/dist/commands/vds/order.js +12 -3
  278. package/dist/commands/vds/order.js.map +1 -1
  279. package/dist/commands/vds/power.d.ts +2 -0
  280. package/dist/commands/vds/power.js +7 -0
  281. package/dist/commands/vds/power.js.map +1 -1
  282. package/dist/commands/vds/reinstall.d.ts +2 -0
  283. package/dist/commands/vds/reinstall.js +8 -0
  284. package/dist/commands/vds/reinstall.js.map +1 -1
  285. package/dist/commands/vds/resize.d.ts +2 -0
  286. package/dist/commands/vds/resize.js +7 -0
  287. package/dist/commands/vds/resize.js.map +1 -1
  288. package/dist/commands/vds/stats.d.ts +2 -0
  289. package/dist/commands/vds/stats.js +6 -0
  290. package/dist/commands/vds/stats.js.map +1 -1
  291. package/dist/commands/vps/activity.d.ts +1 -0
  292. package/dist/commands/vps/activity.js +5 -4
  293. package/dist/commands/vps/activity.js.map +1 -1
  294. package/dist/commands/vps/bandwidth.d.ts +1 -0
  295. package/dist/commands/vps/bandwidth.js +6 -5
  296. package/dist/commands/vps/bandwidth.js.map +1 -1
  297. package/dist/commands/vps/boot-order.d.ts +1 -0
  298. package/dist/commands/vps/boot-order.js +6 -5
  299. package/dist/commands/vps/boot-order.js.map +1 -1
  300. package/dist/commands/vps/console.d.ts +1 -0
  301. package/dist/commands/vps/console.js +10 -9
  302. package/dist/commands/vps/console.js.map +1 -1
  303. package/dist/commands/vps/details.d.ts +5 -0
  304. package/dist/commands/vps/details.js +21 -9
  305. package/dist/commands/vps/details.js.map +1 -1
  306. package/dist/commands/vps/ip/add.d.ts +1 -0
  307. package/dist/commands/vps/ip/add.js +11 -9
  308. package/dist/commands/vps/ip/add.js.map +1 -1
  309. package/dist/commands/vps/ip/list.d.ts +1 -0
  310. package/dist/commands/vps/ip/list.js +7 -6
  311. package/dist/commands/vps/ip/list.js.map +1 -1
  312. package/dist/commands/vps/list.d.ts +1 -0
  313. package/dist/commands/vps/list.js +5 -4
  314. package/dist/commands/vps/list.js.map +1 -1
  315. package/dist/commands/vps/order.d.ts +4 -2
  316. package/dist/commands/vps/order.js +26 -16
  317. package/dist/commands/vps/order.js.map +1 -1
  318. package/dist/commands/vps/power.d.ts +1 -0
  319. package/dist/commands/vps/power.js +15 -13
  320. package/dist/commands/vps/power.js.map +1 -1
  321. package/dist/commands/vps/reinstall.d.ts +1 -0
  322. package/dist/commands/vps/reinstall.js +15 -14
  323. package/dist/commands/vps/reinstall.js.map +1 -1
  324. package/dist/commands/vps/resize.d.ts +1 -0
  325. package/dist/commands/vps/resize.js +11 -9
  326. package/dist/commands/vps/resize.js.map +1 -1
  327. package/dist/commands/vps/stats.d.ts +1 -0
  328. package/dist/commands/vps/stats.js +8 -7
  329. package/dist/commands/vps/stats.js.map +1 -1
  330. package/dist/commands/whoami.d.ts +1 -0
  331. package/dist/commands/whoami.js +1 -0
  332. package/dist/commands/whoami.js.map +1 -1
  333. package/dist/help/help-filter.d.ts +10 -0
  334. package/dist/help/help-filter.js +9 -0
  335. package/dist/help/help-filter.js.map +1 -0
  336. package/dist/help/scope-aware-help.d.ts +30 -0
  337. package/dist/help/scope-aware-help.js +71 -0
  338. package/dist/help/scope-aware-help.js.map +1 -0
  339. package/dist/help.js +0 -1
  340. package/dist/help.js.map +1 -1
  341. package/dist/tui/App.js +1 -1
  342. package/dist/tui/App.js.map +1 -1
  343. package/dist/tui/components/NumberInput.js +1 -1
  344. package/dist/tui/components/Sparkline.js +1 -1
  345. package/dist/tui/screens/Billing.js +10 -10
  346. package/dist/tui/screens/Billing.js.map +1 -1
  347. package/dist/tui/screens/Dashboard.js +1 -1
  348. package/dist/tui/screens/Dashboard.js.map +1 -1
  349. package/dist/tui/screens/Order.js +328 -99
  350. package/dist/tui/screens/Order.js.map +1 -1
  351. package/dist/tui/screens/Resources.js +35 -64
  352. package/dist/tui/screens/Resources.js.map +1 -1
  353. package/dist/tui/screens/Tickets.js +31 -22
  354. package/dist/tui/screens/Tickets.js.map +1 -1
  355. package/dist/ui/image-resolve.js +1 -1
  356. package/dist/ui/image-resolve.js.map +1 -1
  357. package/dist/ui/payment.d.ts +1 -1
  358. package/dist/ui/resource-detail.d.ts +3 -0
  359. package/dist/ui/{vps-detail.js → resource-detail.js} +8 -8
  360. package/dist/ui/resource-detail.js.map +1 -0
  361. package/dist/ui/resource-resolve.d.ts +4 -0
  362. package/dist/ui/resource-resolve.js +24 -0
  363. package/dist/ui/resource-resolve.js.map +1 -0
  364. package/dist/ui/wait.d.ts +1 -1
  365. package/dist/ui/wait.js +4 -4
  366. package/dist/ui/wait.js.map +1 -1
  367. package/dist/version-check-bin.d.ts +35 -0
  368. package/dist/version-check-bin.js +123 -0
  369. package/dist/version-check-bin.js.map +1 -0
  370. package/dist/version-check.d.ts +39 -0
  371. package/dist/version-check.js +148 -0
  372. package/dist/version-check.js.map +1 -0
  373. package/package.json +11 -6
  374. package/dist/commands/bare-metal/index.d.ts +0 -4
  375. package/dist/commands/bare-metal/index.js +0 -5
  376. package/dist/commands/bare-metal/index.js.map +0 -1
  377. package/dist/commands/bare-metal/list.d.ts +0 -9
  378. package/dist/commands/bare-metal/list.js +0 -38
  379. package/dist/commands/bare-metal/list.js.map +0 -1
  380. package/dist/commands/bare-metal/order.d.ts +0 -6
  381. package/dist/commands/bare-metal/order.js +0 -27
  382. package/dist/commands/bare-metal/order.js.map +0 -1
  383. package/dist/ui/vps-detail.d.ts +0 -3
  384. package/dist/ui/vps-detail.js.map +0 -1
  385. package/dist/ui/vps-resolve.d.ts +0 -4
  386. package/dist/ui/vps-resolve.js +0 -24
  387. package/dist/ui/vps-resolve.js.map +0 -1
@@ -39,8 +39,7 @@ const emptyDraft = {
39
39
  const PROGRESS_STEPS = [
40
40
  "kind",
41
41
  "project",
42
- "plan",
43
- "location",
42
+ "plan-location",
44
43
  "image",
45
44
  "hostname",
46
45
  "auth",
@@ -52,17 +51,15 @@ function stepsForKind(kind) {
52
51
  if (kind === "vps") {
53
52
  base.push("vps-spec", "image", "hostname", "auth", "payment", "summary");
54
53
  }
55
- else if (kind === "gpu" || kind === "dedicated") {
56
- base.push("plan", "location", "image", "hostname", "auth", "payment", "summary");
54
+ else if (kind === "gpu" || kind === "dedicated" || kind === "vds") {
55
+ // Split plan/tier picker + location picker into one step so we can probe
56
+ // per-location availability live (server-side /public/order/validate) and
57
+ // offer notify-me when the chosen location is out of stock.
58
+ base.push("plan-location", "image", "hostname", "auth", "payment", "summary");
57
59
  }
58
60
  else if (kind === "storage") {
59
61
  base.push("size", "location", "hostname", "payment", "summary");
60
62
  }
61
- else if (kind === "vds") {
62
- // VDS: pick a tier from the ladder, then the standard trailing steps.
63
- // Server resolves cpu/ram/disk/price from tier_category_slug + tier_index.
64
- base.push("vds-tier", "location", "image", "hostname", "auth", "payment", "summary");
65
- }
66
63
  else {
67
64
  return PROGRESS_STEPS;
68
65
  }
@@ -92,7 +89,7 @@ export function Order() {
92
89
  (async () => {
93
90
  try {
94
91
  const [orderCatalog, storageCatalog, projects, methods, balance] = await Promise.all([
95
- api.vpsOrders.catalog().catch(() => null),
92
+ api.orders.catalog().catch(() => null),
96
93
  api.storage.catalog().catch(() => null),
97
94
  api.projects.list().catch(() => []),
98
95
  api.payments.methods().catch(() => []),
@@ -242,7 +239,7 @@ export function Order() {
242
239
  ? draft.sshKeyId
243
240
  : undefined,
244
241
  };
245
- const out = await api.vpsOrders.create(body);
242
+ const out = await api.orders.create(body);
246
243
  setResult({
247
244
  ok: true,
248
245
  orderId: out.order_id,
@@ -288,7 +285,7 @@ function LivePriceFooter({ draft, cat, }) {
288
285
  React.createElement(Text, { color: colors.dim }, "Est. monthly: "),
289
286
  est ? (React.createElement(React.Fragment, null,
290
287
  React.createElement(Text, { color: colors.accent, bold: true }, `$${est.amount.toFixed(2)}`),
291
- React.createElement(Text, { color: colors.dim }, ` · ${est.label}`))) : (React.createElement(Text, { color: colors.dim }, "—"))));
288
+ React.createElement(Text, { color: colors.dim }, ` · ${est.label}`))) : (React.createElement(Text, { color: colors.dim }, "-"))));
292
289
  }
293
290
  function StepRouter(props) {
294
291
  const { step, draft, setDraft, cat, goNext } = props;
@@ -297,12 +294,10 @@ function StepRouter(props) {
297
294
  return React.createElement(KindStep, { draft: draft, setDraft: setDraft, goNext: goNext });
298
295
  case "project":
299
296
  return React.createElement(ProjectStep, { projects: cat.projects, draft: draft, setDraft: setDraft, goNext: goNext });
300
- case "plan":
301
- return (React.createElement(PlanStep, { catalog: cat.orderCatalog, draft: draft, setDraft: setDraft, goNext: goNext }));
297
+ case "plan-location":
298
+ return (React.createElement(PlanLocationStep, { catalog: cat.orderCatalog, userEmail: props.userEmail, draft: draft, setDraft: setDraft, goNext: goNext }));
302
299
  case "vps-spec":
303
300
  return (React.createElement(VpsSpecStep, { customConfig: cat.orderCatalog?.custom_config ?? null, locations: cat.orderCatalog?.locations ?? [], userEmail: props.userEmail, draft: draft, setDraft: setDraft, goNext: goNext }));
304
- case "vds-tier":
305
- return (React.createElement(VdsTierStep, { catalog: cat.orderCatalog, draft: draft, setDraft: setDraft, goNext: goNext }));
306
301
  case "size":
307
302
  return (React.createElement(SizeStep, { catalog: cat.storageCatalog, draft: draft, setDraft: setDraft, goNext: goNext }));
308
303
  case "location":
@@ -325,7 +320,7 @@ function StepRouter(props) {
325
320
  case "result":
326
321
  return React.createElement(ResultStep, { result: props.result });
327
322
  default:
328
- return React.createElement(Text, null, "\u2014");
323
+ return React.createElement(Text, null, "-");
329
324
  }
330
325
  }
331
326
  function KindStep({ draft, setDraft, goNext, }) {
@@ -334,7 +329,7 @@ function KindStep({ draft, setDraft, goNext, }) {
334
329
  { value: "vds", label: "VDS", hint: "tier-based performance servers (order via web for now)" },
335
330
  { value: "gpu", label: "GPU", hint: "preset GPU-bearing plans" },
336
331
  { value: "dedicated", label: "Instant Metal", hint: "whole physical hosts" },
337
- { value: "storage", label: "Storage", hint: "block volume (attach to a VPS later)" },
332
+ { value: "storage", label: "Storage", hint: "block volume (attach to a resource later)" },
338
333
  ];
339
334
  return (React.createElement(Panel, { title: "What are you ordering?", paddingX: 3, paddingY: 1, width: 80 },
340
335
  React.createElement(Menu, { items: items, initialIndex: Math.max(0, items.findIndex((i) => i.value === draft.kind)), onSelect: (v) => {
@@ -375,33 +370,6 @@ function ProjectStep({ projects, draft, setDraft, goNext, }) {
375
370
  goNext();
376
371
  } })));
377
372
  }
378
- function PlanStep({ catalog, draft, setDraft, goNext, }) {
379
- if (!catalog) {
380
- return (React.createElement(Panel, { title: "Catalog unavailable", paddingX: 3, paddingY: 1, width: 80 },
381
- React.createElement(Text, { color: colors.error }, "Couldn't load the order catalog. Try again later.")));
382
- }
383
- const category = draft.kind === "gpu" ? "gpu_cloud" : "dedicated";
384
- const filtered = catalog.plans.filter((p) => p.category === category || p.category.replace("_", "-") === draft.kind);
385
- const plans = filtered.length ? filtered : catalog.plans;
386
- if (plans.length === 0) {
387
- return (React.createElement(Panel, { title: "No plans in catalog", paddingX: 3, paddingY: 1, width: 80 },
388
- React.createElement(Text, { color: colors.warning },
389
- "No ",
390
- draft.kind,
391
- " plans are currently offered. Try a different resource type.")));
392
- }
393
- const items = plans.map((p) => ({
394
- value: p.id,
395
- label: planRowLabel(p),
396
- hint: planRowHint(p),
397
- disabled: p.in_stock ? undefined : "out of stock",
398
- }));
399
- return (React.createElement(Panel, { title: `Pick a ${draft.kind === "gpu" ? "GPU" : "Instant Metal"} plan`, paddingX: 3, paddingY: 1, width: 80 },
400
- React.createElement(Menu, { items: items, initialIndex: Math.max(0, items.findIndex((i) => i.value === draft.planId)), onSelect: (v) => {
401
- setDraft((d) => ({ ...d, planId: v, locationId: null }));
402
- goNext();
403
- } })));
404
- }
405
373
  function planRowLabel(p) {
406
374
  return `${p.name} $${p.monthly_price}/mo`;
407
375
  }
@@ -412,44 +380,303 @@ function planRowHint(p) {
412
380
  const extra = p.gpu_model ? ` · ${p.gpu_model}` : "";
413
381
  return `${cores} ${ram} ${disk}${extra}`;
414
382
  }
415
- // VDS-specific tier picker. Reads catalog.categories[slug].slider_config.tiers
416
- // (the same ladder the server enforces at order time) and submits the pick
417
- // as tier_category_slug + tier_index. Different shape from PlanStep (plans)
418
- // and VpsSpecStep (custom sliders) — VDS is a third product family.
419
- function VdsTierStep({ catalog, draft, setDraft, goNext, }) {
383
+ // Combined plan/tier + location picker for VDS, GPU Cloud, and Instant Metal.
384
+ // Mirrors what the VPS custom-spec step does: probe /public/order/validate
385
+ // per-location so the user sees which locations can actually fit the pick,
386
+ // and offer marketing.notifyStock when the chosen location is out of stock.
387
+ //
388
+ // The VPS custom-spec flow lives in its own step (VpsSpecStep) because the
389
+ // left pane is a slider grid rather than a plan/tier list - different shape,
390
+ // same idea.
391
+ function PlanLocationStep({ catalog, userEmail, draft, setDraft, goNext, }) {
392
+ const api = useApi();
420
393
  if (!catalog) {
421
394
  return (React.createElement(Panel, { title: "Catalog unavailable", paddingX: 3, paddingY: 1, width: 80 },
422
395
  React.createElement(Text, { color: colors.error }, "Couldn't load the order catalog. Try again later.")));
423
396
  }
424
- // Find an enabled VDS category with a non-empty ladder. Usually
425
- // exactly one (vds_performance); multiple would need a category
426
- // picker step first — not shipped, we take the first enabled.
427
- const vdsCats = (catalog.categories ?? []).filter((c) => c.slug.startsWith("vds") &&
428
- c.slider_config?.enabled &&
429
- (c.slider_config.tiers?.length ?? 0) > 0);
430
- if (vdsCats.length === 0) {
431
- return (React.createElement(Panel, { title: "No VDS tiers configured", paddingX: 3, paddingY: 1, width: 80 },
432
- React.createElement(Text, { color: colors.warning }, "No VDS tier ladders are enabled on this deployment. Pick a different resource kind or order VDS from the web console.")));
397
+ const isVds = draft.kind === "vds";
398
+ const isDedicated = draft.kind === "dedicated";
399
+ let picks = [];
400
+ let leftTitle = "Pick a plan";
401
+ const validateKind = isVds ? "vds" : isDedicated ? "instant_metal" : "gpu_cloud";
402
+ if (isVds) {
403
+ // Find an enabled VDS category with a non-empty ladder. Usually
404
+ // exactly one (vds_performance); we take the first enabled.
405
+ const vdsCats = (catalog.categories ?? []).filter((c) => c.slug.startsWith("vds") &&
406
+ c.slider_config?.enabled &&
407
+ (c.slider_config.tiers?.length ?? 0) > 0);
408
+ if (vdsCats.length === 0) {
409
+ return (React.createElement(Panel, { title: "No VDS tiers configured", paddingX: 3, paddingY: 1, width: 80 },
410
+ React.createElement(Text, { color: colors.warning }, "No VDS tier ladders are enabled on this deployment. Pick a different resource kind or order VDS from the web console.")));
411
+ }
412
+ const cat = vdsCats[0];
413
+ leftTitle = `Pick a VDS tier (${cat.name ?? cat.slug})`;
414
+ const tiers = cat.slider_config?.tiers ?? [];
415
+ picks = tiers.map((t, i) => ({
416
+ key: `${cat.slug}#${i}`,
417
+ label: `Tier ${i} $${t.monthly_price}/mo`,
418
+ hint: `${t.cpu}c · ${t.ram_gb}GB RAM · ${t.disk_gb}GB disk · ${t.bandwidth_tb}TB BW`,
419
+ cpu_cores: t.cpu,
420
+ ram_gb: t.ram_gb,
421
+ disk_gb: t.disk_gb,
422
+ monthly_price: t.monthly_price,
423
+ in_stock: true, // VDS ladders don't carry a coarse in-stock flag; rely on per-loc probe below.
424
+ tierCategorySlug: cat.slug,
425
+ tierIndex: i,
426
+ dedicated: false,
427
+ }));
433
428
  }
434
- const cat = vdsCats[0];
435
- const tiers = cat.slider_config?.tiers ?? [];
436
- const items = tiers.map((t, i) => ({
437
- value: i,
438
- label: `Tier ${i} $${t.monthly_price}/mo`,
439
- hint: `${t.cpu}c · ${t.ram_gb}GB RAM · ${t.disk_gb}GB disk · ${t.bandwidth_tb}TB BW`,
440
- }));
441
- return (React.createElement(Panel, { title: `Pick a VDS tier (${cat.name ?? cat.slug})`, paddingX: 3, paddingY: 1, width: 80 },
442
- React.createElement(Menu, { items: items, initialIndex: Math.max(0, items.findIndex((i) => i.value === draft.tierIndex)), onSelect: (v) => {
443
- setDraft((d) => ({
444
- ...d,
445
- tierCategorySlug: cat.slug,
446
- tierIndex: v,
447
- // Reset downstream location so the next step re-picks based
448
- // on where this tier is actually available.
449
- locationId: null,
450
- }));
451
- goNext();
452
- } })));
429
+ else {
430
+ const category = isDedicated ? "dedicated" : "gpu_cloud";
431
+ const filtered = catalog.plans.filter((p) => p.category === category || p.category.replace("_", "-") === draft.kind);
432
+ const plans = filtered.length ? filtered : catalog.plans;
433
+ if (plans.length === 0) {
434
+ return (React.createElement(Panel, { title: "No plans in catalog", paddingX: 3, paddingY: 1, width: 80 },
435
+ React.createElement(Text, { color: colors.warning },
436
+ "No ",
437
+ draft.kind,
438
+ " plans are currently offered. Try a different resource type.")));
439
+ }
440
+ leftTitle = `Pick a ${isDedicated ? "Instant Metal" : "GPU"} plan`;
441
+ picks = plans.map((p) => ({
442
+ key: p.id,
443
+ label: planRowLabel(p),
444
+ hint: planRowHint(p),
445
+ cpu_cores: p.cpu_cores,
446
+ ram_gb: p.ram_gb,
447
+ disk_gb: p.disk_gb,
448
+ monthly_price: p.monthly_price,
449
+ in_stock: p.in_stock,
450
+ planId: p.id,
451
+ dedicated: isDedicated,
452
+ }));
453
+ }
454
+ const locations = catalog.locations;
455
+ const hasLocations = locations.length > 0;
456
+ // Initial cursor: last-picked selection if present, else the first
457
+ // in-stock (plan-level) row; falls back to 0.
458
+ const initialPickIdx = (() => {
459
+ if (isVds && draft.tierIndex != null && draft.tierCategorySlug) {
460
+ const idx = picks.findIndex((p) => p.tierCategorySlug === draft.tierCategorySlug &&
461
+ p.tierIndex === draft.tierIndex);
462
+ if (idx >= 0)
463
+ return idx;
464
+ }
465
+ if (!isVds && draft.planId) {
466
+ const idx = picks.findIndex((p) => p.planId === draft.planId);
467
+ if (idx >= 0)
468
+ return idx;
469
+ }
470
+ const firstInStock = picks.findIndex((p) => p.in_stock);
471
+ return firstInStock >= 0 ? firstInStock : 0;
472
+ })();
473
+ const [pickCursor, setPickCursor] = useState(initialPickIdx);
474
+ const [locCursor, setLocCursor] = useState(() => {
475
+ const idx = locations.findIndex((l) => l.id === draft.locationId);
476
+ return idx >= 0 ? idx : 0;
477
+ });
478
+ const [pane, setPane] = useState("pick");
479
+ const [notifyState, setNotifyState] = useState("idle");
480
+ // Availability probe keyed on (pickCursor, location). Cleared whenever
481
+ // the pick changes so a stale in-stock badge can't survive a tier switch.
482
+ const [stockByLoc, setStockByLoc] = useState({});
483
+ const currentPick = picks[pickCursor];
484
+ useEffect(() => {
485
+ // Reset probe results when the pick changes - a Tier 2 might fit where
486
+ // Tier 3 does not (and vice versa), so old flags would lie.
487
+ setStockByLoc({});
488
+ setNotifyState("idle");
489
+ }, [pickCursor]);
490
+ useEffect(() => {
491
+ if (!hasLocations || !currentPick)
492
+ return;
493
+ if (!currentPick.in_stock)
494
+ return; // Plan globally OOS - nothing to probe.
495
+ let cancelled = false;
496
+ // Small debounce so switching picks quickly doesn't fire N * K validate
497
+ // calls.
498
+ const t = setTimeout(() => {
499
+ for (const loc of locations) {
500
+ api.orders
501
+ .validate({
502
+ cpu_cores: currentPick.cpu_cores,
503
+ ram_gb: currentPick.ram_gb,
504
+ disk_gb: currentPick.disk_gb,
505
+ location_id: loc.id,
506
+ dedicated: currentPick.dedicated,
507
+ kind: validateKind,
508
+ })
509
+ .then((res) => {
510
+ if (cancelled)
511
+ return;
512
+ setStockByLoc((m) => ({ ...m, [loc.id]: res.available }));
513
+ })
514
+ .catch(() => {
515
+ // Swallow - the location just stays unmarked; the server will
516
+ // fail the order if the spec truly can't fit, and we've already
517
+ // let the user see the pick.
518
+ });
519
+ }
520
+ }, 250);
521
+ return () => {
522
+ cancelled = true;
523
+ clearTimeout(t);
524
+ };
525
+ // Re-run whenever the pick's specs, the location list, or the kind changes.
526
+ // eslint-disable-next-line react-hooks/exhaustive-deps
527
+ }, [
528
+ hasLocations,
529
+ currentPick?.cpu_cores,
530
+ currentPick?.ram_gb,
531
+ currentPick?.disk_gb,
532
+ currentPick?.dedicated,
533
+ validateKind,
534
+ locations,
535
+ ]);
536
+ const selLoc = hasLocations ? locations[locCursor] ?? null : null;
537
+ const planLevelOOS = Boolean(currentPick && !currentPick.in_stock);
538
+ const locStockKnown = selLoc ? stockByLoc[selLoc.id] !== undefined : false;
539
+ const selInStock = !hasLocations ||
540
+ (!planLevelOOS && (!locStockKnown || stockByLoc[selLoc?.id ?? ""] !== false));
541
+ const canContinue = Boolean(currentPick) && Boolean(selLoc) && selInStock;
542
+ const commit = () => {
543
+ if (!currentPick || !selLoc)
544
+ return;
545
+ setDraft((d) => ({
546
+ ...d,
547
+ planId: currentPick.planId ?? null,
548
+ tierCategorySlug: currentPick.tierCategorySlug ?? null,
549
+ tierIndex: currentPick.tierIndex ?? null,
550
+ locationId: selLoc.id,
551
+ }));
552
+ goNext();
553
+ };
554
+ const requestNotify = async () => {
555
+ if (!selLoc || !currentPick)
556
+ return;
557
+ if (notifyState === "sending" || notifyState === "sent")
558
+ return;
559
+ if (!userEmail) {
560
+ setNotifyState("error");
561
+ return;
562
+ }
563
+ setNotifyState("sending");
564
+ try {
565
+ await api.marketing.notifyStock({
566
+ email: userEmail,
567
+ location_id: selLoc.id,
568
+ plan_id: currentPick.planId ?? null,
569
+ note: `CLI order wizard - ${draft.kind}`,
570
+ config_json: {
571
+ cpu_cores: currentPick.cpu_cores,
572
+ ram_gb: currentPick.ram_gb,
573
+ disk_gb: currentPick.disk_gb,
574
+ dedicated: currentPick.dedicated,
575
+ kind: validateKind,
576
+ tier_category_slug: currentPick.tierCategorySlug ?? null,
577
+ tier_index: currentPick.tierIndex ?? null,
578
+ },
579
+ });
580
+ setNotifyState("sent");
581
+ }
582
+ catch {
583
+ setNotifyState("error");
584
+ }
585
+ };
586
+ useInput((input, key) => {
587
+ if (key.tab) {
588
+ if (hasLocations)
589
+ setPane((p) => (p === "pick" ? "loc" : "pick"));
590
+ return;
591
+ }
592
+ if (pane === "pick") {
593
+ if (key.upArrow) {
594
+ setPickCursor((c) => (c === 0 ? picks.length - 1 : c - 1));
595
+ }
596
+ else if (key.downArrow) {
597
+ setPickCursor((c) => (c === picks.length - 1 ? 0 : c + 1));
598
+ }
599
+ else if (key.return || key.rightArrow) {
600
+ if (hasLocations)
601
+ setPane("loc");
602
+ else
603
+ commit();
604
+ }
605
+ return;
606
+ }
607
+ // pane === "loc"
608
+ if (key.upArrow) {
609
+ setLocCursor((c) => (c === 0 ? locations.length - 1 : c - 1));
610
+ }
611
+ else if (key.downArrow) {
612
+ setLocCursor((c) => (c === locations.length - 1 ? 0 : c + 1));
613
+ }
614
+ else if (key.leftArrow) {
615
+ setPane("pick");
616
+ }
617
+ else if (key.return) {
618
+ if (canContinue)
619
+ commit();
620
+ else
621
+ void requestNotify();
622
+ }
623
+ });
624
+ const buttonLabel = canContinue
625
+ ? "Continue"
626
+ : notifyState === "sent"
627
+ ? "Requested ✓"
628
+ : notifyState === "sending"
629
+ ? "Sending…"
630
+ : "Notify me";
631
+ const pickPanel = (React.createElement(Panel, { title: leftTitle, paddingX: 2, paddingY: 1, width: hasLocations ? 50 : 80, borderColor: pane === "pick" ? colors.accent : undefined },
632
+ React.createElement(Box, { flexDirection: "column" },
633
+ picks.map((p, i) => {
634
+ const isCursor = i === pickCursor;
635
+ const disabled = !p.in_stock;
636
+ return (React.createElement(Box, { key: p.key },
637
+ React.createElement(Text, { color: isCursor
638
+ ? pane === "pick"
639
+ ? colors.accent
640
+ : colors.text
641
+ : colors.dim }, isCursor ? `${glyphs.chevronRight} ` : " "),
642
+ React.createElement(Text, { bold: isCursor, color: disabled
643
+ ? colors.dim
644
+ : isCursor && pane === "pick"
645
+ ? colors.accent
646
+ : colors.text }, p.label),
647
+ React.createElement(Text, { color: colors.dim }, ` ${p.hint}`),
648
+ disabled ? (React.createElement(Text, { color: colors.dim }, " out of stock")) : null));
649
+ }),
650
+ React.createElement(Box, { marginTop: 1 },
651
+ React.createElement(ActionButton, { keybind: "\u21B5", label: buttonLabel, onPress: () => (canContinue ? commit() : void requestNotify()), focused: pane === "pick" && !hasLocations })),
652
+ selLoc && !canContinue && currentPick ? (React.createElement(Box, null,
653
+ React.createElement(Text, { color: notifyState === "sent" ? colors.dim : colors.warning }, notifyState === "sent"
654
+ ? `We'll email you when ${selLoc.city ?? selLoc.name} has capacity for this ${isVds ? "tier" : "plan"}.`
655
+ : `${selLoc.city ?? selLoc.name} can't fit this ${isVds ? "tier" : "plan"} right now - we can email you when it can.`))) : null,
656
+ notifyState === "error" ? (React.createElement(Box, null,
657
+ React.createElement(Text, { color: colors.error }, "Couldn't save the notification - try again."))) : null)));
658
+ if (!hasLocations)
659
+ return pickPanel;
660
+ return (React.createElement(Box, { flexDirection: "row", width: 80 },
661
+ pickPanel,
662
+ React.createElement(Panel, { title: "Location", paddingX: 1, paddingY: 1, width: 30, borderColor: pane === "loc" ? colors.accent : undefined },
663
+ React.createElement(Box, { flexDirection: "column" }, locations.map((l, i) => {
664
+ const isCursor = i === locCursor;
665
+ const known = stockByLoc[l.id];
666
+ const oos = planLevelOOS || known === false;
667
+ const name = [l.city ?? l.name, l.country ?? ""]
668
+ .filter(Boolean)
669
+ .join(", ");
670
+ return (React.createElement(Box, { key: l.id, flexDirection: "column" },
671
+ React.createElement(Box, null,
672
+ React.createElement(Text, { color: isCursor
673
+ ? pane === "loc"
674
+ ? colors.accent
675
+ : colors.text
676
+ : colors.dim }, isCursor ? `${glyphs.chevronRight} ` : " "),
677
+ React.createElement(Text, { wrap: "truncate-end", bold: isCursor, dimColor: oos, color: oos ? colors.dim : isCursor ? colors.accent : colors.text }, name)),
678
+ oos ? (React.createElement(Text, { color: colors.dim }, " out of stock")) : known === undefined ? (React.createElement(Text, { color: colors.dim }, ` ${l.code ?? "checking…"}`)) : l.code ? (React.createElement(Text, { color: colors.dim }, ` ${l.code}`)) : null));
679
+ })))));
453
680
  }
454
681
  function VpsSpecStep({ customConfig, locations, userEmail, draft, setDraft, goNext, }) {
455
682
  if (!customConfig?.enabled) {
@@ -492,8 +719,8 @@ function VpsSpecFieldsStep({ customConfig, locations, userEmail, draft, setDraft
492
719
  let cancelled = false;
493
720
  const t = setTimeout(() => {
494
721
  for (const loc of locations) {
495
- api.vpsOrders
496
- .customAvailability({
722
+ api.orders
723
+ .validate({
497
724
  cpu_cores: cpuN,
498
725
  ram_gb: ramN,
499
726
  disk_gb: diskN,
@@ -588,7 +815,7 @@ function VpsSpecFieldsStep({ customConfig, locations, userEmail, draft, setDraft
588
815
  await api.marketing.notifyStock({
589
816
  email: userEmail,
590
817
  location_id: selLoc.id,
591
- note: "CLI order wizard — custom VPS",
818
+ note: "CLI order wizard - custom VPS",
592
819
  config_json: {
593
820
  cpu_cores: Number(cpu) || null,
594
821
  ram_gb: Number(ramGb) || null,
@@ -672,9 +899,9 @@ function VpsSpecFieldsStep({ customConfig, locations, userEmail, draft, setDraft
672
899
  !selInStock && selLoc ? (React.createElement(Box, null,
673
900
  React.createElement(Text, { color: notifyState === "sent" ? colors.dim : colors.warning }, notifyState === "sent"
674
901
  ? `We'll email you when ${selLoc.city ?? selLoc.name} is back in stock.`
675
- : `${selLoc.city ?? selLoc.name} is out of stock — we can email you when it's back.`))) : null,
902
+ : `${selLoc.city ?? selLoc.name} is out of stock - we can email you when it's back.`))) : null,
676
903
  notifyState === "error" ? (React.createElement(Box, null,
677
- React.createElement(Text, { color: colors.error }, "Couldn't save the notification \u2014 try again."))) : null,
904
+ React.createElement(Text, { color: colors.error }, "Couldn't save the notification - try again."))) : null,
678
905
  React.createElement(Box, { marginTop: 1 },
679
906
  React.createElement(Text, { color: colors.dim }, hasLocations
680
907
  ? "Tab location/spec · ↑↓ move · ←/→ CPU type · Enter continue"
@@ -954,7 +1181,7 @@ function PaymentStep({ methods, creditBalance, balanceCurrency, estimatedCost, d
954
1181
  else {
955
1182
  if (!draft.paymentMethodId && !(draft.applyCredits && creditsCover)) {
956
1183
  setErr(creditBalance > 0
957
- ? "Pick a payment method — credits don't cover the full amount."
1184
+ ? "Pick a payment method - credits don't cover the full amount."
958
1185
  : "Pick a payment method.");
959
1186
  return;
960
1187
  }
@@ -1015,7 +1242,7 @@ function PaymentStep({ methods, creditBalance, balanceCurrency, estimatedCost, d
1015
1242
  isBitpay ? (React.createElement(Box, { marginTop: 1 },
1016
1243
  React.createElement(Text, { color: colors.dim }, "BitPay opens a hosted checkout URL in your browser after submit."))) : null,
1017
1244
  methods.length !== eligible.length ? (React.createElement(Box, { marginTop: 1 },
1018
- React.createElement(Text, { color: colors.dim }, "Stripe ACH hidden \u2014 it can't settle instant charges. Pay an existing invoice in Billing instead."))) : null,
1245
+ React.createElement(Text, { color: colors.dim }, "Stripe ACH hidden - it can't settle instant charges. Pay an existing invoice in Billing instead."))) : null,
1019
1246
  err ? (React.createElement(Box, { marginTop: 1 },
1020
1247
  React.createElement(Text, { color: colors.error }, err))) : null,
1021
1248
  React.createElement(Box, { marginTop: 1 },
@@ -1057,9 +1284,9 @@ function SummaryStep({ draft, cat, onSubmit, onEdit, }) {
1057
1284
  const specLine = draft.kind === "vps"
1058
1285
  ? `${draft.customSpec.cpu_cores ?? "?"} vCPU · ${draft.customSpec.ram_gb ?? 0} GB RAM · ${draft.customSpec.disk_gb ?? "?"} GB disk${draft.customSpec.bandwidth_tb ? ` · ${draft.customSpec.bandwidth_tb} TB BW` : ""}${draft.customSpec._dedicated ? " · dedicated" : ""}`
1059
1286
  : draft.kind === "vds" && vdsTier
1060
- ? `Tier ${draft.tierIndex} — ${vdsTier.cpu}c ${vdsTier.ram_gb}G ${vdsTier.disk_gb}G · ${vdsTier.bandwidth_tb}TB BW ($${vdsTier.monthly_price}/mo)`
1287
+ ? `Tier ${draft.tierIndex} - ${vdsTier.cpu}c ${vdsTier.ram_gb}G ${vdsTier.disk_gb}G · ${vdsTier.bandwidth_tb}TB BW ($${vdsTier.monthly_price}/mo)`
1061
1288
  : plan
1062
- ? `${plan.name} — ${plan.cpu_cores}c ${plan.ram_gb}G ${plan.disk_gb}G${plan.gpu_model ? ` · ${plan.gpu_model}` : ""}`
1289
+ ? `${plan.name} - ${plan.cpu_cores}c ${plan.ram_gb}G ${plan.disk_gb}G${plan.gpu_model ? ` · ${plan.gpu_model}` : ""}`
1063
1290
  : undefined;
1064
1291
  const paymentLabel = (() => {
1065
1292
  const parts = [];
@@ -1072,17 +1299,17 @@ function SummaryStep({ draft, cat, onSubmit, onEdit, }) {
1072
1299
  })();
1073
1300
  return (React.createElement(Panel, { title: "Review your order", paddingX: 3, paddingY: 1, width: 80 },
1074
1301
  React.createElement(Box, { flexDirection: "column" },
1075
- React.createElement(Row, { label: "Kind", value: draft.kind ?? "—" }),
1076
- React.createElement(Row, { label: "Project", value: projectName ?? draft.projectId ?? "—" }),
1077
- draft.kind === "storage" ? (React.createElement(Row, { label: "Size", value: draft.storageSizeGb ? `${draft.storageSizeGb} GB` : "—" })) : (React.createElement(Row, { label: "Spec", value: specLine ?? "—" })),
1078
- React.createElement(Row, { label: "Location", value: locName ?? draft.locationId ?? "—" }),
1079
- draft.kind !== "storage" ? (React.createElement(Row, { label: "Image", value: imageName ?? draft.imageId ?? "—" })) : null,
1080
- React.createElement(Row, { label: draft.kind === "storage" ? "Name" : "Hostname", value: draft.hostname || "—" }),
1302
+ React.createElement(Row, { label: "Kind", value: draft.kind ?? "-" }),
1303
+ React.createElement(Row, { label: "Project", value: projectName ?? draft.projectId ?? "-" }),
1304
+ draft.kind === "storage" ? (React.createElement(Row, { label: "Size", value: draft.storageSizeGb ? `${draft.storageSizeGb} GB` : "-" })) : (React.createElement(Row, { label: "Spec", value: specLine ?? "-" })),
1305
+ React.createElement(Row, { label: "Location", value: locName ?? draft.locationId ?? "-" }),
1306
+ draft.kind !== "storage" ? (React.createElement(Row, { label: "Image", value: imageName ?? draft.imageId ?? "-" })) : null,
1307
+ React.createElement(Row, { label: draft.kind === "storage" ? "Name" : "Hostname", value: draft.hostname || "-" }),
1081
1308
  draft.kind !== "storage" ? (React.createElement(Row, { label: "Auth", value: draft.authKind === "password"
1082
1309
  ? "root password (hidden)"
1083
1310
  : draft.authKind === "ssh-paste"
1084
1311
  ? "pasted SSH public key"
1085
- : "—" })) : null,
1312
+ : "-" })) : null,
1086
1313
  React.createElement(Row, { label: "Payment", value: paymentLabel }),
1087
1314
  React.createElement(Box, { marginTop: 1 },
1088
1315
  React.createElement(Menu, { items: [
@@ -1100,7 +1327,7 @@ function Row({ label, value }) {
1100
1327
  return (React.createElement(Box, null,
1101
1328
  React.createElement(Box, { width: 14 },
1102
1329
  React.createElement(Text, { color: colors.dim }, label)),
1103
- React.createElement(Text, { color: colors.text }, value === undefined || value === null || value === "" ? "—" : String(value))));
1330
+ React.createElement(Text, { color: colors.text }, value === undefined || value === null || value === "" ? "-" : String(value))));
1104
1331
  }
1105
1332
  function ResultStep({ result, }) {
1106
1333
  if (!result) {
@@ -1117,13 +1344,13 @@ function ResultStep({ result, }) {
1117
1344
  return (React.createElement(Panel, { title: "Order submitted", paddingX: 3, paddingY: 1, width: 80, borderColor: colors.success },
1118
1345
  React.createElement(Box, { flexDirection: "column" },
1119
1346
  React.createElement(Row, { label: "Status", value: result.status ?? "ok" }),
1120
- React.createElement(Row, { label: "Order id", value: result.orderId ?? "—" }),
1121
- React.createElement(Row, { label: "Invoice id", value: result.invoiceId ?? "—" }),
1347
+ React.createElement(Row, { label: "Order id", value: result.orderId ?? "-" }),
1348
+ React.createElement(Row, { label: "Invoice id", value: result.invoiceId ?? "-" }),
1122
1349
  result.checkoutUrl ? React.createElement(Row, { label: "Checkout URL", value: result.checkoutUrl }) : null,
1123
1350
  React.createElement(Box, { marginTop: 1 },
1124
1351
  React.createElement(Text, { color: color }, result.checkoutUrl
1125
1352
  ? "Open the checkout URL in your browser to complete payment."
1126
- : "All done — see Resources to watch provisioning.")),
1353
+ : "All done - see Resources to watch provisioning.")),
1127
1354
  React.createElement(Box, { marginTop: 1 },
1128
1355
  React.createElement(Text, { color: colors.dim }, "Press Esc or Enter to return to Dashboard.")))));
1129
1356
  }
@@ -1148,6 +1375,8 @@ function tipForStep(step, draft, cancelConfirm) {
1148
1375
  return "↑↓ to choose, Enter to select. Esc to cancel.";
1149
1376
  case "vps-spec":
1150
1377
  return "Tab location/spec · ↑↓ move · Enter continue · Esc back.";
1378
+ case "plan-location":
1379
+ return "Tab pick/location · ↑↓ move · Enter continue (or Notify me if OOS) · Esc back.";
1151
1380
  case "hostname":
1152
1381
  return "Type a hostname (5–253 chars). Enter to confirm · Esc back.";
1153
1382
  case "auth":
@@ -1182,7 +1411,7 @@ function buildCustomSpec(s) {
1182
1411
  function fingerprint(pubKey) {
1183
1412
  const parts = pubKey.trim().split(/\s+/);
1184
1413
  if (parts.length === 0)
1185
- return "—";
1414
+ return "-";
1186
1415
  const algo = parts[0] ?? "";
1187
1416
  const b64 = parts[1] ?? "";
1188
1417
  const comment = parts.slice(2).join(" ");