@redocly/cli 1.34.3 → 2.0.0-next.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 (321) hide show
  1. package/README.md +34 -3
  2. package/bin/cli.js +1 -1
  3. package/lib/auth/device-flow.d.ts +1 -0
  4. package/lib/auth/device-flow.d.ts.map +1 -0
  5. package/lib/auth/device-flow.js +15 -17
  6. package/lib/auth/device-flow.js.map +1 -0
  7. package/lib/auth/oauth-client.d.ts +1 -0
  8. package/lib/auth/oauth-client.d.ts.map +1 -0
  9. package/lib/auth/oauth-client.js +21 -23
  10. package/lib/auth/oauth-client.js.map +1 -0
  11. package/lib/commands/auth.d.ts +3 -5
  12. package/lib/commands/auth.d.ts.map +1 -0
  13. package/lib/commands/auth.js +19 -44
  14. package/lib/commands/auth.js.map +1 -0
  15. package/lib/commands/build-docs/index.d.ts +4 -3
  16. package/lib/commands/build-docs/index.d.ts.map +1 -0
  17. package/lib/commands/build-docs/index.js +23 -24
  18. package/lib/commands/build-docs/index.js.map +1 -0
  19. package/lib/commands/build-docs/types.d.ts +2 -1
  20. package/lib/commands/build-docs/types.d.ts.map +1 -0
  21. package/lib/commands/build-docs/types.js +2 -2
  22. package/lib/commands/build-docs/types.js.map +1 -0
  23. package/lib/commands/build-docs/utils.d.ts +3 -2
  24. package/lib/commands/build-docs/utils.d.ts.map +1 -0
  25. package/lib/commands/build-docs/utils.js +35 -37
  26. package/lib/commands/build-docs/utils.js.map +1 -0
  27. package/lib/commands/bundle.d.ts +6 -3
  28. package/lib/commands/bundle.d.ts.map +1 -0
  29. package/lib/commands/bundle.js +34 -38
  30. package/lib/commands/bundle.js.map +1 -0
  31. package/lib/commands/eject.d.ts +3 -2
  32. package/lib/commands/eject.d.ts.map +1 -0
  33. package/lib/commands/eject.js +11 -13
  34. package/lib/commands/eject.js.map +1 -0
  35. package/lib/commands/join.d.ts +4 -3
  36. package/lib/commands/join.d.ts.map +1 -0
  37. package/lib/commands/join.js +79 -81
  38. package/lib/commands/join.js.map +1 -0
  39. package/lib/commands/lint.d.ts +8 -6
  40. package/lib/commands/lint.d.ts.map +1 -0
  41. package/lib/commands/lint.js +53 -62
  42. package/lib/commands/lint.js.map +1 -0
  43. package/lib/commands/preview-project/constants.d.ts +2 -1
  44. package/lib/commands/preview-project/constants.d.ts.map +1 -0
  45. package/lib/commands/preview-project/constants.js +4 -6
  46. package/lib/commands/preview-project/constants.js.map +1 -0
  47. package/lib/commands/preview-project/index.d.ts +3 -2
  48. package/lib/commands/preview-project/index.d.ts.map +1 -0
  49. package/lib/commands/preview-project/index.js +21 -23
  50. package/lib/commands/preview-project/index.js.map +1 -0
  51. package/lib/commands/preview-project/types.d.ts +3 -2
  52. package/lib/commands/preview-project/types.d.ts.map +1 -0
  53. package/lib/commands/preview-project/types.js +2 -2
  54. package/lib/commands/preview-project/types.js.map +1 -0
  55. package/lib/commands/split/index.d.ts +4 -3
  56. package/lib/commands/split/index.d.ts.map +1 -0
  57. package/lib/commands/split/index.js +53 -57
  58. package/lib/commands/split/index.js.map +1 -0
  59. package/lib/commands/split/types.d.ts +2 -2
  60. package/lib/commands/split/types.d.ts.map +1 -0
  61. package/lib/commands/split/types.js +11 -13
  62. package/lib/commands/split/types.js.map +1 -0
  63. package/lib/commands/stats.d.ts +3 -2
  64. package/lib/commands/stats.d.ts.map +1 -0
  65. package/lib/commands/stats.js +21 -24
  66. package/lib/commands/stats.js.map +1 -0
  67. package/lib/commands/translations.d.ts +3 -2
  68. package/lib/commands/translations.d.ts.map +1 -0
  69. package/lib/commands/translations.js +11 -13
  70. package/lib/commands/translations.js.map +1 -0
  71. package/lib/index.d.ts +2 -1
  72. package/lib/index.d.ts.map +1 -0
  73. package/lib/index.js +109 -239
  74. package/lib/index.js.map +1 -0
  75. package/lib/otel.d.ts +2 -1
  76. package/lib/otel.d.ts.map +1 -0
  77. package/lib/otel.js +22 -23
  78. package/lib/otel.js.map +1 -0
  79. package/lib/reunite/api/api-client.d.ts +4 -3
  80. package/lib/reunite/api/api-client.d.ts.map +1 -0
  81. package/lib/reunite/api/api-client.js +14 -20
  82. package/lib/reunite/api/api-client.js.map +1 -0
  83. package/lib/reunite/api/api-keys.d.ts +2 -1
  84. package/lib/reunite/api/api-keys.d.ts.map +1 -0
  85. package/lib/reunite/api/api-keys.js +4 -20
  86. package/lib/reunite/api/api-keys.js.map +1 -0
  87. package/lib/reunite/api/domains.d.ts +5 -2
  88. package/lib/reunite/api/domains.d.ts.map +1 -0
  89. package/lib/reunite/api/domains.js +6 -15
  90. package/lib/reunite/api/domains.js.map +1 -0
  91. package/lib/reunite/api/index.d.ts +4 -3
  92. package/lib/reunite/api/index.d.ts.map +1 -0
  93. package/lib/reunite/api/index.js +4 -19
  94. package/lib/reunite/api/index.js.map +1 -0
  95. package/lib/reunite/api/types.d.ts +1 -0
  96. package/lib/reunite/api/types.d.ts.map +1 -0
  97. package/lib/reunite/api/types.js +2 -2
  98. package/lib/reunite/api/types.js.map +1 -0
  99. package/lib/reunite/commands/push-status.d.ts +6 -5
  100. package/lib/reunite/commands/push-status.d.ts.map +1 -0
  101. package/lib/reunite/commands/push-status.js +31 -37
  102. package/lib/reunite/commands/push-status.js.map +1 -0
  103. package/lib/reunite/commands/push.d.ts +6 -6
  104. package/lib/reunite/commands/push.d.ts.map +1 -0
  105. package/lib/reunite/commands/push.js +31 -40
  106. package/lib/reunite/commands/push.js.map +1 -0
  107. package/lib/reunite/commands/utils.d.ts +4 -3
  108. package/lib/reunite/commands/utils.d.ts.map +1 -0
  109. package/lib/reunite/commands/utils.js +9 -12
  110. package/lib/reunite/commands/utils.js.map +1 -0
  111. package/lib/reunite/utils.d.ts +1 -0
  112. package/lib/reunite/utils.d.ts.map +1 -0
  113. package/lib/reunite/utils.js +2 -5
  114. package/lib/reunite/utils.js.map +1 -0
  115. package/lib/types.d.ts +15 -27
  116. package/lib/types.d.ts.map +1 -0
  117. package/lib/types.js +2 -5
  118. package/lib/types.js.map +1 -0
  119. package/lib/utils/assert-node-version.d.ts +1 -0
  120. package/lib/utils/assert-node-version.d.ts.map +1 -0
  121. package/lib/utils/assert-node-version.js +8 -10
  122. package/lib/utils/assert-node-version.js.map +1 -0
  123. package/lib/utils/error.d.ts +4 -0
  124. package/lib/utils/error.d.ts.map +1 -0
  125. package/lib/utils/error.js +8 -0
  126. package/lib/utils/error.js.map +1 -0
  127. package/lib/utils/fetch-with-timeout.d.ts +1 -0
  128. package/lib/utils/fetch-with-timeout.d.ts.map +1 -0
  129. package/lib/utils/fetch-with-timeout.js +6 -8
  130. package/lib/utils/fetch-with-timeout.js.map +1 -0
  131. package/lib/utils/{getCommandNameFromArgs.d.ts → get-command-name-from-args.d.ts} +1 -0
  132. package/lib/utils/get-command-name-from-args.d.ts.map +1 -0
  133. package/lib/utils/get-command-name-from-args.js +4 -0
  134. package/lib/utils/get-command-name-from-args.js.map +1 -0
  135. package/lib/utils/js-utils.d.ts +1 -0
  136. package/lib/utils/js-utils.d.ts.map +1 -0
  137. package/lib/utils/js-utils.js +8 -12
  138. package/lib/utils/js-utils.js.map +1 -0
  139. package/lib/utils/miscellaneous.d.ts +9 -48
  140. package/lib/utils/miscellaneous.d.ts.map +1 -0
  141. package/lib/utils/miscellaneous.js +131 -269
  142. package/lib/utils/miscellaneous.js.map +1 -0
  143. package/lib/utils/package.d.ts +2 -0
  144. package/lib/utils/package.d.ts.map +1 -0
  145. package/lib/utils/package.js +4 -0
  146. package/lib/utils/package.js.map +1 -0
  147. package/lib/utils/platform.d.ts +1 -0
  148. package/lib/utils/platform.d.ts.map +1 -0
  149. package/lib/utils/platform.js +5 -9
  150. package/lib/utils/platform.js.map +1 -0
  151. package/lib/utils/proxy-agent.d.ts +3 -0
  152. package/lib/utils/proxy-agent.d.ts.map +1 -0
  153. package/lib/utils/proxy-agent.js +6 -0
  154. package/lib/utils/proxy-agent.js.map +1 -0
  155. package/lib/utils/spinner.d.ts +1 -0
  156. package/lib/utils/spinner.d.ts.map +1 -0
  157. package/lib/utils/spinner.js +8 -10
  158. package/lib/utils/spinner.js.map +1 -0
  159. package/lib/utils/telemetry.d.ts +40 -0
  160. package/lib/utils/telemetry.d.ts.map +1 -0
  161. package/lib/utils/telemetry.js +138 -0
  162. package/lib/utils/telemetry.js.map +1 -0
  163. package/lib/utils/update-version-notifier.d.ts +1 -1
  164. package/lib/utils/update-version-notifier.d.ts.map +1 -0
  165. package/lib/utils/update-version-notifier.js +35 -38
  166. package/lib/utils/update-version-notifier.js.map +1 -0
  167. package/lib/utils/validate-positive-number.d.ts +2 -0
  168. package/lib/utils/validate-positive-number.d.ts.map +1 -0
  169. package/lib/utils/validate-positive-number.js +13 -0
  170. package/lib/utils/validate-positive-number.js.map +1 -0
  171. package/lib/wrapper.d.ts +3 -3
  172. package/lib/wrapper.d.ts.map +1 -0
  173. package/lib/wrapper.js +39 -26
  174. package/lib/wrapper.js.map +1 -0
  175. package/package.json +15 -16
  176. package/CHANGELOG.md +0 -770
  177. package/lib/__mocks__/@redocly/openapi-core.d.ts +0 -99
  178. package/lib/__mocks__/@redocly/openapi-core.js +0 -84
  179. package/lib/__mocks__/documents.d.ts +0 -150
  180. package/lib/__mocks__/documents.js +0 -123
  181. package/lib/__mocks__/fs.d.ts +0 -8
  182. package/lib/__mocks__/fs.js +0 -9
  183. package/lib/__mocks__/perf_hooks.d.ts +0 -3
  184. package/lib/__mocks__/perf_hooks.js +0 -6
  185. package/lib/__mocks__/redoc.d.ts +0 -6
  186. package/lib/__mocks__/redoc.js +0 -5
  187. package/lib/__tests__/commands/build-docs.test.d.ts +0 -1
  188. package/lib/__tests__/commands/build-docs.test.js +0 -54
  189. package/lib/__tests__/commands/bundle.test.d.ts +0 -1
  190. package/lib/__tests__/commands/bundle.test.js +0 -235
  191. package/lib/__tests__/commands/join.test.d.ts +0 -1
  192. package/lib/__tests__/commands/join.test.js +0 -274
  193. package/lib/__tests__/commands/lint.test.d.ts +0 -1
  194. package/lib/__tests__/commands/lint.test.js +0 -149
  195. package/lib/__tests__/commands/push-region.test.d.ts +0 -1
  196. package/lib/__tests__/commands/push-region.test.js +0 -90
  197. package/lib/__tests__/commands/push.test.d.ts +0 -1
  198. package/lib/__tests__/commands/push.test.js +0 -496
  199. package/lib/__tests__/fetch-with-timeout.test.d.ts +0 -1
  200. package/lib/__tests__/fetch-with-timeout.test.js +0 -64
  201. package/lib/__tests__/fixtures/config.d.ts +0 -21
  202. package/lib/__tests__/fixtures/config.js +0 -24
  203. package/lib/__tests__/spinner.test.d.ts +0 -1
  204. package/lib/__tests__/spinner.test.js +0 -43
  205. package/lib/__tests__/utils.test.d.ts +0 -1
  206. package/lib/__tests__/utils.test.js +0 -651
  207. package/lib/__tests__/wrapper.test.d.ts +0 -1
  208. package/lib/__tests__/wrapper.test.js +0 -76
  209. package/lib/auth/__tests__/device-flow.test.d.ts +0 -1
  210. package/lib/auth/__tests__/device-flow.test.js +0 -62
  211. package/lib/auth/__tests__/oauth-client.test.d.ts +0 -1
  212. package/lib/auth/__tests__/oauth-client.test.js +0 -93
  213. package/lib/commands/preview-docs/index.d.ts +0 -12
  214. package/lib/commands/preview-docs/index.js +0 -127
  215. package/lib/commands/preview-docs/preview-server/default.hbs +0 -24
  216. package/lib/commands/preview-docs/preview-server/hot.js +0 -59
  217. package/lib/commands/preview-docs/preview-server/oauth2-redirect.html +0 -21
  218. package/lib/commands/preview-docs/preview-server/preview-server.d.ts +0 -5
  219. package/lib/commands/preview-docs/preview-server/preview-server.js +0 -113
  220. package/lib/commands/preview-docs/preview-server/server.d.ts +0 -22
  221. package/lib/commands/preview-docs/preview-server/server.js +0 -85
  222. package/lib/commands/push.d.ts +0 -44
  223. package/lib/commands/push.js +0 -301
  224. package/lib/commands/split/__tests__/index.test.d.ts +0 -1
  225. package/lib/commands/split/__tests__/index.test.js +0 -91
  226. package/lib/reunite/api/__tests__/api-keys.test.d.ts +0 -1
  227. package/lib/reunite/api/__tests__/api-keys.test.js +0 -26
  228. package/lib/reunite/api/__tests__/api.client.test.d.ts +0 -1
  229. package/lib/reunite/api/__tests__/api.client.test.js +0 -337
  230. package/lib/reunite/api/__tests__/domains.test.d.ts +0 -1
  231. package/lib/reunite/api/__tests__/domains.test.js +0 -32
  232. package/lib/reunite/commands/__tests__/push-status.test.d.ts +0 -1
  233. package/lib/reunite/commands/__tests__/push-status.test.js +0 -563
  234. package/lib/reunite/commands/__tests__/push.test.d.ts +0 -1
  235. package/lib/reunite/commands/__tests__/push.test.js +0 -315
  236. package/lib/reunite/commands/__tests__/utils.test.d.ts +0 -1
  237. package/lib/reunite/commands/__tests__/utils.test.js +0 -51
  238. package/lib/utils/__mocks__/miscellaneous.d.ts +0 -43
  239. package/lib/utils/__mocks__/miscellaneous.js +0 -24
  240. package/lib/utils/getCommandNameFromArgs.js +0 -6
  241. package/src/__mocks__/@redocly/openapi-core.ts +0 -88
  242. package/src/__mocks__/documents.ts +0 -124
  243. package/src/__mocks__/fs.ts +0 -6
  244. package/src/__mocks__/perf_hooks.ts +0 -3
  245. package/src/__mocks__/redoc.ts +0 -2
  246. package/src/__tests__/commands/build-docs.test.ts +0 -59
  247. package/src/__tests__/commands/bundle.test.ts +0 -285
  248. package/src/__tests__/commands/join.test.ts +0 -334
  249. package/src/__tests__/commands/lint.test.ts +0 -190
  250. package/src/__tests__/commands/push-region.test.ts +0 -104
  251. package/src/__tests__/commands/push.test.ts +0 -553
  252. package/src/__tests__/fetch-with-timeout.test.ts +0 -81
  253. package/src/__tests__/fixtures/config.ts +0 -21
  254. package/src/__tests__/fixtures/openapi.json +0 -0
  255. package/src/__tests__/fixtures/openapi.yaml +0 -0
  256. package/src/__tests__/fixtures/redocly.yaml +0 -0
  257. package/src/__tests__/spinner.test.ts +0 -51
  258. package/src/__tests__/utils.test.ts +0 -781
  259. package/src/__tests__/wrapper.test.ts +0 -91
  260. package/src/auth/__tests__/device-flow.test.ts +0 -73
  261. package/src/auth/__tests__/oauth-client.test.ts +0 -117
  262. package/src/auth/device-flow.ts +0 -175
  263. package/src/auth/oauth-client.ts +0 -111
  264. package/src/commands/auth.ts +0 -66
  265. package/src/commands/build-docs/index.ts +0 -55
  266. package/src/commands/build-docs/template.hbs +0 -23
  267. package/src/commands/build-docs/types.ts +0 -25
  268. package/src/commands/build-docs/utils.ts +0 -110
  269. package/src/commands/bundle.ts +0 -154
  270. package/src/commands/eject.ts +0 -42
  271. package/src/commands/join.ts +0 -794
  272. package/src/commands/lint.ts +0 -169
  273. package/src/commands/preview-docs/index.ts +0 -183
  274. package/src/commands/preview-docs/preview-server/default.hbs +0 -24
  275. package/src/commands/preview-docs/preview-server/hot.js +0 -59
  276. package/src/commands/preview-docs/preview-server/oauth2-redirect.html +0 -21
  277. package/src/commands/preview-docs/preview-server/preview-server.ts +0 -159
  278. package/src/commands/preview-docs/preview-server/server.ts +0 -92
  279. package/src/commands/preview-project/constants.ts +0 -23
  280. package/src/commands/preview-project/index.ts +0 -71
  281. package/src/commands/preview-project/types.ts +0 -12
  282. package/src/commands/push.ts +0 -470
  283. package/src/commands/split/__tests__/fixtures/samples.json +0 -61
  284. package/src/commands/split/__tests__/fixtures/spec.json +0 -70
  285. package/src/commands/split/__tests__/fixtures/webhooks.json +0 -85
  286. package/src/commands/split/__tests__/index.test.ts +0 -156
  287. package/src/commands/split/index.ts +0 -397
  288. package/src/commands/split/types.ts +0 -60
  289. package/src/commands/stats.ts +0 -140
  290. package/src/commands/translations.ts +0 -32
  291. package/src/custom.d.ts +0 -1
  292. package/src/index.ts +0 -970
  293. package/src/otel.ts +0 -59
  294. package/src/reunite/api/__tests__/api-keys.test.ts +0 -37
  295. package/src/reunite/api/__tests__/api.client.test.ts +0 -452
  296. package/src/reunite/api/__tests__/domains.test.ts +0 -41
  297. package/src/reunite/api/api-client.ts +0 -381
  298. package/src/reunite/api/api-keys.ts +0 -26
  299. package/src/reunite/api/domains.ts +0 -23
  300. package/src/reunite/api/index.ts +0 -3
  301. package/src/reunite/api/types.ts +0 -108
  302. package/src/reunite/commands/__tests__/push-status.test.ts +0 -653
  303. package/src/reunite/commands/__tests__/push.test.ts +0 -385
  304. package/src/reunite/commands/__tests__/utils.test.ts +0 -62
  305. package/src/reunite/commands/push-status.ts +0 -325
  306. package/src/reunite/commands/push.ts +0 -235
  307. package/src/reunite/commands/utils.ts +0 -66
  308. package/src/reunite/utils.ts +0 -1
  309. package/src/types.ts +0 -64
  310. package/src/utils/__mocks__/miscellaneous.ts +0 -24
  311. package/src/utils/assert-node-version.ts +0 -19
  312. package/src/utils/fetch-with-timeout.ts +0 -30
  313. package/src/utils/getCommandNameFromArgs.ts +0 -5
  314. package/src/utils/js-utils.ts +0 -24
  315. package/src/utils/miscellaneous.ts +0 -729
  316. package/src/utils/platform.ts +0 -31
  317. package/src/utils/spinner.ts +0 -50
  318. package/src/utils/update-version-notifier.ts +0 -115
  319. package/src/wrapper.ts +0 -77
  320. package/tsconfig.json +0 -9
  321. package/tsconfig.tsbuildinfo +0 -1
@@ -1,91 +0,0 @@
1
- import { loadConfigAndHandleErrors, sendTelemetry } from '../utils/miscellaneous';
2
- import * as process from 'process';
3
- import { commandWrapper } from '../wrapper';
4
- import { handleLint } from '../commands/lint';
5
- import { Arguments } from 'yargs';
6
- import { handlePush, PushOptions } from '../commands/push';
7
- import { detectSpec } from '@redocly/openapi-core';
8
-
9
- const mockFetch = jest.fn();
10
- const originalFetch = global.fetch;
11
-
12
- jest.mock('../utils/miscellaneous', () => ({
13
- sendTelemetry: jest.fn(),
14
- loadConfigAndHandleErrors: jest.fn(),
15
- }));
16
-
17
- beforeAll(() => {
18
- global.fetch = mockFetch;
19
- });
20
-
21
- afterAll(() => {
22
- jest.resetAllMocks();
23
- global.fetch = originalFetch;
24
- });
25
-
26
- jest.mock('../commands/lint', () => ({
27
- handleLint: jest.fn().mockImplementation(({ collectSpecData }) => {
28
- collectSpecData({ openapi: '3.1.0' });
29
- }),
30
- lintConfigCallback: jest.fn(),
31
- }));
32
-
33
- describe('commandWrapper', () => {
34
- it('should send telemetry if there is "telemetry: on" in the config', async () => {
35
- (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
36
- return { telemetry: 'on', styleguide: { recommendedFallback: true } };
37
- });
38
- (detectSpec as jest.Mock).mockImplementationOnce(() => {
39
- return 'oas3_1';
40
- });
41
- process.env.REDOCLY_TELEMETRY = 'on';
42
-
43
- const wrappedHandler = commandWrapper(handleLint);
44
- await wrappedHandler({} as any);
45
- expect(handleLint).toHaveBeenCalledTimes(1);
46
- expect(sendTelemetry).toHaveBeenCalledTimes(1);
47
- expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false, 'oas3_1', 'openapi', '3.1.0');
48
- });
49
-
50
- it('should not collect spec version if the file is not parsed to json', async () => {
51
- (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
52
- return { telemetry: 'on', styleguide: { recommendedFallback: true } };
53
- });
54
- (handleLint as jest.Mock).mockImplementation(({ collectSpecData }) => {
55
- collectSpecData();
56
- });
57
- process.env.REDOCLY_TELEMETRY = 'on';
58
-
59
- const wrappedHandler = commandWrapper(handleLint);
60
- await wrappedHandler({} as any);
61
- expect(handleLint).toHaveBeenCalledTimes(1);
62
- expect(sendTelemetry).toHaveBeenCalledTimes(1);
63
- expect(sendTelemetry).toHaveBeenCalledWith({}, 0, false, undefined, undefined, undefined);
64
- });
65
-
66
- it('should NOT send telemetry if there is "telemetry: off" in the config', async () => {
67
- (loadConfigAndHandleErrors as jest.Mock).mockImplementation(() => {
68
- return { telemetry: 'off', styleguide: { recommendedFallback: true } };
69
- });
70
- process.env.REDOCLY_TELEMETRY = 'on';
71
-
72
- const wrappedHandler = commandWrapper(handleLint);
73
- await wrappedHandler({} as any);
74
- expect(handleLint).toHaveBeenCalledTimes(1);
75
-
76
- expect(sendTelemetry).toHaveBeenCalledTimes(0);
77
- });
78
-
79
- it('should pass files from arguments to config', async () => {
80
- const filesToPush = ['test1.yaml', 'test2.yaml'];
81
-
82
- const loadConfigMock = loadConfigAndHandleErrors as jest.Mock<any, any>;
83
-
84
- const argv = {
85
- files: filesToPush,
86
- } as Arguments<PushOptions>;
87
-
88
- await commandWrapper(handlePush)(argv);
89
- expect(loadConfigMock).toHaveBeenCalledWith(expect.objectContaining({ files: filesToPush }));
90
- });
91
- });
@@ -1,73 +0,0 @@
1
- import { RedoclyOAuthDeviceFlow } from '../device-flow';
2
-
3
- jest.mock('child_process');
4
-
5
- describe('RedoclyOAuthDeviceFlow', () => {
6
- const mockBaseUrl = 'https://test.redocly.com';
7
- const mockClientName = 'test-client';
8
- const mockVersion = '1.0.0';
9
- let flow: RedoclyOAuthDeviceFlow;
10
-
11
- beforeEach(() => {
12
- flow = new RedoclyOAuthDeviceFlow(mockBaseUrl, mockClientName, mockVersion);
13
- jest.resetAllMocks();
14
- });
15
-
16
- describe('verifyToken', () => {
17
- it('returns true for valid token', async () => {
18
- jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
19
- json: () => Promise.resolve({ user: { id: '123' } }),
20
- } as Response);
21
-
22
- const result = await flow.verifyToken('valid-token');
23
- expect(result).toBe(true);
24
- });
25
-
26
- it('returns false for invalid token', async () => {
27
- jest.spyOn(flow['apiClient'], 'request').mockRejectedValue(new Error('Invalid token'));
28
- const result = await flow.verifyToken('invalid-token');
29
- expect(result).toBe(false);
30
- });
31
- });
32
-
33
- describe('verifyApiKey', () => {
34
- it('returns true for valid API key', async () => {
35
- jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
36
- json: () => Promise.resolve({ success: true }),
37
- } as Response);
38
-
39
- const result = await flow.verifyApiKey('valid-key');
40
- expect(result).toBe(true);
41
- });
42
-
43
- it('returns false for invalid API key', async () => {
44
- jest.spyOn(flow['apiClient'], 'request').mockRejectedValue(new Error('Invalid API key'));
45
- const result = await flow.verifyApiKey('invalid-key');
46
- expect(result).toBe(false);
47
- });
48
- });
49
-
50
- describe('refreshToken', () => {
51
- it('successfully refreshes token', async () => {
52
- const mockResponse = {
53
- access_token: 'new-token',
54
- refresh_token: 'new-refresh',
55
- expires_in: 3600,
56
- };
57
- jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
58
- json: () => Promise.resolve(mockResponse),
59
- } as Response);
60
-
61
- const result = await flow.refreshToken('old-refresh-token');
62
- expect(result).toEqual(mockResponse);
63
- });
64
-
65
- it('throws error when refresh fails', async () => {
66
- jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
67
- json: () => Promise.resolve({}),
68
- } as Response);
69
-
70
- await expect(flow.refreshToken('invalid-refresh')).rejects.toThrow('Failed to refresh token');
71
- });
72
- });
73
- });
@@ -1,117 +0,0 @@
1
- import { RedoclyOAuthClient } from '../oauth-client';
2
- import { RedoclyOAuthDeviceFlow } from '../device-flow';
3
- import * as fs from 'node:fs';
4
- import * as path from 'node:path';
5
- import * as os from 'node:os';
6
-
7
- jest.mock('node:fs');
8
- jest.mock('node:os');
9
- jest.mock('../device-flow');
10
-
11
- describe('RedoclyOAuthClient', () => {
12
- const mockClientName = 'test-client';
13
- const mockVersion = '1.0.0';
14
- const mockBaseUrl = 'https://test.redocly.com';
15
- const mockHomeDir = '/mock/home/dir';
16
- const mockRedoclyDir = path.join(mockHomeDir, '.redocly');
17
- let client: RedoclyOAuthClient;
18
-
19
- beforeEach(() => {
20
- jest.resetAllMocks();
21
- (os.homedir as jest.Mock).mockReturnValue(mockHomeDir);
22
- process.env.HOME = mockHomeDir;
23
- client = new RedoclyOAuthClient(mockClientName, mockVersion);
24
- });
25
-
26
- describe('login', () => {
27
- it('successfully logs in and saves token', async () => {
28
- const mockToken = { access_token: 'test-token' };
29
- const mockDeviceFlow = {
30
- run: jest.fn().mockResolvedValue(mockToken),
31
- };
32
- (RedoclyOAuthDeviceFlow as jest.Mock).mockImplementation(() => mockDeviceFlow);
33
-
34
- await client.login(mockBaseUrl);
35
-
36
- expect(mockDeviceFlow.run).toHaveBeenCalled();
37
- expect(fs.writeFileSync).toHaveBeenCalled();
38
- });
39
-
40
- it('throws error when login fails', async () => {
41
- const mockDeviceFlow = {
42
- run: jest.fn().mockResolvedValue(null),
43
- };
44
- (RedoclyOAuthDeviceFlow as jest.Mock).mockImplementation(() => mockDeviceFlow);
45
-
46
- await expect(client.login(mockBaseUrl)).rejects.toThrow('Failed to login');
47
- });
48
- });
49
-
50
- describe('logout', () => {
51
- it('removes token file if it exists', async () => {
52
- (fs.existsSync as jest.Mock).mockReturnValue(true);
53
-
54
- await client.logout();
55
-
56
- expect(fs.rmSync).toHaveBeenCalledWith(path.join(mockRedoclyDir, 'auth.json'));
57
- });
58
-
59
- it('silently fails if token file does not exist', async () => {
60
- (fs.existsSync as jest.Mock).mockReturnValue(false);
61
-
62
- await expect(client.logout()).resolves.not.toThrow();
63
- expect(fs.rmSync).not.toHaveBeenCalled();
64
- });
65
- });
66
-
67
- describe('isAuthorized', () => {
68
- it('verifies API key if provided', async () => {
69
- const mockDeviceFlow = {
70
- verifyApiKey: jest.fn().mockResolvedValue(true),
71
- };
72
- (RedoclyOAuthDeviceFlow as jest.Mock).mockImplementation(() => mockDeviceFlow);
73
-
74
- const result = await client.isAuthorized(mockBaseUrl, 'test-api-key');
75
-
76
- expect(result).toBe(true);
77
- expect(mockDeviceFlow.verifyApiKey).toHaveBeenCalledWith('test-api-key');
78
- });
79
-
80
- it('verifies access token if no API key provided', async () => {
81
- const mockToken = { access_token: 'test-token' };
82
- const mockDeviceFlow = {
83
- verifyToken: jest.fn().mockResolvedValue(true),
84
- };
85
- (RedoclyOAuthDeviceFlow as jest.Mock).mockImplementation(() => mockDeviceFlow);
86
- (fs.readFileSync as jest.Mock).mockReturnValue(
87
- client['cipher'].update(JSON.stringify(mockToken), 'utf8', 'hex') +
88
- client['cipher'].final('hex')
89
- );
90
-
91
- const result = await client.isAuthorized(mockBaseUrl);
92
-
93
- expect(result).toBe(true);
94
- expect(mockDeviceFlow.verifyToken).toHaveBeenCalledWith('test-token');
95
- });
96
-
97
- it('returns false if token refresh fails', async () => {
98
- const mockToken = {
99
- access_token: 'old-token',
100
- refresh_token: 'refresh-token',
101
- };
102
- const mockDeviceFlow = {
103
- verifyToken: jest.fn().mockResolvedValue(false),
104
- refreshToken: jest.fn().mockRejectedValue(new Error('Refresh failed')),
105
- };
106
- (RedoclyOAuthDeviceFlow as jest.Mock).mockImplementation(() => mockDeviceFlow);
107
- (fs.readFileSync as jest.Mock).mockReturnValue(
108
- client['cipher'].update(JSON.stringify(mockToken), 'utf8', 'hex') +
109
- client['cipher'].final('hex')
110
- );
111
-
112
- const result = await client.isAuthorized(mockBaseUrl);
113
-
114
- expect(result).toBe(false);
115
- });
116
- });
117
- });
@@ -1,175 +0,0 @@
1
- import { blue, green } from 'colorette';
2
- import * as childProcess from 'child_process';
3
- import { ReuniteApiClient } from '../reunite/api/api-client';
4
-
5
- export type AuthToken = {
6
- access_token: string;
7
- refresh_token?: string;
8
- token_type?: string;
9
- expires_in?: number;
10
- };
11
-
12
- export class RedoclyOAuthDeviceFlow {
13
- private apiClient: ReuniteApiClient;
14
-
15
- constructor(private baseUrl: string, private clientName: string, private version: string) {
16
- this.apiClient = new ReuniteApiClient(this.version, 'login');
17
- }
18
-
19
- async run() {
20
- const code = await this.getDeviceCode();
21
- process.stdout.write(
22
- 'Attempting to automatically open the SSO authorization page in your default browser.\n'
23
- );
24
- process.stdout.write(
25
- 'If the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\n'
26
- );
27
- process.stdout.write(blue(code.verificationUri));
28
- process.stdout.write(`\n\n`);
29
- process.stdout.write(`Then enter the code:\n\n`);
30
- process.stdout.write(blue(code.userCode));
31
- process.stdout.write(`\n\n`);
32
-
33
- this.openBrowser(code.verificationUriComplete);
34
-
35
- const accessToken = await this.pollingAccessToken(
36
- code.deviceCode,
37
- code.interval,
38
- code.expiresIn
39
- );
40
- process.stdout.write(green('āœ… Logged in\n\n'));
41
-
42
- return accessToken;
43
- }
44
-
45
- private openBrowser(url: string) {
46
- try {
47
- const cmd =
48
- process.platform === 'win32'
49
- ? `start ${url}`
50
- : process.platform === 'darwin'
51
- ? `open ${url}`
52
- : `xdg-open ${url}`;
53
-
54
- childProcess.execSync(cmd);
55
- } catch {
56
- // silently fail if browser cannot be opened
57
- }
58
- }
59
-
60
- async verifyToken(accessToken: string) {
61
- try {
62
- const response = await this.sendRequest('/session', 'GET', undefined, {
63
- Cookie: `accessToken=${accessToken};`,
64
- });
65
-
66
- return !!response.user;
67
- } catch {
68
- return false;
69
- }
70
- }
71
-
72
- async verifyApiKey(apiKey: string) {
73
- try {
74
- const response = await this.sendRequest('/api-keys-verify', 'POST', {
75
- apiKey,
76
- });
77
- return !!response.success;
78
- } catch {
79
- return false;
80
- }
81
- }
82
-
83
- async refreshToken(refreshToken: string) {
84
- const response = await this.sendRequest(`/device-rotate-token`, 'POST', {
85
- grant_type: 'refresh_token',
86
- client_name: this.clientName,
87
- refresh_token: refreshToken,
88
- });
89
-
90
- if (!response.access_token) {
91
- throw new Error('Failed to refresh token');
92
- }
93
- return {
94
- access_token: response.access_token,
95
- refresh_token: response.refresh_token,
96
- expires_in: response.expires_in,
97
- };
98
- }
99
-
100
- private async pollingAccessToken(
101
- deviceCode: string,
102
- interval: number,
103
- expiresIn: number
104
- ): Promise<AuthToken> {
105
- return new Promise((resolve, reject) => {
106
- const intervalId = setInterval(async () => {
107
- const response = await this.getAccessToken(deviceCode);
108
- if (response.access_token) {
109
- clearInterval(intervalId);
110
- clearTimeout(timeoutId);
111
- resolve(response);
112
- }
113
- if (response.error && response.error !== 'authorization_pending') {
114
- clearInterval(intervalId);
115
- clearTimeout(timeoutId);
116
- reject(response.error_description);
117
- }
118
- }, interval * 1000);
119
-
120
- const timeoutId = setTimeout(async () => {
121
- clearInterval(intervalId);
122
- clearTimeout(timeoutId);
123
- reject('Authorization has expired. Please try again.');
124
- }, expiresIn * 1000);
125
- });
126
- }
127
-
128
- private async getAccessToken(deviceCode: string) {
129
- return await this.sendRequest('/device-token', 'POST', {
130
- client_name: this.clientName,
131
- device_code: deviceCode,
132
- grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
133
- });
134
- }
135
-
136
- private async getDeviceCode() {
137
- const {
138
- device_code: deviceCode,
139
- user_code: userCode,
140
- verification_uri: verificationUri,
141
- verification_uri_complete: verificationUriComplete,
142
- interval = 10,
143
- expires_in: expiresIn = 300,
144
- } = await this.sendRequest('/device-authorize', 'POST', {
145
- client_name: this.clientName,
146
- });
147
-
148
- return {
149
- deviceCode,
150
- userCode,
151
- verificationUri,
152
- verificationUriComplete,
153
- interval,
154
- expiresIn,
155
- };
156
- }
157
-
158
- private async sendRequest(
159
- url: string,
160
- method: string = 'GET',
161
- body: Record<string, unknown> | undefined = undefined,
162
- headers: Record<string, string> = {}
163
- ) {
164
- url = `${this.baseUrl}${url}`;
165
- const response = await this.apiClient.request(url, {
166
- body: body ? JSON.stringify(body) : body,
167
- method,
168
- headers: { 'Content-Type': 'application/json', ...headers },
169
- });
170
- if (response.status === 204) {
171
- return { success: true };
172
- }
173
- return await response.json();
174
- }
175
- }
@@ -1,111 +0,0 @@
1
- import { homedir } from 'node:os';
2
- import * as path from 'node:path';
3
- import { mkdirSync, existsSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
4
- import * as crypto from 'node:crypto';
5
- import { Buffer } from 'node:buffer';
6
- import { type AuthToken, RedoclyOAuthDeviceFlow } from './device-flow';
7
-
8
- const SALT = '4618dbc9-8aed-4e27-aaf0-225f4603e5a4';
9
- const CRYPTO_ALGORITHM = 'aes-256-cbc';
10
-
11
- export class RedoclyOAuthClient {
12
- private dir: string;
13
- private cipher: crypto.Cipher;
14
- private decipher: crypto.Decipher;
15
-
16
- constructor(private clientName: string, private version: string) {
17
- this.dir = path.join(homedir(), '.redocly');
18
- if (!existsSync(this.dir)) {
19
- mkdirSync(this.dir);
20
- }
21
-
22
- const homeDirPath = process.env.HOME as string;
23
- const hash = crypto.createHash('sha256');
24
- hash.update(`${homeDirPath}${SALT}`);
25
- const hashHex = hash.digest('hex');
26
-
27
- const key = Buffer.alloc(
28
- 32,
29
- Buffer.from(hashHex).toString('base64')
30
- ).toString() as crypto.CipherKey;
31
- const iv = Buffer.alloc(
32
- 16,
33
- Buffer.from(process.env.HOME as string).toString('base64')
34
- ).toString() as crypto.BinaryLike;
35
- this.cipher = crypto.createCipheriv(CRYPTO_ALGORITHM, key, iv);
36
- this.decipher = crypto.createDecipheriv(CRYPTO_ALGORITHM, key, iv);
37
- }
38
-
39
- async login(baseUrl: string) {
40
- const deviceFlow = new RedoclyOAuthDeviceFlow(baseUrl, this.clientName, this.version);
41
-
42
- const token = await deviceFlow.run();
43
- if (!token) {
44
- throw new Error('Failed to login');
45
- }
46
- this.saveToken(token);
47
- }
48
-
49
- async logout() {
50
- try {
51
- this.removeToken();
52
- } catch (err) {
53
- // do nothing
54
- }
55
- }
56
-
57
- async isAuthorized(baseUrl: string, apiKey?: string) {
58
- const deviceFlow = new RedoclyOAuthDeviceFlow(baseUrl, this.clientName, this.version);
59
-
60
- if (apiKey) {
61
- return await deviceFlow.verifyApiKey(apiKey);
62
- }
63
-
64
- const token = await this.readToken();
65
- if (!token) {
66
- return false;
67
- }
68
-
69
- const isValidAccessToken = await deviceFlow.verifyToken(token.access_token);
70
-
71
- if (isValidAccessToken) {
72
- return true;
73
- }
74
-
75
- try {
76
- const newToken = await deviceFlow.refreshToken(token.refresh_token);
77
- await this.saveToken(newToken);
78
- } catch {
79
- return false;
80
- }
81
-
82
- return true;
83
- }
84
-
85
- private async saveToken(token: AuthToken) {
86
- try {
87
- const encrypted =
88
- this.cipher.update(JSON.stringify(token), 'utf8', 'hex') + this.cipher.final('hex');
89
- writeFileSync(path.join(this.dir, 'auth.json'), encrypted);
90
- } catch (error) {
91
- process.stderr.write('Error saving tokens:', error);
92
- }
93
- }
94
-
95
- private async readToken() {
96
- try {
97
- const token = readFileSync(path.join(this.dir, 'auth.json'), 'utf8');
98
- const decrypted = this.decipher.update(token, 'hex', 'utf8') + this.decipher.final('utf8');
99
- return decrypted ? JSON.parse(decrypted) : null;
100
- } catch {
101
- return null;
102
- }
103
- }
104
-
105
- private async removeToken() {
106
- const tokenPath = path.join(this.dir, 'auth.json');
107
- if (existsSync(tokenPath)) {
108
- rmSync(tokenPath);
109
- }
110
- }
111
- }
@@ -1,66 +0,0 @@
1
- import { blue, green, gray, yellow } from 'colorette';
2
- import { RedoclyClient } from '@redocly/openapi-core';
3
- import { exitWithError, promptUser } from '../utils/miscellaneous';
4
- import { RedoclyOAuthClient } from '../auth/oauth-client';
5
- import { getReuniteUrl } from '../reunite/api';
6
-
7
- import type { CommandArgs } from '../wrapper';
8
- import type { Region } from '@redocly/openapi-core';
9
-
10
- export function promptClientToken(domain: string) {
11
- return promptUser(
12
- green(
13
- `\n šŸ”‘ Copy your API key from ${blue(`https://app.${domain}/profile`)} and paste it below`
14
- ) + yellow(' (if you want to log in with Reunite, please run `redocly login --next` instead)'),
15
- true
16
- );
17
- }
18
-
19
- export type LoginOptions = {
20
- verbose?: boolean;
21
- residency?: string;
22
- config?: string;
23
- next?: boolean;
24
- };
25
-
26
- export async function handleLogin({ argv, config, version }: CommandArgs<LoginOptions>) {
27
- if (argv.next) {
28
- try {
29
- const reuniteUrl = getReuniteUrl(argv.residency);
30
- const oauthClient = new RedoclyOAuthClient('redocly-cli', version);
31
- await oauthClient.login(reuniteUrl);
32
- } catch {
33
- if (argv.residency) {
34
- const reuniteUrl = getReuniteUrl(argv.residency);
35
- exitWithError(`āŒ Connection to ${reuniteUrl} failed.`);
36
- } else {
37
- exitWithError(`āŒ Login failed. Please check your credentials and try again.`);
38
- }
39
- }
40
- } else {
41
- try {
42
- const region = (argv.residency as Region) || config.region;
43
- const client = new RedoclyClient(region);
44
- const clientToken = await promptClientToken(client.domain);
45
- process.stdout.write(gray('\n Logging in...\n'));
46
- await client.login(clientToken, argv.verbose);
47
- process.stdout.write(green(' Authorization confirmed. āœ…\n\n'));
48
- } catch (err) {
49
- exitWithError(' ' + err?.message);
50
- }
51
- }
52
- }
53
-
54
- export type LogoutOptions = {
55
- config?: string;
56
- };
57
-
58
- export async function handleLogout({ version }: CommandArgs<LogoutOptions>) {
59
- const client = new RedoclyClient();
60
- client.logout();
61
-
62
- const oauthClient = new RedoclyOAuthClient('redocly-cli', version);
63
- oauthClient.logout();
64
-
65
- process.stdout.write('Logged out from the Redocly account. āœ‹ \n');
66
- }
@@ -1,55 +0,0 @@
1
- import { loadAndBundleSpec } from 'redoc';
2
- import { dirname, resolve } from 'path';
3
- import { writeFileSync, mkdirSync } from 'fs';
4
- import { performance } from 'perf_hooks';
5
- import { getMergedConfig, isAbsoluteUrl } from '@redocly/openapi-core';
6
- import { getObjectOrJSON, getPageHTML } from './utils';
7
- import { exitWithError, getExecutionTime, getFallbackApisOrExit } from '../../utils/miscellaneous';
8
-
9
- import type { BuildDocsArgv } from './types';
10
- import type { CommandArgs } from '../../wrapper';
11
-
12
- export const handlerBuildCommand = async ({
13
- argv,
14
- config: configFromFile,
15
- collectSpecData,
16
- }: CommandArgs<BuildDocsArgv>) => {
17
- const startedAt = performance.now();
18
-
19
- const config = getMergedConfig(configFromFile, argv.api);
20
- const apis = await getFallbackApisOrExit(argv.api ? [argv.api] : [], config);
21
- const { path: pathToApi } = apis[0];
22
-
23
- const options = {
24
- output: argv.o,
25
- title: argv.title,
26
- disableGoogleFont: argv.disableGoogleFont,
27
- templateFileName: argv.template,
28
- templateOptions: argv.templateOptions || {},
29
- redocOptions: getObjectOrJSON(argv.theme?.openapi, config),
30
- };
31
-
32
- const redocCurrentVersion = require('../../../package.json').dependencies.redoc;
33
-
34
- try {
35
- const elapsed = getExecutionTime(startedAt);
36
-
37
- const api = await loadAndBundleSpec(isAbsoluteUrl(pathToApi) ? pathToApi : resolve(pathToApi));
38
- collectSpecData?.(api);
39
- const pageHTML = await getPageHTML(
40
- api,
41
- pathToApi,
42
- { ...options, redocCurrentVersion },
43
- argv.config
44
- );
45
-
46
- mkdirSync(dirname(options.output), { recursive: true });
47
- writeFileSync(options.output, pageHTML);
48
- const sizeInKiB = Math.ceil(Buffer.byteLength(pageHTML) / 1024);
49
- process.stdout.write(
50
- `\nšŸŽ‰ bundled successfully in: ${options.output} (${sizeInKiB} KiB) [ā± ${elapsed}].\n`
51
- );
52
- } catch (e) {
53
- exitWithError(e);
54
- }
55
- };