@wirebench/engine 2.2.1 → 3.1.0-rc.1

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 (566) hide show
  1. package/README.md +134 -1
  2. package/dist/account/schema.d.ts +34 -0
  3. package/dist/account/schema.js +29 -0
  4. package/dist/assert/callback.d.ts +76 -0
  5. package/dist/assert/callback.js +320 -0
  6. package/dist/assert/capture-source.d.ts +50 -0
  7. package/dist/assert/capture-source.js +89 -0
  8. package/dist/assert/check.d.ts +8 -0
  9. package/dist/assert/check.js +18 -0
  10. package/dist/assert/header.d.ts +5 -0
  11. package/dist/assert/header.js +48 -0
  12. package/dist/assert/index.d.ts +2 -2
  13. package/dist/assert/index.js +12 -0
  14. package/dist/assert/match.d.ts +6 -0
  15. package/dist/assert/match.js +13 -4
  16. package/dist/assert/model.d.ts +110 -3
  17. package/dist/assert/model.js +16 -1
  18. package/dist/assert/schema.d.ts +194 -1
  19. package/dist/assert/schema.js +154 -12
  20. package/dist/assert/status-names.d.ts +9 -0
  21. package/dist/assert/status-names.js +27 -0
  22. package/dist/assert/status.d.ts +4 -1
  23. package/dist/assert/status.js +27 -3
  24. package/dist/asyncapi/browser.d.ts +7 -0
  25. package/dist/asyncapi/browser.js +6 -0
  26. package/dist/asyncapi/frame-check-worker-host.d.ts +44 -0
  27. package/dist/asyncapi/frame-check-worker-host.js +175 -0
  28. package/dist/asyncapi/frame-check-worker.d.ts +12 -0
  29. package/dist/asyncapi/frame-check-worker.js +25 -0
  30. package/dist/asyncapi/frame-check.d.ts +25 -0
  31. package/dist/asyncapi/frame-check.js +78 -0
  32. package/dist/asyncapi/import.d.ts +25 -0
  33. package/dist/asyncapi/import.js +34 -0
  34. package/dist/asyncapi/map.d.ts +40 -0
  35. package/dist/asyncapi/map.js +230 -0
  36. package/dist/asyncapi/model.d.ts +84 -0
  37. package/dist/asyncapi/model.js +7 -0
  38. package/dist/asyncapi/normalise-2.d.ts +13 -0
  39. package/dist/asyncapi/normalise-2.js +113 -0
  40. package/dist/asyncapi/normalise-3.d.ts +14 -0
  41. package/dist/asyncapi/normalise-3.js +133 -0
  42. package/dist/asyncapi/parse.d.ts +31 -0
  43. package/dist/asyncapi/parse.js +85 -0
  44. package/dist/asyncapi/read.d.ts +35 -0
  45. package/dist/asyncapi/read.js +186 -0
  46. package/dist/asyncapi/security.d.ts +14 -0
  47. package/dist/asyncapi/security.js +55 -0
  48. package/dist/asyncapi/update.d.ts +53 -0
  49. package/dist/asyncapi/update.js +220 -0
  50. package/dist/errors.d.ts +16 -0
  51. package/dist/errors.js +22 -0
  52. package/dist/grpc/events.d.ts +22 -0
  53. package/dist/grpc/events.js +1 -0
  54. package/dist/grpc/expand.d.ts +1 -1
  55. package/dist/grpc/expand.js +15 -5
  56. package/dist/grpc/files.d.ts +271 -0
  57. package/dist/grpc/files.js +62 -0
  58. package/dist/grpc/model.d.ts +11 -1
  59. package/dist/grpc/module.d.ts +2 -0
  60. package/dist/grpc/module.js +13 -0
  61. package/dist/grpc/run.d.ts +73 -0
  62. package/dist/grpc/run.js +407 -0
  63. package/dist/grpc/script-types.d.ts +8 -0
  64. package/dist/grpc/script-types.js +149 -0
  65. package/dist/grpc/scripting.d.ts +34 -0
  66. package/dist/grpc/scripting.js +147 -0
  67. package/dist/grpc/send-input.d.ts +46 -0
  68. package/dist/grpc/send-input.js +42 -0
  69. package/dist/grpc/send.d.ts +2 -2
  70. package/dist/grpc/status.d.ts +9 -2
  71. package/dist/grpc/status.js +11 -24
  72. package/dist/grpc/storage.d.ts +9 -0
  73. package/dist/grpc/storage.js +167 -0
  74. package/dist/{rest/auth.d.ts → http/auth/apply-auth.d.ts} +4 -4
  75. package/dist/{rest/auth.js → http/auth/apply-auth.js} +1 -1
  76. package/dist/http/auth/apply.d.ts +1 -1
  77. package/dist/{rest → http/auth}/oauth2.d.ts +2 -2
  78. package/dist/{rest → http/auth}/oauth2.js +1 -1
  79. package/dist/http/auth/send-auth.d.ts +57 -0
  80. package/dist/http/auth/send-auth.js +7 -0
  81. package/dist/http/client.js +150 -8
  82. package/dist/http/cookies.d.ts +79 -0
  83. package/dist/http/cookies.js +81 -0
  84. package/dist/http/curl.d.ts +4 -14
  85. package/dist/http/curl.js +4 -154
  86. package/dist/http/decompress.d.ts +7 -0
  87. package/dist/http/decompress.js +23 -1
  88. package/dist/http/document-fetch.d.ts +42 -0
  89. package/dist/http/document-fetch.js +207 -0
  90. package/dist/http/entries.d.ts +27 -0
  91. package/dist/http/entries.js +16 -0
  92. package/dist/http/escape.d.ts +18 -0
  93. package/dist/http/escape.js +30 -0
  94. package/dist/http/fetch-document.d.ts +28 -0
  95. package/dist/{wsdl/fetch.js → http/fetch-document.js} +8 -16
  96. package/dist/http/media-type.d.ts +9 -0
  97. package/dist/http/media-type.js +12 -0
  98. package/dist/http/transcript-cap.d.ts +26 -0
  99. package/dist/http/transcript-cap.js +36 -0
  100. package/dist/http/types.d.ts +59 -0
  101. package/dist/http/webhook-signature.d.ts +81 -0
  102. package/dist/http/webhook-signature.js +227 -0
  103. package/dist/import-detect.d.ts +2 -2
  104. package/dist/import-detect.js +10 -1
  105. package/dist/index.d.ts +207 -55
  106. package/dist/index.js +129 -32
  107. package/dist/json/cursor.d.ts +2 -0
  108. package/dist/json/cursor.js +1 -0
  109. package/dist/json/pointer-range.d.ts +18 -0
  110. package/dist/json/pointer-range.js +157 -0
  111. package/dist/json/schema/model.d.ts +59 -0
  112. package/dist/json/schema/model.js +8 -0
  113. package/dist/json/schema/parse-text.d.ts +16 -0
  114. package/dist/json/schema/parse-text.js +37 -0
  115. package/dist/{rest/openapi → json/schema}/refs.d.ts +2 -2
  116. package/dist/{rest/openapi → json/schema}/refs.js +3 -3
  117. package/dist/{rest/openapi → json/schema}/sample.d.ts +4 -0
  118. package/dist/{rest/openapi → json/schema}/sample.js +2 -2
  119. package/dist/json/schema/source.d.ts +21 -0
  120. package/dist/json/schema/source.js +8 -0
  121. package/dist/json/schema-validate.d.ts +49 -0
  122. package/dist/json/schema-validate.js +557 -0
  123. package/dist/{wss/keystore → keystore}/index.js +1 -1
  124. package/dist/{wss/keystore → keystore}/pem.js +1 -1
  125. package/dist/{wss/keystore → keystore}/pkcs12.js +1 -1
  126. package/dist/project/attachments-cache.d.ts +3 -1
  127. package/dist/{wsdl → project}/cache-naming.js +1 -1
  128. package/dist/project/endpoints.d.ts +18 -8
  129. package/dist/project/endpoints.js +21 -6
  130. package/dist/project/environments.d.ts +7 -5
  131. package/dist/project/history.d.ts +105 -9
  132. package/dist/project/history.js +195 -23
  133. package/dist/project/inherit.d.ts +7 -0
  134. package/dist/project/inherit.js +9 -0
  135. package/dist/project/keystores.d.ts +1 -1
  136. package/dist/project/load-helpers.d.ts +89 -0
  137. package/dist/project/load-helpers.js +177 -0
  138. package/dist/project/load.d.ts +30 -4
  139. package/dist/project/load.js +168 -545
  140. package/dist/project/managed-files.d.ts +36 -0
  141. package/dist/project/managed-files.js +97 -0
  142. package/dist/project/migrate.d.ts +2 -2
  143. package/dist/project/migrate.js +2 -2
  144. package/dist/project/model.d.ts +92 -14
  145. package/dist/project/model.js +50 -4
  146. package/dist/project/paths.d.ts +10 -1
  147. package/dist/project/paths.js +10 -1
  148. package/dist/project/preferences.d.ts +11 -2
  149. package/dist/project/preferences.js +5 -1
  150. package/dist/project/properties.d.ts +31 -17
  151. package/dist/project/properties.js +89 -70
  152. package/dist/project/request-location.d.ts +20 -0
  153. package/dist/project/request-location.js +62 -0
  154. package/dist/project/save.d.ts +12 -2
  155. package/dist/project/save.js +186 -141
  156. package/dist/project/schema-parts.d.ts +337 -0
  157. package/dist/project/schema-parts.js +248 -0
  158. package/dist/project/schema.d.ts +72 -928
  159. package/dist/project/schema.js +17 -466
  160. package/dist/project/sequence-guards.d.ts +43 -0
  161. package/dist/project/sequence-guards.js +109 -0
  162. package/dist/project/serialize-helpers.d.ts +60 -0
  163. package/dist/project/serialize-helpers.js +108 -0
  164. package/dist/project/serialize.d.ts +7 -8
  165. package/dist/project/serialize.js +34 -293
  166. package/dist/protocol/features.d.ts +51 -0
  167. package/dist/protocol/features.js +64 -0
  168. package/dist/protocol/index.d.ts +7 -0
  169. package/dist/protocol/index.js +4 -0
  170. package/dist/protocol/module.d.ts +247 -0
  171. package/dist/protocol/module.js +48 -0
  172. package/dist/protocol/registry.d.ts +42 -0
  173. package/dist/protocol/registry.js +47 -0
  174. package/dist/protocols.d.ts +77 -0
  175. package/dist/protocols.js +40 -0
  176. package/dist/redact/index.d.ts +12 -1
  177. package/dist/redact/index.js +55 -7
  178. package/dist/redact/literal.d.ts +10 -0
  179. package/dist/redact/literal.js +110 -12
  180. package/dist/rest/body.d.ts +2 -10
  181. package/dist/rest/body.js +3 -25
  182. package/dist/rest/browser.d.ts +4 -0
  183. package/dist/rest/browser.js +5 -0
  184. package/dist/rest/contract-check-worker-host.d.ts +36 -0
  185. package/dist/rest/contract-check-worker-host.js +158 -0
  186. package/dist/rest/contract-check-worker.d.ts +7 -0
  187. package/dist/rest/contract-check-worker.js +28 -0
  188. package/dist/rest/contract-check.d.ts +43 -0
  189. package/dist/rest/contract-check.js +217 -0
  190. package/dist/rest/cookie-jar.d.ts +62 -0
  191. package/dist/rest/cookie-jar.js +262 -0
  192. package/dist/rest/cookies.d.ts +6 -22
  193. package/dist/rest/cookies.js +6 -42
  194. package/dist/rest/curl.js +5 -1
  195. package/dist/rest/events.d.ts +12 -0
  196. package/dist/rest/events.js +1 -0
  197. package/dist/rest/expand.d.ts +6 -1
  198. package/dist/rest/expand.js +29 -11
  199. package/dist/rest/files.d.ts +439 -0
  200. package/dist/rest/files.js +107 -0
  201. package/dist/rest/json-form.d.ts +97 -0
  202. package/dist/rest/json-form.js +396 -0
  203. package/dist/rest/model.d.ts +35 -24
  204. package/dist/rest/model.js +6 -9
  205. package/dist/rest/module.d.ts +2 -0
  206. package/dist/rest/module.js +13 -0
  207. package/dist/rest/openapi/cache.d.ts +7 -2
  208. package/dist/rest/openapi/cache.js +2 -2
  209. package/dist/rest/openapi/import.d.ts +11 -16
  210. package/dist/rest/openapi/import.js +6 -2
  211. package/dist/rest/openapi/map.d.ts +38 -1
  212. package/dist/rest/openapi/map.js +151 -41
  213. package/dist/rest/openapi/match.d.ts +20 -0
  214. package/dist/rest/openapi/match.js +117 -0
  215. package/dist/rest/openapi/model.d.ts +33 -45
  216. package/dist/rest/openapi/parse.d.ts +3 -12
  217. package/dist/rest/openapi/parse.js +138 -67
  218. package/dist/rest/openapi/responses.d.ts +23 -0
  219. package/dist/rest/openapi/responses.js +59 -0
  220. package/dist/rest/openapi/runtime-expression.d.ts +69 -0
  221. package/dist/rest/openapi/runtime-expression.js +213 -0
  222. package/dist/rest/openapi/update.d.ts +116 -0
  223. package/dist/rest/openapi/update.js +456 -0
  224. package/dist/rest/postman/map.d.ts +1 -0
  225. package/dist/rest/postman/map.js +66 -4
  226. package/dist/rest/postman/model.d.ts +9 -0
  227. package/dist/rest/postman/parse.js +33 -10
  228. package/dist/rest/response.d.ts +2 -23
  229. package/dist/rest/response.js +3 -75
  230. package/dist/rest/run.d.ts +56 -0
  231. package/dist/rest/run.js +395 -0
  232. package/dist/rest/script-types.d.ts +7 -0
  233. package/dist/rest/script-types.js +83 -0
  234. package/dist/rest/scripting.d.ts +38 -0
  235. package/dist/rest/scripting.js +282 -0
  236. package/dist/rest/send-input.d.ts +54 -0
  237. package/dist/rest/send-input.js +73 -0
  238. package/dist/rest/send.d.ts +77 -4
  239. package/dist/rest/send.js +128 -7
  240. package/dist/rest/sse-transcript.d.ts +25 -0
  241. package/dist/rest/sse-transcript.js +95 -0
  242. package/dist/rest/sse.d.ts +43 -0
  243. package/dist/rest/sse.js +195 -0
  244. package/dist/rest/storage.d.ts +26 -0
  245. package/dist/rest/storage.js +262 -0
  246. package/dist/rest/url.d.ts +10 -4
  247. package/dist/rest/url.js +38 -5
  248. package/dist/run/baseline-update.d.ts +35 -0
  249. package/dist/run/baseline-update.js +97 -0
  250. package/dist/run/baseline.d.ts +42 -0
  251. package/dist/run/baseline.js +93 -0
  252. package/dist/run/context.d.ts +86 -0
  253. package/dist/run/context.js +31 -0
  254. package/dist/run/current-values.d.ts +32 -0
  255. package/dist/run/current-values.js +43 -0
  256. package/dist/run/event-queue.d.ts +14 -0
  257. package/dist/run/event-queue.js +46 -0
  258. package/dist/run/exchange.d.ts +62 -0
  259. package/dist/run/exchange.js +65 -0
  260. package/dist/run/host.d.ts +89 -0
  261. package/dist/run/host.js +1 -0
  262. package/dist/run/index.d.ts +20 -7
  263. package/dist/run/index.js +12 -4
  264. package/dist/run/oauth2-token.d.ts +42 -0
  265. package/dist/run/oauth2-token.js +92 -0
  266. package/dist/run/open.d.ts +12 -0
  267. package/dist/run/open.js +16 -0
  268. package/dist/run/run.d.ts +124 -4
  269. package/dist/run/run.js +293 -134
  270. package/dist/run/scope.d.ts +11 -0
  271. package/dist/run/scope.js +26 -0
  272. package/dist/run/script-support.d.ts +53 -0
  273. package/dist/run/script-support.js +68 -0
  274. package/dist/run/secret-needs.d.ts +11 -4
  275. package/dist/run/secret-needs.js +48 -96
  276. package/dist/run/select.d.ts +34 -25
  277. package/dist/run/select.js +45 -54
  278. package/dist/run/send-helpers.d.ts +93 -0
  279. package/dist/run/send-helpers.js +255 -0
  280. package/dist/run/tree.d.ts +50 -0
  281. package/dist/run/tree.js +54 -0
  282. package/dist/script/api/postman.d.ts +10 -0
  283. package/dist/script/api/postman.js +264 -0
  284. package/dist/script/api/prelude.d.ts +20 -0
  285. package/dist/script/api/prelude.js +215 -0
  286. package/dist/script/apply.d.ts +44 -0
  287. package/dist/script/apply.js +120 -0
  288. package/dist/script/check/host.d.ts +41 -0
  289. package/dist/script/check/host.js +143 -0
  290. package/dist/script/check/service.d.ts +52 -0
  291. package/dist/script/check/service.js +195 -0
  292. package/dist/script/check/worker.d.ts +1 -0
  293. package/dist/script/check/worker.js +40 -0
  294. package/dist/script/index.d.ts +16 -0
  295. package/dist/script/index.js +10 -0
  296. package/dist/script/lookup.d.ts +10 -0
  297. package/dist/script/lookup.js +23 -0
  298. package/dist/script/model.d.ts +82 -0
  299. package/dist/script/model.js +18 -0
  300. package/dist/script/props.d.ts +8 -0
  301. package/dist/script/props.js +28 -0
  302. package/dist/script/request-scripts.d.ts +83 -0
  303. package/dist/script/request-scripts.js +160 -0
  304. package/dist/script/run.d.ts +47 -0
  305. package/dist/script/run.js +146 -0
  306. package/dist/script/sandbox/execute.d.ts +26 -0
  307. package/dist/script/sandbox/execute.js +212 -0
  308. package/dist/script/sandbox/host-api.d.ts +27 -0
  309. package/dist/script/sandbox/host-api.js +101 -0
  310. package/dist/script/sandbox/host.d.ts +18 -0
  311. package/dist/script/sandbox/host.js +172 -0
  312. package/dist/script/sandbox/model.d.ts +69 -0
  313. package/dist/script/sandbox/model.js +24 -0
  314. package/dist/script/sandbox/worker.d.ts +1 -0
  315. package/dist/script/sandbox/worker.js +20 -0
  316. package/dist/script/send.d.ts +27 -0
  317. package/dist/script/send.js +76 -0
  318. package/dist/script/strip.d.ts +5 -0
  319. package/dist/script/strip.js +43 -0
  320. package/dist/script/types/api.d.ts +38 -0
  321. package/dist/script/types/api.js +113 -0
  322. package/dist/script/types/json-schema.d.ts +26 -0
  323. package/dist/script/types/json-schema.js +206 -0
  324. package/dist/secrets/env-names.d.ts +9 -1
  325. package/dist/secrets/env-names.js +17 -1
  326. package/dist/secrets/resolve.d.ts +44 -4
  327. package/dist/secrets/resolve.js +58 -1
  328. package/dist/secrets/scan/apply.d.ts +36 -0
  329. package/dist/secrets/scan/apply.js +194 -0
  330. package/dist/secrets/scan/rules.d.ts +32 -0
  331. package/dist/secrets/scan/rules.js +346 -0
  332. package/dist/secrets/scan/scan.d.ts +6 -0
  333. package/dist/secrets/scan/scan.js +57 -0
  334. package/dist/secrets/scan/walk.d.ts +70 -0
  335. package/dist/secrets/scan/walk.js +156 -0
  336. package/dist/secrets/secret-refs.d.ts +8 -0
  337. package/dist/secrets/secret-refs.js +25 -0
  338. package/dist/secrets/secret-token.d.ts +17 -0
  339. package/dist/secrets/secret-token.js +25 -0
  340. package/dist/sequence/file.d.ts +169 -0
  341. package/dist/sequence/file.js +237 -0
  342. package/dist/sequence/index.d.ts +7 -0
  343. package/dist/sequence/index.js +5 -0
  344. package/dist/sequence/load.d.ts +32 -0
  345. package/dist/sequence/load.js +56 -0
  346. package/dist/sequence/model.d.ts +115 -0
  347. package/dist/sequence/model.js +53 -0
  348. package/dist/sequence/run.d.ts +131 -0
  349. package/dist/sequence/run.js +191 -0
  350. package/dist/sequence/transfer.d.ts +24 -0
  351. package/dist/sequence/transfer.js +75 -0
  352. package/dist/server-api/audit.d.ts +455 -0
  353. package/dist/server-api/audit.js +186 -0
  354. package/dist/server-api/ci-tokens.d.ts +50 -0
  355. package/dist/server-api/ci-tokens.js +35 -0
  356. package/dist/server-api/hooks.d.ts +337 -0
  357. package/dist/server-api/hooks.js +152 -0
  358. package/dist/server-api/identity.d.ts +210 -0
  359. package/dist/server-api/identity.js +115 -0
  360. package/dist/server-api/licensing.d.ts +80 -0
  361. package/dist/server-api/licensing.js +53 -0
  362. package/dist/server-api/live.d.ts +132 -0
  363. package/dist/server-api/live.js +102 -0
  364. package/dist/server-api/meta.d.ts +31 -0
  365. package/dist/server-api/meta.js +21 -0
  366. package/dist/server-api/sync.d.ts +179 -0
  367. package/dist/server-api/sync.js +124 -0
  368. package/dist/server-api/teams.d.ts +306 -0
  369. package/dist/server-api/teams.js +113 -0
  370. package/dist/snapshot/diff.d.ts +30 -0
  371. package/dist/snapshot/diff.js +75 -0
  372. package/dist/snapshot/format.d.ts +17 -0
  373. package/dist/snapshot/format.js +40 -0
  374. package/dist/snapshot/golden-file.d.ts +45 -0
  375. package/dist/snapshot/golden-file.js +173 -0
  376. package/dist/snapshot/ignore.d.ts +14 -0
  377. package/dist/snapshot/ignore.js +79 -0
  378. package/dist/snapshot/index.d.ts +9 -0
  379. package/dist/snapshot/index.js +9 -0
  380. package/dist/snapshot/json-diff.d.ts +3 -0
  381. package/dist/snapshot/json-diff.js +93 -0
  382. package/dist/snapshot/xml-diff.d.ts +10 -0
  383. package/dist/snapshot/xml-diff.js +194 -0
  384. package/dist/soap/auth.d.ts +26 -0
  385. package/dist/soap/auth.js +54 -0
  386. package/dist/soap/curl.d.ts +20 -0
  387. package/dist/soap/curl.js +161 -0
  388. package/dist/soap/expand.d.ts +24 -0
  389. package/dist/soap/expand.js +95 -0
  390. package/dist/soap/files.d.ts +384 -0
  391. package/dist/soap/files.js +114 -0
  392. package/dist/soap/form-request.d.ts +13 -0
  393. package/dist/soap/form-request.js +2 -2
  394. package/dist/soap/generate.d.ts +12 -0
  395. package/dist/{generate.js → soap/generate.js} +4 -4
  396. package/dist/{import.d.ts → soap/import.d.ts} +4 -4
  397. package/dist/{import.js → soap/import.js} +13 -13
  398. package/dist/soap/json-operation.d.ts +35 -0
  399. package/dist/soap/json-operation.js +225 -0
  400. package/dist/soap/legacy-project/env-refs.d.ts +19 -0
  401. package/dist/soap/legacy-project/env-refs.js +105 -0
  402. package/dist/soap/legacy-project/map.d.ts +2 -2
  403. package/dist/soap/legacy-project/map.js +6 -0
  404. package/dist/soap/mime/multipart.d.ts +2 -2
  405. package/dist/soap/mime/multipart.js +2 -5
  406. package/dist/soap/mime/send-pipeline.d.ts +1 -1
  407. package/dist/soap/mime/send-pipeline.js +1 -1
  408. package/dist/soap/mime/types.d.ts +1 -3
  409. package/dist/soap/module.d.ts +2 -0
  410. package/dist/soap/module.js +13 -0
  411. package/dist/soap/namespace-scope.js +1 -1
  412. package/dist/soap/operations.d.ts +12 -0
  413. package/dist/{operations.js → soap/operations.js} +4 -4
  414. package/dist/soap/run.d.ts +70 -0
  415. package/dist/soap/run.js +549 -0
  416. package/dist/soap/script-types.d.ts +65 -0
  417. package/dist/soap/script-types.js +379 -0
  418. package/dist/soap/scripting.d.ts +45 -0
  419. package/dist/soap/scripting.js +221 -0
  420. package/dist/soap/send-input.d.ts +61 -0
  421. package/dist/{send-options.js → soap/send-input.js} +5 -109
  422. package/dist/{send.d.ts → soap/send.d.ts} +1 -1
  423. package/dist/{send.js → soap/send.js} +28 -12
  424. package/dist/soap/storage.d.ts +9 -0
  425. package/dist/soap/storage.js +237 -0
  426. package/dist/soap/transforms.d.ts +3 -12
  427. package/dist/soap/transforms.js +3 -14
  428. package/dist/{types.d.ts → soap/types.d.ts} +34 -84
  429. package/dist/sync/git-cli.d.ts +202 -0
  430. package/dist/sync/git-cli.js +684 -0
  431. package/dist/sync/three-way-merge.d.ts +41 -0
  432. package/dist/sync/three-way-merge.js +85 -0
  433. package/dist/sync/tree-paths.d.ts +34 -0
  434. package/dist/sync/tree-paths.js +131 -0
  435. package/dist/team-secrets/envelope.d.ts +10 -0
  436. package/dist/team-secrets/envelope.js +121 -0
  437. package/dist/team-secrets/errors.d.ts +26 -0
  438. package/dist/team-secrets/errors.js +27 -0
  439. package/dist/team-secrets/index.d.ts +14 -0
  440. package/dist/team-secrets/index.js +8 -0
  441. package/dist/team-secrets/keys.d.ts +52 -0
  442. package/dist/team-secrets/keys.js +158 -0
  443. package/dist/team-secrets/log.d.ts +48 -0
  444. package/dist/team-secrets/log.js +175 -0
  445. package/dist/team-secrets/resolve-conflict.d.ts +7 -0
  446. package/dist/team-secrets/resolve-conflict.js +14 -0
  447. package/dist/team-secrets/schema.d.ts +97 -0
  448. package/dist/team-secrets/schema.js +157 -0
  449. package/dist/team-secrets/sign.d.ts +24 -0
  450. package/dist/team-secrets/sign.js +71 -0
  451. package/dist/team-secrets/vault.d.ts +49 -0
  452. package/dist/team-secrets/vault.js +148 -0
  453. package/dist/validate/wsi/run-message.d.ts +2 -2
  454. package/dist/validate/wsi/run-message.js +1 -1
  455. package/dist/validate/wsi/run-wsdl.d.ts +2 -2
  456. package/dist/validate/wsi/run-wsdl.js +1 -1
  457. package/dist/validate/wsi/types.d.ts +1 -1
  458. package/dist/webhooks/model.d.ts +138 -0
  459. package/dist/webhooks/model.js +150 -0
  460. package/dist/workspace/commit-message.d.ts +1 -1
  461. package/dist/workspace/commit-message.js +6 -1
  462. package/dist/workspace/environments.d.ts +11 -4
  463. package/dist/workspace/environments.js +12 -0
  464. package/dist/workspace/index.d.ts +3 -3
  465. package/dist/workspace/index.js +2 -2
  466. package/dist/workspace/paths.d.ts +5 -2
  467. package/dist/workspace/paths.js +5 -2
  468. package/dist/workspace/schema.d.ts +7 -3
  469. package/dist/workspace/schema.js +24 -3
  470. package/dist/workspace/share.d.ts +30 -11
  471. package/dist/workspace/share.js +32 -6
  472. package/dist/ws/call.d.ts +1 -1
  473. package/dist/ws/call.js +2 -2
  474. package/dist/ws/connect.d.ts +60 -0
  475. package/dist/ws/connect.js +131 -0
  476. package/dist/ws/events.d.ts +17 -0
  477. package/dist/ws/events.js +1 -0
  478. package/dist/ws/expand.d.ts +1 -1
  479. package/dist/ws/expand.js +1 -1
  480. package/dist/ws/files.d.ts +284 -0
  481. package/dist/ws/files.js +71 -0
  482. package/dist/ws/history-entry.d.ts +44 -0
  483. package/dist/ws/history-entry.js +93 -0
  484. package/dist/ws/model.d.ts +44 -3
  485. package/dist/ws/model.js +3 -0
  486. package/dist/ws/module.d.ts +2 -0
  487. package/dist/ws/module.js +11 -0
  488. package/dist/ws/run.d.ts +63 -0
  489. package/dist/ws/run.js +470 -0
  490. package/dist/ws/session.d.ts +18 -0
  491. package/dist/ws/session.js +52 -25
  492. package/dist/ws/storage.d.ts +9 -0
  493. package/dist/ws/storage.js +176 -0
  494. package/dist/ws/transcript.d.ts +3 -4
  495. package/dist/ws/transcript.js +26 -17
  496. package/dist/ws/url.d.ts +1 -1
  497. package/dist/wsdl/cache.js +1 -1
  498. package/dist/wsdl/docs-generator.d.ts +3 -3
  499. package/dist/wsdl/docs-generator.js +1 -1
  500. package/dist/wsdl/export-definition.js +1 -1
  501. package/dist/wsdl/qname.d.ts +2 -5
  502. package/dist/wsdl/resolver.d.ts +4 -11
  503. package/dist/wsdl/resolver.js +3 -3
  504. package/dist/wsdl/update-definition.d.ts +5 -5
  505. package/dist/wsdl/update-definition.js +6 -6
  506. package/dist/wss/apply.js +1 -1
  507. package/dist/{project/wss-configs.d.ts → wss/configs.d.ts} +2 -2
  508. package/dist/{project/wss-configs.js → wss/configs.js} +2 -2
  509. package/dist/wss/incoming/decrypt.d.ts +1 -1
  510. package/dist/wss/incoming/index.js +1 -1
  511. package/dist/wss/incoming/verify.d.ts +1 -1
  512. package/dist/wss/incoming/verify.js +1 -1
  513. package/dist/wss/key-identifiers.js +1 -1
  514. package/dist/wss/model.d.ts +1 -1
  515. package/dist/wss/outgoing/encryption.d.ts +1 -1
  516. package/dist/wss/outgoing/signature.d.ts +1 -1
  517. package/dist/xml/decode.d.ts +15 -0
  518. package/dist/xml/decode.js +22 -0
  519. package/dist/xml/entitize.d.ts +17 -0
  520. package/dist/xml/entitize.js +19 -0
  521. package/dist/xml/index.d.ts +1 -1
  522. package/dist/xml/index.js +1 -1
  523. package/dist/xml/locate.d.ts +39 -0
  524. package/dist/xml/locate.js +117 -0
  525. package/dist/xml/qname.d.ts +12 -0
  526. package/dist/xml/qname.js +8 -0
  527. package/dist/xpath/evaluate-async.d.ts +19 -0
  528. package/dist/xpath/evaluate-async.js +31 -11
  529. package/dist/xpath/evaluate.d.ts +1 -1
  530. package/dist/xpath/namespaces.js +1 -1
  531. package/dist/xpath/worker.d.ts +11 -5
  532. package/dist/xpath/worker.js +24 -7
  533. package/dist/xsd/form-model.d.ts +19 -2
  534. package/dist/xsd/form-model.js +14 -2
  535. package/dist/xsd/json-bridge.d.ts +152 -0
  536. package/dist/xsd/json-bridge.js +1213 -0
  537. package/dist/xsd/locate.d.ts +2 -30
  538. package/dist/xsd/locate.js +1 -109
  539. package/dist/xsd/xml-scan.d.ts +2 -0
  540. package/dist/xsd/xml-scan.js +1 -1
  541. package/dist/xsd/xml-writer.d.ts +2 -0
  542. package/dist/xsd/xml-writer.js +4 -0
  543. package/package.json +12 -1
  544. package/dist/generate.d.ts +0 -12
  545. package/dist/operations.d.ts +0 -12
  546. package/dist/run/effective-auth.d.ts +0 -10
  547. package/dist/run/effective-auth.js +0 -19
  548. package/dist/run/prepare.d.ts +0 -43
  549. package/dist/run/prepare.js +0 -280
  550. package/dist/send-options.d.ts +0 -141
  551. package/dist/wsdl/fetch.d.ts +0 -13
  552. /package/dist/{soap → http}/charset.d.ts +0 -0
  553. /package/dist/{soap → http}/charset.js +0 -0
  554. /package/dist/{wsdl → http}/ref-policy.d.ts +0 -0
  555. /package/dist/{wsdl → http}/ref-policy.js +0 -0
  556. /package/dist/{wss/keystore → keystore}/certificate.d.ts +0 -0
  557. /package/dist/{wss/keystore → keystore}/certificate.js +0 -0
  558. /package/dist/{wss/keystore → keystore}/index.d.ts +0 -0
  559. /package/dist/{wss/keystore → keystore}/model.d.ts +0 -0
  560. /package/dist/{wss/keystore → keystore}/model.js +0 -0
  561. /package/dist/{wss/keystore → keystore}/pem.d.ts +0 -0
  562. /package/dist/{wss/keystore → keystore}/pkcs12.d.ts +0 -0
  563. /package/dist/{wsdl → project}/cache-naming.d.ts +0 -0
  564. /package/dist/{types.js → soap/types.js} +0 -0
  565. /package/dist/{soap → xml}/prefixes.d.ts +0 -0
  566. /package/dist/{soap → xml}/prefixes.js +0 -0
@@ -5,36 +5,41 @@
5
5
  * rewritten (so an autosave produces a one-file git diff, and file watchers
6
6
  * stay quiet), and every write goes through a temp file plus `rename`.
7
7
  *
8
- * Only Wirebench's own subtrees are managed. The definition cache
8
+ * Only Wirebench's own subtrees are managed: core lists its own files, and each
9
+ * protocol module lists those of its containers. The definition cache
9
10
  * (`interfaces/<slug>/definition/`) and `attachments/` belong to other
10
11
  * components and are never read or removed here — except when their owning
11
12
  * interface is deleted, in which case the whole interface folder goes.
12
13
  */
13
- import { dirname, join } from 'node:path';
14
- import { API_FILE, APIS_DIR, ENVIRONMENTS_DIR, FOLDER_FILE, INTERFACES_DIR, OPERATIONS_DIR, REQUEST_SUFFIX, REQUESTS_DIR, WSS_DIR, } from './paths.js';
14
+ import { randomBytes } from 'node:crypto';
15
+ import { dirname } from 'node:path';
16
+ import { ProjectError } from '../errors.js';
17
+ import { defaultRegistry } from '../protocols.js';
18
+ import { SEQUENCES_DIR } from '../sequence/file.js';
19
+ import { readSequences } from '../sequence/load.js';
15
20
  import { nodeFs, readFileIfExists, readdirIfExists, writeFileAtomic } from './fs.js';
21
+ import { listApiTreeFiles, toAbsolute } from './managed-files.js';
22
+ import { takenContainerSlugs, unsupportedOf } from './model.js';
23
+ import { APIS_DIR, ENVIRONMENTS_DIR, INTERFACES_DIR, REQUESTS_DIR, WEBHOOKS_DIR, WEBHOOKS_FEATURE, WEBHOOKS_FILE, WSS_DIR, } from './paths.js';
16
24
  import { KEYSTORES_PATH, MANIFEST_PATH, projectFiles } from './serialize.js';
17
- function toAbsolute(root, relative) {
18
- return join(root, ...relative.split('/'));
19
- }
20
25
  /**
21
- * Lists every file Wirebench manages under `root` — i.e. every file that
22
- * matches one of the format's own patterns:
26
+ * Lists the files core itself manages under `root` — every file that matches one of these
27
+ * patterns:
23
28
  *
24
29
  * - `wirebench.yaml`
25
30
  * - `environments/*.yaml`
26
- * - `interfaces/*\/interface.yaml`
27
- * - `interfaces/*\/operations/*\/*.request.yaml`, plus the sibling `*.xml` of
28
- * any such file
29
31
  * - `wss/{outgoing,incoming}/*.yaml`
30
32
  * - `wss/keystores.yaml`
33
+ * - `webhooks/webhooks.yaml`, while the `rest` feature is on
34
+ * - `webhooks/requests/**` (the collection's own request tree, same layout as an API's), while the
35
+ * `rest` feature is on
36
+ * - the `sequences/*.sequence.yaml` this build loaded
31
37
  *
32
- * Anything else on disk — a README, a `.gitkeep`, notes, an orphan `.xml`
33
- * with no matching `.request.yaml` — is a foreign file and is never a
34
- * deletion candidate, even when it sits inside a directory Wirebench
35
- * otherwise manages.
38
+ * A container's files are its protocol's to list (`storage.managed`). Anything else on disk — a
39
+ * README, a `.gitkeep`, notes — is a foreign file and is never a deletion candidate, even when it
40
+ * sits inside a directory Wirebench otherwise manages.
36
41
  */
37
- async function listManagedFiles(fs, root) {
42
+ async function listCoreManagedFiles(fs, root, registry) {
38
43
  const managed = [];
39
44
  if ((await readFileIfExists(fs, toAbsolute(root, MANIFEST_PATH))) !== undefined) {
40
45
  managed.push(MANIFEST_PATH);
@@ -55,118 +60,18 @@ async function listManagedFiles(fs, root) {
55
60
  if ((await readFileIfExists(fs, toAbsolute(root, KEYSTORES_PATH))) !== undefined) {
56
61
  managed.push(KEYSTORES_PATH);
57
62
  }
58
- for (const entry of await readdirIfExists(fs, toAbsolute(root, APIS_DIR))) {
59
- if (!entry.isDirectory) {
60
- continue;
61
- }
62
- const base = `${APIS_DIR}/${entry.name}`;
63
- if ((await readFileIfExists(fs, toAbsolute(root, `${base}/${API_FILE}`))) !== undefined) {
64
- managed.push(`${base}/${API_FILE}`);
65
- }
66
- managed.push(...(await listApiTreeFiles(fs, root, `${base}/${REQUESTS_DIR}`)));
67
- }
68
- for (const entry of await readdirIfExists(fs, toAbsolute(root, INTERFACES_DIR))) {
69
- if (!entry.isDirectory) {
70
- continue;
71
- }
72
- const base = `${INTERFACES_DIR}/${entry.name}`;
73
- const ifaceFile = `${base}/interface.yaml`;
74
- if ((await readFileIfExists(fs, toAbsolute(root, ifaceFile))) !== undefined) {
75
- managed.push(ifaceFile);
76
- }
77
- const opsDir = `${base}/${OPERATIONS_DIR}`;
78
- for (const opEntry of await readdirIfExists(fs, toAbsolute(root, opsDir))) {
79
- if (!opEntry.isDirectory) {
80
- continue;
81
- }
82
- const opDir = `${opsDir}/${opEntry.name}`;
83
- const requestSlugs = new Set();
84
- const opFiles = await readdirIfExists(fs, toAbsolute(root, opDir));
85
- for (const fileEntry of opFiles) {
86
- if (fileEntry.isFile && fileEntry.name.endsWith(REQUEST_SUFFIX)) {
87
- requestSlugs.add(fileEntry.name.slice(0, -REQUEST_SUFFIX.length));
88
- managed.push(`${opDir}/${fileEntry.name}`);
89
- }
90
- }
91
- for (const fileEntry of opFiles) {
92
- if (fileEntry.isFile && fileEntry.name.endsWith('.xml')) {
93
- const slug = fileEntry.name.slice(0, -'.xml'.length);
94
- if (requestSlugs.has(slug)) {
95
- managed.push(`${opDir}/${fileEntry.name}`);
96
- }
97
- }
98
- }
99
- }
100
- }
101
- return managed;
102
- }
103
- /**
104
- * True when `name` is a WebSocket request's saved-message sibling for `requestSlug`:
105
- * `<requestSlug>.msg-<message-slug>.<ext>`, where `<ext>` is one `[A-Za-z0-9]+` run at the very
106
- * end. Matched by trying the known `requestSlug` as a literal prefix — never by a greedy regex
107
- * capture across the whole name — so a request slug that itself contains a dot or the literal text
108
- * `.msg-` cannot be mis-split from the message slug that follows it.
109
- */
110
- function isWsMessageSibling(name, requestSlug) {
111
- const prefix = `${requestSlug}.msg-`;
112
- if (!name.startsWith(prefix)) {
113
- return false;
114
- }
115
- const rest = name.slice(prefix.length);
116
- const dot = rest.lastIndexOf('.');
117
- // dot > 0 requires a non-empty message slug before the extension.
118
- return dot > 0 && /^[A-Za-z0-9]+$/.test(rest.slice(dot + 1));
119
- }
120
- /**
121
- * Lists the managed files inside one directory of an API's request tree: its `folder.yaml`, every
122
- * `*.request.yaml`, and two conventions of per-request sibling file, each claimed only when it
123
- * belongs to a request slug actually present in this directory:
124
- *
125
- * - `<slug>.body.<ext>` — a REST raw body or a gRPC message, one file for the whole request.
126
- * - `<slug>.msg-<message-slug>.<ext>` — one WebSocket saved message, one file per message
127
- * ({@link isWsMessageSibling}).
128
- *
129
- * Claiming only a sibling of a *known* request slug (rather than every file matching either
130
- * pattern) means a hand-placed file — notes, a `.body.json` or `.msg-x.txt` with no matching
131
- * request — is foreign and never a deletion candidate, exactly as in an operation folder.
132
- */
133
- async function listApiTreeFiles(fs, root, dir) {
134
- const managed = [];
135
- const entries = await readdirIfExists(fs, toAbsolute(root, dir));
136
- const requestSlugs = new Set();
137
- for (const entry of entries) {
138
- if (!entry.isFile) {
139
- continue;
140
- }
141
- if (entry.name === FOLDER_FILE) {
142
- managed.push(`${dir}/${entry.name}`);
143
- continue;
144
- }
145
- if (entry.name.endsWith(REQUEST_SUFFIX)) {
146
- requestSlugs.add(entry.name.slice(0, -REQUEST_SUFFIX.length));
147
- managed.push(`${dir}/${entry.name}`);
148
- }
149
- }
150
- for (const entry of entries) {
151
- if (!entry.isFile) {
152
- continue;
153
- }
154
- const body = /^(.*)\.body\.[A-Za-z0-9]+$/.exec(entry.name);
155
- if (body !== null && requestSlugs.has(body[1])) {
156
- managed.push(`${dir}/${entry.name}`);
157
- continue;
158
- }
159
- for (const slug of requestSlugs) {
160
- if (isWsMessageSibling(entry.name, slug)) {
161
- managed.push(`${dir}/${entry.name}`);
162
- break;
163
- }
164
- }
63
+ // The request tree is managed only beside its `webhooks.yaml`, as an API's is beside its `api.yaml`,
64
+ // and only while REST is on: with it off the collection was not loaded, and is not this save's.
65
+ const webhooksFile = `${WEBHOOKS_DIR}/${WEBHOOKS_FILE}`;
66
+ if (registry.features.isEnabled(WEBHOOKS_FEATURE) &&
67
+ (await readFileIfExists(fs, toAbsolute(root, webhooksFile))) !== undefined) {
68
+ managed.push(webhooksFile);
69
+ managed.push(...(await listApiTreeFiles(fs, root, `${WEBHOOKS_DIR}/${REQUESTS_DIR}`)));
165
70
  }
166
- for (const entry of entries) {
167
- if (entry.isDirectory) {
168
- managed.push(...(await listApiTreeFiles(fs, root, `${dir}/${entry.name}`)));
169
- }
71
+ // Only the sequence files this build loaded: one it refused (too new, malformed, a duplicate id) is
72
+ // foreign, so a save can never delete a sequence the user has not seen (`sequence/load.ts`).
73
+ for (const { file } of (await readSequences(fs, root)).loaded) {
74
+ managed.push(file);
170
75
  }
171
76
  return managed;
172
77
  }
@@ -192,15 +97,94 @@ async function pruneEmptyDirs(fs, root, relativeDirs) {
192
97
  }
193
98
  return pruned;
194
99
  }
100
+ /**
101
+ * Refuses a save that would write over a sequence file this build did not load. A new sequence whose
102
+ * slug matches a file from a newer build (or one mid-merge) would otherwise replace it unseen; the
103
+ * mutation layer picks slugs around such files, so this is the backstop, not the usual path.
104
+ *
105
+ * @throws ProjectError `sequence-file-conflict`
106
+ */
107
+ async function refuseOverwritingForeignSequences(fs, root, desired, managed) {
108
+ const loaded = new Set(managed);
109
+ for (const relative of desired.keys()) {
110
+ if (relative.startsWith(`${SEQUENCES_DIR}/`) &&
111
+ !loaded.has(relative) &&
112
+ (await readFileIfExists(fs, toAbsolute(root, relative))) !== undefined) {
113
+ throw new ProjectError('sequence-file-conflict', `${relative} exists but could not be loaded by this build; rename the sequence instead of replacing it`, { details: { file: relative } });
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Refuses a save that would write a container into a placeholder's directory (spec §6): the files
119
+ * there belong to a container this build could not read, and none of them may be replaced. Slugs
120
+ * are compared without case, as `uniqueSlug` compares them, because on most machines two names
121
+ * that differ only in case are one directory. A host that names containers with
122
+ * `takenContainerSlugs` never gets here.
123
+ *
124
+ * @throws ProjectError `container-slug-conflict`
125
+ */
126
+ function refusePlaceholderConflicts(project, registry) {
127
+ const placeholders = unsupportedOf(project);
128
+ if (placeholders.length === 0) {
129
+ return;
130
+ }
131
+ for (const { storage } of registry.modules) {
132
+ for (const container of storage.containers(project)) {
133
+ const placeholder = placeholders.find((candidate) => candidate.dir === storage.dir && candidate.slug.toLowerCase() === container.slug.toLowerCase());
134
+ if (placeholder !== undefined) {
135
+ throw new ProjectError('container-slug-conflict', `"${container.name}" would be saved to ${storage.dir}/${placeholder.slug}, which holds a "${placeholder.kind}" container this build did not load; give it another name`, {
136
+ details: {
137
+ dir: storage.dir,
138
+ slug: container.slug,
139
+ kind: placeholder.kind,
140
+ reason: placeholder.reason,
141
+ },
142
+ });
143
+ }
144
+ }
145
+ }
146
+ }
195
147
  /**
196
148
  * Saves `project` into the directory `root`, creating it if needed.
197
149
  *
198
150
  * @returns which files were written, removed and left untouched.
151
+ * @throws ProjectError `container-slug-conflict` when a container has the slug of a placeholder in
152
+ * its directory; `sequence-file-conflict`; what {@link projectFiles} throws
199
153
  */
200
154
  export async function saveProject(project, root, options) {
201
155
  const fs = options?.fs ?? nodeFs;
202
- const desired = projectFiles(project, options?.writer !== undefined ? { writer: options.writer } : undefined);
203
- const existing = await listManagedFiles(fs, root);
156
+ const registry = options?.registry ?? defaultRegistry();
157
+ const desired = projectFiles(project, {
158
+ registry,
159
+ ...(options?.writer !== undefined ? { writer: options.writer } : {}),
160
+ });
161
+ refusePlaceholderConflicts(project, registry);
162
+ // Which container directories are alive: every container the project holds and every placeholder,
163
+ // whatever this save's registry can write (spec R6). A save never deletes what it cannot write.
164
+ const live = {
165
+ interfaces: takenContainerSlugs(project, 'interfaces'),
166
+ apis: takenContainerSlugs(project, 'apis'),
167
+ };
168
+ // An API whose slug an interface has is skipped on load (`api-slug-conflict`), so it is in no list
169
+ // above; its folder is still the user's and stays.
170
+ const interfaceKeys = new Set([...live.interfaces].map((slug) => slug.toLowerCase()));
171
+ const keptApiDir = (name) => interfaceKeys.has(name.toLowerCase());
172
+ // On a file system that does not tell `Graph` from `graph`, a container renamed only by case still
173
+ // sits in its old folder; give the folder its new name before anything is written into it.
174
+ const foldsCase = await foldsCaseUnder(fs, root);
175
+ if (foldsCase) {
176
+ await renameContainersByCase(fs, root, live);
177
+ }
178
+ // What this save may delete: core's own files, then each module's word on each of its containers
179
+ // (spec §5.2). A placeholder, and a container no enabled module answers for, has no managed file,
180
+ // so nothing under its directory is removed or touched (spec §6).
181
+ const existing = await listCoreManagedFiles(fs, root, registry);
182
+ for (const { storage } of registry.modules) {
183
+ for (const container of storage.containers(project)) {
184
+ existing.push(...(await storage.managed(fs, root, container.slug)));
185
+ }
186
+ }
187
+ await refuseOverwritingForeignSequences(fs, root, desired, existing);
204
188
  const backupsWritten = [];
205
189
  for (const backup of options?.backups ?? []) {
206
190
  if (!backup.endsWith('.xml.bak')) {
@@ -232,19 +216,9 @@ export async function saveProject(project, root, options) {
232
216
  const touchedDirs = new Set();
233
217
  // A deleted interface or API takes its whole folder with it, definition cache included.
234
218
  const goneEntities = new Set();
235
- for (const [dir, liveSlugs] of [
236
- [INTERFACES_DIR, new Set(project.interfaces.map((i) => i.slug))],
237
- [
238
- APIS_DIR,
239
- new Set([
240
- ...project.apis.map((a) => a.slug),
241
- ...project.grpcApis.map((a) => a.slug),
242
- ...project.wsApis.map((a) => a.slug),
243
- ]),
244
- ],
245
- ]) {
219
+ for (const dir of [INTERFACES_DIR, APIS_DIR]) {
246
220
  for (const entry of await readdirIfExists(fs, toAbsolute(root, dir))) {
247
- if (entry.isDirectory && !liveSlugs.has(entry.name)) {
221
+ if (entry.isDirectory && !live[dir].has(entry.name) && !(dir === APIS_DIR && keptApiDir(entry.name))) {
248
222
  const relative = `${dir}/${entry.name}`;
249
223
  await fs.rm(toAbsolute(root, relative), { recursive: true, force: true });
250
224
  removed.push(relative);
@@ -252,10 +226,20 @@ export async function saveProject(project, root, options) {
252
226
  }
253
227
  }
254
228
  }
229
+ // The written path, by its case-folded form, for a file renamed only by case.
230
+ const desiredByKey = new Map([...desired.keys()].map((path) => [path.toLowerCase(), path]));
231
+ const renamedByCase = new Set();
255
232
  for (const relative of existing) {
256
233
  if (desired.has(relative) || [...goneEntities].some((prefix) => relative.startsWith(prefix))) {
257
234
  continue;
258
235
  }
236
+ const sameFile = foldsCase ? desiredByKey.get(relative.toLowerCase()) : undefined;
237
+ if (sameFile !== undefined) {
238
+ // The write above went into this very file and kept its old name; removing it would remove
239
+ // the new content. Give it the new name instead.
240
+ await renamePathByCase(fs, root, relative, sameFile, renamedByCase);
241
+ continue;
242
+ }
259
243
  await fs.rm(toAbsolute(root, relative), { force: true });
260
244
  removed.push(relative);
261
245
  const parent = dirname(relative);
@@ -293,3 +277,64 @@ async function timestampedBackupPath(fs, root, backup, now) {
293
277
  }
294
278
  return candidate;
295
279
  }
280
+ /**
281
+ * Whether the file system under `root` treats two names that differ only by case as one entry, as
282
+ * the default ones on macOS and Windows do. Probed with an entry `root` already holds; a folder that
283
+ * holds nothing yet has nothing to rename, so it answers `false`.
284
+ */
285
+ async function foldsCaseUnder(fs, root) {
286
+ const names = (await readdirIfExists(fs, root)).map((entry) => entry.name);
287
+ const probe = names.find((name) => name.toLowerCase() !== name.toUpperCase());
288
+ if (probe === undefined) {
289
+ return false;
290
+ }
291
+ const swapped = probe === probe.toUpperCase() ? probe.toLowerCase() : probe.toUpperCase();
292
+ if (names.includes(swapped)) {
293
+ return false;
294
+ }
295
+ try {
296
+ await fs.stat(toAbsolute(root, swapped));
297
+ return true;
298
+ }
299
+ catch {
300
+ return false;
301
+ }
302
+ }
303
+ /** Renames `from` to `to`, two names of one entry, through a temporary name so the case change holds. */
304
+ async function renameByCase(fs, from, to) {
305
+ const hop = `${from}.case-${randomBytes(6).toString('hex')}`;
306
+ await fs.rename(from, hop);
307
+ await fs.rename(hop, to);
308
+ }
309
+ /** Gives each container folder whose container was renamed only by case its new name. */
310
+ async function renameContainersByCase(fs, root, live) {
311
+ for (const dir of [INTERFACES_DIR, APIS_DIR]) {
312
+ const byKey = new Map([...live[dir]].map((slug) => [slug.toLowerCase(), slug]));
313
+ for (const entry of await readdirIfExists(fs, toAbsolute(root, dir))) {
314
+ const slug = byKey.get(entry.name.toLowerCase());
315
+ if (entry.isDirectory && slug !== undefined && slug !== entry.name) {
316
+ await renameByCase(fs, toAbsolute(root, `${dir}/${entry.name}`), toAbsolute(root, `${dir}/${slug}`));
317
+ }
318
+ }
319
+ }
320
+ }
321
+ /**
322
+ * Gives the managed file `from` the name `to`, which differs from it only by case, renaming each
323
+ * folder on the way whose case changed too. `done` holds the case-folded paths already renamed.
324
+ */
325
+ async function renamePathByCase(fs, root, from, to, done) {
326
+ const fromParts = from.split('/');
327
+ const toParts = to.split('/');
328
+ for (let index = 0; index < toParts.length; index += 1) {
329
+ if (fromParts[index] === toParts[index]) {
330
+ continue;
331
+ }
332
+ const target = toParts.slice(0, index + 1).join('/');
333
+ if (done.has(target.toLowerCase())) {
334
+ continue;
335
+ }
336
+ const current = [...toParts.slice(0, index), fromParts[index]].join('/');
337
+ await renameByCase(fs, toAbsolute(root, current), toAbsolute(root, target));
338
+ done.add(target.toLowerCase());
339
+ }
340
+ }