@seamapi/cli 0.18.1 → 0.19.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 (364) hide show
  1. package/README.md +55 -1
  2. package/bin/cli.js +73 -249
  3. package/bin/cli.js.map +1 -1
  4. package/lib/args/coerce.d.ts +28 -0
  5. package/lib/args/coerce.js +131 -0
  6. package/lib/args/coerce.js.map +1 -0
  7. package/lib/{util/cli-args.d.ts → args/parse.d.ts} +12 -15
  8. package/lib/{util/cli-args.js → args/parse.js} +21 -24
  9. package/lib/args/parse.js.map +1 -0
  10. package/lib/args/validate.d.ts +23 -0
  11. package/lib/args/validate.js +42 -0
  12. package/lib/args/validate.js.map +1 -0
  13. package/lib/auth/operations.d.ts +54 -0
  14. package/lib/auth/operations.js +115 -0
  15. package/lib/auth/operations.js.map +1 -0
  16. package/lib/{validate-token.js → auth/validate-token.js} +2 -2
  17. package/lib/auth/validate-token.js.map +1 -0
  18. package/lib/blueprint/cache.d.ts +16 -0
  19. package/lib/blueprint/cache.js +73 -0
  20. package/lib/blueprint/cache.js.map +1 -0
  21. package/lib/blueprint/endpoint.d.ts +14 -0
  22. package/lib/{get-response-key.js → blueprint/endpoint.js} +11 -2
  23. package/lib/blueprint/endpoint.js.map +1 -0
  24. package/lib/blueprint/index.d.ts +12 -0
  25. package/lib/blueprint/index.js +10 -0
  26. package/lib/blueprint/index.js.map +1 -0
  27. package/lib/blueprint/source-npm.d.ts +10 -0
  28. package/lib/{blueprint.js → blueprint/source-npm.js} +20 -74
  29. package/lib/blueprint/source-npm.js.map +1 -0
  30. package/lib/blueprint/source-remote.d.ts +6 -0
  31. package/lib/blueprint/source-remote.js +14 -0
  32. package/lib/blueprint/source-remote.js.map +1 -0
  33. package/lib/commands/api-command.d.ts +8 -0
  34. package/lib/commands/api-command.js +71 -0
  35. package/lib/commands/api-command.js.map +1 -0
  36. package/lib/commands/local/completion.d.ts +18 -0
  37. package/lib/commands/local/completion.js +35 -0
  38. package/lib/commands/local/completion.js.map +1 -0
  39. package/lib/commands/local/config-reveal-location.d.ts +2 -0
  40. package/lib/commands/local/config-reveal-location.js +15 -0
  41. package/lib/commands/local/config-reveal-location.js.map +1 -0
  42. package/lib/commands/local/config-set-fake-server.d.ts +3 -0
  43. package/lib/commands/local/config-set-fake-server.js +20 -0
  44. package/lib/commands/local/config-set-fake-server.js.map +1 -0
  45. package/lib/commands/local/config-use-remote-api-defs.d.ts +2 -0
  46. package/lib/commands/local/config-use-remote-api-defs.js +20 -0
  47. package/lib/commands/local/config-use-remote-api-defs.js.map +1 -0
  48. package/lib/commands/local/health.d.ts +2 -0
  49. package/lib/commands/local/health.js +18 -0
  50. package/lib/commands/local/health.js.map +1 -0
  51. package/lib/commands/local/login.d.ts +2 -0
  52. package/lib/commands/local/login.js +35 -0
  53. package/lib/commands/local/login.js.map +1 -0
  54. package/lib/commands/local/logout.d.ts +2 -0
  55. package/lib/commands/local/logout.js +17 -0
  56. package/lib/commands/local/logout.js.map +1 -0
  57. package/lib/commands/local/select-server.d.ts +2 -0
  58. package/lib/commands/local/select-server.js +27 -0
  59. package/lib/commands/local/select-server.js.map +1 -0
  60. package/lib/commands/local/select-workspace.d.ts +2 -0
  61. package/lib/commands/local/select-workspace.js +22 -0
  62. package/lib/commands/local/select-workspace.js.map +1 -0
  63. package/lib/commands/local/wizard.d.ts +9 -0
  64. package/lib/commands/local/wizard.js +28 -0
  65. package/lib/commands/local/wizard.js.map +1 -0
  66. package/lib/commands/registry.d.ts +54 -0
  67. package/lib/commands/registry.js +64 -0
  68. package/lib/commands/registry.js.map +1 -0
  69. package/lib/{command-spec.d.ts → commands/spec.d.ts} +8 -12
  70. package/lib/{command-spec.js → commands/spec.js} +27 -120
  71. package/lib/commands/spec.js.map +1 -0
  72. package/lib/config/config-store.d.ts +23 -8
  73. package/lib/config/config-store.js +16 -42
  74. package/lib/config/config-store.js.map +1 -1
  75. package/lib/config/index.d.ts +2 -1
  76. package/lib/config/index.js +2 -1
  77. package/lib/config/index.js.map +1 -1
  78. package/lib/config/memory-config-store.d.ts +21 -0
  79. package/lib/config/memory-config-store.js +48 -0
  80. package/lib/config/memory-config-store.js.map +1 -0
  81. package/lib/config/migrate.js +1 -1
  82. package/lib/config/migrate.js.map +1 -1
  83. package/lib/config/values.d.ts +12 -0
  84. package/lib/config/values.js +50 -0
  85. package/lib/config/values.js.map +1 -0
  86. package/lib/context.d.ts +37 -0
  87. package/lib/context.js +31 -0
  88. package/lib/context.js.map +1 -0
  89. package/lib/env.d.ts +5 -0
  90. package/lib/env.js +5 -0
  91. package/lib/env.js.map +1 -1
  92. package/lib/errors.d.ts +31 -0
  93. package/lib/errors.js +58 -0
  94. package/lib/errors.js.map +1 -0
  95. package/lib/http/api.d.ts +37 -0
  96. package/lib/http/api.js +20 -0
  97. package/lib/http/api.js.map +1 -0
  98. package/lib/http/client.d.ts +4 -0
  99. package/lib/{get-seam.js → http/client.js} +16 -17
  100. package/lib/http/client.js.map +1 -0
  101. package/lib/http/follow-ups.d.ts +6 -0
  102. package/lib/http/follow-ups.js +30 -0
  103. package/lib/http/follow-ups.js.map +1 -0
  104. package/lib/http/memory-seam-api.d.ts +22 -0
  105. package/lib/http/memory-seam-api.js +41 -0
  106. package/lib/http/memory-seam-api.js.map +1 -0
  107. package/lib/http/request.d.ts +19 -0
  108. package/lib/http/request.js +39 -0
  109. package/lib/http/request.js.map +1 -0
  110. package/lib/{interact-for-access-code.js → interactions/access-code.js} +4 -4
  111. package/lib/interactions/access-code.js.map +1 -0
  112. package/lib/{interact-for-acs-entrance.js → interactions/acs-entrance.js} +3 -3
  113. package/lib/interactions/acs-entrance.js.map +1 -0
  114. package/lib/{interact-for-acs-system.js → interactions/acs-system.js} +3 -3
  115. package/lib/interactions/acs-system.js.map +1 -0
  116. package/lib/{interact-for-acs-user.js → interactions/acs-user.js} +4 -4
  117. package/lib/interactions/acs-user.js.map +1 -0
  118. package/lib/{interact-for-action-attempt-poll.js → interactions/action-attempt-poll.js} +5 -5
  119. package/lib/interactions/action-attempt-poll.js.map +1 -0
  120. package/lib/{interact-for-array.js → interactions/array.js} +4 -3
  121. package/lib/interactions/array.js.map +1 -0
  122. package/lib/{interact-for-blueprint-object.d.ts → interactions/blueprint-object.d.ts} +3 -2
  123. package/lib/{interact-for-blueprint-object.js → interactions/blueprint-object.js} +49 -20
  124. package/lib/interactions/blueprint-object.js.map +1 -0
  125. package/lib/{interact-for-command-params.d.ts → interactions/command-params.d.ts} +2 -2
  126. package/lib/{interact-for-command-params.js → interactions/command-params.js} +4 -3
  127. package/lib/interactions/command-params.js.map +1 -0
  128. package/lib/interactions/command-selection.d.ts +10 -0
  129. package/lib/{interact-for-command-selection.js → interactions/command-selection.js} +9 -15
  130. package/lib/interactions/command-selection.js.map +1 -0
  131. package/lib/{interact-for-connected-account.js → interactions/connected-account.js} +3 -3
  132. package/lib/interactions/connected-account.js.map +1 -0
  133. package/lib/{interact-for-custom-metadata.js → interactions/custom-metadata.js} +4 -3
  134. package/lib/interactions/custom-metadata.js.map +1 -0
  135. package/lib/{interact-for-device.js → interactions/device.js} +3 -3
  136. package/lib/interactions/device.js.map +1 -0
  137. package/lib/interactions/index.d.ts +19 -0
  138. package/lib/interactions/index.js +20 -0
  139. package/lib/interactions/index.js.map +1 -0
  140. package/lib/{interact-for-login.js → interactions/login.js} +16 -14
  141. package/lib/interactions/login.js.map +1 -0
  142. package/lib/{interact-for-resource.js → interactions/resource.js} +3 -3
  143. package/lib/interactions/resource.js.map +1 -0
  144. package/lib/{interact-for-server-selection.js → interactions/server-selection.js} +10 -13
  145. package/lib/interactions/server-selection.js.map +1 -0
  146. package/lib/{interact-for-timestamp.js → interactions/timestamp.js} +2 -2
  147. package/lib/interactions/timestamp.js.map +1 -0
  148. package/lib/{interact-for-use-remote-api-defs.js → interactions/use-remote-api-defs.js} +5 -6
  149. package/lib/interactions/use-remote-api-defs.js.map +1 -0
  150. package/lib/{interact-for-user-identity.js → interactions/user-identity.js} +3 -3
  151. package/lib/interactions/user-identity.js.map +1 -0
  152. package/lib/{interact-for-workspace-id.js → interactions/workspace-id.js} +11 -10
  153. package/lib/interactions/workspace-id.js.map +1 -0
  154. package/lib/memory-prompt.d.ts +32 -0
  155. package/lib/memory-prompt.js +41 -0
  156. package/lib/memory-prompt.js.map +1 -0
  157. package/lib/output/get-output.d.ts +1 -1
  158. package/lib/output/get-output.js +1 -1
  159. package/lib/output/get-output.js.map +1 -1
  160. package/lib/output/{create-memory-output.d.ts → memory-output.d.ts} +1 -1
  161. package/lib/output/{create-memory-output.js → memory-output.js} +2 -2
  162. package/lib/output/memory-output.js.map +1 -0
  163. package/lib/output/{create-output.d.ts → output.d.ts} +18 -1
  164. package/lib/output/output.js +46 -0
  165. package/lib/output/output.js.map +1 -0
  166. package/lib/output/read-stdin-json.js.map +1 -0
  167. package/lib/output/resolve-output-format.d.ts +1 -1
  168. package/lib/{util → output}/with-loading.js +1 -1
  169. package/lib/output/with-loading.js.map +1 -0
  170. package/lib/prompt.d.ts +101 -0
  171. package/lib/{util/prompt.js → prompt.js} +83 -56
  172. package/lib/prompt.js.map +1 -0
  173. package/lib/{completion → render/completion}/describe.js +1 -2
  174. package/lib/render/completion/describe.js.map +1 -0
  175. package/lib/{completion → render/completion}/index.d.ts +2 -2
  176. package/lib/{completion → render/completion}/index.js +1 -2
  177. package/lib/render/completion/index.js.map +1 -0
  178. package/lib/{completion → render/completion}/render-bash.d.ts +1 -1
  179. package/lib/{completion → render/completion}/render-bash.js +1 -1
  180. package/lib/render/completion/render-bash.js.map +1 -0
  181. package/lib/{completion → render/completion}/render-fish.d.ts +1 -1
  182. package/lib/render/completion/render-fish.js.map +1 -0
  183. package/lib/{completion → render/completion}/render-zsh.d.ts +1 -1
  184. package/lib/{completion → render/completion}/render-zsh.js +1 -1
  185. package/lib/render/completion/render-zsh.js.map +1 -0
  186. package/lib/{render-help.d.ts → render/help.d.ts} +1 -1
  187. package/lib/{render-help.js → render/help.js} +2 -2
  188. package/lib/render/help.js.map +1 -0
  189. package/lib/render/text.d.ts +4 -0
  190. package/lib/render/text.js +16 -0
  191. package/lib/render/text.js.map +1 -0
  192. package/lib/version.d.ts +2 -2
  193. package/lib/version.js +2 -2
  194. package/package.json +4 -3
  195. package/src/bin/cli.ts +91 -332
  196. package/src/lib/args/coerce.ts +164 -0
  197. package/src/lib/{util/cli-args.ts → args/parse.ts} +30 -25
  198. package/src/lib/args/validate.ts +73 -0
  199. package/src/lib/auth/operations.ts +169 -0
  200. package/src/lib/{validate-token.ts → auth/validate-token.ts} +2 -2
  201. package/src/lib/blueprint/cache.ts +97 -0
  202. package/src/lib/{get-response-key.ts → blueprint/endpoint.ts} +17 -3
  203. package/src/lib/blueprint/index.ts +27 -0
  204. package/src/lib/{blueprint.ts → blueprint/source-npm.ts} +27 -99
  205. package/src/lib/blueprint/source-remote.ts +17 -0
  206. package/src/lib/commands/api-command.ts +109 -0
  207. package/src/lib/commands/local/completion.ts +51 -0
  208. package/src/lib/commands/local/config-reveal-location.ts +16 -0
  209. package/src/lib/commands/local/config-set-fake-server.ts +21 -0
  210. package/src/lib/commands/local/config-use-remote-api-defs.ts +23 -0
  211. package/src/lib/commands/local/health.ts +22 -0
  212. package/src/lib/commands/local/login.ts +42 -0
  213. package/src/lib/commands/local/logout.ts +18 -0
  214. package/src/lib/commands/local/select-server.ts +30 -0
  215. package/src/lib/commands/local/select-workspace.ts +25 -0
  216. package/src/lib/commands/local/wizard.ts +31 -0
  217. package/src/lib/commands/registry.ts +127 -0
  218. package/src/lib/{command-spec.ts → commands/spec.ts} +30 -131
  219. package/src/lib/config/config-store.ts +39 -64
  220. package/src/lib/config/index.ts +8 -1
  221. package/src/lib/config/memory-config-store.ts +62 -0
  222. package/src/lib/config/migrate.ts +1 -1
  223. package/src/lib/config/values.ts +72 -0
  224. package/src/lib/context.ts +84 -0
  225. package/src/lib/env.ts +9 -2
  226. package/src/lib/errors.ts +67 -0
  227. package/src/lib/http/api.ts +61 -0
  228. package/src/lib/{get-seam.ts → http/client.ts} +19 -18
  229. package/src/lib/http/follow-ups.ts +42 -0
  230. package/src/lib/http/memory-seam-api.ts +57 -0
  231. package/src/lib/http/request.ts +69 -0
  232. package/src/lib/{interact-for-access-code.ts → interactions/access-code.ts} +4 -3
  233. package/src/lib/{interact-for-acs-entrance.ts → interactions/acs-entrance.ts} +3 -2
  234. package/src/lib/{interact-for-acs-system.ts → interactions/acs-system.ts} +3 -2
  235. package/src/lib/{interact-for-acs-user.ts → interactions/acs-user.ts} +4 -3
  236. package/src/lib/{interact-for-action-attempt-poll.ts → interactions/action-attempt-poll.ts} +4 -4
  237. package/src/lib/{interact-for-array.ts → interactions/array.ts} +3 -3
  238. package/src/lib/{interact-for-blueprint-object.ts → interactions/blueprint-object.ts} +57 -24
  239. package/src/lib/{interact-for-command-params.ts → interactions/command-params.ts} +6 -4
  240. package/src/lib/{interact-for-command-selection.ts → interactions/command-selection.ts} +11 -23
  241. package/src/lib/{interact-for-connected-account.ts → interactions/connected-account.ts} +3 -2
  242. package/src/lib/{interact-for-custom-metadata.ts → interactions/custom-metadata.ts} +3 -7
  243. package/src/lib/{interact-for-device.ts → interactions/device.ts} +3 -2
  244. package/src/lib/interactions/index.ts +19 -0
  245. package/src/lib/{interact-for-login.ts → interactions/login.ts} +16 -13
  246. package/src/lib/{interact-for-resource.ts → interactions/resource.ts} +2 -2
  247. package/src/lib/{interact-for-server-selection.ts → interactions/server-selection.ts} +12 -17
  248. package/src/lib/{interact-for-timestamp.ts → interactions/timestamp.ts} +1 -1
  249. package/src/lib/{interact-for-use-remote-api-defs.ts → interactions/use-remote-api-defs.ts} +4 -5
  250. package/src/lib/{interact-for-user-identity.ts → interactions/user-identity.ts} +3 -2
  251. package/src/lib/{interact-for-workspace-id.ts → interactions/workspace-id.ts} +10 -17
  252. package/src/lib/memory-prompt.ts +89 -0
  253. package/src/lib/output/get-output.ts +1 -1
  254. package/src/lib/output/{create-memory-output.ts → memory-output.ts} +1 -1
  255. package/src/lib/output/{create-output.ts → output.ts} +47 -32
  256. package/src/lib/output/resolve-output-format.ts +1 -1
  257. package/src/lib/{util → output}/with-loading.ts +1 -1
  258. package/src/lib/prompt.ts +306 -0
  259. package/src/lib/{completion → render/completion}/describe.ts +1 -2
  260. package/src/lib/{completion → render/completion}/index.ts +3 -4
  261. package/src/lib/{completion → render/completion}/render-bash.ts +1 -1
  262. package/src/lib/{completion → render/completion}/render-fish.ts +2 -1
  263. package/src/lib/{completion → render/completion}/render-zsh.ts +2 -1
  264. package/src/lib/{render-help.ts → render/help.ts} +1 -1
  265. package/src/lib/render/text.ts +17 -0
  266. package/src/lib/version.ts +2 -2
  267. package/lib/blueprint.d.ts +0 -7
  268. package/lib/blueprint.js.map +0 -1
  269. package/lib/command-spec.js.map +0 -1
  270. package/lib/completion/describe.js.map +0 -1
  271. package/lib/completion/index.js.map +0 -1
  272. package/lib/completion/render-bash.js.map +0 -1
  273. package/lib/completion/render-fish.js.map +0 -1
  274. package/lib/completion/render-zsh.js.map +0 -1
  275. package/lib/get-api-blueprint.d.ts +0 -6
  276. package/lib/get-api-blueprint.js +0 -18
  277. package/lib/get-api-blueprint.js.map +0 -1
  278. package/lib/get-command-blueprint-def.d.ts +0 -2
  279. package/lib/get-command-blueprint-def.js +0 -11
  280. package/lib/get-command-blueprint-def.js.map +0 -1
  281. package/lib/get-credentials.d.ts +0 -15
  282. package/lib/get-credentials.js +0 -35
  283. package/lib/get-credentials.js.map +0 -1
  284. package/lib/get-current-workspace-id.d.ts +0 -1
  285. package/lib/get-current-workspace-id.js +0 -9
  286. package/lib/get-current-workspace-id.js.map +0 -1
  287. package/lib/get-response-key.d.ts +0 -9
  288. package/lib/get-response-key.js.map +0 -1
  289. package/lib/get-seam.d.ts +0 -3
  290. package/lib/get-seam.js.map +0 -1
  291. package/lib/get-server.d.ts +0 -6
  292. package/lib/get-server.js +0 -17
  293. package/lib/get-server.js.map +0 -1
  294. package/lib/interact-for-access-code.js.map +0 -1
  295. package/lib/interact-for-acs-entrance.js.map +0 -1
  296. package/lib/interact-for-acs-system.js.map +0 -1
  297. package/lib/interact-for-acs-user.js.map +0 -1
  298. package/lib/interact-for-action-attempt-poll.js.map +0 -1
  299. package/lib/interact-for-array.js.map +0 -1
  300. package/lib/interact-for-blueprint-object.js.map +0 -1
  301. package/lib/interact-for-command-params.js.map +0 -1
  302. package/lib/interact-for-command-selection.d.ts +0 -2
  303. package/lib/interact-for-command-selection.js.map +0 -1
  304. package/lib/interact-for-connected-account.js.map +0 -1
  305. package/lib/interact-for-custom-metadata.js.map +0 -1
  306. package/lib/interact-for-device.js.map +0 -1
  307. package/lib/interact-for-login.js.map +0 -1
  308. package/lib/interact-for-resource.js.map +0 -1
  309. package/lib/interact-for-server-selection.js.map +0 -1
  310. package/lib/interact-for-timestamp.js.map +0 -1
  311. package/lib/interact-for-use-remote-api-defs.js.map +0 -1
  312. package/lib/interact-for-user-identity.js.map +0 -1
  313. package/lib/interact-for-workspace-id.js.map +0 -1
  314. package/lib/output/create-memory-output.js.map +0 -1
  315. package/lib/output/create-output.js +0 -34
  316. package/lib/output/create-output.js.map +0 -1
  317. package/lib/render-help.js.map +0 -1
  318. package/lib/types.d.ts +0 -6
  319. package/lib/types.js +0 -2
  320. package/lib/types.js.map +0 -1
  321. package/lib/util/cli-args.js.map +0 -1
  322. package/lib/util/ellipsis.d.ts +0 -1
  323. package/lib/util/ellipsis.js +0 -6
  324. package/lib/util/ellipsis.js.map +0 -1
  325. package/lib/util/prompt.d.ts +0 -80
  326. package/lib/util/prompt.js.map +0 -1
  327. package/lib/util/read-stdin-json.js.map +0 -1
  328. package/lib/util/request-seam-api.d.ts +0 -7
  329. package/lib/util/request-seam-api.js +0 -26
  330. package/lib/util/request-seam-api.js.map +0 -1
  331. package/lib/util/with-loading.js.map +0 -1
  332. package/lib/validate-token.js.map +0 -1
  333. package/src/lib/get-api-blueprint.ts +0 -31
  334. package/src/lib/get-command-blueprint-def.ts +0 -15
  335. package/src/lib/get-credentials.ts +0 -38
  336. package/src/lib/get-current-workspace-id.ts +0 -9
  337. package/src/lib/get-server.ts +0 -20
  338. package/src/lib/types.ts +0 -7
  339. package/src/lib/util/ellipsis.ts +0 -4
  340. package/src/lib/util/prompt.ts +0 -229
  341. package/src/lib/util/request-seam-api.ts +0 -47
  342. /package/lib/{validate-token.d.ts → auth/validate-token.d.ts} +0 -0
  343. /package/lib/{interact-for-access-code.d.ts → interactions/access-code.d.ts} +0 -0
  344. /package/lib/{interact-for-acs-entrance.d.ts → interactions/acs-entrance.d.ts} +0 -0
  345. /package/lib/{interact-for-acs-system.d.ts → interactions/acs-system.d.ts} +0 -0
  346. /package/lib/{interact-for-acs-user.d.ts → interactions/acs-user.d.ts} +0 -0
  347. /package/lib/{interact-for-action-attempt-poll.d.ts → interactions/action-attempt-poll.d.ts} +0 -0
  348. /package/lib/{interact-for-array.d.ts → interactions/array.d.ts} +0 -0
  349. /package/lib/{interact-for-connected-account.d.ts → interactions/connected-account.d.ts} +0 -0
  350. /package/lib/{interact-for-custom-metadata.d.ts → interactions/custom-metadata.d.ts} +0 -0
  351. /package/lib/{interact-for-device.d.ts → interactions/device.d.ts} +0 -0
  352. /package/lib/{interact-for-login.d.ts → interactions/login.d.ts} +0 -0
  353. /package/lib/{interact-for-resource.d.ts → interactions/resource.d.ts} +0 -0
  354. /package/lib/{interact-for-server-selection.d.ts → interactions/server-selection.d.ts} +0 -0
  355. /package/lib/{interact-for-timestamp.d.ts → interactions/timestamp.d.ts} +0 -0
  356. /package/lib/{interact-for-use-remote-api-defs.d.ts → interactions/use-remote-api-defs.d.ts} +0 -0
  357. /package/lib/{interact-for-user-identity.d.ts → interactions/user-identity.d.ts} +0 -0
  358. /package/lib/{interact-for-workspace-id.d.ts → interactions/workspace-id.d.ts} +0 -0
  359. /package/lib/{util → output}/read-stdin-json.d.ts +0 -0
  360. /package/lib/{util → output}/read-stdin-json.js +0 -0
  361. /package/lib/{util → output}/with-loading.d.ts +0 -0
  362. /package/lib/{completion → render/completion}/describe.d.ts +0 -0
  363. /package/lib/{completion → render/completion}/render-fish.js +0 -0
  364. /package/src/lib/{util → output}/read-stdin-json.ts +0 -0
@@ -0,0 +1,164 @@
1
+ import type { Parameter } from '@seamapi/blueprint'
2
+
3
+ /** An argument whose value does not fit the parameter's documented format. */
4
+ export interface CoercionIssue {
5
+ name: string
6
+ given: unknown
7
+ /** What the parameter takes, e.g., `a number`. */
8
+ expected: string
9
+ }
10
+
11
+ type Coerced = { value: unknown } | { issue: string }
12
+
13
+ /**
14
+ * Read each argument as the JSON value its parameter documents: booleans and
15
+ * numbers become real booleans and numbers, lists split on commas, objects
16
+ * parse as JSON. The request body is then the same whether a value arrived
17
+ * as an argument, over stdin, or interactively.
18
+ *
19
+ * An argument naming no parameter passes through unchanged: unknown
20
+ * arguments are reported by `assertKnownArgs`, not silently dropped here.
21
+ */
22
+ export const coerceArgParams = (
23
+ parameters: Parameter[],
24
+ argParams: Record<string, unknown>,
25
+ ): { params: Record<string, unknown>; issues: CoercionIssue[] } => {
26
+ const byName = new Map(
27
+ parameters.map((parameter) => [parameter.name, parameter]),
28
+ )
29
+
30
+ const params: Record<string, unknown> = {}
31
+ const issues: CoercionIssue[] = []
32
+
33
+ for (const [name, given] of Object.entries(argParams)) {
34
+ const parameter = byName.get(name)
35
+ if (parameter == null) {
36
+ params[name] = given
37
+ continue
38
+ }
39
+
40
+ const coerced = coerceParam(parameter, given)
41
+ if ('issue' in coerced) {
42
+ issues.push({ name, given, expected: coerced.issue })
43
+ continue
44
+ }
45
+ params[name] = coerced.value
46
+ }
47
+
48
+ return { params, issues }
49
+ }
50
+
51
+ export const coerceParam = (parameter: Parameter, given: unknown): Coerced => {
52
+ // `null` is an explicit JSON value for nullable parameters, not the string
53
+ // "null" (or a one-item list containing it).
54
+ if (parameter.isNullable && (given === null || given === 'null')) {
55
+ return { value: null }
56
+ }
57
+
58
+ if (parameter.format === 'list') return coerceList(parameter, given)
59
+
60
+ // A repeated argument parses as an array, which only a list accepts.
61
+ if (Array.isArray(given)) return { issue: 'a single value' }
62
+
63
+ switch (parameter.format) {
64
+ case 'boolean':
65
+ return coerceBoolean(given)
66
+ case 'number':
67
+ return coerceNumber(given)
68
+ case 'enum':
69
+ return coerceEnum(parameter, given)
70
+ case 'object':
71
+ return coerceObject(given)
72
+ default:
73
+ return { value: String(given) }
74
+ }
75
+ }
76
+
77
+ const coerceBoolean = (given: unknown): Coerced => {
78
+ if (given === true || given === 'true' || given === '1' || given === 1) {
79
+ return { value: true }
80
+ }
81
+ if (given === false || given === 'false' || given === '0' || given === 0) {
82
+ return { value: false }
83
+ }
84
+ return { issue: 'true or false' }
85
+ }
86
+
87
+ const coerceNumber = (given: unknown): Coerced => {
88
+ if (typeof given === 'number') return { value: given }
89
+ if (typeof given === 'string' && given.trim() !== '') {
90
+ const value = Number(given)
91
+ if (!Number.isNaN(value)) return { value }
92
+ }
93
+ return { issue: 'a number' }
94
+ }
95
+
96
+ const coerceEnum = (
97
+ parameter: Parameter & { format: 'enum' },
98
+ given: unknown,
99
+ ): Coerced => {
100
+ const value = String(given)
101
+ const names = parameter.values.map(({ name }) => name)
102
+ if (!names.includes(value)) return { issue: `one of ${names.join(', ')}` }
103
+ return { value }
104
+ }
105
+
106
+ const coerceObject = (given: unknown): Coerced => {
107
+ if (typeof given !== 'string') return { issue: 'a JSON object' }
108
+ try {
109
+ const value: unknown = JSON.parse(given)
110
+ if (value == null || typeof value !== 'object' || Array.isArray(value)) {
111
+ return { issue: 'a JSON object' }
112
+ }
113
+ return { value }
114
+ } catch {
115
+ return { issue: 'a JSON object' }
116
+ }
117
+ }
118
+
119
+ const coerceList = (
120
+ parameter: Parameter & { format: 'list' },
121
+ given: unknown,
122
+ ): Coerced => {
123
+ const items = Array.isArray(given)
124
+ ? given
125
+ : typeof given === 'string'
126
+ ? given.split(',')
127
+ : [given]
128
+
129
+ const values: unknown[] = []
130
+ for (const item of items) {
131
+ const coerced = coerceListItem(parameter, item)
132
+ if ('issue' in coerced) return coerced
133
+ values.push(coerced.value)
134
+ }
135
+ return { value: values }
136
+ }
137
+
138
+ const coerceListItem = (
139
+ parameter: Parameter & { format: 'list' },
140
+ item: unknown,
141
+ ): Coerced => {
142
+ if (parameter.itemFormat === 'number') {
143
+ const coerced = coerceNumber(item)
144
+ if ('issue' in coerced) return { issue: 'a list of numbers' }
145
+ return coerced
146
+ }
147
+
148
+ if (parameter.itemFormat === 'boolean') {
149
+ const coerced = coerceBoolean(item)
150
+ if ('issue' in coerced) return { issue: 'a list of true or false' }
151
+ return coerced
152
+ }
153
+
154
+ if (parameter.itemFormat === 'enum') {
155
+ const value = String(item)
156
+ const names = parameter.itemEnumValues.map(({ name }) => name)
157
+ if (!names.includes(value)) {
158
+ return { issue: `a list of ${names.join(', ')}` }
159
+ }
160
+ return { value }
161
+ }
162
+
163
+ return { value: String(item) }
164
+ }
@@ -37,40 +37,45 @@ export const cliFlags: string[] = [
37
37
  'version',
38
38
  ]
39
39
 
40
- /**
41
- * Thrown when the CLI needs input it cannot prompt for.
42
- */
43
- export class NonInteractiveError extends Error {
44
- override name = 'NonInteractiveError'
45
- }
46
-
47
- /**
48
- * Thrown when the arguments do not name something the CLI can run.
49
- */
50
- export class UsageError extends Error {
51
- override name = 'UsageError'
52
-
53
- /** What to run instead, reported after the message. */
54
- readonly hint: string
55
-
56
- constructor(message: string, { hint = '' }: { hint?: string } = {}) {
57
- super(message)
58
- this.hint = hint
59
- }
40
+ export interface ParseCliArgsOptions {
41
+ /**
42
+ * Argument keys read exactly as given rather than by guessing at a type,
43
+ * e.g., every parameter of an endpoint that does not take a number or a
44
+ * boolean. Read as a number, an opaque value like an access code would
45
+ * lose leading zeroes or turn exponent notation into a digit string.
46
+ */
47
+ stringKeys?: string[]
60
48
  }
61
49
 
62
- export const parseCliArgs = (argv: string[]): ParsedArgs =>
50
+ export const parseCliArgs = (
51
+ argv: string[],
52
+ { stringKeys = [] }: ParseCliArgsOptions = {},
53
+ ): ParsedArgs =>
63
54
  parseArgs(argv, {
64
- // A page cursor is opaque, so keep it exactly as given: read as a number
65
- // it would lose leading zeroes and turn exponent notation into a digit
66
- // string, naming a page the API never issued.
67
- string: ['code', 'page-cursor', 'page_cursor'],
55
+ // A page cursor and a code are opaque even before the endpoint's own
56
+ // parameter types are known, so always keep them exactly as given.
57
+ string: ['code', 'page-cursor', 'page_cursor', ...stringKeys],
68
58
  boolean: ['non-interactive', 'interactive', 'json'],
69
59
  // Deliberately not aliased to -n, which is reserved for a future
70
60
  // --dry-run flag.
71
61
  alias: { 'non-interactive': 'y', interactive: 'i' },
72
62
  })
73
63
 
64
+ /**
65
+ * The request params among the parsed arguments: every key normalized to
66
+ * the parameter it names, minus the flags that configure the CLI itself.
67
+ */
68
+ export const toArgParams = (args: ParsedArgs): Record<string, unknown> => {
69
+ const argParams: Record<string, unknown> = {}
70
+ for (const [key, value] of Object.entries(args)) {
71
+ if (key === '_') continue
72
+ const name = toParameterName(key)
73
+ if (cliFlags.includes(name)) continue
74
+ argParams[name] = value
75
+ }
76
+ return argParams
77
+ }
78
+
74
79
  export interface GetInteractivityOptions {
75
80
  /**
76
81
  * Whether there is a terminal to prompt on.
@@ -0,0 +1,73 @@
1
+ import type { Parameter } from '@seamapi/blueprint'
2
+
3
+ import { NonInteractiveError, UsageError } from 'lib/errors.js'
4
+
5
+ import { toArgName, toGivenArgName } from './parse.js'
6
+
7
+ /**
8
+ * Report every required parameter still missing from the params, rather
9
+ * than prompting for it.
10
+ *
11
+ * @param target What the params are for, e.g., `/devices/list`.
12
+ */
13
+ export const assertRequiredParams = (
14
+ parameters: Parameter[],
15
+ params: Record<string, unknown>,
16
+ target: string,
17
+ ): void => {
18
+ // A required parameter is satisfied by being present, not by being
19
+ // truthy: `false`, `0` and `''` are values a caller can supply.
20
+ const missing = parameters
21
+ .filter((parameter) => parameter.isRequired)
22
+ .map((parameter) => parameter.name)
23
+ .filter((name) => params[name] === undefined)
24
+
25
+ if (missing.length === 0) return
26
+
27
+ throw new NonInteractiveError(
28
+ `Missing required ${
29
+ missing.length === 1 ? 'parameter' : 'parameters'
30
+ } for ${target}: ${missing.map(toArgName).join(' ')}`,
31
+ )
32
+ }
33
+
34
+ /**
35
+ * Report any argument the command does not accept, rather than acting on it.
36
+ * An unrecognized argument is a mistake: forwarded to the API it would fail
37
+ * somewhere less obvious or be quietly ignored, and on a command the CLI
38
+ * handles itself it would go nowhere at all.
39
+ *
40
+ * Only arguments are checked. Params read from stdin are passed through as
41
+ * given, so a caller may send whatever the API itself accepts.
42
+ */
43
+ export const assertKnownArgs = (
44
+ argParams: Record<string, unknown>,
45
+ command: string[],
46
+ {
47
+ accepted,
48
+ isLocal,
49
+ }: {
50
+ /** Parameter names the command accepts. */
51
+ accepted: Set<string>
52
+ /** Whether the CLI handles the command itself. */
53
+ isLocal: boolean
54
+ },
55
+ ): void => {
56
+ const unknown = Object.keys(argParams).filter((key) => !accepted.has(key))
57
+ if (unknown.length === 0) return
58
+
59
+ // Name an endpoint command by its path, as missing params are named, and a
60
+ // command the CLI handles itself by the words that run it.
61
+ const target = isLocal
62
+ ? command.join(' ')
63
+ : `/${command.join('/').replace(/-/g, '_')}`
64
+
65
+ throw new UsageError(
66
+ `Unknown ${
67
+ unknown.length === 1 ? 'parameter' : 'parameters'
68
+ } for ${target}: ${unknown.map(toGivenArgName).join(' ')}`,
69
+ {
70
+ hint: `Run 'seam ${command.join(' ')} --help' to see what it accepts.`,
71
+ },
72
+ )
73
+ }
@@ -0,0 +1,169 @@
1
+ import { randomBytes } from 'node:crypto'
2
+
3
+ import { type ConfigStore, getConfigStore } from 'lib/config/index.js'
4
+ import { type AuthContext, resolveAuth } from 'lib/context.js'
5
+ import {
6
+ assertEnvVarUnset,
7
+ endpointEnvVar,
8
+ tokenEnvVar,
9
+ workspaceIdEnvVar,
10
+ } from 'lib/env.js'
11
+
12
+ import { validateToken } from './validate-token.js'
13
+
14
+ /** A stored auth setting an environment variable may override. */
15
+ export type AuthSetting = 'server' | 'token' | 'workspaceId'
16
+
17
+ /**
18
+ * Refuse to store a setting the environment overrides.
19
+ *
20
+ * The env-override policy lives here alone: every auth mutation asserts
21
+ * through this before writing, so a command that appears to succeed cannot
22
+ * leave the CLI using something else.
23
+ *
24
+ * @param action What the command does, e.g., `log in`.
25
+ */
26
+ export const assertMutable = (
27
+ auth: AuthContext,
28
+ setting: AuthSetting,
29
+ action: string,
30
+ ): void => {
31
+ const { envVar, source, value } = {
32
+ server: {
33
+ envVar: endpointEnvVar,
34
+ source: auth.serverSource,
35
+ value: auth.server,
36
+ },
37
+ token: { envVar: tokenEnvVar, source: auth.tokenSource, value: auth.token },
38
+ workspaceId: {
39
+ envVar: workspaceIdEnvVar,
40
+ source: auth.workspaceIdSource,
41
+ value: auth.workspaceId,
42
+ },
43
+ }[setting]
44
+
45
+ if (source !== 'env') return
46
+ assertEnvVarUnset(envVar, value, action)
47
+ }
48
+
49
+ export interface LoginOptions {
50
+ server?: string | undefined
51
+ token?: string | undefined
52
+ workspaceId?: string | undefined
53
+ }
54
+
55
+ /**
56
+ * Store the given credentials, validating the token first.
57
+ *
58
+ * The token is stored under the server it will be used with, so a given
59
+ * server is stored and re-resolved before the token key is derived.
60
+ *
61
+ * Validation reaches the network, so a test may inject its own `validate`.
62
+ */
63
+ export const login = async (
64
+ { server, token, workspaceId }: LoginOptions,
65
+ config: ConfigStore = getConfigStore(),
66
+ validate: typeof validateToken = validateToken,
67
+ ): Promise<void> => {
68
+ let auth = resolveAuth(config)
69
+
70
+ // Nothing is stored while the environment overrides it, so refuse before
71
+ // storing anything rather than part way through.
72
+ assertMutable(auth, 'token', 'log in')
73
+ if (server != null) assertMutable(auth, 'server', 'select a server')
74
+ if (workspaceId != null) {
75
+ assertMutable(auth, 'workspaceId', 'select a workspace')
76
+ }
77
+
78
+ if (server != null) {
79
+ config.set('server', server)
80
+ config.delete('current_workspace_id')
81
+ auth = resolveAuth(config)
82
+ }
83
+
84
+ if (token != null) {
85
+ await validate(token, workspaceId)
86
+ config.set(`${auth.server}.pat`, token)
87
+ config.delete('current_workspace_id')
88
+ }
89
+
90
+ if (workspaceId != null) {
91
+ config.set('current_workspace_id', workspaceId)
92
+ }
93
+ }
94
+
95
+ /** Store the token for the current server, e.g., one just prompted for. */
96
+ export const storeToken = (
97
+ token: string,
98
+ config: ConfigStore = getConfigStore(),
99
+ ): void => {
100
+ const auth = resolveAuth(config)
101
+ assertMutable(auth, 'token', 'log in')
102
+ config.set(`${auth.server}.pat`, token)
103
+ }
104
+
105
+ /** Remove the stored token and workspace selection. */
106
+ export const logout = (config: ConfigStore = getConfigStore()): void => {
107
+ const auth = resolveAuth(config)
108
+ assertMutable(auth, 'token', 'log out')
109
+ config.delete(`${auth.server}.pat`)
110
+ // Configs written before tokens were stored per server may still hold an
111
+ // un-namespaced token, so drop that too.
112
+ config.delete('pat')
113
+ config.delete('current_workspace_id')
114
+ }
115
+
116
+ /**
117
+ * Store the server to make requests against.
118
+ *
119
+ * The workspace selection belongs to the previous server, so it is cleared.
120
+ */
121
+ export const selectServer = (
122
+ server: string,
123
+ config: ConfigStore = getConfigStore(),
124
+ ): void => {
125
+ assertMutable(resolveAuth(config), 'server', 'select a server')
126
+ config.set('server', server)
127
+ config.delete('current_workspace_id')
128
+ }
129
+
130
+ /** Store the workspace requests are made against. */
131
+ export const selectWorkspace = (
132
+ workspaceId: string,
133
+ config: ConfigStore = getConfigStore(),
134
+ ): void => {
135
+ assertMutable(resolveAuth(config), 'workspaceId', 'select a workspace')
136
+ config.set('current_workspace_id', workspaceId)
137
+ }
138
+
139
+ /**
140
+ * Point the CLI at a fake Seam Connect server and store the well-known
141
+ * token it accepts. Returns the generated server URL for reporting.
142
+ */
143
+ export const selectFakeServer = ({
144
+ urlSeed = randomBytes(5).toString('hex'),
145
+ config = getConfigStore(),
146
+ }: {
147
+ urlSeed?: string
148
+ config?: ConfigStore
149
+ } = {}): { server: string; token: string } => {
150
+ const auth = resolveAuth(config)
151
+ assertMutable(auth, 'server', 'select a server')
152
+ assertMutable(auth, 'token', 'log in')
153
+
154
+ const server = `https://${urlSeed}.fakeseamconnect.seam.vc`
155
+ const token = 'seam_apikey1_token'
156
+ config.set('server', server)
157
+ config.set(`${server}.pat`, token)
158
+ config.delete('current_workspace_id')
159
+
160
+ return { server, token }
161
+ }
162
+
163
+ /** Store whether API definitions come from the server instead of npm. */
164
+ export const setUseRemoteApiDefs = (
165
+ useRemoteApiDefs: boolean,
166
+ config: ConfigStore = getConfigStore(),
167
+ ): void => {
168
+ config.set('use_remote_api_defs', useRemoteApiDefs)
169
+ }
@@ -5,10 +5,10 @@ import {
5
5
  SeamHttpWithoutWorkspace,
6
6
  } from '@seamapi/http/connect'
7
7
 
8
- import { getServer } from './get-server.js'
8
+ import { resolveAuth } from 'lib/context.js'
9
9
 
10
10
  export const validateToken = async (token: string, workspaceId?: string) => {
11
- const options = { endpoint: getServer() }
11
+ const options = { endpoint: resolveAuth().server }
12
12
 
13
13
  if (isPersonalAccessToken(token)) {
14
14
  const seam = workspaceId
@@ -0,0 +1,97 @@
1
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises'
2
+ import { dirname, join } from 'node:path'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ import type { Blueprint } from '@seamapi/blueprint'
6
+
7
+ import { seamapiBlueprintVersion } from 'lib/version.js'
8
+
9
+ const cacheFileName = 'blueprint.json'
10
+ const updateCheckInterval = 24 * 60 * 60 * 1000
11
+
12
+ export interface BlueprintCache {
13
+ blueprintVersion: string
14
+ typesVersion: string
15
+ checkedAt: string
16
+ blueprint: Blueprint
17
+ }
18
+
19
+ export const getCacheFile = (cacheDirectory: string): string =>
20
+ join(cacheDirectory, cacheFileName)
21
+
22
+ export const readCache = async (
23
+ file: string,
24
+ ): Promise<BlueprintCache | null> => {
25
+ try {
26
+ const contents = await readFile(file, 'utf8')
27
+ const cache = JSON.parse(contents) as unknown
28
+ if (!isBlueprintCache(cache)) return null
29
+ return cache
30
+ } catch {
31
+ return null
32
+ }
33
+ }
34
+
35
+ export const writeCache = async (
36
+ file: string,
37
+ cache: BlueprintCache,
38
+ ): Promise<void> => {
39
+ const temporaryFile = `${file}.tmp`
40
+ await mkdir(dirname(file), { recursive: true })
41
+ await writeFile(temporaryFile, `${JSON.stringify(cache)}\n`, 'utf8')
42
+ await rename(temporaryFile, file)
43
+ }
44
+
45
+ export const isUpdateCheckDue = (checkedAt: string): boolean => {
46
+ const checkedAtTime = Date.parse(checkedAt)
47
+ if (Number.isNaN(checkedAtTime)) return true
48
+ return Date.now() - checkedAtTime > updateCheckInterval
49
+ }
50
+
51
+ /**
52
+ * The blueprint version the cache is keyed on: a cached blueprint built by a
53
+ * different @seamapi/blueprint version is stale even for the same types.
54
+ */
55
+ export const getBlueprintVersion = async (): Promise<string> => {
56
+ if (seamapiBlueprintVersion !== '0.0.0') return seamapiBlueprintVersion
57
+
58
+ // The version is only injected when the package is packed, so a
59
+ // development checkout reads the pinned version from package.json
60
+ // to keep invalidating the cache on version changes as expected.
61
+ const pkg = await findOwnPackageJson()
62
+ return pkg?.dependencies?.['@seamapi/blueprint'] ?? seamapiBlueprintVersion
63
+ }
64
+
65
+ const findOwnPackageJson = async (): Promise<{
66
+ dependencies?: Record<string, string>
67
+ } | null> => {
68
+ let directory = dirname(fileURLToPath(import.meta.url))
69
+ while (true) {
70
+ try {
71
+ const contents = await readFile(join(directory, 'package.json'), 'utf8')
72
+ const pkg = JSON.parse(contents) as {
73
+ name?: string
74
+ dependencies?: Record<string, string>
75
+ }
76
+ if (pkg.name === '@seamapi/cli') return pkg
77
+ } catch {
78
+ // Keep walking up until a package.json for this package is found.
79
+ }
80
+ const parent = dirname(directory)
81
+ if (parent === directory) return null
82
+ directory = parent
83
+ }
84
+ }
85
+
86
+ const isBlueprintCache = (cache: unknown): cache is BlueprintCache => {
87
+ if (cache == null || typeof cache !== 'object') return false
88
+ const { blueprintVersion, typesVersion, checkedAt, blueprint } =
89
+ cache as Record<string, unknown>
90
+ return (
91
+ typeof blueprintVersion === 'string' &&
92
+ typeof typesVersion === 'string' &&
93
+ typeof checkedAt === 'string' &&
94
+ blueprint != null &&
95
+ typeof blueprint === 'object'
96
+ )
97
+ }
@@ -1,5 +1,19 @@
1
- import { getCommandBlueprintDef } from './get-command-blueprint-def.js'
2
- import type { ContextHelpers } from './types.js'
1
+ import type { ApiBlueprint } from './index.js'
2
+
3
+ export const getCommandBlueprintDef = (
4
+ cmd: string[],
5
+ helpers: { blueprint: ApiBlueprint },
6
+ ) => {
7
+ const path = `/${cmd.join('/').replace(/-/g, '_')}`
8
+ const def = helpers.blueprint.routes
9
+ .flatMap((route) => route.endpoints)
10
+ .find((endpoint) => endpoint.path === path)
11
+ if (!def) {
12
+ throw new Error(`No definition for path ${path}`)
13
+ }
14
+
15
+ return def
16
+ }
3
17
 
4
18
  /**
5
19
  * The top level response key documented for a command,
@@ -10,7 +24,7 @@ import type { ContextHelpers } from './types.js'
10
24
  */
11
25
  export const getResponseKey = (
12
26
  command: string[],
13
- ctx: ContextHelpers,
27
+ ctx: { blueprint: ApiBlueprint },
14
28
  ): string | null => {
15
29
  let endpoint
16
30
  try {
@@ -0,0 +1,27 @@
1
+ import type { Blueprint } from '@seamapi/blueprint'
2
+
3
+ import { getBlueprint } from './source-npm.js'
4
+ import { createRemoteBlueprint } from './source-remote.js'
5
+
6
+ export type ApiBlueprint = Blueprint
7
+
8
+ export interface GetApiBlueprintOptions {
9
+ /**
10
+ * Build from the OpenAPI document the configured server is currently
11
+ * running, instead of the published npm types.
12
+ */
13
+ useRemoteDefinitions?: boolean
14
+ /** Force an update of the cached Seam API definitions. */
15
+ update?: boolean
16
+ }
17
+
18
+ export const getApiBlueprint = async ({
19
+ useRemoteDefinitions = false,
20
+ update = false,
21
+ }: GetApiBlueprintOptions = {}): Promise<ApiBlueprint> => {
22
+ // Remote definitions describe whatever the server is currently running, so
23
+ // build them directly from the server's OpenAPI document.
24
+ if (useRemoteDefinitions) return await createRemoteBlueprint()
25
+
26
+ return await getBlueprint({ update })
27
+ }