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
package/dist/http.d.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import type { TokenSource } from "./auth/types.js";
2
2
  type QueryScalar = string | number | boolean | null | undefined;
3
- export type QueryValue = QueryScalar | QueryScalar[];
3
+ type QueryObject = {
4
+ readonly [key: string]: QueryValue;
5
+ };
6
+ type HeaderScalar = string | number | boolean | undefined;
7
+ export type QueryValue = QueryScalar | QueryValue[] | QueryObject;
4
8
  export interface HttpRequestOptions {
5
9
  baseUrl: string;
6
10
  path: string;
@@ -10,7 +14,13 @@ export interface HttpRequestOptions {
10
14
  fetch?: typeof globalThis.fetch;
11
15
  pathParams?: Record<string, string | number | boolean>;
12
16
  query?: Record<string, QueryValue>;
17
+ headers?: Record<string, HeaderScalar>;
13
18
  body?: unknown;
19
+ bodyMode?: "json" | "form" | "raw" | "base64" | "multipart";
20
+ contentType?: string;
21
+ multipartBinaryFields?: readonly string[];
22
+ responseMode?: "json" | "text" | "binary";
23
+ accept?: string;
14
24
  dryRun?: boolean;
15
25
  verbose?: boolean;
16
26
  signal?: AbortSignal;
@@ -29,6 +39,12 @@ export interface HttpErrorResponse {
29
39
  headers: Record<string, string>;
30
40
  body: unknown;
31
41
  }
42
+ export interface BinaryHttpResponse {
43
+ contentType: string;
44
+ encoding: "base64";
45
+ byteLength: number;
46
+ data: string;
47
+ }
32
48
  export declare class HttpError extends Error {
33
49
  readonly status: number;
34
50
  readonly statusText: string;
package/dist/http.js CHANGED
@@ -1,4 +1,4 @@
1
- import { text as designText } from "@poe-code/design-system";
1
+ import { text as designText } from "toolcraft-design";
2
2
  import { UserError } from "toolcraft";
3
3
  import { classifyNetworkError } from "./network-error.js";
4
4
  import { redactHeaders, redactHeaderValue, redactSensitiveQueryValues } from "./redaction.js";
@@ -25,9 +25,19 @@ export async function requestJson(options) {
25
25
  const token = options.auth === "none" ? undefined : await options.tokenSource.getToken();
26
26
  const method = options.method.toUpperCase();
27
27
  const hasBody = options.body !== undefined;
28
- const serializedBody = hasBody ? JSON.stringify(options.body) : undefined;
28
+ const serializedBody = hasBody
29
+ ? options.bodyMode === "form"
30
+ ? serializeFormBody(options.body)
31
+ : options.bodyMode === "raw"
32
+ ? serializeRawBody(options.body)
33
+ : options.bodyMode === "base64"
34
+ ? decodeBase64Body(options.body)
35
+ : options.bodyMode === "multipart"
36
+ ? serializeMultipartBody(options.body, options.multipartBinaryFields)
37
+ : JSON.stringify(options.body)
38
+ : undefined;
29
39
  const url = buildRequestUrl(options);
30
- const headers = createHeaders(token, hasBody);
40
+ const headers = createHeaders(token, hasBody, options.headers, options.accept, options.bodyMode, options.contentType);
31
41
  const writeStdout = options.writeStdout ?? process.stdout.write.bind(process.stdout);
32
42
  const writeStderr = options.writeStderr ?? process.stderr.write.bind(process.stderr);
33
43
  const requestLine = `${method} ${redactSensitiveQueryValues(url)}`;
@@ -50,10 +60,29 @@ export async function requestJson(options) {
50
60
  catch (error) {
51
61
  throw classifyNetworkError(error, url) ?? error;
52
62
  }
53
- const text = await response.text();
54
63
  const contentType = response.headers.get("content-type");
55
64
  const request = createHttpErrorRequest(method, url, headers, options.body);
56
65
  const responseHeaders = redactHeaders(serializeHeaders(response.headers));
66
+ if (response.ok && options.responseMode === "binary") {
67
+ const bytes = new Uint8Array(await response.arrayBuffer());
68
+ if (bytes.byteLength === 0) {
69
+ if (options.verbose) {
70
+ writeStderr(formatTranscriptLines(formatVerboseResponseTranscript(response, responseHeaders)));
71
+ }
72
+ return undefined;
73
+ }
74
+ const body = {
75
+ contentType: contentType ?? options.accept ?? "application/octet-stream",
76
+ encoding: "base64",
77
+ byteLength: bytes.byteLength,
78
+ data: Buffer.from(bytes).toString("base64")
79
+ };
80
+ if (options.verbose) {
81
+ writeStderr(formatTranscriptLines(formatVerboseResponseTranscript(response, responseHeaders, body)));
82
+ }
83
+ return body;
84
+ }
85
+ const text = await response.text();
57
86
  if (response.ok) {
58
87
  if (text.length === 0) {
59
88
  if (options.verbose) {
@@ -61,6 +90,12 @@ export async function requestJson(options) {
61
90
  }
62
91
  return undefined;
63
92
  }
93
+ if (options.responseMode === "text") {
94
+ if (options.verbose) {
95
+ writeStderr(formatTranscriptLines(formatVerboseResponseTranscript(response, responseHeaders, text)));
96
+ }
97
+ return text;
98
+ }
64
99
  if (!isJsonContentType(contentType)) {
65
100
  if (options.verbose) {
66
101
  writeStderr(formatTranscriptLines(formatVerboseResponseTranscript(response, responseHeaders, text)));
@@ -146,18 +181,89 @@ function substitutePathParams(path, pathParams) {
146
181
  return resolvedPath;
147
182
  }
148
183
  function appendQueryValue(searchParams, key, value) {
184
+ if (isQueryObject(value)) {
185
+ for (const [childKey, childValue] of Object.entries(value)) {
186
+ appendQueryValue(searchParams, `${key}[${childKey}]`, childValue);
187
+ }
188
+ return;
189
+ }
149
190
  const values = Array.isArray(value) ? value : [value];
150
- for (const entry of values) {
191
+ for (const [index, entry] of values.entries()) {
151
192
  if (entry === undefined) {
152
193
  continue;
153
194
  }
195
+ if (isQueryObject(entry)) {
196
+ for (const [childKey, childValue] of Object.entries(entry)) {
197
+ appendQueryValue(searchParams, `${key}[${Array.isArray(value) ? `${index}][` : ""}${childKey}]`, childValue);
198
+ }
199
+ continue;
200
+ }
154
201
  searchParams.append(key, entry === null ? "" : String(entry));
155
202
  }
156
203
  }
157
- function createHeaders(token, hasBody) {
204
+ function serializeFormBody(body) {
205
+ if (body === null || typeof body !== "object" || Array.isArray(body)) {
206
+ throw new UserError("URL-encoded form bodies must be objects.");
207
+ }
208
+ const searchParams = new URLSearchParams();
209
+ for (const [key, value] of Object.entries(body)) {
210
+ appendQueryValue(searchParams, key, value);
211
+ }
212
+ return searchParams.toString();
213
+ }
214
+ function serializeRawBody(body) {
215
+ if (typeof body !== "string") {
216
+ throw new UserError("Raw request bodies must be strings.");
217
+ }
218
+ return body;
219
+ }
220
+ function decodeBase64Body(body) {
221
+ if (typeof body !== "string") {
222
+ throw new UserError("Base64 request bodies must be strings.");
223
+ }
224
+ return Uint8Array.from(Buffer.from(body, "base64")).buffer;
225
+ }
226
+ function serializeMultipartBody(body, binaryFields = []) {
227
+ if (body === null || typeof body !== "object" || Array.isArray(body)) {
228
+ throw new UserError("Multipart request bodies must be objects.");
229
+ }
230
+ const binary = new Set(binaryFields);
231
+ const form = new FormData();
232
+ for (const [key, value] of Object.entries(body)) {
233
+ if (value === undefined)
234
+ continue;
235
+ if (binary.has(key)) {
236
+ form.append(key, new Blob([decodeBase64Body(value)]), key);
237
+ }
238
+ else if (Array.isArray(value)) {
239
+ for (const item of value)
240
+ form.append(key, String(item));
241
+ }
242
+ else {
243
+ form.append(key, String(value));
244
+ }
245
+ }
246
+ return form;
247
+ }
248
+ function isQueryObject(value) {
249
+ return value !== null && typeof value === "object" && !Array.isArray(value);
250
+ }
251
+ function createHeaders(token, hasBody, customHeaders, accept = "application/json", bodyMode = "json", contentType) {
252
+ const headers = Object.fromEntries(Object.entries(customHeaders ?? {})
253
+ .filter(([name, value]) => value !== undefined &&
254
+ !["accept", "content-type"].includes(name.toLowerCase()) &&
255
+ !(token !== undefined && name.toLowerCase() === "authorization"))
256
+ .map(([name, value]) => [name, String(value)]));
158
257
  return {
258
+ ...headers,
259
+ Accept: accept,
159
260
  ...(token === undefined ? {} : { Authorization: `Bearer ${token}` }),
160
- ...(hasBody ? { "Content-Type": "application/json" } : {})
261
+ ...(hasBody && bodyMode !== "multipart"
262
+ ? {
263
+ "Content-Type": contentType ??
264
+ (bodyMode === "form" ? "application/x-www-form-urlencoded" : "application/json")
265
+ }
266
+ : {})
161
267
  };
162
268
  }
163
269
  function createHttpErrorRequest(method, url, headers, body) {
package/dist/index.d.ts CHANGED
@@ -2,6 +2,11 @@ export { defineApiCommand } from "./api-command.js";
2
2
  export { defineClient } from "./define-client.js";
3
3
  export { generate } from "./generate.js";
4
4
  export type { GenerateOptions, GeneratedFile, OpenApiDocument } from "./generate.js";
5
+ export { inspectOpenApiDocument } from "./inspect.js";
6
+ export type { OpenApiInspectionOperation, OpenApiInspectionReport } from "./inspect.js";
7
+ export { inspectOpenApiSource } from "./inspect-source.js";
8
+ export type { InspectOpenApiSourceOptions, OpenApiInspectionSource } from "./inspect-source.js";
9
+ export { renderOpenApiInspection } from "./render-inspection.js";
5
10
  export { commandsFromSpec, defineClientFromSpec } from "./runtime.js";
6
11
  export type { CommandsFromSpecOptions, DefineClientFromSpecOptions, OpenApiDocumentSource } from "./runtime.js";
7
12
  export type { DefineClientOptions, DefinedClient, OpenApiClientServices } from "./define-client.js";
@@ -9,4 +14,4 @@ export type { AuthProvider, CommandContributor, TokenSource } from "./auth/types
9
14
  export { bearerTokenAuth } from "./auth/bearer-token-auth.js";
10
15
  export type { BearerTokenAuthOptions } from "./auth/bearer-token-auth.js";
11
16
  export { HttpError, requestJson } from "./http.js";
12
- export type { HttpErrorRequest, HttpErrorResponse, HttpRequestOptions, QueryValue } from "./http.js";
17
+ export type { BinaryHttpResponse, HttpErrorRequest, HttpErrorResponse, HttpRequestOptions, QueryValue } from "./http.js";
package/dist/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  export { defineApiCommand } from "./api-command.js";
2
2
  export { defineClient } from "./define-client.js";
3
3
  export { generate } from "./generate.js";
4
+ export { inspectOpenApiDocument } from "./inspect.js";
5
+ export { inspectOpenApiSource } from "./inspect-source.js";
6
+ export { renderOpenApiInspection } from "./render-inspection.js";
4
7
  export { commandsFromSpec, defineClientFromSpec } from "./runtime.js";
5
8
  export { bearerTokenAuth } from "./auth/bearer-token-auth.js";
6
9
  export { HttpError, requestJson } from "./http.js";
@@ -0,0 +1,10 @@
1
+ import { type OpenApiInspectionReport } from "./inspect.js";
2
+ import type { OpenApiDocument } from "./generate.js";
3
+ import { type OpenApiSourceFileSystem } from "./spec-source.js";
4
+ export type OpenApiInspectionSource = OpenApiDocument | string | URL;
5
+ export interface InspectOpenApiSourceOptions {
6
+ cwd?: string;
7
+ fetch?: typeof globalThis.fetch;
8
+ fs?: OpenApiSourceFileSystem;
9
+ }
10
+ export declare function inspectOpenApiSource(source: OpenApiInspectionSource, options?: InspectOpenApiSourceOptions): Promise<OpenApiInspectionReport>;
@@ -0,0 +1,14 @@
1
+ import fs from "node:fs/promises";
2
+ import { inspectOpenApiDocument } from "./inspect.js";
3
+ import { parseOpenApiDocument, readOpenApiSourceText } from "./spec-source.js";
4
+ export async function inspectOpenApiSource(source, options = {}) {
5
+ if (typeof source !== "string" && !(source instanceof URL)) {
6
+ return inspectOpenApiDocument(source);
7
+ }
8
+ const sourceText = await readOpenApiSourceText(source, {
9
+ cwd: options.cwd ?? process.cwd(),
10
+ fetch: options.fetch ?? globalThis.fetch,
11
+ fs: options.fs ?? fs
12
+ });
13
+ return inspectOpenApiDocument(parseOpenApiDocument(sourceText, source));
14
+ }
@@ -0,0 +1,22 @@
1
+ import { type OpenApiDocument } from "./generate.js";
2
+ declare const HTTP_METHOD_ORDER: readonly ["get", "post", "put", "patch", "delete", "head", "options", "trace"];
3
+ type InspectedHttpMethod = (typeof HTTP_METHOD_ORDER)[number];
4
+ export interface OpenApiInspectionOperation {
5
+ method: Uppercase<InspectedHttpMethod>;
6
+ path: string;
7
+ operationId: string;
8
+ summary?: string;
9
+ status: "supported" | "unsupported";
10
+ commandPath?: string;
11
+ reason?: string;
12
+ }
13
+ export interface OpenApiInspectionReport {
14
+ title?: string;
15
+ version?: string;
16
+ operationCount: number;
17
+ supportedCount: number;
18
+ unsupportedCount: number;
19
+ operations: OpenApiInspectionOperation[];
20
+ }
21
+ export declare function inspectOpenApiDocument(document: OpenApiDocument): OpenApiInspectionReport;
22
+ export {};
@@ -0,0 +1,171 @@
1
+ import { UserError } from "toolcraft";
2
+ import { collectGeneratedCommand } from "./generate.js";
3
+ import { normalizeOpenApiDocument } from "./normalize-swagger.js";
4
+ import { deriveDisambiguatedVerb, derivePathDisambiguatedVerb } from "./naming.js";
5
+ const HTTP_METHOD_ORDER = [
6
+ "get",
7
+ "post",
8
+ "put",
9
+ "patch",
10
+ "delete",
11
+ "head",
12
+ "options",
13
+ "trace"
14
+ ];
15
+ export function inspectOpenApiDocument(document) {
16
+ const normalizedDocument = normalizeOpenApiDocument(document);
17
+ if (normalizedDocument.paths === undefined) {
18
+ throw new UserError('OpenAPI document must define a top-level "paths" object.');
19
+ }
20
+ const operations = collectInspectionOperations(normalizedDocument);
21
+ markCommandPathCollisions(operations);
22
+ const supportedCount = operations.filter((operation) => operation.status === "supported").length;
23
+ return {
24
+ ...(normalizedDocument.info?.title === undefined ? {} : { title: normalizedDocument.info.title }),
25
+ ...(normalizedDocument.info?.version === undefined ? {} : { version: normalizedDocument.info.version }),
26
+ operationCount: operations.length,
27
+ supportedCount,
28
+ unsupportedCount: operations.length - supportedCount,
29
+ operations
30
+ };
31
+ }
32
+ function collectInspectionOperations(document) {
33
+ return Object.entries(document.paths ?? {})
34
+ .sort(([left], [right]) => left.localeCompare(right))
35
+ .flatMap(([path, pathItem]) => {
36
+ if (pathItem === undefined) {
37
+ return [];
38
+ }
39
+ return HTTP_METHOD_ORDER.flatMap((method) => {
40
+ const operation = pathItem[method];
41
+ if (operation === undefined) {
42
+ return [];
43
+ }
44
+ return [inspectOperation(document, path, pathItem, method, operation)];
45
+ });
46
+ });
47
+ }
48
+ function inspectOperation(document, path, pathItem, method, operation) {
49
+ const metadata = readOperationMetadata(path, method, operation);
50
+ try {
51
+ const command = method === "trace"
52
+ ? undefined
53
+ : collectGeneratedCommand(document, path, method);
54
+ if (command === undefined) {
55
+ throw new UserError(`Operation ${JSON.stringify(metadata.operationId)} uses unsupported HTTP method ${JSON.stringify(method.toUpperCase())}. Supported in v1: GET, POST, PUT, PATCH, DELETE.`);
56
+ }
57
+ return createSupportedOperation(metadata, command);
58
+ }
59
+ catch (error) {
60
+ return {
61
+ ...metadata,
62
+ status: "unsupported",
63
+ reason: error instanceof Error ? error.message : String(error)
64
+ };
65
+ }
66
+ }
67
+ function createSupportedOperation(metadata, command) {
68
+ return {
69
+ ...metadata,
70
+ status: "supported",
71
+ commandPath: `${command.noun} ${command.verb}`
72
+ };
73
+ }
74
+ function readOperationMetadata(path, method, operation) {
75
+ const operationObject = isObject(operation) ? operation : {};
76
+ const operationId = typeof operationObject.operationId === "string"
77
+ ? operationObject.operationId
78
+ : `${method.toUpperCase()} ${path}`;
79
+ const summary = typeof operationObject.summary === "string"
80
+ ? operationObject.summary
81
+ : typeof operationObject.description === "string"
82
+ ? operationObject.description
83
+ : undefined;
84
+ return {
85
+ method: method.toUpperCase(),
86
+ path,
87
+ operationId,
88
+ ...(summary === undefined ? {} : { summary })
89
+ };
90
+ }
91
+ function markCommandPathCollisions(operations) {
92
+ const byCommandPath = new Map();
93
+ for (const operation of operations) {
94
+ if (operation.status !== "supported" || operation.commandPath === undefined) {
95
+ continue;
96
+ }
97
+ const collisions = byCommandPath.get(operation.commandPath) ?? [];
98
+ collisions.push(operation);
99
+ byCommandPath.set(operation.commandPath, collisions);
100
+ }
101
+ for (const collisions of byCommandPath.values()) {
102
+ if (collisions.length < 2) {
103
+ continue;
104
+ }
105
+ const existingPaths = new Set(operations
106
+ .filter((operation) => !collisions.includes(operation) && operation.commandPath !== undefined)
107
+ .map((operation) => operation.commandPath));
108
+ const operationIdCandidates = collisions.map((operation) => {
109
+ const noun = operation.commandPath?.split(" ")[0] ?? "";
110
+ return { operation, commandPath: `${noun} ${deriveDisambiguatedVerb(operation.operationId, noun)}` };
111
+ });
112
+ if (applyInspectionCommandPaths(operationIdCandidates, existingPaths)) {
113
+ continue;
114
+ }
115
+ const pathCandidates = collisions.map((operation) => {
116
+ const [noun = "", verb = ""] = operation.commandPath?.split(" ") ?? [];
117
+ const pathVerb = derivePathDisambiguatedVerb(operation.method.toLowerCase(), operation.path, noun, verb);
118
+ return { operation, commandPath: `${noun} ${pathVerb}` };
119
+ });
120
+ if (applyInspectionCommandPaths(pathCandidates, existingPaths)) {
121
+ continue;
122
+ }
123
+ if (applyInspectionCommandPaths(collisions.map((operation) => {
124
+ const [noun = "", verb = ""] = operation.commandPath?.split(" ") ?? [];
125
+ const pathVerb = derivePathDisambiguatedVerb(operation.method.toLowerCase(), operation.path, noun, verb, true);
126
+ return { operation, commandPath: `${noun} ${pathVerb}` };
127
+ }), existingPaths)) {
128
+ continue;
129
+ }
130
+ applyInspectionCommandPaths(collisions.map((operation) => {
131
+ const [noun = "", verb = ""] = operation.commandPath?.split(" ") ?? [];
132
+ const pathVerb = derivePathDisambiguatedVerb(operation.method.toLowerCase(), operation.path, noun, verb, true, true);
133
+ return { operation, commandPath: `${noun} ${pathVerb}` };
134
+ }), existingPaths);
135
+ }
136
+ const remainingByCommandPath = new Map();
137
+ for (const operation of operations) {
138
+ if (operation.status !== "supported" || operation.commandPath === undefined) {
139
+ continue;
140
+ }
141
+ remainingByCommandPath.set(operation.commandPath, [
142
+ ...(remainingByCommandPath.get(operation.commandPath) ?? []),
143
+ operation
144
+ ]);
145
+ }
146
+ for (const [commandPath, collisions] of remainingByCommandPath) {
147
+ if (collisions.length < 2) {
148
+ continue;
149
+ }
150
+ const reason = `Generated command path ${JSON.stringify(commandPath)} is defined more than once (${collisions.map((operation) => JSON.stringify(operation.operationId)).join(" and ")}).`;
151
+ for (const operation of collisions) {
152
+ operation.status = "unsupported";
153
+ operation.reason = reason;
154
+ }
155
+ }
156
+ }
157
+ function applyInspectionCommandPaths(candidates, existingPaths) {
158
+ const candidatePaths = candidates.map(({ commandPath }) => commandPath);
159
+ if (candidates.some(({ commandPath }) => commandPath.endsWith(" ")) ||
160
+ new Set(candidatePaths).size !== candidates.length ||
161
+ candidatePaths.some((commandPath) => existingPaths.has(commandPath))) {
162
+ return false;
163
+ }
164
+ for (const { operation, commandPath } of candidates) {
165
+ operation.commandPath = commandPath;
166
+ }
167
+ return true;
168
+ }
169
+ function isObject(value) {
170
+ return value !== null && typeof value === "object" && !Array.isArray(value);
171
+ }
@@ -16,6 +16,10 @@ const VALUE_REFERENCE_OPERATIONS = {
16
16
  }
17
17
  };
18
18
  const VALUE_EXPRESSION_OPERATIONS = {
19
+ emptyObject: {
20
+ render: (_value) => "{}",
21
+ evaluate: (_value) => ({})
22
+ },
19
23
  reference: {
20
24
  render: (value) => renderValueReference(value.reference),
21
25
  evaluate: (value, context) => evaluateValueReference(value.reference, context)
@@ -270,13 +274,13 @@ function evaluateValueExpression(value, context) {
270
274
  return VALUE_EXPRESSION_OPERATIONS[value.kind].evaluate(value, context);
271
275
  }
272
276
  function renderSerializedQueryArray(reference, serialization) {
273
- if (serialization === "repeat") {
277
+ if (serialization === "repeat" || serialization === "brackets") {
274
278
  return reference;
275
279
  }
276
280
  return `${reference} === undefined || ${reference} === null ? ${reference} : ${reference}.join(${JSON.stringify(QUERY_ARRAY_SERIALIZATION_SEPARATORS[serialization])})`;
277
281
  }
278
282
  function serializeQueryArrayValue(value, serialization) {
279
- if (serialization === "repeat" || value === undefined || value === null) {
283
+ if (serialization === "repeat" || serialization === "brackets" || value === undefined || value === null) {
280
284
  return value;
281
285
  }
282
286
  return Array.isArray(value) ? value.join(QUERY_ARRAY_SERIALIZATION_SEPARATORS[serialization]) : value;
@@ -1,8 +1,9 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { UserError } from "toolcraft";
4
+ import { hasOwnErrorCode } from "../error-codes.js";
4
5
  import { parseOpenApiDocument, readOpenApiSourceText } from "../spec-source.js";
5
- const HTTP_METHOD_NAMES = ["get", "post", "put", "patch", "delete"];
6
+ const HTTP_METHOD_NAMES = ["get", "post", "put", "patch", "delete", "head", "options"];
6
7
  export async function mockFetch(options) {
7
8
  const document = await resolveSpec(options);
8
9
  const operations = compileOperations(document);
@@ -15,7 +16,7 @@ export async function mockFetch(options) {
15
16
  const method = (init?.method ?? getRequestMethod(input) ?? "GET").toUpperCase();
16
17
  const headers = collectHeaders(input, init);
17
18
  const bodyText = await readRequestBody(input, init);
18
- const parsedBody = parseJsonOrUndefined(bodyText);
19
+ const parsedBody = parseRequestBody(bodyText, headers["content-type"]);
19
20
  const matchingPath = operations.filter((op) => op.pathRegex.test(requestUrl.pathname));
20
21
  if (matchingPath.length === 0) {
21
22
  throw new MockFetchError(`mockFetch: no operation in the spec matches ${method} ${requestUrl.pathname}.`);
@@ -223,7 +224,7 @@ function extractExample(response, document) {
223
224
  }
224
225
  if (media.examples !== undefined) {
225
226
  for (const value of Object.values(media.examples)) {
226
- if (value !== undefined && "value" in value) {
227
+ if (value !== undefined && Object.prototype.hasOwnProperty.call(value, "value")) {
227
228
  return value.value;
228
229
  }
229
230
  }
@@ -244,7 +245,7 @@ function pickJsonMediaType(content) {
244
245
  return undefined;
245
246
  }
246
247
  for (const [type, media] of Object.entries(content)) {
247
- if (media !== undefined && /application\/json|\+json/i.test(type)) {
248
+ if (media !== undefined && (type === "*/*" || /application\/json|\+json/i.test(type))) {
248
249
  return media;
249
250
  }
250
251
  }
@@ -253,7 +254,7 @@ function pickJsonMediaType(content) {
253
254
  function isReference(value) {
254
255
  return (typeof value === "object" &&
255
256
  value !== null &&
256
- "$ref" in value &&
257
+ Object.prototype.hasOwnProperty.call(value, "$ref") &&
257
258
  typeof value.$ref === "string");
258
259
  }
259
260
  function resolveReference(reference, document) {
@@ -270,6 +271,9 @@ function resolveReference(reference, document) {
270
271
  if (current === null || typeof current !== "object") {
271
272
  throw new UserError(`mockFetch: failed to resolve $ref ${JSON.stringify(ref)}.`);
272
273
  }
274
+ if (!Object.prototype.hasOwnProperty.call(current, segment)) {
275
+ throw new UserError(`mockFetch: failed to resolve $ref ${JSON.stringify(ref)}.`);
276
+ }
273
277
  current = current[segment];
274
278
  }
275
279
  if (current === undefined) {
@@ -394,6 +398,9 @@ function collectHeaders(input, init) {
394
398
  const requestHeaders = typeof input !== "string" && !(input instanceof URL) ? input.headers : undefined;
395
399
  appendHeaders(headers, requestHeaders);
396
400
  appendHeaders(headers, initHeaders);
401
+ if (init?.body instanceof FormData && headers["content-type"] === undefined) {
402
+ appendHeaders(headers, new Request("https://mock.invalid", { method: "POST", body: init.body }).headers);
403
+ }
397
404
  return headers;
398
405
  }
399
406
  function appendHeaders(target, source) {
@@ -433,10 +440,18 @@ async function readRequestBody(input, init) {
433
440
  }
434
441
  return undefined;
435
442
  }
436
- function parseJsonOrUndefined(text) {
443
+ function parseRequestBody(text, contentType) {
437
444
  if (text === undefined || text.length === 0) {
438
445
  return undefined;
439
446
  }
447
+ if (contentType?.toLowerCase().includes("application/x-www-form-urlencoded") === true) {
448
+ const body = {};
449
+ for (const [key, value] of new URLSearchParams(text)) {
450
+ const existing = body[key];
451
+ body[key] = existing === undefined ? value : Array.isArray(existing) ? [...existing, value] : [existing, value];
452
+ }
453
+ return body;
454
+ }
440
455
  try {
441
456
  return JSON.parse(text);
442
457
  }
@@ -447,7 +462,12 @@ function parseJsonOrUndefined(text) {
447
462
  function buildResponse(fixture, defaultStatus) {
448
463
  const status = fixture.status ?? defaultStatus;
449
464
  const headers = new Headers(fixture.headers ?? { "content-type": "application/json" });
450
- const body = fixture.body === undefined ? null : fixture.body === null ? null : JSON.stringify(fixture.body);
465
+ const contentType = headers.get("content-type")?.toLowerCase();
466
+ const body = fixture.body === undefined || fixture.body === null
467
+ ? null
468
+ : contentType?.includes("json") === true
469
+ ? JSON.stringify(fixture.body)
470
+ : String(fixture.body);
451
471
  return new Response(body, { status, headers });
452
472
  }
453
473
  function jsonResponse(status, body) {
@@ -507,9 +527,5 @@ function formatList(values) {
507
527
  return values.map((value) => JSON.stringify(value)).join(", ");
508
528
  }
509
529
  function isNotFoundError(error) {
510
- if (typeof error !== "object" || error === null) {
511
- return false;
512
- }
513
- const code = error.code;
514
- return code === "ENOENT" || code === "ENOTDIR";
530
+ return hasOwnErrorCode(error, "ENOENT") || hasOwnErrorCode(error, "ENOTDIR");
515
531
  }
@@ -0,0 +1,4 @@
1
+ import type { OpenApiDocument } from "../generate.js";
2
+ export declare const FORGEYARD_BASE_URL = "https://api.forgeyard.invalid";
3
+ export declare const FORGEYARD_RESOURCES: readonly ["artifacts", "audits", "automations", "branches", "builds", "checks", "changes", "comments", "commits", "deployments", "discussions", "environments", "events", "files", "hooks", "identities", "integrations", "invitations", "jobs", "keys", "labels", "licenses", "members", "milestones", "notifications", "organizations", "packages", "pages", "permissions", "pipelines", "policies", "projects", "releases", "repositories", "reviews", "runners", "secrets", "sessions", "settings", "snapshots", "statuses", "tags", "teams", "templates", "tokens", "topics", "variables", "webhooks", "workflows", "workspaces", "approvals", "archives", "attestations", "billing-accounts", "codespaces", "dependencies", "exports", "imports", "mirrors", "rulesets", "security-alerts", "service-accounts", "signatures", "sponsors"];
4
+ export declare function createForgeyardSpec(): OpenApiDocument;