@voxgig/sdkgen 4.22.0 → 4.24.0

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 (315) hide show
  1. package/bin/voxgig-sdkgen +18 -2
  2. package/dist/action/doctor.d.ts +1 -1
  3. package/dist/action/doctor.js +12 -10
  4. package/dist/action/doctor.js.map +1 -1
  5. package/dist/action/edition.js +4 -0
  6. package/dist/action/edition.js.map +1 -1
  7. package/dist/action/feature.js +5 -1
  8. package/dist/action/feature.js.map +1 -1
  9. package/dist/action/remove.d.ts +16 -0
  10. package/dist/action/remove.js +345 -0
  11. package/dist/action/remove.js.map +1 -0
  12. package/dist/action/target.js +6 -1
  13. package/dist/action/target.js.map +1 -1
  14. package/dist/cmp/ReadmeTop.js +1 -1
  15. package/dist/cmp/ReadmeTop.js.map +1 -1
  16. package/dist/cmp/ReadmeUnions.js +1 -1
  17. package/dist/cmp/ReadmeUnions.js.map +1 -1
  18. package/dist/cmp/Test.js +1 -1
  19. package/dist/cmp/Test.js.map +1 -1
  20. package/dist/helpers/buildIdNames.d.ts +3 -1
  21. package/dist/helpers/buildIdNames.js +15 -7
  22. package/dist/helpers/buildIdNames.js.map +1 -1
  23. package/dist/helpers/canonSpec.js +2 -2
  24. package/dist/helpers/canonSpec.js.map +1 -1
  25. package/dist/helpers/getMatchEntries.js +2 -2
  26. package/dist/helpers/getMatchEntries.js.map +1 -1
  27. package/dist/helpers/modelNames.js +5 -1
  28. package/dist/helpers/modelNames.js.map +1 -1
  29. package/dist/helpers/opShape.js +33 -33
  30. package/dist/helpers/opShape.js.map +1 -1
  31. package/dist/helpers/pointPath.js +5 -10
  32. package/dist/helpers/pointPath.js.map +1 -1
  33. package/dist/helpers/resolved.js +2 -29
  34. package/dist/helpers/resolved.js.map +1 -1
  35. package/dist/sdkgen.d.ts +2 -2
  36. package/dist/sdkgen.js +5 -3
  37. package/dist/sdkgen.js.map +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/dist/utility.js +15 -7
  40. package/dist/utility.js.map +1 -1
  41. package/package.json +3 -3
  42. package/project/.sdk/src/cmp/c/EntityTypes_c.ts +4 -4
  43. package/project/.sdk/src/cmp/c/ReadmeEntity_c.ts +3 -3
  44. package/project/.sdk/src/cmp/c/ReadmeModel_c.ts +3 -3
  45. package/project/.sdk/src/cmp/c/ReadmeRef_c.ts +5 -5
  46. package/project/.sdk/src/cmp/c/Schema_c.ts +1 -1
  47. package/project/.sdk/src/cmp/c/TestDirect_c.ts +12 -12
  48. package/project/.sdk/src/cmp/clojure/ReadmeEntity_clojure.ts +3 -3
  49. package/project/.sdk/src/cmp/clojure/ReadmeModel_clojure.ts +3 -3
  50. package/project/.sdk/src/cmp/clojure/ReadmeRef_clojure.ts +5 -5
  51. package/project/.sdk/src/cmp/clojure/Schema_clojure.ts +1 -1
  52. package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +3 -3
  53. package/project/.sdk/src/cmp/cpp/ReadmeEntity_cpp.ts +3 -3
  54. package/project/.sdk/src/cmp/cpp/ReadmeModel_cpp.ts +3 -3
  55. package/project/.sdk/src/cmp/cpp/ReadmeRef_cpp.ts +5 -5
  56. package/project/.sdk/src/cmp/cpp/Schema_cpp.ts +1 -1
  57. package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +14 -14
  58. package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +51 -50
  59. package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +4 -4
  60. package/project/.sdk/src/cmp/csharp/ReadmeEntity_csharp.ts +3 -3
  61. package/project/.sdk/src/cmp/csharp/ReadmeModel_csharp.ts +3 -3
  62. package/project/.sdk/src/cmp/csharp/ReadmeRef_csharp.ts +5 -5
  63. package/project/.sdk/src/cmp/csharp/Schema_csharp.ts +1 -1
  64. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +30 -30
  65. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +66 -65
  66. package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +4 -4
  67. package/project/.sdk/src/cmp/elixir/ReadmeEntity_elixir.ts +3 -3
  68. package/project/.sdk/src/cmp/elixir/ReadmeModel_elixir.ts +3 -3
  69. package/project/.sdk/src/cmp/elixir/ReadmeRef_elixir.ts +4 -4
  70. package/project/.sdk/src/cmp/elixir/Schema_elixir.ts +1 -1
  71. package/project/.sdk/src/cmp/go/EntityTypes_go.ts +4 -4
  72. package/project/.sdk/src/cmp/go/ReadmeEntity_go.ts +3 -3
  73. package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +3 -3
  74. package/project/.sdk/src/cmp/go/ReadmeRef_go.ts +5 -5
  75. package/project/.sdk/src/cmp/go/Schema_go.ts +1 -1
  76. package/project/.sdk/src/cmp/go/TestDirect_go.ts +38 -38
  77. package/project/.sdk/src/cmp/go/TestEntity_go.ts +75 -74
  78. package/project/.sdk/src/cmp/go/utility_go.ts +5 -5
  79. package/project/.sdk/src/cmp/java/EntityTypes_java.ts +4 -4
  80. package/project/.sdk/src/cmp/java/ReadmeEntity_java.ts +3 -3
  81. package/project/.sdk/src/cmp/java/ReadmeModel_java.ts +3 -3
  82. package/project/.sdk/src/cmp/java/ReadmeRef_java.ts +5 -5
  83. package/project/.sdk/src/cmp/java/Schema_java.ts +1 -1
  84. package/project/.sdk/src/cmp/java/TestDirect_java.ts +30 -30
  85. package/project/.sdk/src/cmp/java/TestEntity_java.ts +69 -68
  86. package/project/.sdk/src/cmp/js/EntityTypes_js.ts +5 -5
  87. package/project/.sdk/src/cmp/js/ReadmeEntity_js.ts +3 -3
  88. package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +3 -3
  89. package/project/.sdk/src/cmp/js/ReadmeRef_js.ts +5 -5
  90. package/project/.sdk/src/cmp/js/Schema_js.ts +1 -1
  91. package/project/.sdk/src/cmp/js/TestDirect_js.ts +27 -27
  92. package/project/.sdk/src/cmp/js/TestEntity_js.ts +66 -69
  93. package/project/.sdk/src/cmp/js/TestLive_js.ts +3 -3
  94. package/project/.sdk/src/cmp/js/utility_js.ts +5 -5
  95. package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +4 -4
  96. package/project/.sdk/src/cmp/kotlin/ReadmeEntity_kotlin.ts +3 -3
  97. package/project/.sdk/src/cmp/kotlin/ReadmeModel_kotlin.ts +3 -3
  98. package/project/.sdk/src/cmp/kotlin/ReadmeRef_kotlin.ts +5 -5
  99. package/project/.sdk/src/cmp/kotlin/Schema_kotlin.ts +1 -1
  100. package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +30 -30
  101. package/project/.sdk/src/cmp/kotlin/TestEntity_kotlin.ts +67 -66
  102. package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +5 -5
  103. package/project/.sdk/src/cmp/lua/ReadmeEntity_lua.ts +3 -3
  104. package/project/.sdk/src/cmp/lua/ReadmeModel_lua.ts +3 -3
  105. package/project/.sdk/src/cmp/lua/ReadmeQuick_lua.ts +4 -4
  106. package/project/.sdk/src/cmp/lua/ReadmeRef_lua.ts +5 -5
  107. package/project/.sdk/src/cmp/lua/Schema_lua.ts +1 -1
  108. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +25 -25
  109. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +66 -65
  110. package/project/.sdk/src/cmp/ocaml/ReadmeEntity_ocaml.ts +3 -3
  111. package/project/.sdk/src/cmp/ocaml/ReadmeModel_ocaml.ts +3 -3
  112. package/project/.sdk/src/cmp/ocaml/ReadmeRef_ocaml.ts +5 -5
  113. package/project/.sdk/src/cmp/ocaml/Schema_ocaml.ts +1 -1
  114. package/project/.sdk/src/cmp/perl/ReadmeEntity_perl.ts +3 -3
  115. package/project/.sdk/src/cmp/perl/ReadmeModel_perl.ts +3 -3
  116. package/project/.sdk/src/cmp/perl/ReadmeRef_perl.ts +5 -5
  117. package/project/.sdk/src/cmp/perl/Schema_perl.ts +1 -1
  118. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +25 -25
  119. package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +60 -59
  120. package/project/.sdk/src/cmp/php/EntityTypes_php.ts +4 -4
  121. package/project/.sdk/src/cmp/php/ReadmeEntity_php.ts +3 -3
  122. package/project/.sdk/src/cmp/php/ReadmeModel_php.ts +3 -3
  123. package/project/.sdk/src/cmp/php/ReadmeQuick_php.ts +4 -4
  124. package/project/.sdk/src/cmp/php/ReadmeRef_php.ts +5 -5
  125. package/project/.sdk/src/cmp/php/Schema_php.ts +1 -1
  126. package/project/.sdk/src/cmp/php/TestDirect_php.ts +25 -25
  127. package/project/.sdk/src/cmp/php/TestEntity_php.ts +66 -65
  128. package/project/.sdk/src/cmp/py/EntityTypes_py.ts +4 -4
  129. package/project/.sdk/src/cmp/py/ReadmeEntity_py.ts +3 -3
  130. package/project/.sdk/src/cmp/py/ReadmeModel_py.ts +3 -3
  131. package/project/.sdk/src/cmp/py/ReadmeRef_py.ts +5 -5
  132. package/project/.sdk/src/cmp/py/Schema_py.ts +1 -1
  133. package/project/.sdk/src/cmp/py/TestDirect_py.ts +25 -25
  134. package/project/.sdk/src/cmp/py/TestEntity_py.ts +66 -65
  135. package/project/.sdk/src/cmp/py-data/Main_py-data.ts +4 -4
  136. package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +4 -4
  137. package/project/.sdk/src/cmp/rb/ReadmeEntity_rb.ts +3 -3
  138. package/project/.sdk/src/cmp/rb/ReadmeModel_rb.ts +3 -3
  139. package/project/.sdk/src/cmp/rb/ReadmeQuick_rb.ts +4 -4
  140. package/project/.sdk/src/cmp/rb/ReadmeRef_rb.ts +5 -5
  141. package/project/.sdk/src/cmp/rb/Schema_rb.ts +1 -1
  142. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +25 -25
  143. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +66 -65
  144. package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +4 -4
  145. package/project/.sdk/src/cmp/rust/ReadmeEntity_rust.ts +3 -3
  146. package/project/.sdk/src/cmp/rust/ReadmeModel_rust.ts +3 -3
  147. package/project/.sdk/src/cmp/rust/ReadmeRef_rust.ts +5 -5
  148. package/project/.sdk/src/cmp/rust/Schema_rust.ts +1 -1
  149. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +18 -18
  150. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +63 -62
  151. package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +4 -4
  152. package/project/.sdk/src/cmp/scala/ReadmeEntity_scala.ts +3 -3
  153. package/project/.sdk/src/cmp/scala/ReadmeModel_scala.ts +3 -3
  154. package/project/.sdk/src/cmp/scala/ReadmeRef_scala.ts +5 -5
  155. package/project/.sdk/src/cmp/scala/Schema_scala.ts +1 -1
  156. package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +14 -14
  157. package/project/.sdk/src/cmp/scala/TestEntity_scala.ts +60 -59
  158. package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +4 -4
  159. package/project/.sdk/src/cmp/swift/ReadmeEntity_swift.ts +3 -3
  160. package/project/.sdk/src/cmp/swift/ReadmeModel_swift.ts +3 -3
  161. package/project/.sdk/src/cmp/swift/ReadmeRef_swift.ts +5 -5
  162. package/project/.sdk/src/cmp/swift/Schema_swift.ts +1 -1
  163. package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +5 -5
  164. package/project/.sdk/src/cmp/ts/ReadmeEntity_ts.ts +3 -3
  165. package/project/.sdk/src/cmp/ts/ReadmeModel_ts.ts +3 -3
  166. package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +1 -1
  167. package/project/.sdk/src/cmp/ts/ReadmeRef_ts.ts +5 -5
  168. package/project/.sdk/src/cmp/ts/Schema_ts.ts +1 -1
  169. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +40 -40
  170. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +72 -75
  171. package/project/.sdk/src/cmp/ts/TestLive_ts.ts +3 -3
  172. package/project/.sdk/src/cmp/ts/utility_ts.ts +5 -5
  173. package/project/.sdk/src/cmp/zig/ReadmeEntity_zig.ts +3 -3
  174. package/project/.sdk/src/cmp/zig/ReadmeModel_zig.ts +3 -3
  175. package/project/.sdk/src/cmp/zig/ReadmeRef_zig.ts +5 -5
  176. package/project/.sdk/src/cmp/zig/Schema_zig.ts +1 -1
  177. package/project/.sdk/tm/c/core/context.c +3 -1
  178. package/project/.sdk/tm/c/feature/paging.c +37 -3
  179. package/project/.sdk/tm/c/feature/test.c +71 -31
  180. package/project/.sdk/tm/c/utility/prepare_query.c +2 -1
  181. package/project/.sdk/tm/c/utility/transform_request.c +25 -3
  182. package/project/.sdk/tm/clojure/src/sdk/core.clj +21 -7
  183. package/project/.sdk/tm/clojure/src/sdk/features.clj +74 -22
  184. package/project/.sdk/tm/cpp/core/types.hpp +1 -1
  185. package/project/.sdk/tm/cpp/feature/paging.hpp +36 -3
  186. package/project/.sdk/tm/cpp/feature/test.hpp +58 -19
  187. package/project/.sdk/tm/cpp/utility/pipeline.hpp +16 -4
  188. package/project/.sdk/tm/csharp/core/Context.cs +1 -1
  189. package/project/.sdk/tm/csharp/feature/PagingFeature.cs +58 -4
  190. package/project/.sdk/tm/csharp/feature/TestFeature.cs +23 -25
  191. package/project/.sdk/tm/csharp/utility/Fetcher.cs +19 -12
  192. package/project/.sdk/tm/csharp/utility/PrepareQuery.cs +1 -1
  193. package/project/.sdk/tm/csharp/utility/TransformRequest.cs +23 -3
  194. package/project/.sdk/tm/elixir/lib/projectname/context.ex +1 -1
  195. package/project/.sdk/tm/elixir/lib/projectname/feature/paging.ex +52 -10
  196. package/project/.sdk/tm/elixir/lib/projectname/feature/test.ex +58 -22
  197. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +30 -9
  198. package/project/.sdk/tm/go/core/context.go +13 -13
  199. package/project/.sdk/tm/go/feature/paging_feature.go +40 -2
  200. package/project/.sdk/tm/go/feature/test_feature.go +3 -15
  201. package/project/.sdk/tm/go/test/feature_corpus_test.go +1 -0
  202. package/project/.sdk/tm/go/test/feature_test.go +54 -0
  203. package/project/.sdk/tm/go/utility/fetcher.go +41 -20
  204. package/project/.sdk/tm/go/utility/prepare_query.go +1 -1
  205. package/project/.sdk/tm/go/utility/transform_request.go +22 -3
  206. package/project/.sdk/tm/java/core/Context.java +2 -1
  207. package/project/.sdk/tm/java/feature/PagingFeature.java +46 -4
  208. package/project/.sdk/tm/java/feature/TestFeature.java +21 -19
  209. package/project/.sdk/tm/java/test/FeatureCorpusTest.java +3 -0
  210. package/project/.sdk/tm/java/test/FeatureTest.java +42 -0
  211. package/project/.sdk/tm/java/utility/Fetcher.java +36 -28
  212. package/project/.sdk/tm/java/utility/PrepareQuery.java +1 -1
  213. package/project/.sdk/tm/java/utility/TransformRequest.java +18 -3
  214. package/project/.sdk/tm/js/src/Context.js +7 -2
  215. package/project/.sdk/tm/js/src/feature/paging/PagingFeature.js +24 -6
  216. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +7 -5
  217. package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +1 -1
  218. package/project/.sdk/tm/js/test/feature/Corpus.test.js +4 -0
  219. package/project/.sdk/tm/js/test/live-entity.js +29 -29
  220. package/project/.sdk/tm/js/test/live-scenarios.js +4 -4
  221. package/project/.sdk/tm/kotlin/core/Context.kt +1 -1
  222. package/project/.sdk/tm/kotlin/feature/PagingFeature.kt +36 -4
  223. package/project/.sdk/tm/kotlin/feature/TestFeature.kt +19 -18
  224. package/project/.sdk/tm/kotlin/utility/Fetcher.kt +33 -24
  225. package/project/.sdk/tm/kotlin/utility/Prepare.kt +1 -1
  226. package/project/.sdk/tm/kotlin/utility/ResultTransform.kt +18 -3
  227. package/project/.sdk/tm/lua/core/context.lua +8 -1
  228. package/project/.sdk/tm/lua/core/control.lua +3 -0
  229. package/project/.sdk/tm/lua/feature/paging_feature.lua +44 -5
  230. package/project/.sdk/tm/lua/feature/test_feature.lua +32 -14
  231. package/project/.sdk/tm/lua/utility/prepare_query.lua +2 -1
  232. package/project/.sdk/tm/lua/utility/transform_request.lua +19 -3
  233. package/project/.sdk/tm/ocaml/sdk_features.ml +78 -25
  234. package/project/.sdk/tm/ocaml/sdk_runtime.ml +23 -8
  235. package/project/.sdk/tm/perl/core/context.pm +2 -1
  236. package/project/.sdk/tm/perl/feature/paging_feature.pm +31 -5
  237. package/project/.sdk/tm/perl/feature/test_feature.pm +52 -20
  238. package/project/.sdk/tm/perl/feature/timeout_feature.pm +17 -13
  239. package/project/.sdk/tm/perl/t/feature_corpus.t +14 -1
  240. package/project/.sdk/tm/perl/utility/fetcher.pm +15 -1
  241. package/project/.sdk/tm/perl/utility/prepare_query.pm +1 -0
  242. package/project/.sdk/tm/perl/utility/transform_request.pm +13 -3
  243. package/project/.sdk/tm/php/core/Context.php +5 -1
  244. package/project/.sdk/tm/php/core/Control.php +5 -0
  245. package/project/.sdk/tm/php/feature/PagingFeature.php +26 -5
  246. package/project/.sdk/tm/php/feature/TestFeature.php +27 -42
  247. package/project/.sdk/tm/php/test/FeatureCorpusTest.php +17 -1
  248. package/project/.sdk/tm/php/test/FeatureTest.php +44 -0
  249. package/project/.sdk/tm/php/utility/Fetcher.php +17 -3
  250. package/project/.sdk/tm/php/utility/PrepareQuery.php +1 -1
  251. package/project/.sdk/tm/php/utility/TransformRequest.php +15 -3
  252. package/project/.sdk/tm/py/pkg/core/context.py +2 -1
  253. package/project/.sdk/tm/py/pkg/feature/paging_feature.py +29 -4
  254. package/project/.sdk/tm/py/pkg/feature/test_feature.py +29 -12
  255. package/project/.sdk/tm/py/pkg/utility/fetcher.py +63 -65
  256. package/project/.sdk/tm/py/pkg/utility/prepare_query.py +2 -1
  257. package/project/.sdk/tm/py/pkg/utility/transform_request.py +11 -3
  258. package/project/.sdk/tm/py/test/test_feature.py +27 -0
  259. package/project/.sdk/tm/py/test/test_feature_corpus.py +11 -1
  260. package/project/.sdk/tm/rb/core/context.rb +1 -1
  261. package/project/.sdk/tm/rb/feature/paging_feature.rb +27 -5
  262. package/project/.sdk/tm/rb/feature/test_feature.rb +39 -11
  263. package/project/.sdk/tm/rb/test/feature_corpus_test.rb +12 -1
  264. package/project/.sdk/tm/rb/test/feature_test.rb +38 -0
  265. package/project/.sdk/tm/rb/utility/fetcher.rb +49 -3
  266. package/project/.sdk/tm/rb/utility/prepare_query.rb +1 -1
  267. package/project/.sdk/tm/rb/utility/transform_request.rb +10 -3
  268. package/project/.sdk/tm/rust/core/context.rs +2 -6
  269. package/project/.sdk/tm/rust/feature/paging.rs +44 -3
  270. package/project/.sdk/tm/rust/feature/secrets.rs +1 -1
  271. package/project/.sdk/tm/rust/feature/test.rs +74 -37
  272. package/project/.sdk/tm/rust/utility/fetcher.rs +41 -14
  273. package/project/.sdk/tm/rust/utility/prepare_query.rs +1 -1
  274. package/project/.sdk/tm/rust/utility/transform_request.rs +31 -5
  275. package/project/.sdk/tm/scala/core/Context.scala +2 -1
  276. package/project/.sdk/tm/scala/feature/PagingFeature.scala +41 -4
  277. package/project/.sdk/tm/scala/feature/TestFeature.scala +21 -18
  278. package/project/.sdk/tm/scala/utility/Fetcher.scala +34 -13
  279. package/project/.sdk/tm/scala/utility/Prepare.scala +1 -1
  280. package/project/.sdk/tm/scala/utility/Transform.scala +19 -3
  281. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +1 -1
  282. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/PagingFeature.swift +31 -4
  283. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TestFeature.swift +22 -15
  284. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Fetcher.swift +22 -3
  285. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +1 -1
  286. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +14 -3
  287. package/project/.sdk/tm/ts/src/Context.ts +7 -2
  288. package/project/.sdk/tm/ts/src/feature/paging/PagingFeature.ts +19 -3
  289. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +3 -0
  290. package/project/.sdk/tm/ts/src/utility/PrepareQueryUtility.ts +1 -1
  291. package/project/.sdk/tm/ts/test/feature/Corpus.test.ts +1 -0
  292. package/project/.sdk/tm/ts/test/live-entity.ts +26 -26
  293. package/project/.sdk/tm/ts/test/live-scenarios.ts +3 -3
  294. package/project/.sdk/tm/zig/core/context.zig +1 -1
  295. package/project/.sdk/tm/zig/core/utility.zig +19 -5
  296. package/project/.sdk/tm/zig/feature/paging.zig +34 -4
  297. package/project/.sdk/tm/zig/feature/test.zig +65 -30
  298. package/project/sdkgen-package.json +1 -1
  299. package/src/action/doctor.ts +12 -9
  300. package/src/action/edition.ts +8 -0
  301. package/src/action/feature.ts +7 -1
  302. package/src/action/remove.ts +492 -0
  303. package/src/action/target.ts +8 -1
  304. package/src/cmp/ReadmeTop.ts +1 -1
  305. package/src/cmp/ReadmeUnions.ts +1 -1
  306. package/src/cmp/Test.ts +1 -1
  307. package/src/helpers/buildIdNames.ts +17 -7
  308. package/src/helpers/canonSpec.ts +2 -2
  309. package/src/helpers/getMatchEntries.ts +2 -2
  310. package/src/helpers/modelNames.ts +6 -1
  311. package/src/helpers/opShape.ts +33 -33
  312. package/src/helpers/pointPath.ts +5 -10
  313. package/src/helpers/resolved.ts +3 -14
  314. package/src/sdkgen.ts +3 -1
  315. package/src/utility.ts +16 -7
@@ -63,12 +63,16 @@ class TestFeature : BaseFeature("test", "0.0.1", true) {
63
63
  if (null == data || null == ctx) return data
64
64
  val tm = Struct.getprop(ctx.point, "transform")
65
65
  val restf = Struct.getprop(tm, "res") as? String ?: return data
66
- // Exactly `body.<key>`; a deeper path is not an envelope this mock can
67
- // synthesise, so it is left alone rather than guessed at.
66
+ // Rebuild whatever nesting the transform unwraps. Multi-segment on purpose:
67
+ // GraphQL ops unwrap `body.data.<field>`, not just one envelope property.
68
68
  if (!restf.startsWith("`body.") || !restf.endsWith("`") || restf.length < 8) return data
69
69
  val inner = restf.substring(6, restf.length - 1)
70
- if (inner.isEmpty() || inner.contains(".")) return data
71
- return linkedMapOf<String, Any?>(inner to data)
70
+ if (inner.isEmpty()) return data
71
+ var out: Any? = data
72
+ for (seg in inner.split(".").reversed()) {
73
+ out = linkedMapOf<String, Any?>(seg to out)
74
+ }
75
+ return out
72
76
  }
73
77
 
74
78
  private fun respond(ctx: Context?, status: Int, data: Any?, extra: MutableMap<String, Any?>?): MutableMap<String, Any?> {
@@ -156,20 +160,13 @@ class TestFeature : BaseFeature("test", "0.0.1", true) {
156
160
  }
157
161
  val args = buildArgs(ctx, op, updateMatch)
158
162
  val found = Struct.select(entmap, args)
159
- var ent = Struct.getelem(found, 0, null)
160
- if (ent == null) {
161
- for (e in entmap.values) {
162
- if (e is MutableMap<*, *>) {
163
- ent = e
164
- break
165
- }
166
- }
167
- }
163
+ val ent = Struct.getelem(found, 0, null)
168
164
  if (ent == null) {
165
+ // update miss: 404, never another record
169
166
  return respond(ctx, 404, null, extra("statusText", "Not found"))
170
167
  }
171
168
  if (ent is MutableMap<*, *>) {
172
- (ent as MutableMap<String, Any?>).putAll(reqdata)
169
+ Struct.merge(Struct.jt(ent, reqdata))
173
170
  }
174
171
  Struct.delprop(ent, "\$KEY")
175
172
  val out = Struct.clone(ent)
@@ -316,10 +313,14 @@ class TestFeature : BaseFeature("test", "0.0.1", true) {
316
313
  }
317
314
  }
318
315
 
319
- // Get required params.
320
- val paramsPath = Struct.getpath(point, listOf("args", "params"))
321
- val reqdParams = Struct.select(paramsPath, Struct.jm("reqd", true))
322
- val reqd = Struct.transform(reqdParams, Struct.jt("`\$EACH`", "", "`\$KEY.name`"))
316
+ // Path AND query: a path-only read misses a query-addressed record
317
+ // (e.g. GET /result?trace_id=), which has no path param at all.
318
+ val reqdArgs = Struct.jt()
319
+ for (kind in listOf("params", "query")) {
320
+ val argsPath = Struct.getpath(point, listOf("args", kind))
321
+ reqdArgs.addAll(Struct.select(argsPath, Struct.jm("reqd", true)))
322
+ }
323
+ val reqd = Struct.transform(reqdArgs, Struct.jt("`\$EACH`", "", "`\$KEY.name`"))
323
324
 
324
325
  val qand = Struct.jt()
325
326
  val q = Struct.jm("`\$AND`", qand)
@@ -6,12 +6,44 @@ import java.net.URI
6
6
  import java.net.http.HttpClient
7
7
  import java.net.http.HttpRequest
8
8
  import java.net.http.HttpResponse
9
+ import java.util.concurrent.ConcurrentHashMap
9
10
  import java.util.function.BiFunction
10
11
  import java.util.function.Supplier
11
12
 
12
13
  import KOTLINPACKAGE.core.Context
13
14
  import KOTLINPACKAGE.utility.struct.Struct
14
15
 
16
+ // Clients keyed by redirect policy and proxy. Each HttpClient owns a
17
+ // connection pool and a selector thread, so one per request reused
18
+ // nothing; one per key pools across calls.
19
+ private val clients = ConcurrentHashMap<String, HttpClient>()
20
+
21
+ private fun clientFor(fetchdef: MutableMap<String, Any?>): HttpClient {
22
+ // "manual" (set by the station feature's middleware under a hosts
23
+ // policy) returns a 3xx like any other response: an automatic follow
24
+ // would carry injected credentials to a host no policy approved.
25
+ val redirectPolicy =
26
+ if ("manual" == fetchdef["redirect"]) HttpClient.Redirect.NEVER
27
+ else HttpClient.Redirect.NORMAL
28
+
29
+ val praw = fetchdef["proxy"]
30
+ val proxy = if (praw is String) praw else ""
31
+
32
+ return clients.computeIfAbsent("$redirectPolicy|$proxy") {
33
+ val clientb = HttpClient.newBuilder().followRedirects(redirectPolicy)
34
+ if ("" != proxy) {
35
+ try {
36
+ val proxyUri = URI.create(proxy)
37
+ val port = if (proxyUri.port < 0) 80 else proxyUri.port
38
+ clientb.proxy(ProxySelector.of(InetSocketAddress(proxyUri.host, port)))
39
+ } catch (e: RuntimeException) {
40
+ // Unparseable proxy target: direct connection, as the go transport.
41
+ }
42
+ }
43
+ clientb.build()
44
+ }
45
+ }
46
+
15
47
  @Suppress("UNCHECKED_CAST")
16
48
  fun defaultHttpFetch(fullurl: String, fetchdef: MutableMap<String, Any?>): MutableMap<String, Any?> {
17
49
  var method = if (fetchdef["method"] is String) fetchdef["method"] as String else ""
@@ -50,32 +82,9 @@ fun defaultHttpFetch(fullurl: String, fetchdef: MutableMap<String, Any?>): Mutab
50
82
  reqb.setHeader("User-Agent", "Mozilla/5.0 (compatible; ProjectNameSDK/1.0)")
51
83
  }
52
84
 
53
- // Honour a redirect annotation on the fetch definition (set by the
54
- // station feature's middleware under a hosts policy): "manual" returns
55
- // a 3xx like any other response instead of following it — the ts
56
- // donor's fetch honours the same key natively, and an automatic follow
57
- // would carry injected credentials to a host no policy approved.
58
- val redirectPolicy =
59
- if ("manual" == fetchdef["redirect"]) HttpClient.Redirect.NEVER
60
- else HttpClient.Redirect.NORMAL
61
-
62
- // Honour a proxy annotation on the fetch definition (set by the proxy
63
- // feature): route the request through a proxied HttpClient.
64
- val clientb = HttpClient.newBuilder().followRedirects(redirectPolicy)
65
- val proxy = fetchdef["proxy"]
66
- if (proxy is String && "" != proxy) {
67
- try {
68
- val proxyUri = URI.create(proxy)
69
- val port = if (proxyUri.port < 0) 80 else proxyUri.port
70
- clientb.proxy(ProxySelector.of(InetSocketAddress(proxyUri.host, port)))
71
- } catch (e: RuntimeException) {
72
- // Unparseable proxy target: fall through to a direct connection.
73
- }
74
- }
75
-
76
85
  val resp: HttpResponse<String>
77
86
  try {
78
- resp = clientb.build().send(reqb.build(), HttpResponse.BodyHandlers.ofString())
87
+ resp = clientFor(fetchdef).send(reqb.build(), HttpResponse.BodyHandlers.ofString())
79
88
  } catch (e: Exception) {
80
89
  throw RuntimeException("fetch: " + e.message, e)
81
90
  }
@@ -194,7 +194,7 @@ fun prepareQuery(ctx: Context): MutableMap<String, Any?> {
194
194
  for (item in Struct.items(reqmatch)) {
195
195
  val key = if (item[0] is String) item[0] as String else ""
196
196
  val v = item[1]
197
- if (v != null && !containsStr(params, key)) {
197
+ if (v != null && "\$action" != key && !containsStr(params, key)) {
198
198
  out[key] = v
199
199
  }
200
200
  }
@@ -58,21 +58,36 @@ fun resultHeaders(ctx: Context): KOTLINPACKAGE.core.Result {
58
58
  return result!!
59
59
  }
60
60
 
61
+ // `$action` selects the point (see makePoint); it is never an API field, so
62
+ // the body is a copy without it. The caller's map is left untouched.
63
+ private fun stripAction(reqdata: Any?): Any? {
64
+ if (reqdata !is Map<*, *> || !reqdata.containsKey("\$action")) {
65
+ return reqdata
66
+ }
67
+ val body = linkedMapOf<String, Any?>()
68
+ for ((k, v) in reqdata) {
69
+ if ("\$action" != k) {
70
+ body[k.toString()] = v
71
+ }
72
+ }
73
+ return body
74
+ }
75
+
61
76
  fun transformRequest(ctx: Context): Any? {
62
77
  if (ctx.spec != null) {
63
78
  ctx.spec!!.step = "reqform"
64
79
  }
65
80
 
66
81
  val transform = Helpers.toMapAny(Struct.getprop(ctx.point, "transform"))
67
- ?: return ctx.reqdata
82
+ ?: return stripAction(ctx.reqdata)
68
83
 
69
84
  val reqform = Struct.getprop(transform, "req", null)
70
- ?: return ctx.reqdata
85
+ ?: return stripAction(ctx.reqdata)
71
86
 
72
87
  val data = linkedMapOf<String, Any?>()
73
88
  data["reqdata"] = ctx.reqdata
74
89
 
75
- return Struct.transform(data, reqform)
90
+ return stripAction(Struct.transform(data, reqform))
76
91
  }
77
92
 
78
93
  fun transformResponse(ctx: Context): Any? {
@@ -49,7 +49,14 @@ function Context.new(ctxmap, basectx)
49
49
  if type(ctrl_raw.explain) == "table" then
50
50
  self.ctrl.explain = ctrl_raw.explain
51
51
  end
52
- elseif basectx ~= nil and basectx.ctrl ~= nil then
52
+ if ctrl_raw.actor ~= nil then
53
+ self.ctrl.actor = ctrl_raw.actor
54
+ end
55
+ if type(ctrl_raw.paging) == "table" then
56
+ self.ctrl.paging = ctrl_raw.paging
57
+ end
58
+ elseif basectx ~= nil and basectx.ctrl ~= nil
59
+ and helpers.get_ctx_prop(ctxmap, "opname") == nil then
53
60
  self.ctrl = basectx.ctrl
54
61
  end
55
62
 
@@ -10,6 +10,9 @@ function Control.new(opts)
10
10
  self.throw_err = opts.throw_err
11
11
  self.err = nil
12
12
  self.explain = opts.explain
13
+ -- Per-call feature inputs (audit actor, paging cursor/page).
14
+ self.actor = opts.actor
15
+ self.paging = opts.paging
13
16
  return self
14
17
  end
15
18
 
@@ -5,8 +5,9 @@
5
5
  -- (PreResult) it reads the server's pagination signals — a
6
6
  -- `Link: <...>; rel="next"` header, `X-Page`/`X-Next-Page`/
7
7
  -- `X-Total-Count` headers, or `next`/`cursor`/`nextCursor`/`hasMore`
8
- -- fields in the body — and records them on `ctx.result.paging`. A
9
- -- per-call `ctrl.paging` (cursor or page) wins over the option defaults,
8
+ -- fields in the body (snake_case forms too) — and records them on
9
+ -- `ctx.result.paging` and the caller's `ctrl.paging`. A per-call
10
+ -- `ctrl.paging` (cursor or page) wins over the option defaults,
10
11
  -- so auto-iteration can advance the cursor/page and re-issue the list
11
12
  -- call until `hasMore` is false. Parameter names (`pageParam`,
12
13
  -- `limitParam`, `cursorParam`), `startPage` (default 1) and `limit` are
@@ -95,8 +96,14 @@ function PagingFeature:PreRequest(ctx)
95
96
  if paging["cursor"] ~= nil then
96
97
  spec.query[cursor_param] = paging["cursor"]
97
98
  elseif spec.query[page_param] == nil then
98
- if paging["page"] ~= nil then
99
- spec.query[page_param] = paging["page"]
99
+ -- A record written back by PreResult holds the page just fetched as
100
+ -- "page" and the one to fetch as "nextPage", so nextPage wins.
101
+ local page = paging["nextPage"]
102
+ if page == nil then
103
+ page = paging["page"]
104
+ end
105
+ if page ~= nil then
106
+ spec.query[page_param] = page
100
107
  else
101
108
  spec.query[page_param] = self.options["startPage"] or 1
102
109
  end
@@ -218,17 +225,33 @@ function PagingFeature:PreResult(ctx)
218
225
  end
219
226
  end
220
227
 
221
- -- Body-level cursors.
228
+ -- Body-level signals; snake_case forms are read first so camelCase wins.
222
229
  if type(body) == "table" then
223
230
  if body["next"] ~= nil and paging.next == nil then
224
231
  paging.next = body["next"]
225
232
  end
233
+ if body["next_cursor"] ~= nil then
234
+ paging.cursor = body["next_cursor"]
235
+ end
226
236
  if body["cursor"] ~= nil then
227
237
  paging.cursor = body["cursor"]
228
238
  end
229
239
  if body["nextCursor"] ~= nil then
230
240
  paging.cursor = body["nextCursor"]
231
241
  end
242
+ if paging.nextPage == nil then
243
+ local np = body["nextPage"]
244
+ if np == nil then
245
+ np = body["next_page"]
246
+ end
247
+ if type(np) == "number" or type(np) == "string" then
248
+ paging.nextPage = np
249
+ end
250
+ end
251
+ if type(body["has_more"]) == "boolean" then
252
+ paging.hasMore = body["has_more"]
253
+ explicit_more = true
254
+ end
232
255
  if type(body["hasMore"]) == "boolean" then
233
256
  paging.hasMore = body["hasMore"]
234
257
  explicit_more = true
@@ -247,6 +270,22 @@ function PagingFeature:PreResult(ctx)
247
270
 
248
271
  result.paging = paging
249
272
 
273
+ if ctx.ctrl ~= nil then
274
+ -- The Context shares the caller's paging table by reference, so refill
275
+ -- it in place; a fresh table on ctrl never reaches the caller.
276
+ if type(ctx.ctrl.paging) == "table" then
277
+ local shared = ctx.ctrl.paging
278
+ for k in pairs(shared) do
279
+ shared[k] = nil
280
+ end
281
+ for k, v in pairs(paging) do
282
+ shared[k] = v
283
+ end
284
+ else
285
+ ctx.ctrl.paging = paging
286
+ end
287
+ end
288
+
250
289
  local client = self.client
251
290
  client._paging = { last = paging }
252
291
  end
@@ -167,21 +167,12 @@ function TestFeature:init(ctx, options)
167
167
  local args = test_self:build_args(fctx, op, update_match)
168
168
  local found = vs.select(entmap, args)
169
169
  local ent = vs.getelem(found, 0)
170
- if ent == nil and type(entmap) == "table" then
171
- for _, e in pairs(entmap) do
172
- if type(e) == "table" then ent = e; break end
173
- end
174
- end
175
170
  if ent == nil then
171
+ -- update miss: 404, never another record
176
172
  return respond(404, nil, { statusText = "Not found" })
177
173
  end
178
- if type(ent) == "table" then
179
- local reqdata = fctx.reqdata
180
- if reqdata ~= nil then
181
- for k, v in pairs(reqdata) do
182
- ent[k] = v
183
- end
184
- end
174
+ if type(ent) == "table" and type(fctx.reqdata) == "table" then
175
+ vs.merge({ ent, fctx.reqdata })
185
176
  end
186
177
  vs.delprop(ent, "$KEY")
187
178
  local out = vs.clone(ent)
@@ -312,12 +303,39 @@ function TestFeature:make_netsim(net, inner)
312
303
  end
313
304
 
314
305
 
306
+ local function point_terminal(p)
307
+ local parts = vs.getprop(p, "parts")
308
+ if type(parts) ~= "table" or #parts == 0 then return false end
309
+ local last = parts[#parts]
310
+ return type(last) == "string" and last:sub(1, 1) == "{"
311
+ end
312
+
313
+ local function point_depth(p)
314
+ local parts = vs.getprop(p, "parts")
315
+ return type(parts) == "table" and #parts or 0
316
+ end
317
+
318
+ -- The entity's own endpoint: a terminal `{param}` marks a record route, and
319
+ -- among equals the shallower path wins (the same rule as make_point).
320
+ local function pick_point(points)
321
+ if type(points) ~= "table" or #points == 0 then return nil end
322
+ local point = points[1]
323
+ for i = 2, #points do
324
+ local cand = points[i]
325
+ if point_terminal(cand) ~= point_terminal(point) then
326
+ if point_terminal(cand) then point = cand end
327
+ elseif point_depth(cand) < point_depth(point) then
328
+ point = cand
329
+ end
330
+ end
331
+ return point
332
+ end
333
+
315
334
  function TestFeature:build_args(ctx, op, args)
316
335
  local opname = op.name
317
336
 
318
- -- Get last point from config.
319
337
  local points = vs.getpath(ctx.config, "entity." .. ctx.entity:get_name() .. ".op." .. opname .. ".points")
320
- local point = vs.getelem(points, -1)
338
+ local point = pick_point(points)
321
339
 
322
340
  -- Path AND query: a path-only read misses a query-addressed record
323
341
  -- (e.g. GET /result?trace_id=), which has no path param at all.
@@ -29,7 +29,8 @@ local function prepare_query_util(ctx)
29
29
  for _, item in ipairs(reqmatch_items) do
30
30
  local key = item[1]
31
31
  local val = item[2]
32
- if val ~= nil and type(key) == "string" and not contains_param(params, key) then
32
+ if val ~= nil and type(key) == "string" and key ~= "$action"
33
+ and not contains_param(params, key) then
33
34
  out[key] = val
34
35
  end
35
36
  end
@@ -3,6 +3,22 @@
3
3
  local vs = require("utility.struct.struct")
4
4
  local helpers = require("core.helpers")
5
5
 
6
+ -- `$action` selects the point (see make_point_util); it is never an API
7
+ -- field, so the body is a copy without it. The caller's table is left
8
+ -- untouched.
9
+ local function strip_action(reqdata)
10
+ if not vs.ismap(reqdata) or reqdata["$action"] == nil then
11
+ return reqdata
12
+ end
13
+ local body = {}
14
+ for k, v in pairs(reqdata) do
15
+ if k ~= "$action" then
16
+ body[k] = v
17
+ end
18
+ end
19
+ return body
20
+ end
21
+
6
22
  local function transform_request_util(ctx)
7
23
  local spec = ctx.spec
8
24
  local point = ctx.point
@@ -13,19 +29,19 @@ local function transform_request_util(ctx)
13
29
 
14
30
  local transform = helpers.to_map(vs.getprop(point, "transform"))
15
31
  if transform == nil then
16
- return ctx.reqdata
32
+ return strip_action(ctx.reqdata)
17
33
  end
18
34
 
19
35
  local reqform = vs.getprop(transform, "req")
20
36
  if reqform == nil then
21
- return ctx.reqdata
37
+ return strip_action(ctx.reqdata)
22
38
  end
23
39
 
24
40
  local reqdata = vs.transform({
25
41
  reqdata = ctx.reqdata,
26
42
  }, reqform)
27
43
 
28
- return reqdata
44
+ return strip_action(reqdata)
29
45
  end
30
46
 
31
47
  return transform_request_util
@@ -1121,9 +1121,15 @@ let paging_feature () : feature =
1121
1121
  | Noval | Null ->
1122
1122
  (match getp q page_param with
1123
1123
  | Noval ->
1124
- let page = (match getp paging "page" with
1125
- | Noval | Null -> (match getp !options "startPage" with Num n -> Num n | _ -> Num 1.)
1126
- | p -> p) in
1124
+ (* A record written back by PreResult holds the page just
1125
+ * fetched as `page` and the one to fetch as `nextPage`,
1126
+ * so nextPage wins. *)
1127
+ let page = (match getp paging "nextPage" with
1128
+ | Noval | Null ->
1129
+ (match getp paging "page" with
1130
+ | Noval | Null -> (match getp !options "startPage" with Num n -> Num n | _ -> Num 1.)
1131
+ | p -> p)
1132
+ | np -> np) in
1127
1133
  setp q page_param page
1128
1134
  | _ -> ())
1129
1135
  | c -> setp q cursor_param c);
@@ -1176,11 +1182,20 @@ let paging_feature () : feature =
1176
1182
  (match body with
1177
1183
  | Map _ ->
1178
1184
  (match getp body "next" with Noval | Null -> () | n -> if is_nullish (getp paging "next") then setp paging "next" n);
1185
+ (* Both spellings, camelCase last so it wins when a body
1186
+ * carries the two. *)
1187
+ (match getp body "next_cursor" with Noval | Null -> () | c -> setp paging "cursor" c);
1179
1188
  (match getp body "cursor" with Noval | Null -> () | c -> setp paging "cursor" c);
1180
1189
  (match getp body "nextCursor" with Noval | Null -> () | c -> setp paging "cursor" c);
1181
- (match getp body "hasMore" with
1182
- | Bool b -> setp paging "hasMore" (Bool b); explicit_more := true
1183
- | _ -> ())
1190
+ if is_nullish (getp paging "nextPage") then begin
1191
+ let np = (match getp body "nextPage" with
1192
+ | Noval | Null -> getp body "next_page"
1193
+ | v -> v) in
1194
+ (match np with Num _ | Str _ -> setp paging "nextPage" np | _ -> ())
1195
+ end;
1196
+ List.iter (fun k -> match getp body k with
1197
+ | Bool b -> setp paging "hasMore" (Bool b); explicit_more := true
1198
+ | _ -> ()) ["has_more"; "hasMore"]
1184
1199
  | _ -> ());
1185
1200
  (* Cursor presence only INFERS another page. When the server
1186
1201
  * stated the answer outright — relay's `hasNextPage: false`, or
@@ -1196,6 +1211,16 @@ let paging_feature () : feature =
1196
1211
  setp paging "hasMore" (Bool hm)
1197
1212
  end;
1198
1213
  result.rt_paging <- paging;
1214
+ (* The record reached the caller through ctrl in every other typed
1215
+ * port and through nothing here, so a caller who asked for paging
1216
+ * got the pages and never the signals to continue. *)
1217
+ (match ctx.c_ctrl.ctrl_paging with
1218
+ | Map _ as held ->
1219
+ (* The caller holds this map: refill it in place. Every key of
1220
+ * the record is written, so no key of an earlier page lives on. *)
1221
+ List.iter (fun k -> setp held k (getp paging k))
1222
+ ["page"; "totalCount"; "nextPage"; "next"; "cursor"; "hasMore"]
1223
+ | _ -> ctx.c_ctrl.ctrl_paging <- paging);
1199
1224
  track_set (cc ctx) "paging" (jo [("last", paging)]))
1200
1225
  | _ -> ());
1201
1226
  f
@@ -1394,33 +1419,57 @@ let test_feature () : feature =
1394
1419
  match getp (getp ctx.c_point "transform") "res" with
1395
1420
  | Str spec ->
1396
1421
  let n = String.length spec in
1397
- (* Exactly `body.<key>`; a deeper path is not an envelope this mock
1398
- can synthesise, so it is left alone rather than guessed at. *)
1422
+ (* Rebuild whatever nesting the transform unwraps. Multi-segment on
1423
+ purpose: GraphQL ops unwrap `body.data.<field>`. *)
1399
1424
  if n > 7 && String.sub spec 0 6 = "`body." && spec.[n - 1] = '`' then
1400
1425
  let inner = String.sub spec 6 (n - 7) in
1401
- if String.length inner = 0 || String.contains inner '.' then data
1402
- else jo [(inner, data)]
1426
+ if String.length inner = 0 then data
1427
+ else
1428
+ List.fold_left (fun out seg -> jo [(seg, out)]) data
1429
+ (List.rev (String.split_on_char '.' inner))
1403
1430
  else data
1404
1431
  | _ -> data in
1405
1432
  let respond ctx status data extra =
1406
1433
  let out = jo [("status", vint_of status); ("statusText", Str "OK"); ("json", json_thunk (envelope ctx data)); ("body", Str "not-used")] in
1407
1434
  (match extra with Some (Map _ as e) -> List.iter (fun k -> setp out k (getp e k)) (keysof e) | _ -> ());
1408
1435
  (out, None) in
1436
+ let point_terminal p =
1437
+ match getp p "parts" with
1438
+ | List r -> (match List.rev !r with Str s :: _ -> String.length s > 0 && s.[0] = '{' | _ -> false)
1439
+ | _ -> false in
1440
+ let point_depth p = match getp p "parts" with List r -> List.length !r | _ -> 0 in
1441
+ (* The entity's own endpoint: a terminal `{param}` marks a record route, and
1442
+ among equals the shallower path wins (the same rule as make_point). *)
1443
+ let pick_point points =
1444
+ match points with
1445
+ | List r ->
1446
+ (match !r with
1447
+ | [] -> Noval
1448
+ | first :: rest ->
1449
+ List.fold_left (fun point cand ->
1450
+ if point_terminal cand <> point_terminal point then (if point_terminal cand then cand else point)
1451
+ else if point_depth cand < point_depth point then cand
1452
+ else point) first rest)
1453
+ | _ -> Noval in
1454
+ let reqd_names point kind =
1455
+ let reqd_args = select (getpath_s point ("args." ^ kind)) (jo [("reqd", Bool true)]) in
1456
+ transform reqd_args (ja [Str "`$EACH`"; Str ""; Str "`$KEY.name`"]) in
1409
1457
  let build_args ctx (op : operation) args =
1410
1458
  let opname = op.op_name in
1411
1459
  let entname = match ctx.c_entity with Some e -> e.e_name | None -> "_" in
1412
1460
  let points = getpath_s ctx.c_config ("entity." ^ entname ^ ".op." ^ opname ^ ".points") in
1413
- let point = getelem points (Num (-1.0)) in
1414
- let params_path = getpath_s point "args.params" in
1415
- let reqd_params = select params_path (jo [("reqd", Bool true)]) in
1416
- let reqd = transform reqd_params (ja [Str "`$EACH`"; Str ""; Str "`$KEY.name`"]) in
1461
+ let point = pick_point points in
1462
+ (* Path AND query: a path-only read misses a query-addressed record
1463
+ (e.g. GET /result?trace_id=), which has no path param at all. *)
1464
+ let reqd_params = reqd_names point "params" in
1465
+ let reqd_query = reqd_names point "query" in
1417
1466
  let qand = ref [] in
1418
1467
  (match args with
1419
1468
  | Map _ ->
1420
1469
  List.iter (fun key ->
1421
1470
  let is_id = key = "id" in
1422
- let selected = select reqd (Str key) in
1423
- let is_reqd = not (isempty selected) in
1471
+ let is_reqd = not (isempty (select reqd_params (Str key)))
1472
+ || not (isempty (select reqd_query (Str key))) in
1424
1473
  if is_id || is_reqd then begin
1425
1474
  let v = (cu ctx).u_param ctx (Str key) in
1426
1475
  let ka = (match op.op_alias with Map _ -> (match getp op.op_alias key with Str s -> Some s | _ -> None) | _ -> None) in
@@ -1461,18 +1510,22 @@ let test_feature () : feature =
1461
1510
  end
1462
1511
  | "update" ->
1463
1512
  let update_match = empty_map () in
1464
- (match fctx.c_reqdata with Map _ -> (match getp fctx.c_reqdata "id" with Noval -> () | v -> setp update_match "id" v) | _ -> ());
1513
+ (match fctx.c_reqdata with
1514
+ | Map _ ->
1515
+ (match getp fctx.c_reqdata "id" with Noval -> () | v -> setp update_match "id" v);
1516
+ (match getp op.op_alias "id" with
1517
+ | Str alias_id -> (match getp fctx.c_reqdata alias_id with Noval -> () | v -> setp update_match alias_id v)
1518
+ | _ -> ())
1519
+ | _ -> ());
1465
1520
  let update_match = if size update_match > 0 then update_match else resolve_match fctx (empty_map ()) in
1466
1521
  let args = build_args fctx op update_match in
1467
- let ent = ref (getelem (select entmap args) (Num 0.0)) in
1468
- (if is_nullish !ent then match entmap with
1469
- | Map m -> (try (match List.find (fun (_, v) -> match v with Map _ -> true | _ -> false) m.entries with (_, v) -> ent := v) with Not_found -> ())
1470
- | _ -> ());
1471
- if is_nullish !ent then respond fctx 404 Noval (Some (jo [("statusText", Str "Not found")]))
1522
+ let ent = getelem (select entmap args) (Num 0.0) in
1523
+ (* update miss: 404, never another record *)
1524
+ if is_nullish ent then respond fctx 404 Noval (Some (jo [("statusText", Str "Not found")]))
1472
1525
  else begin
1473
- (match !ent with Map _ -> (match fctx.c_reqdata with Map _ -> List.iter (fun k -> setp !ent k (getp fctx.c_reqdata k)) (keysof fctx.c_reqdata) | _ -> ()) | _ -> ());
1474
- ignore (delprop !ent (Str "$KEY"));
1475
- respond fctx 200 (clone !ent) None
1526
+ (match ent, fctx.c_reqdata with Map _, Map _ -> ignore (merge (ja [ent; fctx.c_reqdata])) | _ -> ());
1527
+ ignore (delprop ent (Str "$KEY"));
1528
+ respond fctx 200 (clone ent) None
1476
1529
  end
1477
1530
  | "remove" ->
1478
1531
  let args = build_args fctx op (resolve_match fctx fctx.c_reqmatch) in
@@ -189,7 +189,9 @@ let make_context_impl (cs : ctxspec) (basectx : ctx option) : ctx =
189
189
  (match getp cr "actor" with Noval -> () | a -> c.ctrl_actor <- a);
190
190
  (match getp cr "paging" with Map _ as m -> c.ctrl_paging <- m | _ -> ());
191
191
  c
192
- | _ -> (match basectx with Some b -> b.c_ctrl | None -> new_control ())
192
+ | _ -> (match basectx with
193
+ | Some b when cs.cs_opname = None -> b.c_ctrl
194
+ | _ -> new_control ())
193
195
  in
194
196
  let meta =
195
197
  match cs.cs_meta with Some (Map _ as m) -> m
@@ -413,7 +415,7 @@ let prepare_query_util (ctx : ctx) : value =
413
415
  let out = empty_map () in
414
416
  List.iter (fun k ->
415
417
  let v = getp reqmatch k in
416
- if not (is_noval v) && not (contains_param k) then setp out k v)
418
+ if not (is_noval v) && k <> "$action" && not (contains_param k) then setp out k v)
417
419
  (keysof reqmatch);
418
420
  out
419
421
 
@@ -555,14 +557,27 @@ let prepare_auth_util = Sdk_prepare_auth.prepare_auth_util
555
557
 
556
558
  (* ----- transforms / result helpers ----- *)
557
559
 
560
+ (* `$action` selects the point (see make_point_util); it is never an API
561
+ field, so the body is a copy without it. The caller's map is left
562
+ untouched. *)
563
+ let strip_action (reqdata : value) : value =
564
+ match reqdata with
565
+ | Map _ when List.mem "$action" (keysof reqdata) ->
566
+ let body = empty_map () in
567
+ List.iter (fun k -> if k <> "$action" then setp body k (getp reqdata k))
568
+ (keysof reqdata);
569
+ body
570
+ | _ -> reqdata
571
+
558
572
  let transform_request_util (ctx : ctx) : value =
559
573
  (match ctx.c_spec with Some s -> s.sp_step <- "reqform" | None -> ());
560
- match to_map (getp ctx.c_point "transform") with
561
- | Map _ as tr ->
562
- (match getp tr "req" with
563
- | Noval -> ctx.c_reqdata
564
- | reqform -> transform (jo [("reqdata", ctx.c_reqdata)]) reqform)
565
- | _ -> ctx.c_reqdata
574
+ strip_action
575
+ (match to_map (getp ctx.c_point "transform") with
576
+ | Map _ as tr ->
577
+ (match getp tr "req" with
578
+ | Noval -> ctx.c_reqdata
579
+ | reqform -> transform (jo [("reqdata", ctx.c_reqdata)]) reqform)
580
+ | _ -> ctx.c_reqdata)
566
581
 
567
582
  let transform_response_util (ctx : ctx) : value =
568
583
  (match ctx.c_spec with Some s -> s.sp_step <- "resform" | None -> ());
@@ -45,7 +45,8 @@ sub new {
45
45
  $self->{ctrl}{actor} = $ctrl_raw->{actor} if exists $ctrl_raw->{actor};
46
46
  $self->{ctrl}{paging} = $ctrl_raw->{paging} if Voxgig::Struct::ismap($ctrl_raw->{paging});
47
47
  }
48
- elsif ($basectx && $basectx->{ctrl}) {
48
+ elsif ($basectx && $basectx->{ctrl}
49
+ && !defined ProjectNameHelpers::get_ctx_prop($ctxmap, 'opname')) {
49
50
  $self->{ctrl} = $basectx->{ctrl};
50
51
  }
51
52