@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
@@ -9,8 +9,8 @@ import SCALAPACKAGE.utility.struct.Struct
9
9
  // stamps page/limit (or a cursor) into the request query; on the way back
10
10
  // (PreResult) it reads the server's pagination signals — a `Link:
11
11
  // rel="next"` header, `X-Page`/`X-Next-Page`/`X-Total-Count` headers, or
12
- // `next`/`cursor`/`nextCursor`/`hasMore` fields in the body — and records
13
- // them on `ctx.result.paging`. A per-call cursor/page from ctrl takes
12
+ // `next`/`cursor`/`nextCursor`/`hasMore` fields in the body (snake_case
13
+ // forms too) — and records them on `ctx.result.paging` and `ctrl.paging`. A per-call cursor/page from ctrl takes
14
14
  // priority (used by auto-iteration). Parameter names (`pageParam`,
15
15
  // `limitParam`, `cursorParam`), the page size (`limit`) and the start page
16
16
  // (`startPage`, default 1) are configurable.
@@ -65,7 +65,10 @@ class PagingFeature extends BaseFeature("paging", "0.0.1", true) {
65
65
  if (cursor != null) {
66
66
  spec.query.put(cursorParam, cursor)
67
67
  } else if (spec.query.get(pageParam) == null) {
68
- val page = paging.get("page")
68
+ // A record written back by preResult holds the page just fetched as
69
+ // "page" and the one to fetch as "nextPage", so nextPage wins.
70
+ var page = paging.get("nextPage")
71
+ if (page == null) page = paging.get("page")
69
72
  if (page != null) {
70
73
  spec.query.put(pageParam, page)
71
74
  } else {
@@ -192,19 +195,37 @@ class PagingFeature extends BaseFeature("paging", "0.0.1", true) {
192
195
  case _ =>
193
196
  }
194
197
 
195
- // Body-level cursors.
198
+ // Body-level signals; snake_case forms are read first so camelCase wins.
196
199
  body match {
197
200
  case bm0: JMap[_, _] =>
198
201
  val bm = bm0.asInstanceOf[JMap[String, Object]]
199
202
  if (bm.get("next") != null && paging.get("next") == null) {
200
203
  paging.put("next", bm.get("next"))
201
204
  }
205
+ if (bm.get("next_cursor") != null) {
206
+ paging.put("cursor", bm.get("next_cursor"))
207
+ }
202
208
  if (bm.get("cursor") != null) {
203
209
  paging.put("cursor", bm.get("cursor"))
204
210
  }
205
211
  if (bm.get("nextCursor") != null) {
206
212
  paging.put("cursor", bm.get("nextCursor"))
207
213
  }
214
+ if (paging.get("nextPage") == null) {
215
+ var np = bm.get("nextPage")
216
+ if (np == null) np = bm.get("next_page")
217
+ np match {
218
+ case n: java.lang.Number => paging.put("nextPage", java.lang.Integer.valueOf(n.intValue()))
219
+ case s: String => paging.put("nextPage", s)
220
+ case _ =>
221
+ }
222
+ }
223
+ bm.get("has_more") match {
224
+ case b: java.lang.Boolean =>
225
+ paging.put("hasMore", b)
226
+ explicitMore = true
227
+ case _ =>
228
+ }
208
229
  bm.get("hasMore") match {
209
230
  case b: java.lang.Boolean =>
210
231
  paging.put("hasMore", b)
@@ -227,6 +248,22 @@ class PagingFeature extends BaseFeature("paging", "0.0.1", true) {
227
248
 
228
249
  result.paging = paging
229
250
  this.last = paging
251
+
252
+ if (ctx.ctrl != null) {
253
+ // The Context shares the caller's paging map by reference, so refill
254
+ // it in place; an immutable map falls back to replacing the reference.
255
+ val shared = ctx.ctrl.paging
256
+ if (shared == null) {
257
+ ctx.ctrl.paging = paging
258
+ } else {
259
+ try {
260
+ shared.clear()
261
+ shared.putAll(paging)
262
+ } catch {
263
+ case _: UnsupportedOperationException => ctx.ctrl.paging = paging
264
+ }
265
+ }
266
+ }
230
267
  }
231
268
 
232
269
  private def isList(ctx: Context): Boolean = {
@@ -50,14 +50,18 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
50
50
  val tm = Struct.getprop(ctx.point, "transform")
51
51
  Struct.getprop(tm, "res") match {
52
52
  case spec: String =>
53
- // Exactly `body.<key>`; a deeper path is not an envelope this mock
54
- // can synthesise, so it is left alone rather than guessed at.
53
+ // Rebuild whatever nesting the transform unwraps. Multi-segment on purpose:
54
+ // GraphQL ops unwrap `body.data.<field>`, not just one envelope property.
55
55
  if (!spec.startsWith("`body.") || !spec.endsWith("`") || spec.length < 8) return data
56
56
  val inner = spec.substring(6, spec.length - 1)
57
- if (inner.isEmpty || inner.contains(".")) return data
58
- val wrapped = new java.util.LinkedHashMap[String, Object]()
59
- wrapped.put(inner, data)
60
- wrapped
57
+ if (inner.isEmpty) return data
58
+ var out: Object = data
59
+ for (seg <- inner.split("\\.", -1).reverse) {
60
+ val wrapped = new java.util.LinkedHashMap[String, Object]()
61
+ wrapped.put(seg, out)
62
+ out = wrapped
63
+ }
64
+ out
61
65
  case _ => data
62
66
  }
63
67
  }
@@ -134,16 +138,10 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
134
138
  if (updateMatch.isEmpty) updateMatch = resolveMatch(ctx, new LinkedHashMap[String, Object]()).asInstanceOf[LinkedHashMap[String, Object]]
135
139
  val args = buildArgs(ctx, op, updateMatch)
136
140
  val found = Struct.select(entmap, args)
137
- var ent = Struct.getelem(found, java.lang.Integer.valueOf(0))
138
- if (ent == null && entmap != null) {
139
- val vit = entmap.values().iterator()
140
- var brk = false
141
- while (vit.hasNext && !brk) {
142
- vit.next() match { case e: JMap[_, _] => ent = e; brk = true; case _ => }
143
- }
144
- }
141
+ val ent = Struct.getelem(found, java.lang.Integer.valueOf(0))
142
+ // update miss: 404, never another record
145
143
  if (ent == null) return respond(ctx, 404, null, extra("statusText", "Not found"))
146
- ent match { case m: JMap[_, _] if ctx.reqdata != null => m.asInstanceOf[JMap[String, Object]].putAll(ctx.reqdata); case _ => }
144
+ ent match { case _: JMap[_, _] if ctx.reqdata != null => Struct.merge(Struct.jt(ent, ctx.reqdata)); case _ => }
147
145
  Struct.delprop(ent, "$KEY")
148
146
  val out = Struct.clone(ent)
149
147
  respond(ctx, 200, out, null)
@@ -277,9 +275,14 @@ class TestFeature extends BaseFeature("test", "0.0.1", true) {
277
275
  case _ =>
278
276
  }
279
277
 
280
- val paramsPath = Struct.getpath(point, java.util.List.of("args", "params"))
281
- val reqdParams = Struct.select(paramsPath, Struct.jm("reqd", java.lang.Boolean.TRUE))
282
- val reqd = Struct.transform(reqdParams, Struct.jt("`$EACH`", "", "`$KEY.name`"))
278
+ // Path AND query: a path-only read misses a query-addressed record
279
+ // (e.g. GET /result?trace_id=), which has no path param at all.
280
+ val reqdArgs = Struct.jt()
281
+ for (kind <- List("params", "query")) {
282
+ val argsPath = Struct.getpath(point, java.util.List.of("args", kind))
283
+ reqdArgs.addAll(Struct.select(argsPath, Struct.jm("reqd", java.lang.Boolean.TRUE)))
284
+ }
285
+ val reqd = Struct.transform(reqdArgs, Struct.jt("`$EACH`", "", "`$KEY.name`"))
283
286
 
284
287
  val qand = Struct.jt()
285
288
  val q = Struct.jm("`$AND`", qand)
@@ -3,12 +3,44 @@ package SCALAPACKAGE.utility
3
3
  import java.net.{InetSocketAddress, ProxySelector, URI}
4
4
  import java.net.http.{HttpClient, HttpRequest, HttpResponse}
5
5
  import java.util.{LinkedHashMap, List => JList, Map => JMap}
6
- import java.util.function.{BiFunction, Supplier}
6
+ import java.util.concurrent.ConcurrentHashMap
7
+ import java.util.function.{BiFunction, Function => JFunction, Supplier}
7
8
  import SCALAPACKAGE.core._
8
9
  import SCALAPACKAGE.utility.struct.Struct
9
10
 
10
11
  object Fetcher {
11
12
 
13
+ // Clients keyed by redirect policy and proxy. Each HttpClient owns a
14
+ // connection pool and a selector thread, so one per request reused
15
+ // nothing; one per key pools across calls.
16
+ private val clients = new ConcurrentHashMap[String, HttpClient]()
17
+
18
+ private def clientFor(fetchdef: JMap[String, Object]): HttpClient = {
19
+ // "manual" (set by the station feature's middleware under a hosts
20
+ // policy) returns a 3xx like any other response: an automatic follow
21
+ // would carry injected credentials to a host no policy approved.
22
+ val redirectPolicy =
23
+ if ("manual" == fetchdef.get("redirect")) HttpClient.Redirect.NEVER
24
+ else HttpClient.Redirect.NORMAL
25
+
26
+ val proxy = fetchdef.get("proxy") match { case p: String => p; case _ => "" }
27
+
28
+ clients.computeIfAbsent(redirectPolicy.toString + "|" + proxy,
29
+ new JFunction[String, HttpClient] {
30
+ def apply(key: String): HttpClient = {
31
+ val clientb = HttpClient.newBuilder().followRedirects(redirectPolicy)
32
+ if (proxy != "") {
33
+ try {
34
+ val proxyUri = URI.create(proxy)
35
+ val port = if (proxyUri.getPort < 0) 80 else proxyUri.getPort
36
+ clientb.proxy(ProxySelector.of(new InetSocketAddress(proxyUri.getHost, port)))
37
+ } catch { case _: RuntimeException => }
38
+ }
39
+ clientb.build()
40
+ }
41
+ })
42
+ }
43
+
12
44
  def defaultHttpFetch(fullurl: String, fetchdef: JMap[String, Object]): JMap[String, Object] = {
13
45
  var method = fetchdef.get("method") match { case s: String => s; case _ => "" }
14
46
  if ("" == method) method = "GET"
@@ -40,19 +72,8 @@ object Fetcher {
40
72
  }
41
73
  if (!hasUA) reqb.setHeader("User-Agent", "Mozilla/5.0 (compatible; ProjectNameSDK/1.0)")
42
74
 
43
- val clientb = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL)
44
- fetchdef.get("proxy") match {
45
- case proxy: String if proxy != "" =>
46
- try {
47
- val proxyUri = URI.create(proxy)
48
- val port = if (proxyUri.getPort < 0) 80 else proxyUri.getPort
49
- clientb.proxy(ProxySelector.of(new InetSocketAddress(proxyUri.getHost, port)))
50
- } catch { case _: RuntimeException => }
51
- case _ =>
52
- }
53
-
54
75
  val resp =
55
- try clientb.build().send(reqb.build(), HttpResponse.BodyHandlers.ofString())
76
+ try clientFor(fetchdef).send(reqb.build(), HttpResponse.BodyHandlers.ofString())
56
77
  catch { case e: Exception => throw new RuntimeException("fetch: " + e.getMessage, e) }
57
78
 
58
79
  val headers = new LinkedHashMap[String, Object]()
@@ -79,7 +79,7 @@ object PrepareQuery {
79
79
  val item = it.next()
80
80
  val key = item.get(0) match { case s: String => s; case _ => "" }
81
81
  val v = item.get(1)
82
- if (v != null && !containsStr(params, key)) out.put(key, v)
82
+ if (v != null && "$action" != key && !containsStr(params, key)) out.put(key, v)
83
83
  }
84
84
  out
85
85
  }
@@ -9,15 +9,31 @@ object TransformRequest {
9
9
  if (ctx.spec != null) ctx.spec.step = "reqform"
10
10
 
11
11
  val transform = Helpers.toMapAny(Struct.getprop(ctx.point, "transform"))
12
- if (transform == null) return ctx.reqdata
12
+ if (transform == null) return stripAction(ctx.reqdata)
13
13
 
14
14
  val reqform = Struct.getprop(transform, "req", null)
15
- if (reqform == null) return ctx.reqdata
15
+ if (reqform == null) return stripAction(ctx.reqdata)
16
16
 
17
17
  val data = new LinkedHashMap[String, Object]()
18
18
  data.put("reqdata", ctx.reqdata)
19
19
 
20
- Struct.transform(data, reqform)
20
+ stripAction(Struct.transform(data, reqform))
21
+ }
22
+
23
+ // `$action` selects the point (see MakePoint); it is never an API field, so
24
+ // the body is a copy without it. The caller's map is left untouched.
25
+ private def stripAction(reqdata: Object): Object = {
26
+ reqdata match {
27
+ case src: JMap[_, _] if src.containsKey("$action") =>
28
+ val body = new LinkedHashMap[String, Object]()
29
+ val it = src.asInstanceOf[JMap[String, Object]].entrySet().iterator()
30
+ while (it.hasNext) {
31
+ val e = it.next()
32
+ if ("$action" != e.getKey) body.put(e.getKey, e.getValue)
33
+ }
34
+ body
35
+ case _ => reqdata
36
+ }
21
37
  }
22
38
  }
23
39
 
@@ -56,7 +56,7 @@ public final class Context {
56
56
  if let e = cm.entries["explain"]?.asMap { ctrl.explain = e }
57
57
  if let a = cm.entries["actor"]?.asString { ctrl.actor = a }
58
58
  if let p = cm.entries["paging"]?.asMap { ctrl.paging = p }
59
- } else if let b = basectx {
59
+ } else if let b = basectx, ctxProp(ctxmap, "opname") == nil {
60
60
  ctrl = b.ctrl
61
61
  }
62
62
 
@@ -2,8 +2,8 @@
2
2
  // stamps page/limit (or a cursor) into the request query; on the way back
3
3
  // (PreResult) it reads the server's pagination signals - a `Link:
4
4
  // rel="next"` header, `X-Page`/`X-Next-Page`/`X-Total-Count` headers, or
5
- // `next`/`cursor`/`nextCursor`/`hasMore` fields in the body - and records
6
- // them on `ctx.result.paging`. A per-call cursor/page from ctrl takes
5
+ // `next`/`cursor`/`nextCursor`/`hasMore` fields in the body (snake_case
6
+ // forms too) - and records them on `ctx.result.paging` and `ctrl.paging`. A per-call cursor/page from ctrl takes
7
7
  // priority (used by auto-iteration). Parameter names (`pageParam`,
8
8
  // `limitParam`, `cursorParam`), the page size (`limit`) and the start page
9
9
  // (`startPage`, default 1) are configurable.
@@ -68,8 +68,11 @@ public final class PagingFeature: BaseFeature {
68
68
  } else if isNil(gp(spec.query, pageParam)) {
69
69
  var page: Value? = nil
70
70
  if let paging = paging {
71
+ // A record written back by preResult holds the page just fetched as
72
+ // "page" and the one to fetch as "nextPage", so nextPage wins.
73
+ let np = gp(paging, "nextPage")
71
74
  let p = gp(paging, "page")
72
- if !isNil(p) { page = p }
75
+ if !isNil(np) { page = np } else if !isNil(p) { page = p }
73
76
  }
74
77
  spec.query.entries[pageParam] = page ?? .int(Int64(foptInt(options, "startPage", 1)))
75
78
  }
@@ -177,12 +180,16 @@ public final class PagingFeature: BaseFeature {
177
180
  }
178
181
  }
179
182
 
180
- // Body-level cursors.
183
+ // Body-level signals; snake_case forms are read first so camelCase wins.
181
184
  if let bm = body.asMap {
182
185
  let next = gp(bm, "next")
183
186
  if !isNil(next) && isNil(gp(paging, "next")) {
184
187
  paging.entries["next"] = next
185
188
  }
189
+ let snakeCursor = gp(bm, "next_cursor")
190
+ if !isNil(snakeCursor) {
191
+ paging.entries["cursor"] = snakeCursor
192
+ }
186
193
  let cursor = gp(bm, "cursor")
187
194
  if !isNil(cursor) {
188
195
  paging.entries["cursor"] = cursor
@@ -191,6 +198,18 @@ public final class PagingFeature: BaseFeature {
191
198
  if !isNil(nextCursor) {
192
199
  paging.entries["cursor"] = nextCursor
193
200
  }
201
+ if isNil(gp(paging, "nextPage")) {
202
+ var np = gp(bm, "nextPage")
203
+ if isNil(np) { np = gp(bm, "next_page") }
204
+ switch np {
205
+ case .int, .double, .string: paging.entries["nextPage"] = np
206
+ default: break
207
+ }
208
+ }
209
+ if let smb = gp(bm, "has_more").asBool {
210
+ paging.entries["hasMore"] = .bool(smb)
211
+ explicitMore = true
212
+ }
194
213
  if let hmb = gp(bm, "hasMore").asBool {
195
214
  paging.entries["hasMore"] = .bool(hmb)
196
215
  explicitMore = true
@@ -210,6 +229,14 @@ public final class PagingFeature: BaseFeature {
210
229
 
211
230
  result.paging = paging
212
231
  last = paging
232
+
233
+ // VMap is a class, so the caller's map is refilled in place; a fresh map
234
+ // on ctrl never reaches the caller.
235
+ if let shared = ctx.ctrl.paging {
236
+ shared.entries = paging.entries
237
+ } else {
238
+ ctx.ctrl.paging = paging
239
+ }
213
240
  }
214
241
 
215
242
  private func isList(_ ctx: Context) -> Bool {
@@ -16,14 +16,18 @@ private func testEnvelope(_ ctx: Context, _ data: Value) -> Value {
16
16
  guard let point = ctx.point else { return data }
17
17
  guard case .map(let tm)? = point.entries["transform"] else { return data }
18
18
  guard case .string(let spec)? = tm.entries["res"] else { return data }
19
- // Exactly `body.<key>`; a deeper path is not an envelope this mock can
20
- // synthesise, so it is left alone rather than guessed at.
19
+ // Rebuild whatever nesting the transform unwraps. Multi-segment on purpose:
20
+ // GraphQL ops unwrap `body.data.<field>`, not just one envelope property.
21
21
  guard spec.hasPrefix("`body."), spec.hasSuffix("`"), spec.count >= 8 else { return data }
22
22
  let inner = String(spec.dropFirst(6).dropLast(1))
23
- guard !inner.isEmpty, !inner.contains(".") else { return data }
24
- let wrapped = VMap()
25
- wrapped.entries[inner] = data
26
- return .map(wrapped)
23
+ guard !inner.isEmpty else { return data }
24
+ var out = data
25
+ for seg in inner.split(separator: ".", omittingEmptySubsequences: false).reversed() {
26
+ let wrapped = VMap()
27
+ wrapped.entries[String(seg)] = out
28
+ out = .map(wrapped)
29
+ }
30
+ return out
27
31
  }
28
32
 
29
33
  private func testRespond(_ ctx: Context, _ status: Int, _ data: Value, _ extra: VMap?) -> Value {
@@ -89,9 +93,14 @@ private func testBuildArgs(_ ctx: Context, _ op: Operation, _ args: VMap?) -> Va
89
93
  }
90
94
  }
91
95
 
92
- let paramsPath = getpath(point, jtp("args", "params"))
93
- let reqdParams = select(paramsPath, .map(vm(("reqd", .bool(true)))))
94
- let reqd = transform(reqdParams, jtp("`$EACH`", "", "`$KEY.name`"))
96
+ // Path AND query: a path-only read misses a query-addressed record
97
+ // (e.g. GET /result?trace_id=), which has no path param at all.
98
+ let reqdArgs = VList()
99
+ for kind in ["params", "query"] {
100
+ let argsPath = getpath(point, jtp("args", kind))
101
+ reqdArgs.items.append(contentsOf: select(argsPath, .map(vm(("reqd", .bool(true))))).asList?.items ?? [])
102
+ }
103
+ let reqd = transform(.list(reqdArgs), jtp("`$EACH`", "", "`$KEY.name`"))
95
104
 
96
105
  let qand = VList()
97
106
  let q = VMap()
@@ -202,17 +211,15 @@ public final class TestFeature: BaseFeature {
202
211
  }
203
212
  let args = testBuildArgs(ctx2, op, updateMatch)
204
213
  let found = select(.map(entmap), args)
205
- var ent = getelem(found, .int(0))
206
- if isNil(ent) {
207
- for (_, e) in entmap.entries where e.isMap { ent = e; break }
208
- }
214
+ let ent = getelem(found, .int(0))
209
215
  if isNil(ent) {
216
+ // update miss: 404, never another record
210
217
  let extra = VMap()
211
218
  extra.entries["statusText"] = .string("Not found")
212
219
  return testRespond(ctx2, 404, .noval, extra)
213
220
  }
214
- if let entm = ent.asMap {
215
- for (k, v) in ctx2.reqdata.entries { entm.entries[k] = v }
221
+ if ent.isMap {
222
+ _ = merge(.list(VList([ent, .map(ctx2.reqdata)])))
216
223
  }
217
224
  delprop(ent, .string("$KEY"))
218
225
  return testRespond(ctx2, 200, clone(ent), nil)
@@ -6,7 +6,21 @@ import Foundation
6
6
  import FoundationNetworking
7
7
  #endif
8
8
 
9
- // Non-following twin of URLSession.shared. The station feature's
9
+ // Cookies OFF on both sessions: the process-wide session carries the
10
+ // process-wide cookie storage, so one call's Set-Cookie would come back on
11
+ // the next, under a different credential. Pooling is per configuration and
12
+ // is unaffected.
13
+ private func cookielessConfiguration() -> URLSessionConfiguration {
14
+ let cfg = URLSessionConfiguration.default
15
+ cfg.httpCookieStorage = nil
16
+ cfg.httpShouldSetCookies = false
17
+ cfg.httpCookieAcceptPolicy = .never
18
+ return cfg
19
+ }
20
+
21
+ private let defaultSession = URLSession(configuration: cookielessConfiguration())
22
+
23
+ // Non-following twin of defaultSession. The station feature's
10
24
  // middleware sets `redirect: manual` on the fetch definition under a
11
25
  // hosts egress policy: a 3xx must come back as a response like any
12
26
  // other, because an automatic follow would carry injected credentials
@@ -25,7 +39,8 @@ private final class ManualRedirectDelegate: NSObject, URLSessionTaskDelegate {
25
39
  }
26
40
 
27
41
  private let manualRedirectSession = URLSession(
28
- configuration: .default, delegate: ManualRedirectDelegate(), delegateQueue: nil)
42
+ configuration: cookielessConfiguration(),
43
+ delegate: ManualRedirectDelegate(), delegateQueue: nil)
29
44
 
30
45
  func defaultHttpFetch(_ fullurl: String, _ fetchdef: VMap) throws -> Value {
31
46
  guard let url = URL(string: fullurl) else {
@@ -59,6 +74,10 @@ func defaultHttpFetch(_ fullurl: String, _ fetchdef: VMap) throws -> Value {
59
74
  req.setValue("Mozilla/5.0 (compatible; ProjectNameSDK/1.0)", forHTTPHeaderField: "User-Agent")
60
75
  }
61
76
 
77
+ // Also per request, so no store reached another way can rewrite the
78
+ // Cookie header set above — an `apiKey in: cookie` scheme sets one.
79
+ req.httpShouldHandleCookies = false
80
+
62
81
  final class FetchBox: @unchecked Sendable {
63
82
  var data: Data?
64
83
  var resp: URLResponse?
@@ -67,7 +86,7 @@ func defaultHttpFetch(_ fullurl: String, _ fetchdef: VMap) throws -> Value {
67
86
  let box = FetchBox()
68
87
  let sem = DispatchSemaphore(value: 0)
69
88
  let session = gp(fetchdef, "redirect").asString == "manual"
70
- ? manualRedirectSession : URLSession.shared
89
+ ? manualRedirectSession : defaultSession
71
90
  let task = session.dataTask(with: req) { d, r, e in
72
91
  box.data = d; box.resp = r; box.err = e; sem.signal()
73
92
  }
@@ -71,7 +71,7 @@ func prepareQueryUtil(_ ctx: Context) -> VMap {
71
71
  for item in items(.map(reqmatch)) {
72
72
  let key = item[0].asString ?? ""
73
73
  let val = item[1]
74
- if !isNil(val) && !containsStr(paramnames, key) {
74
+ if !isNil(val) && "$action" != key && !containsStr(paramnames, key) {
75
75
  query.entries[key] = val
76
76
  }
77
77
  }
@@ -54,14 +54,25 @@ func resultHeadersUtil(_ ctx: Context) -> Result {
54
54
  return result!
55
55
  }
56
56
 
57
+ // `$action` selects the point (see makePointUtil); it is never an API field,
58
+ // so the body is a copy without it. The caller's map is left untouched.
59
+ private func stripAction(_ reqdata: Value) -> Value {
60
+ guard let src = reqdata.asMap, src.entries["$action"] != nil else { return reqdata }
61
+ let body = VMap()
62
+ for (key, val) in src.entries where "$action" != key {
63
+ body.entries[key] = val
64
+ }
65
+ return .map(body)
66
+ }
67
+
57
68
  func transformRequestUtil(_ ctx: Context) -> Value {
58
69
  if let sp = ctx.spec { sp.step = "reqform" }
59
70
 
60
- guard let tfm = gp(ctx.point, "transform").asMap else { return .map(ctx.reqdata) }
71
+ guard let tfm = gp(ctx.point, "transform").asMap else { return stripAction(.map(ctx.reqdata)) }
61
72
  let reqform = gp(tfm, "req")
62
- if isNil(reqform) { return .map(ctx.reqdata) }
73
+ if isNil(reqform) { return stripAction(.map(ctx.reqdata)) }
63
74
 
64
- return transform(.map(vm(("reqdata", .map(ctx.reqdata)))), reqform)
75
+ return stripAction(transform(.map(vm(("reqdata", .map(ctx.reqdata)))), reqform))
65
76
  }
66
77
 
67
78
  func transformResponseUtil(_ ctx: Context) -> Value {
@@ -58,7 +58,13 @@ class Context {
58
58
  this.client = getprop(ctxmap, 'client', getprop(basectx, 'client'))
59
59
  this.utility = getprop(ctxmap, 'utility', getprop(basectx, 'utility'))
60
60
 
61
- this.ctrl = getprop(ctxmap, 'ctrl', getprop(basectx, 'ctrl', this.ctrl))
61
+ // An operation gets its OWN control unless the caller passed one: a
62
+ // paging cursor left on the client's control would otherwise be picked
63
+ // up by the next, unrelated call. A context with no opname is not an
64
+ // operation, so it still shares (an entity's, with the client's).
65
+ const opname = getprop(ctxmap, 'opname')
66
+ const basectrl = null == opname ? getprop(basectx, 'ctrl', this.ctrl) : this.ctrl
67
+ this.ctrl = getprop(ctxmap, 'ctrl', basectrl)
62
68
  this.meta = getprop(ctxmap, 'meta', getprop(basectx, 'meta', this.meta))
63
69
 
64
70
  this.config = getprop(ctxmap, 'config', getprop(basectx, 'config'))
@@ -79,7 +85,6 @@ class Context {
79
85
  this.result = getprop(ctxmap, 'result', getprop(basectx, 'result'))
80
86
  this.response = getprop(ctxmap, 'response', getprop(basectx, 'response'))
81
87
 
82
- const opname = getprop(ctxmap, 'opname')
83
88
  this.op = this.resolveOp(opname)
84
89
  }
85
90
 
@@ -22,7 +22,7 @@ class PagingFeature extends BaseFeature {
22
22
 
23
23
 
24
24
  PreRequest(this: any, ctx: any) {
25
- if (!this._isList(ctx)) {
25
+ if (!this.active || !this._isList(ctx)) {
26
26
  return
27
27
  }
28
28
  const spec = ctx.spec
@@ -51,7 +51,10 @@ class PagingFeature extends BaseFeature {
51
51
  spec.query[cursorParam] = paging.cursor
52
52
  }
53
53
  else if (null == spec.query[pageParam]) {
54
- spec.query[pageParam] = null != paging.page ? paging.page : (this._options.startPage || 1)
54
+ // A record written back by PreResult holds the page just fetched as
55
+ // `page` and the one to fetch as `nextPage`, so nextPage wins.
56
+ spec.query[pageParam] = null != paging.nextPage ? paging.nextPage :
57
+ null != paging.page ? paging.page : (this._options.startPage || 1)
55
58
  }
56
59
 
57
60
  if (null != this._options.limit && null == spec.query[limitParam]) {
@@ -61,7 +64,7 @@ class PagingFeature extends BaseFeature {
61
64
 
62
65
 
63
66
  PreResult(this: any, ctx: any) {
64
- if (!this._isList(ctx)) {
67
+ if (!this.active || !this._isList(ctx)) {
65
68
  return
66
69
  }
67
70
  const result = ctx.result
@@ -118,8 +121,17 @@ class PagingFeature extends BaseFeature {
118
121
 
119
122
  if (body && 'object' === typeof body) {
120
123
  if (null != body.next) { paging.next = paging.next || body.next }
124
+ if (null != body.next_cursor) { paging.cursor = body.next_cursor }
121
125
  if (null != body.cursor) { paging.cursor = body.cursor }
122
126
  if (null != body.nextCursor) { paging.cursor = body.nextCursor }
127
+ if (null == paging.nextPage) {
128
+ const np = null != body.nextPage ? body.nextPage : body.next_page
129
+ if ('number' === typeof np || 'string' === typeof np) { paging.nextPage = np }
130
+ }
131
+ if ('boolean' === typeof body.has_more) {
132
+ paging.hasMore = body.has_more
133
+ explicitMore = true
134
+ }
123
135
  if ('boolean' === typeof body.hasMore) {
124
136
  paging.hasMore = body.hasMore
125
137
  explicitMore = true
@@ -138,6 +150,10 @@ class PagingFeature extends BaseFeature {
138
150
 
139
151
  result.paging = paging
140
152
 
153
+ if (null != ctx.ctrl) {
154
+ ctx.ctrl.paging = paging
155
+ }
156
+
141
157
  const client: any = this._client
142
158
  client._paging = { last: paging }
143
159
  }
@@ -193,6 +193,7 @@ class TestFeature extends BaseFeature {
193
193
  const found = select(entmap, args)
194
194
  const ent = getelem(found, 0)
195
195
  if (null == ent) {
196
+ // update miss: 404, never another record
196
197
  return respond(404, undefined, { statusText: S_NOT_FOUND })
197
198
  }
198
199
  else {
@@ -237,6 +238,8 @@ class TestFeature extends BaseFeature {
237
238
  const out = clone(ent)
238
239
  return respond(200, out)
239
240
  }
241
+
242
+ return respond(404, undefined, { statusText: 'Unknown operation' })
240
243
  }
241
244
 
242
245
  // Optional network behaviour simulation over the mock transport. Enable
@@ -16,7 +16,7 @@ function prepareQuery(ctx: Context) {
16
16
 
17
17
  const out: any = {}
18
18
  for (let [key, val] of items(reqmatch)) {
19
- if (null != val && !params.includes(key)) {
19
+ if (null != val && '$action' !== key && !params.includes(key)) {
20
20
  out[key] = val
21
21
  }
22
22
  }
@@ -206,6 +206,7 @@ describe('FeatureCorpus', () => {
206
206
 
207
207
  const probe: any = makeClient({})
208
208
  if (!probe._rootctx.config.hasFeature(name)) {
209
+ t.diagnostic(`feature.${name}: inert (this SDK does not generate the feature)`)
209
210
  return t.skip(`this SDK was generated without the ${name} feature`)
210
211
  }
211
212