@voxgig/sdkgen 4.34.1 → 4.34.2

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 (305) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/ReadmeErrors.js +3 -3
  3. package/dist/cmp/ReadmeErrors.js.map +1 -1
  4. package/dist/cmp/ReadmeExplanation.js +3 -3
  5. package/dist/cmp/ReadmeExplanation.js.map +1 -1
  6. package/dist/cmp/ReadmeQuick.js +3 -1
  7. package/dist/cmp/ReadmeQuick.js.map +1 -1
  8. package/dist/cmp/ReadmeTop.js +9 -8
  9. package/dist/cmp/ReadmeTop.js.map +1 -1
  10. package/dist/helpers/definitionPlan.js +8 -4
  11. package/dist/helpers/definitionPlan.js.map +1 -1
  12. package/dist/helpers/naming.d.ts +2 -1
  13. package/dist/helpers/naming.js +11 -4
  14. package/dist/helpers/naming.js.map +1 -1
  15. package/dist/helpers/opExample.d.ts +16 -2
  16. package/dist/helpers/opExample.js +80 -21
  17. package/dist/helpers/opExample.js.map +1 -1
  18. package/dist/helpers/opShape.d.ts +3 -1
  19. package/dist/helpers/opShape.js +21 -8
  20. package/dist/helpers/opShape.js.map +1 -1
  21. package/dist/sdkgen.d.ts +4 -4
  22. package/dist/sdkgen.js +12 -4
  23. package/dist/sdkgen.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/dist/utility.d.ts +2 -1
  26. package/dist/utility.js +29 -3
  27. package/dist/utility.js.map +1 -1
  28. package/package.json +2 -2
  29. package/project/.sdk/src/cmp/c/ReadmeEntity_c.ts +3 -2
  30. package/project/.sdk/src/cmp/c/ReadmeHowto_c.ts +7 -3
  31. package/project/.sdk/src/cmp/c/ReadmeQuick_c.ts +3 -2
  32. package/project/.sdk/src/cmp/c/ReadmeRef_c.ts +5 -4
  33. package/project/.sdk/src/cmp/c/ReadmeTopQuick_c.ts +3 -2
  34. package/project/.sdk/src/cmp/c/ReadmeTopTest_c.ts +8 -7
  35. package/project/.sdk/src/cmp/c/utility_c.ts +21 -2
  36. package/project/.sdk/src/cmp/clojure/ReadmeEntity_clojure.ts +4 -1
  37. package/project/.sdk/src/cmp/clojure/ReadmeHowto_clojure.ts +17 -6
  38. package/project/.sdk/src/cmp/clojure/ReadmeModel_clojure.ts +6 -6
  39. package/project/.sdk/src/cmp/clojure/ReadmeQuick_clojure.ts +13 -8
  40. package/project/.sdk/src/cmp/clojure/ReadmeRef_clojure.ts +21 -18
  41. package/project/.sdk/src/cmp/clojure/ReadmeTopQuick_clojure.ts +6 -3
  42. package/project/.sdk/src/cmp/clojure/ReadmeTopTest_clojure.ts +16 -9
  43. package/project/.sdk/src/cmp/clojure/TestClean_clojure.ts +4 -4
  44. package/project/.sdk/src/cmp/clojure/fragment/Entity.fragment.clj +2 -1
  45. package/project/.sdk/src/cmp/clojure/utility_clojure.ts +14 -0
  46. package/project/.sdk/src/cmp/cpp/ReadmeEntity_cpp.ts +3 -2
  47. package/project/.sdk/src/cmp/cpp/ReadmeHowto_cpp.ts +7 -3
  48. package/project/.sdk/src/cmp/cpp/ReadmeQuick_cpp.ts +3 -2
  49. package/project/.sdk/src/cmp/cpp/ReadmeRef_cpp.ts +6 -5
  50. package/project/.sdk/src/cmp/cpp/ReadmeTopQuick_cpp.ts +3 -2
  51. package/project/.sdk/src/cmp/cpp/ReadmeTopTest_cpp.ts +8 -7
  52. package/project/.sdk/src/cmp/cpp/utility_cpp.ts +13 -0
  53. package/project/.sdk/src/cmp/csharp/ReadmeEntity_csharp.ts +3 -2
  54. package/project/.sdk/src/cmp/csharp/ReadmeHowto_csharp.ts +20 -8
  55. package/project/.sdk/src/cmp/csharp/ReadmeQuick_csharp.ts +13 -8
  56. package/project/.sdk/src/cmp/csharp/ReadmeRef_csharp.ts +10 -5
  57. package/project/.sdk/src/cmp/csharp/ReadmeTopQuick_csharp.ts +14 -7
  58. package/project/.sdk/src/cmp/csharp/ReadmeTopTest_csharp.ts +18 -10
  59. package/project/.sdk/src/cmp/csharp/utility_csharp.ts +13 -0
  60. package/project/.sdk/src/cmp/elixir/ReadmeEntity_elixir.ts +4 -4
  61. package/project/.sdk/src/cmp/elixir/ReadmeExplanation_elixir.ts +2 -1
  62. package/project/.sdk/src/cmp/elixir/ReadmeHowto_elixir.ts +13 -6
  63. package/project/.sdk/src/cmp/elixir/ReadmeModel_elixir.ts +5 -5
  64. package/project/.sdk/src/cmp/elixir/ReadmeQuick_elixir.ts +13 -10
  65. package/project/.sdk/src/cmp/elixir/ReadmeRef_elixir.ts +11 -11
  66. package/project/.sdk/src/cmp/elixir/ReadmeTopQuick_elixir.ts +8 -6
  67. package/project/.sdk/src/cmp/elixir/ReadmeTopTest_elixir.ts +14 -10
  68. package/project/.sdk/src/cmp/elixir/fragment/EntityCreateOp.fragment.ex +4 -3
  69. package/project/.sdk/src/cmp/elixir/fragment/EntityListOp.fragment.ex +4 -3
  70. package/project/.sdk/src/cmp/elixir/fragment/EntityLoadOp.fragment.ex +4 -3
  71. package/project/.sdk/src/cmp/elixir/fragment/EntityPatchOp.fragment.ex +4 -3
  72. package/project/.sdk/src/cmp/elixir/fragment/EntityRemoveOp.fragment.ex +4 -3
  73. package/project/.sdk/src/cmp/elixir/fragment/EntityUpdateOp.fragment.ex +4 -3
  74. package/project/.sdk/src/cmp/elixir/utility_elixir.ts +12 -0
  75. package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +8 -5
  76. package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +3 -1
  77. package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +20 -8
  78. package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +16 -13
  79. package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +14 -13
  80. package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +14 -13
  81. package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +10 -8
  82. package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +6 -2
  83. package/project/.sdk/src/cmp/go/utility_go.ts +1 -1
  84. package/project/.sdk/src/cmp/java/ReadmeEntity_java.ts +8 -19
  85. package/project/.sdk/src/cmp/java/ReadmeHowto_java.ts +19 -22
  86. package/project/.sdk/src/cmp/java/ReadmeModel_java.ts +10 -9
  87. package/project/.sdk/src/cmp/java/ReadmeQuick_java.ts +24 -28
  88. package/project/.sdk/src/cmp/java/ReadmeRef_java.ts +27 -35
  89. package/project/.sdk/src/cmp/java/ReadmeTopQuick_java.ts +22 -25
  90. package/project/.sdk/src/cmp/java/ReadmeTopTest_java.ts +18 -24
  91. package/project/.sdk/src/cmp/java/utility_java.ts +25 -0
  92. package/project/.sdk/src/cmp/js/EntityOperation_js.ts +3 -1
  93. package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +2 -8
  94. package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +11 -9
  95. package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +9 -9
  96. package/project/.sdk/src/cmp/js/ReadmeQuick_js.ts +7 -13
  97. package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +14 -15
  98. package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +16 -11
  99. package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +11 -7
  100. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +1 -1
  101. package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +1 -1
  102. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +1 -1
  103. package/project/.sdk/src/cmp/js/fragment/EntityPatchOp.fragment.js +1 -1
  104. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +1 -1
  105. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +1 -1
  106. package/project/.sdk/src/cmp/js/utility_js.ts +2 -1
  107. package/project/.sdk/src/cmp/kotlin/ReadmeEntity_kotlin.ts +3 -2
  108. package/project/.sdk/src/cmp/kotlin/ReadmeHowto_kotlin.ts +19 -9
  109. package/project/.sdk/src/cmp/kotlin/ReadmeModel_kotlin.ts +10 -9
  110. package/project/.sdk/src/cmp/kotlin/ReadmeQuick_kotlin.ts +14 -9
  111. package/project/.sdk/src/cmp/kotlin/ReadmeRef_kotlin.ts +18 -15
  112. package/project/.sdk/src/cmp/kotlin/ReadmeTopQuick_kotlin.ts +14 -8
  113. package/project/.sdk/src/cmp/kotlin/ReadmeTopTest_kotlin.ts +17 -10
  114. package/project/.sdk/src/cmp/kotlin/utility_kotlin.ts +21 -1
  115. package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +3 -2
  116. package/project/.sdk/src/cmp/lua/ReadmeExamplesTest_lua.ts +7 -4
  117. package/project/.sdk/src/cmp/lua/ReadmeHowto_lua.ts +9 -7
  118. package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +13 -13
  119. package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +20 -9
  120. package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +9 -8
  121. package/project/.sdk/src/cmp/lua/ReadmeTopQuick_lua.ts +15 -7
  122. package/project/.sdk/src/cmp/lua/ReadmeTopTest_lua.ts +6 -5
  123. package/project/.sdk/src/cmp/lua/fragment/Entity.fragment.lua +1 -0
  124. package/project/.sdk/src/cmp/lua/fragment/EntityCreateOp.fragment.lua +1 -1
  125. package/project/.sdk/src/cmp/lua/fragment/EntityListOp.fragment.lua +1 -1
  126. package/project/.sdk/src/cmp/lua/fragment/EntityLoadOp.fragment.lua +1 -1
  127. package/project/.sdk/src/cmp/lua/fragment/EntityPatchOp.fragment.lua +1 -1
  128. package/project/.sdk/src/cmp/lua/fragment/EntityRemoveOp.fragment.lua +1 -1
  129. package/project/.sdk/src/cmp/lua/fragment/EntityUpdateOp.fragment.lua +1 -1
  130. package/project/.sdk/src/cmp/ocaml/ReadmeEntity_ocaml.ts +3 -2
  131. package/project/.sdk/src/cmp/ocaml/ReadmeHowto_ocaml.ts +3 -2
  132. package/project/.sdk/src/cmp/ocaml/ReadmeModel_ocaml.ts +1 -0
  133. package/project/.sdk/src/cmp/ocaml/ReadmeQuick_ocaml.ts +5 -3
  134. package/project/.sdk/src/cmp/ocaml/ReadmeRef_ocaml.ts +10 -8
  135. package/project/.sdk/src/cmp/ocaml/ReadmeTopQuick_ocaml.ts +4 -2
  136. package/project/.sdk/src/cmp/ocaml/ReadmeTopTest_ocaml.ts +3 -2
  137. package/project/.sdk/src/cmp/ocaml/utility_ocaml.ts +13 -1
  138. package/project/.sdk/src/cmp/perl/ReadmeEntity_perl.ts +4 -1
  139. package/project/.sdk/src/cmp/perl/ReadmeHowto_perl.ts +10 -5
  140. package/project/.sdk/src/cmp/perl/ReadmeModel_perl.ts +6 -6
  141. package/project/.sdk/src/cmp/perl/ReadmeQuick_perl.ts +8 -5
  142. package/project/.sdk/src/cmp/perl/ReadmeRef_perl.ts +21 -18
  143. package/project/.sdk/src/cmp/perl/ReadmeTopQuick_perl.ts +6 -3
  144. package/project/.sdk/src/cmp/perl/ReadmeTopTest_perl.ts +11 -8
  145. package/project/.sdk/src/cmp/perl/fragment/Entity.fragment.pm +1 -1
  146. package/project/.sdk/src/cmp/perl/fragment/EntityCreateOp.fragment.pm +2 -2
  147. package/project/.sdk/src/cmp/perl/fragment/EntityLoadOp.fragment.pm +2 -2
  148. package/project/.sdk/src/cmp/perl/fragment/EntityPatchOp.fragment.pm +2 -2
  149. package/project/.sdk/src/cmp/perl/fragment/EntityRemoveOp.fragment.pm +1 -1
  150. package/project/.sdk/src/cmp/perl/fragment/EntityUpdateOp.fragment.pm +2 -2
  151. package/project/.sdk/src/cmp/perl/utility_perl.ts +11 -1
  152. package/project/.sdk/src/cmp/php/EntityOperation_php.ts +3 -1
  153. package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +4 -3
  154. package/project/.sdk/src/cmp/php/ReadmeHowto_php.ts +12 -6
  155. package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +9 -9
  156. package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +3 -2
  157. package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +15 -14
  158. package/project/.sdk/src/cmp/php/ReadmeTopQuick_php.ts +5 -4
  159. package/project/.sdk/src/cmp/php/ReadmeTopTest_php.ts +13 -7
  160. package/project/.sdk/src/cmp/php/fragment/EntityCreateOp.fragment.php +2 -2
  161. package/project/.sdk/src/cmp/php/fragment/EntityListOp.fragment.php +2 -2
  162. package/project/.sdk/src/cmp/php/fragment/EntityLoadOp.fragment.php +2 -2
  163. package/project/.sdk/src/cmp/php/fragment/EntityPatchOp.fragment.php +2 -2
  164. package/project/.sdk/src/cmp/php/fragment/EntityRemoveOp.fragment.php +2 -2
  165. package/project/.sdk/src/cmp/php/fragment/EntityUpdateOp.fragment.php +2 -2
  166. package/project/.sdk/src/cmp/py/EntityOperation_py.ts +3 -1
  167. package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +3 -8
  168. package/project/.sdk/src/cmp/py/ReadmeHowto_py.ts +9 -9
  169. package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +9 -9
  170. package/project/.sdk/src/cmp/py/ReadmeQuick_py.ts +9 -14
  171. package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +23 -30
  172. package/project/.sdk/src/cmp/py/ReadmeTopQuick_py.ts +7 -12
  173. package/project/.sdk/src/cmp/py/ReadmeTopTest_py.ts +8 -7
  174. package/project/.sdk/src/cmp/py/fragment/EntityCreateOp.fragment.py +1 -1
  175. package/project/.sdk/src/cmp/py/fragment/EntityListOp.fragment.py +1 -1
  176. package/project/.sdk/src/cmp/py/fragment/EntityLoadOp.fragment.py +1 -1
  177. package/project/.sdk/src/cmp/py/fragment/EntityPatchOp.fragment.py +1 -1
  178. package/project/.sdk/src/cmp/py/fragment/EntityRemoveOp.fragment.py +1 -1
  179. package/project/.sdk/src/cmp/py/fragment/EntityUpdateOp.fragment.py +1 -1
  180. package/project/.sdk/src/cmp/rb/EntityOperation_rb.ts +3 -1
  181. package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +2 -1
  182. package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +4 -1
  183. package/project/.sdk/src/cmp/rb/ReadmeExamplesTest_rb.ts +3 -2
  184. package/project/.sdk/src/cmp/rb/ReadmeHowto_rb.ts +20 -10
  185. package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +10 -9
  186. package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +6 -3
  187. package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +14 -11
  188. package/project/.sdk/src/cmp/rb/ReadmeTopQuick_rb.ts +6 -3
  189. package/project/.sdk/src/cmp/rb/ReadmeTopTest_rb.ts +14 -10
  190. package/project/.sdk/src/cmp/rb/fragment/EntityCreateOp.fragment.rb +2 -1
  191. package/project/.sdk/src/cmp/rb/fragment/EntityListOp.fragment.rb +1 -1
  192. package/project/.sdk/src/cmp/rb/fragment/EntityLoadOp.fragment.rb +2 -1
  193. package/project/.sdk/src/cmp/rb/fragment/EntityPatchOp.fragment.rb +2 -1
  194. package/project/.sdk/src/cmp/rb/fragment/EntityRemoveOp.fragment.rb +2 -1
  195. package/project/.sdk/src/cmp/rb/fragment/EntityUpdateOp.fragment.rb +2 -1
  196. package/project/.sdk/src/cmp/rb/utility_rb.ts +10 -0
  197. package/project/.sdk/src/cmp/rust/ReadmeEntity_rust.ts +3 -2
  198. package/project/.sdk/src/cmp/rust/ReadmeHowto_rust.ts +6 -2
  199. package/project/.sdk/src/cmp/rust/ReadmeQuick_rust.ts +3 -2
  200. package/project/.sdk/src/cmp/rust/ReadmeRef_rust.ts +5 -4
  201. package/project/.sdk/src/cmp/rust/ReadmeTopQuick_rust.ts +3 -2
  202. package/project/.sdk/src/cmp/rust/ReadmeTopTest_rust.ts +7 -6
  203. package/project/.sdk/src/cmp/rust/utility_rust.ts +13 -1
  204. package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +5 -2
  205. package/project/.sdk/src/cmp/scala/ReadmeEntity_scala.ts +8 -19
  206. package/project/.sdk/src/cmp/scala/ReadmeHowto_scala.ts +17 -22
  207. package/project/.sdk/src/cmp/scala/ReadmeModel_scala.ts +10 -9
  208. package/project/.sdk/src/cmp/scala/ReadmeQuick_scala.ts +18 -28
  209. package/project/.sdk/src/cmp/scala/ReadmeRef_scala.ts +25 -35
  210. package/project/.sdk/src/cmp/scala/ReadmeTopQuick_scala.ts +14 -25
  211. package/project/.sdk/src/cmp/scala/ReadmeTopTest_scala.ts +16 -24
  212. package/project/.sdk/src/cmp/scala/utility_scala.ts +25 -0
  213. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +1 -1
  214. package/project/.sdk/src/cmp/swift/ReadmeEntity_swift.ts +3 -2
  215. package/project/.sdk/src/cmp/swift/ReadmeHowto_swift.ts +22 -8
  216. package/project/.sdk/src/cmp/swift/ReadmeModel_swift.ts +10 -9
  217. package/project/.sdk/src/cmp/swift/ReadmeQuick_swift.ts +16 -8
  218. package/project/.sdk/src/cmp/swift/ReadmeRef_swift.ts +20 -15
  219. package/project/.sdk/src/cmp/swift/ReadmeTopQuick_swift.ts +12 -7
  220. package/project/.sdk/src/cmp/swift/ReadmeTopTest_swift.ts +21 -10
  221. package/project/.sdk/src/cmp/swift/utility_swift.ts +14 -1
  222. package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +2 -8
  223. package/project/.sdk/src/cmp/ts/ReadmeHowto_ts.ts +11 -9
  224. package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +9 -9
  225. package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +7 -13
  226. package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +14 -23
  227. package/project/.sdk/src/cmp/ts/ReadmeTopQuick_ts.ts +8 -14
  228. package/project/.sdk/src/cmp/ts/ReadmeTopTest_ts.ts +29 -14
  229. package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +1 -1
  230. package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +1 -1
  231. package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +1 -1
  232. package/project/.sdk/src/cmp/ts/fragment/EntityPatchOp.fragment.ts +1 -1
  233. package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +1 -1
  234. package/project/.sdk/src/cmp/ts/utility_ts.ts +2 -1
  235. package/project/.sdk/src/cmp/zig/ReadmeEntity_zig.ts +3 -2
  236. package/project/.sdk/src/cmp/zig/ReadmeHowto_zig.ts +6 -2
  237. package/project/.sdk/src/cmp/zig/ReadmeQuick_zig.ts +4 -3
  238. package/project/.sdk/src/cmp/zig/ReadmeRef_zig.ts +5 -4
  239. package/project/.sdk/src/cmp/zig/ReadmeTopQuick_zig.ts +3 -2
  240. package/project/.sdk/src/cmp/zig/ReadmeTopTest_zig.ts +7 -6
  241. package/project/.sdk/src/cmp/zig/utility_zig.ts +13 -0
  242. package/project/.sdk/tm/c/utility/transform_request.c +1 -1
  243. package/project/.sdk/tm/clojure/src/sdk/core.clj +32 -26
  244. package/project/.sdk/tm/clojure/test/sdk/test/concurrency.clj +136 -0
  245. package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +3 -1
  246. package/project/.sdk/tm/cpp/core/types.hpp +36 -6
  247. package/project/.sdk/tm/cpp/test/concurrency_test.cpp +348 -0
  248. package/project/.sdk/tm/cpp/utility/pipeline.hpp +42 -25
  249. package/project/.sdk/tm/csharp/core/Context.cs +8 -5
  250. package/project/.sdk/tm/csharp/test/ConcurrencyTest.cs +238 -0
  251. package/project/.sdk/tm/csharp/utility/Clean.cs +12 -10
  252. package/project/.sdk/tm/csharp/utility/TransformRequest.cs +1 -1
  253. package/project/.sdk/tm/elixir/lib/projectname/context.ex +3 -0
  254. package/project/.sdk/tm/elixir/lib/projectname/entity_base.ex +2 -1
  255. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +31 -10
  256. package/project/.sdk/tm/elixir/test/concurrency_test.exs +176 -0
  257. package/project/.sdk/tm/go/core/context.go +5 -1
  258. package/project/.sdk/tm/go/test/concurrency_test.go +214 -0
  259. package/project/.sdk/tm/go/utility/transform_request.go +1 -1
  260. package/project/.sdk/tm/java/core/Context.java +6 -3
  261. package/project/.sdk/tm/java/test/ConcurrencyTest.java +221 -0
  262. package/project/.sdk/tm/java/utility/Clean.java +22 -17
  263. package/project/.sdk/tm/java/utility/TransformRequest.java +1 -1
  264. package/project/.sdk/tm/js/src/utility/TransformRequestUtility.js +1 -1
  265. package/project/.sdk/tm/kotlin/core/Context.kt +5 -3
  266. package/project/.sdk/tm/kotlin/test/ConcurrencyTest.kt +193 -0
  267. package/project/.sdk/tm/kotlin/utility/ResultTransform.kt +1 -1
  268. package/project/.sdk/tm/lua/utility/transform_request.lua +1 -1
  269. package/project/.sdk/tm/ocaml/Makefile +21 -8
  270. package/project/.sdk/tm/ocaml/sdk_runtime.ml +27 -12
  271. package/project/.sdk/tm/ocaml/sdk_types.ml +6 -2
  272. package/project/.sdk/tm/ocaml/test/concurrency_test.ml +148 -0
  273. package/project/.sdk/tm/perl/utility/transform_request.pm +1 -1
  274. package/project/.sdk/tm/php/feature/TestFeature.php +9 -9
  275. package/project/.sdk/tm/php/utility/TransformRequest.php +1 -1
  276. package/project/.sdk/tm/py/pkg/core/context.py +2 -2
  277. package/project/.sdk/tm/py/pkg/utility/clean.py +12 -8
  278. package/project/.sdk/tm/py/pkg/utility/transform_request.py +1 -1
  279. package/project/.sdk/tm/py/test/test_concurrency.py +177 -0
  280. package/project/.sdk/tm/rb/core/context.rb +8 -3
  281. package/project/.sdk/tm/rb/test/concurrency_test.rb +160 -0
  282. package/project/.sdk/tm/rb/utility/clean.rb +8 -7
  283. package/project/.sdk/tm/rb/utility/transform_request.rb +1 -1
  284. package/project/.sdk/tm/rust/utility/transform_request.rs +1 -1
  285. package/project/.sdk/tm/scala/Makefile +2 -0
  286. package/project/.sdk/tm/scala/core/Context.scala +6 -4
  287. package/project/.sdk/tm/scala/sdktest/ConcurrencyTest.scala +186 -0
  288. package/project/.sdk/tm/scala/utility/Transform.scala +1 -1
  289. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +2 -0
  290. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +35 -12
  291. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/ConcurrencyTest.swift +214 -0
  292. package/project/.sdk/tm/ts/src/utility/TransformRequestUtility.ts +1 -1
  293. package/project/.sdk/tm/zig/core/utility.zig +1 -1
  294. package/project/.sdk/tm/zig/feature/test.zig +10 -8
  295. package/project/sdkgen-package.json +1 -1
  296. package/src/cmp/ReadmeErrors.ts +5 -5
  297. package/src/cmp/ReadmeExplanation.ts +4 -5
  298. package/src/cmp/ReadmeQuick.ts +3 -1
  299. package/src/cmp/ReadmeTop.ts +10 -12
  300. package/src/helpers/definitionPlan.ts +8 -4
  301. package/src/helpers/naming.ts +12 -4
  302. package/src/helpers/opExample.ts +97 -25
  303. package/src/helpers/opShape.ts +25 -9
  304. package/src/sdkgen.ts +14 -3
  305. package/src/utility.ts +31 -4
@@ -0,0 +1,214 @@
1
+ package sdktest
2
+
3
+ import (
4
+ "fmt"
5
+ "sync"
6
+ "testing"
7
+
8
+ sdk "GOMODULE"
9
+ )
10
+
11
+ // Requests in flight at once on one client. Each resolves its operation
12
+ // through the cache the client's root context shares with every request, and
13
+ // registers and cleans secrets through the one registry the client holds.
14
+
15
+ const concurrencyRounds = 200
16
+ const concurrencyWidth = 8
17
+ const concurrencyOps = 32
18
+
19
+ // concurrencyClient is a live client whose transport answers at once.
20
+ func concurrencyClient() *sdk.ProjectNameSDK {
21
+ return sdk.NewProjectNameSDK(map[string]any{
22
+ "base": "http://concurrency.test/api",
23
+ "allow": map[string]any{"op": "direct"},
24
+ "system": map[string]any{
25
+ "fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
26
+ return map[string]any{
27
+ "status": 200,
28
+ "statusText": "OK",
29
+ "headers": map[string]any{},
30
+ "json": func() any { return map[string]any{"ok": true} },
31
+ }, nil
32
+ },
33
+ },
34
+ })
35
+ }
36
+
37
+ // atOnce runs body on concurrencyWidth goroutines released together.
38
+ func atOnce(body func(n int)) {
39
+ var ready, done sync.WaitGroup
40
+ start := make(chan struct{})
41
+ ready.Add(concurrencyWidth)
42
+ done.Add(concurrencyWidth)
43
+ for i := 0; i < concurrencyWidth; i++ {
44
+ go func(n int) {
45
+ defer done.Done()
46
+ ready.Done()
47
+ <-start
48
+ body(n)
49
+ }(i)
50
+ }
51
+ ready.Wait()
52
+ close(start)
53
+ done.Wait()
54
+ }
55
+
56
+ func TestConcurrentFirstRequests(t *testing.T) {
57
+ for round := 0; round < concurrencyRounds; round++ {
58
+ // A fresh client each round, so every request in it is a first request.
59
+ client := concurrencyClient()
60
+ results := make([]map[string]any, concurrencyWidth)
61
+ errs := make([]error, concurrencyWidth)
62
+ atOnce(func(n int) {
63
+ results[n], errs[n] = client.Direct(map[string]any{"path": fmt.Sprintf("p%d", n)})
64
+ })
65
+ for n := range results {
66
+ if errs[n] != nil || results[n]["ok"] != true {
67
+ t.Fatalf("round %d, request %d failed: %v %v", round, n, errs[n], results[n])
68
+ }
69
+ }
70
+ }
71
+ }
72
+
73
+ func TestConcurrentOperationResolution(t *testing.T) {
74
+ for round := 0; round < concurrencyRounds; round++ {
75
+ client := concurrencyClient()
76
+ utility := client.GetUtility()
77
+ root := client.GetRootCtx()
78
+ ops := make([][]*sdk.Operation, concurrencyWidth)
79
+ atOnce(func(n int) {
80
+ ops[n] = make([]*sdk.Operation, concurrencyOps)
81
+ for k := range ops[n] {
82
+ ops[n][k] = utility.MakeContext(map[string]any{"opname": fmt.Sprintf("op%d", k)}, root).Op
83
+ }
84
+ })
85
+ for k := 0; k < concurrencyOps; k++ {
86
+ cached := utility.MakeContext(map[string]any{"opname": fmt.Sprintf("op%d", k)}, root).Op
87
+ for n := range ops {
88
+ if ops[n][k] != cached {
89
+ t.Fatalf("round %d: op%d resolved to more than one Operation", round, k)
90
+ }
91
+ }
92
+ }
93
+ }
94
+ }
95
+
96
+ func addedSecret(round, n, k int) string {
97
+ return fmt.Sprintf("ADDED-SECRET-%d-%d-%d", round, n, k)
98
+ }
99
+
100
+ // registerSecrets registers goroutine n's secrets.
101
+ func registerSecrets(utility *sdk.Utility, root *sdk.Context, round, n int) {
102
+ for k := 0; k < concurrencyOps; k++ {
103
+ utility.CleanAdd(root, addedSecret(round, n, k))
104
+ }
105
+ }
106
+
107
+ // unmaskedSecret is the first secret registered in the round that a clean
108
+ // leaves raw, or "".
109
+ func unmaskedSecret(utility *sdk.Utility, root *sdk.Context, round int) string {
110
+ for n := 0; n < concurrencyWidth/2; n++ {
111
+ for k := 0; k < concurrencyOps; k++ {
112
+ added := addedSecret(round, n, k)
113
+ if got := utility.Clean(root, added); got != "[redacted]" {
114
+ return added
115
+ }
116
+ }
117
+ }
118
+ return ""
119
+ }
120
+
121
+ // whileRegistering has half the goroutines register their secrets, and the
122
+ // rest run body until those are done or body returns false.
123
+ func whileRegistering(utility *sdk.Utility, root *sdk.Context, round int, body func(n int) bool) {
124
+ var registering sync.WaitGroup
125
+ registering.Add(concurrencyWidth / 2)
126
+ registered := make(chan struct{})
127
+ go func() {
128
+ registering.Wait()
129
+ close(registered)
130
+ }()
131
+ atOnce(func(n int) {
132
+ if n < concurrencyWidth/2 {
133
+ defer registering.Done()
134
+ registerSecrets(utility, root, round, n)
135
+ return
136
+ }
137
+ for {
138
+ select {
139
+ case <-registered:
140
+ return
141
+ default:
142
+ }
143
+ if !body(n) {
144
+ return
145
+ }
146
+ }
147
+ })
148
+ }
149
+
150
+ // Secrets registered on some goroutines while others clean: every clean masks
151
+ // what was registered before it, the longer secret whole, and no registration
152
+ // is lost.
153
+ func TestConcurrentCleanRegistry(t *testing.T) {
154
+ const masked = "a [redacted] b [redacted] c"
155
+ for round := 0; round < concurrencyRounds/4; round++ {
156
+ client := concurrencyClient()
157
+ utility := client.GetUtility()
158
+ root := client.GetRootCtx()
159
+ inner := fmt.Sprintf("INNER-SECRET-%d", round)
160
+ utility.CleanAdd(root, inner)
161
+ utility.CleanAdd(root, "OUTER-"+inner+"-TAIL")
162
+ text := "a " + inner + " b OUTER-" + inner + "-TAIL c"
163
+ if got := utility.Clean(root, text); got != masked {
164
+ t.Fatalf("round %d cleaned to: %v", round, got)
165
+ }
166
+
167
+ wrong := make([]any, concurrencyWidth)
168
+ whileRegistering(utility, root, round, func(n int) bool {
169
+ if got := utility.Clean(root, text); got != masked {
170
+ wrong[n] = got
171
+ return false
172
+ }
173
+ return true
174
+ })
175
+
176
+ for n, got := range wrong {
177
+ if got != nil {
178
+ t.Fatalf("round %d, cleaner %d cleaned to: %v", round, n, got)
179
+ }
180
+ }
181
+ if raw := unmaskedSecret(utility, root, round); raw != "" {
182
+ t.Fatalf("round %d: %s was registered but not masked", round, raw)
183
+ }
184
+ }
185
+ }
186
+
187
+ // Requests on one client while secrets register on it: each request copies
188
+ // the client's options, the registry among them.
189
+ func TestConcurrentRequestsWhileRegistering(t *testing.T) {
190
+ for round := 0; round < concurrencyRounds/4; round++ {
191
+ client := concurrencyClient()
192
+ utility := client.GetUtility()
193
+ root := client.GetRootCtx()
194
+
195
+ failed := make([]any, concurrencyWidth)
196
+ whileRegistering(utility, root, round, func(n int) bool {
197
+ res, err := client.Direct(map[string]any{"path": fmt.Sprintf("p%d", n)})
198
+ if err != nil || res["ok"] != true {
199
+ failed[n] = fmt.Sprint(err, res)
200
+ return false
201
+ }
202
+ return true
203
+ })
204
+
205
+ for n, got := range failed {
206
+ if got != nil {
207
+ t.Fatalf("round %d, request %d failed: %v", round, n, got)
208
+ }
209
+ }
210
+ if raw := unmaskedSecret(utility, root, round); raw != "" {
211
+ t.Fatalf("round %d: %s was registered but not masked", round, raw)
212
+ }
213
+ }
214
+ }
@@ -49,7 +49,7 @@ func stripAction(reqdata any) any {
49
49
 
50
50
  // A header, cookie or query argument travels where prepareHeadersUtil or
51
51
  // prepareQueryUtil sends it, so the body is built from the request data
52
- // without it, unless the entity declares it as a field too.
52
+ // without it, unless the point marks it as a field the body keeps.
53
53
  func routedArgNames(ctx *core.Context) []string {
54
54
  names := []string{}
55
55
  for _, arg := range append(append(callArgs(ctx, "header"), callArgs(ctx, "cookie")...), callArgs(ctx, "query")...) {
@@ -4,6 +4,7 @@ import java.util.ArrayList;
4
4
  import java.util.LinkedHashMap;
5
5
  import java.util.List;
6
6
  import java.util.Map;
7
+ import java.util.concurrent.ConcurrentHashMap;
7
8
  import java.util.concurrent.ThreadLocalRandom;
8
9
 
9
10
  import JAVAPACKAGE.utility.struct.Struct;
@@ -151,7 +152,7 @@ public class Context {
151
152
  this.opmap = basectx.opmap;
152
153
  }
153
154
  if (this.opmap == null) {
154
- this.opmap = new LinkedHashMap<>();
155
+ this.opmap = new ConcurrentHashMap<>();
155
156
  }
156
157
 
157
158
  // Data
@@ -260,8 +261,10 @@ public class Context {
260
261
 
261
262
  Operation op = new Operation(opdef);
262
263
 
263
- this.opmap.put(cacheKey, op);
264
- return op;
264
+ // Requests on other threads share this cache; every one of them gets
265
+ // the Operation stored first.
266
+ Operation stored = this.opmap.putIfAbsent(cacheKey, op);
267
+ return null == stored ? op : stored;
265
268
  }
266
269
 
267
270
  public SdkError makeError(String code, String msg) {
@@ -0,0 +1,221 @@
1
+ package JAVAPACKAGE.sdktest;
2
+
3
+ // Requests in flight at once on one client. Each resolves its operation
4
+ // through the cache the client's root context shares with every request, and
5
+ // registers and cleans secrets through the one registry the client holds.
6
+
7
+ import static org.junit.jupiter.api.Assertions.assertEquals;
8
+ import static org.junit.jupiter.api.Assertions.assertSame;
9
+ import static org.junit.jupiter.api.Assertions.assertTrue;
10
+
11
+ import java.util.ArrayList;
12
+ import java.util.LinkedHashMap;
13
+ import java.util.List;
14
+ import java.util.Map;
15
+ import java.util.concurrent.ConcurrentLinkedQueue;
16
+ import java.util.concurrent.CountDownLatch;
17
+ import java.util.concurrent.CyclicBarrier;
18
+ import java.util.function.BiFunction;
19
+ import java.util.function.IntConsumer;
20
+ import java.util.function.Supplier;
21
+
22
+ import org.junit.jupiter.api.Test;
23
+
24
+ import JAVAPACKAGE.core.Context;
25
+ import JAVAPACKAGE.core.Operation;
26
+ import JAVAPACKAGE.core.ProjectNameSDK;
27
+ import JAVAPACKAGE.core.Utility;
28
+
29
+ public class ConcurrencyTest {
30
+
31
+ static final int ROUNDS = 200;
32
+ static final int WIDTH = 8;
33
+ static final int OPS = 32;
34
+
35
+ static Map<String, Object> map(Object... kv) {
36
+ Map<String, Object> out = new LinkedHashMap<>();
37
+ for (int i = 0; i + 1 < kv.length; i += 2) {
38
+ out.put((String) kv[i], kv[i + 1]);
39
+ }
40
+ return out;
41
+ }
42
+
43
+ // A live client whose transport answers at once.
44
+ static ProjectNameSDK liveClient() {
45
+ BiFunction<String, Map<String, Object>, Map<String, Object>> fetch =
46
+ (url, fetchdef) -> map(
47
+ "status", 200,
48
+ "statusText", "OK",
49
+ "headers", new LinkedHashMap<String, Object>(),
50
+ "json", (Supplier<Object>) () -> map("ok", true));
51
+ return new ProjectNameSDK(map(
52
+ "base", "http://concurrency.test/api",
53
+ "allow", map("op", "direct"),
54
+ "system", map("fetch", fetch)));
55
+ }
56
+
57
+ // Runs body on WIDTH threads released together, and returns what they threw.
58
+ static List<Throwable> atOnce(IntConsumer body) throws InterruptedException {
59
+ CyclicBarrier start = new CyclicBarrier(WIDTH);
60
+ ConcurrentLinkedQueue<Throwable> thrown = new ConcurrentLinkedQueue<>();
61
+ List<Thread> threads = new ArrayList<>();
62
+ for (int i = 0; i < WIDTH; i++) {
63
+ final int n = i;
64
+ Thread thread = new Thread(() -> {
65
+ try {
66
+ start.await();
67
+ body.accept(n);
68
+ }
69
+ catch (Throwable t) {
70
+ thrown.add(t);
71
+ }
72
+ });
73
+ thread.start();
74
+ threads.add(thread);
75
+ }
76
+ for (Thread thread : threads) {
77
+ thread.join();
78
+ }
79
+ return new ArrayList<>(thrown);
80
+ }
81
+
82
+ @Test
83
+ public void concurrentFirstRequestsSucceed() throws InterruptedException {
84
+ for (int round = 0; round < ROUNDS; round++) {
85
+ // A fresh client each round, so every request in it is a first request.
86
+ ProjectNameSDK client = liveClient();
87
+ List<Map<String, Object>> results = new ArrayList<>();
88
+ for (int n = 0; n < WIDTH; n++) {
89
+ results.add(null);
90
+ }
91
+ List<Throwable> thrown = atOnce(n -> results.set(n, client.direct(map("path", "p" + n))));
92
+
93
+ assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
94
+ for (int n = 0; n < WIDTH; n++) {
95
+ Map<String, Object> res = results.get(n);
96
+ assertEquals(true, null == res ? null : res.get("ok"),
97
+ "round " + round + ", request " + n + " failed: " + res);
98
+ }
99
+ }
100
+ }
101
+
102
+ @Test
103
+ public void concurrentResolutionsShareOneCachedOperation() throws InterruptedException {
104
+ for (int round = 0; round < ROUNDS; round++) {
105
+ ProjectNameSDK client = liveClient();
106
+ Utility utility = client.getUtility();
107
+ Context root = client.getRootCtx();
108
+ Operation[][] ops = new Operation[WIDTH][OPS];
109
+ List<Throwable> thrown = atOnce(n -> {
110
+ for (int k = 0; k < OPS; k++) {
111
+ ops[n][k] = utility.makeContext.apply(map("opname", "op" + k), root).op;
112
+ }
113
+ });
114
+
115
+ assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
116
+ for (int k = 0; k < OPS; k++) {
117
+ Operation cached = utility.makeContext.apply(map("opname", "op" + k), root).op;
118
+ for (int n = 0; n < WIDTH; n++) {
119
+ assertSame(cached, ops[n][k],
120
+ "round " + round + ": op" + k + " resolved to more than one Operation");
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ static String addedSecret(int round, int n, int k) {
127
+ return "ADDED-SECRET-" + round + "-" + n + "-" + k;
128
+ }
129
+
130
+ // Registers thread n's secrets, then counts the thread out of registering.
131
+ static void registerSecrets(Utility utility, Context root, int round, int n,
132
+ CountDownLatch registering) {
133
+ try {
134
+ for (int k = 0; k < OPS; k++) {
135
+ utility.cleanAdd.apply(root, addedSecret(round, n, k));
136
+ }
137
+ }
138
+ finally {
139
+ registering.countDown();
140
+ }
141
+ }
142
+
143
+ static void assertEverySecretMasked(Utility utility, Context root, int round) {
144
+ for (int n = 0; n < WIDTH / 2; n++) {
145
+ for (int k = 0; k < OPS; k++) {
146
+ String added = addedSecret(round, n, k);
147
+ assertEquals("[redacted]", utility.clean.apply(root, added),
148
+ "round " + round + ": " + added + " was registered but not masked");
149
+ }
150
+ }
151
+ }
152
+
153
+ // Secrets registered on some threads while others clean: every clean masks
154
+ // what was registered before it, the longer secret whole, and no
155
+ // registration is lost.
156
+ @Test
157
+ public void concurrentRegistrationKeepsEverySecretMasked() throws InterruptedException {
158
+ for (int round = 0; round < ROUNDS / 4; round++) {
159
+ final int r = round;
160
+ ProjectNameSDK client = liveClient();
161
+ Utility utility = client.getUtility();
162
+ Context root = client.getRootCtx();
163
+ String inner = "INNER-SECRET-" + round;
164
+ utility.cleanAdd.apply(root, inner);
165
+ utility.cleanAdd.apply(root, "OUTER-" + inner + "-TAIL");
166
+ String text = "a " + inner + " b OUTER-" + inner + "-TAIL c";
167
+ String masked = "a [redacted] b [redacted] c";
168
+ assertEquals(masked, utility.clean.apply(root, text));
169
+
170
+ CountDownLatch registering = new CountDownLatch(WIDTH / 2);
171
+ ConcurrentLinkedQueue<Object> wrong = new ConcurrentLinkedQueue<>();
172
+ List<Throwable> thrown = atOnce(n -> {
173
+ if (n < WIDTH / 2) {
174
+ registerSecrets(utility, root, r, n, registering);
175
+ return;
176
+ }
177
+ while (0 < registering.getCount()) {
178
+ Object got = utility.clean.apply(root, text);
179
+ if (!masked.equals(got)) {
180
+ wrong.add(String.valueOf(got));
181
+ }
182
+ }
183
+ });
184
+
185
+ assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
186
+ assertTrue(wrong.isEmpty(), "round " + round + " cleaned to: " + wrong);
187
+ assertEverySecretMasked(utility, root, round);
188
+ }
189
+ }
190
+
191
+ // Requests on one client while secrets register on it: each request copies
192
+ // the client's options, the registry among them.
193
+ @Test
194
+ public void concurrentRequestsSurviveRegistration() throws InterruptedException {
195
+ for (int round = 0; round < ROUNDS / 4; round++) {
196
+ final int r = round;
197
+ ProjectNameSDK client = liveClient();
198
+ Utility utility = client.getUtility();
199
+ Context root = client.getRootCtx();
200
+ CountDownLatch registering = new CountDownLatch(WIDTH / 2);
201
+ ConcurrentLinkedQueue<Object> failed = new ConcurrentLinkedQueue<>();
202
+ List<Throwable> thrown = atOnce(n -> {
203
+ if (n < WIDTH / 2) {
204
+ registerSecrets(utility, root, r, n, registering);
205
+ return;
206
+ }
207
+ while (0 < registering.getCount()) {
208
+ Map<String, Object> res = client.direct(map("path", "p" + n));
209
+ if (!Boolean.TRUE.equals(res.get("ok"))) {
210
+ failed.add(String.valueOf(res));
211
+ return;
212
+ }
213
+ }
214
+ });
215
+
216
+ assertTrue(thrown.isEmpty(), "round " + round + " threw: " + thrown);
217
+ assertTrue(failed.isEmpty(), "round " + round + ", a request failed: " + failed);
218
+ assertEverySecretMasked(utility, root, round);
219
+ }
220
+ }
221
+ }
@@ -14,6 +14,7 @@ import java.util.LinkedHashMap;
14
14
  import java.util.List;
15
15
  import java.util.Locale;
16
16
  import java.util.Map;
17
+ import java.util.concurrent.ConcurrentHashMap;
17
18
  import java.util.function.BiFunction;
18
19
  import java.util.function.Consumer;
19
20
  import java.util.function.Function;
@@ -37,8 +38,8 @@ import JAVAPACKAGE.utility.struct.Struct;
37
38
  //
38
39
  // The configuration is the derived block MakeOptions builds
39
40
  // (`options.__derived__.clean`): active, keys, values, mask, hint, min. It
40
- // is a plain map so the registry stays MUTABLE after construction - the
41
- // auth step and the features register what they handle later.
41
+ // is a map so the registry can grow after construction - the auth step and
42
+ // the features register what they handle later.
42
43
  @SuppressWarnings({"unchecked"})
43
44
  final class Clean {
44
45
 
@@ -67,7 +68,9 @@ final class Clean {
67
68
 
68
69
  static Map<String, Object> makeCleanConfig(Map<String, Object> cleanopts) {
69
70
  Map<String, Object> opts = cleanopts == null ? new LinkedHashMap<>() : cleanopts;
70
- Map<String, Object> cfg = new LinkedHashMap<>();
71
+ // Read without the monitor add() holds, by a clean or a request copying
72
+ // the options: each read sees the list the last registration put.
73
+ Map<String, Object> cfg = new ConcurrentHashMap<>();
71
74
  cfg.put("active", !Boolean.FALSE.equals(opts.get("active")));
72
75
  cfg.put("keys", splitkeys(opts.get("keys")));
73
76
  cfg.put("values", new ArrayList<String>());
@@ -148,10 +151,8 @@ final class Clean {
148
151
  }
149
152
 
150
153
  private static List<String> values(Map<String, Object> cfg) {
151
- if (!(cfg.get("values") instanceof List)) {
152
- cfg.put("values", new ArrayList<String>());
153
- }
154
- return (List<String>) cfg.get("values");
154
+ Object values = cfg.get("values");
155
+ return values instanceof List ? (List<String>) values : List.of();
155
156
  }
156
157
 
157
158
  private static String mask(Map<String, Object> cfg) {
@@ -193,21 +194,25 @@ final class Clean {
193
194
  }
194
195
 
195
196
  // Register a secret value. Idempotent; shorter than `min` is not a secret
196
- // the SDK can mask without blanking ordinary text.
197
+ // the SDK can mask without blanking ordinary text. Requests on other
198
+ // threads clean while one registers, so a registration publishes a new
199
+ // list and never changes a published one.
197
200
  static void add(Map<String, Object> cfg, Object value) {
198
201
  if (!(value instanceof String) || ((String) value).length() < min(cfg)) {
199
202
  return;
200
203
  }
201
- List<String> values = values(cfg);
202
- boolean changed = false;
203
- for (String form : forms((String) value)) {
204
- if (form.length() >= min(cfg) && !values.contains(form)) {
205
- values.add(form);
206
- changed = true;
204
+ synchronized (cfg) {
205
+ List<String> values = new ArrayList<>(values(cfg));
206
+ int had = values.size();
207
+ for (String form : forms((String) value)) {
208
+ if (form.length() >= min(cfg) && !values.contains(form)) {
209
+ values.add(form);
210
+ }
211
+ }
212
+ if (had < values.size()) {
213
+ values.sort((a, b) -> b.length() - a.length());
214
+ cfg.put("values", List.copyOf(values));
207
215
  }
208
- }
209
- if (changed) {
210
- values.sort((a, b) -> b.length() - a.length());
211
216
  }
212
217
  }
213
218
 
@@ -45,7 +45,7 @@ final class TransformRequest {
45
45
 
46
46
  // A header, cookie or query argument travels where PrepareHeaders or
47
47
  // PrepareQuery sends it, so the body is built from the request data without
48
- // it, unless the entity declares it as a field too.
48
+ // it, unless the point marks it as a field the body keeps.
49
49
  private static List<String> routedArgNames(Context ctx) {
50
50
  List<String> names = new ArrayList<>();
51
51
  for (String kind : List.of("header", "cookie", "query")) {
@@ -50,7 +50,7 @@ function stripAction(reqdata) {
50
50
 
51
51
  // A header, cookie or query argument travels where prepareHeaders or
52
52
  // prepareQuery sends it, so the body is built from the request data without
53
- // it, unless the entity declares it as a field too.
53
+ // it, unless the point marks it as a field the body keeps.
54
54
  function routedArgNames(ctx) {
55
55
  return callArgs(ctx, 'header').concat(callArgs(ctx, 'cookie'), callArgs(ctx, 'query'))
56
56
  .map((arg) => arg.name)
@@ -1,5 +1,6 @@
1
1
  package KOTLINPACKAGE.core
2
2
 
3
+ import java.util.concurrent.ConcurrentHashMap
3
4
  import java.util.concurrent.ThreadLocalRandom
4
5
 
5
6
  import KOTLINPACKAGE.utility.struct.Struct
@@ -143,7 +144,7 @@ class Context(ctxmap: MutableMap<String, Any?>?, basectx: Context?) {
143
144
  this.opmap = basectx.opmap
144
145
  }
145
146
  if (this.opmap == null) {
146
- this.opmap = linkedMapOf()
147
+ this.opmap = ConcurrentHashMap()
147
148
  }
148
149
 
149
150
  // Data
@@ -237,8 +238,9 @@ class Context(ctxmap: MutableMap<String, Any?>?, basectx: Context?) {
237
238
 
238
239
  val op = Operation(opdef)
239
240
 
240
- this.opmap!![cacheKey] = op
241
- return op
241
+ // Requests on other threads share this cache; every one of them gets
242
+ // the Operation stored first.
243
+ return this.opmap!!.putIfAbsent(cacheKey, op) ?: op
242
244
  }
243
245
 
244
246
  fun makeError(code: String, msg: String): SdkError {