specli 0.0.11 → 0.0.13

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 (335) hide show
  1. package/README.md +216 -325
  2. package/bin/cli.sh +27 -0
  3. package/dist/{src/ai → ai}/tools.d.ts +0 -1
  4. package/dist/ai/tools.js +161 -0
  5. package/dist/ai/tools.test.d.ts +1 -0
  6. package/dist/ai/tools.test.js +56 -0
  7. package/dist/{src/cli → cli}/auth-requirements.d.ts +0 -1
  8. package/dist/cli/auth-requirements.js +65 -0
  9. package/dist/cli/auth-requirements.test.d.ts +1 -0
  10. package/dist/cli/auth-requirements.test.js +16 -0
  11. package/dist/{src/cli → cli}/auth-schemes.d.ts +0 -1
  12. package/dist/cli/auth-schemes.js +112 -0
  13. package/dist/cli/auth-schemes.test.d.ts +1 -0
  14. package/dist/cli/auth-schemes.test.js +56 -0
  15. package/dist/{src/cli → cli}/capabilities.d.ts +0 -1
  16. package/dist/cli/capabilities.js +41 -0
  17. package/dist/cli/capabilities.test.d.ts +1 -0
  18. package/dist/cli/capabilities.test.js +84 -0
  19. package/dist/{src/cli → cli}/command-id.d.ts +0 -1
  20. package/dist/cli/command-id.js +8 -0
  21. package/dist/cli/command-id.test.d.ts +1 -0
  22. package/dist/cli/command-id.test.js +27 -0
  23. package/dist/{src/cli → cli}/command-index.d.ts +0 -1
  24. package/dist/cli/command-index.js +9 -0
  25. package/dist/{src/cli → cli}/command-model.d.ts +0 -1
  26. package/dist/cli/command-model.js +53 -0
  27. package/dist/cli/command-model.test.d.ts +1 -0
  28. package/dist/cli/command-model.test.js +40 -0
  29. package/dist/{src/cli → cli}/compile.d.ts +0 -1
  30. package/dist/cli/compile.js +79 -0
  31. package/dist/{src/cli → cli}/crypto.d.ts +0 -1
  32. package/dist/cli/crypto.js +9 -0
  33. package/dist/{src/cli → cli}/derive-name.d.ts +0 -1
  34. package/dist/cli/derive-name.js +96 -0
  35. package/dist/{src/cli → cli}/exec.d.ts +0 -1
  36. package/dist/cli/exec.js +50 -0
  37. package/dist/{src/cli → cli}/main.d.ts +0 -1
  38. package/dist/cli/main.js +177 -0
  39. package/dist/{src/cli → cli}/naming.d.ts +0 -1
  40. package/dist/cli/naming.js +191 -0
  41. package/dist/cli/naming.test.d.ts +1 -0
  42. package/dist/cli/naming.test.js +75 -0
  43. package/dist/{src/cli → cli}/operations.d.ts +0 -1
  44. package/dist/cli/operations.js +100 -0
  45. package/dist/cli/operations.test.d.ts +1 -0
  46. package/dist/cli/operations.test.js +51 -0
  47. package/dist/{src/cli → cli}/params.d.ts +0 -1
  48. package/dist/cli/params.js +36 -0
  49. package/dist/cli/params.test.d.ts +1 -0
  50. package/dist/cli/params.test.js +62 -0
  51. package/dist/{src/cli → cli}/pluralize.d.ts +0 -1
  52. package/dist/cli/pluralize.js +38 -0
  53. package/dist/{src/cli → cli}/positional.d.ts +0 -1
  54. package/dist/cli/positional.js +35 -0
  55. package/dist/cli/positional.test.d.ts +1 -0
  56. package/dist/cli/positional.test.js +60 -0
  57. package/dist/{src/cli → cli}/request-body.d.ts +0 -1
  58. package/dist/cli/request-body.js +44 -0
  59. package/dist/cli/request-body.test.d.ts +1 -0
  60. package/dist/cli/request-body.test.js +31 -0
  61. package/dist/{src/cli → cli}/runtime/argv.d.ts +0 -1
  62. package/dist/cli/runtime/argv.js +15 -0
  63. package/dist/{src/cli → cli}/runtime/auth/resolve.d.ts +0 -1
  64. package/dist/cli/runtime/auth/resolve.js +39 -0
  65. package/dist/{src/cli → cli}/runtime/body-flags.d.ts +0 -1
  66. package/dist/cli/runtime/body-flags.js +117 -0
  67. package/dist/cli/runtime/body-flags.test.d.ts +1 -0
  68. package/dist/cli/runtime/body-flags.test.js +192 -0
  69. package/dist/{src/cli → cli}/runtime/body.d.ts +0 -1
  70. package/dist/cli/runtime/body.js +16 -0
  71. package/dist/{src/cli → cli}/runtime/collect.d.ts +0 -1
  72. package/dist/cli/runtime/collect.js +3 -0
  73. package/dist/{src/cli → cli}/runtime/compat.d.ts +0 -1
  74. package/dist/cli/runtime/compat.js +78 -0
  75. package/dist/{src/cli → cli}/runtime/context.d.ts +0 -1
  76. package/dist/cli/runtime/context.js +44 -0
  77. package/dist/{src/cli → cli}/runtime/execute.d.ts +0 -1
  78. package/dist/cli/runtime/execute.js +106 -0
  79. package/dist/{src/cli → cli}/runtime/generated.d.ts +0 -1
  80. package/dist/cli/runtime/generated.js +168 -0
  81. package/dist/{src/cli → cli}/runtime/headers.d.ts +0 -1
  82. package/dist/cli/runtime/headers.js +30 -0
  83. package/dist/{src/cli → cli}/runtime/index.d.ts +0 -1
  84. package/dist/cli/runtime/index.js +3 -0
  85. package/dist/{src/cli → cli}/runtime/profile/secrets.d.ts +0 -1
  86. package/dist/cli/runtime/profile/secrets.js +53 -0
  87. package/dist/{src/cli → cli}/runtime/profile/store.d.ts +0 -1
  88. package/dist/cli/runtime/profile/store.js +63 -0
  89. package/dist/{src/cli → cli}/runtime/request.d.ts +0 -1
  90. package/dist/cli/runtime/request.js +283 -0
  91. package/dist/cli/runtime/request.test.d.ts +1 -0
  92. package/dist/cli/runtime/request.test.js +332 -0
  93. package/dist/{src/cli → cli}/runtime/server-url.d.ts +0 -1
  94. package/dist/cli/runtime/server-url.js +28 -0
  95. package/dist/{src/cli → cli}/runtime/template.d.ts +0 -1
  96. package/dist/cli/runtime/template.js +22 -0
  97. package/dist/cli/runtime/validate/ajv.d.ts +2 -0
  98. package/dist/cli/runtime/validate/ajv.js +11 -0
  99. package/dist/{src/cli → cli}/runtime/validate/coerce.d.ts +0 -1
  100. package/dist/cli/runtime/validate/coerce.js +63 -0
  101. package/dist/cli/runtime/validate/coerce.test.d.ts +1 -0
  102. package/dist/cli/runtime/validate/coerce.test.js +75 -0
  103. package/dist/{src/cli → cli}/runtime/validate/error.d.ts +0 -1
  104. package/dist/cli/runtime/validate/error.js +19 -0
  105. package/dist/{src/cli → cli}/runtime/validate/index.d.ts +0 -1
  106. package/dist/cli/runtime/validate/index.js +4 -0
  107. package/dist/{src/cli → cli}/runtime/validate/schema.d.ts +0 -1
  108. package/dist/cli/runtime/validate/schema.js +38 -0
  109. package/dist/{src/cli → cli}/schema-shape.d.ts +0 -1
  110. package/dist/cli/schema-shape.js +34 -0
  111. package/dist/{src/cli → cli}/schema.d.ts +0 -1
  112. package/dist/cli/schema.js +31 -0
  113. package/dist/{src/cli → cli}/server.d.ts +0 -1
  114. package/dist/cli/server.js +130 -0
  115. package/dist/cli/server.test.d.ts +1 -0
  116. package/dist/cli/server.test.js +49 -0
  117. package/dist/{src/cli → cli}/spec-id.d.ts +0 -1
  118. package/dist/cli/spec-id.js +8 -0
  119. package/dist/{src/cli → cli}/spec-loader.d.ts +0 -1
  120. package/dist/cli/spec-loader.js +40 -0
  121. package/dist/{src/cli → cli}/stable-json.d.ts +0 -1
  122. package/dist/cli/stable-json.js +29 -0
  123. package/dist/{src/cli → cli}/strings.d.ts +0 -1
  124. package/dist/cli/strings.js +20 -0
  125. package/dist/{src/cli → cli}/types.d.ts +0 -1
  126. package/dist/cli/types.js +3 -0
  127. package/dist/cli.d.ts +0 -1
  128. package/dist/cli.js +51 -2324
  129. package/dist/compiled.d.ts +2 -0
  130. package/{src/compiled.ts → dist/compiled.js} +8 -11
  131. package/dist/macros/env.d.ts +10 -0
  132. package/dist/macros/env.js +22 -0
  133. package/dist/macros/spec.d.ts +5 -0
  134. package/dist/macros/spec.js +16 -0
  135. package/package.json +17 -25
  136. package/bin/specli.js +0 -26
  137. package/cli.ts +0 -77
  138. package/dist/cli.d.ts.map +0 -1
  139. package/dist/cli.js.map +0 -53
  140. package/dist/index.d.ts +0 -2
  141. package/dist/index.d.ts.map +0 -1
  142. package/dist/index.js +0 -2032
  143. package/dist/index.js.map +0 -48
  144. package/dist/src/ai/tools.d.ts.map +0 -1
  145. package/dist/src/ai/tools.js +0 -1656
  146. package/dist/src/ai/tools.js.map +0 -45
  147. package/dist/src/cli/auth-requirements.d.ts.map +0 -1
  148. package/dist/src/cli/auth-requirements.js +0 -66
  149. package/dist/src/cli/auth-requirements.js.map +0 -10
  150. package/dist/src/cli/auth-schemes.d.ts.map +0 -1
  151. package/dist/src/cli/auth-schemes.js +0 -116
  152. package/dist/src/cli/auth-schemes.js.map +0 -11
  153. package/dist/src/cli/capabilities.d.ts.map +0 -1
  154. package/dist/src/cli/capabilities.js +0 -45
  155. package/dist/src/cli/capabilities.js.map +0 -10
  156. package/dist/src/cli/command-id.d.ts.map +0 -1
  157. package/dist/src/cli/command-id.js +0 -18
  158. package/dist/src/cli/command-id.js.map +0 -11
  159. package/dist/src/cli/command-index.d.ts.map +0 -1
  160. package/dist/src/cli/command-index.js +0 -15
  161. package/dist/src/cli/command-index.js.map +0 -10
  162. package/dist/src/cli/command-model.d.ts.map +0 -1
  163. package/dist/src/cli/command-model.js +0 -274
  164. package/dist/src/cli/command-model.js.map +0 -18
  165. package/dist/src/cli/compile.d.ts.map +0 -1
  166. package/dist/src/cli/compile.js +0 -146
  167. package/dist/src/cli/compile.js.map +0 -11
  168. package/dist/src/cli/crypto.d.ts.map +0 -1
  169. package/dist/src/cli/crypto.js +0 -15
  170. package/dist/src/cli/crypto.js.map +0 -10
  171. package/dist/src/cli/derive-name.d.ts.map +0 -1
  172. package/dist/src/cli/derive-name.js +0 -70
  173. package/dist/src/cli/derive-name.js.map +0 -10
  174. package/dist/src/cli/exec.d.ts.map +0 -1
  175. package/dist/src/cli/exec.js +0 -2077
  176. package/dist/src/cli/exec.js.map +0 -49
  177. package/dist/src/cli/main.d.ts.map +0 -1
  178. package/dist/src/cli/main.js +0 -2032
  179. package/dist/src/cli/main.js.map +0 -48
  180. package/dist/src/cli/naming.d.ts.map +0 -1
  181. package/dist/src/cli/naming.js +0 -216
  182. package/dist/src/cli/naming.js.map +0 -12
  183. package/dist/src/cli/operations.d.ts.map +0 -1
  184. package/dist/src/cli/operations.js +0 -103
  185. package/dist/src/cli/operations.js.map +0 -10
  186. package/dist/src/cli/params.d.ts.map +0 -1
  187. package/dist/src/cli/params.js +0 -79
  188. package/dist/src/cli/params.js.map +0 -12
  189. package/dist/src/cli/pluralize.d.ts.map +0 -1
  190. package/dist/src/cli/pluralize.js +0 -43
  191. package/dist/src/cli/pluralize.js.map +0 -10
  192. package/dist/src/cli/positional.d.ts.map +0 -1
  193. package/dist/src/cli/positional.js +0 -39
  194. package/dist/src/cli/positional.js.map +0 -10
  195. package/dist/src/cli/request-body.d.ts.map +0 -1
  196. package/dist/src/cli/request-body.js +0 -82
  197. package/dist/src/cli/request-body.js.map +0 -12
  198. package/dist/src/cli/runtime/argv.d.ts.map +0 -1
  199. package/dist/src/cli/runtime/argv.js +0 -22
  200. package/dist/src/cli/runtime/argv.js.map +0 -10
  201. package/dist/src/cli/runtime/auth/resolve.d.ts.map +0 -1
  202. package/dist/src/cli/runtime/auth/resolve.js +0 -38
  203. package/dist/src/cli/runtime/auth/resolve.js.map +0 -10
  204. package/dist/src/cli/runtime/body-flags.d.ts.map +0 -1
  205. package/dist/src/cli/runtime/body-flags.js +0 -86
  206. package/dist/src/cli/runtime/body-flags.js.map +0 -10
  207. package/dist/src/cli/runtime/body.d.ts.map +0 -1
  208. package/dist/src/cli/runtime/body.js +0 -40
  209. package/dist/src/cli/runtime/body.js.map +0 -11
  210. package/dist/src/cli/runtime/collect.d.ts.map +0 -1
  211. package/dist/src/cli/runtime/collect.js +0 -9
  212. package/dist/src/cli/runtime/collect.js.map +0 -10
  213. package/dist/src/cli/runtime/compat.d.ts.map +0 -1
  214. package/dist/src/cli/runtime/compat.js +0 -62
  215. package/dist/src/cli/runtime/compat.js.map +0 -10
  216. package/dist/src/cli/runtime/context.d.ts.map +0 -1
  217. package/dist/src/cli/runtime/context.js +0 -936
  218. package/dist/src/cli/runtime/context.js.map +0 -32
  219. package/dist/src/cli/runtime/execute.d.ts.map +0 -1
  220. package/dist/src/cli/runtime/execute.js +0 -670
  221. package/dist/src/cli/runtime/execute.js.map +0 -22
  222. package/dist/src/cli/runtime/generated.d.ts.map +0 -1
  223. package/dist/src/cli/runtime/generated.js +0 -869
  224. package/dist/src/cli/runtime/generated.js.map +0 -23
  225. package/dist/src/cli/runtime/headers.d.ts.map +0 -1
  226. package/dist/src/cli/runtime/headers.js +0 -36
  227. package/dist/src/cli/runtime/headers.js.map +0 -10
  228. package/dist/src/cli/runtime/index.d.ts.map +0 -1
  229. package/dist/src/cli/runtime/index.js +0 -1808
  230. package/dist/src/cli/runtime/index.js.map +0 -46
  231. package/dist/src/cli/runtime/profile/secrets.d.ts.map +0 -1
  232. package/dist/src/cli/runtime/profile/secrets.js +0 -51
  233. package/dist/src/cli/runtime/profile/secrets.js.map +0 -11
  234. package/dist/src/cli/runtime/profile/store.d.ts.map +0 -1
  235. package/dist/src/cli/runtime/profile/store.js +0 -102
  236. package/dist/src/cli/runtime/profile/store.js.map +0 -11
  237. package/dist/src/cli/runtime/request.d.ts.map +0 -1
  238. package/dist/src/cli/runtime/request.js +0 -571
  239. package/dist/src/cli/runtime/request.js.map +0 -21
  240. package/dist/src/cli/runtime/server-url.d.ts.map +0 -1
  241. package/dist/src/cli/runtime/server-url.js +0 -55
  242. package/dist/src/cli/runtime/server-url.js.map +0 -11
  243. package/dist/src/cli/runtime/template.d.ts.map +0 -1
  244. package/dist/src/cli/runtime/template.js +0 -29
  245. package/dist/src/cli/runtime/template.js.map +0 -10
  246. package/dist/src/cli/runtime/validate/ajv.d.ts +0 -3
  247. package/dist/src/cli/runtime/validate/ajv.d.ts.map +0 -1
  248. package/dist/src/cli/runtime/validate/ajv.js +0 -17
  249. package/dist/src/cli/runtime/validate/ajv.js.map +0 -10
  250. package/dist/src/cli/runtime/validate/coerce.d.ts.map +0 -1
  251. package/dist/src/cli/runtime/validate/coerce.js +0 -60
  252. package/dist/src/cli/runtime/validate/coerce.js.map +0 -10
  253. package/dist/src/cli/runtime/validate/error.d.ts.map +0 -1
  254. package/dist/src/cli/runtime/validate/error.js +0 -21
  255. package/dist/src/cli/runtime/validate/error.js.map +0 -10
  256. package/dist/src/cli/runtime/validate/index.d.ts.map +0 -1
  257. package/dist/src/cli/runtime/validate/index.js +0 -122
  258. package/dist/src/cli/runtime/validate/index.js.map +0 -13
  259. package/dist/src/cli/runtime/validate/schema.d.ts.map +0 -1
  260. package/dist/src/cli/runtime/validate/schema.js +0 -36
  261. package/dist/src/cli/runtime/validate/schema.js.map +0 -10
  262. package/dist/src/cli/schema-shape.d.ts.map +0 -1
  263. package/dist/src/cli/schema-shape.js +0 -41
  264. package/dist/src/cli/schema-shape.js.map +0 -10
  265. package/dist/src/cli/schema.d.ts.map +0 -1
  266. package/dist/src/cli/schema.js +0 -38
  267. package/dist/src/cli/schema.js.map +0 -10
  268. package/dist/src/cli/server.d.ts.map +0 -1
  269. package/dist/src/cli/server.js +0 -64
  270. package/dist/src/cli/server.js.map +0 -11
  271. package/dist/src/cli/spec-id.d.ts.map +0 -1
  272. package/dist/src/cli/spec-id.js +0 -21
  273. package/dist/src/cli/spec-id.js.map +0 -11
  274. package/dist/src/cli/spec-loader.d.ts.map +0 -1
  275. package/dist/src/cli/spec-loader.js +0 -110
  276. package/dist/src/cli/spec-loader.js.map +0 -15
  277. package/dist/src/cli/stable-json.d.ts.map +0 -1
  278. package/dist/src/cli/stable-json.js +0 -35
  279. package/dist/src/cli/stable-json.js.map +0 -10
  280. package/dist/src/cli/strings.d.ts.map +0 -1
  281. package/dist/src/cli/strings.js +0 -16
  282. package/dist/src/cli/strings.js.map +0 -10
  283. package/dist/src/cli/types.d.ts.map +0 -1
  284. package/dist/src/cli/types.js +0 -9
  285. package/dist/src/cli/types.js.map +0 -10
  286. package/index.ts +0 -1
  287. package/src/ai/tools.ts +0 -211
  288. package/src/cli/auth-requirements.ts +0 -91
  289. package/src/cli/auth-schemes.ts +0 -187
  290. package/src/cli/capabilities.ts +0 -88
  291. package/src/cli/command-id.ts +0 -16
  292. package/src/cli/command-index.ts +0 -19
  293. package/src/cli/command-model.ts +0 -128
  294. package/src/cli/compile.ts +0 -101
  295. package/src/cli/crypto.ts +0 -9
  296. package/src/cli/derive-name.ts +0 -101
  297. package/src/cli/exec.ts +0 -72
  298. package/src/cli/main.ts +0 -231
  299. package/src/cli/naming.ts +0 -224
  300. package/src/cli/operations.ts +0 -152
  301. package/src/cli/params.ts +0 -71
  302. package/src/cli/pluralize.ts +0 -41
  303. package/src/cli/positional.ts +0 -75
  304. package/src/cli/request-body.ts +0 -94
  305. package/src/cli/runtime/argv.ts +0 -14
  306. package/src/cli/runtime/auth/resolve.ts +0 -59
  307. package/src/cli/runtime/body-flags.ts +0 -176
  308. package/src/cli/runtime/body.ts +0 -24
  309. package/src/cli/runtime/collect.ts +0 -6
  310. package/src/cli/runtime/compat.ts +0 -89
  311. package/src/cli/runtime/context.ts +0 -62
  312. package/src/cli/runtime/execute.ts +0 -147
  313. package/src/cli/runtime/generated.ts +0 -242
  314. package/src/cli/runtime/headers.ts +0 -37
  315. package/src/cli/runtime/index.ts +0 -3
  316. package/src/cli/runtime/profile/secrets.ts +0 -83
  317. package/src/cli/runtime/profile/store.ts +0 -100
  318. package/src/cli/runtime/request.ts +0 -390
  319. package/src/cli/runtime/server-url.ts +0 -45
  320. package/src/cli/runtime/template.ts +0 -26
  321. package/src/cli/runtime/validate/ajv.ts +0 -13
  322. package/src/cli/runtime/validate/coerce.ts +0 -71
  323. package/src/cli/runtime/validate/error.ts +0 -29
  324. package/src/cli/runtime/validate/index.ts +0 -4
  325. package/src/cli/runtime/validate/schema.ts +0 -54
  326. package/src/cli/schema-shape.ts +0 -36
  327. package/src/cli/schema.ts +0 -76
  328. package/src/cli/server.ts +0 -88
  329. package/src/cli/spec-id.ts +0 -12
  330. package/src/cli/spec-loader.ts +0 -58
  331. package/src/cli/stable-json.ts +0 -35
  332. package/src/cli/strings.ts +0 -21
  333. package/src/cli/types.ts +0 -59
  334. package/src/macros/env.ts +0 -21
  335. package/src/macros/spec.ts +0 -17
@@ -1,390 +0,0 @@
1
- import type { AuthScheme } from "../auth-schemes.ts";
2
- import type { CommandAction } from "../command-model.ts";
3
-
4
- import { resolveAuthScheme } from "./auth/resolve.ts";
5
- import { getToken } from "./profile/secrets.ts";
6
- import { getProfile, readProfiles } from "./profile/store.ts";
7
- import { resolveServerUrl } from "./server-url.ts";
8
- import { applyTemplate } from "./template.ts";
9
- import {
10
- createAjv,
11
- deriveValidationSchemas,
12
- formatAjvErrors,
13
- } from "./validate/index.ts";
14
-
15
- export type RuntimeGlobals = {
16
- spec?: string;
17
- server?: string;
18
- serverVar?: string[];
19
-
20
- curl?: boolean;
21
- json?: boolean;
22
-
23
- auth?: string;
24
- bearerToken?: string;
25
- oauthToken?: string;
26
- username?: string;
27
- password?: string;
28
- apiKey?: string;
29
- };
30
-
31
- function parseKeyValuePairs(
32
- pairs: string[] | undefined,
33
- ): Record<string, string> {
34
- const out: Record<string, string> = {};
35
- for (const pair of pairs ?? []) {
36
- const idx = pair.indexOf("=");
37
- if (idx === -1)
38
- throw new Error(`Invalid pair '${pair}', expected name=value`);
39
- const name = pair.slice(0, idx).trim();
40
- const value = pair.slice(idx + 1).trim();
41
- if (!name) throw new Error(`Invalid pair '${pair}', missing name`);
42
- out[name] = value;
43
- }
44
- return out;
45
- }
46
-
47
- function _parseTimeoutMs(value: string | undefined): number | undefined {
48
- if (!value) return undefined;
49
- const n = Number(value);
50
- if (!Number.isFinite(n) || n <= 0)
51
- throw new Error("--timeout must be a positive number");
52
- return n;
53
- }
54
-
55
- function pickAuthSchemeKey(
56
- action: CommandAction,
57
- globals: RuntimeGlobals,
58
- ): string | undefined {
59
- if (globals.auth) return globals.auth;
60
-
61
- // If operation declares a single requirement set with a single scheme, default to it.
62
- const req = action.auth.alternatives;
63
- if (req.length === 1 && req[0]?.length === 1) {
64
- return req[0][0]?.key;
65
- }
66
-
67
- return undefined;
68
- }
69
-
70
- function applyAuth(
71
- headers: Headers,
72
- url: URL,
73
- action: CommandAction,
74
- globals: RuntimeGlobals,
75
- authSchemes: AuthScheme[],
76
- ): { headers: Headers; url: URL } {
77
- const schemeKey = pickAuthSchemeKey(action, globals);
78
- if (!schemeKey) return { headers, url };
79
-
80
- const scheme = authSchemes.find((s) => s.key === schemeKey);
81
- if (!scheme) {
82
- throw new Error(
83
- `Unknown auth scheme '${schemeKey}'. Available: ${authSchemes
84
- .map((s) => s.key)
85
- .join(", ")}`,
86
- );
87
- }
88
-
89
- if (
90
- scheme.kind === "http-bearer" ||
91
- scheme.kind === "oauth2" ||
92
- scheme.kind === "openIdConnect"
93
- ) {
94
- const token = globals.bearerToken ?? globals.oauthToken;
95
- if (!token)
96
- throw new Error("Missing token. Provide --bearer-token <token>.");
97
- headers.set("Authorization", `Bearer ${token}`);
98
- return { headers, url };
99
- }
100
-
101
- if (scheme.kind === "http-basic") {
102
- if (!globals.username) throw new Error("Missing --username for basic auth");
103
- if (!globals.password) throw new Error("Missing --password for basic auth");
104
- const raw = `${globals.username}:${globals.password}`;
105
- const encoded = Buffer.from(raw, "utf8").toString("base64");
106
- headers.set("Authorization", `Basic ${encoded}`);
107
- return { headers, url };
108
- }
109
-
110
- if (scheme.kind === "api-key") {
111
- if (!scheme.name)
112
- throw new Error(`apiKey scheme '${scheme.key}' missing name`);
113
- if (!scheme.in)
114
- throw new Error(`apiKey scheme '${scheme.key}' missing location`);
115
- if (!globals.apiKey) throw new Error("Missing --api-key for apiKey auth");
116
-
117
- if (scheme.in === "header") {
118
- headers.set(scheme.name, globals.apiKey);
119
- }
120
- if (scheme.in === "query") {
121
- url.searchParams.set(scheme.name, globals.apiKey);
122
- }
123
- if (scheme.in === "cookie") {
124
- const existing = headers.get("Cookie");
125
- const part = `${scheme.name}=${globals.apiKey}`;
126
- headers.set("Cookie", existing ? `${existing}; ${part}` : part);
127
- }
128
-
129
- return { headers, url };
130
- }
131
-
132
- return { headers, url };
133
- }
134
-
135
- export type EmbeddedDefaults = {
136
- server?: string;
137
- serverVars?: string[];
138
- auth?: string;
139
- };
140
-
141
- export type BuildRequestInput = {
142
- specId: string;
143
- action: CommandAction;
144
- positionalValues: string[];
145
- flagValues: Record<string, unknown>;
146
- globals: RuntimeGlobals;
147
- servers: import("../server.ts").ServerInfo[];
148
- authSchemes: AuthScheme[];
149
- embeddedDefaults?: EmbeddedDefaults;
150
- bodyFlagDefs?: import("./body-flags.ts").BodyFlagDef[];
151
- };
152
-
153
- export async function buildRequest(
154
- input: BuildRequestInput,
155
- ): Promise<{ request: Request; curl: string }> {
156
- // Always use the "default" profile for simplicity
157
- const defaultProfileName = "default";
158
- const profilesFile = await readProfiles();
159
- const profile = getProfile(profilesFile, defaultProfileName);
160
- const embedded = input.embeddedDefaults;
161
-
162
- // Merge server vars: CLI flags override embedded defaults
163
- const embeddedServerVars = parseKeyValuePairs(embedded?.serverVars);
164
- const cliServerVars = parseKeyValuePairs(input.globals.serverVar);
165
- const serverVars = { ...embeddedServerVars, ...cliServerVars };
166
-
167
- // Priority: CLI flag > profile > embedded default
168
- const serverUrl = resolveServerUrl({
169
- serverOverride: input.globals.server ?? profile?.server ?? embedded?.server,
170
- servers: input.servers,
171
- serverVars,
172
- });
173
-
174
- // Path params: action.positionals order matches templated params order.
175
- const pathVars: Record<string, string> = {};
176
- for (let i = 0; i < input.action.positionals.length; i++) {
177
- const pos = input.action.positionals[i];
178
- const raw = input.action.pathArgs[i];
179
- const value = input.positionalValues[i];
180
- if (typeof raw === "string" && typeof value === "string") {
181
- pathVars[raw] = value;
182
- }
183
- // Use cli name too as fallback
184
- if (pos?.name && typeof value === "string") {
185
- pathVars[pos.name] = value;
186
- }
187
- }
188
-
189
- const path = applyTemplate(input.action.path, pathVars, { encode: true });
190
-
191
- // Build the full URL by combining server URL and path.
192
- // We need to handle the case where path starts with "/" carefully:
193
- // URL constructor treats absolute paths as relative to origin, not base path.
194
- const baseUrl = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
195
- const relativePath = path.startsWith("/") ? path.slice(1) : path;
196
- const url = new URL(relativePath, baseUrl);
197
-
198
- const headers = new Headers();
199
-
200
- // Collect declared params for validation.
201
- const queryValues: Record<string, unknown> = {};
202
- const headerValues: Record<string, unknown> = {};
203
- const cookieValues: Record<string, unknown> = {};
204
-
205
- for (const p of input.action.params) {
206
- if (p.kind !== "flag") continue;
207
- const optValue = input.flagValues[optionKeyFromFlag(p.flag)];
208
- if (typeof optValue === "undefined") continue;
209
-
210
- if (p.in === "query") {
211
- queryValues[p.name] = optValue;
212
- }
213
- if (p.in === "header") {
214
- headerValues[p.name] = optValue;
215
- }
216
- if (p.in === "cookie") {
217
- cookieValues[p.name] = optValue;
218
- }
219
- }
220
-
221
- // Validate params (query/header/cookie) using Ajv.
222
- const schemas = deriveValidationSchemas(input.action);
223
- const ajv = createAjv();
224
-
225
- if (schemas.querySchema) {
226
- const validate = ajv.compile(schemas.querySchema);
227
- if (!validate(queryValues)) {
228
- throw new Error(formatAjvErrors(validate.errors));
229
- }
230
- }
231
- if (schemas.headerSchema) {
232
- const validate = ajv.compile(schemas.headerSchema);
233
- if (!validate(headerValues)) {
234
- throw new Error(formatAjvErrors(validate.errors));
235
- }
236
- }
237
- if (schemas.cookieSchema) {
238
- const validate = ajv.compile(schemas.cookieSchema);
239
- if (!validate(cookieValues)) {
240
- throw new Error(formatAjvErrors(validate.errors));
241
- }
242
- }
243
-
244
- // Apply params -> query/header/cookie
245
- for (const [name, value] of Object.entries(queryValues)) {
246
- if (Array.isArray(value)) {
247
- for (const item of value) {
248
- url.searchParams.append(name, String(item));
249
- }
250
- continue;
251
- }
252
- url.searchParams.set(name, String(value));
253
- }
254
- for (const [name, value] of Object.entries(headerValues)) {
255
- headers.set(name, String(value));
256
- }
257
- for (const [name, value] of Object.entries(cookieValues)) {
258
- const existing = headers.get("Cookie");
259
- const part = `${name}=${String(value)}`;
260
- headers.set("Cookie", existing ? `${existing}; ${part}` : part);
261
- }
262
-
263
- let body: string | undefined;
264
- if (input.action.requestBody) {
265
- // Check if any body flags were provided using the flag definitions
266
- const bodyFlagDefs = input.bodyFlagDefs ?? [];
267
- const hasBodyFlags = bodyFlagDefs.some((def) => {
268
- // Commander keeps dots in option names: --address.street -> "address.street"
269
- const dotKey = def.path.join(".");
270
- return input.flagValues[dotKey] !== undefined;
271
- });
272
-
273
- const contentType = input.action.requestBody.preferredContentType;
274
- if (contentType) headers.set("Content-Type", contentType);
275
-
276
- const schema = input.action.requestBodySchema;
277
-
278
- // Check if there are any required fields in the body
279
- const requiredFields = bodyFlagDefs.filter((d) => d.required);
280
-
281
- if (!hasBodyFlags) {
282
- if (requiredFields.length > 0) {
283
- // Error: user must provide required fields
284
- const flagList = requiredFields.map((d) => `--${d.path.join(".")}`);
285
- throw new Error(`Required: ${flagList.join(", ")}`);
286
- }
287
- // No required fields - send empty body if body is required, otherwise skip
288
- if (input.action.requestBody.required) {
289
- body = "{}";
290
- }
291
- } else {
292
- if (!contentType?.includes("json")) {
293
- throw new Error(
294
- "Body field flags are only supported for JSON request bodies.",
295
- );
296
- }
297
-
298
- // Check for missing required fields
299
- const { findMissingRequired, parseDotNotationFlags } = await import(
300
- "./body-flags.ts"
301
- );
302
- const missing = findMissingRequired(input.flagValues, bodyFlagDefs);
303
- if (missing.length > 0) {
304
- const missingFlags = missing.map((m) => `--${m}`).join(", ");
305
- throw new Error(`Missing required fields: ${missingFlags}`);
306
- }
307
-
308
- // Build nested object from dot-notation flags
309
- const built = parseDotNotationFlags(input.flagValues, bodyFlagDefs);
310
-
311
- if (schema) {
312
- const validate = ajv.compile(schema);
313
- if (!validate(built)) {
314
- throw new Error(formatAjvErrors(validate.errors));
315
- }
316
- }
317
-
318
- body = JSON.stringify(built);
319
- }
320
- }
321
-
322
- // Check if user has a stored token (needed for auth scheme auto-selection)
323
- const storedToken = profile?.name
324
- ? await getToken(input.specId, profile.name)
325
- : null;
326
-
327
- // Auth resolution priority: CLI flag > profile > embedded default
328
- const resolvedAuthScheme = resolveAuthScheme(
329
- input.authSchemes,
330
- input.action.auth,
331
- {
332
- flagAuthScheme: input.globals.auth,
333
- profileAuthScheme: profile?.authScheme,
334
- embeddedAuthScheme: embedded?.auth,
335
- hasStoredToken: Boolean(storedToken),
336
- },
337
- );
338
-
339
- const tokenFromProfile = resolvedAuthScheme ? storedToken : null;
340
-
341
- const globalsWithProfileAuth: RuntimeGlobals = {
342
- ...input.globals,
343
- auth: resolvedAuthScheme,
344
- bearerToken:
345
- input.globals.bearerToken ??
346
- input.globals.oauthToken ??
347
- tokenFromProfile ??
348
- undefined,
349
- };
350
-
351
- const final = applyAuth(
352
- headers,
353
- url,
354
- input.action,
355
- globalsWithProfileAuth,
356
- input.authSchemes,
357
- );
358
-
359
- const req = new Request(final.url.toString(), {
360
- method: input.action.method,
361
- headers: final.headers,
362
- body,
363
- });
364
-
365
- const curl = buildCurl(req, body);
366
- return { request: req, curl };
367
- }
368
-
369
- function buildCurl(req: Request, body: string | undefined): string {
370
- const parts: string[] = ["curl", "-sS", "-X", req.method];
371
- for (const [k, v] of req.headers.entries()) {
372
- parts.push("-H", shellQuote(`${k}: ${v}`));
373
- }
374
- if (typeof body === "string") {
375
- parts.push("--data", shellQuote(body));
376
- }
377
- parts.push(shellQuote(req.url));
378
- return parts.join(" ");
379
- }
380
-
381
- function shellQuote(value: string): string {
382
- return `'${value.replace(/'/g, `'\\''`)}'`;
383
- }
384
-
385
- function optionKeyFromFlag(flag: string): string {
386
- // Commander uses camelCase property names derived from long flag.
387
- // Example: --x-request-id -> xRequestId
388
- const name = flag.replace(/^--/, "");
389
- return name.replace(/-([a-z])/g, (_, c) => String(c).toUpperCase());
390
- }
@@ -1,45 +0,0 @@
1
- import type { ServerInfo } from "../server.ts";
2
-
3
- import { applyTemplate, extractTemplateVars } from "./template.ts";
4
-
5
- export type ResolveServerInput = {
6
- serverOverride?: string;
7
- servers: ServerInfo[];
8
- serverVars: Record<string, string>;
9
- };
10
-
11
- export function resolveServerUrl(input: ResolveServerInput): string {
12
- // Treat empty string as undefined (serverOverride can come from env vars or profiles)
13
- const base = input.serverOverride || input.servers[0]?.url;
14
- if (!base) {
15
- throw new Error(
16
- "No server URL found. Provide --server <url> or define servers in the OpenAPI spec.",
17
- );
18
- }
19
-
20
- const names = extractTemplateVars(base);
21
- if (!names.length) return base;
22
-
23
- const vars: Record<string, string> = {};
24
- for (const name of names) {
25
- const provided = input.serverVars[name];
26
- if (typeof provided === "string") {
27
- vars[name] = provided;
28
- continue;
29
- }
30
-
31
- // If spec has default for this var, use it.
32
- const match = input.servers.find((s) => s.url === base);
33
- const v = match?.variables.find((x) => x.name === name);
34
- if (typeof v?.default === "string") {
35
- vars[name] = v.default;
36
- continue;
37
- }
38
-
39
- throw new Error(
40
- `Missing server variable '${name}'. Provide --server-var ${name}=...`,
41
- );
42
- }
43
-
44
- return applyTemplate(base, vars);
45
- }
@@ -1,26 +0,0 @@
1
- export function extractTemplateVars(template: string): string[] {
2
- const out: string[] = [];
3
- const re = /\{([^}]+)\}/g;
4
- while (true) {
5
- const match = re.exec(template);
6
- if (!match) break;
7
- out.push((match[1] ?? "").trim());
8
- }
9
- return out.filter(Boolean);
10
- }
11
-
12
- export function applyTemplate(
13
- template: string,
14
- vars: Record<string, string>,
15
- options?: { encode?: boolean },
16
- ): string {
17
- const encode = options?.encode ?? false;
18
- return template.replace(/\{([^}]+)\}/g, (_, rawName) => {
19
- const name = String(rawName).trim();
20
- const value = vars[name];
21
- if (typeof value !== "string") {
22
- throw new Error(`Missing template variable: ${name}`);
23
- }
24
- return encode ? encodeURIComponent(value) : value;
25
- });
26
- }
@@ -1,13 +0,0 @@
1
- import Ajv from "ajv";
2
- import addFormats from "ajv-formats";
3
-
4
- export function createAjv() {
5
- const ajv = new Ajv({
6
- allErrors: true,
7
- strict: false,
8
- coerceTypes: false,
9
- });
10
-
11
- addFormats(ajv);
12
- return ajv;
13
- }
@@ -1,71 +0,0 @@
1
- import { InvalidArgumentError } from "commander";
2
-
3
- import type { ParamType } from "../../schema-shape.ts";
4
-
5
- export function coerceValue(raw: string, type: ParamType): unknown {
6
- if (type === "string" || type === "unknown") return raw;
7
-
8
- if (type === "boolean") {
9
- // Commander boolean options are handled without a value; keep for completeness.
10
- if (raw === "true") return true;
11
- if (raw === "false") return false;
12
- throw new InvalidArgumentError(`Expected boolean, got '${raw}'`);
13
- }
14
-
15
- if (type === "integer") {
16
- const n = Number.parseInt(raw, 10);
17
- if (!Number.isFinite(n))
18
- throw new InvalidArgumentError(`Expected integer, got '${raw}'`);
19
- return n;
20
- }
21
-
22
- if (type === "number") {
23
- const n = Number(raw);
24
- if (!Number.isFinite(n))
25
- throw new InvalidArgumentError(`Expected number, got '${raw}'`);
26
- return n;
27
- }
28
-
29
- // For now, accept objects as JSON strings.
30
- if (type === "object") {
31
- try {
32
- return JSON.parse(raw);
33
- } catch {
34
- throw new InvalidArgumentError(
35
- `Expected JSON object, got '${raw}'. Use --data/--file for complex bodies.`,
36
- );
37
- }
38
- }
39
-
40
- // Arrays should usually be passed as repeatable flags or comma-separated,
41
- // but allow JSON arrays too.
42
- if (type === "array") {
43
- return coerceArrayInput(raw, "string");
44
- }
45
-
46
- return raw;
47
- }
48
-
49
- export function coerceArrayInput(raw: string, itemType: ParamType): unknown[] {
50
- const trimmed = raw.trim();
51
- if (!trimmed) return [];
52
-
53
- if (trimmed.startsWith("[")) {
54
- let parsed: unknown;
55
- try {
56
- parsed = JSON.parse(trimmed);
57
- } catch {
58
- throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
59
- }
60
- if (!Array.isArray(parsed)) {
61
- throw new InvalidArgumentError(`Expected JSON array, got '${raw}'`);
62
- }
63
- return parsed.map((v) => coerceValue(String(v), itemType));
64
- }
65
-
66
- return trimmed
67
- .split(",")
68
- .map((s) => s.trim())
69
- .filter(Boolean)
70
- .map((s) => coerceValue(s, itemType));
71
- }
@@ -1,29 +0,0 @@
1
- import type { ErrorObject } from "ajv";
2
-
3
- export function formatAjvErrors(
4
- errors: ErrorObject[] | null | undefined,
5
- ): string {
6
- if (!errors?.length) return "Invalid input";
7
-
8
- return errors
9
- .map((e) => {
10
- const path = e.instancePath || e.schemaPath || "";
11
-
12
- if (
13
- e.keyword === "required" &&
14
- e.params &&
15
- typeof e.params === "object" &&
16
- "missingProperty" in e.params
17
- ) {
18
- const missing = String(
19
- (e.params as { missingProperty?: unknown }).missingProperty,
20
- );
21
- const where = e.instancePath || "/";
22
- return `${where} missing required property '${missing}'`.trim();
23
- }
24
-
25
- const msg = e.message || "invalid";
26
- return `${path} ${msg}`.trim();
27
- })
28
- .join("\n");
29
- }
@@ -1,4 +0,0 @@
1
- export * from "./ajv.ts";
2
- export * from "./coerce.ts";
3
- export * from "./error.ts";
4
- export * from "./schema.ts";
@@ -1,54 +0,0 @@
1
- import type { CommandAction } from "../../command-model.ts";
2
- import type { JsonSchema } from "../../types.ts";
3
-
4
- export type ValidationSchemas = {
5
- querySchema?: JsonSchema;
6
- headerSchema?: JsonSchema;
7
- cookieSchema?: JsonSchema;
8
- };
9
-
10
- type ObjectSchema = {
11
- type: "object";
12
- properties: Record<string, JsonSchema>;
13
- required?: string[];
14
- };
15
-
16
- export function deriveValidationSchemas(
17
- action: CommandAction,
18
- ): ValidationSchemas {
19
- // We validate only simple containers for now.
20
- // Deep style/encoding differences for OpenAPI params are out of scope for v1.
21
- const query: ObjectSchema = { type: "object", properties: {}, required: [] };
22
- const header: ObjectSchema = { type: "object", properties: {}, required: [] };
23
- const cookie: ObjectSchema = { type: "object", properties: {}, required: [] };
24
-
25
- for (const p of action.params) {
26
- if (p.kind !== "flag") continue;
27
- const target =
28
- p.in === "query"
29
- ? query
30
- : p.in === "header"
31
- ? header
32
- : p.in === "cookie"
33
- ? cookie
34
- : undefined;
35
- if (!target) continue;
36
-
37
- const schema = p.schema ?? (p.type === "unknown" ? {} : { type: p.type });
38
- target.properties[p.name] = schema;
39
- if (p.required) {
40
- if (!target.required) target.required = [];
41
- target.required.push(p.name);
42
- }
43
- }
44
-
45
- if (!query.required?.length) delete query.required;
46
- if (!header.required?.length) delete header.required;
47
- if (!cookie.required?.length) delete cookie.required;
48
-
49
- return {
50
- querySchema: Object.keys(query.properties).length ? query : undefined,
51
- headerSchema: Object.keys(header.properties).length ? header : undefined,
52
- cookieSchema: Object.keys(cookie.properties).length ? cookie : undefined,
53
- };
54
- }
@@ -1,36 +0,0 @@
1
- export type ParamType =
2
- | "string"
3
- | "number"
4
- | "integer"
5
- | "boolean"
6
- | "array"
7
- | "object"
8
- | "unknown";
9
-
10
- export function getSchemaType(schema: unknown): ParamType {
11
- if (!schema || typeof schema !== "object") return "unknown";
12
- const t = (schema as { type?: unknown }).type;
13
- if (t === "string") return "string";
14
- if (t === "number") return "number";
15
- if (t === "integer") return "integer";
16
- if (t === "boolean") return "boolean";
17
- if (t === "array") return "array";
18
- if (t === "object") return "object";
19
- return "unknown";
20
- }
21
-
22
- export function getSchemaFormat(schema: unknown): string | undefined {
23
- if (!schema || typeof schema !== "object") return undefined;
24
- const f = (schema as { format?: unknown }).format;
25
- return typeof f === "string" ? f : undefined;
26
- }
27
-
28
- export function getSchemaEnumStrings(schema: unknown): string[] | undefined {
29
- if (!schema || typeof schema !== "object") return undefined;
30
- const e = (schema as { enum?: unknown }).enum;
31
- if (!Array.isArray(e)) return undefined;
32
-
33
- // We only surface string enums for now (enough for flag docs + completion).
34
- const values = e.filter((v) => typeof v === "string") as string[];
35
- return values.length ? values : undefined;
36
- }