toolcraft-openapi 0.0.26 → 0.0.33

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 (218) hide show
  1. package/dist/auth/bearer-token-auth.js +1 -1
  2. package/dist/bin/generate.d.ts +9 -1
  3. package/dist/bin/generate.js +65 -9
  4. package/dist/error-codes.d.ts +1 -0
  5. package/dist/error-codes.js +6 -0
  6. package/dist/generate.d.ts +20 -3
  7. package/dist/generate.js +604 -144
  8. package/dist/http.d.ts +17 -1
  9. package/dist/http.js +113 -7
  10. package/dist/index.d.ts +6 -1
  11. package/dist/index.js +3 -0
  12. package/dist/inspect-source.d.ts +10 -0
  13. package/dist/inspect-source.js +14 -0
  14. package/dist/inspect.d.ts +22 -0
  15. package/dist/inspect.js +171 -0
  16. package/dist/interpreter.js +6 -2
  17. package/dist/mock/fetch.js +28 -12
  18. package/dist/mock/forgeyard.d.ts +4 -0
  19. package/dist/mock/forgeyard.js +452 -0
  20. package/dist/mock.d.ts +1 -0
  21. package/dist/mock.js +1 -0
  22. package/dist/naming.d.ts +4 -1
  23. package/dist/naming.js +93 -7
  24. package/dist/network-error.js +29 -12
  25. package/dist/normalize-swagger.d.ts +2 -0
  26. package/dist/normalize-swagger.js +201 -0
  27. package/dist/render-inspection.d.ts +2 -0
  28. package/dist/render-inspection.js +130 -0
  29. package/dist/request-shape.d.ts +4 -0
  30. package/dist/request-shape.js +1 -0
  31. package/dist/runtime.js +7 -1
  32. package/dist/spec-source.js +7 -4
  33. package/node_modules/auth-store/dist/create-secret-store.js +6 -1
  34. package/node_modules/auth-store/dist/encrypted-file-store.d.ts +1 -1
  35. package/node_modules/auth-store/dist/encrypted-file-store.js +32 -28
  36. package/node_modules/auth-store/dist/error-codes.d.ts +1 -0
  37. package/node_modules/auth-store/dist/error-codes.js +5 -0
  38. package/node_modules/auth-store/dist/keychain-store.js +23 -8
  39. package/node_modules/toolcraft-design/README.md +148 -0
  40. package/node_modules/toolcraft-design/dist/components/catalog.d.ts +26 -0
  41. package/node_modules/toolcraft-design/dist/components/catalog.js +94 -0
  42. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/index.d.ts +2 -0
  43. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/index.js +1 -0
  44. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/footer.js +1 -2
  45. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/output-pane.js +16 -19
  46. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/stats-pane.js +1 -15
  47. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/demo.js +2 -2
  48. package/node_modules/toolcraft-design/dist/explorer/theme.js +29 -0
  49. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/index.d.ts +7 -1
  50. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/index.js +4 -0
  51. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/theme-detect.d.ts +1 -0
  52. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/theme-detect.js +28 -6
  53. package/node_modules/toolcraft-design/dist/internal/theme-state.d.ts +12 -0
  54. package/node_modules/toolcraft-design/dist/internal/theme-state.js +35 -0
  55. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/theme.d.ts +1 -1
  56. package/node_modules/toolcraft-design/dist/prompts/theme.js +15 -0
  57. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/frontmatter.js +50 -0
  58. package/node_modules/toolcraft-design/dist/tokens/brand.d.ts +5 -0
  59. package/node_modules/toolcraft-design/dist/tokens/brand.js +5 -0
  60. package/node_modules/toolcraft-design/dist/tokens/colors.d.ts +37 -0
  61. package/node_modules/toolcraft-design/dist/tokens/colors.js +85 -0
  62. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/index.d.ts +2 -0
  63. package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/index.js +1 -0
  64. package/node_modules/toolcraft-design/package.json +42 -0
  65. package/package.json +8 -6
  66. package/node_modules/@poe-code/design-system/dist/explorer/theme.js +0 -97
  67. package/node_modules/@poe-code/design-system/dist/prompts/theme.js +0 -12
  68. package/node_modules/@poe-code/design-system/dist/tokens/colors.d.ts +0 -35
  69. package/node_modules/@poe-code/design-system/dist/tokens/colors.js +0 -34
  70. package/node_modules/@poe-code/design-system/package.json +0 -29
  71. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/components.d.ts +0 -0
  72. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/components.js +0 -0
  73. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/index.d.ts +0 -0
  74. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/index.js +0 -0
  75. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/writer.d.ts +0 -0
  76. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/acp/writer.js +0 -0
  77. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/browser.d.ts +0 -0
  78. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/browser.js +0 -0
  79. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/color.d.ts +0 -0
  80. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/color.js +0 -0
  81. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/command-errors.d.ts +0 -0
  82. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/command-errors.js +0 -0
  83. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/detail-card.d.ts +0 -0
  84. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/detail-card.js +0 -0
  85. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/help-formatter-plain.d.ts +0 -0
  86. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/help-formatter-plain.js +0 -0
  87. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/help-formatter.d.ts +0 -0
  88. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/help-formatter.js +0 -0
  89. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/logger.d.ts +0 -0
  90. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/logger.js +0 -0
  91. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/symbols.d.ts +0 -0
  92. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/symbols.js +0 -0
  93. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/table.d.ts +0 -0
  94. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/table.js +0 -0
  95. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/template.d.ts +0 -0
  96. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/template.js +0 -0
  97. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/text.d.ts +0 -0
  98. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/components/text.js +0 -0
  99. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/ansi.d.ts +0 -0
  100. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/ansi.js +0 -0
  101. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/buffer.d.ts +0 -0
  102. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/buffer.js +0 -0
  103. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/border.d.ts +0 -0
  104. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/border.js +0 -0
  105. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/footer.d.ts +0 -0
  106. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/output-pane.d.ts +0 -0
  107. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/components/stats-pane.d.ts +0 -0
  108. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/dashboard.d.ts +0 -0
  109. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/dashboard.js +0 -0
  110. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/demo.d.ts +0 -0
  111. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/demo.js +0 -0
  112. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/index.d.ts +0 -0
  113. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/index.js +0 -0
  114. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/keymap.d.ts +0 -0
  115. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/keymap.js +0 -0
  116. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/layout.d.ts +0 -0
  117. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/layout.js +0 -0
  118. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/should-use-dashboard.d.ts +0 -0
  119. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/should-use-dashboard.js +0 -0
  120. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/snapshot.d.ts +0 -0
  121. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/snapshot.js +0 -0
  122. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/store.d.ts +0 -0
  123. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/store.js +0 -0
  124. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/terminal-width.d.ts +0 -0
  125. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/terminal-width.js +0 -0
  126. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/terminal.d.ts +0 -0
  127. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/terminal.js +0 -0
  128. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/types.d.ts +0 -0
  129. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/dashboard/types.js +0 -0
  130. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/actions.d.ts +0 -0
  131. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/actions.js +0 -0
  132. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/demo.d.ts +0 -0
  133. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/events.d.ts +0 -0
  134. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/events.js +0 -0
  135. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/filter.d.ts +0 -0
  136. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/filter.js +0 -0
  137. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/index.d.ts +0 -0
  138. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/index.js +0 -0
  139. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/jobs.d.ts +0 -0
  140. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/jobs.js +0 -0
  141. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/keymap.d.ts +0 -0
  142. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/keymap.js +0 -0
  143. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/layout.d.ts +0 -0
  144. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/layout.js +0 -0
  145. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/reducer.d.ts +0 -0
  146. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/reducer.js +0 -0
  147. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/detail.d.ts +0 -0
  148. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/detail.js +0 -0
  149. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/footer.d.ts +0 -0
  150. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/footer.js +0 -0
  151. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/header.d.ts +0 -0
  152. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/header.js +0 -0
  153. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/index.d.ts +0 -0
  154. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/index.js +0 -0
  155. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/list.d.ts +0 -0
  156. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/list.js +0 -0
  157. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/modal.d.ts +0 -0
  158. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/modal.js +0 -0
  159. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/test-fixtures.d.ts +0 -0
  160. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/test-fixtures.js +0 -0
  161. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/text.d.ts +0 -0
  162. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/render/text.js +0 -0
  163. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/runtime.d.ts +0 -0
  164. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/runtime.js +0 -0
  165. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/runtime.test-helpers.d.ts +0 -0
  166. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/runtime.test-helpers.js +0 -0
  167. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/state.d.ts +0 -0
  168. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/state.js +0 -0
  169. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/explorer/theme.d.ts +0 -0
  170. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/color-support.d.ts +0 -0
  171. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/color-support.js +0 -0
  172. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/output-format.d.ts +0 -0
  173. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/output-format.js +0 -0
  174. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/strip-ansi.d.ts +0 -0
  175. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/internal/strip-ansi.js +0 -0
  176. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/index.d.ts +0 -0
  177. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/index.js +0 -0
  178. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/cancel.d.ts +0 -0
  179. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/cancel.js +0 -0
  180. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/intro.d.ts +0 -0
  181. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/intro.js +0 -0
  182. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/log.d.ts +0 -0
  183. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/log.js +0 -0
  184. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/note.d.ts +0 -0
  185. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/note.js +0 -0
  186. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/outro.d.ts +0 -0
  187. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/outro.js +0 -0
  188. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/spinner.d.ts +0 -0
  189. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/prompts/primitives/spinner.js +0 -0
  190. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/index.d.ts +0 -0
  191. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/index.js +0 -0
  192. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/menu.d.ts +0 -0
  193. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/menu.js +0 -0
  194. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/spinner.d.ts +0 -0
  195. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/static/spinner.js +0 -0
  196. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/ast.d.ts +0 -0
  197. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/ast.js +0 -0
  198. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/demo-content.d.ts +0 -0
  199. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/demo-content.js +0 -0
  200. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/index.d.ts +0 -0
  201. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/index.js +0 -0
  202. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/block.d.ts +0 -0
  203. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/block.js +0 -0
  204. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/frontmatter.d.ts +0 -0
  205. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/inline.d.ts +0 -0
  206. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser/inline.js +0 -0
  207. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser.d.ts +0 -0
  208. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/parser.js +0 -0
  209. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/renderer.d.ts +0 -0
  210. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/renderer.js +0 -0
  211. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/testing/theme-render-fixture.d.ts +0 -0
  212. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/terminal-markdown/testing/theme-render-fixture.js +0 -0
  213. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/spacing.d.ts +0 -0
  214. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/spacing.js +0 -0
  215. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/typography.d.ts +0 -0
  216. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/typography.js +0 -0
  217. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/widths.d.ts +0 -0
  218. /package/node_modules/{@poe-code/design-system → toolcraft-design}/dist/tokens/widths.js +0 -0
@@ -5,7 +5,7 @@ export function classifyNetworkError(error, url) {
5
5
  const urlParts = new URL(url);
6
6
  const host = getHost(networkError, urlParts);
7
7
  const redactedUrl = redactSensitiveQueryValues(url);
8
- switch (networkError?.code) {
8
+ switch (readStringProperty(networkError, "code")) {
9
9
  case "ECONNREFUSED":
10
10
  return new UserError(`Connection refused: ${host}:${getPort(networkError, urlParts)}. Is the server running?`, { cause: error });
11
11
  case "ETIMEDOUT":
@@ -36,10 +36,10 @@ export function classifyNetworkError(error, url) {
36
36
  function findNetworkError(error) {
37
37
  let current = error;
38
38
  while (isErrorLikeObject(current)) {
39
- if (typeof current.code === "string") {
39
+ if (readStringProperty(current, "code") !== undefined) {
40
40
  return current;
41
41
  }
42
- current = current.cause;
42
+ current = readOwnProperty(current, "cause");
43
43
  }
44
44
  return null;
45
45
  }
@@ -52,19 +52,20 @@ function findAbortError(error) {
52
52
  if (isAbortError(current)) {
53
53
  return current;
54
54
  }
55
- current = current.cause;
55
+ current = readOwnProperty(current, "cause");
56
56
  }
57
57
  return null;
58
58
  }
59
59
  function hasCause(error) {
60
- return "cause" in error && error.cause !== undefined;
60
+ return readOwnProperty(error, "cause") !== undefined;
61
61
  }
62
62
  function getHost(error, url) {
63
- return typeof error?.address === "string" ? error.address : url.hostname;
63
+ return readStringProperty(error, "address") ?? url.hostname;
64
64
  }
65
65
  function getPort(error, url) {
66
- if (typeof error?.port === "number" || typeof error?.port === "string") {
67
- return String(error.port);
66
+ const port = readStringOrNumberProperty(error, "port");
67
+ if (port !== undefined) {
68
+ return String(port);
68
69
  }
69
70
  if (url.port) {
70
71
  return url.port;
@@ -72,14 +73,30 @@ function getPort(error, url) {
72
73
  return url.protocol === "https:" ? "443" : "80";
73
74
  }
74
75
  function getTimeoutMs(error) {
75
- if (typeof error.ms === "number" || typeof error.ms === "string") {
76
- return String(error.ms);
76
+ const ms = readStringOrNumberProperty(error, "ms");
77
+ if (ms !== undefined) {
78
+ return String(ms);
77
79
  }
78
- if (typeof error.timeout === "number" || typeof error.timeout === "string") {
79
- return String(error.timeout);
80
+ const timeout = readStringOrNumberProperty(error, "timeout");
81
+ if (timeout !== undefined) {
82
+ return String(timeout);
80
83
  }
81
84
  return "unknown";
82
85
  }
83
86
  function isErrorLikeObject(value) {
84
87
  return typeof value === "object" && value !== null;
85
88
  }
89
+ function readOwnProperty(value, name) {
90
+ if (value === null || value === undefined || !Object.prototype.hasOwnProperty.call(value, name)) {
91
+ return undefined;
92
+ }
93
+ return value[name];
94
+ }
95
+ function readStringProperty(value, name) {
96
+ const property = readOwnProperty(value, name);
97
+ return typeof property === "string" ? property : undefined;
98
+ }
99
+ function readStringOrNumberProperty(value, name) {
100
+ const property = readOwnProperty(value, name);
101
+ return typeof property === "string" || typeof property === "number" ? property : undefined;
102
+ }
@@ -0,0 +1,2 @@
1
+ import type { OpenApiDocument } from "./generate.js";
2
+ export declare function normalizeOpenApiDocument(document: OpenApiDocument): OpenApiDocument;
@@ -0,0 +1,201 @@
1
+ const HTTP_METHODS = ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
2
+ const SCHEMA_PARAMETER_KEYS = [
3
+ "type",
4
+ "format",
5
+ "items",
6
+ "default",
7
+ "enum",
8
+ "minimum",
9
+ "maximum",
10
+ "minLength",
11
+ "maxLength",
12
+ "pattern",
13
+ "minItems",
14
+ "maxItems"
15
+ ];
16
+ export function normalizeOpenApiDocument(document) {
17
+ const source = document;
18
+ if (source.swagger !== "2.0") {
19
+ return document;
20
+ }
21
+ const consumes = readStringArray(source.consumes);
22
+ const produces = readStringArray(source.produces);
23
+ const paths = Object.fromEntries(Object.entries(source.paths ?? {}).map(([path, pathItem]) => [
24
+ path,
25
+ pathItem === undefined
26
+ ? undefined
27
+ : normalizePathItem(pathItem, consumes, produces, isRecord(source.parameters) ? source.parameters : {})
28
+ ]));
29
+ const components = {
30
+ ...(source.components ?? {}),
31
+ ...(!isRecord(source.definitions) ? {} : { schemas: rewriteReferences(source.definitions) }),
32
+ ...(!isRecord(source.parameters) ? {} : { parameters: rewriteReferences(source.parameters) }),
33
+ ...(!isRecord(source.responses) ? {} : { responses: rewriteReferences(source.responses) }),
34
+ ...(!isRecord(source.securityDefinitions)
35
+ ? {}
36
+ : { securitySchemes: rewriteReferences(source.securityDefinitions) })
37
+ };
38
+ return rewriteReferences({
39
+ ...source,
40
+ openapi: "3.0.3",
41
+ paths,
42
+ components
43
+ });
44
+ }
45
+ function normalizePathItem(pathItem, documentConsumes, documentProduces, reusableParameters) {
46
+ const normalized = {
47
+ ...pathItem,
48
+ ...(pathItem.parameters === undefined
49
+ ? {}
50
+ : { parameters: pathItem.parameters.map((parameter) => normalizeParameter(resolveReusableParameter(parameter, reusableParameters))).filter(isOpenApiParameter) })
51
+ };
52
+ for (const method of HTTP_METHODS) {
53
+ const operation = pathItem[method];
54
+ if (!isRecord(operation) || isReferenceObject(operation)) {
55
+ continue;
56
+ }
57
+ normalized[method] = normalizeOperation(operation, documentConsumes, documentProduces, reusableParameters);
58
+ }
59
+ return normalized;
60
+ }
61
+ function normalizeOperation(operation, documentConsumes, documentProduces, reusableParameters) {
62
+ const parameters = (operation.parameters ?? []).map((parameter) => normalizeParameter(resolveReusableParameter(parameter, reusableParameters)));
63
+ const body = parameters.find(isSwaggerBodyParameter);
64
+ const formParameters = parameters.filter(isSwaggerFormParameter);
65
+ const nonBodyParameters = parameters.filter((parameter) => isOpenApiParameter(parameter) && !isSwaggerFormParameter(parameter));
66
+ const consumes = readStringArray(operation.consumes).length > 0
67
+ ? readStringArray(operation.consumes)
68
+ : documentConsumes;
69
+ const produces = readStringArray(operation.produces).length > 0
70
+ ? readStringArray(operation.produces)
71
+ : documentProduces;
72
+ return {
73
+ ...operation,
74
+ parameters: nonBodyParameters,
75
+ ...(body !== undefined
76
+ ? { requestBody: normalizeBodyParameter(body, consumes) }
77
+ : formParameters.length === 0
78
+ ? {}
79
+ : { requestBody: normalizeFormParameters(formParameters, consumes) }),
80
+ responses: Object.fromEntries(Object.entries(operation.responses ?? {}).map(([status, response]) => [
81
+ status,
82
+ normalizeResponse(response, produces)
83
+ ]))
84
+ };
85
+ }
86
+ function resolveReusableParameter(parameter, reusableParameters) {
87
+ if (!isReferenceObject(parameter) || !parameter.$ref.startsWith("#/parameters/")) {
88
+ return parameter;
89
+ }
90
+ return reusableParameters[parameter.$ref.slice("#/parameters/".length)];
91
+ }
92
+ function normalizeParameter(parameter) {
93
+ if (isReferenceObject(parameter)) {
94
+ return { $ref: rewriteReference(parameter.$ref) };
95
+ }
96
+ if (parameter.in === "body") {
97
+ return {
98
+ in: "body",
99
+ required: parameter.required === true,
100
+ description: typeof parameter.description === "string" ? parameter.description : undefined,
101
+ schema: rewriteReferences(parameter.schema ?? {})
102
+ };
103
+ }
104
+ const parameterRecord = parameter;
105
+ const schema = isRecord(parameterRecord.schema)
106
+ ? parameterRecord.schema
107
+ : Object.fromEntries(SCHEMA_PARAMETER_KEYS.flatMap((key) => parameterRecord[key] === undefined ? [] : [[key, parameterRecord[key]]]));
108
+ const normalized = {
109
+ ...parameter,
110
+ schema: rewriteReferences(parameter.in === "formData" && parameterRecord.type === "file"
111
+ ? { type: "string", format: "binary" }
112
+ : schema)
113
+ };
114
+ return parameter.in === "formData"
115
+ ? normalized
116
+ : normalized;
117
+ }
118
+ function normalizeBodyParameter(parameter, consumes) {
119
+ const mediaTypes = consumes.length === 0 ? ["application/json"] : consumes;
120
+ return {
121
+ ...(parameter.description === undefined ? {} : { description: parameter.description }),
122
+ ...(parameter.required ? { required: true } : {}),
123
+ content: Object.fromEntries(mediaTypes.map((mediaType) => [mediaType, { schema: parameter.schema }]))
124
+ };
125
+ }
126
+ function normalizeResponse(response, produces) {
127
+ if (isReferenceObject(response)) {
128
+ return { $ref: rewriteReference(response.$ref) };
129
+ }
130
+ const responseRecord = response;
131
+ if (responseRecord.schema === undefined) {
132
+ return response;
133
+ }
134
+ const mediaTypes = produces.length === 0 ? ["application/json"] : produces;
135
+ return {
136
+ ...response,
137
+ content: Object.fromEntries(mediaTypes.map((mediaType) => [
138
+ mediaType,
139
+ { schema: rewriteReferences(responseRecord.schema) }
140
+ ]))
141
+ };
142
+ }
143
+ function isSwaggerBodyParameter(parameter) {
144
+ return !isReferenceObject(parameter) && parameter.in === "body";
145
+ }
146
+ function isSwaggerFormParameter(parameter) {
147
+ return !isReferenceObject(parameter) && parameter.in === "formData";
148
+ }
149
+ function normalizeFormParameters(parameters, consumes) {
150
+ const required = parameters.filter((parameter) => parameter.required === true).map((parameter) => parameter.name);
151
+ const mediaType = consumes.find((value) => value.toLowerCase() === "multipart/form-data") ??
152
+ "application/x-www-form-urlencoded";
153
+ return {
154
+ ...(required.length === 0 ? {} : { required: true }),
155
+ content: {
156
+ [mediaType]: {
157
+ schema: {
158
+ type: "object",
159
+ ...(required.length === 0 ? {} : { required }),
160
+ properties: Object.fromEntries(parameters.map((parameter) => [
161
+ parameter.name,
162
+ {
163
+ ...parameter.schema,
164
+ ...(parameter.description === undefined ? {} : { description: parameter.description })
165
+ }
166
+ ]))
167
+ }
168
+ }
169
+ }
170
+ };
171
+ }
172
+ function isOpenApiParameter(parameter) {
173
+ return isReferenceObject(parameter) || (parameter.in !== "body" && parameter.in !== "formData");
174
+ }
175
+ function isReferenceObject(value) {
176
+ return isRecord(value) && typeof value.$ref === "string";
177
+ }
178
+ function rewriteReferences(value) {
179
+ if (Array.isArray(value)) {
180
+ return value.map((entry) => rewriteReferences(entry));
181
+ }
182
+ if (!isRecord(value)) {
183
+ return value;
184
+ }
185
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
186
+ key,
187
+ key === "$ref" && typeof entry === "string" ? rewriteReference(entry) : rewriteReferences(entry)
188
+ ]));
189
+ }
190
+ function rewriteReference(reference) {
191
+ return reference
192
+ .replace("#/definitions/", "#/components/schemas/")
193
+ .replace("#/parameters/", "#/components/parameters/")
194
+ .replace("#/responses/", "#/components/responses/");
195
+ }
196
+ function readStringArray(value) {
197
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
198
+ }
199
+ function isRecord(value) {
200
+ return value !== null && typeof value === "object" && !Array.isArray(value);
201
+ }
@@ -0,0 +1,2 @@
1
+ import type { OpenApiInspectionReport } from "./inspect.js";
2
+ export declare function renderOpenApiInspection(report: OpenApiInspectionReport): string;
@@ -0,0 +1,130 @@
1
+ import { getTheme, renderCatalog, resolveOutputFormat } from "toolcraft-design";
2
+ const LARGE_API_OPERATION_THRESHOLD = 50;
3
+ export function renderOpenApiInspection(report) {
4
+ if (resolveOutputFormat() === "json") {
5
+ return JSON.stringify(report, null, 2);
6
+ }
7
+ return renderCatalog({
8
+ theme: getTheme(),
9
+ title: report.title ?? "OpenAPI",
10
+ ...(report.version === undefined ? {} : { subtitle: `v${report.version}` }),
11
+ metrics: [
12
+ {
13
+ label: "compatible",
14
+ value: `${Math.round((report.supportedCount / Math.max(report.operationCount, 1)) * 100)}%`,
15
+ tone: report.unsupportedCount === 0 ? "success" : "accent"
16
+ },
17
+ { label: pluralize("operation", report.operationCount), value: report.operationCount },
18
+ { label: "supported", value: report.supportedCount, tone: "success" },
19
+ {
20
+ label: "unsupported",
21
+ value: report.unsupportedCount,
22
+ tone: report.unsupportedCount === 0 ? "muted" : "warning"
23
+ }
24
+ ],
25
+ groups: report.operationCount > LARGE_API_OPERATION_THRESHOLD
26
+ ? summarizeOperationGroups(report.operations)
27
+ : groupOperations(report.operations)
28
+ });
29
+ }
30
+ function groupOperations(operations) {
31
+ return collectOperationGroups(operations).map(([title, groupOperations]) => ({
32
+ title,
33
+ items: groupOperations.map((operation) => ({
34
+ label: operation.status === "supported" ? "ready" : "blocked",
35
+ value: `${operation.method} ${operation.path}`,
36
+ detail: operation.status === "supported"
37
+ ? (operation.commandPath ?? operation.operationId)
38
+ : (operation.reason ?? operation.operationId),
39
+ tone: operation.status === "supported" ? "success" : "warning"
40
+ }))
41
+ }));
42
+ }
43
+ function summarizeOperationGroups(operations) {
44
+ const groups = collectOperationGroups(operations);
45
+ const incompatibilities = summarizeIncompatibilities(operations);
46
+ const blockedGroups = groups
47
+ .filter(([, groupOperations]) => groupOperations.some((operation) => operation.status === "unsupported"))
48
+ .sort(([leftTitle, leftOperations], [rightTitle, rightOperations]) => {
49
+ const blockedCountDifference = countUnsupported(rightOperations) - countUnsupported(leftOperations);
50
+ return blockedCountDifference || leftTitle.localeCompare(rightTitle);
51
+ });
52
+ const resourceItems = blockedGroups.length === 0
53
+ ? [
54
+ {
55
+ label: `${operations.length}/${operations.length}`,
56
+ value: "all resources",
57
+ detail: `${groups.length} groups compatible`,
58
+ tone: "success"
59
+ }
60
+ ]
61
+ : blockedGroups.map(([title, groupOperations]) => {
62
+ const supportedCount = groupOperations.filter((operation) => operation.status === "supported").length;
63
+ const unsupportedCount = countUnsupported(groupOperations);
64
+ const firstUnsupported = groupOperations.find((operation) => operation.status === "unsupported");
65
+ return {
66
+ label: `${supportedCount}/${groupOperations.length}`,
67
+ value: title,
68
+ detail: `${unsupportedCount} unsupported · ${firstUnsupported?.reason ?? "inspect JSON output"}`,
69
+ tone: "warning"
70
+ };
71
+ });
72
+ return [
73
+ {
74
+ title: "resources",
75
+ description: blockedGroups.length === 0
76
+ ? "Every generated command group is compatible."
77
+ : `Showing ${blockedGroups.length} of ${groups.length} command groups that need attention. Use --output-format json for every route.`,
78
+ items: resourceItems
79
+ },
80
+ ...(incompatibilities.length === 0
81
+ ? []
82
+ : [
83
+ {
84
+ title: "top incompatibilities",
85
+ description: "First failing compatibility check per blocked route.",
86
+ items: incompatibilities.map(([reason, count]) => ({
87
+ label: `${count} ${pluralize("route", count)}`,
88
+ value: reason,
89
+ tone: "warning"
90
+ }))
91
+ }
92
+ ])
93
+ ];
94
+ }
95
+ function countUnsupported(operations) {
96
+ return operations.filter((operation) => operation.status === "unsupported").length;
97
+ }
98
+ function summarizeIncompatibilities(operations) {
99
+ const counts = new Map();
100
+ for (const operation of operations) {
101
+ if (operation.status !== "unsupported" || operation.reason === undefined) {
102
+ continue;
103
+ }
104
+ const normalizedReason = operation.reason.replace(/^Operation "[^"]+" /, "Operation ");
105
+ counts.set(normalizedReason, (counts.get(normalizedReason) ?? 0) + 1);
106
+ }
107
+ return [...counts.entries()]
108
+ .sort(([leftReason, leftCount], [rightReason, rightCount]) => rightCount - leftCount || leftReason.localeCompare(rightReason))
109
+ .slice(0, 5);
110
+ }
111
+ function collectOperationGroups(operations) {
112
+ const groups = new Map();
113
+ for (const operation of operations) {
114
+ const groupName = getGroupName(operation);
115
+ const group = groups.get(groupName) ?? [];
116
+ group.push(operation);
117
+ groups.set(groupName, group);
118
+ }
119
+ return [...groups.entries()].sort(([left], [right]) => left.localeCompare(right));
120
+ }
121
+ function getGroupName(operation) {
122
+ if (operation.commandPath !== undefined) {
123
+ return operation.commandPath.split(" ")[0] ?? "root";
124
+ }
125
+ return (operation.path.split("/").find((segment) => segment.length > 0 && !segment.startsWith("{")) ??
126
+ "root");
127
+ }
128
+ function pluralize(noun, count) {
129
+ return count === 1 ? noun : `${noun}s`;
130
+ }
@@ -6,6 +6,10 @@ export declare const REQUEST_PARAM_SECTIONS: readonly [{
6
6
  readonly location: "query";
7
7
  readonly key: "query";
8
8
  readonly omittable: false;
9
+ }, {
10
+ readonly location: "header";
11
+ readonly key: "headers";
12
+ readonly omittable: false;
9
13
  }, {
10
14
  readonly location: "body";
11
15
  readonly key: "body";
@@ -1,5 +1,6 @@
1
1
  export const REQUEST_PARAM_SECTIONS = [
2
2
  { location: "path", key: "pathParams", omittable: false },
3
3
  { location: "query", key: "query", omittable: false },
4
+ { location: "header", key: "headers", omittable: false },
4
5
  { location: "body", key: "body", omittable: true }
5
6
  ];
package/dist/runtime.js CHANGED
@@ -53,10 +53,15 @@ function createRuntimeHandler(command) {
53
53
  const resolvedValues = executePreflightBlocks(command.preflightBlocks, params);
54
54
  const requestShape = buildRequestShape(command.requestFields, command.sectionRenders, command.optionalSections, params, resolvedValues);
55
55
  return requestJson({
56
- baseUrl,
56
+ baseUrl: command.baseUrl ?? baseUrl,
57
57
  path: command.path,
58
58
  method: command.method,
59
59
  auth: command.auth,
60
+ responseMode: command.responseMode,
61
+ accept: command.accept,
62
+ bodyMode: command.bodyMode,
63
+ contentType: command.contentType,
64
+ multipartBinaryFields: command.multipartBinaryFields,
60
65
  tokenSource,
61
66
  fetch,
62
67
  dryRun: params.dryRun,
@@ -80,6 +85,7 @@ const RUNTIME_DEFINITION_BUILDERS = {
80
85
  },
81
86
  boolean: (_definition, options) => options === undefined ? S.Boolean() : S.Boolean(options),
82
87
  enum: (definition, options) => options === undefined ? S.Enum(definition.enumValues) : S.Enum(definition.enumValues, options),
88
+ json: (_definition) => S.Json(),
83
89
  number: (_definition, options) => options === undefined ? S.Number() : S.Number(options),
84
90
  string: (_definition, options) => options === undefined ? S.String() : S.String(options)
85
91
  };
@@ -93,8 +93,11 @@ function formatParseErrorMessage(error, sourceText, filePath) {
93
93
  filePath
94
94
  })}`;
95
95
  }
96
+ function hasOwnProperty(value, name) {
97
+ return Object.prototype.hasOwnProperty.call(value, name);
98
+ }
96
99
  function getYamlLinePosition(error) {
97
- if (typeof error !== "object" || error === null || !("linePos" in error)) {
100
+ if (typeof error !== "object" || error === null || !hasOwnProperty(error, "linePos")) {
98
101
  return null;
99
102
  }
100
103
  const linePos = error.linePos;
@@ -105,15 +108,15 @@ function getYamlLinePosition(error) {
105
108
  if (typeof firstPosition !== "object" || firstPosition === null) {
106
109
  return null;
107
110
  }
108
- const line = "line" in firstPosition ? firstPosition.line : undefined;
109
- const column = "col" in firstPosition ? firstPosition.col : undefined;
111
+ const line = hasOwnProperty(firstPosition, "line") ? firstPosition.line : undefined;
112
+ const column = hasOwnProperty(firstPosition, "col") ? firstPosition.col : undefined;
110
113
  if (typeof line !== "number" || typeof column !== "number") {
111
114
  return null;
112
115
  }
113
116
  return { line, column };
114
117
  }
115
118
  function getYamlOffsetPosition(error, sourceText) {
116
- if (typeof error !== "object" || error === null || !("pos" in error)) {
119
+ if (typeof error !== "object" || error === null || !hasOwnProperty(error, "pos")) {
117
120
  return null;
118
121
  }
119
122
  const pos = error.pos;
@@ -27,7 +27,7 @@ export function createSecretStore(input) {
27
27
  }
28
28
  function resolveBackend(input) {
29
29
  const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
30
- const configuredBackend = input.backend ?? input.env?.[envVar] ?? process.env[envVar];
30
+ const configuredBackend = input.backend ?? getOwnEnvValue(input.env, envVar) ?? getOwnEnvValue(process.env, envVar);
31
31
  if (configuredBackend === "keychain") {
32
32
  return "keychain";
33
33
  }
@@ -36,3 +36,8 @@ function resolveBackend(input) {
36
36
  }
37
37
  throw new Error(`Unsupported auth store backend: ${configuredBackend}`);
38
38
  }
39
+ function getOwnEnvValue(env, key) {
40
+ return env !== undefined && Object.prototype.hasOwnProperty.call(env, key)
41
+ ? env[key]
42
+ : undefined;
43
+ }
@@ -42,6 +42,6 @@ export declare class EncryptedFileStore implements SecretStore {
42
42
  get(): Promise<string | null>;
43
43
  set(value: string): Promise<void>;
44
44
  delete(): Promise<void>;
45
- private assertRegularCredentialPath;
45
+ private assertCredentialPathHasNoSymbolicLinks;
46
46
  private getEncryptionKey;
47
47
  }
@@ -1,7 +1,8 @@
1
- import { createCipheriv, createDecipheriv, randomBytes, scrypt } from "node:crypto";
1
+ import { createCipheriv, createDecipheriv, randomBytes, randomUUID, scrypt } from "node:crypto";
2
2
  import { promises as fs } from "node:fs";
3
3
  import { homedir, hostname, userInfo } from "node:os";
4
4
  import path from "node:path";
5
+ import { hasOwnErrorCode } from "./error-codes.js";
5
6
  const derivedKeyCache = new Map();
6
7
  const ENCRYPTION_ALGORITHM = "aes-256-gcm";
7
8
  const ENCRYPTION_VERSION = 1;
@@ -9,7 +10,6 @@ const ENCRYPTION_KEY_BYTES = 32;
9
10
  const ENCRYPTION_IV_BYTES = 12;
10
11
  const ENCRYPTION_AUTH_TAG_BYTES = 16;
11
12
  const ENCRYPTION_FILE_MODE = 0o600;
12
- let temporaryFileSequence = 0;
13
13
  export class EncryptedFileStore {
14
14
  fs;
15
15
  filePath;
@@ -35,7 +35,7 @@ export class EncryptedFileStore {
35
35
  this.getRandomBytes = input.getRandomBytes ?? randomBytes;
36
36
  }
37
37
  async get() {
38
- await this.assertRegularCredentialPath();
38
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
39
39
  let rawDocument;
40
40
  try {
41
41
  rawDocument = await this.fs.readFile(this.filePath, "utf8");
@@ -69,7 +69,7 @@ export class EncryptedFileStore {
69
69
  }
70
70
  }
71
71
  async set(value) {
72
- await this.assertRegularCredentialPath();
72
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
73
73
  const key = await this.getEncryptionKey();
74
74
  const iv = this.getRandomBytes(ENCRYPTION_IV_BYTES);
75
75
  const cipher = createCipheriv(ENCRYPTION_ALGORITHM, key, iv);
@@ -85,26 +85,29 @@ export class EncryptedFileStore {
85
85
  ciphertext: ciphertext.toString("base64")
86
86
  };
87
87
  await this.fs.mkdir(path.dirname(this.filePath), { recursive: true });
88
- await this.assertRegularCredentialPath();
89
- const temporaryPath = `${this.filePath}.${process.pid}.${temporaryFileSequence++}.tmp`;
88
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
89
+ const temporaryPath = `${this.filePath}.${process.pid}.${randomUUID()}.tmp`;
90
+ let temporaryCreated = false;
90
91
  try {
92
+ await this.assertCredentialPathHasNoSymbolicLinks(temporaryPath);
91
93
  await this.fs.writeFile(temporaryPath, JSON.stringify(document), {
92
94
  encoding: "utf8",
93
95
  flag: "wx",
94
96
  mode: ENCRYPTION_FILE_MODE
95
97
  });
98
+ temporaryCreated = true;
96
99
  await this.fs.chmod(temporaryPath, ENCRYPTION_FILE_MODE);
97
100
  await this.fs.rename(temporaryPath, this.filePath);
98
101
  }
99
102
  catch (error) {
100
- if (!isAlreadyExistsError(error)) {
103
+ if (temporaryCreated || !isAlreadyExistsError(error)) {
101
104
  await removeIfPresent(this.fs, temporaryPath).catch(() => undefined);
102
105
  }
103
106
  throw error;
104
107
  }
105
108
  }
106
109
  async delete() {
107
- await this.assertRegularCredentialPath();
110
+ await this.assertCredentialPathHasNoSymbolicLinks(this.filePath);
108
111
  try {
109
112
  await this.fs.unlink(this.filePath);
110
113
  }
@@ -114,8 +117,8 @@ export class EncryptedFileStore {
114
117
  }
115
118
  }
116
119
  }
117
- async assertRegularCredentialPath() {
118
- const resolvedPath = path.resolve(this.filePath);
120
+ async assertCredentialPathHasNoSymbolicLinks(targetPath) {
121
+ const resolvedPath = path.resolve(targetPath);
119
122
  const protectedPaths = getProtectedCredentialPaths(resolvedPath, this.symbolicLinkCheckStartPath);
120
123
  for (const currentPath of protectedPaths) {
121
124
  try {
@@ -179,12 +182,6 @@ async function removeIfPresent(fileSystem, filePath) {
179
182
  }
180
183
  }
181
184
  }
182
- function isAlreadyExistsError(error) {
183
- return (typeof error === "object" &&
184
- error !== null &&
185
- "code" in error &&
186
- error.code === "EEXIST");
187
- }
188
185
  function defaultMachineIdentity() {
189
186
  return {
190
187
  hostname: hostname(),
@@ -222,19 +219,23 @@ function parseEncryptedDocument(raw) {
222
219
  if (!isRecord(parsed)) {
223
220
  return null;
224
221
  }
225
- if (parsed.version !== ENCRYPTION_VERSION) {
222
+ const version = getOwnEntry(parsed, "version");
223
+ const iv = getOwnEntry(parsed, "iv");
224
+ const authTag = getOwnEntry(parsed, "authTag");
225
+ const ciphertext = getOwnEntry(parsed, "ciphertext");
226
+ if (version !== ENCRYPTION_VERSION) {
226
227
  return null;
227
228
  }
228
- if (typeof parsed.iv !== "string" ||
229
- typeof parsed.authTag !== "string" ||
230
- typeof parsed.ciphertext !== "string") {
229
+ if (typeof iv !== "string" ||
230
+ typeof authTag !== "string" ||
231
+ typeof ciphertext !== "string") {
231
232
  return null;
232
233
  }
233
234
  return {
234
- version: parsed.version,
235
- iv: parsed.iv,
236
- authTag: parsed.authTag,
237
- ciphertext: parsed.ciphertext
235
+ version,
236
+ iv,
237
+ authTag,
238
+ ciphertext
238
239
  };
239
240
  }
240
241
  catch {
@@ -244,9 +245,12 @@ function parseEncryptedDocument(raw) {
244
245
  function isRecord(value) {
245
246
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
246
247
  }
248
+ function getOwnEntry(record, key) {
249
+ return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
250
+ }
247
251
  function isNotFoundError(error) {
248
- return Boolean(error &&
249
- typeof error === "object" &&
250
- "code" in error &&
251
- error.code === "ENOENT");
252
+ return hasOwnErrorCode(error, "ENOENT");
253
+ }
254
+ function isAlreadyExistsError(error) {
255
+ return hasOwnErrorCode(error, "EEXIST");
252
256
  }
@@ -0,0 +1 @@
1
+ export declare function hasOwnErrorCode(error: unknown, code: string): boolean;