@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
@@ -110,7 +110,7 @@ class EntityOperation {
110
110
  }
111
111
  else {
112
112
  // Off-happy-path (throw disabled): typed as any so the method's
113
- // Promise<EntityName> return stays clean under strict null checks.
113
+ // Promise<EntyClass> return stays clean under strict null checks.
114
114
  return undefined as any
115
115
  }
116
116
  }
@@ -111,7 +111,7 @@ class EntityOperation {
111
111
  }
112
112
  else {
113
113
  // Off-happy-path (throw disabled): typed as any so the method's
114
- // Promise<EntityName> return stays clean under strict null checks.
114
+ // Promise<EntyClass> return stays clean under strict null checks.
115
115
  return undefined as any
116
116
  }
117
117
  }
@@ -111,7 +111,7 @@ class EntityOperation {
111
111
  }
112
112
  else {
113
113
  // Off-happy-path (throw disabled): typed as any so the method's
114
- // Promise<EntityName> return stays clean under strict null checks.
114
+ // Promise<EntyClass> return stays clean under strict null checks.
115
115
  return undefined as any
116
116
  }
117
117
  }
@@ -7,6 +7,7 @@ import {
7
7
  canonScalarKey,
8
8
  each,
9
9
  opParams,
10
+ jsQuote,
10
11
  } from '@voxgig/sdkgen'
11
12
 
12
13
  import {
@@ -55,7 +56,7 @@ function exampleValue(entity: any, op: any, paramName: string, placeholder: stri
55
56
  if ('NULL' === key) {
56
57
  return 'null'
57
58
  }
58
- return `'${placeholder}'`
59
+ return jsQuote(placeholder)
59
60
  }
60
61
 
61
62
 
@@ -6,7 +6,7 @@ import {
6
6
  getModelPath,
7
7
  } from '@voxgig/apidef'
8
8
 
9
- import { zigVarName } from './utility_zig'
9
+ import { zigVarName, zigListMatch } from './utility_zig'
10
10
 
11
11
 
12
12
  // Canonical type sentinel -> a zig type name for the field/param tables.
@@ -27,6 +27,7 @@ function zigType(type: any): string {
27
27
  // A type-correct zig expression constructing a voxgig struct Value.
28
28
  function zigLit(type: any, placeholder: string = 'example'): string {
29
29
  const k = canonScalarKey(type)
30
+ if ('NULL' === k) return 'h.vnull()'
30
31
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
31
32
  if ('BOOLEAN' === k) return 'h.vbool(true)'
32
33
  if ('ARRAY' === k) return 'h.olist()'
@@ -154,7 +155,7 @@ switch (client.${method}(h.vnull()).load(${loadArg}, h.vnull())) {
154
155
  Content(`#### Example: List
155
156
 
156
157
  \`\`\`zig
157
- switch (client.${method}(h.vnull()).list(h.vnull(), h.vnull())) {
158
+ switch (client.${method}(h.vnull()).list(${zigListMatch(entity)}, h.vnull())) {
158
159
  .ok => |${eVar}s| {
159
160
  for (${eVar}s) |${eVar}| {
160
161
  std.debug.print("{s}\\n", .{h.stringify(${eVar}.asEntity().data(null))});
@@ -1,5 +1,5 @@
1
1
 
2
- import { cmp, Content, isAuthActive, envName, canonKey, canonScalarKey, entityIdField, pickExampleEntity, opRequestShape } from '@voxgig/sdkgen'
2
+ import { cmp, Content, isAuthActive, envName, canonKey, canonScalarKey, entityIdField, pickExampleEntity, opRequestShape, requiredItems } from '@voxgig/sdkgen'
3
3
 
4
4
  import {
5
5
  KIT,
@@ -13,6 +13,7 @@ import { zigVarName } from './utility_zig'
13
13
  // A type-correct zig expression constructing a voxgig struct Value.
14
14
  function zigLit(type: any): string {
15
15
  const k = canonScalarKey(type)
16
+ if ('NULL' === k) return 'h.vnull()'
16
17
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
17
18
  if ('BOOLEAN' === k) return 'h.vbool(true)'
18
19
  if ('ARRAY' === k) return 'h.olist()'
@@ -36,13 +37,16 @@ const ReadmeHowto = cmp(function ReadmeHowto(props: any) {
36
37
  let testArg = 'h.vnull()'
37
38
  if (exampleEntity && isMatchOp) {
38
39
  testArg = idF ? `h.jo(&.{.{ "${idF}", h.vstr("test01") }})` : 'h.vnull()'
40
+ } else if (exampleEntity && 'list' === primaryOp && 0 < requiredItems(exampleEntity, 'list').length) {
41
+ const chosen = requiredItems(exampleEntity, 'list')
42
+ testArg = `h.jo(&.{${chosen.map((it: any) => `.{ ${JSON.stringify(it.name)}, ${zigLit(it.type)} }`).join(', ')}})`
39
43
  } else if (exampleEntity && ('create' === primaryOp || 'update' === primaryOp || 'patch' === primaryOp)) {
40
44
  const items = opRequestShape(exampleEntity, primaryOp).items
41
45
  .filter((it: any) => it.name !== idF && it.name !== 'id')
42
46
  const required = items.filter((it: any) => !it.optional)
43
47
  const chosen = required.length ? required : items.slice(0, 3)
44
48
  testArg = 0 < chosen.length
45
- ? `h.jo(&.{${chosen.map((it: any) => `.{ "${it.name}", ${zigLit(it.type)} }`).join(', ')}})`
49
+ ? `h.jo(&.{${chosen.map((it: any) => `.{ ${JSON.stringify(it.name)}, ${zigLit(it.type)} }`).join(', ')}})`
46
50
  : 'h.omap()'
47
51
  }
48
52
 
@@ -7,7 +7,7 @@ import {
7
7
  nom,
8
8
  } from '@voxgig/apidef'
9
9
 
10
- import { zigVarName } from './utility_zig'
10
+ import { zigVarName, zigListMatch } from './utility_zig'
11
11
 
12
12
 
13
13
  const ReadmeQuick = cmp(function ReadmeQuick(props: any) {
@@ -36,6 +36,7 @@ const ReadmeQuick = cmp(function ReadmeQuick(props: any) {
36
36
  // A type-correct zig expression constructing a voxgig struct Value.
37
37
  const zigLit = (type: any, placeholder: string = 'example'): string => {
38
38
  const k = canonScalarKey(type)
39
+ if ('NULL' === k) return 'h.vnull()'
39
40
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
40
41
  if ('BOOLEAN' === k) return 'h.vbool(true)'
41
42
  if ('ARRAY' === k) return 'h.olist()'
@@ -70,7 +71,7 @@ const client = ${ctor};
70
71
  it. \`asEntity().data(null)\` reads an entity's record.
71
72
 
72
73
  \`\`\`zig
73
- switch (client.${method}(h.vnull()).list(h.vnull(), h.vnull())) {
74
+ switch (client.${method}(h.vnull()).list(${zigListMatch(exampleEntity)}, h.vnull())) {
74
75
  .ok => |${eVar}s| {
75
76
  for (${eVar}s) |${eVar}| {
76
77
  std.debug.print("{s}\\n", .{h.stringify(${eVar}.asEntity().data(null))});
@@ -191,7 +192,7 @@ switch (client.${method}(h.vnull()).update(h.jo(&.{${updatePairs.join(', ')}}),
191
192
  const patchPairs = (idF ? [`.{ "${idF}", ${idValueFor('patch')} }`] : []).concat(examplePairs('patch'))
192
193
  Content(`// Patch — sends only the fields given
193
194
  switch (client.${method}(h.vnull()).patch(h.jo(&.{${patchPairs.join(', ')}}), h.vnull())) {
194
- .ok => |patched| std.debug.print("{s}\\n", .{h.stringify(patched)}),
195
+ .ok => |patched| std.debug.print("{s}\\n", .{h.stringify(patched.asEntity().data(null))}),
195
196
  .err => |e| std.debug.print("patch failed: {s}\\n", .{e.msg}),
196
197
  }
197
198
 
@@ -7,7 +7,7 @@ import {
7
7
  getModelPath,
8
8
  } from '@voxgig/apidef'
9
9
 
10
- import { zigVarName } from './utility_zig'
10
+ import { zigVarName, zigListMatch } from './utility_zig'
11
11
 
12
12
 
13
13
  // Canonical type sentinel -> a zig type name for the field/param tables.
@@ -26,6 +26,7 @@ function zigType(type: any): string {
26
26
  // A type-correct zig expression constructing a voxgig struct Value.
27
27
  function zigLit(type: any, placeholder: string = 'example'): string {
28
28
  const k = canonScalarKey(type)
29
+ if ('NULL' === k) return 'h.vnull()'
29
30
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
30
31
  if ('BOOLEAN' === k) return 'h.vbool(true)'
31
32
  if ('ARRAY' === k) return 'h.olist()'
@@ -61,8 +62,8 @@ const ReadmeRef = cmp(function ReadmeRef(props: any) {
61
62
  desc: 'Update an existing entity. The data must include the entity id. `.ok` carries the updated entity.',
62
63
  },
63
64
  patch: {
64
- sig: 'patch(reqdata: Value, ctrl: Value) OpResult',
65
- desc: 'Change part of an existing entity: only the fields given are sent. The data must include the entity id. `.ok` carries the patched entity data.',
65
+ sig: 'patch(reqdata: Value, ctrl: Value) EntResult',
66
+ desc: 'Change part of an existing entity: only the fields given are sent. The data must include the entity id. `.ok` carries the patched entity.',
66
67
  },
67
68
  remove: {
68
69
  sig: 'remove(reqmatch: Value, ctrl: Value) EntResult',
@@ -290,7 +291,7 @@ switch (client.${method}(h.vnull()).${opname}(${arg}, h.vnull())) {
290
291
  }
291
292
  else if ('list' === opname) {
292
293
  Content(`\`\`\`zig
293
- switch (client.${method}(h.vnull()).list(h.vnull(), h.vnull())) {
294
+ switch (client.${method}(h.vnull()).list(${zigListMatch(ent)}, h.vnull())) {
294
295
  .ok => |results| {
295
296
  for (results) |result| {
296
297
  std.debug.print("{s}\\n", .{h.stringify(result.asEntity().data(null))});
@@ -7,7 +7,7 @@ import {
7
7
  nom,
8
8
  } from '@voxgig/apidef'
9
9
 
10
- import { zigVarName } from './utility_zig'
10
+ import { zigVarName, zigListMatch } from './utility_zig'
11
11
 
12
12
 
13
13
  // A type-correct zig expression constructing a voxgig struct Value for a
@@ -15,6 +15,7 @@ import { zigVarName } from './utility_zig'
15
15
  // render a typed literal.
16
16
  function zigLit(type: any, placeholder: string = 'example'): string {
17
17
  const k = canonScalarKey(type)
18
+ if ('NULL' === k) return 'h.vnull()'
18
19
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
19
20
  if ('BOOLEAN' === k) return 'h.vbool(true)'
20
21
  if ('ARRAY' === k) return 'h.olist()'
@@ -55,7 +56,7 @@ const client = ${ctor};
55
56
 
56
57
  if (opnames.includes('list')) {
57
58
  Content(`// List all ${eName.toLowerCase()}s (one entity per record, .err on failure)
58
- switch (client.${method}(h.vnull()).list(h.vnull(), h.vnull())) {
59
+ switch (client.${method}(h.vnull()).list(${zigListMatch(exampleEntity)}, h.vnull())) {
59
60
  .ok => |${eVar}s| {
60
61
  for (${eVar}s) |${eVar}| {
61
62
  std.debug.print("{s}\\n", .{h.stringify(${eVar}.asEntity().data(null))});
@@ -1,5 +1,5 @@
1
1
 
2
- import { cmp, Content, canonKey, canonScalarKey, entityIdField, pickExampleEntity, opRequestShape } from '@voxgig/sdkgen'
2
+ import { cmp, Content, canonKey, canonScalarKey, entityIdField, pickExampleEntity, opRequestShape, requiredItems } from '@voxgig/sdkgen'
3
3
 
4
4
  import {
5
5
  KIT,
@@ -13,6 +13,7 @@ import { zigVarName } from './utility_zig'
13
13
  // A type-correct zig expression constructing a voxgig struct Value.
14
14
  function zigLit(type: any): string {
15
15
  const k = canonScalarKey(type)
16
+ if ('NULL' === k) return 'h.vnull()'
16
17
  if ('INTEGER' === k || 'NUMBER' === k) return 'h.vnum(1)'
17
18
  if ('BOOLEAN' === k) return 'h.vbool(true)'
18
19
  if ('ARRAY' === k) return 'h.olist()'
@@ -43,16 +44,16 @@ const client = sdk.test_sdk(h.vnull(), h.vnull());
43
44
  const idF = entityIdField(exampleEntity)
44
45
  const isMatchOp = 'load' === primaryOp || 'remove' === primaryOp
45
46
  let arg = 'h.vnull()'
46
- if (isMatchOp) {
47
+ if (isMatchOp || ('list' === primaryOp && 0 < requiredItems(exampleEntity, 'list').length)) {
47
48
  // Every REQUIRED match key (id first) — the same shape that generates
48
49
  // the op's request match.
49
- const items = opRequestShape(exampleEntity, primaryOp).items
50
- .filter((it: any) => !it.optional || it.name === idF)
50
+ const items = (isMatchOp ? opRequestShape(exampleEntity, primaryOp).items
51
+ .filter((it: any) => !it.optional || it.name === idF) : requiredItems(exampleEntity, 'list'))
51
52
  .sort((a: any, b: any) =>
52
53
  (a.name === idF ? 0 : 1) - (b.name === idF ? 0 : 1))
53
54
  arg = 0 < items.length
54
55
  ? `h.jo(&.{${items.map((it: any) =>
55
- `.{ "${it.name}", ${it.name === idF ? 'h.vstr("test01")' : zigLit(it.type)} }`).join(', ')}})`
56
+ `.{ ${JSON.stringify(it.name)}, ${isMatchOp && it.name === idF ? 'h.vstr("test01")' : zigLit(it.type)} }`).join(', ')}})`
56
57
  : 'h.vnull()'
57
58
  } else if ('create' === primaryOp || 'update' === primaryOp || 'patch' === primaryOp) {
58
59
  const items = opRequestShape(exampleEntity, primaryOp).items
@@ -60,7 +61,7 @@ const client = sdk.test_sdk(h.vnull(), h.vnull());
60
61
  const required = items.filter((it: any) => !it.optional)
61
62
  const chosen = required.length ? required : items.slice(0, 3)
62
63
  arg = 0 < chosen.length
63
- ? `h.jo(&.{${chosen.map((it: any) => `.{ "${it.name}", ${zigLit(it.type)} }`).join(', ')}})`
64
+ ? `h.jo(&.{${chosen.map((it: any) => `.{ ${JSON.stringify(it.name)}, ${zigLit(it.type)} }`).join(', ')}})`
64
65
  : 'h.omap()'
65
66
  }
66
67
  const eVar = zigVarName(exampleEntity.name)
@@ -4,6 +4,8 @@ import {
4
4
  walk,
5
5
  } from '@voxgig/struct'
6
6
 
7
+ import { canonScalarKey, requiredItems } from '@voxgig/sdkgen'
8
+
7
9
 
8
10
  // Zig keywords that are illegal as a plain identifier.
9
11
  const ZIG_RESERVED = new Set<string>([
@@ -138,8 +140,19 @@ function clean(o: any, dropDefaults?: boolean): any {
138
140
  return prune(o, true === dropDefaults)
139
141
  }
140
142
 
143
+ // A list's required route and query parameters, as the match it is called with.
144
+ function zigListMatch(entity: any): string {
145
+ const lit = (type: any): string =>
146
+ (({ NULL: 'h.vnull()', INTEGER: 'h.vnum(1)', NUMBER: 'h.vnum(1)', BOOLEAN: 'h.vbool(true)', ARRAY: 'h.olist()', OBJECT: 'h.omap()' }) as any)[canonScalarKey(type)] ?? 'h.vstr("example")'
147
+ const items = requiredItems(entity, 'list')
148
+ return 0 < items.length
149
+ ? `h.jo(&.{${items.map((it: any) => `.{ ${JSON.stringify(it.name)}, ${lit(it.type)} }`).join(', ')}})`
150
+ : 'h.vnull()'
151
+ }
152
+
141
153
 
142
154
  export {
155
+ zigListMatch,
143
156
  clean,
144
157
  formatZigValue,
145
158
  zigModuleName,
@@ -27,7 +27,7 @@ static bool field_arg(Context* ctx, const char* name) {
27
27
 
28
28
  /* A header, cookie or query argument travels where prepare_headers_util or
29
29
  prepare_query_util sends it, so the body is built from the request data
30
- without it, unless the entity declares it as a field too. */
30
+ without it, unless the point marks it as a field the body keeps. */
31
31
  static voxgig_value* routed_args(Context* ctx) {
32
32
  voxgig_value* routed = voxgig_new_list();
33
33
  for (size_t k = 0; k < 3; k++) {
@@ -395,8 +395,8 @@
395
395
  points (let [t (when (vs/ismap opcfg) (vs/getprop opcfg "points"))]
396
396
  (if (vs/islist t) t (vs/jt)))
397
397
  op (make-operation (vs/jm "entity" entname "name" opname "input" input "points" points))]
398
- (swap! opmap assoc cache-key op)
399
- op))))
398
+ ;; Every request racing to build this Operation gets the one stored first.
399
+ (get (swap! opmap #(if (contains? % cache-key) % (assoc % cache-key op))) cache-key)))))
400
400
 
401
401
  ;; ---------------------------------------------------------------------------
402
402
  ;; Feature dispatch.
@@ -488,19 +488,21 @@
488
488
  (let [n (try (long (Math/floor (Double/parseDouble (str v)))) (catch Exception _ nil))]
489
489
  (if (and n (<= 0 n)) n dflt)))
490
490
 
491
- ;; The derived clean block: a struct map so it lives in options.__derived__
492
- ;; and its `values` list stays MUTABLE after make-options - features register
493
- ;; what they resolve later.
491
+ ;; The derived clean block: a java.util.Map so it lives in options.__derived__
492
+ ;; and its `values` list can be replaced after make-options - features
493
+ ;; register what they resolve later. Concurrent, so a clean or a request
494
+ ;; copying the options reads it without the lock and sees the last put.
494
495
  (defn make-clean-config [cleanopts]
495
496
  (let [o (fn [k] (mget cleanopts k))
496
497
  keys (vs/jt)]
497
498
  (doseq [k (splitkeys (o "keys"))] (.add ^java.util.List keys k))
498
- (vs/jm "active" (not= false (o "active"))
499
- "keys" keys
500
- "values" (vs/jt)
501
- "mask" (let [m (o "mask")] (if (string? m) m "[redacted]"))
502
- "hint" (count-opt (o "hint") 0)
503
- "min" (max 1 (count-opt (o "min") 4)))))
499
+ (doto (java.util.concurrent.ConcurrentHashMap.)
500
+ (.put "active" (not= false (o "active")))
501
+ (.put "keys" keys)
502
+ (.put "values" (vs/jt))
503
+ (.put "mask" (let [m (o "mask")] (if (string? m) m "[redacted]")))
504
+ (.put "hint" (count-opt (o "hint") 0))
505
+ (.put "min" (max 1 (count-opt (o "min") 4))))))
504
506
 
505
507
  ;; A context without options (make-error accepts a bare one) still masks by
506
508
  ;; the schema defaults.
@@ -521,21 +523,25 @@
521
523
 
522
524
  (defn u-clean-add [ctx value]
523
525
  (let [cfg (clean-config ctx)
524
- minlen (long (or (mget cfg "min") 4))
525
- values (mget cfg "values")]
526
- (when (and (string? value) (>= (count value) minlen) (instance? java.util.List values))
527
- (let [changed (atom false)]
528
- (doseq [form (clean-forms value)]
529
- (when (and (>= (count form) minlen) (not (.contains ^java.util.List values form)))
530
- (.add ^java.util.List values form)
531
- (reset! changed true)))
532
- ;; Longest first, so a value is never masked by a substring of itself.
533
- (when @changed
534
- (let [sorted (sort-by (fn [^String s] (- (count s))) (vec values))]
535
- (.clear ^java.util.List values)
536
- (doseq [s sorted] (.add ^java.util.List values s))))))
526
+ minlen (long (or (mget cfg "min") 4))]
527
+ (when (and (string? value) (>= (count value) minlen)
528
+ (instance? java.util.List (mget cfg "values")))
529
+ (let [forms (filterv #(>= (count %) minlen) (clean-forms value))]
530
+ ;; Every request copies the options, the registry among them, so a
531
+ ;; registration publishes a new vector and never changes a published one.
532
+ (locking cfg
533
+ (let [values (vec (mget cfg "values"))
534
+ added (remove #(.contains ^java.util.List values %) forms)]
535
+ ;; Longest first, so a value is never masked by a substring of itself.
536
+ (when (seq added)
537
+ (.put ^java.util.Map cfg "values"
538
+ (vec (sort-by (fn [^String s] (- (count s))) (into values added)))))))))
537
539
  nil))
538
540
 
541
+ (defn- registered [cfg]
542
+ (let [values (mget cfg "values")]
543
+ (if (instance? java.util.List values) values [])))
544
+
539
545
  (defn- mask-value [cfg ^String value]
540
546
  (let [hint (long (or (mget cfg "hint") 0))
541
547
  mask (str (mget cfg "mask"))]
@@ -547,7 +553,7 @@
547
553
  (reduce (fn [^String out ^String value]
548
554
  (if (.contains out value) (str/replace out value (mask-value cfg value)) out))
549
555
  text
550
- (vec (or (mget cfg "values") []))))
556
+ (registered cfg)))
551
557
 
552
558
  (defn- sensitive-key? [cfg key]
553
559
  (if (or (nil? key) (number? key))
@@ -1003,7 +1009,7 @@
1003
1009
 
1004
1010
  ;; A header, cookie or query argument travels where u-prepare-headers or
1005
1011
  ;; u-prepare-query sends it, so the body is built from the request data
1006
- ;; without it, unless the entity declares it as a field too.
1012
+ ;; without it, unless the point marks it as a field the body keeps.
1007
1013
  (defn- routed-arg-names [ctx]
1008
1014
  (->> (concat (call-args ctx "header") (call-args ctx "cookie") (call-args ctx "query"))
1009
1015
  (map first)
@@ -0,0 +1,136 @@
1
+ ;; ProjectName SDK concurrency tests - requests in flight at once on one
2
+ ;; client. Each resolves its operation through the cache the client's root
3
+ ;; context shares with every request, and registers and cleans secrets
4
+ ;; through the one registry the client holds.
5
+ (ns sdk.test.concurrency
6
+ (:require [sdk.core :as core]
7
+ [sdk.client :as client]
8
+ [sdk.testutil :as t]
9
+ [voxgig.struct :as vs])
10
+ (:import [java.util.concurrent ConcurrentLinkedQueue CountDownLatch CyclicBarrier]))
11
+
12
+ (def ^:private rounds 200)
13
+ (def ^:private width 8)
14
+ (def ^:private ops 32)
15
+ (def ^:private masked "a [redacted] b [redacted] c")
16
+
17
+ ;; Runs body on width threads released together, and returns what they threw.
18
+ (defn- at-once [body]
19
+ (let [start (CyclicBarrier. width)
20
+ thrown (ConcurrentLinkedQueue.)
21
+ threads (mapv (fn [n]
22
+ (doto (Thread. ^Runnable (fn []
23
+ (try
24
+ (.await start)
25
+ (body n)
26
+ (catch Throwable e (.add thrown e)))))
27
+ (.start)))
28
+ (range width))]
29
+ (doseq [^Thread thread threads] (.join thread))
30
+ (vec thrown)))
31
+
32
+ (defn- resolve-op [root k]
33
+ (core/oget (core/make-context (vs/jm "opname" (str "op" k)) root) :op))
34
+
35
+ (defn- resolutions-share-one-cached-operation []
36
+ (dotimes [round rounds]
37
+ (let [sdk (client/test-sdk nil nil)
38
+ root @(:root-ctx sdk)
39
+ got (vec (repeatedly width #(object-array ops)))
40
+ thrown (at-once (fn [n] (dotimes [k ops] (aset ^objects (got n) k (resolve-op root k)))))]
41
+ (t/is-true (empty? thrown) (str "round " round " threw: " (pr-str thrown)))
42
+ (dotimes [k ops]
43
+ (let [cached (resolve-op root k)]
44
+ (dotimes [n width]
45
+ (t/is-true (identical? cached (aget ^objects (got n) k))
46
+ (str "round " round ": op" k " resolved to more than one Operation"))))))))
47
+
48
+ ;; A live client whose transport answers at once.
49
+ (defn- live-sdk []
50
+ (client/make-sdk
51
+ (vs/jm "base" "http://concurrency.test/api"
52
+ "allow" (vs/jm "op" "direct")
53
+ "system" (vs/jm "fetch" (fn [_url _fetchdef]
54
+ [(vs/jm "status" 200 "statusText" "OK" "headers" (vs/jm)
55
+ "json" (fn [] (vs/jm "ok" true)))
56
+ nil])))))
57
+
58
+ (defn- added-secret [round n k] (str "ADDED-SECRET-" round "-" n "-" k))
59
+
60
+ ;; Registers thread n's secrets, then counts the thread out of registering.
61
+ (defn- register-secrets [clean-add ^CountDownLatch registering round n]
62
+ (try
63
+ (dotimes [k ops] (clean-add (added-secret round n k)))
64
+ (finally (.countDown registering))))
65
+
66
+ (defn- every-secret-masked [clean round]
67
+ (dotimes [n (quot width 2)]
68
+ (dotimes [k ops]
69
+ (let [added (added-secret round n k)]
70
+ (t/is-eq (clean added) "[redacted]"
71
+ (str "round " round ": " added " was registered but not masked"))))))
72
+
73
+ ;; Secrets registered on some threads while others clean: every clean masks
74
+ ;; what was registered before it, the longer secret whole, and no
75
+ ;; registration is lost.
76
+ (defn- registration-keeps-every-secret-masked []
77
+ (dotimes [round (quot rounds 4)]
78
+ (let [sdk (client/test-sdk nil nil)
79
+ root @(:root-ctx sdk)
80
+ clean (fn [v] ((core/uget root :clean) root v))
81
+ clean-add (fn [v] ((core/uget root :clean-add) root v))
82
+ inner (str "INNER-SECRET-" round)
83
+ text (str "a " inner " b OUTER-" inner "-TAIL c")
84
+ _ (clean-add inner)
85
+ _ (clean-add (str "OUTER-" inner "-TAIL"))
86
+ _ (t/is-eq (clean text) masked (str "round " round))
87
+ registering (CountDownLatch. (quot width 2))
88
+ wrong (ConcurrentLinkedQueue.)
89
+ thrown (at-once
90
+ (fn [n]
91
+ (if (< n (quot width 2))
92
+ (register-secrets clean-add registering round n)
93
+ (loop []
94
+ (when (pos? (.getCount registering))
95
+ (let [got (clean text)]
96
+ (if (= masked got) (recur) (.add wrong got))))))))]
97
+ (t/is-true (empty? thrown) (str "round " round " threw: " (pr-str thrown)))
98
+ (t/is-true (.isEmpty wrong) (str "round " round " cleaned to: " (pr-str (vec wrong))))
99
+ (every-secret-masked clean round))))
100
+
101
+ ;; Requests on one client while secrets register on it: each request copies
102
+ ;; the client's options, the registry among them.
103
+ (defn- requests-survive-registration []
104
+ (dotimes [round (quot rounds 4)]
105
+ (let [sdk (live-sdk)
106
+ root @(:root-ctx sdk)
107
+ clean (fn [v] ((core/uget root :clean) root v))
108
+ clean-add (fn [v] ((core/uget root :clean-add) root v))
109
+ registering (CountDownLatch. (quot width 2))
110
+ failed (ConcurrentLinkedQueue.)
111
+ thrown (at-once
112
+ (fn [n]
113
+ (if (< n (quot width 2))
114
+ (register-secrets clean-add registering round n)
115
+ (loop []
116
+ (when (pos? (.getCount registering))
117
+ (let [res (client/direct sdk (vs/jm "path" (str "p" n)))]
118
+ (if (true? (vs/getprop res "ok")) (recur) (.add failed res))))))))]
119
+ (t/is-true (empty? thrown) (str "round " round " threw: " (pr-str thrown)))
120
+ (t/is-true (.isEmpty failed) (str "round " round ", a request failed: " (pr-str (vec failed))))
121
+ (every-secret-masked clean round))))
122
+
123
+ (defn run [rec]
124
+ (let [ran (atom 0)
125
+ failed (atom 0)
126
+ counting (fn [name ok? msg]
127
+ (swap! ran inc)
128
+ (when-not ok? (swap! failed inc))
129
+ (rec name ok? msg))]
130
+ (t/run-check counting "concurrency-resolutions-share-one-cached-operation"
131
+ resolutions-share-one-cached-operation)
132
+ (t/run-check counting "concurrency-registration-keeps-every-secret-masked"
133
+ registration-keeps-every-secret-masked)
134
+ (t/run-check counting "concurrency-requests-survive-registration"
135
+ requests-survive-registration)
136
+ (println (str "concurrency: " @ran " check(s), " @failed " failed"))))
@@ -1,6 +1,6 @@
1
1
  ;; ProjectName SDK test runner (tools.deps main entry point).
2
2
  ;; Runs the vendored omni runner's smoke test, the API-agnostic suites
3
- ;; (primary utility, pipeline, features, netsim), the generated API-specific
3
+ ;; (primary utility, pipeline, features, netsim, concurrency), the generated API-specific
4
4
  ;; suite, and the vendored struct corpus, then reports counts and exits
5
5
  ;; non-zero on any failure. `--sdk-only` skips the corpus steps (see -main).
6
6
  (ns sdk.test-runner
@@ -11,6 +11,7 @@
11
11
  [sdk.test.struct-corpus :as corpus]
12
12
  [sdk.test.omni-smoke :as omnismoke]
13
13
  [sdk.test.clean :as clean]
14
+ [sdk.test.concurrency :as concurrency]
14
15
  [sdk.gentest :as gentest]
15
16
  [clojure.java.io :as io]))
16
17
 
@@ -119,6 +120,7 @@
119
120
  (feature/run rec)
120
121
  (run-feature-suites rec)
121
122
  (netsim/run rec)
123
+ (concurrency/run rec)
122
124
  (gentest/run rec)
123
125
  ;; The canary sweep (generated: sdk/test/clean.clj) prints its own
124
126
  ;; `clean: swept N surface(s), M leak(s)` line, which sdkgen's lane reads.
@@ -12,11 +12,14 @@
12
12
  #define SDK_CORE_TYPES_HPP
13
13
 
14
14
  #include <algorithm>
15
+ #include <atomic>
15
16
  #include <cctype>
16
17
  #include <functional>
17
18
  #include <map>
18
19
  #include <memory>
20
+ #include <mutex>
19
21
  #include <ostream>
22
+ #include <shared_mutex>
20
23
  #include <stdexcept>
21
24
  #include <string>
22
25
  #include <vector>
@@ -51,7 +54,11 @@ using FeaturePtr = std::shared_ptr<Feature>;
51
54
  using UtilityPtr = std::shared_ptr<Utility>;
52
55
  using CtxPtr = std::shared_ptr<Context>;
53
56
 
54
- using OpMap = std::map<std::string, OperationPtr>;
57
+ // Shared by every context of one client, so by requests on several threads.
58
+ struct OpMap {
59
+ std::mutex lock;
60
+ std::map<std::string, OperationPtr> ops;
61
+ };
55
62
  using OpMapPtr = std::shared_ptr<OpMap>;
56
63
 
57
64
  // Generated (core/config.hpp) — the embedded API config + feature factory.
@@ -623,6 +630,24 @@ public:
623
630
 
624
631
  // ---- SdkClient --------------------------------------------------------
625
632
 
633
+ // A registration replaces the secret registry (options.__derived__.clean
634
+ // .values) while requests copy the options: it holds this lock exclusively,
635
+ // and every read of that slot holds it shared.
636
+ inline std::shared_mutex& cleanRegistryLock() {
637
+ // winpthreads sets up a static rwlock on its first lock, failing threads
638
+ // that race it with EINVAL; that first lock runs in this static's
639
+ // initialization, which every other caller waits for.
640
+ struct Warmed {
641
+ std::shared_mutex lock;
642
+ Warmed() {
643
+ lock.lock();
644
+ lock.unlock();
645
+ }
646
+ };
647
+ static Warmed warmed;
648
+ return warmed.lock;
649
+ }
650
+
626
651
  class SdkClient {
627
652
  public:
628
653
  std::string mode = "live";
@@ -744,7 +769,7 @@ inline SdkErrorPtr Helpers::unsupportedOp(const std::string& opname,
744
769
 
745
770
  // ---- Context ----
746
771
  inline Context::Context(const CtxSpec& cs, const CtxPtr& basectx) {
747
- static long long counter = 10000000;
772
+ static std::atomic<long long> counter{10000000};
748
773
  id = "C" + std::to_string(++counter);
749
774
 
750
775
  // Client
@@ -826,8 +851,11 @@ inline OperationPtr Context::resolveOp(const std::string& opname) {
826
851
  if (entity) entname = entity->getName();
827
852
  std::string cacheKey = entname + ":" + opname;
828
853
 
829
- auto it = opmap->find(cacheKey);
830
- if (it != opmap->end()) return it->second;
854
+ {
855
+ std::lock_guard<std::mutex> guard(opmap->lock);
856
+ auto it = opmap->ops.find(cacheKey);
857
+ if (it != opmap->ops.end()) return it->second;
858
+ }
831
859
 
832
860
  if (opname.empty()) {
833
861
  return std::make_shared<Operation>(vmap());
@@ -852,8 +880,9 @@ inline OperationPtr Context::resolveOp(const std::string& opname) {
852
880
  map_put(opdef, "points", points);
853
881
 
854
882
  auto op_ = std::make_shared<Operation>(opdef);
855
- (*opmap)[cacheKey] = op_;
856
- return op_;
883
+ // Every request racing to build this Operation gets the one stored first.
884
+ std::lock_guard<std::mutex> guard(opmap->lock);
885
+ return opmap->ops.emplace(cacheKey, op_).first->second;
857
886
  }
858
887
 
859
888
  inline SdkErrorPtr Context::makeError(const std::string& code, const std::string& msg) {
@@ -951,6 +980,7 @@ inline SdkClient::SdkClient(const Value& options_) {
951
980
  }
952
981
 
953
982
  inline Value SdkClient::optionsMap() {
983
+ std::shared_lock<std::shared_mutex> guard(cleanRegistryLock());
954
984
  Value out = Struct::clone(options);
955
985
  return out.is_map() ? out : vmap();
956
986
  }