@voxgig/sdkgen 1.5.0 → 2.0.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 (270) hide show
  1. package/dist/cmp/AgentGuideContent.js +5 -0
  2. package/dist/cmp/AgentGuideContent.js.map +1 -1
  3. package/dist/cmp/Feature.js +13 -0
  4. package/dist/cmp/Feature.js.map +1 -1
  5. package/dist/helpers/canonType.d.ts +3 -1
  6. package/dist/helpers/canonType.js +44 -1
  7. package/dist/helpers/canonType.js.map +1 -1
  8. package/dist/helpers/packageMeta.js +7 -0
  9. package/dist/helpers/packageMeta.js.map +1 -1
  10. package/dist/sdkgen.d.ts +3 -3
  11. package/dist/sdkgen.js +4 -1
  12. package/dist/sdkgen.js.map +1 -1
  13. package/dist/tsconfig.tsbuildinfo +1 -1
  14. package/package.json +7 -6
  15. package/project/.sdk/model/feature/paging.aontu +7 -0
  16. package/project/.sdk/model/target/py-data.aontu +64 -0
  17. package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +89 -1
  18. package/project/.sdk/src/cmp/clojure/Main_clojure.ts +1 -0
  19. package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +97 -0
  20. package/project/.sdk/src/cmp/dart/fragment/Main.fragment.dart +78 -0
  21. package/project/.sdk/src/cmp/elixir/fragment/Main.fragment.ex +84 -0
  22. package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +87 -0
  23. package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +75 -0
  24. package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +85 -0
  25. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +4 -0
  26. package/project/.sdk/src/cmp/perl/fragment/Main.fragment.pm +80 -0
  27. package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +86 -0
  28. package/project/.sdk/src/cmp/py/Entity_py.ts +9 -2
  29. package/project/.sdk/src/cmp/py/MainEntity_py.ts +1 -1
  30. package/project/.sdk/src/cmp/py/Main_py.ts +34 -6
  31. package/project/.sdk/src/cmp/py/Package_py.ts +6 -9
  32. package/project/.sdk/src/cmp/py/TestDirect_py.ts +2 -2
  33. package/project/.sdk/src/cmp/py/TestEntity_py.ts +3 -3
  34. package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +2 -2
  35. package/project/.sdk/src/cmp/py/fragment/EntityCreateOp.fragment.py +2 -2
  36. package/project/.sdk/src/cmp/py/fragment/EntityLoadOp.fragment.py +2 -2
  37. package/project/.sdk/src/cmp/py/fragment/EntityRemoveOp.fragment.py +2 -2
  38. package/project/.sdk/src/cmp/py/fragment/EntityUpdateOp.fragment.py +2 -2
  39. package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +75 -8
  40. package/project/.sdk/src/cmp/py-data/Main_py-data.ts +987 -0
  41. package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +71 -0
  42. package/project/.sdk/src/cmp/rust/fragment/Main.fragment.rs +95 -0
  43. package/project/.sdk/src/cmp/swift/fragment/Main.fragment.swift +86 -0
  44. package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +75 -0
  45. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +95 -0
  46. package/project/.sdk/tm/c/core/sdk.h +7 -0
  47. package/project/.sdk/tm/c/feature/paging.c +141 -2
  48. package/project/.sdk/tm/c/utility/graphql.c +178 -0
  49. package/project/.sdk/tm/c/utility/make_options.c +1 -1
  50. package/project/.sdk/tm/c/utility/make_response.c +6 -0
  51. package/project/.sdk/tm/c/utility/make_spec.c +23 -3
  52. package/project/.sdk/tm/clojure/src/sdk/client.clj +64 -1
  53. package/project/.sdk/tm/clojure/src/sdk/core.clj +126 -3
  54. package/project/.sdk/tm/clojure/src/sdk/features.clj +80 -14
  55. package/project/.sdk/tm/cpp/core/types.hpp +83 -0
  56. package/project/.sdk/tm/cpp/feature/paging.hpp +103 -1
  57. package/project/.sdk/tm/cpp/utility/pipeline.hpp +152 -3
  58. package/project/.sdk/tm/csharp/core/Utility.cs +4 -0
  59. package/project/.sdk/tm/csharp/feature/PagingFeature.cs +118 -1
  60. package/project/.sdk/tm/csharp/utility/Graphql.cs +190 -0
  61. package/project/.sdk/tm/csharp/utility/MakeOptions.cs +1 -1
  62. package/project/.sdk/tm/csharp/utility/MakeResponse.cs +7 -0
  63. package/project/.sdk/tm/csharp/utility/MakeSpec.cs +21 -2
  64. package/project/.sdk/tm/csharp/utility/Register.cs +2 -0
  65. package/project/.sdk/tm/dart/lib/Point.dart +7 -0
  66. package/project/.sdk/tm/dart/lib/feature/paging/PagingFeature.dart +99 -4
  67. package/project/.sdk/tm/dart/lib/utility/GraphqlUtility.dart +162 -0
  68. package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +1 -1
  69. package/project/.sdk/tm/dart/lib/utility/MakeResponseUtility.dart +5 -0
  70. package/project/.sdk/tm/dart/lib/utility/MakeSpecUtility.dart +18 -2
  71. package/project/.sdk/tm/dart/lib/utility/PrepareMethodUtility.dart +6 -1
  72. package/project/.sdk/tm/dart/lib/utility/Utility.dart +9 -0
  73. package/project/.sdk/tm/elixir/lib/projectname/feature/paging.ex +136 -13
  74. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +187 -3
  75. package/project/.sdk/tm/go/core/utility_type.go +2 -0
  76. package/project/.sdk/tm/go/feature/paging_feature.go +87 -1
  77. package/project/.sdk/tm/go/utility/graphql.go +168 -0
  78. package/project/.sdk/tm/go/utility/make_options.go +1 -1
  79. package/project/.sdk/tm/go/utility/make_response.go +6 -0
  80. package/project/.sdk/tm/go/utility/make_spec.go +19 -2
  81. package/project/.sdk/tm/go/utility/register.go +2 -0
  82. package/project/.sdk/tm/haskell/src/SdkFeatures.hs +146 -7
  83. package/project/.sdk/tm/haskell/src/SdkRuntime.hs +153 -3
  84. package/project/.sdk/tm/java/core/SdkClient.java +93 -0
  85. package/project/.sdk/tm/java/core/Utility.java +4 -0
  86. package/project/.sdk/tm/java/feature/PagingFeature.java +100 -1
  87. package/project/.sdk/tm/java/utility/Graphql.java +191 -0
  88. package/project/.sdk/tm/java/utility/MakeOptions.java +1 -1
  89. package/project/.sdk/tm/java/utility/MakeResponse.java +6 -0
  90. package/project/.sdk/tm/java/utility/MakeSpec.java +17 -2
  91. package/project/.sdk/tm/java/utility/Register.java +2 -0
  92. package/project/.sdk/tm/js/src/Point.js +5 -0
  93. package/project/.sdk/tm/js/src/feature/paging/PagingFeature.js +82 -3
  94. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +14 -2
  95. package/project/.sdk/tm/js/src/utility/GraphqlUtility.js +148 -0
  96. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +1 -1
  97. package/project/.sdk/tm/js/src/utility/MakeResponseUtility.js +7 -0
  98. package/project/.sdk/tm/js/src/utility/MakeSpecUtility.js +19 -2
  99. package/project/.sdk/tm/js/src/utility/Utility.js +4 -0
  100. package/project/.sdk/tm/kotlin/core/SdkClient.kt +84 -0
  101. package/project/.sdk/tm/kotlin/core/Utility.kt +2 -0
  102. package/project/.sdk/tm/kotlin/feature/PagingFeature.kt +92 -1
  103. package/project/.sdk/tm/kotlin/utility/Graphql.kt +145 -0
  104. package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +1 -1
  105. package/project/.sdk/tm/kotlin/utility/MakeReqRes.kt +6 -0
  106. package/project/.sdk/tm/kotlin/utility/MakeSpecUrl.kt +17 -2
  107. package/project/.sdk/tm/kotlin/utility/Register.kt +2 -0
  108. package/project/.sdk/tm/lean/src/SdkUtility.lean +134 -1
  109. package/project/.sdk/tm/lua/feature/paging_feature.lua +97 -2
  110. package/project/.sdk/tm/lua/utility/graphql.lua +163 -0
  111. package/project/.sdk/tm/lua/utility/make_options.lua +1 -1
  112. package/project/.sdk/tm/lua/utility/make_response.lua +6 -0
  113. package/project/.sdk/tm/lua/utility/make_spec.lua +18 -2
  114. package/project/.sdk/tm/lua/utility/register.lua +3 -0
  115. package/project/.sdk/tm/ocaml/sdk_features.ml +164 -20
  116. package/project/.sdk/tm/ocaml/sdk_runtime.ml +143 -4
  117. package/project/.sdk/tm/ocaml/sdk_types.ml +2 -0
  118. package/project/.sdk/tm/perl/feature/paging_feature.pm +91 -3
  119. package/project/.sdk/tm/perl/utility/graphql.pm +150 -0
  120. package/project/.sdk/tm/perl/utility/make_options.pm +1 -1
  121. package/project/.sdk/tm/perl/utility/make_response.pm +6 -0
  122. package/project/.sdk/tm/perl/utility/make_spec.pm +20 -2
  123. package/project/.sdk/tm/perl/utility/register.pm +1 -0
  124. package/project/.sdk/tm/php/core/UtilityType.php +2 -0
  125. package/project/.sdk/tm/php/feature/PagingFeature.php +106 -4
  126. package/project/.sdk/tm/php/utility/Graphql.php +176 -0
  127. package/project/.sdk/tm/php/utility/MakeOptions.php +1 -1
  128. package/project/.sdk/tm/php/utility/MakeResponse.php +7 -0
  129. package/project/.sdk/tm/php/utility/MakeSpec.php +20 -2
  130. package/project/.sdk/tm/php/utility/Register.php +3 -0
  131. package/project/.sdk/tm/py/pkg/core/__init__.py +0 -0
  132. package/project/.sdk/tm/py/{core → pkg/core}/context.py +8 -8
  133. package/project/.sdk/tm/py/{core → pkg/core}/operation.py +1 -1
  134. package/project/.sdk/tm/py/{core → pkg/core}/response.py +1 -1
  135. package/project/.sdk/tm/py/{core → pkg/core}/result.py +1 -1
  136. package/project/.sdk/tm/py/{core → pkg/core}/utility_type.py +2 -0
  137. package/project/.sdk/tm/py/pkg/entity/__init__.py +0 -0
  138. package/project/.sdk/tm/py/pkg/feature/__init__.py +0 -0
  139. package/project/.sdk/tm/py/{feature → pkg/feature}/audit_feature.py +1 -1
  140. package/project/.sdk/tm/py/{feature → pkg/feature}/cache_feature.py +1 -1
  141. package/project/.sdk/tm/py/{feature → pkg/feature}/clienttrack_feature.py +1 -1
  142. package/project/.sdk/tm/py/{feature → pkg/feature}/debug_feature.py +1 -1
  143. package/project/.sdk/tm/py/{feature → pkg/feature}/idempotency_feature.py +1 -1
  144. package/project/.sdk/tm/py/{feature → pkg/feature}/log_feature.py +1 -1
  145. package/project/.sdk/tm/py/{feature → pkg/feature}/metrics_feature.py +1 -1
  146. package/project/.sdk/tm/py/{feature → pkg/feature}/netsim_feature.py +1 -1
  147. package/project/.sdk/tm/py/{feature → pkg/feature}/paging_feature.py +87 -6
  148. package/project/.sdk/tm/py/{feature → pkg/feature}/proxy_feature.py +1 -1
  149. package/project/.sdk/tm/py/{feature → pkg/feature}/ratelimit_feature.py +1 -1
  150. package/project/.sdk/tm/py/{feature → pkg/feature}/rbac_feature.py +1 -1
  151. package/project/.sdk/tm/py/{feature → pkg/feature}/retry_feature.py +1 -1
  152. package/project/.sdk/tm/py/{feature → pkg/feature}/streaming_feature.py +1 -1
  153. package/project/.sdk/tm/py/{feature → pkg/feature}/telemetry_feature.py +1 -1
  154. package/project/.sdk/tm/py/{feature → pkg/feature}/test_feature.py +2 -2
  155. package/project/.sdk/tm/py/{feature → pkg/feature}/timeout_feature.py +1 -1
  156. package/project/.sdk/tm/py/pkg/utility/__init__.py +0 -0
  157. package/project/.sdk/tm/py/{utility → pkg/utility}/feature_init.py +1 -1
  158. package/project/.sdk/tm/py/{utility → pkg/utility}/fetcher.py +1 -1
  159. package/project/.sdk/tm/py/pkg/utility/graphql.py +145 -0
  160. package/project/.sdk/tm/py/{utility → pkg/utility}/make_context.py +1 -1
  161. package/project/.sdk/tm/py/{utility → pkg/utility}/make_error.py +5 -5
  162. package/project/.sdk/tm/py/{utility → pkg/utility}/make_fetch_def.py +2 -2
  163. package/project/.sdk/tm/py/{utility → pkg/utility}/make_options.py +2 -2
  164. package/project/.sdk/tm/py/{utility → pkg/utility}/make_point.py +2 -2
  165. package/project/.sdk/tm/py/{utility → pkg/utility}/make_request.py +2 -2
  166. package/project/.sdk/tm/py/{utility → pkg/utility}/make_response.py +6 -0
  167. package/project/.sdk/tm/py/{utility → pkg/utility}/make_spec.py +19 -4
  168. package/project/.sdk/tm/py/{utility → pkg/utility}/make_url.py +1 -1
  169. package/project/.sdk/tm/py/{utility → pkg/utility}/param.py +2 -2
  170. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_auth.py +1 -1
  171. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_headers.py +1 -1
  172. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_method.py +1 -1
  173. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_params.py +1 -1
  174. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_path.py +1 -1
  175. package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_query.py +1 -1
  176. package/project/.sdk/tm/py/pkg/utility/register.py +71 -0
  177. package/project/.sdk/tm/py/{utility → pkg/utility}/transform_request.py +2 -2
  178. package/project/.sdk/tm/py/{utility → pkg/utility}/transform_response.py +2 -2
  179. package/project/.sdk/tm/py/test/feature_harness.py +6 -6
  180. package/project/.sdk/tm/py/test/runner.py +1 -1
  181. package/project/.sdk/tm/py/test/struct_runner.py +1 -1
  182. package/project/.sdk/tm/py/test/test_pipeline.py +5 -5
  183. package/project/.sdk/tm/py/test/test_primary_utility.py +8 -8
  184. package/project/.sdk/tm/py/test/test_struct_utility.py +3 -3
  185. package/project/.sdk/tm/py-data/LICENSE +22 -0
  186. package/project/.sdk/tm/py-data/Makefile +57 -0
  187. package/project/.sdk/tm/py-data/pkg/auth.py +131 -0
  188. package/project/.sdk/tm/py-data/pkg/fetch.py +178 -0
  189. package/project/.sdk/tm/py-data/pkg/frames.py +236 -0
  190. package/project/.sdk/tm/py-data/src/feature/README.md +8 -0
  191. package/project/.sdk/tm/py-data/src/feature/debug/.gitkeep +0 -0
  192. package/project/.sdk/tm/py-data/src/feature/idempotency/.gitkeep +0 -0
  193. package/project/.sdk/tm/py-data/src/feature/log/.gitkeep +0 -0
  194. package/project/.sdk/tm/py-data/src/feature/metrics/.gitkeep +0 -0
  195. package/project/.sdk/tm/py-data/src/feature/netsim/.gitkeep +0 -0
  196. package/project/.sdk/tm/py-data/src/feature/paging/.gitkeep +0 -0
  197. package/project/.sdk/tm/py-data/src/feature/proxy/.gitkeep +0 -0
  198. package/project/.sdk/tm/py-data/src/feature/ratelimit/.gitkeep +0 -0
  199. package/project/.sdk/tm/py-data/src/feature/rbac/.gitkeep +0 -0
  200. package/project/.sdk/tm/py-data/src/feature/retry/.gitkeep +0 -0
  201. package/project/.sdk/tm/py-data/src/feature/streaming/.gitkeep +0 -0
  202. package/project/.sdk/tm/py-data/src/feature/telemetry/.gitkeep +0 -0
  203. package/project/.sdk/tm/py-data/src/feature/test/.gitkeep +0 -0
  204. package/project/.sdk/tm/py-data/src/feature/timeout/.gitkeep +0 -0
  205. package/project/.sdk/tm/py-data/test/__init__.py +0 -0
  206. package/project/.sdk/tm/py-data/test/test_auth.py +95 -0
  207. package/project/.sdk/tm/py-data/test/test_fetch.py +152 -0
  208. package/project/.sdk/tm/py-data/test/test_frames.py +250 -0
  209. package/project/.sdk/tm/rb/core/utility_type.rb +1 -0
  210. package/project/.sdk/tm/rb/feature/paging_feature.rb +89 -3
  211. package/project/.sdk/tm/rb/utility/graphql.rb +131 -0
  212. package/project/.sdk/tm/rb/utility/make_options.rb +1 -1
  213. package/project/.sdk/tm/rb/utility/make_response.rb +6 -0
  214. package/project/.sdk/tm/rb/utility/make_spec.rb +18 -2
  215. package/project/.sdk/tm/rb/utility/register.rb +3 -0
  216. package/project/.sdk/tm/rust/feature/paging.rs +124 -2
  217. package/project/.sdk/tm/rust/utility/graphql.rs +193 -0
  218. package/project/.sdk/tm/rust/utility/make_options.rs +1 -1
  219. package/project/.sdk/tm/rust/utility/make_response.rs +6 -0
  220. package/project/.sdk/tm/rust/utility/make_spec.rs +32 -4
  221. package/project/.sdk/tm/rust/utility/mod.rs +1 -0
  222. package/project/.sdk/tm/scala/core/SdkClient.scala +90 -0
  223. package/project/.sdk/tm/scala/core/Utility.scala +4 -0
  224. package/project/.sdk/tm/scala/feature/PagingFeature.scala +104 -3
  225. package/project/.sdk/tm/scala/utility/Graphql.scala +160 -0
  226. package/project/.sdk/tm/scala/utility/Make.scala +7 -1
  227. package/project/.sdk/tm/scala/utility/MakeSpec.scala +22 -2
  228. package/project/.sdk/tm/scala/utility/Register.scala +2 -0
  229. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Utility.swift +4 -0
  230. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/PagingFeature.swift +86 -1
  231. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Graphql.swift +142 -0
  232. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Make.swift +24 -2
  233. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +1 -1
  234. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Register.swift +2 -0
  235. package/project/.sdk/tm/ts/src/Point.ts +7 -0
  236. package/project/.sdk/tm/ts/src/feature/paging/PagingFeature.ts +82 -3
  237. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +14 -2
  238. package/project/.sdk/tm/ts/src/utility/GraphqlUtility.ts +152 -0
  239. package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +1 -1
  240. package/project/.sdk/tm/ts/src/utility/MakeResponseUtility.ts +7 -0
  241. package/project/.sdk/tm/ts/src/utility/MakeSpecUtility.ts +19 -2
  242. package/project/.sdk/tm/ts/src/utility/Utility.ts +4 -0
  243. package/project/.sdk/tm/zig/core/utility.zig +198 -3
  244. package/project/.sdk/tm/zig/feature/paging.zig +128 -1
  245. package/src/cmp/AgentGuideContent.ts +5 -0
  246. package/src/cmp/Feature.ts +13 -0
  247. package/src/helpers/canonType.ts +46 -0
  248. package/src/helpers/packageMeta.ts +7 -0
  249. package/src/sdkgen.ts +6 -1
  250. package/project/.sdk/tm/py/utility/register.py +0 -68
  251. /package/project/.sdk/tm/py/{core → pkg/core}/control.py +0 -0
  252. /package/project/.sdk/tm/py/{core → pkg/core}/error.py +0 -0
  253. /package/project/.sdk/tm/py/{core → pkg/core}/helpers.py +0 -0
  254. /package/project/.sdk/tm/py/{core → pkg/core}/spec.py +0 -0
  255. /package/project/.sdk/tm/py/{feature → pkg/feature}/base_feature.py +0 -0
  256. /package/project/.sdk/tm/py/{utility → pkg/utility}/clean.py +0 -0
  257. /package/project/.sdk/tm/py/{utility → pkg/utility}/done.py +0 -0
  258. /package/project/.sdk/tm/py/{utility → pkg/utility}/feature_add.py +0 -0
  259. /package/project/.sdk/tm/py/{utility → pkg/utility}/feature_hook.py +0 -0
  260. /package/project/.sdk/tm/py/{utility → pkg/utility}/make_result.py +0 -0
  261. /package/project/.sdk/tm/py/{utility → pkg/utility}/prepare_body.py +0 -0
  262. /package/project/.sdk/tm/py/{utility → pkg/utility}/result_basic.py +0 -0
  263. /package/project/.sdk/tm/py/{utility → pkg/utility}/result_body.py +0 -0
  264. /package/project/.sdk/tm/py/{utility → pkg/utility}/result_headers.py +0 -0
  265. /package/project/.sdk/tm/py/{utility → pkg/utility}/voxgig_struct/__init__.py +0 -0
  266. /package/project/.sdk/tm/py/{utility → pkg/utility}/voxgig_struct/voxgig_struct.py +0 -0
  267. /package/project/.sdk/tm/{py/core/__init__.py → py-data/src/feature/audit/.gitkeep} +0 -0
  268. /package/project/.sdk/tm/{py/entity/__init__.py → py-data/src/feature/base/.gitkeep} +0 -0
  269. /package/project/.sdk/tm/{py/feature/__init__.py → py-data/src/feature/cache/.gitkeep} +0 -0
  270. /package/project/.sdk/tm/{py/utility/__init__.py → py-data/src/feature/clienttrack/.gitkeep} +0 -0
@@ -0,0 +1,150 @@
1
+ # ProjectName SDK utility: graphql
2
+ #
3
+ # GraphQL transport. API-INDEPENDENT: every GraphQL SDK this generator
4
+ # produces uses this file unchanged. The API-specific part — which
5
+ # operations exist and what each one's document is — is model data,
6
+ # computed once by apidef and emitted into Config.
7
+ #
8
+ # Two jobs:
9
+ #
10
+ # graphql_body — build { query, variables } for a point, binding the
11
+ # op's arguments to the document's declared variables.
12
+ #
13
+ # graphql_errors — lift a GraphQL failure into an SDK error. GraphQL
14
+ # reports failures as a top-level `errors` array under
15
+ # HTTP 200, so the status-driven path in result_basic
16
+ # never sees them.
17
+
18
+ use strict;
19
+ use warnings;
20
+
21
+ use File::Basename ();
22
+ use Cwd ();
23
+
24
+ my $__dir;
25
+ BEGIN { $__dir = File::Basename::dirname(Cwd::abs_path(__FILE__)) }
26
+ require(Cwd::abs_path("$__dir/../lib/Voxgig/Struct.pm"));
27
+ require(Cwd::abs_path("$__dir/../core/helpers.pm"));
28
+
29
+ package ProjectNameUtilities;
30
+
31
+ our %REGISTRY;
32
+
33
+ # Content type every GraphQL-over-HTTP request uses.
34
+ our $GRAPHQL_CONTENT_TYPE = 'application/json';
35
+
36
+ # Map a GraphQL error to the same error codes the HTTP path produces, so a
37
+ # caller handles auth or rate limiting identically on both transports.
38
+ # Servers put the machine-readable code in `extensions.code`; Linear-style
39
+ # APIs use `extensions.type`.
40
+ sub graphql_error_code {
41
+ my ($gqlerr) = @_;
42
+
43
+ my $ext = ProjectNameHelpers::gp($gqlerr, 'extensions');
44
+
45
+ my $raw = ProjectNameHelpers::gp($ext, 'code');
46
+ $raw = ProjectNameHelpers::gp($ext, 'type') if !defined $raw || '' eq $raw;
47
+ $raw = defined $raw ? uc("$raw") : '';
48
+
49
+ return 'request_auth'
50
+ if $raw =~ /AUTH/ || $raw =~ /FORBIDDEN/ || $raw =~ /UNAUTHENTICATED/;
51
+ return 'request_ratelimit'
52
+ if $raw =~ /RATELIMIT/ || $raw =~ /RATE_LIMIT/ || $raw =~ /TOO_MANY/;
53
+ return 'request_invalid'
54
+ if $raw =~ /BAD_USER_INPUT/ || $raw =~ /VALIDATION/ || $raw =~ /INVALID/;
55
+
56
+ return 'request_graphql';
57
+ }
58
+
59
+ # Build the request body for a GraphQL point.
60
+ #
61
+ # Variables come from the op's own arguments: a named variable binds to the
62
+ # like-named argument (`from`), and the input-object variable (empty
63
+ # `from`) takes the request data as a whole — which is what makes a
64
+ # generated create/update call look exactly like its REST equivalent.
65
+ $REGISTRY{graphql_body} = sub {
66
+ my ($ctx) = @_;
67
+
68
+ my $gql = ProjectNameHelpers::gp($ctx->{point}, 'graphql');
69
+ return undef unless ref($gql) eq 'HASH';
70
+
71
+ # reqmatch/reqdata hold the caller's arguments for THIS call; data/match
72
+ # hold the entity's current state. Which pair depends on whether the op
73
+ # takes match or data input. A named variable falls back to the current
74
+ # state, so updating a loaded entity with just {title} still binds the
75
+ # stored id the mutation requires.
76
+ my $datainput =
77
+ $ctx->{op} && defined $ctx->{op}{input} && 'data' eq $ctx->{op}{input};
78
+ my $reqsrc = $datainput ? $ctx->{reqdata} : $ctx->{reqmatch};
79
+ my $datasrc = $datainput ? $ctx->{data} : $ctx->{match};
80
+ $reqsrc = {} unless ref($reqsrc) eq 'HASH';
81
+ $datasrc = {} unless ref($datasrc) eq 'HASH';
82
+
83
+ my %variables;
84
+
85
+ my $varlist = ProjectNameHelpers::gp($gql, 'vars');
86
+ $varlist = [] unless ref($varlist) eq 'ARRAY';
87
+
88
+ for my $spec (@$varlist) {
89
+ next unless ref($spec) eq 'HASH';
90
+
91
+ my $name = ProjectNameHelpers::gp($spec, 'name');
92
+ my $from = ProjectNameHelpers::gp($spec, 'from');
93
+ next unless defined $name;
94
+
95
+ if (!defined $from || '' eq $from) {
96
+ # The input object IS the request body. Strip the action selector,
97
+ # which is an SDK-side point discriminator, not an API field.
98
+ my %body;
99
+ for my $k (keys %$reqsrc) {
100
+ $body{$k} = $reqsrc->{$k} unless '$action' eq $k;
101
+ }
102
+ $variables{$name} = \%body;
103
+ next;
104
+ }
105
+
106
+ # Only send variables the caller actually supplied: sending an explicit
107
+ # null would clear a field on many APIs.
108
+ my $val = ProjectNameHelpers::gp($reqsrc, $from);
109
+ $val = ProjectNameHelpers::gp($datasrc, $from) unless defined $val;
110
+ $variables{$name} = $val if defined $val;
111
+ }
112
+
113
+ return {
114
+ query => ProjectNameHelpers::gp($gql, 'doc'),
115
+ variables => \%variables,
116
+ };
117
+ };
118
+
119
+ # Inspect a decoded GraphQL response body and record a failure when the
120
+ # server reported one. Returns true when an error was recorded.
121
+ #
122
+ # Partial data (`data` alongside `errors`) is treated as failure: the REST
123
+ # surface has no partial-success concept, and silently returning half an
124
+ # object would be worse than failing.
125
+ $REGISTRY{graphql_errors} = sub {
126
+ my ($ctx) = @_;
127
+
128
+ my $result = $ctx->{result};
129
+ return 0 unless $result && $ctx->{point};
130
+
131
+ my $kind = ProjectNameHelpers::gp($ctx->{point}, 'kind');
132
+ return 0 unless defined $kind && 'graphql' eq $kind;
133
+
134
+ my $errors = ProjectNameHelpers::gp($result->{body}, 'errors');
135
+ return 0 unless ref($errors) eq 'ARRAY' && 0 < scalar(@$errors);
136
+
137
+ my $first = $errors->[0];
138
+ my $msg = ProjectNameHelpers::gp($first, 'message');
139
+ $msg = 'graphql error' unless defined $msg && '' ne $msg;
140
+ $msg = $msg . ' (+' . (scalar(@$errors) - 1) . ' more)'
141
+ if 1 < scalar(@$errors);
142
+
143
+ $result->{err} =
144
+ $ctx->make_error(graphql_error_code($first), 'graphql: ' . $msg);
145
+ $result->{ok} = 0;
146
+
147
+ return 1;
148
+ };
149
+
150
+ 1;
@@ -70,7 +70,7 @@ $REGISTRY{make_options} = sub {
70
70
  'headers' => { '`$CHILD`' => '`$STRING`' },
71
71
  'allow' => {
72
72
  'method' => 'GET,PUT,POST,PATCH,DELETE,OPTIONS',
73
- 'op' => 'create,update,load,list,remove,command,direct',
73
+ 'op' => 'create,update,load,list,remove,command,direct,graphql',
74
74
  },
75
75
  'entity' => { '`$CHILD`' => { '`$OPEN`' => $JT, 'active' => $JF, 'alias' => {} } },
76
76
  'feature' => { '`$CHILD`' => { '`$OPEN`' => $JT, 'active' => $JF } },
@@ -27,6 +27,12 @@ $REGISTRY{make_response} = sub {
27
27
  $utility->{result_basic}->($ctx);
28
28
  $utility->{result_headers}->($ctx);
29
29
  $utility->{result_body}->($ctx);
30
+
31
+ # GraphQL reports failures as a top-level `errors` array under HTTP 200,
32
+ # so result_basic's status check never sees them. Lift them here, before
33
+ # the response transform tries to unwrap data that is not there.
34
+ $utility->{graphql_errors}->($ctx);
35
+
30
36
  $utility->{transform_response}->($ctx);
31
37
 
32
38
  $result->{ok} = 1 if !defined $result->{err};
@@ -56,8 +56,26 @@ $REGISTRY{make_spec} = sub {
56
56
  $ctx->{spec}{params} = $utility->{prepare_params}->($ctx);
57
57
  $ctx->{spec}{query} = $utility->{prepare_query}->($ctx);
58
58
  $ctx->{spec}{headers} = $utility->{prepare_headers}->($ctx);
59
- $ctx->{spec}{body} = $utility->{prepare_body}->($ctx);
60
- $ctx->{spec}{path} = $utility->{prepare_path}->($ctx);
59
+
60
+ my $pkind = ProjectNameHelpers::gp($ctx->{point}, 'kind');
61
+ if (defined $pkind && 'graphql' eq $pkind) {
62
+ # GraphQL addresses one endpoint: no path parts, no query string, and
63
+ # the body carries the operation. prepare_body is skipped deliberately
64
+ # — it only emits a body for data-input ops, whereas every GraphQL op
65
+ # posts one, including load/list/remove.
66
+ $ctx->{spec}{body} = $utility->{graphql_body}->($ctx);
67
+ $ctx->{spec}{path} = '';
68
+ # prepare_query already copied the op's match arguments into the query
69
+ # string. Those same values are bound as operation variables, so
70
+ # leaving them would send /graphql?id=i1.
71
+ $ctx->{spec}{query} = {};
72
+ $ctx->{spec}{headers}{'content-type'} =
73
+ $ProjectNameUtilities::GRAPHQL_CONTENT_TYPE;
74
+ }
75
+ else {
76
+ $ctx->{spec}{body} = $utility->{prepare_body}->($ctx);
77
+ $ctx->{spec}{path} = $utility->{prepare_path}->($ctx);
78
+ }
61
79
 
62
80
  $ctx->{ctrl}{explain}{spec} = $ctx->{spec} if $ctx->{ctrl}{explain};
63
81
 
@@ -35,6 +35,7 @@ require(Cwd::abs_path("$__dir/prepare_method.pm"));
35
35
  require(Cwd::abs_path("$__dir/prepare_params.pm"));
36
36
  require(Cwd::abs_path("$__dir/prepare_path.pm"));
37
37
  require(Cwd::abs_path("$__dir/prepare_query.pm"));
38
+ require(Cwd::abs_path("$__dir/graphql.pm"));
38
39
  require(Cwd::abs_path("$__dir/result_basic.pm"));
39
40
  require(Cwd::abs_path("$__dir/result_body.pm"));
40
41
  require(Cwd::abs_path("$__dir/result_headers.pm"));
@@ -29,6 +29,8 @@ class ProjectNameUtility
29
29
  public mixed $prepare_params = null;
30
30
  public mixed $prepare_path = null;
31
31
  public mixed $prepare_query = null;
32
+ public mixed $graphql_body = null;
33
+ public mixed $graphql_errors = null;
32
34
  public mixed $result_basic = null;
33
35
  public mixed $result_body = null;
34
36
  public mixed $result_headers = null;
@@ -57,6 +57,15 @@ class ProjectNamePagingFeature extends ProjectNameBaseFeature
57
57
  $paging = [];
58
58
  }
59
59
 
60
+ // GraphQL paginates through operation VARIABLES, not the query
61
+ // string. This hook runs after makeSpec, so spec->body already holds
62
+ // the { query, variables } envelope, and before makeFetchDef
63
+ // serialises it.
64
+ if ('graphql' === \Voxgig\Struct\Struct::getprop($ctx->point, 'kind')) {
65
+ $this->_graphql_pre_request($ctx, $paging);
66
+ return;
67
+ }
68
+
60
69
  if (($paging['cursor'] ?? null) !== null) {
61
70
  $spec->query[$cursor_param] = $paging['cursor'];
62
71
  } elseif (($spec->query[$page_param] ?? null) === null) {
@@ -72,6 +81,53 @@ class ProjectNamePagingFeature extends ProjectNameBaseFeature
72
81
  }
73
82
  }
74
83
 
84
+ // Relay pagination: the cursor is the `after` variable (or whatever the
85
+ // model named it), and the page size is `first`.
86
+ private function _graphql_pre_request(ProjectNameContext $ctx, array $paging): void
87
+ {
88
+ $body = $ctx->spec->body;
89
+ if (!is_array($body)) {
90
+ return;
91
+ }
92
+
93
+ $variables = $body['variables'] ?? null;
94
+ if (!is_array($variables)) {
95
+ $variables = [];
96
+ }
97
+
98
+ $after_var = $this->options['afterVar'] ?? 'after';
99
+ $first_var = $this->options['firstVar'] ?? 'first';
100
+
101
+ // Only bind variables the operation actually declares, or the server
102
+ // rejects the document.
103
+ $declared = [];
104
+ $varlist = \Voxgig\Struct\Struct::getpath($ctx->point, 'graphql.vars');
105
+ if (is_array($varlist)) {
106
+ foreach ($varlist as $v) {
107
+ $name = \Voxgig\Struct\Struct::getprop($v, 'name');
108
+ if (null !== $name) {
109
+ $declared[$name] = true;
110
+ }
111
+ }
112
+ }
113
+
114
+ if (($paging['cursor'] ?? null) !== null
115
+ && ($declared[$after_var] ?? false)) {
116
+ $variables[$after_var] = $paging['cursor'];
117
+ }
118
+
119
+ if (($this->options['limit'] ?? null) !== null
120
+ && ($variables[$first_var] ?? null) === null
121
+ && ($declared[$first_var] ?? false)) {
122
+ $variables[$first_var] = $this->options['limit'];
123
+ }
124
+
125
+ // PHP arrays are values, not references: write the whole envelope
126
+ // back or the bindings are lost.
127
+ $body['variables'] = $variables;
128
+ $ctx->spec->body = $body;
129
+ }
130
+
75
131
  public function PreResult(ProjectNameContext $ctx): void
76
132
  {
77
133
  if (!$this->active || !$this->_is_list($ctx)) {
@@ -100,6 +156,44 @@ class ProjectNamePagingFeature extends ProjectNameBaseFeature
100
156
  $paging['next'] = $m[1];
101
157
  }
102
158
 
159
+ // Set when the response states hasMore outright, rather than leaving
160
+ // it to be inferred from the presence of a cursor.
161
+ $explicit_more = false;
162
+
163
+ // Relay connections carry the cursor in pageInfo, at the path the
164
+ // model recorded for this op.
165
+ $page = \Voxgig\Struct\Struct::getpath($ctx->point, 'graphql.page');
166
+ if (is_array($page) && is_array($body)) {
167
+ // `connpath` locates the connection object inside the response
168
+ // envelope (data.<field>); the cursor/more paths are relative
169
+ // to it.
170
+ $connpath = $page['connpath'] ?? null;
171
+ $conn = $body;
172
+ if (is_string($connpath) && '' !== $connpath) {
173
+ $sub = \Voxgig\Struct\Struct::getpath($body, $connpath);
174
+ if (null !== $sub) {
175
+ $conn = $sub;
176
+ }
177
+ }
178
+
179
+ $cursorpath = $page['cursor'] ?? null;
180
+ if (is_string($cursorpath) && '' !== $cursorpath) {
181
+ $cursor = \Voxgig\Struct\Struct::getpath($conn, $cursorpath);
182
+ if (null !== $cursor) {
183
+ $paging['cursor'] = $cursor;
184
+ }
185
+ }
186
+
187
+ $morepath = $page['more'] ?? null;
188
+ if (is_string($morepath) && '' !== $morepath) {
189
+ $more = \Voxgig\Struct\Struct::getpath($conn, $morepath);
190
+ if (is_bool($more)) {
191
+ $paging['hasMore'] = $more;
192
+ $explicit_more = true;
193
+ }
194
+ }
195
+ }
196
+
103
197
  // Body-level cursors.
104
198
  if (is_array($body)) {
105
199
  if (($body['next'] ?? null) !== null) {
@@ -113,13 +207,21 @@ class ProjectNamePagingFeature extends ProjectNameBaseFeature
113
207
  }
114
208
  if (is_bool($body['hasMore'] ?? null)) {
115
209
  $paging['hasMore'] = $body['hasMore'];
210
+ $explicit_more = true;
116
211
  }
117
212
  }
118
213
 
119
- $paging['hasMore'] = $paging['hasMore']
120
- || $paging['next'] !== null
121
- || $paging['cursor'] !== null
122
- || $paging['nextPage'] !== null;
214
+ // Cursor presence only INFERS another page. When the server stated
215
+ // the answer outright — relay's `hasNextPage: false`, or a body
216
+ // `hasMore` that wins: a final page normally carries both an end
217
+ // cursor and hasNextPage false, and inferring from the cursor there
218
+ // would send the caller back for a page that does not exist, forever.
219
+ if (!$explicit_more) {
220
+ $paging['hasMore'] = $paging['hasMore']
221
+ || $paging['next'] !== null
222
+ || $paging['cursor'] !== null
223
+ || $paging['nextPage'] !== null;
224
+ }
123
225
 
124
226
  $result->paging = $paging;
125
227
 
@@ -0,0 +1,176 @@
1
+ <?php
2
+ declare(strict_types=1);
3
+
4
+ // ProjectName SDK utility: graphql
5
+ //
6
+ // GraphQL transport. API-INDEPENDENT: every GraphQL SDK this generator
7
+ // produces uses this file unchanged. The API-specific part — which
8
+ // operations exist and what each one's document is — is model data,
9
+ // computed once by apidef and emitted into Config.
10
+ //
11
+ // Two jobs:
12
+ //
13
+ // graphql_body — build { query, variables } for a point, binding the
14
+ // op's arguments to the document's declared variables.
15
+ //
16
+ // graphql_errors — lift a GraphQL failure into an SDK error. GraphQL
17
+ // reports failures as a top-level `errors` array under
18
+ // HTTP 200, so the status-driven path in result_basic
19
+ // never sees them.
20
+
21
+ class ProjectNameGraphql
22
+ {
23
+ // Content type every GraphQL-over-HTTP request uses.
24
+ public const CONTENT_TYPE = 'application/json';
25
+
26
+ // Map a GraphQL error to the same error codes the HTTP path produces,
27
+ // so a caller handles auth or rate limiting identically on both
28
+ // transports. Servers put the machine-readable code in
29
+ // `extensions.code`; Linear-style APIs use `extensions.type`.
30
+ public static function errorCode(mixed $gqlerr): string
31
+ {
32
+ $ext = \Voxgig\Struct\Struct::getprop($gqlerr, 'extensions');
33
+ if (!is_array($ext)) {
34
+ $ext = [];
35
+ }
36
+
37
+ $raw = \Voxgig\Struct\Struct::getprop($ext, 'code');
38
+ if (null === $raw || '' === $raw) {
39
+ $raw = \Voxgig\Struct\Struct::getprop($ext, 'type');
40
+ }
41
+ $raw = strtoupper(is_string($raw) ? $raw : '');
42
+
43
+ if (str_contains($raw, 'AUTH') || str_contains($raw, 'FORBIDDEN')
44
+ || str_contains($raw, 'UNAUTHENTICATED')) {
45
+ return 'request_auth';
46
+ }
47
+ if (str_contains($raw, 'RATELIMIT') || str_contains($raw, 'RATE_LIMIT')
48
+ || str_contains($raw, 'TOO_MANY')) {
49
+ return 'request_ratelimit';
50
+ }
51
+ if (str_contains($raw, 'BAD_USER_INPUT') || str_contains($raw, 'VALIDATION')
52
+ || str_contains($raw, 'INVALID')) {
53
+ return 'request_invalid';
54
+ }
55
+
56
+ return 'request_graphql';
57
+ }
58
+
59
+ // Build the request body for a GraphQL point.
60
+ //
61
+ // Variables come from the op's own arguments: a named variable binds
62
+ // to the like-named argument (`from`), and the input-object variable
63
+ // (empty `from`) takes the request data as a whole — which is what
64
+ // makes a generated create/update call look exactly like its REST
65
+ // equivalent.
66
+ public static function body(ProjectNameContext $ctx): mixed
67
+ {
68
+ $gql = \Voxgig\Struct\Struct::getprop($ctx->point, 'graphql');
69
+ if (!is_array($gql)) {
70
+ return null;
71
+ }
72
+
73
+ // reqmatch/reqdata hold the caller's arguments for THIS call;
74
+ // data/match hold the entity's current state. Which pair depends on
75
+ // whether the op takes match or data input. A named variable falls
76
+ // back to the current state, so updating a loaded entity with just
77
+ // {title} still binds the stored id the mutation requires.
78
+ $reqsrc = $ctx->reqmatch;
79
+ $datasrc = $ctx->match;
80
+ if (null !== $ctx->op && 'data' === $ctx->op->input) {
81
+ $reqsrc = $ctx->reqdata;
82
+ $datasrc = $ctx->data;
83
+ }
84
+ if (!is_array($reqsrc)) {
85
+ $reqsrc = [];
86
+ }
87
+ if (!is_array($datasrc)) {
88
+ $datasrc = [];
89
+ }
90
+
91
+ $variables = [];
92
+
93
+ $varlist = \Voxgig\Struct\Struct::getprop($gql, 'vars');
94
+ if (!is_array($varlist)) {
95
+ $varlist = [];
96
+ }
97
+
98
+ foreach ($varlist as $spec) {
99
+ if (!is_array($spec)) {
100
+ continue;
101
+ }
102
+
103
+ $name = \Voxgig\Struct\Struct::getprop($spec, 'name');
104
+ $from = \Voxgig\Struct\Struct::getprop($spec, 'from');
105
+
106
+ if (null === $from || '' === $from) {
107
+ // The input object IS the request body. Strip the action
108
+ // selector, which is an SDK-side point discriminator, not
109
+ // an API field.
110
+ $body = [];
111
+ foreach ($reqsrc as $k => $v) {
112
+ if ('$action' !== $k) {
113
+ $body[$k] = $v;
114
+ }
115
+ }
116
+ $variables[$name] = $body;
117
+ continue;
118
+ }
119
+
120
+ // Only send variables the caller actually supplied: sending an
121
+ // explicit null would clear a field on many APIs.
122
+ $val = \Voxgig\Struct\Struct::getprop($reqsrc, $from);
123
+ if (null === $val) {
124
+ $val = \Voxgig\Struct\Struct::getprop($datasrc, $from);
125
+ }
126
+ if (null !== $val) {
127
+ $variables[$name] = $val;
128
+ }
129
+ }
130
+
131
+ return [
132
+ 'query' => \Voxgig\Struct\Struct::getprop($gql, 'doc'),
133
+ 'variables' => $variables,
134
+ ];
135
+ }
136
+
137
+ // Inspect a decoded GraphQL response body and record a failure when
138
+ // the server reported one. Returns true when an error was recorded.
139
+ //
140
+ // Partial data (`data` alongside `errors`) is treated as failure: the
141
+ // REST surface has no partial-success concept, and silently returning
142
+ // half an object would be worse than failing. The raw envelope stays
143
+ // available on the result for callers that need it.
144
+ public static function errors(ProjectNameContext $ctx): bool
145
+ {
146
+ $result = $ctx->result;
147
+ $point = $ctx->point;
148
+
149
+ if (null === $result || null === $point) {
150
+ return false;
151
+ }
152
+
153
+ if ('graphql' !== \Voxgig\Struct\Struct::getprop($point, 'kind')) {
154
+ return false;
155
+ }
156
+
157
+ $errors = \Voxgig\Struct\Struct::getprop($result->body, 'errors');
158
+ if (!is_array($errors) || 0 === count($errors)) {
159
+ return false;
160
+ }
161
+
162
+ $first = $errors[0];
163
+ $msg = \Voxgig\Struct\Struct::getprop($first, 'message');
164
+ if (!is_string($msg) || '' === $msg) {
165
+ $msg = 'graphql error';
166
+ }
167
+ if (1 < count($errors)) {
168
+ $msg = $msg . ' (+' . (count($errors) - 1) . ' more)';
169
+ }
170
+
171
+ $result->err = $ctx->make_error(self::errorCode($first), 'graphql: ' . $msg);
172
+ $result->ok = false;
173
+
174
+ return true;
175
+ }
176
+ }
@@ -80,7 +80,7 @@ class ProjectNameMakeOptions
80
80
  'headers' => ['`$CHILD`' => '`$STRING`'],
81
81
  'allow' => [
82
82
  'method' => 'GET,PUT,POST,PATCH,DELETE,OPTIONS',
83
- 'op' => 'create,update,load,list,remove,command,direct',
83
+ 'op' => 'create,update,load,list,remove,command,direct,graphql',
84
84
  ],
85
85
  'entity' => ['`$CHILD`' => ['`$OPEN`' => true, 'active' => false, 'alias' => (object)[]]],
86
86
  'feature' => ['`$CHILD`' => ['`$OPEN`' => true, 'active' => false]],
@@ -29,6 +29,13 @@ class ProjectNameMakeResponse
29
29
  ($utility->result_basic)($ctx);
30
30
  ($utility->result_headers)($ctx);
31
31
  ($utility->result_body)($ctx);
32
+
33
+ // GraphQL reports failures as a top-level `errors` array under
34
+ // HTTP 200, so result_basic's status check never sees them. Lift
35
+ // them here, before the response transform tries to unwrap data
36
+ // that is not there.
37
+ ($utility->graphql_errors)($ctx);
38
+
32
39
  ($utility->transform_response)($ctx);
33
40
 
34
41
  if ($result->err === null) {
@@ -3,6 +3,8 @@ declare(strict_types=1);
3
3
 
4
4
  // ProjectName SDK utility: make_spec
5
5
 
6
+ require_once __DIR__ . '/Graphql.php';
7
+
6
8
  require_once __DIR__ . '/../core/Spec.php';
7
9
 
8
10
  class ProjectNameMakeSpec
@@ -46,8 +48,24 @@ class ProjectNameMakeSpec
46
48
  $ctx->spec->params = ($utility->prepare_params)($ctx);
47
49
  $ctx->spec->query = ($utility->prepare_query)($ctx);
48
50
  $ctx->spec->headers = ($utility->prepare_headers)($ctx);
49
- $ctx->spec->body = ($utility->prepare_body)($ctx);
50
- $ctx->spec->path = ($utility->prepare_path)($ctx);
51
+
52
+ if ('graphql' === \Voxgig\Struct\Struct::getprop($point, 'kind')) {
53
+ // GraphQL addresses one endpoint: no path parts, no query
54
+ // string, and the body carries the operation. prepare_body is
55
+ // skipped deliberately — it only emits a body for data-input
56
+ // ops, whereas every GraphQL op posts one, including
57
+ // load/list/remove.
58
+ $ctx->spec->body = ($utility->graphql_body)($ctx);
59
+ $ctx->spec->path = '';
60
+ // prepare_query already copied the op's match arguments into
61
+ // the query string. Those same values are bound as operation
62
+ // variables, so leaving them would send /graphql?id=i1.
63
+ $ctx->spec->query = [];
64
+ $ctx->spec->headers['content-type'] = ProjectNameGraphql::CONTENT_TYPE;
65
+ } else {
66
+ $ctx->spec->body = ($utility->prepare_body)($ctx);
67
+ $ctx->spec->path = ($utility->prepare_path)($ctx);
68
+ }
51
69
 
52
70
  if ($ctx->ctrl->explain) {
53
71
  $ctx->ctrl->explain['spec'] = $ctx->spec;
@@ -23,6 +23,7 @@ require_once __DIR__ . '/MakeUrl.php';
23
23
  require_once __DIR__ . '/Param.php';
24
24
  require_once __DIR__ . '/PrepareAuth.php';
25
25
  require_once __DIR__ . '/PrepareBody.php';
26
+ require_once __DIR__ . '/Graphql.php';
26
27
  require_once __DIR__ . '/PrepareHeaders.php';
27
28
  require_once __DIR__ . '/PrepareMethod.php';
28
29
  require_once __DIR__ . '/PrepareParams.php';
@@ -59,6 +60,8 @@ ProjectNameUtility::setRegistrar(function (ProjectNameUtility $u): void {
59
60
  $u->prepare_params = [ProjectNamePrepareParams::class, 'call'];
60
61
  $u->prepare_path = [ProjectNamePreparePath::class, 'call'];
61
62
  $u->prepare_query = [ProjectNamePrepareQuery::class, 'call'];
63
+ $u->graphql_body = [ProjectNameGraphql::class, 'body'];
64
+ $u->graphql_errors = [ProjectNameGraphql::class, 'errors'];
62
65
  $u->result_basic = [ProjectNameResultBasic::class, 'call'];
63
66
  $u->result_body = [ProjectNameResultBody::class, 'call'];
64
67
  $u->result_headers = [ProjectNameResultHeaders::class, 'call'];
File without changes
@@ -3,14 +3,14 @@
3
3
  from __future__ import annotations
4
4
  import random
5
5
 
6
- from utility.voxgig_struct import voxgig_struct as vs
7
- from core.control import ProjectNameControl
8
- from core.operation import ProjectNameOperation
9
- from core.spec import ProjectNameSpec
10
- from core.result import ProjectNameResult
11
- from core.response import ProjectNameResponse
12
- from core.error import ProjectNameError
13
- from core.helpers import get_ctx_prop, to_map
6
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
7
+ from projectname_sdk.core.control import ProjectNameControl
8
+ from projectname_sdk.core.operation import ProjectNameOperation
9
+ from projectname_sdk.core.spec import ProjectNameSpec
10
+ from projectname_sdk.core.result import ProjectNameResult
11
+ from projectname_sdk.core.response import ProjectNameResponse
12
+ from projectname_sdk.core.error import ProjectNameError
13
+ from projectname_sdk.core.helpers import get_ctx_prop, to_map
14
14
 
15
15
 
16
16
  class ProjectNameContext:
@@ -1,7 +1,7 @@
1
1
  # ProjectName SDK operation
2
2
 
3
3
  from __future__ import annotations
4
- from utility.voxgig_struct import voxgig_struct as vs
4
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
5
5
 
6
6
 
7
7
  class ProjectNameOperation:
@@ -1,7 +1,7 @@
1
1
  # ProjectName SDK response
2
2
 
3
3
  from __future__ import annotations
4
- from utility.voxgig_struct import voxgig_struct as vs
4
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
5
5
 
6
6
 
7
7
  class ProjectNameResponse: