openapi-typesafe 1.0.0-rc.3 → 1.0.0-rc.5

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 (596) hide show
  1. package/CHANGELOG.md +1972 -0
  2. package/dist/adapters/node-file-system/file-claims.cjs +105 -0
  3. package/dist/adapters/node-file-system/file-claims.cjs.map +1 -0
  4. package/dist/adapters/node-file-system/file-claims.mjs +95 -0
  5. package/dist/adapters/node-file-system/file-claims.mjs.map +1 -0
  6. package/dist/adapters/node-file-system/file-identity.cjs +82 -0
  7. package/dist/adapters/node-file-system/file-identity.cjs.map +1 -0
  8. package/dist/adapters/node-file-system/file-identity.mjs +74 -0
  9. package/dist/adapters/node-file-system/file-identity.mjs.map +1 -0
  10. package/dist/adapters/node-file-system/node-file-system.cjs +97 -14
  11. package/dist/adapters/node-file-system/node-file-system.cjs.map +1 -1
  12. package/dist/adapters/node-file-system/node-file-system.mjs +97 -14
  13. package/dist/adapters/node-file-system/node-file-system.mjs.map +1 -1
  14. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs +19 -0
  15. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.cjs.map +1 -0
  16. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs +17 -0
  17. package/dist/adapters/pipe-safe-writer/pipe-safe-writer.mjs.map +1 -0
  18. package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs +48 -0
  19. package/dist/adapters/redocly-loader/bundled-mapping-copies.cjs.map +1 -0
  20. package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs +45 -0
  21. package/dist/adapters/redocly-loader/bundled-mapping-copies.mjs.map +1 -0
  22. package/dist/adapters/redocly-loader/bundled-ref-repair.cjs +1 -1
  23. package/dist/adapters/redocly-loader/bundled-ref-repair.cjs.map +1 -1
  24. package/dist/adapters/redocly-loader/bundled-ref-repair.mjs +2 -2
  25. package/dist/adapters/redocly-loader/bundled-ref-repair.mjs.map +1 -1
  26. package/dist/adapters/redocly-loader/component-schemas.cjs +17 -0
  27. package/dist/adapters/redocly-loader/component-schemas.cjs.map +1 -0
  28. package/dist/adapters/redocly-loader/component-schemas.mjs +14 -0
  29. package/dist/adapters/redocly-loader/component-schemas.mjs.map +1 -0
  30. package/dist/adapters/redocly-loader/loaded-documents.cjs +28 -0
  31. package/dist/adapters/redocly-loader/loaded-documents.cjs.map +1 -0
  32. package/dist/adapters/redocly-loader/loaded-documents.mjs +21 -0
  33. package/dist/adapters/redocly-loader/loaded-documents.mjs.map +1 -0
  34. package/dist/adapters/redocly-loader/mapping-schema-names.cjs +22 -0
  35. package/dist/adapters/redocly-loader/mapping-schema-names.cjs.map +1 -0
  36. package/dist/adapters/redocly-loader/mapping-schema-names.mjs +20 -0
  37. package/dist/adapters/redocly-loader/mapping-schema-names.mjs.map +1 -0
  38. package/dist/adapters/redocly-loader/query-named-components.cjs +137 -0
  39. package/dist/adapters/redocly-loader/query-named-components.cjs.map +1 -0
  40. package/dist/adapters/redocly-loader/query-named-components.mjs +134 -0
  41. package/dist/adapters/redocly-loader/query-named-components.mjs.map +1 -0
  42. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs +40 -29
  43. package/dist/adapters/redocly-loader/redocly-schema-loader.cjs.map +1 -1
  44. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs +38 -27
  45. package/dist/adapters/redocly-loader/redocly-schema-loader.mjs.map +1 -1
  46. package/dist/adapters/redocly-loader/ref-access.cjs +45 -4
  47. package/dist/adapters/redocly-loader/ref-access.cjs.map +1 -1
  48. package/dist/adapters/redocly-loader/ref-access.mjs +45 -4
  49. package/dist/adapters/redocly-loader/ref-access.mjs.map +1 -1
  50. package/dist/adapters/redocly-loader/ref-holders.cjs +52 -10
  51. package/dist/adapters/redocly-loader/ref-holders.cjs.map +1 -1
  52. package/dist/adapters/redocly-loader/ref-holders.mjs +53 -12
  53. package/dist/adapters/redocly-loader/ref-holders.mjs.map +1 -1
  54. package/dist/adapters/redocly-loader/remote-body-limit.cjs +50 -0
  55. package/dist/adapters/redocly-loader/remote-body-limit.cjs.map +1 -0
  56. package/dist/adapters/redocly-loader/remote-body-limit.mjs +48 -0
  57. package/dist/adapters/redocly-loader/remote-body-limit.mjs.map +1 -0
  58. package/dist/adapters/redocly-loader/remote-fetch.cjs +40 -9
  59. package/dist/adapters/redocly-loader/remote-fetch.cjs.map +1 -1
  60. package/dist/adapters/redocly-loader/remote-fetch.mjs +40 -9
  61. package/dist/adapters/redocly-loader/remote-fetch.mjs.map +1 -1
  62. package/dist/adapters/redocly-loader/remote-node-limit.cjs +61 -0
  63. package/dist/adapters/redocly-loader/remote-node-limit.cjs.map +1 -0
  64. package/dist/adapters/redocly-loader/remote-node-limit.mjs +58 -0
  65. package/dist/adapters/redocly-loader/remote-node-limit.mjs.map +1 -0
  66. package/dist/adapters/redocly-loader/schema-load-errors.cjs +32 -8
  67. package/dist/adapters/redocly-loader/schema-load-errors.cjs.map +1 -1
  68. package/dist/adapters/redocly-loader/schema-load-errors.mjs +32 -9
  69. package/dist/adapters/redocly-loader/schema-load-errors.mjs.map +1 -1
  70. package/dist/adapters/redocly-loader/schema-source.cjs +18 -9
  71. package/dist/adapters/redocly-loader/schema-source.cjs.map +1 -1
  72. package/dist/adapters/redocly-loader/schema-source.mjs +20 -11
  73. package/dist/adapters/redocly-loader/schema-source.mjs.map +1 -1
  74. package/dist/adapters/redocly-loader/unsupported-keys.cjs +3 -5
  75. package/dist/adapters/redocly-loader/unsupported-keys.cjs.map +1 -1
  76. package/dist/adapters/redocly-loader/unsupported-keys.mjs +3 -5
  77. package/dist/adapters/redocly-loader/unsupported-keys.mjs.map +1 -1
  78. package/dist/adapters/terminal-logger/terminal-logger.cjs +10 -4
  79. package/dist/adapters/terminal-logger/terminal-logger.cjs.map +1 -1
  80. package/dist/adapters/terminal-logger/terminal-logger.mjs +10 -4
  81. package/dist/adapters/terminal-logger/terminal-logger.mjs.map +1 -1
  82. package/dist/api/default-ports.cjs +14 -2
  83. package/dist/api/default-ports.cjs.map +1 -1
  84. package/dist/api/default-ports.mjs +14 -2
  85. package/dist/api/default-ports.mjs.map +1 -1
  86. package/dist/api/discriminator-enum-parent.cjs +2 -2
  87. package/dist/api/discriminator-enum-parent.cjs.map +1 -1
  88. package/dist/api/discriminator-enum-parent.mjs +3 -3
  89. package/dist/api/discriminator-enum-parent.mjs.map +1 -1
  90. package/dist/api/discriminator-other-owners.cjs +5 -3
  91. package/dist/api/discriminator-other-owners.cjs.map +1 -1
  92. package/dist/api/discriminator-other-owners.mjs +5 -3
  93. package/dist/api/discriminator-other-owners.mjs.map +1 -1
  94. package/dist/api/discriminator-patch.cjs +5 -1
  95. package/dist/api/discriminator-patch.cjs.map +1 -1
  96. package/dist/api/discriminator-patch.mjs +5 -1
  97. package/dist/api/discriminator-patch.mjs.map +1 -1
  98. package/dist/api/discriminator-scan.cjs +15 -8
  99. package/dist/api/discriminator-scan.cjs.map +1 -1
  100. package/dist/api/discriminator-scan.mjs +15 -8
  101. package/dist/api/discriminator-scan.mjs.map +1 -1
  102. package/dist/api/document-refs.cjs +16 -1
  103. package/dist/api/document-refs.cjs.map +1 -1
  104. package/dist/api/document-refs.mjs +16 -1
  105. package/dist/api/document-refs.mjs.map +1 -1
  106. package/dist/api/document-run.cjs +6 -12
  107. package/dist/api/document-run.cjs.map +1 -1
  108. package/dist/api/document-run.mjs +6 -12
  109. package/dist/api/document-run.mjs.map +1 -1
  110. package/dist/api/legacy-utils.cjs.map +1 -1
  111. package/dist/api/legacy-utils.mjs.map +1 -1
  112. package/dist/api/openapi-ts.cjs +9 -6
  113. package/dist/api/openapi-ts.cjs.map +1 -1
  114. package/dist/api/openapi-ts.mjs +10 -8
  115. package/dist/api/openapi-ts.mjs.map +1 -1
  116. package/dist/api/ref-limit-options.cjs +63 -0
  117. package/dist/api/ref-limit-options.cjs.map +1 -0
  118. package/dist/api/ref-limit-options.mjs +57 -0
  119. package/dist/api/ref-limit-options.mjs.map +1 -0
  120. package/dist/api/schema-callbacks.cjs +36 -12
  121. package/dist/api/schema-callbacks.cjs.map +1 -1
  122. package/dist/api/schema-callbacks.mjs +36 -12
  123. package/dist/api/schema-callbacks.mjs.map +1 -1
  124. package/dist/api/transform-context.cjs +7 -3
  125. package/dist/api/transform-context.cjs.map +1 -1
  126. package/dist/api/transform-context.mjs +7 -3
  127. package/dist/api/transform-context.mjs.map +1 -1
  128. package/dist/api/transform-schema.cjs +47 -10
  129. package/dist/api/transform-schema.cjs.map +1 -1
  130. package/dist/api/transform-schema.mjs +48 -11
  131. package/dist/api/transform-schema.mjs.map +1 -1
  132. package/dist/application/print/text-writer.cjs +10 -3
  133. package/dist/application/print/text-writer.cjs.map +1 -1
  134. package/dist/application/print/text-writer.mjs +10 -3
  135. package/dist/application/print/text-writer.mjs.map +1 -1
  136. package/dist/application/stack-overflow.cjs +2 -1
  137. package/dist/application/stack-overflow.cjs.map +1 -1
  138. package/dist/application/stack-overflow.mjs +2 -1
  139. package/dist/application/stack-overflow.mjs.map +1 -1
  140. package/dist/application/transform/declared-value-types.cjs +36 -0
  141. package/dist/application/transform/declared-value-types.cjs.map +1 -0
  142. package/dist/application/transform/declared-value-types.mjs +34 -0
  143. package/dist/application/transform/declared-value-types.mjs.map +1 -0
  144. package/dist/application/transform/document/components.cjs +1 -1
  145. package/dist/application/transform/document/components.cjs.map +1 -1
  146. package/dist/application/transform/document/components.mjs +2 -2
  147. package/dist/application/transform/document/components.mjs.map +1 -1
  148. package/dist/application/transform/document/declared-type-names.cjs +23 -0
  149. package/dist/application/transform/document/declared-type-names.cjs.map +1 -0
  150. package/dist/application/transform/document/declared-type-names.mjs +20 -0
  151. package/dist/application/transform/document/declared-type-names.mjs.map +1 -0
  152. package/dist/application/transform/document/defs-root.cjs +1 -1
  153. package/dist/application/transform/document/defs-root.cjs.map +1 -1
  154. package/dist/application/transform/document/defs-root.mjs +2 -2
  155. package/dist/application/transform/document/defs-root.mjs.map +1 -1
  156. package/dist/application/transform/document/document.cjs +7 -2
  157. package/dist/application/transform/document/document.cjs.map +1 -1
  158. package/dist/application/transform/document/document.mjs +6 -3
  159. package/dist/application/transform/document/document.mjs.map +1 -1
  160. package/dist/application/transform/document/enum-names-given-back.cjs +62 -0
  161. package/dist/application/transform/document/enum-names-given-back.cjs.map +1 -0
  162. package/dist/application/transform/document/enum-names-given-back.mjs +58 -0
  163. package/dist/application/transform/document/enum-names-given-back.mjs.map +1 -0
  164. package/dist/application/transform/document/exploded-query-values.cjs +63 -0
  165. package/dist/application/transform/document/exploded-query-values.cjs.map +1 -0
  166. package/dist/application/transform/document/exploded-query-values.mjs +59 -0
  167. package/dist/application/transform/document/exploded-query-values.mjs.map +1 -0
  168. package/dist/application/transform/document/global-type-references.cjs +1 -0
  169. package/dist/application/transform/document/global-type-references.cjs.map +1 -1
  170. package/dist/application/transform/document/global-type-references.mjs +1 -1
  171. package/dist/application/transform/document/global-type-references.mjs.map +1 -1
  172. package/dist/application/transform/document/header.cjs +11 -3
  173. package/dist/application/transform/document/header.cjs.map +1 -1
  174. package/dist/application/transform/document/header.mjs +10 -2
  175. package/dist/application/transform/document/header.mjs.map +1 -1
  176. package/dist/application/transform/document/media-type.cjs +2 -2
  177. package/dist/application/transform/document/media-type.cjs.map +1 -1
  178. package/dist/application/transform/document/media-type.mjs +3 -3
  179. package/dist/application/transform/document/media-type.mjs.map +1 -1
  180. package/dist/application/transform/document/operation-keys-written.cjs +26 -0
  181. package/dist/application/transform/document/operation-keys-written.cjs.map +1 -0
  182. package/dist/application/transform/document/operation-keys-written.mjs +24 -0
  183. package/dist/application/transform/document/operation-keys-written.mjs.map +1 -0
  184. package/dist/application/transform/document/operation.cjs +1 -1
  185. package/dist/application/transform/document/operation.cjs.map +1 -1
  186. package/dist/application/transform/document/operation.mjs +2 -2
  187. package/dist/application/transform/document/operation.mjs.map +1 -1
  188. package/dist/application/transform/document/parameter-entries.cjs +34 -0
  189. package/dist/application/transform/document/parameter-entries.cjs.map +1 -0
  190. package/dist/application/transform/document/parameter-entries.mjs +30 -0
  191. package/dist/application/transform/document/parameter-entries.mjs.map +1 -0
  192. package/dist/application/transform/document/parameter.cjs +12 -4
  193. package/dist/application/transform/document/parameter.cjs.map +1 -1
  194. package/dist/application/transform/document/parameter.mjs +13 -5
  195. package/dist/application/transform/document/parameter.mjs.map +1 -1
  196. package/dist/application/transform/document/parameters.cjs +29 -34
  197. package/dist/application/transform/document/parameters.cjs.map +1 -1
  198. package/dist/application/transform/document/parameters.mjs +29 -34
  199. package/dist/application/transform/document/parameters.mjs.map +1 -1
  200. package/dist/application/transform/document/path-item.cjs +15 -17
  201. package/dist/application/transform/document/path-item.cjs.map +1 -1
  202. package/dist/application/transform/document/path-item.mjs +15 -19
  203. package/dist/application/transform/document/path-item.mjs.map +1 -1
  204. package/dist/application/transform/document/path-template-key.cjs +84 -0
  205. package/dist/application/transform/document/path-template-key.cjs.map +1 -0
  206. package/dist/application/transform/document/path-template-key.mjs +79 -0
  207. package/dist/application/transform/document/path-template-key.mjs.map +1 -0
  208. package/dist/application/transform/document/path-template-refs.cjs +70 -0
  209. package/dist/application/transform/document/path-template-refs.cjs.map +1 -0
  210. package/dist/application/transform/document/path-template-refs.mjs +67 -0
  211. package/dist/application/transform/document/path-template-refs.mjs.map +1 -0
  212. package/dist/application/transform/document/paths-enum.cjs +8 -6
  213. package/dist/application/transform/document/paths-enum.cjs.map +1 -1
  214. package/dist/application/transform/document/paths-enum.mjs +8 -7
  215. package/dist/application/transform/document/paths-enum.mjs.map +1 -1
  216. package/dist/application/transform/document/paths.cjs +43 -67
  217. package/dist/application/transform/document/paths.cjs.map +1 -1
  218. package/dist/application/transform/document/paths.mjs +42 -68
  219. package/dist/application/transform/document/paths.mjs.map +1 -1
  220. package/dist/application/transform/document/referenced-parameter.cjs +80 -0
  221. package/dist/application/transform/document/referenced-parameter.cjs.map +1 -0
  222. package/dist/application/transform/document/referenced-parameter.mjs +78 -0
  223. package/dist/application/transform/document/referenced-parameter.mjs.map +1 -0
  224. package/dist/application/transform/document/request-body.cjs +1 -1
  225. package/dist/application/transform/document/request-body.cjs.map +1 -1
  226. package/dist/application/transform/document/request-body.mjs +2 -2
  227. package/dist/application/transform/document/request-body.mjs.map +1 -1
  228. package/dist/application/transform/document/response.cjs +2 -2
  229. package/dist/application/transform/document/response.cjs.map +1 -1
  230. package/dist/application/transform/document/response.mjs +3 -3
  231. package/dist/application/transform/document/response.mjs.map +1 -1
  232. package/dist/application/transform/document/responses.cjs +1 -1
  233. package/dist/application/transform/document/responses.cjs.map +1 -1
  234. package/dist/application/transform/document/responses.mjs +2 -2
  235. package/dist/application/transform/document/responses.mjs.map +1 -1
  236. package/dist/application/transform/document/root-type-aliases.cjs +8 -23
  237. package/dist/application/transform/document/root-type-aliases.cjs.map +1 -1
  238. package/dist/application/transform/document/root-type-aliases.mjs +8 -24
  239. package/dist/application/transform/document/root-type-aliases.mjs.map +1 -1
  240. package/dist/application/transform/document/type-resolution.cjs +3 -1
  241. package/dist/application/transform/document/type-resolution.cjs.map +1 -1
  242. package/dist/application/transform/document/type-resolution.mjs +3 -1
  243. package/dist/application/transform/document/type-resolution.mjs.map +1 -1
  244. package/dist/application/transform/document/webhooks.cjs +10 -3
  245. package/dist/application/transform/document/webhooks.cjs.map +1 -1
  246. package/dist/application/transform/document/webhooks.mjs +10 -3
  247. package/dist/application/transform/document/webhooks.mjs.map +1 -1
  248. package/dist/application/transform/footer/document-footer.cjs +16 -5
  249. package/dist/application/transform/footer/document-footer.cjs.map +1 -1
  250. package/dist/application/transform/footer/document-footer.mjs +16 -5
  251. package/dist/application/transform/footer/document-footer.mjs.map +1 -1
  252. package/dist/application/transform/footer/enum-name-claims.cjs +48 -0
  253. package/dist/application/transform/footer/enum-name-claims.cjs.map +1 -0
  254. package/dist/application/transform/footer/enum-name-claims.mjs +46 -0
  255. package/dist/application/transform/footer/enum-name-claims.mjs.map +1 -0
  256. package/dist/application/transform/footer/operation-keys.cjs +23 -0
  257. package/dist/application/transform/footer/operation-keys.cjs.map +1 -0
  258. package/dist/application/transform/footer/operation-keys.mjs +21 -0
  259. package/dist/application/transform/footer/operation-keys.mjs.map +1 -0
  260. package/dist/application/transform/footer/type-evaluation.cjs +4 -4
  261. package/dist/application/transform/footer/type-evaluation.cjs.map +1 -1
  262. package/dist/application/transform/footer/type-evaluation.mjs +4 -4
  263. package/dist/application/transform/footer/type-evaluation.mjs.map +1 -1
  264. package/dist/application/transform/helper-types.cjs +3 -3
  265. package/dist/application/transform/helper-types.cjs.map +1 -1
  266. package/dist/application/transform/helper-types.mjs +3 -3
  267. package/dist/application/transform/helper-types.mjs.map +1 -1
  268. package/dist/application/transform/numbered-names.cjs +9 -0
  269. package/dist/application/transform/numbered-names.cjs.map +1 -1
  270. package/dist/application/transform/numbered-names.mjs +9 -1
  271. package/dist/application/transform/numbered-names.mjs.map +1 -1
  272. package/dist/application/transform/ref-pointer/generated-location.cjs +5 -5
  273. package/dist/application/transform/ref-pointer/generated-location.cjs.map +1 -1
  274. package/dist/application/transform/ref-pointer/generated-location.mjs +3 -3
  275. package/dist/application/transform/ref-pointer/generated-location.mjs.map +1 -1
  276. package/dist/application/transform/ref-pointer/generated-shape.cjs +47 -66
  277. package/dist/application/transform/ref-pointer/generated-shape.cjs.map +1 -1
  278. package/dist/application/transform/ref-pointer/generated-shape.mjs +36 -50
  279. package/dist/application/transform/ref-pointer/generated-shape.mjs.map +1 -1
  280. package/dist/application/transform/ref-pointer/inline-cycles.cjs +2 -2
  281. package/dist/application/transform/ref-pointer/inline-cycles.cjs.map +1 -1
  282. package/dist/application/transform/ref-pointer/inline-cycles.mjs +1 -1
  283. package/dist/application/transform/ref-pointer/inline-cycles.mjs.map +1 -1
  284. package/dist/application/transform/ref-pointer/located-node.cjs +23 -0
  285. package/dist/application/transform/ref-pointer/located-node.cjs.map +1 -0
  286. package/dist/application/transform/ref-pointer/located-node.mjs +18 -0
  287. package/dist/application/transform/ref-pointer/located-node.mjs.map +1 -0
  288. package/dist/application/transform/ref-pointer/original-index.cjs +68 -13
  289. package/dist/application/transform/ref-pointer/original-index.cjs.map +1 -1
  290. package/dist/application/transform/ref-pointer/original-index.mjs +70 -15
  291. package/dist/application/transform/ref-pointer/original-index.mjs.map +1 -1
  292. package/dist/application/transform/ref-pointer/pointer-type.cjs +2 -2
  293. package/dist/application/transform/ref-pointer/pointer-type.cjs.map +1 -1
  294. package/dist/application/transform/ref-pointer/pointer-type.mjs +1 -1
  295. package/dist/application/transform/ref-pointer/pointer-type.mjs.map +1 -1
  296. package/dist/application/transform/ref-pointer/pointer-walk.cjs +54 -13
  297. package/dist/application/transform/ref-pointer/pointer-walk.cjs.map +1 -1
  298. package/dist/application/transform/ref-pointer/pointer-walk.mjs +46 -7
  299. package/dist/application/transform/ref-pointer/pointer-walk.mjs.map +1 -1
  300. package/dist/application/transform/ref-pointer/property-shape.cjs +52 -0
  301. package/dist/application/transform/ref-pointer/property-shape.cjs.map +1 -0
  302. package/dist/application/transform/ref-pointer/property-shape.mjs +45 -0
  303. package/dist/application/transform/ref-pointer/property-shape.mjs.map +1 -0
  304. package/dist/application/transform/ref-pointer/typed-walk.cjs +79 -21
  305. package/dist/application/transform/ref-pointer/typed-walk.cjs.map +1 -1
  306. package/dist/application/transform/ref-pointer/typed-walk.mjs +76 -18
  307. package/dist/application/transform/ref-pointer/typed-walk.mjs.map +1 -1
  308. package/dist/application/transform/ref-type.cjs +2 -1
  309. package/dist/application/transform/ref-type.cjs.map +1 -1
  310. package/dist/application/transform/ref-type.mjs +2 -1
  311. package/dist/application/transform/ref-type.mjs.map +1 -1
  312. package/dist/application/transform/schema/access-flags.cjs.map +1 -1
  313. package/dist/application/transform/schema/access-flags.mjs.map +1 -1
  314. package/dist/application/transform/schema/composition-type.cjs +1 -1
  315. package/dist/application/transform/schema/composition-type.cjs.map +1 -1
  316. package/dist/application/transform/schema/composition-type.mjs +2 -2
  317. package/dist/application/transform/schema/composition-type.mjs.map +1 -1
  318. package/dist/application/transform/schema/enum-rule.cjs +1 -1
  319. package/dist/application/transform/schema/enum-rule.cjs.map +1 -1
  320. package/dist/application/transform/schema/enum-rule.mjs +2 -2
  321. package/dist/application/transform/schema/enum-rule.mjs.map +1 -1
  322. package/dist/application/transform/schema/index-signature-type.cjs +21 -0
  323. package/dist/application/transform/schema/index-signature-type.cjs.map +1 -0
  324. package/dist/application/transform/schema/index-signature-type.mjs +19 -0
  325. package/dist/application/transform/schema/index-signature-type.mjs.map +1 -0
  326. package/dist/application/transform/schema/input-location.cjs +23 -0
  327. package/dist/application/transform/schema/input-location.cjs.map +1 -0
  328. package/dist/application/transform/schema/input-location.mjs +21 -0
  329. package/dist/application/transform/schema/input-location.mjs.map +1 -0
  330. package/dist/application/transform/schema/object-type.cjs +18 -8
  331. package/dist/application/transform/schema/object-type.cjs.map +1 -1
  332. package/dist/application/transform/schema/object-type.mjs +19 -9
  333. package/dist/application/transform/schema/object-type.mjs.map +1 -1
  334. package/dist/application/transform/schema/ref-siblings.cjs +47 -0
  335. package/dist/application/transform/schema/ref-siblings.cjs.map +1 -0
  336. package/dist/application/transform/schema/ref-siblings.mjs +45 -0
  337. package/dist/application/transform/schema/ref-siblings.mjs.map +1 -0
  338. package/dist/application/transform/schema/schema-transform.cjs +6 -3
  339. package/dist/application/transform/schema/schema-transform.cjs.map +1 -1
  340. package/dist/application/transform/schema/schema-transform.mjs +6 -3
  341. package/dist/application/transform/schema/schema-transform.mjs.map +1 -1
  342. package/dist/application/transform/schema/unevaluated-properties.cjs +2 -30
  343. package/dist/application/transform/schema/unevaluated-properties.cjs.map +1 -1
  344. package/dist/application/transform/schema/unevaluated-properties.mjs +3 -31
  345. package/dist/application/transform/schema/unevaluated-properties.mjs.map +1 -1
  346. package/dist/application/transform/schema-comment.cjs +5 -1
  347. package/dist/application/transform/schema-comment.cjs.map +1 -1
  348. package/dist/application/transform/schema-comment.mjs +5 -1
  349. package/dist/application/transform/schema-comment.mjs.map +1 -1
  350. package/dist/cli/api-logger.cjs +13 -0
  351. package/dist/cli/api-logger.cjs.map +1 -0
  352. package/dist/cli/api-logger.mjs +11 -0
  353. package/dist/cli/api-logger.mjs.map +1 -0
  354. package/dist/cli/api-settings.cjs +57 -9
  355. package/dist/cli/api-settings.cjs.map +1 -1
  356. package/dist/cli/api-settings.mjs +56 -11
  357. package/dist/cli/api-settings.mjs.map +1 -1
  358. package/dist/cli/api-writes.cjs +72 -0
  359. package/dist/cli/api-writes.cjs.map +1 -0
  360. package/dist/cli/api-writes.mjs +69 -0
  361. package/dist/cli/api-writes.mjs.map +1 -0
  362. package/dist/cli/cli-arguments.cjs +51 -11
  363. package/dist/cli/cli-arguments.cjs.map +1 -1
  364. package/dist/cli/cli-arguments.mjs +51 -11
  365. package/dist/cli/cli-arguments.mjs.map +1 -1
  366. package/dist/cli/cli-errors.cjs +29 -1
  367. package/dist/cli/cli-errors.cjs.map +1 -1
  368. package/dist/cli/cli-errors.mjs +29 -2
  369. package/dist/cli/cli-errors.mjs.map +1 -1
  370. package/dist/cli/cli-output.cjs +111 -4
  371. package/dist/cli/cli-output.cjs.map +1 -1
  372. package/dist/cli/cli-output.mjs +104 -5
  373. package/dist/cli/cli-output.mjs.map +1 -1
  374. package/dist/cli/main.cjs +13 -3
  375. package/dist/cli/main.cjs.map +1 -1
  376. package/dist/cli/main.mjs +14 -4
  377. package/dist/cli/main.mjs.map +1 -1
  378. package/dist/cli/redocly-apis.cjs +94 -37
  379. package/dist/cli/redocly-apis.cjs.map +1 -1
  380. package/dist/cli/redocly-apis.mjs +99 -42
  381. package/dist/cli/redocly-apis.mjs.map +1 -1
  382. package/dist/cli/ref-limits.cjs +15 -1
  383. package/dist/cli/ref-limits.cjs.map +1 -1
  384. package/dist/cli/ref-limits.mjs +15 -2
  385. package/dist/cli/ref-limits.mjs.map +1 -1
  386. package/dist/cli/run-cli.cjs +37 -14
  387. package/dist/cli/run-cli.cjs.map +1 -1
  388. package/dist/cli/run-cli.mjs +39 -16
  389. package/dist/cli/run-cli.mjs.map +1 -1
  390. package/dist/domain/append-all.cjs +10 -0
  391. package/dist/domain/append-all.cjs.map +1 -0
  392. package/dist/domain/append-all.mjs +8 -0
  393. package/dist/domain/append-all.mjs.map +1 -0
  394. package/dist/domain/cause-secrets.cjs +52 -0
  395. package/dist/domain/cause-secrets.cjs.map +1 -0
  396. package/dist/domain/cause-secrets.mjs +50 -0
  397. package/dist/domain/cause-secrets.mjs.map +1 -0
  398. package/dist/domain/errors.cjs +11 -3
  399. package/dist/domain/errors.cjs.map +1 -1
  400. package/dist/domain/errors.mjs +11 -3
  401. package/dist/domain/errors.mjs.map +1 -1
  402. package/dist/domain/ir/identifier-text.cjs.map +1 -1
  403. package/dist/domain/ir/identifier-text.mjs +1 -1
  404. package/dist/domain/ir/identifier-text.mjs.map +1 -1
  405. package/dist/domain/ir/ir-shape.cjs +187 -0
  406. package/dist/domain/ir/ir-shape.cjs.map +1 -0
  407. package/dist/domain/ir/ir-shape.mjs +184 -0
  408. package/dist/domain/ir/ir-shape.mjs.map +1 -0
  409. package/dist/domain/ir/newer-identifier-ranges.cjs +182 -29
  410. package/dist/domain/ir/newer-identifier-ranges.cjs.map +1 -1
  411. package/dist/domain/ir/newer-identifier-ranges.mjs +182 -29
  412. package/dist/domain/ir/newer-identifier-ranges.mjs.map +1 -1
  413. package/dist/domain/location-text.cjs +9 -0
  414. package/dist/domain/location-text.cjs.map +1 -0
  415. package/dist/domain/location-text.mjs +7 -0
  416. package/dist/domain/location-text.mjs.map +1 -0
  417. package/dist/domain/openapi/alias-expansion.cjs +3 -1
  418. package/dist/domain/openapi/alias-expansion.cjs.map +1 -1
  419. package/dist/domain/openapi/alias-expansion.mjs +3 -1
  420. package/dist/domain/openapi/alias-expansion.mjs.map +1 -1
  421. package/dist/domain/openapi/discriminated-union.cjs +3 -3
  422. package/dist/domain/openapi/discriminated-union.cjs.map +1 -1
  423. package/dist/domain/openapi/discriminated-union.mjs +4 -4
  424. package/dist/domain/openapi/discriminated-union.mjs.map +1 -1
  425. package/dist/domain/openapi/discriminator-conflicts.cjs +10 -6
  426. package/dist/domain/openapi/discriminator-conflicts.cjs.map +1 -1
  427. package/dist/domain/openapi/discriminator-conflicts.mjs +11 -7
  428. package/dist/domain/openapi/discriminator-conflicts.mjs.map +1 -1
  429. package/dist/domain/openapi/document-places.cjs +55 -0
  430. package/dist/domain/openapi/document-places.cjs.map +1 -0
  431. package/dist/domain/openapi/document-places.mjs +53 -0
  432. package/dist/domain/openapi/document-places.mjs.map +1 -0
  433. package/dist/domain/openapi/json-pointer.cjs +43 -1
  434. package/dist/domain/openapi/json-pointer.cjs.map +1 -1
  435. package/dist/domain/openapi/json-pointer.mjs +40 -2
  436. package/dist/domain/openapi/json-pointer.mjs.map +1 -1
  437. package/dist/domain/openapi/schema-dialect.cjs +15 -0
  438. package/dist/domain/openapi/schema-dialect.cjs.map +1 -0
  439. package/dist/domain/openapi/schema-dialect.mjs +12 -0
  440. package/dist/domain/openapi/schema-dialect.mjs.map +1 -0
  441. package/dist/domain/openapi/unsupported-features.cjs +1 -1
  442. package/dist/domain/openapi/unsupported-features.cjs.map +1 -1
  443. package/dist/domain/openapi/unsupported-features.mjs +2 -2
  444. package/dist/domain/openapi/unsupported-features.mjs.map +1 -1
  445. package/dist/domain/output-fixes.cjs +20 -0
  446. package/dist/domain/output-fixes.cjs.map +1 -1
  447. package/dist/domain/output-fixes.mjs +20 -0
  448. package/dist/domain/output-fixes.mjs.map +1 -1
  449. package/dist/domain/terminal-text.cjs +31 -0
  450. package/dist/domain/terminal-text.cjs.map +1 -0
  451. package/dist/domain/terminal-text.mjs +29 -0
  452. package/dist/domain/terminal-text.mjs.map +1 -0
  453. package/dist/domain/url-secrets.cjs +48 -0
  454. package/dist/domain/url-secrets.cjs.map +1 -0
  455. package/dist/domain/url-secrets.mjs +45 -0
  456. package/dist/domain/url-secrets.mjs.map +1 -0
  457. package/dist/domain/warnings.cjs +1 -0
  458. package/dist/domain/warnings.cjs.map +1 -1
  459. package/dist/domain/warnings.mjs +1 -0
  460. package/dist/domain/warnings.mjs.map +1 -1
  461. package/dist/index.d.cts +46 -20
  462. package/dist/index.d.mts +46 -20
  463. package/dist/index.d.ts +46 -20
  464. package/package.json +4 -5
  465. package/src/adapters/node-file-system/file-claims.ts +138 -0
  466. package/src/adapters/node-file-system/file-identity.ts +137 -0
  467. package/src/adapters/node-file-system/node-file-system.ts +158 -18
  468. package/src/adapters/pipe-safe-writer/pipe-safe-writer.ts +29 -0
  469. package/src/adapters/redocly-loader/bundled-mapping-copies.ts +60 -0
  470. package/src/adapters/redocly-loader/bundled-ref-repair.ts +2 -2
  471. package/src/adapters/redocly-loader/component-schemas.ts +19 -0
  472. package/src/adapters/redocly-loader/loaded-documents.ts +46 -0
  473. package/src/adapters/redocly-loader/mapping-schema-names.ts +25 -0
  474. package/src/adapters/redocly-loader/query-named-components.ts +201 -0
  475. package/src/adapters/redocly-loader/redocly-schema-loader.ts +64 -38
  476. package/src/adapters/redocly-loader/ref-access.ts +51 -4
  477. package/src/adapters/redocly-loader/ref-holders.ts +76 -15
  478. package/src/adapters/redocly-loader/remote-body-limit.ts +66 -0
  479. package/src/adapters/redocly-loader/remote-fetch.ts +85 -13
  480. package/src/adapters/redocly-loader/remote-node-limit.ts +102 -0
  481. package/src/adapters/redocly-loader/schema-load-errors.ts +52 -13
  482. package/src/adapters/redocly-loader/schema-source.ts +35 -11
  483. package/src/adapters/redocly-loader/unsupported-keys.ts +3 -7
  484. package/src/adapters/terminal-logger/terminal-logger.ts +17 -6
  485. package/src/api/default-ports.ts +33 -4
  486. package/src/api/discriminator-enum-parent.ts +3 -3
  487. package/src/api/discriminator-other-owners.ts +5 -3
  488. package/src/api/discriminator-patch.ts +5 -1
  489. package/src/api/discriminator-scan.ts +16 -8
  490. package/src/api/document-refs.ts +29 -1
  491. package/src/api/document-run.ts +10 -19
  492. package/src/api/legacy-utils.ts +5 -1
  493. package/src/api/openapi-ts.ts +26 -8
  494. package/src/api/ref-limit-options.ts +76 -0
  495. package/src/api/run-context.ts +3 -0
  496. package/src/api/schema-callbacks.ts +60 -17
  497. package/src/api/transform-context.ts +7 -3
  498. package/src/api/transform-schema.ts +79 -12
  499. package/src/application/ports/file-system.ts +47 -0
  500. package/src/application/ports/schema-loader.ts +11 -1
  501. package/src/application/print/text-writer.ts +10 -3
  502. package/src/application/stack-overflow.ts +9 -5
  503. package/src/application/transform/declared-value-types.ts +42 -0
  504. package/src/application/transform/document/components.ts +2 -2
  505. package/src/application/transform/document/declared-type-names.ts +36 -0
  506. package/src/application/transform/document/defs-root.ts +2 -2
  507. package/src/application/transform/document/document.ts +8 -5
  508. package/src/application/transform/document/enum-names-given-back.ts +91 -0
  509. package/src/application/transform/document/exploded-query-values.ts +88 -0
  510. package/src/application/transform/document/global-type-references.ts +1 -1
  511. package/src/application/transform/document/header.ts +25 -5
  512. package/src/application/transform/document/media-type.ts +4 -3
  513. package/src/application/transform/document/operation-keys-written.ts +27 -0
  514. package/src/application/transform/document/operation.ts +2 -2
  515. package/src/application/transform/document/parameter-entries.ts +70 -0
  516. package/src/application/transform/document/parameter.ts +21 -9
  517. package/src/application/transform/document/parameters.ts +56 -66
  518. package/src/application/transform/document/path-item.ts +16 -34
  519. package/src/application/transform/document/path-template-key.ts +152 -0
  520. package/src/application/transform/document/path-template-refs.ts +106 -0
  521. package/src/application/transform/document/paths-enum.ts +24 -10
  522. package/src/application/transform/document/paths.ts +59 -125
  523. package/src/application/transform/document/referenced-parameter.ts +146 -0
  524. package/src/application/transform/document/request-body.ts +2 -2
  525. package/src/application/transform/document/response.ts +3 -3
  526. package/src/application/transform/document/responses.ts +2 -2
  527. package/src/application/transform/document/root-type-aliases.ts +17 -38
  528. package/src/application/transform/document/type-resolution.ts +2 -1
  529. package/src/application/transform/document/webhooks.ts +19 -6
  530. package/src/application/transform/footer/document-footer.ts +36 -9
  531. package/src/application/transform/footer/enum-name-claims.ts +62 -0
  532. package/src/application/transform/footer/operation-keys.ts +28 -0
  533. package/src/application/transform/footer/type-evaluation.ts +4 -4
  534. package/src/application/transform/helper-types.ts +8 -7
  535. package/src/application/transform/numbered-names.ts +15 -0
  536. package/src/application/transform/ref-pointer/generated-location.ts +3 -3
  537. package/src/application/transform/ref-pointer/generated-shape.ts +67 -78
  538. package/src/application/transform/ref-pointer/inline-cycles.ts +1 -1
  539. package/src/application/transform/ref-pointer/located-node.ts +38 -0
  540. package/src/application/transform/ref-pointer/original-index.ts +100 -17
  541. package/src/application/transform/ref-pointer/pointer-type.ts +1 -1
  542. package/src/application/transform/ref-pointer/pointer-walk.ts +82 -8
  543. package/src/application/transform/ref-pointer/property-shape.ts +97 -0
  544. package/src/application/transform/ref-pointer/typed-walk.ts +117 -25
  545. package/src/application/transform/ref-type.ts +2 -1
  546. package/src/application/transform/schema/access-flags.ts +5 -2
  547. package/src/application/transform/schema/composition-type.ts +2 -2
  548. package/src/application/transform/schema/enum-rule.ts +6 -2
  549. package/src/application/transform/schema/index-signature-type.ts +31 -0
  550. package/src/application/transform/schema/input-location.ts +35 -0
  551. package/src/application/transform/schema/object-type.ts +22 -12
  552. package/src/application/transform/schema/ref-siblings.ts +76 -0
  553. package/src/application/transform/schema/schema-context.ts +3 -0
  554. package/src/application/transform/schema/schema-transform.ts +6 -3
  555. package/src/application/transform/schema/unevaluated-properties.ts +4 -44
  556. package/src/application/transform/schema-comment.ts +5 -1
  557. package/src/application/transform/transform-context.ts +5 -0
  558. package/src/cli/api-logger.ts +17 -0
  559. package/src/cli/api-settings.ts +80 -13
  560. package/src/cli/api-writes.ts +117 -0
  561. package/src/cli/cli-arguments.ts +90 -14
  562. package/src/cli/cli-dependencies.ts +26 -4
  563. package/src/cli/cli-errors.ts +42 -1
  564. package/src/cli/cli-output.ts +195 -15
  565. package/src/cli/main.ts +14 -5
  566. package/src/cli/redocly-apis.ts +177 -52
  567. package/src/cli/ref-limits.ts +21 -2
  568. package/src/cli/run-cli.ts +76 -15
  569. package/src/domain/append-all.ts +10 -0
  570. package/src/domain/cause-secrets.ts +86 -0
  571. package/src/domain/errors.ts +16 -5
  572. package/src/domain/ir/identifier-text.ts +6 -5
  573. package/src/domain/ir/ir-shape.ts +299 -0
  574. package/src/domain/ir/newer-identifier-ranges.ts +183 -30
  575. package/src/domain/location-text.ts +12 -0
  576. package/src/domain/openapi/alias-expansion.ts +4 -1
  577. package/src/domain/openapi/discriminated-union.ts +6 -4
  578. package/src/domain/openapi/discriminator-conflicts.ts +21 -7
  579. package/src/domain/openapi/document-object.ts +2 -0
  580. package/src/domain/openapi/document-places.ts +78 -0
  581. package/src/domain/openapi/json-pointer.ts +96 -7
  582. package/src/domain/openapi/schema-dialect.ts +22 -0
  583. package/src/domain/openapi/unsupported-features.ts +2 -2
  584. package/src/domain/output-fixes.ts +28 -2
  585. package/src/domain/terminal-text.ts +44 -0
  586. package/src/domain/url-secrets.ts +72 -0
  587. package/src/domain/warnings.ts +1 -0
  588. package/src/types/generator-options.ts +1 -1
  589. package/dist/cli/main.d.cts +0 -2
  590. package/dist/cli/main.d.mts +0 -2
  591. package/dist/cli/main.d.ts +0 -2
  592. package/dist/domain/url-credentials.cjs +0 -10
  593. package/dist/domain/url-credentials.cjs.map +0 -1
  594. package/dist/domain/url-credentials.mjs +0 -8
  595. package/dist/domain/url-credentials.mjs.map +0 -1
  596. package/src/domain/url-credentials.ts +0 -18
@@ -2,30 +2,72 @@
2
2
 
3
3
  const jsonPointer = require('../../domain/openapi/json-pointer.cjs');
4
4
 
5
- function hasStringRef(value) {
6
- return !Array.isArray(value) && typeof value.$ref === "string";
5
+ const DATA_KEYWORDS = /* @__PURE__ */ new Set(["example", "examples", "default", "const", "enum"]);
6
+ const EXTENSION_PREFIX = "x-";
7
+ const NAME_MAPS = /* @__PURE__ */ new Set([
8
+ "properties",
9
+ "patternProperties",
10
+ "dependentSchemas",
11
+ "$defs",
12
+ "definitions",
13
+ "schemas",
14
+ "responses",
15
+ "parameters",
16
+ "requestBodies",
17
+ "headers",
18
+ "securitySchemes",
19
+ "links",
20
+ "callbacks",
21
+ "pathItems",
22
+ "mediaTypes",
23
+ "content",
24
+ "encoding",
25
+ "paths",
26
+ "webhooks"
27
+ ]);
28
+ function isDataKey(key) {
29
+ return DATA_KEYWORDS.has(key) || key.startsWith(EXTENSION_PREFIX);
7
30
  }
8
- function findRefHolders(document) {
31
+ function openApiNodes(document) {
9
32
  const found = [];
10
33
  const visited = /* @__PURE__ */ new WeakSet();
11
34
  const pending = [];
12
- const enqueue = (value, pointer) => {
35
+ const enqueue = (value, pointer, hasNameKeys) => {
13
36
  if (typeof value === "object" && value !== null && !visited.has(value)) {
14
37
  visited.add(value);
15
- pending.push({ value, pointer });
38
+ pending.push({ value, pointer, hasNameKeys });
16
39
  }
17
40
  };
18
- enqueue(document, "#");
41
+ enqueue(document, jsonPointer.ROOT_POINTER, false);
19
42
  for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
20
- if (hasStringRef(next.value)) {
21
- found.push({ node: next.value, pointer: next.pointer });
22
- }
43
+ found.push(next);
23
44
  for (const [key, child] of Object.entries(next.value)) {
24
- enqueue(child, `${next.pointer}/${jsonPointer.escapePointerSegment(key)}`);
45
+ if (next.hasNameKeys || !isDataKey(key)) {
46
+ enqueue(child, jsonPointer.childPointer(next.pointer, key), !next.hasNameKeys && NAME_MAPS.has(key));
47
+ }
25
48
  }
26
49
  }
27
50
  return found;
28
51
  }
52
+ function hasStringRef(value) {
53
+ return !Array.isArray(value) && typeof value.$ref === "string";
54
+ }
55
+ function findRefHolders(document) {
56
+ return openApiNodes(document).flatMap(
57
+ ({ value, pointer, hasNameKeys }) => !hasNameKeys && hasStringRef(value) ? [{ node: value, pointer }] : []
58
+ );
59
+ }
60
+ function isMapping(value) {
61
+ return typeof value === "object" && value !== null && !Array.isArray(value);
62
+ }
63
+ function findMappings(document) {
64
+ return openApiNodes(document).flatMap(({ value, hasNameKeys }) => {
65
+ const { discriminator } = value;
66
+ const mapping = !hasNameKeys && isMapping(discriminator) ? discriminator.mapping : void 0;
67
+ return isMapping(mapping) ? [mapping] : [];
68
+ });
69
+ }
29
70
 
71
+ exports.findMappings = findMappings;
30
72
  exports.findRefHolders = findRefHolders;
31
73
  //# sourceMappingURL=ref-holders.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ref-holders.cjs","sources":["../../../src/adapters/redocly-loader/ref-holders.ts"],"sourcesContent":["import { escapePointerSegment } from \"../../domain/openapi/json-pointer.js\";\n\n/** An object with a string `$ref`, and its JSON Pointer in the document. */\nexport interface RefHolder {\n readonly node: { $ref: string };\n readonly pointer: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\nfunction hasStringRef(value: object): value is { $ref: string } {\n return !Array.isArray(value) && typeof (value as { $ref?: unknown }).$ref === \"string\";\n}\n\n/**\n * Every object with a string `$ref` in a parsed document, in no particular order. The walk uses\n * its own stack, so a deeply nested document does not run out of call stack, and a node shared by\n * YAML aliases (or a cycle of them) is visited once.\n */\nexport function findRefHolders(document: unknown): RefHolder[] {\n const found: RefHolder[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document, \"#\");\n for (let next = pending.pop(); next !== undefined; next = pending.pop()) {\n if (hasStringRef(next.value)) {\n found.push({ node: next.value, pointer: next.pointer });\n }\n for (const [key, child] of Object.entries(next.value)) {\n enqueue(child, `${next.pointer}/${escapePointerSegment(key)}`);\n }\n }\n return found;\n}\n"],"names":["escapePointerSegment"],"mappings":";;;;AAaA,SAAS,aAAa,KAAA,EAA0C;AAC9D,EAAA,OAAO,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,OAAQ,MAA6B,IAAA,KAAS,QAAA;AAChF;AAOO,SAAS,eAAe,QAAA,EAAgC;AAC7D,EAAA,MAAM,QAAqB,EAAC;AAC5B,EAAA,MAAM,OAAA,uBAAc,OAAA,EAAgB;AACpC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAgB,OAAA,KAA0B;AACzD,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,IAAI,KAAK,CAAA;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACA,EAAA,OAAA,CAAQ,UAAU,GAAG,CAAA;AACrB,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,GAAA,EAAI,EAAG,SAAS,MAAA,EAAW,IAAA,GAAO,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvE,IAAA,IAAI,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA,EAAG;AAC5B,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AAAA,IACxD;AACA,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACrD,MAAA,OAAA,CAAQ,KAAA,EAAO,GAAG,IAAA,CAAK,OAAO,IAAIA,gCAAA,CAAqB,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,IAC/D;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;;"}
1
+ {"version":3,"file":"ref-holders.cjs","sources":["../../../src/adapters/redocly-loader/ref-holders.ts"],"sourcesContent":["import { childPointer, ROOT_POINTER } from \"../../domain/openapi/json-pointer.js\";\n\n/** An object with a string `$ref`, and its JSON Pointer in the document. */\nexport interface RefHolder {\n readonly node: { $ref: string };\n readonly pointer: string;\n}\n\n/**\n * Keywords whose value is data, not OpenAPI: a `$ref` or a `discriminator` in an example, a\n * default, a `const` or an `enum` value, or an extension is part of the data and stays as written.\n */\nconst DATA_KEYWORDS = new Set([\"example\", \"examples\", \"default\", \"const\", \"enum\"]);\nconst EXTENSION_PREFIX = \"x-\";\n\n/**\n * Keywords whose value maps names to objects: a property, a schema or a response may be named\n * `default` or `example`, and is OpenAPI all the same.\n */\nconst NAME_MAPS = new Set([\n \"properties\",\n \"patternProperties\",\n \"dependentSchemas\",\n \"$defs\",\n \"definitions\",\n \"schemas\",\n \"responses\",\n \"parameters\",\n \"requestBodies\",\n \"headers\",\n \"securitySchemes\",\n \"links\",\n \"callbacks\",\n \"pathItems\",\n \"mediaTypes\",\n \"content\",\n \"encoding\",\n \"paths\",\n \"webhooks\",\n]);\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n /** Whether the keys of `value` are names (of properties, schemas, responses), not keywords. */\n readonly hasNameKeys: boolean;\n}\n\nfunction isDataKey(key: string): boolean {\n return DATA_KEYWORDS.has(key) || key.startsWith(EXTENSION_PREFIX);\n}\n\n/**\n * Every object of a parsed document that is OpenAPI, not data (`DATA_KEYWORDS`), with its JSON\n * Pointer, in no particular order. The walk uses its own stack, so a deeply nested document does\n * not run out of call stack, and a node shared by YAML aliases (or a cycle of them) is visited\n * once.\n */\nfunction openApiNodes(document: unknown): PendingNode[] {\n const found: PendingNode[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string, hasNameKeys: boolean): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer, hasNameKeys });\n }\n };\n enqueue(document, ROOT_POINTER, false);\n for (let next = pending.pop(); next !== undefined; next = pending.pop()) {\n found.push(next);\n // One push per child: spreading an array of millions of children overflows the stack.\n for (const [key, child] of Object.entries(next.value)) {\n if (next.hasNameKeys || !isDataKey(key)) {\n enqueue(child, childPointer(next.pointer, key), !next.hasNameKeys && NAME_MAPS.has(key));\n }\n }\n }\n return found;\n}\n\nfunction hasStringRef(value: object): value is { $ref: string } {\n return !Array.isArray(value) && typeof (value as { $ref?: unknown }).$ref === \"string\";\n}\n\n/** Every object with a string `$ref` in a parsed document, outside data, in no particular order. */\nexport function findRefHolders(document: unknown): RefHolder[] {\n return openApiNodes(document).flatMap(({ value, pointer, hasNameKeys }) =>\n !hasNameKeys && hasStringRef(value) ? [{ node: value, pointer }] : [],\n );\n}\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Every `discriminator.mapping` object of a parsed document, outside data. */\nexport function findMappings(document: unknown): Record<string, unknown>[] {\n return openApiNodes(document).flatMap(({ value, hasNameKeys }) => {\n const { discriminator } = value as { discriminator?: unknown };\n const mapping = !hasNameKeys && isMapping(discriminator) ? discriminator.mapping : undefined;\n return isMapping(mapping) ? [mapping] : [];\n });\n}\n"],"names":["ROOT_POINTER","childPointer"],"mappings":"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"}
@@ -1,29 +1,70 @@
1
- import { escapePointerSegment } from '../../domain/openapi/json-pointer.mjs';
1
+ import { childPointer, ROOT_POINTER } from '../../domain/openapi/json-pointer.mjs';
2
2
 
3
- function hasStringRef(value) {
4
- return !Array.isArray(value) && typeof value.$ref === "string";
3
+ const DATA_KEYWORDS = /* @__PURE__ */ new Set(["example", "examples", "default", "const", "enum"]);
4
+ const EXTENSION_PREFIX = "x-";
5
+ const NAME_MAPS = /* @__PURE__ */ new Set([
6
+ "properties",
7
+ "patternProperties",
8
+ "dependentSchemas",
9
+ "$defs",
10
+ "definitions",
11
+ "schemas",
12
+ "responses",
13
+ "parameters",
14
+ "requestBodies",
15
+ "headers",
16
+ "securitySchemes",
17
+ "links",
18
+ "callbacks",
19
+ "pathItems",
20
+ "mediaTypes",
21
+ "content",
22
+ "encoding",
23
+ "paths",
24
+ "webhooks"
25
+ ]);
26
+ function isDataKey(key) {
27
+ return DATA_KEYWORDS.has(key) || key.startsWith(EXTENSION_PREFIX);
5
28
  }
6
- function findRefHolders(document) {
29
+ function openApiNodes(document) {
7
30
  const found = [];
8
31
  const visited = /* @__PURE__ */ new WeakSet();
9
32
  const pending = [];
10
- const enqueue = (value, pointer) => {
33
+ const enqueue = (value, pointer, hasNameKeys) => {
11
34
  if (typeof value === "object" && value !== null && !visited.has(value)) {
12
35
  visited.add(value);
13
- pending.push({ value, pointer });
36
+ pending.push({ value, pointer, hasNameKeys });
14
37
  }
15
38
  };
16
- enqueue(document, "#");
39
+ enqueue(document, ROOT_POINTER, false);
17
40
  for (let next = pending.pop(); next !== void 0; next = pending.pop()) {
18
- if (hasStringRef(next.value)) {
19
- found.push({ node: next.value, pointer: next.pointer });
20
- }
41
+ found.push(next);
21
42
  for (const [key, child] of Object.entries(next.value)) {
22
- enqueue(child, `${next.pointer}/${escapePointerSegment(key)}`);
43
+ if (next.hasNameKeys || !isDataKey(key)) {
44
+ enqueue(child, childPointer(next.pointer, key), !next.hasNameKeys && NAME_MAPS.has(key));
45
+ }
23
46
  }
24
47
  }
25
48
  return found;
26
49
  }
50
+ function hasStringRef(value) {
51
+ return !Array.isArray(value) && typeof value.$ref === "string";
52
+ }
53
+ function findRefHolders(document) {
54
+ return openApiNodes(document).flatMap(
55
+ ({ value, pointer, hasNameKeys }) => !hasNameKeys && hasStringRef(value) ? [{ node: value, pointer }] : []
56
+ );
57
+ }
58
+ function isMapping(value) {
59
+ return typeof value === "object" && value !== null && !Array.isArray(value);
60
+ }
61
+ function findMappings(document) {
62
+ return openApiNodes(document).flatMap(({ value, hasNameKeys }) => {
63
+ const { discriminator } = value;
64
+ const mapping = !hasNameKeys && isMapping(discriminator) ? discriminator.mapping : void 0;
65
+ return isMapping(mapping) ? [mapping] : [];
66
+ });
67
+ }
27
68
 
28
- export { findRefHolders };
69
+ export { findMappings, findRefHolders };
29
70
  //# sourceMappingURL=ref-holders.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ref-holders.mjs","sources":["../../../src/adapters/redocly-loader/ref-holders.ts"],"sourcesContent":["import { escapePointerSegment } from \"../../domain/openapi/json-pointer.js\";\n\n/** An object with a string `$ref`, and its JSON Pointer in the document. */\nexport interface RefHolder {\n readonly node: { $ref: string };\n readonly pointer: string;\n}\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n}\n\nfunction hasStringRef(value: object): value is { $ref: string } {\n return !Array.isArray(value) && typeof (value as { $ref?: unknown }).$ref === \"string\";\n}\n\n/**\n * Every object with a string `$ref` in a parsed document, in no particular order. The walk uses\n * its own stack, so a deeply nested document does not run out of call stack, and a node shared by\n * YAML aliases (or a cycle of them) is visited once.\n */\nexport function findRefHolders(document: unknown): RefHolder[] {\n const found: RefHolder[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer });\n }\n };\n enqueue(document, \"#\");\n for (let next = pending.pop(); next !== undefined; next = pending.pop()) {\n if (hasStringRef(next.value)) {\n found.push({ node: next.value, pointer: next.pointer });\n }\n for (const [key, child] of Object.entries(next.value)) {\n enqueue(child, `${next.pointer}/${escapePointerSegment(key)}`);\n }\n }\n return found;\n}\n"],"names":[],"mappings":";;AAaA,SAAS,aAAa,KAAA,EAA0C;AAC9D,EAAA,OAAO,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,IAAK,OAAQ,MAA6B,IAAA,KAAS,QAAA;AAChF;AAOO,SAAS,eAAe,QAAA,EAAgC;AAC7D,EAAA,MAAM,QAAqB,EAAC;AAC5B,EAAA,MAAM,OAAA,uBAAc,OAAA,EAAgB;AACpC,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,OAAA,GAAU,CAAC,KAAA,EAAgB,OAAA,KAA0B;AACzD,IAAA,IAAI,OAAO,UAAU,QAAA,IAAY,KAAA,KAAU,QAAQ,CAAC,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAA,EAAG;AACtE,MAAA,OAAA,CAAQ,IAAI,KAAK,CAAA;AACjB,MAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,KAAA,EAAO,OAAA,EAAS,CAAA;AAAA,IACjC;AAAA,EACF,CAAA;AACA,EAAA,OAAA,CAAQ,UAAU,GAAG,CAAA;AACrB,EAAA,KAAA,IAAS,IAAA,GAAO,QAAQ,GAAA,EAAI,EAAG,SAAS,MAAA,EAAW,IAAA,GAAO,OAAA,CAAQ,GAAA,EAAI,EAAG;AACvE,IAAA,IAAI,YAAA,CAAa,IAAA,CAAK,KAAK,CAAA,EAAG;AAC5B,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA,CAAK,SAAS,CAAA;AAAA,IACxD;AACA,IAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,EAAG;AACrD,MAAA,OAAA,CAAQ,KAAA,EAAO,GAAG,IAAA,CAAK,OAAO,IAAI,oBAAA,CAAqB,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,IAC/D;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;;"}
1
+ {"version":3,"file":"ref-holders.mjs","sources":["../../../src/adapters/redocly-loader/ref-holders.ts"],"sourcesContent":["import { childPointer, ROOT_POINTER } from \"../../domain/openapi/json-pointer.js\";\n\n/** An object with a string `$ref`, and its JSON Pointer in the document. */\nexport interface RefHolder {\n readonly node: { $ref: string };\n readonly pointer: string;\n}\n\n/**\n * Keywords whose value is data, not OpenAPI: a `$ref` or a `discriminator` in an example, a\n * default, a `const` or an `enum` value, or an extension is part of the data and stays as written.\n */\nconst DATA_KEYWORDS = new Set([\"example\", \"examples\", \"default\", \"const\", \"enum\"]);\nconst EXTENSION_PREFIX = \"x-\";\n\n/**\n * Keywords whose value maps names to objects: a property, a schema or a response may be named\n * `default` or `example`, and is OpenAPI all the same.\n */\nconst NAME_MAPS = new Set([\n \"properties\",\n \"patternProperties\",\n \"dependentSchemas\",\n \"$defs\",\n \"definitions\",\n \"schemas\",\n \"responses\",\n \"parameters\",\n \"requestBodies\",\n \"headers\",\n \"securitySchemes\",\n \"links\",\n \"callbacks\",\n \"pathItems\",\n \"mediaTypes\",\n \"content\",\n \"encoding\",\n \"paths\",\n \"webhooks\",\n]);\n\ninterface PendingNode {\n readonly value: object;\n readonly pointer: string;\n /** Whether the keys of `value` are names (of properties, schemas, responses), not keywords. */\n readonly hasNameKeys: boolean;\n}\n\nfunction isDataKey(key: string): boolean {\n return DATA_KEYWORDS.has(key) || key.startsWith(EXTENSION_PREFIX);\n}\n\n/**\n * Every object of a parsed document that is OpenAPI, not data (`DATA_KEYWORDS`), with its JSON\n * Pointer, in no particular order. The walk uses its own stack, so a deeply nested document does\n * not run out of call stack, and a node shared by YAML aliases (or a cycle of them) is visited\n * once.\n */\nfunction openApiNodes(document: unknown): PendingNode[] {\n const found: PendingNode[] = [];\n const visited = new WeakSet<object>();\n const pending: PendingNode[] = [];\n const enqueue = (value: unknown, pointer: string, hasNameKeys: boolean): void => {\n if (typeof value === \"object\" && value !== null && !visited.has(value)) {\n visited.add(value);\n pending.push({ value, pointer, hasNameKeys });\n }\n };\n enqueue(document, ROOT_POINTER, false);\n for (let next = pending.pop(); next !== undefined; next = pending.pop()) {\n found.push(next);\n // One push per child: spreading an array of millions of children overflows the stack.\n for (const [key, child] of Object.entries(next.value)) {\n if (next.hasNameKeys || !isDataKey(key)) {\n enqueue(child, childPointer(next.pointer, key), !next.hasNameKeys && NAME_MAPS.has(key));\n }\n }\n }\n return found;\n}\n\nfunction hasStringRef(value: object): value is { $ref: string } {\n return !Array.isArray(value) && typeof (value as { $ref?: unknown }).$ref === \"string\";\n}\n\n/** Every object with a string `$ref` in a parsed document, outside data, in no particular order. */\nexport function findRefHolders(document: unknown): RefHolder[] {\n return openApiNodes(document).flatMap(({ value, pointer, hasNameKeys }) =>\n !hasNameKeys && hasStringRef(value) ? [{ node: value, pointer }] : [],\n );\n}\n\nfunction isMapping(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Every `discriminator.mapping` object of a parsed document, outside data. */\nexport function findMappings(document: unknown): Record<string, unknown>[] {\n return openApiNodes(document).flatMap(({ value, hasNameKeys }) => {\n const { discriminator } = value as { discriminator?: unknown };\n const mapping = !hasNameKeys && isMapping(discriminator) ? discriminator.mapping : undefined;\n return isMapping(mapping) ? [mapping] : [];\n });\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const schemaLoadErrors = require('./schema-load-errors.cjs');
4
+
5
+ class RemoteBodyLimit {
6
+ #limits;
7
+ #totalBytes = 0;
8
+ constructor(limits) {
9
+ this.#limits = limits;
10
+ }
11
+ /** The whole body of `response` from `url`; fails with `SCHEMA_REF_FORBIDDEN` past a limit. */
12
+ async read(response, url) {
13
+ const reader = response.body?.getReader();
14
+ if (reader === void 0) {
15
+ return new ArrayBuffer(0);
16
+ }
17
+ const chunks = [];
18
+ let documentBytes = 0;
19
+ for (let next = await reader.read(); !next.done; next = await reader.read()) {
20
+ documentBytes += next.value.byteLength;
21
+ this.#totalBytes += next.value.byteLength;
22
+ const refusal = this.#refusal(url, documentBytes);
23
+ if (refusal !== void 0) {
24
+ await reader.cancel();
25
+ throw refusal;
26
+ }
27
+ chunks.push(next.value);
28
+ }
29
+ return joined(chunks, documentBytes);
30
+ }
31
+ #refusal(url, documentBytes) {
32
+ const { maxDocumentBytes, maxTotalBytes } = this.#limits;
33
+ if (documentBytes > maxDocumentBytes) {
34
+ return schemaLoadErrors.refForbiddenError(url, { reason: "remote-document-too-large", maxDocumentBytes });
35
+ }
36
+ return this.#totalBytes > maxTotalBytes ? schemaLoadErrors.refForbiddenError(url, { reason: "remote-documents-too-large", maxTotalBytes }) : void 0;
37
+ }
38
+ }
39
+ function joined(chunks, byteLength) {
40
+ const body = new Uint8Array(byteLength);
41
+ let offset = 0;
42
+ for (const chunk of chunks) {
43
+ body.set(chunk, offset);
44
+ offset += chunk.byteLength;
45
+ }
46
+ return body.buffer;
47
+ }
48
+
49
+ exports.RemoteBodyLimit = RemoteBodyLimit;
50
+ //# sourceMappingURL=remote-body-limit.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-body-limit.cjs","sources":["../../../src/adapters/redocly-loader/remote-body-limit.ts"],"sourcesContent":["import type { OpenAPITypesafeError } from \"../../domain/errors.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/** The decoded size limits of the remote documents of one load (threat model T2). */\nexport interface RemoteBodyLimits {\n /** Bytes of one remote document's body after `Content-Encoding` is decoded. */\n readonly maxDocumentBytes: number;\n /** Bytes of the bodies of every remote document of one load together, decoded. */\n readonly maxTotalBytes: number;\n}\n\n/**\n * Reads remote bodies as a stream and stops at the limits. Fetch decodes `gzip`, `deflate` and\n * `br` before the body reaches the loader, so a body of a few megabytes on the wire can become\n * gigabytes in memory (a \"gzip bomb\"); counting the decoded bytes while they arrive stops it before\n * the memory is taken. One instance per load: the total covers every document of that load.\n */\nexport class RemoteBodyLimit {\n readonly #limits: RemoteBodyLimits;\n #totalBytes = 0;\n\n constructor(limits: RemoteBodyLimits) {\n this.#limits = limits;\n }\n\n /** The whole body of `response` from `url`; fails with `SCHEMA_REF_FORBIDDEN` past a limit. */\n async read(response: Response, url: string): Promise<ArrayBuffer> {\n const reader = response.body?.getReader();\n if (reader === undefined) {\n return new ArrayBuffer(0);\n }\n const chunks: Uint8Array[] = [];\n let documentBytes = 0;\n for (let next = await reader.read(); !next.done; next = await reader.read()) {\n documentBytes += next.value.byteLength;\n this.#totalBytes += next.value.byteLength;\n const refusal = this.#refusal(url, documentBytes);\n if (refusal !== undefined) {\n await reader.cancel();\n throw refusal;\n }\n chunks.push(next.value);\n }\n return joined(chunks, documentBytes);\n }\n\n #refusal(url: string, documentBytes: number): OpenAPITypesafeError | undefined {\n const { maxDocumentBytes, maxTotalBytes } = this.#limits;\n if (documentBytes > maxDocumentBytes) {\n return refForbiddenError(url, { reason: \"remote-document-too-large\", maxDocumentBytes });\n }\n return this.#totalBytes > maxTotalBytes\n ? refForbiddenError(url, { reason: \"remote-documents-too-large\", maxTotalBytes })\n : undefined;\n }\n}\n\nfunction joined(chunks: readonly Uint8Array[], byteLength: number): ArrayBuffer {\n const body = new Uint8Array(byteLength);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body.buffer;\n}\n"],"names":["refForbiddenError"],"mappings":";;;;AAiBO,MAAM,eAAA,CAAgB;AAAA,EAClB,OAAA;AAAA,EACT,WAAA,GAAc,CAAA;AAAA,EAEd,YAAY,MAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA;AAAA,EAGA,MAAM,IAAA,CAAK,QAAA,EAAoB,GAAA,EAAmC;AAChE,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,EAAM,SAAA,EAAU;AACxC,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,OAAO,IAAI,YAAY,CAAC,CAAA;AAAA,IAC1B;AACA,IAAA,MAAM,SAAuB,EAAC;AAC9B,IAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,IAAA,KAAA,IAAS,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK,EAAG,CAAC,IAAA,CAAK,IAAA,EAAM,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK,EAAG;AAC3E,MAAA,aAAA,IAAiB,KAAK,KAAA,CAAM,UAAA;AAC5B,MAAA,IAAA,CAAK,WAAA,IAAe,KAAK,KAAA,CAAM,UAAA;AAC/B,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,GAAA,EAAK,aAAa,CAAA;AAChD,MAAA,IAAI,YAAY,MAAA,EAAW;AACzB,QAAA,MAAM,OAAO,MAAA,EAAO;AACpB,QAAA,MAAM,OAAA;AAAA,MACR;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAO,MAAA,CAAO,QAAQ,aAAa,CAAA;AAAA,EACrC;AAAA,EAEA,QAAA,CAAS,KAAa,aAAA,EAAyD;AAC7E,IAAA,MAAM,EAAE,gBAAA,EAAkB,aAAA,EAAc,GAAI,IAAA,CAAK,OAAA;AACjD,IAAA,IAAI,gBAAgB,gBAAA,EAAkB;AACpC,MAAA,OAAOA,mCAAkB,GAAA,EAAK,EAAE,MAAA,EAAQ,2BAAA,EAA6B,kBAAkB,CAAA;AAAA,IACzF;AACA,IAAA,OAAO,IAAA,CAAK,WAAA,GAAc,aAAA,GACtBA,kCAAA,CAAkB,GAAA,EAAK,EAAE,MAAA,EAAQ,4BAAA,EAA8B,aAAA,EAAe,CAAA,GAC9E,MAAA;AAAA,EACN;AACF;AAEA,SAAS,MAAA,CAAO,QAA+B,UAAA,EAAiC;AAC9E,EAAA,MAAM,IAAA,GAAO,IAAI,UAAA,CAAW,UAAU,CAAA;AACtC,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAA,CAAK,GAAA,CAAI,OAAO,MAAM,CAAA;AACtB,IAAA,MAAA,IAAU,KAAA,CAAM,UAAA;AAAA,EAClB;AACA,EAAA,OAAO,IAAA,CAAK,MAAA;AACd;;"}
@@ -0,0 +1,48 @@
1
+ import { refForbiddenError } from './schema-load-errors.mjs';
2
+
3
+ class RemoteBodyLimit {
4
+ #limits;
5
+ #totalBytes = 0;
6
+ constructor(limits) {
7
+ this.#limits = limits;
8
+ }
9
+ /** The whole body of `response` from `url`; fails with `SCHEMA_REF_FORBIDDEN` past a limit. */
10
+ async read(response, url) {
11
+ const reader = response.body?.getReader();
12
+ if (reader === void 0) {
13
+ return new ArrayBuffer(0);
14
+ }
15
+ const chunks = [];
16
+ let documentBytes = 0;
17
+ for (let next = await reader.read(); !next.done; next = await reader.read()) {
18
+ documentBytes += next.value.byteLength;
19
+ this.#totalBytes += next.value.byteLength;
20
+ const refusal = this.#refusal(url, documentBytes);
21
+ if (refusal !== void 0) {
22
+ await reader.cancel();
23
+ throw refusal;
24
+ }
25
+ chunks.push(next.value);
26
+ }
27
+ return joined(chunks, documentBytes);
28
+ }
29
+ #refusal(url, documentBytes) {
30
+ const { maxDocumentBytes, maxTotalBytes } = this.#limits;
31
+ if (documentBytes > maxDocumentBytes) {
32
+ return refForbiddenError(url, { reason: "remote-document-too-large", maxDocumentBytes });
33
+ }
34
+ return this.#totalBytes > maxTotalBytes ? refForbiddenError(url, { reason: "remote-documents-too-large", maxTotalBytes }) : void 0;
35
+ }
36
+ }
37
+ function joined(chunks, byteLength) {
38
+ const body = new Uint8Array(byteLength);
39
+ let offset = 0;
40
+ for (const chunk of chunks) {
41
+ body.set(chunk, offset);
42
+ offset += chunk.byteLength;
43
+ }
44
+ return body.buffer;
45
+ }
46
+
47
+ export { RemoteBodyLimit };
48
+ //# sourceMappingURL=remote-body-limit.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-body-limit.mjs","sources":["../../../src/adapters/redocly-loader/remote-body-limit.ts"],"sourcesContent":["import type { OpenAPITypesafeError } from \"../../domain/errors.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/** The decoded size limits of the remote documents of one load (threat model T2). */\nexport interface RemoteBodyLimits {\n /** Bytes of one remote document's body after `Content-Encoding` is decoded. */\n readonly maxDocumentBytes: number;\n /** Bytes of the bodies of every remote document of one load together, decoded. */\n readonly maxTotalBytes: number;\n}\n\n/**\n * Reads remote bodies as a stream and stops at the limits. Fetch decodes `gzip`, `deflate` and\n * `br` before the body reaches the loader, so a body of a few megabytes on the wire can become\n * gigabytes in memory (a \"gzip bomb\"); counting the decoded bytes while they arrive stops it before\n * the memory is taken. One instance per load: the total covers every document of that load.\n */\nexport class RemoteBodyLimit {\n readonly #limits: RemoteBodyLimits;\n #totalBytes = 0;\n\n constructor(limits: RemoteBodyLimits) {\n this.#limits = limits;\n }\n\n /** The whole body of `response` from `url`; fails with `SCHEMA_REF_FORBIDDEN` past a limit. */\n async read(response: Response, url: string): Promise<ArrayBuffer> {\n const reader = response.body?.getReader();\n if (reader === undefined) {\n return new ArrayBuffer(0);\n }\n const chunks: Uint8Array[] = [];\n let documentBytes = 0;\n for (let next = await reader.read(); !next.done; next = await reader.read()) {\n documentBytes += next.value.byteLength;\n this.#totalBytes += next.value.byteLength;\n const refusal = this.#refusal(url, documentBytes);\n if (refusal !== undefined) {\n await reader.cancel();\n throw refusal;\n }\n chunks.push(next.value);\n }\n return joined(chunks, documentBytes);\n }\n\n #refusal(url: string, documentBytes: number): OpenAPITypesafeError | undefined {\n const { maxDocumentBytes, maxTotalBytes } = this.#limits;\n if (documentBytes > maxDocumentBytes) {\n return refForbiddenError(url, { reason: \"remote-document-too-large\", maxDocumentBytes });\n }\n return this.#totalBytes > maxTotalBytes\n ? refForbiddenError(url, { reason: \"remote-documents-too-large\", maxTotalBytes })\n : undefined;\n }\n}\n\nfunction joined(chunks: readonly Uint8Array[], byteLength: number): ArrayBuffer {\n const body = new Uint8Array(byteLength);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return body.buffer;\n}\n"],"names":[],"mappings":";;AAiBO,MAAM,eAAA,CAAgB;AAAA,EAClB,OAAA;AAAA,EACT,WAAA,GAAc,CAAA;AAAA,EAEd,YAAY,MAAA,EAA0B;AACpC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA;AAAA,EAGA,MAAM,IAAA,CAAK,QAAA,EAAoB,GAAA,EAAmC;AAChE,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,EAAM,SAAA,EAAU;AACxC,IAAA,IAAI,WAAW,MAAA,EAAW;AACxB,MAAA,OAAO,IAAI,YAAY,CAAC,CAAA;AAAA,IAC1B;AACA,IAAA,MAAM,SAAuB,EAAC;AAC9B,IAAA,IAAI,aAAA,GAAgB,CAAA;AACpB,IAAA,KAAA,IAAS,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK,EAAG,CAAC,IAAA,CAAK,IAAA,EAAM,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA,EAAK,EAAG;AAC3E,MAAA,aAAA,IAAiB,KAAK,KAAA,CAAM,UAAA;AAC5B,MAAA,IAAA,CAAK,WAAA,IAAe,KAAK,KAAA,CAAM,UAAA;AAC/B,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,QAAA,CAAS,GAAA,EAAK,aAAa,CAAA;AAChD,MAAA,IAAI,YAAY,MAAA,EAAW;AACzB,QAAA,MAAM,OAAO,MAAA,EAAO;AACpB,QAAA,MAAM,OAAA;AAAA,MACR;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,KAAK,CAAA;AAAA,IACxB;AACA,IAAA,OAAO,MAAA,CAAO,QAAQ,aAAa,CAAA;AAAA,EACrC;AAAA,EAEA,QAAA,CAAS,KAAa,aAAA,EAAyD;AAC7E,IAAA,MAAM,EAAE,gBAAA,EAAkB,aAAA,EAAc,GAAI,IAAA,CAAK,OAAA;AACjD,IAAA,IAAI,gBAAgB,gBAAA,EAAkB;AACpC,MAAA,OAAO,kBAAkB,GAAA,EAAK,EAAE,MAAA,EAAQ,2BAAA,EAA6B,kBAAkB,CAAA;AAAA,IACzF;AACA,IAAA,OAAO,IAAA,CAAK,WAAA,GAAc,aAAA,GACtB,iBAAA,CAAkB,GAAA,EAAK,EAAE,MAAA,EAAQ,4BAAA,EAA8B,aAAA,EAAe,CAAA,GAC9E,MAAA;AAAA,EACN;AACF;AAEA,SAAS,MAAA,CAAO,QAA+B,UAAA,EAAiC;AAC9E,EAAA,MAAM,IAAA,GAAO,IAAI,UAAA,CAAW,UAAU,CAAA;AACtC,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAA,CAAK,GAAA,CAAI,OAAO,MAAM,CAAA;AACtB,IAAA,MAAA,IAAU,KAAA,CAAM,UAAA;AAAA,EAClB;AACA,EAAA,OAAO,IAAA,CAAK,MAAA;AACd;;"}
@@ -2,13 +2,14 @@
2
2
 
3
3
  const allowedHosts = require('./allowed-hosts.cjs');
4
4
  const configuredHeaders = require('./configured-headers.cjs');
5
+ const remoteBodyLimit = require('./remote-body-limit.cjs');
5
6
  const schemaLoadErrors = require('./schema-load-errors.cjs');
6
7
 
7
8
  const MAX_REDIRECTS = 20;
8
9
  const REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
9
10
  const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
10
- async function bufferedResponse(response) {
11
- const body = await response.arrayBuffer();
11
+ async function bufferedResponse(response, url, bodyLimit) {
12
+ const body = await bodyLimit.read(response, url);
12
13
  const { status, statusText, headers } = response;
13
14
  return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {
14
15
  status,
@@ -16,25 +17,53 @@ async function bufferedResponse(response) {
16
17
  headers
17
18
  });
18
19
  }
19
- function fetchWithTimeout(timeoutMs) {
20
+ const CLOSED_CONNECTION_CODES = /* @__PURE__ */ new Set([
21
+ "ECONNRESET",
22
+ "EPIPE",
23
+ "UND_ERR_SOCKET"
24
+ ]);
25
+ const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
26
+ const DEFAULT_METHOD = "GET";
27
+ function isClosedConnection(error) {
28
+ const cause = error instanceof TypeError ? error.cause : void 0;
29
+ const code = cause instanceof Error && "code" in cause ? cause.code : void 0;
30
+ return typeof code === "string" && CLOSED_CONNECTION_CODES.has(code);
31
+ }
32
+ async function fetchOnOpenConnection(input, init) {
33
+ try {
34
+ return await fetch(input, init);
35
+ } catch (error) {
36
+ const method = (init.method ?? DEFAULT_METHOD).toUpperCase();
37
+ if (!(IDEMPOTENT_METHODS.has(method) && isClosedConnection(error))) {
38
+ throw error;
39
+ }
40
+ return fetch(input, init);
41
+ }
42
+ }
43
+ function fetchWithTimeout(timeoutMs, bodyLimit) {
20
44
  return async (input, init = {}) => {
21
45
  try {
22
- const response = await fetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });
23
- return await bufferedResponse(response);
46
+ const signal = AbortSignal.timeout(timeoutMs);
47
+ const response = await fetchOnOpenConnection(input, { ...init, signal });
48
+ return await bufferedResponse(response, input, bodyLimit);
24
49
  } catch (cause) {
25
50
  const isTimeout = cause instanceof Error && cause.name === "TimeoutError";
26
51
  throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;
27
52
  }
28
53
  };
29
54
  }
55
+ function fetchWithBodyLimit(fetchImpl, bodyLimit) {
56
+ return async (input, init) => bufferedResponse(await fetchImpl(input, init), input, bodyLimit);
57
+ }
30
58
  function fetchWithCheckedRedirects(fetchImpl, policy) {
31
59
  return async (input, init = {}) => {
60
+ const hosts = input === policy.rootUrl ? void 0 : policy.hosts;
32
61
  let url = new URL(input);
33
62
  for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {
34
- if (hop > 0 && policy.hosts !== void 0 && !allowedHosts.isHostAllowed(url, policy.hosts)) {
63
+ if (hop > 0 && hosts !== void 0 && !allowedHosts.isHostAllowed(url, hosts)) {
35
64
  throw schemaLoadErrors.refForbiddenError(url.href, {
36
65
  reason: "host-not-allowed",
37
- allowedHosts: [...policy.hosts]
66
+ allowedHosts: [...hosts]
38
67
  });
39
68
  }
40
69
  const headers = await configuredHeaders.headersFor(url, policy.headers);
@@ -71,10 +100,12 @@ function fetchWithConcurrencyLimit(fetchImpl, limit) {
71
100
  }
72
101
  function resolveConfigWithAccess(resolve, options) {
73
102
  const configured = resolve.http.customFetch;
74
- const base = configured ?? fetchWithTimeout(options.timeoutMs);
103
+ const bodyLimit = new remoteBodyLimit.RemoteBodyLimit(options.bodyLimits);
104
+ const base = configured === void 0 ? fetchWithTimeout(options.timeoutMs, bodyLimit) : fetchWithBodyLimit(configured, bodyLimit);
75
105
  const checked = fetchWithCheckedRedirects(base, {
76
106
  headers: resolve.http.headers,
77
- hosts: options.access.remoteHosts
107
+ hosts: options.access.remoteHosts,
108
+ rootUrl: options.rootUrl
78
109
  });
79
110
  const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);
80
111
  return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };
@@ -1 +1 @@
1
- {"version":3,"file":"remote-fetch.cjs","sources":["../../../src/adapters/redocly-loader/remote-fetch.ts"],"sourcesContent":["import type { Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport type { RefAccess } from \"../../application/ports/schema-loader.js\";\nimport { isHostAllowed } from \"./allowed-hosts.js\";\nimport { type ConfiguredHeader, headersFor } from \"./configured-headers.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/**\n * How the loader fetches remote documents: a time limit, the host limit and the configured headers\n * checked on every redirect.\n */\n\ntype ResolveConfig = RedoclyConfig[\"resolve\"];\n\n/** The fetch Redocly calls for a remote document (`resolve.http.customFetch`). */\nexport type RemoteFetch = (input: string, init?: RequestInit) => Promise<Response>;\n\n/**\n * Redirects followed for one remote document. The loader follows them itself, so that each hop is\n * checked; 20 is the limit of the Fetch standard, which fetch applied before.\n */\nexport const MAX_REDIRECTS = 20;\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\n/** Statuses whose responses have no body; `new Response()` refuses a body for them. */\nconst NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);\n\n/** A response whose body is already read, so that reading it again cannot wait or fail. */\nasync function bufferedResponse(response: Response): Promise<Response> {\n const body = await response.arrayBuffer();\n const { status, statusText, headers } = response;\n return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {\n status,\n statusText,\n headers,\n });\n}\n\n/**\n * Fetch with a time limit for the whole response, body included: Node's own fetch waits five\n * minutes for a server that never answers, and a server that sends its body one byte at a time\n * never finishes. The body is read here, inside the limit; when Redocly read it, the abort\n * surfaced as a `DOMException` whose read-only `message` Redocly tried to change, which gave\n * \"Cannot set property message of which has only a getter\" instead of the time limit.\n */\nfunction fetchWithTimeout(timeoutMs: number): RemoteFetch {\n return async (input, init = {}) => {\n try {\n const response = await fetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });\n return await bufferedResponse(response);\n } catch (cause) {\n const isTimeout = cause instanceof Error && cause.name === \"TimeoutError\";\n throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;\n }\n };\n}\n\n/** What every hop of a remote fetch is checked against. */\nexport interface RedirectPolicy {\n /** `resolve.http.headers` of the Redocly config; chosen again for the URL of every hop. */\n readonly headers: readonly ConfiguredHeader[];\n /** `--remote-ref-hosts`; undefined allows every host. */\n readonly hosts: readonly string[] | undefined;\n}\n\n/**\n * Follow redirects one by one. Fetch drops only `Authorization`, `Cookie` and\n * `Proxy-Authorization` on a redirect to another origin and keeps every other header (an\n * `X-Api-Key`), so the configured headers are chosen for each hop's own URL instead, and a hop to\n * a host that is not listed is refused before it is fetched. The first URL was checked by the\n * resolver (or is the root document). Redocly passes only the configured headers in `init`, and\n * it gets an empty list of them (`resolveConfigWithAccess`), so `init.headers` is replaced.\n */\nexport function fetchWithCheckedRedirects(\n fetchImpl: RemoteFetch,\n policy: RedirectPolicy,\n): RemoteFetch {\n return async (input, init = {}) => {\n let url = new URL(input);\n for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {\n if (hop > 0 && policy.hosts !== undefined && !isHostAllowed(url, policy.hosts)) {\n throw refForbiddenError(url.href, {\n reason: \"host-not-allowed\",\n allowedHosts: [...policy.hosts],\n });\n }\n const headers = await headersFor(url, policy.headers);\n const response = await fetchImpl(url.href, { ...init, headers, redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n if (!REDIRECT_STATUSES.has(response.status) || location === null) {\n return response;\n }\n url = new URL(location, url);\n }\n throw new Error(`More than ${MAX_REDIRECTS} redirects loading ${input}`);\n };\n}\n\n/** Bounds on the remote documents of one load (threat model T2, ADR-033). */\nexport interface RemoteDocumentLimits {\n /** Remote documents one load may fetch, the root included; one more is refused. */\n readonly maxDocuments: number;\n /** Remote documents fetched at the same time; the others wait for a free slot. */\n readonly maxParallelFetches: number;\n}\n\n/**\n * At most `limit` calls of the fetch run at once; the others wait in order. A finished call hands\n * its slot to the next waiting one.\n */\nexport function fetchWithConcurrencyLimit(fetchImpl: RemoteFetch, limit: number): RemoteFetch {\n let running = 0;\n const waiting: (() => void)[] = [];\n return async (input, init) => {\n if (running < limit) {\n running += 1;\n } else {\n await new Promise<void>((resolve) => waiting.push(resolve));\n }\n try {\n return await fetchImpl(input, init);\n } finally {\n const next = waiting.shift();\n if (next === undefined) {\n running -= 1;\n } else {\n next();\n }\n }\n };\n}\n\nexport interface RemoteFetchOptions {\n /** Time limit of one fetch and its body, unless the Redocly config has its own `customFetch`. */\n readonly timeoutMs: number;\n readonly access: RefAccess;\n readonly maxParallelFetches: number;\n}\n\n/**\n * The resolve config with the fetch the loader uses. A `customFetch` of the Redocly config is\n * kept and wrapped, so that each redirect is checked and only a few documents load at once. The\n * configured headers move into that wrapper: Redocly would match them against the raw URL and\n * send them on through redirects.\n */\nexport function resolveConfigWithAccess(\n resolve: ResolveConfig,\n options: RemoteFetchOptions,\n): ResolveConfig {\n // Redocly types `customFetch` as `Function`; it is called as fetch is.\n const configured = resolve.http.customFetch as RemoteFetch | undefined;\n const base = configured ?? fetchWithTimeout(options.timeoutMs);\n const checked = fetchWithCheckedRedirects(base, {\n headers: resolve.http.headers,\n hosts: options.access.remoteHosts,\n });\n // The limit is outside the redirects, so all hops of one document share one slot.\n const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);\n return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };\n}\n"],"names":["isHostAllowed","refForbiddenError","headersFor"],"mappings":"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"}
1
+ {"version":3,"file":"remote-fetch.cjs","sources":["../../../src/adapters/redocly-loader/remote-fetch.ts"],"sourcesContent":["import type { Config as RedoclyConfig } from \"@redocly/openapi-core\";\nimport type { RefAccess } from \"../../application/ports/schema-loader.js\";\nimport { isHostAllowed } from \"./allowed-hosts.js\";\nimport { type ConfiguredHeader, headersFor } from \"./configured-headers.js\";\nimport { RemoteBodyLimit, type RemoteBodyLimits } from \"./remote-body-limit.js\";\nimport { refForbiddenError } from \"./schema-load-errors.js\";\n\n/**\n * How the loader fetches remote documents: a time limit, size limits, the host limit and the\n * configured headers checked on every redirect.\n */\n\ntype ResolveConfig = RedoclyConfig[\"resolve\"];\n\n/** The fetch Redocly calls for a remote document (`resolve.http.customFetch`). */\nexport type RemoteFetch = (input: string, init?: RequestInit) => Promise<Response>;\n\n/**\n * Redirects followed for one remote document. The loader follows them itself, so that each hop is\n * checked; 20 is the limit of the Fetch standard, which fetch applied before.\n */\nexport const MAX_REDIRECTS = 20;\n\nconst REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);\n\n/** Statuses whose responses have no body; `new Response()` refuses a body for them. */\nconst NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);\n\n/**\n * A response whose body is already read within the size limits, so that reading it again cannot\n * wait, fail or take more memory.\n */\nasync function bufferedResponse(\n response: Response,\n url: string,\n bodyLimit: RemoteBodyLimit,\n): Promise<Response> {\n const body = await bodyLimit.read(response, url);\n const { status, statusText, headers } = response;\n return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {\n status,\n statusText,\n headers,\n });\n}\n\n/**\n * Codes of a connection that closed before any response came. The server can close a kept-alive\n * connection while the process is busy (parsing a large document, generating another API) and\n * has not read the close yet; the next request on that connection then fails with one of these.\n */\nconst CLOSED_CONNECTION_CODES: ReadonlySet<string> = new Set([\n \"ECONNRESET\",\n \"EPIPE\",\n \"UND_ERR_SOCKET\",\n]);\n\n/** Methods that may be sent again without a second effect (RFC 9110 §9.2.2). */\nconst IDEMPOTENT_METHODS: ReadonlySet<string> = new Set([\"GET\", \"HEAD\"]);\nconst DEFAULT_METHOD = \"GET\";\n\n/** Whether fetch failed because its connection closed before any response came. */\nfunction isClosedConnection(error: unknown): boolean {\n const cause = error instanceof TypeError ? error.cause : undefined;\n const code = cause instanceof Error && \"code\" in cause ? cause.code : undefined;\n return typeof code === \"string\" && CLOSED_CONNECTION_CODES.has(code);\n}\n\n/**\n * Fetch, and send the request once more when its connection closed before any response came, as\n * RFC 9112 §9.3.1 allows for an idempotent request. Fetch drops a connection that failed, so the\n * second attempt goes out on another one; a second failure is the server's answer and is thrown.\n */\nasync function fetchOnOpenConnection(input: string, init: RequestInit): Promise<Response> {\n try {\n return await fetch(input, init);\n } catch (error) {\n const method = (init.method ?? DEFAULT_METHOD).toUpperCase();\n if (!(IDEMPOTENT_METHODS.has(method) && isClosedConnection(error))) {\n throw error;\n }\n return fetch(input, init);\n }\n}\n\n/**\n * Fetch with a time limit for the whole response, body included: Node's own fetch waits five\n * minutes for a server that never answers, and a server that sends its body one byte at a time\n * never finishes. The body is read here, inside the limit; when Redocly read it, the abort\n * surfaced as a `DOMException` whose read-only `message` Redocly tried to change, which gave\n * \"Cannot set property message of which has only a getter\" instead of the time limit.\n */\nfunction fetchWithTimeout(timeoutMs: number, bodyLimit: RemoteBodyLimit): RemoteFetch {\n return async (input, init = {}) => {\n try {\n // One signal for both attempts, so that a request sent again stays within the same limit.\n const signal = AbortSignal.timeout(timeoutMs);\n const response = await fetchOnOpenConnection(input, { ...init, signal });\n return await bufferedResponse(response, input, bodyLimit);\n } catch (cause) {\n const isTimeout = cause instanceof Error && cause.name === \"TimeoutError\";\n throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;\n }\n };\n}\n\n/** A configured `customFetch` with its bodies read within the size limits. */\nfunction fetchWithBodyLimit(fetchImpl: RemoteFetch, bodyLimit: RemoteBodyLimit): RemoteFetch {\n return async (input, init) => bufferedResponse(await fetchImpl(input, init), input, bodyLimit);\n}\n\n/** What every hop of a remote fetch is checked against. */\nexport interface RedirectPolicy {\n /** `resolve.http.headers` of the Redocly config; chosen again for the URL of every hop. */\n readonly headers: readonly ConfiguredHeader[];\n /** `--remote-ref-hosts`; undefined allows every host. */\n readonly hosts: readonly string[] | undefined;\n /**\n * The URL of the root document, if it is remote. The developer chose it, so neither it nor its\n * redirects are limited to the hosts (ADR-017): a spec URL that redirects to a CDN loads.\n */\n readonly rootUrl: string | undefined;\n}\n\n/**\n * Follow redirects one by one. Fetch drops only `Authorization`, `Cookie` and\n * `Proxy-Authorization` on a redirect to another origin and keeps every other header (an\n * `X-Api-Key`), so the configured headers are chosen for each hop's own URL instead, and a hop to\n * a host that is not listed is refused before it is fetched. The first URL was checked by the\n * resolver (or is the root document). Redocly passes only the configured headers in `init`, and\n * it gets an empty list of them (`resolveConfigWithAccess`), so `init.headers` is replaced.\n */\nexport function fetchWithCheckedRedirects(\n fetchImpl: RemoteFetch,\n policy: RedirectPolicy,\n): RemoteFetch {\n return async (input, init = {}) => {\n const hosts = input === policy.rootUrl ? undefined : policy.hosts;\n let url = new URL(input);\n for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {\n if (hop > 0 && hosts !== undefined && !isHostAllowed(url, hosts)) {\n throw refForbiddenError(url.href, {\n reason: \"host-not-allowed\",\n allowedHosts: [...hosts],\n });\n }\n const headers = await headersFor(url, policy.headers);\n const response = await fetchImpl(url.href, { ...init, headers, redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n if (!REDIRECT_STATUSES.has(response.status) || location === null) {\n return response;\n }\n url = new URL(location, url);\n }\n throw new Error(`More than ${MAX_REDIRECTS} redirects loading ${input}`);\n };\n}\n\n/** Bounds on the remote documents of one load (threat model T2, ADR-033). */\nexport interface RemoteDocumentLimits extends RemoteBodyLimits {\n /** Remote documents one load may fetch, the root included; one more is refused. */\n readonly maxDocuments: number;\n /** Remote documents fetched at the same time; the others wait for a free slot. */\n readonly maxParallelFetches: number;\n /** Nodes (keys and values) the remote documents of one load may parse into together. */\n readonly maxNodes: number;\n}\n\n/**\n * At most `limit` calls of the fetch run at once; the others wait in order. A finished call hands\n * its slot to the next waiting one.\n */\nexport function fetchWithConcurrencyLimit(fetchImpl: RemoteFetch, limit: number): RemoteFetch {\n let running = 0;\n const waiting: (() => void)[] = [];\n return async (input, init) => {\n if (running < limit) {\n running += 1;\n } else {\n await new Promise<void>((resolve) => waiting.push(resolve));\n }\n try {\n return await fetchImpl(input, init);\n } finally {\n const next = waiting.shift();\n if (next === undefined) {\n running -= 1;\n } else {\n next();\n }\n }\n };\n}\n\nexport interface RemoteFetchOptions {\n /** Time limit of one fetch and its body, unless the Redocly config has its own `customFetch`. */\n readonly timeoutMs: number;\n readonly access: RefAccess;\n /** The root document's URL, whose redirects are not limited to the hosts. */\n readonly rootUrl: string | undefined;\n readonly maxParallelFetches: number;\n readonly bodyLimits: RemoteBodyLimits;\n}\n\n/**\n * The resolve config with the fetch the loader uses. A `customFetch` of the Redocly config is\n * kept and wrapped, so that each redirect is checked, each body is read within the size limits\n * and only a few documents load at once. The\n * configured headers move into that wrapper: Redocly would match them against the raw URL and\n * send them on through redirects.\n */\nexport function resolveConfigWithAccess(\n resolve: ResolveConfig,\n options: RemoteFetchOptions,\n): ResolveConfig {\n // Redocly types `customFetch` as `Function`; it is called as fetch is.\n const configured = resolve.http.customFetch as RemoteFetch | undefined;\n // One limit per load, so that the total covers every document this resolver fetches.\n const bodyLimit = new RemoteBodyLimit(options.bodyLimits);\n const base =\n configured === undefined\n ? fetchWithTimeout(options.timeoutMs, bodyLimit)\n : fetchWithBodyLimit(configured, bodyLimit);\n const checked = fetchWithCheckedRedirects(base, {\n headers: resolve.http.headers,\n hosts: options.access.remoteHosts,\n rootUrl: options.rootUrl,\n });\n // The limit is outside the redirects, so all hops of one document share one slot.\n const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);\n return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };\n}\n"],"names":["isHostAllowed","refForbiddenError","headersFor","RemoteBodyLimit"],"mappings":"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"}
@@ -1,12 +1,13 @@
1
1
  import { isHostAllowed } from './allowed-hosts.mjs';
2
2
  import { headersFor } from './configured-headers.mjs';
3
+ import { RemoteBodyLimit } from './remote-body-limit.mjs';
3
4
  import { refForbiddenError } from './schema-load-errors.mjs';
4
5
 
5
6
  const MAX_REDIRECTS = 20;
6
7
  const REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
7
8
  const NULL_BODY_STATUSES = /* @__PURE__ */ new Set([101, 103, 204, 205, 304]);
8
- async function bufferedResponse(response) {
9
- const body = await response.arrayBuffer();
9
+ async function bufferedResponse(response, url, bodyLimit) {
10
+ const body = await bodyLimit.read(response, url);
10
11
  const { status, statusText, headers } = response;
11
12
  return new Response(NULL_BODY_STATUSES.has(status) ? null : body, {
12
13
  status,
@@ -14,25 +15,53 @@ async function bufferedResponse(response) {
14
15
  headers
15
16
  });
16
17
  }
17
- function fetchWithTimeout(timeoutMs) {
18
+ const CLOSED_CONNECTION_CODES = /* @__PURE__ */ new Set([
19
+ "ECONNRESET",
20
+ "EPIPE",
21
+ "UND_ERR_SOCKET"
22
+ ]);
23
+ const IDEMPOTENT_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
24
+ const DEFAULT_METHOD = "GET";
25
+ function isClosedConnection(error) {
26
+ const cause = error instanceof TypeError ? error.cause : void 0;
27
+ const code = cause instanceof Error && "code" in cause ? cause.code : void 0;
28
+ return typeof code === "string" && CLOSED_CONNECTION_CODES.has(code);
29
+ }
30
+ async function fetchOnOpenConnection(input, init) {
31
+ try {
32
+ return await fetch(input, init);
33
+ } catch (error) {
34
+ const method = (init.method ?? DEFAULT_METHOD).toUpperCase();
35
+ if (!(IDEMPOTENT_METHODS.has(method) && isClosedConnection(error))) {
36
+ throw error;
37
+ }
38
+ return fetch(input, init);
39
+ }
40
+ }
41
+ function fetchWithTimeout(timeoutMs, bodyLimit) {
18
42
  return async (input, init = {}) => {
19
43
  try {
20
- const response = await fetch(input, { ...init, signal: AbortSignal.timeout(timeoutMs) });
21
- return await bufferedResponse(response);
44
+ const signal = AbortSignal.timeout(timeoutMs);
45
+ const response = await fetchOnOpenConnection(input, { ...init, signal });
46
+ return await bufferedResponse(response, input, bodyLimit);
22
47
  } catch (cause) {
23
48
  const isTimeout = cause instanceof Error && cause.name === "TimeoutError";
24
49
  throw isTimeout ? new Error(`Timed out after ${timeoutMs} ms loading ${input}`) : cause;
25
50
  }
26
51
  };
27
52
  }
53
+ function fetchWithBodyLimit(fetchImpl, bodyLimit) {
54
+ return async (input, init) => bufferedResponse(await fetchImpl(input, init), input, bodyLimit);
55
+ }
28
56
  function fetchWithCheckedRedirects(fetchImpl, policy) {
29
57
  return async (input, init = {}) => {
58
+ const hosts = input === policy.rootUrl ? void 0 : policy.hosts;
30
59
  let url = new URL(input);
31
60
  for (let hop = 0; hop <= MAX_REDIRECTS; hop += 1) {
32
- if (hop > 0 && policy.hosts !== void 0 && !isHostAllowed(url, policy.hosts)) {
61
+ if (hop > 0 && hosts !== void 0 && !isHostAllowed(url, hosts)) {
33
62
  throw refForbiddenError(url.href, {
34
63
  reason: "host-not-allowed",
35
- allowedHosts: [...policy.hosts]
64
+ allowedHosts: [...hosts]
36
65
  });
37
66
  }
38
67
  const headers = await headersFor(url, policy.headers);
@@ -69,10 +98,12 @@ function fetchWithConcurrencyLimit(fetchImpl, limit) {
69
98
  }
70
99
  function resolveConfigWithAccess(resolve, options) {
71
100
  const configured = resolve.http.customFetch;
72
- const base = configured ?? fetchWithTimeout(options.timeoutMs);
101
+ const bodyLimit = new RemoteBodyLimit(options.bodyLimits);
102
+ const base = configured === void 0 ? fetchWithTimeout(options.timeoutMs, bodyLimit) : fetchWithBodyLimit(configured, bodyLimit);
73
103
  const checked = fetchWithCheckedRedirects(base, {
74
104
  headers: resolve.http.headers,
75
- hosts: options.access.remoteHosts
105
+ hosts: options.access.remoteHosts,
106
+ rootUrl: options.rootUrl
76
107
  });
77
108
  const customFetch = fetchWithConcurrencyLimit(checked, options.maxParallelFetches);
78
109
  return { ...resolve, http: { ...resolve.http, headers: [], customFetch } };