@synteq/cli 0.2.0 → 1.1.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 (433) hide show
  1. package/dist/api/client.d.ts +362 -5
  2. package/dist/api/client.js +559 -44
  3. package/dist/api/client.js.map +1 -1
  4. package/dist/api/factory.js +5 -2
  5. package/dist/api/factory.js.map +1 -1
  6. package/dist/api/types.d.ts +892 -3
  7. package/dist/apps-support/deploy.d.ts +197 -0
  8. package/dist/apps-support/deploy.js +639 -0
  9. package/dist/apps-support/deploy.js.map +1 -0
  10. package/dist/apps-support/dotenv.d.ts +67 -0
  11. package/dist/apps-support/dotenv.js +136 -0
  12. package/dist/apps-support/dotenv.js.map +1 -0
  13. package/dist/apps-support/env-rollout.d.ts +18 -0
  14. package/dist/apps-support/env-rollout.js +52 -0
  15. package/dist/apps-support/env-rollout.js.map +1 -0
  16. package/dist/apps-support/git.d.ts +14 -0
  17. package/dist/apps-support/git.js +25 -0
  18. package/dist/apps-support/git.js.map +1 -0
  19. package/dist/apps-support/link.d.ts +25 -0
  20. package/dist/apps-support/link.js +39 -0
  21. package/dist/apps-support/link.js.map +1 -0
  22. package/dist/apps-support/log-stream.d.ts +25 -0
  23. package/dist/apps-support/log-stream.js +85 -0
  24. package/dist/apps-support/log-stream.js.map +1 -0
  25. package/dist/apps-support/paid-app.d.ts +64 -0
  26. package/dist/apps-support/paid-app.js +195 -0
  27. package/dist/apps-support/paid-app.js.map +1 -0
  28. package/dist/apps-support/plans.d.ts +44 -0
  29. package/dist/apps-support/plans.js +43 -0
  30. package/dist/apps-support/plans.js.map +1 -0
  31. package/dist/apps-support/resolve.d.ts +10 -0
  32. package/dist/apps-support/resolve.js +53 -0
  33. package/dist/apps-support/resolve.js.map +1 -0
  34. package/dist/apps-support/time.d.ts +20 -0
  35. package/dist/apps-support/time.js +82 -0
  36. package/dist/apps-support/time.js.map +1 -0
  37. package/dist/auth/scope.js +4 -0
  38. package/dist/auth/scope.js.map +1 -1
  39. package/dist/auth/tokens.d.ts +3 -0
  40. package/dist/auth/tokens.js +6 -4
  41. package/dist/auth/tokens.js.map +1 -1
  42. package/dist/base/command.d.ts +35 -0
  43. package/dist/base/command.js +87 -4
  44. package/dist/base/command.js.map +1 -1
  45. package/dist/commands/agents.d.ts +10 -0
  46. package/dist/commands/agents.js +53 -0
  47. package/dist/commands/agents.js.map +1 -0
  48. package/dist/commands/api.d.ts +0 -1
  49. package/dist/commands/api.js +6 -5
  50. package/dist/commands/api.js.map +1 -1
  51. package/dist/commands/app/deployment/list.d.ts +14 -0
  52. package/dist/commands/app/deployment/list.js +45 -0
  53. package/dist/commands/app/deployment/list.js.map +1 -0
  54. package/dist/commands/app/deployment/rollback.d.ts +18 -0
  55. package/dist/commands/app/deployment/rollback.js +57 -0
  56. package/dist/commands/app/deployment/rollback.js.map +1 -0
  57. package/dist/commands/app/deployment/show.d.ts +26 -0
  58. package/dist/commands/app/deployment/show.js +98 -0
  59. package/dist/commands/app/deployment/show.js.map +1 -0
  60. package/dist/commands/app/domain/add.d.ts +17 -0
  61. package/dist/commands/app/domain/add.js +59 -0
  62. package/dist/commands/app/domain/add.js.map +1 -0
  63. package/dist/commands/app/domain/list.d.ts +14 -0
  64. package/dist/commands/app/domain/list.js +42 -0
  65. package/dist/commands/app/domain/list.js.map +1 -0
  66. package/dist/commands/app/domain/remove.d.ts +16 -0
  67. package/dist/commands/app/domain/remove.js +51 -0
  68. package/dist/commands/app/domain/remove.js.map +1 -0
  69. package/dist/commands/app/domain/verify.d.ts +15 -0
  70. package/dist/commands/app/domain/verify.js +39 -0
  71. package/dist/commands/app/domain/verify.js.map +1 -0
  72. package/dist/commands/app/env/add.d.ts +22 -0
  73. package/dist/commands/app/env/add.js +103 -0
  74. package/dist/commands/app/env/add.js.map +1 -0
  75. package/dist/commands/app/env/list.d.ts +17 -0
  76. package/dist/commands/app/env/list.js +40 -0
  77. package/dist/commands/app/env/list.js.map +1 -0
  78. package/dist/commands/app/env/reveal.d.ts +17 -0
  79. package/dist/commands/app/env/reveal.js +40 -0
  80. package/dist/commands/app/env/reveal.js.map +1 -0
  81. package/dist/commands/app/env/rm.d.ts +16 -0
  82. package/dist/commands/app/env/rm.js +48 -0
  83. package/dist/commands/app/env/rm.js.map +1 -0
  84. package/dist/commands/app/health.d.ts +14 -0
  85. package/dist/commands/app/health.js +40 -0
  86. package/dist/commands/app/health.js.map +1 -0
  87. package/dist/commands/app/index.d.ts +6 -0
  88. package/dist/commands/app/index.js +7 -0
  89. package/dist/commands/app/index.js.map +1 -0
  90. package/dist/commands/app/link.d.ts +22 -0
  91. package/dist/commands/app/link.js +31 -0
  92. package/dist/commands/app/link.js.map +1 -0
  93. package/dist/commands/app/logs.d.ts +25 -0
  94. package/dist/commands/app/logs.js +121 -0
  95. package/dist/commands/app/logs.js.map +1 -0
  96. package/dist/commands/app/metrics.d.ts +21 -0
  97. package/dist/commands/app/metrics.js +123 -0
  98. package/dist/commands/app/metrics.js.map +1 -0
  99. package/dist/commands/app/plan/change.d.ts +18 -0
  100. package/dist/commands/app/plan/change.js +79 -0
  101. package/dist/commands/app/plan/change.js.map +1 -0
  102. package/dist/commands/app/plan/show.d.ts +14 -0
  103. package/dist/commands/app/plan/show.js +40 -0
  104. package/dist/commands/app/plan/show.js.map +1 -0
  105. package/dist/commands/app/settings/set.d.ts +25 -0
  106. package/dist/commands/app/settings/set.js +96 -0
  107. package/dist/commands/app/settings/set.js.map +1 -0
  108. package/dist/commands/app/settings/show.d.ts +14 -0
  109. package/dist/commands/app/settings/show.js +48 -0
  110. package/dist/commands/app/settings/show.js.map +1 -0
  111. package/dist/commands/app/unlink.d.ts +8 -0
  112. package/dist/commands/app/unlink.js +25 -0
  113. package/dist/commands/app/unlink.js.map +1 -0
  114. package/dist/commands/apps/create.d.ts +26 -0
  115. package/dist/commands/apps/create.js +91 -0
  116. package/dist/commands/apps/create.js.map +1 -0
  117. package/dist/commands/apps/list.d.ts +16 -0
  118. package/dist/commands/apps/list.js +54 -0
  119. package/dist/commands/apps/list.js.map +1 -0
  120. package/dist/commands/baremetal/activity.d.ts +14 -0
  121. package/dist/commands/baremetal/activity.js +53 -0
  122. package/dist/commands/baremetal/activity.js.map +1 -0
  123. package/dist/commands/baremetal/bandwidth.d.ts +10 -0
  124. package/dist/commands/baremetal/bandwidth.js +86 -0
  125. package/dist/commands/baremetal/bandwidth.js.map +1 -0
  126. package/dist/commands/baremetal/console.d.ts +20 -0
  127. package/dist/commands/baremetal/console.js +72 -0
  128. package/dist/commands/baremetal/console.js.map +1 -0
  129. package/dist/commands/baremetal/details.d.ts +11 -0
  130. package/dist/commands/baremetal/details.js +116 -0
  131. package/dist/commands/baremetal/details.js.map +1 -0
  132. package/dist/commands/baremetal/index.d.ts +5 -0
  133. package/dist/commands/baremetal/index.js +6 -0
  134. package/dist/commands/baremetal/index.js.map +1 -0
  135. package/dist/commands/baremetal/install-password.d.ts +14 -0
  136. package/dist/commands/baremetal/install-password.js +80 -0
  137. package/dist/commands/baremetal/install-password.js.map +1 -0
  138. package/dist/commands/baremetal/list.d.ts +11 -0
  139. package/dist/commands/baremetal/list.js +59 -0
  140. package/dist/commands/baremetal/list.js.map +1 -0
  141. package/dist/commands/baremetal/order.d.ts +34 -0
  142. package/dist/commands/baremetal/order.js +394 -0
  143. package/dist/commands/baremetal/order.js.map +1 -0
  144. package/dist/commands/baremetal/power.d.ts +18 -0
  145. package/dist/commands/baremetal/power.js +168 -0
  146. package/dist/commands/baremetal/power.js.map +1 -0
  147. package/dist/commands/baremetal/reinstall.d.ts +21 -0
  148. package/dist/commands/baremetal/reinstall.js +168 -0
  149. package/dist/commands/baremetal/reinstall.js.map +1 -0
  150. package/dist/commands/config/profile/add.d.ts +11 -0
  151. package/dist/commands/config/profile/add.js +51 -0
  152. package/dist/commands/config/profile/add.js.map +1 -0
  153. package/dist/commands/config/profile/list.d.ts +7 -0
  154. package/dist/commands/config/profile/list.js +29 -0
  155. package/dist/commands/config/profile/list.js.map +1 -0
  156. package/dist/commands/config/profile/remove.d.ts +11 -0
  157. package/dist/commands/config/profile/remove.js +35 -0
  158. package/dist/commands/config/profile/remove.js.map +1 -0
  159. package/dist/commands/config/profile/use.d.ts +10 -0
  160. package/dist/commands/config/profile/use.js +44 -0
  161. package/dist/commands/config/profile/use.js.map +1 -0
  162. package/dist/commands/config/show.js +4 -1
  163. package/dist/commands/config/show.js.map +1 -1
  164. package/dist/commands/credits/add.js +2 -2
  165. package/dist/commands/credits/add.js.map +1 -1
  166. package/dist/commands/credits/index.js +5 -1
  167. package/dist/commands/credits/index.js.map +1 -1
  168. package/dist/commands/deploy.d.ts +51 -0
  169. package/dist/commands/deploy.js +515 -0
  170. package/dist/commands/deploy.js.map +1 -0
  171. package/dist/commands/function/create.d.ts +29 -0
  172. package/dist/commands/function/create.js +113 -0
  173. package/dist/commands/function/create.js.map +1 -0
  174. package/dist/commands/function/credits/add.d.ts +29 -0
  175. package/dist/commands/function/credits/add.js +209 -0
  176. package/dist/commands/function/credits/add.js.map +1 -0
  177. package/dist/commands/function/credits/auto-reload.d.ts +27 -0
  178. package/dist/commands/function/credits/auto-reload.js +107 -0
  179. package/dist/commands/function/credits/auto-reload.js.map +1 -0
  180. package/dist/commands/function/credits/index.d.ts +22 -0
  181. package/dist/commands/function/credits/index.js +80 -0
  182. package/dist/commands/function/credits/index.js.map +1 -0
  183. package/dist/commands/function/cron/add.d.ts +19 -0
  184. package/dist/commands/function/cron/add.js +74 -0
  185. package/dist/commands/function/cron/add.js.map +1 -0
  186. package/dist/commands/function/cron/list.d.ts +12 -0
  187. package/dist/commands/function/cron/list.js +55 -0
  188. package/dist/commands/function/cron/list.js.map +1 -0
  189. package/dist/commands/function/cron/rm.d.ts +17 -0
  190. package/dist/commands/function/cron/rm.js +73 -0
  191. package/dist/commands/function/cron/rm.js.map +1 -0
  192. package/dist/commands/function/cron/run.d.ts +16 -0
  193. package/dist/commands/function/cron/run.js +59 -0
  194. package/dist/commands/function/cron/run.js.map +1 -0
  195. package/dist/commands/function/cron/update.d.ts +21 -0
  196. package/dist/commands/function/cron/update.js +87 -0
  197. package/dist/commands/function/cron/update.js.map +1 -0
  198. package/dist/commands/function/delete.d.ts +23 -0
  199. package/dist/commands/function/delete.js +90 -0
  200. package/dist/commands/function/delete.js.map +1 -0
  201. package/dist/commands/function/deploy.d.ts +64 -0
  202. package/dist/commands/function/deploy.js +608 -0
  203. package/dist/commands/function/deploy.js.map +1 -0
  204. package/dist/commands/function/env/list.d.ts +12 -0
  205. package/dist/commands/function/env/list.js +46 -0
  206. package/dist/commands/function/env/list.js.map +1 -0
  207. package/dist/commands/function/env/reveal.d.ts +21 -0
  208. package/dist/commands/function/env/reveal.js +54 -0
  209. package/dist/commands/function/env/reveal.js.map +1 -0
  210. package/dist/commands/function/env/rm.d.ts +17 -0
  211. package/dist/commands/function/env/rm.js +62 -0
  212. package/dist/commands/function/env/rm.js.map +1 -0
  213. package/dist/commands/function/env/set.d.ts +28 -0
  214. package/dist/commands/function/env/set.js +124 -0
  215. package/dist/commands/function/env/set.js.map +1 -0
  216. package/dist/commands/function/index.d.ts +14 -0
  217. package/dist/commands/function/index.js +11 -0
  218. package/dist/commands/function/index.js.map +1 -0
  219. package/dist/commands/function/init.d.ts +47 -0
  220. package/dist/commands/function/init.js +269 -0
  221. package/dist/commands/function/init.js.map +1 -0
  222. package/dist/commands/function/invoke.d.ts +29 -0
  223. package/dist/commands/function/invoke.js +138 -0
  224. package/dist/commands/function/invoke.js.map +1 -0
  225. package/dist/commands/function/link.d.ts +23 -0
  226. package/dist/commands/function/link.js +80 -0
  227. package/dist/commands/function/link.js.map +1 -0
  228. package/dist/commands/function/list.d.ts +16 -0
  229. package/dist/commands/function/list.js +55 -0
  230. package/dist/commands/function/list.js.map +1 -0
  231. package/dist/commands/function/logs.d.ts +29 -0
  232. package/dist/commands/function/logs.js +171 -0
  233. package/dist/commands/function/logs.js.map +1 -0
  234. package/dist/commands/function/pause.d.ts +19 -0
  235. package/dist/commands/function/pause.js +50 -0
  236. package/dist/commands/function/pause.js.map +1 -0
  237. package/dist/commands/function/releases.d.ts +15 -0
  238. package/dist/commands/function/releases.js +62 -0
  239. package/dist/commands/function/releases.js.map +1 -0
  240. package/dist/commands/function/resume.d.ts +16 -0
  241. package/dist/commands/function/resume.js +47 -0
  242. package/dist/commands/function/resume.js.map +1 -0
  243. package/dist/commands/function/rollback.d.ts +18 -0
  244. package/dist/commands/function/rollback.js +69 -0
  245. package/dist/commands/function/rollback.js.map +1 -0
  246. package/dist/commands/function/settings/set.d.ts +23 -0
  247. package/dist/commands/function/settings/set.js +119 -0
  248. package/dist/commands/function/settings/set.js.map +1 -0
  249. package/dist/commands/function/show.d.ts +15 -0
  250. package/dist/commands/function/show.js +80 -0
  251. package/dist/commands/function/show.js.map +1 -0
  252. package/dist/commands/function/unlink.d.ts +9 -0
  253. package/dist/commands/function/unlink.js +34 -0
  254. package/dist/commands/function/unlink.js.map +1 -0
  255. package/dist/commands/link.d.ts +77 -0
  256. package/dist/commands/link.js +530 -0
  257. package/dist/commands/link.js.map +1 -0
  258. package/dist/commands/login.js +9 -0
  259. package/dist/commands/login.js.map +1 -1
  260. package/dist/commands/order.js +3 -1
  261. package/dist/commands/order.js.map +1 -1
  262. package/dist/commands/payments/methods/delete.js +2 -2
  263. package/dist/commands/payments/methods/delete.js.map +1 -1
  264. package/dist/commands/resources.js +50 -7
  265. package/dist/commands/resources.js.map +1 -1
  266. package/dist/commands/status.d.ts +12 -0
  267. package/dist/commands/status.js +71 -0
  268. package/dist/commands/status.js.map +1 -0
  269. package/dist/commands/storage/detach.js +1 -1
  270. package/dist/commands/storage/detach.js.map +1 -1
  271. package/dist/commands/storage/list.js +6 -2
  272. package/dist/commands/storage/list.js.map +1 -1
  273. package/dist/commands/storage/order.d.ts +2 -0
  274. package/dist/commands/storage/order.js +100 -18
  275. package/dist/commands/storage/order.js.map +1 -1
  276. package/dist/commands/storage/resize.js +19 -6
  277. package/dist/commands/storage/resize.js.map +1 -1
  278. package/dist/commands/tickets/create.d.ts +2 -0
  279. package/dist/commands/tickets/create.js +40 -1
  280. package/dist/commands/tickets/create.js.map +1 -1
  281. package/dist/commands/tickets/download.d.ts +18 -0
  282. package/dist/commands/tickets/download.js +138 -0
  283. package/dist/commands/tickets/download.js.map +1 -0
  284. package/dist/commands/tickets/list.js +13 -7
  285. package/dist/commands/tickets/list.js.map +1 -1
  286. package/dist/commands/tickets/reply.d.ts +2 -0
  287. package/dist/commands/tickets/reply.js +33 -4
  288. package/dist/commands/tickets/reply.js.map +1 -1
  289. package/dist/commands/vds/order.js +72 -7
  290. package/dist/commands/vds/order.js.map +1 -1
  291. package/dist/commands/vps/console.js +14 -6
  292. package/dist/commands/vps/console.js.map +1 -1
  293. package/dist/commands/vps/details.js +7 -1
  294. package/dist/commands/vps/details.js.map +1 -1
  295. package/dist/commands/vps/ip/add.js +76 -9
  296. package/dist/commands/vps/ip/add.js.map +1 -1
  297. package/dist/commands/vps/list.js +13 -4
  298. package/dist/commands/vps/list.js.map +1 -1
  299. package/dist/commands/vps/order.d.ts +19 -0
  300. package/dist/commands/vps/order.js +179 -23
  301. package/dist/commands/vps/order.js.map +1 -1
  302. package/dist/commands/vps/power.js +2 -2
  303. package/dist/commands/vps/power.js.map +1 -1
  304. package/dist/commands/vps/reinstall.js +2 -2
  305. package/dist/commands/vps/reinstall.js.map +1 -1
  306. package/dist/commands/vps/resize.js +36 -13
  307. package/dist/commands/vps/resize.js.map +1 -1
  308. package/dist/commands/whoami.d.ts +5 -0
  309. package/dist/commands/whoami.js +8 -3
  310. package/dist/commands/whoami.js.map +1 -1
  311. package/dist/config/paths.d.ts +1 -1
  312. package/dist/config/paths.js +6 -1
  313. package/dist/config/paths.js.map +1 -1
  314. package/dist/config/store.d.ts +58 -0
  315. package/dist/config/store.js +84 -2
  316. package/dist/config/store.js.map +1 -1
  317. package/dist/functions-support/credits.d.ts +64 -0
  318. package/dist/functions-support/credits.js +181 -0
  319. package/dist/functions-support/credits.js.map +1 -0
  320. package/dist/functions-support/cron.d.ts +17 -0
  321. package/dist/functions-support/cron.js +99 -0
  322. package/dist/functions-support/cron.js.map +1 -0
  323. package/dist/functions-support/env.d.ts +23 -0
  324. package/dist/functions-support/env.js +44 -0
  325. package/dist/functions-support/env.js.map +1 -0
  326. package/dist/functions-support/link.d.ts +25 -0
  327. package/dist/functions-support/link.js +51 -0
  328. package/dist/functions-support/link.js.map +1 -0
  329. package/dist/functions-support/poll.d.ts +40 -0
  330. package/dist/functions-support/poll.js +109 -0
  331. package/dist/functions-support/poll.js.map +1 -0
  332. package/dist/functions-support/resolve.d.ts +3 -0
  333. package/dist/functions-support/resolve.js +31 -0
  334. package/dist/functions-support/resolve.js.map +1 -0
  335. package/dist/functions-support/runtime.d.ts +30 -0
  336. package/dist/functions-support/runtime.js +52 -0
  337. package/dist/functions-support/runtime.js.map +1 -0
  338. package/dist/functions-support/source.d.ts +92 -0
  339. package/dist/functions-support/source.js +343 -0
  340. package/dist/functions-support/source.js.map +1 -0
  341. package/dist/help/scope-aware-help.js +10 -1
  342. package/dist/help/scope-aware-help.js.map +1 -1
  343. package/dist/tui/App.js +10 -25
  344. package/dist/tui/App.js.map +1 -1
  345. package/dist/tui/components/Menu.d.ts +3 -1
  346. package/dist/tui/components/Menu.js +7 -3
  347. package/dist/tui/components/Menu.js.map +1 -1
  348. package/dist/tui/router.d.ts +1 -1
  349. package/dist/tui/router.js.map +1 -1
  350. package/dist/tui/screens/Billing.js +56 -4
  351. package/dist/tui/screens/Billing.js.map +1 -1
  352. package/dist/tui/screens/Dashboard.js +8 -7
  353. package/dist/tui/screens/Dashboard.js.map +1 -1
  354. package/dist/tui/screens/Deploy.d.ts +2 -0
  355. package/dist/tui/screens/Deploy.js +912 -0
  356. package/dist/tui/screens/Deploy.js.map +1 -0
  357. package/dist/tui/screens/Order.js +359 -26
  358. package/dist/tui/screens/Order.js.map +1 -1
  359. package/dist/tui/screens/Resources.js +273 -31
  360. package/dist/tui/screens/Resources.js.map +1 -1
  361. package/dist/tui/screens/Tickets.js +18 -6
  362. package/dist/tui/screens/Tickets.js.map +1 -1
  363. package/dist/tui/screens/deployPreset.d.ts +20 -0
  364. package/dist/tui/screens/deployPreset.js +11 -0
  365. package/dist/tui/screens/deployPreset.js.map +1 -0
  366. package/dist/tui/screens/resources/AppDetail.d.ts +7 -0
  367. package/dist/tui/screens/resources/AppDetail.js +810 -0
  368. package/dist/tui/screens/resources/AppDetail.js.map +1 -0
  369. package/dist/tui/screens/resources/FunctionDetail.d.ts +7 -0
  370. package/dist/tui/screens/resources/FunctionDetail.js +751 -0
  371. package/dist/tui/screens/resources/FunctionDetail.js.map +1 -0
  372. package/dist/ui/attach.d.ts +15 -0
  373. package/dist/ui/attach.js +63 -0
  374. package/dist/ui/attach.js.map +1 -0
  375. package/dist/ui/baremetal-resolve.d.ts +10 -0
  376. package/dist/ui/baremetal-resolve.js +50 -0
  377. package/dist/ui/baremetal-resolve.js.map +1 -0
  378. package/dist/ui/confirm.js +1 -1
  379. package/dist/ui/confirm.js.map +1 -1
  380. package/dist/ui/cycle.d.ts +66 -0
  381. package/dist/ui/cycle.js +96 -0
  382. package/dist/ui/cycle.js.map +1 -0
  383. package/dist/ui/deploy-ui.d.ts +75 -0
  384. package/dist/ui/deploy-ui.js +243 -0
  385. package/dist/ui/deploy-ui.js.map +1 -0
  386. package/dist/ui/order-result.d.ts +4 -0
  387. package/dist/ui/order-result.js +32 -0
  388. package/dist/ui/order-result.js.map +1 -0
  389. package/dist/ui/payment-gate.d.ts +26 -0
  390. package/dist/ui/payment-gate.js +70 -0
  391. package/dist/ui/payment-gate.js.map +1 -0
  392. package/dist/ui/payment.js +10 -3
  393. package/dist/ui/payment.js.map +1 -1
  394. package/dist/ui/portal.d.ts +1 -1
  395. package/dist/ui/portal.js +7 -2
  396. package/dist/ui/portal.js.map +1 -1
  397. package/dist/ui/project-resolve.d.ts +25 -0
  398. package/dist/ui/project-resolve.js +31 -0
  399. package/dist/ui/project-resolve.js.map +1 -0
  400. package/dist/ui/render-mode.d.ts +5 -0
  401. package/dist/ui/render-mode.js +1 -1
  402. package/dist/ui/render-mode.js.map +1 -1
  403. package/dist/ui/resource-detail.js +0 -3
  404. package/dist/ui/resource-detail.js.map +1 -1
  405. package/dist/ui/resource-resolve.d.ts +9 -2
  406. package/dist/ui/resource-resolve.js +11 -4
  407. package/dist/ui/resource-resolve.js.map +1 -1
  408. package/dist/ui/spinner.d.ts +10 -1
  409. package/dist/ui/spinner.js +12 -3
  410. package/dist/ui/spinner.js.map +1 -1
  411. package/dist/ui/table.d.ts +7 -0
  412. package/dist/ui/table.js +11 -0
  413. package/dist/ui/table.js.map +1 -1
  414. package/dist/ui/tax.d.ts +10 -0
  415. package/dist/ui/tax.js +31 -0
  416. package/dist/ui/tax.js.map +1 -0
  417. package/dist/ui/ticket-resolve.d.ts +9 -1
  418. package/dist/ui/ticket-resolve.js +13 -2
  419. package/dist/ui/ticket-resolve.js.map +1 -1
  420. package/dist/ui/volume-resolve.js +4 -1
  421. package/dist/ui/volume-resolve.js.map +1 -1
  422. package/dist/ui/wait.d.ts +4 -0
  423. package/dist/ui/wait.js +7 -2
  424. package/dist/ui/wait.js.map +1 -1
  425. package/dist/ui/wizard.d.ts +2 -1
  426. package/dist/ui/wizard.js +1 -1
  427. package/dist/ui/wizard.js.map +1 -1
  428. package/dist/version-check-bin.js +2 -2
  429. package/dist/version-check-bin.js.map +1 -1
  430. package/dist/version-check.d.ts +5 -0
  431. package/dist/version-check.js +6 -1
  432. package/dist/version-check.js.map +1 -1
  433. package/package.json +53 -6
@@ -0,0 +1,912 @@
1
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { existsSync, rmSync, statSync } from "node:fs";
4
+ import { basename, dirname, resolve } from "node:path";
5
+ import { Panel } from "../components/Panel.js";
6
+ import { Menu } from "../components/Menu.js";
7
+ import { StatusBar } from "../components/StatusBar.js";
8
+ import { Tip } from "../components/Tip.js";
9
+ import { Spinner } from "../components/Spinner.js";
10
+ import { InputBar } from "../components/InputBar.js";
11
+ import { CenteredFrame } from "../components/CenteredFrame.js";
12
+ import { BackButton } from "../components/BackButton.js";
13
+ import { useApi, useAppContext } from "../hooks/useApi.js";
14
+ import { useHeader } from "../hooks/useHeader.js";
15
+ import { useMousePause } from "../hooks/useMouse.js";
16
+ import { useRouter } from "../router.js";
17
+ import { colors, statusColor } from "../theme/colors.js";
18
+ import { glyphs } from "../theme/glyphs.js";
19
+ import { deployPresetRef } from "./deployPreset.js";
20
+ import { humanSize, dotenvFiles, makeTarball, pickFrontend, pollBuild, resolveNewRelease, uploadSource, waitForReleaseOutcome, } from "../../apps-support/deploy.js";
21
+ import { ApiError } from "../../api/errors.js";
22
+ import { chargeLine, priceLine } from "../../apps-support/paid-app.js";
23
+ import { isPaidPlan, planCapReason, planLine, toLocationOptions } from "../../apps-support/plans.js";
24
+ import { describePaymentMethod, readBalance } from "../../ui/wizard.js";
25
+ import { waitFor } from "../../ui/wait.js";
26
+ import { portalUrl } from "../../ui/portal.js";
27
+ import { PAYMENT_METHODS_PATH } from "../../ui/payment-gate.js";
28
+ import { truncationNote } from "../../ui/table.js";
29
+ /** The sub-steps of "create a new app" all count as the App step. */
30
+ const NEW_APP_STEPS = new Set([
31
+ "new-app-plan",
32
+ "new-app-region",
33
+ "new-app-price",
34
+ "new-app-pay",
35
+ "new-app-confirm",
36
+ "new-app-order",
37
+ ]);
38
+ const STEP_LABELS = {
39
+ project: "Project",
40
+ app: "App",
41
+ "new-app-plan": "Plan",
42
+ "new-app-region": "Location",
43
+ "new-app-price": "Price",
44
+ "new-app-pay": "Payment",
45
+ "new-app-confirm": "Confirm charge",
46
+ "new-app-order": "Ordering",
47
+ dir: "Directory",
48
+ confirm: "Confirm",
49
+ deploying: "Deploying",
50
+ result: "Done",
51
+ };
52
+ const PROGRESS = ["project", "app", "dir", "confirm", "deploying", "result"];
53
+ const SLUG_RE = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
54
+ function nameCheckMessage(reason) {
55
+ if (reason === "taken")
56
+ return "This name is taken.";
57
+ if (reason === "banned")
58
+ return "This name isn't allowed.";
59
+ if (reason === "invalid_shape")
60
+ return "Use 3–63 lowercase letters, digits and dashes.";
61
+ return "This name is unavailable.";
62
+ }
63
+ /** ACH settles asynchronously, so it can't underwrite instant provisioning
64
+ * (the same exclusion the Order screen applies). */
65
+ function isAch(m) {
66
+ return m.provider === "stripe" && m.card_brand === "us_bank_account";
67
+ }
68
+ export function Deploy() {
69
+ const api = useApi();
70
+ const { config } = useAppContext();
71
+ const { header } = useHeader();
72
+ const { navigate, goBack } = useRouter();
73
+ useMousePause(true);
74
+ const preset = useRef(deployPresetRef.current);
75
+ const fromOrder = useRef(Boolean(deployPresetRef.current?.newApp));
76
+ useEffect(() => {
77
+ deployPresetRef.current = null;
78
+ }, []);
79
+ // A deploy of an existing app (preset appId) skips the project step.
80
+ const [step, setStep] = useState(preset.current?.appId ? "app" : "project");
81
+ const [projects, setProjects] = useState([]);
82
+ const [projectId, setProjectId] = useState(header.projectId ?? null);
83
+ // The App step holds the new-app name input and the existing-app list;
84
+ // Tab moves between them.
85
+ const [appPane, setAppPane] = useState("name");
86
+ const [nameState, setNameState] = useState({ kind: "idle" });
87
+ const [apps, setApps] = useState(null);
88
+ // The server's count: the list is one page of 200 (portal #419).
89
+ const [appsTotal, setAppsTotal] = useState(0);
90
+ const [plans, setPlans] = useState([]);
91
+ const [loadError, setLoadError] = useState(null);
92
+ const [app, setApp] = useState(null);
93
+ const [slug, setSlug] = useState("");
94
+ const [creating, setCreating] = useState(false);
95
+ const [dirInput, setDirInput] = useState(process.cwd());
96
+ const [dir, setDir] = useState(null);
97
+ const [dirError, setDirError] = useState(null);
98
+ const [frontend, setFrontend] = useState("railpack");
99
+ const [linkDir, setLinkDir] = useState(true);
100
+ const [phases, setPhases] = useState([]);
101
+ const [outcome, setOutcome] = useState(null);
102
+ const [error, setError] = useState(null);
103
+ const [order, setOrder] = useState(null);
104
+ // Catalog: the team's apps in the active project, plus plans for "new app".
105
+ useEffect(() => {
106
+ let cancelled = false;
107
+ (async () => {
108
+ try {
109
+ const [appsPage, plansOut, projectsOut] = await Promise.all([
110
+ api.apps.listPage(),
111
+ api.apps.plans().catch(() => []),
112
+ api.projects.list().catch(() => []),
113
+ ]);
114
+ if (cancelled)
115
+ return;
116
+ const list = appsPage.items;
117
+ setApps(list);
118
+ setAppsTotal(appsPage.total);
119
+ setPlans(plansOut);
120
+ setProjects(projectsOut);
121
+ setProjectId((cur) => cur ?? (projectsOut.find((p) => p.is_default) ?? projectsOut[0])?.id ?? null);
122
+ const pre = preset.current;
123
+ if (pre?.newApp) {
124
+ setStep("project");
125
+ }
126
+ else if (pre) {
127
+ const hit = list.find((a) => a.id === pre.appId);
128
+ if (hit) {
129
+ setApp(hit);
130
+ if (pre.dir)
131
+ setDirInput(pre.dir);
132
+ else {
133
+ const linked = linkedDirFor(config.get().links, hit.id);
134
+ if (linked)
135
+ setDirInput(linked);
136
+ }
137
+ setStep("dir");
138
+ }
139
+ }
140
+ }
141
+ catch (e) {
142
+ if (!cancelled)
143
+ setLoadError(e instanceof Error ? e.message : String(e));
144
+ }
145
+ })();
146
+ return () => {
147
+ cancelled = true;
148
+ };
149
+ }, [api, config]);
150
+ // Live slug check while the user types (debounced): the shape rule first,
151
+ // then the server's check-name, so a taken name shows here and not as a
152
+ // refused order after the plan step.
153
+ const nameReq = useRef(0);
154
+ useEffect(() => {
155
+ const name = slug.trim();
156
+ const reqId = ++nameReq.current;
157
+ if (!name) {
158
+ setNameState({ kind: "idle" });
159
+ return;
160
+ }
161
+ if (!SLUG_RE.test(name)) {
162
+ setNameState({ kind: "invalid", msg: "Use 3–63 lowercase letters, digits and dashes." });
163
+ return;
164
+ }
165
+ setNameState({ kind: "checking" });
166
+ const t = setTimeout(() => {
167
+ api.apps
168
+ .checkName(name)
169
+ .then((r) => {
170
+ if (reqId !== nameReq.current)
171
+ return;
172
+ setNameState(r.available ? { kind: "available", hostname: r.hostname } : { kind: "taken", msg: nameCheckMessage(r.reason) });
173
+ })
174
+ .catch((e) => {
175
+ if (reqId !== nameReq.current)
176
+ return;
177
+ setNameState({ kind: "taken", msg: e instanceof Error ? e.message : String(e) });
178
+ });
179
+ }, 300);
180
+ return () => clearTimeout(t);
181
+ }, [slug, api]);
182
+ // When an app is picked, offer the directory it is already linked to.
183
+ const pickApp = useCallback((a) => {
184
+ setApp(a);
185
+ const linked = linkedDirFor(config.get().links, a.id);
186
+ if (linked)
187
+ setDirInput(linked);
188
+ setStep("dir");
189
+ }, [config]);
190
+ const alreadyLinked = useMemo(() => {
191
+ if (!app || !dir)
192
+ return false;
193
+ const link = config.linkFor(dir);
194
+ return !!link && link.app_id === app.id;
195
+ }, [app, dir, config]);
196
+ const confirmDir = useCallback((raw) => {
197
+ const path = resolve(raw.trim() || ".");
198
+ if (!existsSync(path) || !statSync(path).isDirectory()) {
199
+ setDirError(`Not a directory: ${path}`);
200
+ return;
201
+ }
202
+ setDirError(null);
203
+ setDir(path);
204
+ setFrontend(pickFrontend(path));
205
+ setStep("confirm");
206
+ }, []);
207
+ // The deploy itself — runs once when the confirm step hands over.
208
+ useEffect(() => {
209
+ if (step !== "deploying" || !app || !dir)
210
+ return;
211
+ let cancelled = false;
212
+ const started = Date.now();
213
+ const initial = [
214
+ { label: "Pack source", state: "active" },
215
+ { label: "Upload", state: "pending" },
216
+ { label: "Build", state: "pending" },
217
+ { label: "Release", state: "pending" },
218
+ ];
219
+ setPhases(initial);
220
+ const mark = (i, patch) => setPhases((ps) => ps.map((p, j) => (j === i ? { ...p, ...patch } : p)));
221
+ (async () => {
222
+ try {
223
+ const archive = await makeTarball(dir);
224
+ let build;
225
+ try {
226
+ if (cancelled)
227
+ return;
228
+ const dotenv = dotenvFiles(dir);
229
+ mark(0, {
230
+ state: "done",
231
+ detail: `${basename(dir)} → ${humanSize(archive)}` +
232
+ (dotenv.length ? ` (not packed: ${dotenv.join(", ")} — set variables in the Environment tab)` : ""),
233
+ });
234
+ mark(1, { state: "active", detail: "0%" });
235
+ // The orchestrator decides Dockerfile vs Railpack from what it finds
236
+ // in the source now — the client no longer sends a frontend hint.
237
+ // Shared with `synteq deploy --dir` (apps-support/deploy.ts) so the
238
+ // two surfaces can't diverge on retry/fallback behaviour.
239
+ build = await uploadSource(api, app.id, archive, {
240
+ onProgress: (pct) => mark(1, { detail: `${pct}%` }),
241
+ });
242
+ }
243
+ finally {
244
+ // The pack is a full copy of the source (an un-ignored .env included)
245
+ // in a shared tmpdir — gone once the upload settles, either way.
246
+ rmSync(dirname(archive), { recursive: true, force: true });
247
+ }
248
+ if (cancelled)
249
+ return;
250
+ mark(1, { state: "done", detail: `build ${build.id.slice(0, 8)} · ${frontend}` });
251
+ mark(2, { state: "active", detail: build.status });
252
+ const final = await pollBuild(api, app.id, build, {
253
+ intervalMs: 4000,
254
+ // A large source can sit in its first status for several minutes
255
+ // while the API prepares it in the background (202 + poll) — a
256
+ // deadline under 30 minutes can cut off a still-running deploy.
257
+ timeoutMs: 1_800_000,
258
+ onStatus: (s) => mark(2, { detail: s }),
259
+ });
260
+ if (cancelled)
261
+ return;
262
+ if (final.status !== "succeeded") {
263
+ mark(2, { state: "failed", detail: final.status });
264
+ setOutcome({
265
+ ok: false,
266
+ error: final.status === "failed"
267
+ ? [
268
+ "The build failed.",
269
+ final.failureReason ?? null,
270
+ "The Deployments tab in the portal carries the build log.",
271
+ ]
272
+ .filter(Boolean)
273
+ .join(" ")
274
+ : `The build is still ${final.status} after 30 minutes; it may still finish server-side.`,
275
+ buildId: final.id,
276
+ });
277
+ setStep("result");
278
+ return;
279
+ }
280
+ mark(2, { state: "done", detail: "succeeded" });
281
+ mark(3, { state: "active", detail: "waiting for the release" });
282
+ const release = await resolveNewRelease(api, app.id, final);
283
+ if (cancelled)
284
+ return;
285
+ const status = release
286
+ ? await waitForReleaseOutcome(api, app.id, release.number, 180, (s) => mark(3, { detail: `#${release.number} ${s ?? "pending"}` }))
287
+ : null;
288
+ if (cancelled)
289
+ return;
290
+ const live = !release || status === "live";
291
+ mark(3, { state: live ? "done" : "failed", detail: release ? `#${release.number} ${status ?? "still rolling out"}` : "no release yet" });
292
+ let linked = false;
293
+ if (live && linkDir && !alreadyLinked) {
294
+ config.setLink(dir, {
295
+ team_id: app.teamId,
296
+ project_id: app.projectId,
297
+ app_id: app.id,
298
+ app_slug: app.slug,
299
+ linked_at: new Date().toISOString(),
300
+ kind: "app",
301
+ });
302
+ linked = true;
303
+ }
304
+ if (live) {
305
+ setOutcome({
306
+ ok: true,
307
+ release: release?.number ?? null,
308
+ url: `https://${app.hostname}`,
309
+ durationMs: Date.now() - started,
310
+ linked,
311
+ });
312
+ }
313
+ else {
314
+ setOutcome({
315
+ ok: false,
316
+ error: status === "start_failed" || status === "health_failed"
317
+ ? `Release #${release?.number} ${status.replace("_", " ")}. The previous release keeps serving.`
318
+ : `Release #${release?.number} is ${status ?? "still rolling out"}.`,
319
+ });
320
+ }
321
+ setStep("result");
322
+ }
323
+ catch (e) {
324
+ if (cancelled)
325
+ return;
326
+ setPhases((ps) => ps.map((p) => (p.state === "active" ? { ...p, state: "failed" } : p)));
327
+ setOutcome({ ok: false, error: e instanceof Error ? e.message : String(e) });
328
+ setStep("result");
329
+ }
330
+ })();
331
+ return () => {
332
+ cancelled = true;
333
+ };
334
+ // eslint-disable-next-line react-hooks/exhaustive-deps
335
+ }, [step]);
336
+ const createApp = useCallback(async (planTier) => {
337
+ setCreating(true);
338
+ setError(null);
339
+ try {
340
+ const created = await api.apps.create({ slug: slug.trim(), ...(planTier ? { planTier } : {}) }, projectId ?? undefined);
341
+ setApps((list) => [created, ...(list ?? [])]);
342
+ setApp(created);
343
+ setStep("dir");
344
+ }
345
+ catch (e) {
346
+ setError(e instanceof Error ? e.message : String(e));
347
+ setStep("app");
348
+ }
349
+ finally {
350
+ setCreating(false);
351
+ }
352
+ }, [api, slug, projectId]);
353
+ const patchOrder = useCallback((patch) => setOrder((o) => (o ? { ...o, ...patch } : o)), []);
354
+ // A paid tier is an ORDER, not a bare create (POST /apps refuses it with
355
+ // 402): walk the same steps `orderPaidApp` runs — location, price, credits,
356
+ // card, confirm, charge — one ink step each. Nothing charges before the
357
+ // confirm step's Enter.
358
+ const pickPlan = useCallback(async (planName) => {
359
+ const plan = plans.find((p) => p.name === planName);
360
+ if (!plan || !isPaidPlan(plan)) {
361
+ await createApp(planName);
362
+ return;
363
+ }
364
+ setError(null);
365
+ setCreating(true);
366
+ try {
367
+ const locations = toLocationOptions(await api.apps.locations());
368
+ if (locations.length === 0) {
369
+ setError("No locations are available for new apps right now. Try again later.");
370
+ return;
371
+ }
372
+ const next = {
373
+ plan,
374
+ region: locations.length === 1 ? locations[0].region : null,
375
+ locations,
376
+ quote: null,
377
+ credit: 0,
378
+ applyCredits: false,
379
+ methods: null,
380
+ methodId: null,
381
+ status: null,
382
+ };
383
+ setOrder(next);
384
+ setStep(next.region ? "new-app-price" : "new-app-region");
385
+ }
386
+ catch (e) {
387
+ setError(e instanceof Error ? e.message : String(e));
388
+ }
389
+ finally {
390
+ setCreating(false);
391
+ }
392
+ }, [api, plans, createApp]);
393
+ const orderSpec = useMemo(() => order?.region
394
+ ? { slug: slug.trim(), plan_tier: order.plan.name, region: order.region, project_id: projectId ?? undefined }
395
+ : null, [order?.plan.name, order?.region, slug, projectId]);
396
+ // Price step: the first-month quote (tax included) and the credit balance.
397
+ // A preview the API REFUSED (4xx other than 429) is not a degraded quote —
398
+ // the order would be refused the same way — so it goes back to the plan.
399
+ useEffect(() => {
400
+ if (step !== "new-app-price" || !order || !orderSpec || order.quote)
401
+ return;
402
+ let cancelled = false;
403
+ (async () => {
404
+ let quote;
405
+ try {
406
+ const q = await api.orders.preview({ kind: "app", spec: orderSpec });
407
+ quote = {
408
+ total: Number(q.total),
409
+ taxTotal: Number(q.tax_total ?? 0),
410
+ taxLabel: q.tax_label ?? "tax",
411
+ currency: q.currency ?? "USD",
412
+ degraded: Boolean(q.estimate_degraded),
413
+ };
414
+ }
415
+ catch (e) {
416
+ if (cancelled)
417
+ return;
418
+ if (e instanceof ApiError && e.status >= 400 && e.status < 500 && e.status !== 429) {
419
+ setError(`Can't order ${order.plan.displayName ?? order.plan.name}: ${e.detail}`);
420
+ setOrder(null);
421
+ setStep("new-app-plan");
422
+ return;
423
+ }
424
+ quote = { total: Number(order.plan.monthlyAnchorUsd ?? 0), taxTotal: 0, taxLabel: "tax", currency: "USD", degraded: true };
425
+ }
426
+ const balance = await api.billing.balance().catch(() => ({}));
427
+ if (cancelled)
428
+ return;
429
+ const credit = readBalance(balance.credit);
430
+ patchOrder({ quote, credit });
431
+ // No credit to ask about: straight on to the card.
432
+ if (credit <= 0)
433
+ setStep("new-app-pay");
434
+ })();
435
+ return () => {
436
+ cancelled = true;
437
+ };
438
+ // eslint-disable-next-line react-hooks/exhaustive-deps
439
+ }, [step, orderSpec]);
440
+ // Credits-first decided: credit that covers the whole month skips the card.
441
+ const decideCredits = useCallback((apply) => {
442
+ if (!order?.quote)
443
+ return;
444
+ patchOrder({ applyCredits: apply });
445
+ const covered = apply && order.credit >= order.quote.total && order.quote.total > 0;
446
+ setStep(covered ? "new-app-confirm" : "new-app-pay");
447
+ }, [order, patchOrder]);
448
+ // Payment step: the methods the app_order touchpoint may charge.
449
+ const loadMethods = useCallback(async () => {
450
+ patchOrder({ methods: null });
451
+ const rows = await api.payments.methodsForTouchpoint("app_order").catch(() => []);
452
+ patchOrder({ methods: rows.filter((m) => !isAch(m)) });
453
+ }, [api, patchOrder]);
454
+ useEffect(() => {
455
+ if (step !== "new-app-pay" || !order || order.methods)
456
+ return;
457
+ void loadMethods();
458
+ // eslint-disable-next-line react-hooks/exhaustive-deps
459
+ }, [step]);
460
+ const coveredByCredit = !!order?.quote && order.applyCredits && order.credit >= order.quote.total && order.quote.total > 0;
461
+ const chosenMethod = order?.methods?.find((m) => m.id === order.methodId) ?? null;
462
+ // Order step: charge, then poll the order until the app row exists.
463
+ useEffect(() => {
464
+ if (step !== "new-app-order" || !order?.quote || !orderSpec)
465
+ return;
466
+ let cancelled = false;
467
+ (async () => {
468
+ try {
469
+ const payment = coveredByCredit
470
+ ? { method: "credit_only" }
471
+ : { method: "saved", payment_method_id: order.methodId, apply_credits: order.applyCredits && order.credit > 0 };
472
+ patchOrder({ status: "charging" });
473
+ const result = await api.orders.createApp(orderSpec, payment);
474
+ if (cancelled)
475
+ return;
476
+ if (result.checkout_url)
477
+ throw new Error(`This order needs hosted checkout: ${result.checkout_url}`);
478
+ if (result.status === "failed")
479
+ throw new Error("The charge did not go through; no app created.");
480
+ const wait = await waitFor({
481
+ timeoutSeconds: 120,
482
+ poll: () => api.orders.status(result.order_id),
483
+ classify: (o) => {
484
+ const st = (o.status ?? "").toLowerCase();
485
+ if ((st === "complete" || st === "provisioned") && o.resource_id)
486
+ return { state: "success", label: `order ${st}` };
487
+ if (st === "failed" || st === "cancelled") {
488
+ return { state: "failure", label: `order ${st}`, reason: `Order ${st}: ${o.error_detail ?? "no detail from server"}` };
489
+ }
490
+ return { state: "pending", label: `order ${st || "pending"}` };
491
+ },
492
+ onStatus: (l) => patchOrder({ status: l }),
493
+ });
494
+ if (cancelled)
495
+ return;
496
+ if (wait.outcome === "timeout") {
497
+ throw new Error(`Charged, but the app is still being created (order ${result.order_id}). It will appear in Resources shortly.`);
498
+ }
499
+ if (wait.outcome === "failure")
500
+ throw new Error(wait.reason);
501
+ const created = await api.apps.get(wait.value.resource_id);
502
+ if (cancelled)
503
+ return;
504
+ setApps((list) => [created, ...(list ?? [])]);
505
+ setApp(created);
506
+ setOrder(null);
507
+ setStep("dir");
508
+ }
509
+ catch (e) {
510
+ if (cancelled)
511
+ return;
512
+ setError(e instanceof Error ? e.message : String(e));
513
+ setOrder(null);
514
+ setStep("new-app-plan");
515
+ }
516
+ })();
517
+ return () => {
518
+ cancelled = true;
519
+ };
520
+ // eslint-disable-next-line react-hooks/exhaustive-deps
521
+ }, [step]);
522
+ const textOwnsKeys = (step === "app" && appPane === "name") || step === "dir";
523
+ useInput((input, key) => {
524
+ if (step === "app" && key.tab) {
525
+ setAppPane((p) => (p === "name" ? "list" : "name"));
526
+ return;
527
+ }
528
+ // Down from the name input lands on the list (Up from its first row comes back).
529
+ if (step === "app" && appPane === "name" && key.downArrow && appItems.length) {
530
+ setAppPane("list");
531
+ return;
532
+ }
533
+ if (textOwnsKeys) {
534
+ if (key.escape) {
535
+ if (step === "app") {
536
+ // Entered from New order → App or the dashboard: Esc leaves the walkthrough.
537
+ if (fromOrder.current || projects.length === 0)
538
+ goBack();
539
+ else
540
+ setStep("project");
541
+ }
542
+ else
543
+ setStep("app");
544
+ }
545
+ return;
546
+ }
547
+ if (step === "deploying")
548
+ return; // the build continues server-side either way
549
+ if (key.escape) {
550
+ if (step === "project" || step === "result")
551
+ goBack();
552
+ else if (step === "app") {
553
+ if (fromOrder.current || projects.length === 0)
554
+ goBack();
555
+ else
556
+ setStep("project");
557
+ }
558
+ else if (step === "new-app-plan")
559
+ setStep("app");
560
+ else if (step === "new-app-region" || step === "new-app-price") {
561
+ setOrder(null);
562
+ setStep("new-app-plan");
563
+ }
564
+ else if (step === "new-app-pay")
565
+ setStep("new-app-price");
566
+ else if (step === "new-app-confirm")
567
+ setStep(coveredByCredit ? "new-app-price" : "new-app-pay");
568
+ else if (step === "confirm")
569
+ setStep("dir");
570
+ return;
571
+ }
572
+ if (step === "new-app-order")
573
+ return; // the charge is in flight
574
+ if (step === "new-app-price") {
575
+ if (!order?.quote || order.credit <= 0)
576
+ return;
577
+ if (input === "y" || key.return)
578
+ decideCredits(true);
579
+ else if (input === "n")
580
+ decideCredits(false);
581
+ return;
582
+ }
583
+ if (step === "new-app-pay") {
584
+ if (input === "r")
585
+ void loadMethods();
586
+ return;
587
+ }
588
+ if (step === "new-app-confirm") {
589
+ if (key.return)
590
+ setStep("new-app-order");
591
+ return;
592
+ }
593
+ if (step === "confirm") {
594
+ if (key.return)
595
+ setStep("deploying");
596
+ else if (input === "f")
597
+ setFrontend((f) => (f === "dockerfile" ? "railpack" : "dockerfile"));
598
+ else if (input === "l" && !alreadyLinked)
599
+ setLinkDir((v) => !v);
600
+ return;
601
+ }
602
+ if (step === "result") {
603
+ if (input === "d") {
604
+ setOutcome(null);
605
+ setStep("confirm");
606
+ }
607
+ else if (input === "a" && app) {
608
+ navigate("resources");
609
+ }
610
+ else if (key.return)
611
+ goBack();
612
+ }
613
+ }, { isActive: true });
614
+ const stepIndex = Math.max(0, PROGRESS.indexOf(NEW_APP_STEPS.has(step) ? "app" : step));
615
+ const totalRows = process.stdout.rows ?? 24;
616
+ const paneHeight = Math.max(12, totalRows - 6);
617
+ const projectItems = useMemo(() => projects.map((p) => ({ value: p.id, label: p.name, hint: p.is_default ? "default" : (p.description ?? undefined) })), [projects]);
618
+ // Existing apps in the chosen project; "new app" is the input above the list.
619
+ const appItems = useMemo(() => (apps ?? [])
620
+ .filter((a) => !projectId || a.projectId === projectId)
621
+ .map((a) => ({ value: a.id, label: a.slug, hint: `${a.hostname} · ${a.planTier} · ${a.status}` })), [apps, projectId]);
622
+ const submitNewApp = useCallback((v) => {
623
+ const name = v.trim();
624
+ if (!SLUG_RE.test(name)) {
625
+ setError("Use 3–63 lowercase letters, digits and dashes.");
626
+ return;
627
+ }
628
+ if (nameState.kind !== "available")
629
+ return; // still checking, or taken
630
+ setError(null);
631
+ setStep("new-app-plan");
632
+ }, [nameState.kind]);
633
+ const planItems = useMemo(() => plans.length
634
+ ? plans.map((p) => ({
635
+ value: p.name,
636
+ label: p.displayName ?? p.name,
637
+ hint: planLine(p),
638
+ // At the per-team cap (or no capacity): shown, not pickable —
639
+ // the same rule the CLI picker applies.
640
+ disabled: planCapReason(p),
641
+ }))
642
+ : [{ value: "", label: "Default plan", hint: "the platform's default tier" }], [plans]);
643
+ const regionItems = useMemo(() => (order?.locations ?? []).map((l) => ({ value: l.region, label: l.city, hint: l.code })), [order?.locations]);
644
+ const methodItems = useMemo(() => (order?.methods ?? []).map((m) => ({
645
+ value: m.id,
646
+ label: describePaymentMethod(m),
647
+ disabled: m.eligible ? undefined : (m.ineligible_reason ?? "not allowed for apps"),
648
+ })), [order?.methods]);
649
+ const eligibleMethods = (order?.methods ?? []).filter((m) => m.eligible);
650
+ let body;
651
+ if (loadError) {
652
+ body = React.createElement(Text, { color: colors.error },
653
+ "Error: ",
654
+ loadError);
655
+ }
656
+ else if (apps === null) {
657
+ body = React.createElement(Spinner, { label: "Loading your apps\u2026" });
658
+ }
659
+ else if (step === "project") {
660
+ body = projects.length === 0 ? (React.createElement(Box, { flexDirection: "column" },
661
+ React.createElement(Text, { color: colors.error }, "You need at least one project. Create one in the portal and try again."),
662
+ React.createElement(Box, { marginTop: 1 },
663
+ React.createElement(Text, { color: colors.dim }, "Esc to go back.")))) : (React.createElement(Box, { flexDirection: "column" },
664
+ React.createElement(Text, { color: colors.dim }, "Which project is the app in?"),
665
+ React.createElement(Box, { marginTop: 1 },
666
+ React.createElement(Menu, { items: projectItems, initialIndex: Math.max(0, projectItems.findIndex((i) => i.value === projectId)), focused: true, onSelect: (v) => {
667
+ setProjectId(v);
668
+ setAppPane("name");
669
+ setStep("app");
670
+ } }))));
671
+ }
672
+ else if (step === "app") {
673
+ const nameLine = nameState.kind === "checking" ? React.createElement(Text, { color: colors.dim }, "checking\u2026")
674
+ : nameState.kind === "available" ? React.createElement(Text, { color: colors.success }, `available${nameState.hostname ? ` · ${nameState.hostname}` : ""}`)
675
+ : nameState.kind === "invalid" || nameState.kind === "taken" ? React.createElement(Text, { color: colors.error }, nameState.msg)
676
+ : React.createElement(Text, { color: colors.dim }, "lowercase letters, digits and dashes \u2014 it becomes the hostname");
677
+ body = (React.createElement(Box, { flexDirection: "column" },
678
+ React.createElement(Text, { color: colors.dim }, "Name a new app, or pick an existing one below (\u2193 / Tab to move between them)."),
679
+ error ? React.createElement(Text, { color: colors.error }, error) : null,
680
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
681
+ React.createElement(Text, { color: appPane === "name" ? colors.accent : colors.dim }, "New app"),
682
+ React.createElement(InputBar, { value: slug, onChange: setSlug, onSubmit: submitNewApp, placeholder: "my-api", focused: appPane === "name" }),
683
+ React.createElement(Box, { paddingX: 4 }, nameLine)),
684
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
685
+ React.createElement(Text, { color: appPane === "list" ? colors.accent : colors.dim }, appItems.length ? "Existing apps" : "No apps in this project yet"),
686
+ appItems.length ? (React.createElement(Menu, { items: appItems, focused: appPane === "list", onUpFromTop: () => setAppPane("name"), onSelect: (v) => {
687
+ const hit = apps.find((a) => a.id === v);
688
+ if (hit)
689
+ pickApp(hit);
690
+ } })) : null,
691
+ truncationNote(apps?.length ?? 0, appsTotal, "`synteq link --app <slug>`") ? (React.createElement(Text, { color: colors.dim }, truncationNote(apps?.length ?? 0, appsTotal, "`synteq link --app <slug>`"))) : null)));
692
+ }
693
+ else if (step === "new-app-plan") {
694
+ body = creating ? (React.createElement(Spinner, { label: `Creating ${slug}…` })) : (React.createElement(Box, { flexDirection: "column" },
695
+ React.createElement(Text, { color: colors.dim },
696
+ "Pick a plan for ",
697
+ slug,
698
+ ". A paid plan charges its first month now."),
699
+ error ? React.createElement(Text, { color: colors.error }, error) : null,
700
+ React.createElement(Box, { marginTop: 1 },
701
+ React.createElement(Menu, { items: planItems, focused: true, onSelect: (v) => void pickPlan(v || null) }))));
702
+ }
703
+ else if (step === "new-app-region" && order) {
704
+ body = (React.createElement(Box, { flexDirection: "column" },
705
+ React.createElement(Text, { color: colors.dim },
706
+ "Where should ",
707
+ slug,
708
+ " run?"),
709
+ React.createElement(Box, { marginTop: 1 },
710
+ React.createElement(Menu, { items: regionItems, focused: true, onSelect: (region) => {
711
+ patchOrder({ region });
712
+ setStep("new-app-price");
713
+ } }))));
714
+ }
715
+ else if (step === "new-app-price" && order) {
716
+ body = !order.quote ? (React.createElement(Spinner, { label: "Pricing the first month\u2026" })) : (React.createElement(Box, { flexDirection: "column" },
717
+ React.createElement(Text, { color: colors.text }, priceLine({ ...order.quote, slug: slug.trim(), planName: order.plan.displayName ?? order.plan.name })),
718
+ order.credit > 0 ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" },
719
+ React.createElement(Text, { color: colors.text },
720
+ "Apply your credit balance ($",
721
+ order.credit.toFixed(2),
722
+ ") first?"),
723
+ React.createElement(Text, { color: colors.dim }, "y / Enter yes \u00B7 n no \u00B7 Esc back"))) : null));
724
+ }
725
+ else if (step === "new-app-pay" && order) {
726
+ body = !order.methods ? (React.createElement(Spinner, { label: "Loading payment methods\u2026" })) : eligibleMethods.length === 0 ? (React.createElement(Box, { flexDirection: "column" },
727
+ React.createElement(Text, { color: colors.text }, "No saved payment method can be charged for an app."),
728
+ order.methods.map((m) => m.ineligible_reason).filter(Boolean)[0] ? (React.createElement(Text, { color: colors.dim }, order.methods.map((m) => m.ineligible_reason).filter(Boolean)[0])) : null,
729
+ React.createElement(Box, { marginTop: 1, flexDirection: "column" },
730
+ React.createElement(Text, { color: colors.dim },
731
+ "Add a card in the portal: ",
732
+ React.createElement(Text, { color: colors.text }, portalUrl(config.get().api_base_url, PAYMENT_METHODS_PATH))),
733
+ React.createElement(Text, { color: colors.dim }, "r re-check \u00B7 Esc back")))) : (React.createElement(Box, { flexDirection: "column" },
734
+ React.createElement(Text, { color: colors.dim }, "Charge which payment method?"),
735
+ React.createElement(Box, { marginTop: 1 },
736
+ React.createElement(Menu, { items: methodItems, focused: true, onSelect: (methodId) => {
737
+ patchOrder({ methodId });
738
+ setStep("new-app-confirm");
739
+ } }))));
740
+ }
741
+ else if (step === "new-app-confirm" && order?.quote) {
742
+ body = (React.createElement(Box, { flexDirection: "column" },
743
+ React.createElement(Text, { color: colors.text }, chargeLine({
744
+ ...order.quote,
745
+ slug: slug.trim(),
746
+ planName: order.plan.displayName ?? order.plan.name,
747
+ method: chosenMethod ?? undefined,
748
+ creditsApplied: order.applyCredits ? Math.min(order.credit, order.quote.total) : 0,
749
+ })),
750
+ order.quote.degraded ? (React.createElement(Text, { color: colors.dim }, "Tax estimate unavailable; the final total is on the invoice.")) : null,
751
+ React.createElement(Box, { marginTop: 1 },
752
+ React.createElement(Text, { color: colors.dim }, "Enter charges and creates the app \u00B7 Esc back"))));
753
+ }
754
+ else if (step === "new-app-order" && order) {
755
+ body = React.createElement(Spinner, { label: `Charging and creating ${slug.trim()}… ${order.status ?? ""}` });
756
+ }
757
+ else if (step === "dir") {
758
+ body = (React.createElement(Box, { flexDirection: "column" },
759
+ React.createElement(Text, { color: colors.dim },
760
+ "Directory to build and ship to ",
761
+ React.createElement(Text, { color: colors.text }, app?.slug),
762
+ ". Enter keeps the path shown."),
763
+ dirError ? React.createElement(Text, { color: colors.error }, dirError) : null,
764
+ React.createElement(Box, { marginTop: 1 },
765
+ React.createElement(InputBar, { value: dirInput, onChange: setDirInput, onSubmit: confirmDir, placeholder: process.cwd(), focused: true }))));
766
+ }
767
+ else if (step === "confirm" && app && dir) {
768
+ body = (React.createElement(Box, { flexDirection: "column" },
769
+ React.createElement(Row, { label: "App", value: `${app.slug} ${colorless(app.status)}` }),
770
+ React.createElement(Row, { label: "URL", value: `https://${app.hostname}` }),
771
+ React.createElement(Row, { label: "Directory", value: dir }),
772
+ React.createElement(Row, { label: "Builder", value: frontend === "dockerfile" ? "Dockerfile (found in the directory)" : "railpack (zero-config; no Dockerfile found)" }),
773
+ React.createElement(Row, { label: "Link directory", value: alreadyLinked ? "already linked to this app" : linkDir ? "yes — a bare `synteq deploy` here will target this app" : "no" }),
774
+ React.createElement(Box, { marginTop: 1 },
775
+ React.createElement(Text, { color: colors.dim },
776
+ "Enter to deploy \u00B7 f toggle builder",
777
+ alreadyLinked ? "" : " · l toggle link",
778
+ " \u00B7 Esc back"))));
779
+ }
780
+ else if (step === "deploying") {
781
+ body = (React.createElement(Box, { flexDirection: "column" },
782
+ phases.map((p) => (React.createElement(Box, { key: p.label },
783
+ React.createElement(Box, { width: 3 },
784
+ React.createElement(Text, { color: phaseColor(p.state) }, phaseGlyph(p.state))),
785
+ React.createElement(Box, { width: 16 },
786
+ React.createElement(Text, { color: p.state === "pending" ? colors.dim : colors.text }, p.label)),
787
+ React.createElement(Text, { color: colors.dim }, p.detail ?? "")))),
788
+ React.createElement(Box, { marginTop: 1 },
789
+ React.createElement(Spinner, { label: "Working\u2026" }))));
790
+ }
791
+ else if (step === "result" && outcome) {
792
+ body = outcome.ok ? (React.createElement(Box, { flexDirection: "column" },
793
+ React.createElement(Text, { color: colors.success },
794
+ glyphs.check,
795
+ " Deployed ",
796
+ app?.slug,
797
+ outcome.release !== null ? ` · release #${outcome.release}` : "",
798
+ outcome.durationMs !== null ? ` · ${Math.round(outcome.durationMs / 1000)}s` : ""),
799
+ React.createElement(Box, { marginTop: 1 },
800
+ React.createElement(Row, { label: "URL", value: outcome.url })),
801
+ outcome.linked ? (React.createElement(Text, { color: colors.dim },
802
+ "Linked ",
803
+ dir,
804
+ " \u2192 ",
805
+ app?.slug,
806
+ ". `synteq deploy` from that directory targets it now.")) : null,
807
+ React.createElement(Box, { marginTop: 1 },
808
+ React.createElement(Text, { color: colors.dim }, "d deploy again \u00B7 a open Resources (logs, metrics, env) \u00B7 Enter back")))) : (React.createElement(Box, { flexDirection: "column" },
809
+ React.createElement(Text, { color: colors.error }, "Deploy did not go live."),
810
+ React.createElement(Box, { marginTop: 1 },
811
+ React.createElement(Text, { color: colors.text }, outcome.error)),
812
+ phases.length ? (React.createElement(Box, { marginTop: 1, flexDirection: "column" }, phases.map((p) => (React.createElement(Box, { key: p.label },
813
+ React.createElement(Box, { width: 3 },
814
+ React.createElement(Text, { color: phaseColor(p.state) }, phaseGlyph(p.state))),
815
+ React.createElement(Box, { width: 16 },
816
+ React.createElement(Text, { color: colors.dim }, p.label)),
817
+ React.createElement(Text, { color: colors.dim }, p.detail ?? "")))))) : null,
818
+ React.createElement(Box, { marginTop: 1 },
819
+ React.createElement(Text, { color: colors.dim }, "d try again \u00B7 Enter back"))));
820
+ }
821
+ else {
822
+ body = React.createElement(Spinner, { label: "\u2026" });
823
+ }
824
+ return (React.createElement(CenteredFrame, { fullHeight: true, maxWidth: 120 },
825
+ React.createElement(Box, { paddingX: 2, paddingY: 0, height: 2, alignItems: "center" },
826
+ React.createElement(BackButton, { onBack: () => {
827
+ if (step === "deploying")
828
+ return;
829
+ if (step === "app" || step === "result")
830
+ goBack();
831
+ else if (step === "confirm")
832
+ setStep("dir");
833
+ else if (step === "new-app-order")
834
+ return;
835
+ else {
836
+ setOrder(null);
837
+ setStep("app");
838
+ }
839
+ } }),
840
+ React.createElement(Text, { color: colors.dim },
841
+ " · ",
842
+ React.createElement(Text, { color: colors.text }, "Deploy"),
843
+ app ? React.createElement(Text, { color: colors.dim }, ` · ${app.slug}`) : null)),
844
+ React.createElement(Box, { flexGrow: 1, flexDirection: "column", paddingX: 1 },
845
+ React.createElement(Panel, { title: STEP_LABELS[step], rightLabel: `step ${stepIndex + 1} of ${PROGRESS.length}`, paddingX: 2, paddingY: 1, height: paneHeight, borderColor: colors.accent }, body)),
846
+ React.createElement(Box, { flexDirection: "column" },
847
+ React.createElement(Tip, null, step === "project"
848
+ ? "↑↓ pick a project · Enter · Esc back."
849
+ : step === "app"
850
+ ? "Type a name · Enter when it reads available · Tab to the app list · Esc back."
851
+ : step === "dir"
852
+ ? "Type a path · Enter to continue · Esc to pick another app."
853
+ : step === "confirm"
854
+ ? "Enter deploys · f switches Dockerfile / railpack · Esc back."
855
+ : step === "deploying"
856
+ ? "The build runs server-side; you can leave and it keeps going."
857
+ : step === "result"
858
+ ? "d to deploy again · Enter to go back."
859
+ : step === "new-app-plan"
860
+ ? "↑↓ pick a plan · greyed tiers are at this team's cap · Esc back."
861
+ : step === "new-app-confirm"
862
+ ? "Nothing is charged until you press Enter here."
863
+ : step === "new-app-order"
864
+ ? "Charging the first month and creating the app…"
865
+ : "Enter to continue · Esc back."),
866
+ React.createElement(StatusBar, { left: STEP_LABELS[step], right: [
867
+ header.projectName ? `Project: ${header.projectName}` : "",
868
+ header.teamName ? `Team: ${header.teamName}` : "",
869
+ ].filter(Boolean) }))));
870
+ }
871
+ function Row({ label, value }) {
872
+ return (React.createElement(Box, null,
873
+ React.createElement(Box, { width: 16 },
874
+ React.createElement(Text, { color: colors.dim }, label)),
875
+ React.createElement(Text, { color: colors.text }, value)));
876
+ }
877
+ function colorless(s) {
878
+ return statusColor(s) ? s : s;
879
+ }
880
+ function phaseGlyph(state) {
881
+ switch (state) {
882
+ case "done":
883
+ return glyphs.check;
884
+ case "failed":
885
+ return "✗";
886
+ case "active":
887
+ return glyphs.chevronRight;
888
+ default:
889
+ return "·";
890
+ }
891
+ }
892
+ function phaseColor(state) {
893
+ switch (state) {
894
+ case "done":
895
+ return colors.success;
896
+ case "failed":
897
+ return colors.error;
898
+ case "active":
899
+ return colors.accent;
900
+ default:
901
+ return colors.dim;
902
+ }
903
+ }
904
+ /** The directory this machine has linked to the app, if any. */
905
+ function linkedDirFor(links, appId) {
906
+ for (const [path, link] of Object.entries(links ?? {})) {
907
+ if (link.app_id === appId && (link.kind ?? "app") === "app" && existsSync(path))
908
+ return path;
909
+ }
910
+ return null;
911
+ }
912
+ //# sourceMappingURL=Deploy.js.map