@voxgig/sdkgen 1.5.1 → 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 +3 -3
  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
@@ -179,7 +179,41 @@ function ProjectNameSDK:prepare(fetchargs)
179
179
  end
180
180
 
181
181
 
182
+ -- Raw endpoint access is operator-controllable, like every entity op.
183
+ -- Blocking it means denying BOTH the 'direct' and 'graphql' tokens, since
184
+ -- either one reaches the same endpoint.
182
185
  function ProjectNameSDK:direct(fetchargs)
186
+ if not self:_op_allowed("direct") then
187
+ return self:_op_denied("direct"), nil
188
+ end
189
+
190
+ return self:_raw_request(fetchargs)
191
+ end
192
+
193
+
194
+ -- Is this raw-access op permitted by the SDK's allow.op option?
195
+ function ProjectNameSDK:_op_allowed(op)
196
+ local allow = vs.getpath(self.options, "allow.op")
197
+ return type(allow) == "string" and allow:find(op, 1, true) ~= nil
198
+ end
199
+
200
+
201
+ function ProjectNameSDK:_op_denied(op)
202
+ local allow = vs.getpath(self.options, "allow.op")
203
+ if type(allow) ~= "string" then allow = "" end
204
+ return {
205
+ ok = false,
206
+ err = "ProjectNameSDK: " .. op .. ": operation not allowed by" ..
207
+ " SDK option allow.op value: \"" .. allow .. "\"",
208
+ }
209
+ end
210
+
211
+
212
+ -- Ungated request path shared by direct and graphql, each of which checks its
213
+ -- own allow.op token first. Private, rather than a flag on fetchargs: a
214
+ -- caller-supplied marker would let anyone opt straight back out of the gate
215
+ -- by passing it.
216
+ function ProjectNameSDK:_raw_request(fetchargs)
183
217
  local utility = self._utility
184
218
 
185
219
  local fetchdef, err = self:prepare(fetchargs)
@@ -248,6 +282,57 @@ function ProjectNameSDK:direct(fetchargs)
248
282
  end
249
283
 
250
284
 
285
+ -- Raw GraphQL access: the pressure valve that makes the generated surface's
286
+ -- deliberate omissions (per-call selection sets, typed filter builders,
287
+ -- batching, subscriptions) livable — the whole schema stays reachable.
288
+ --
289
+ -- Thin wrapper over the same prepare/fetch path direct uses, with the one
290
+ -- thing raw direct cannot do for GraphQL: a GraphQL failure rides HTTP 200 as
291
+ -- a top-level `errors` array, so status alone would report a failed query as
292
+ -- ok.
293
+ --
294
+ -- NOTE: like direct, this bypasses the feature pipeline — no retry, ratelimit
295
+ -- or paging features apply.
296
+ function ProjectNameSDK:graphql(query, variables, ctrl)
297
+ if not self:_op_allowed("graphql") then
298
+ return self:_op_denied("graphql"), nil
299
+ end
300
+
301
+ local res, err = self:_raw_request({
302
+ method = "POST",
303
+ headers = { ["content-type"] = "application/json" },
304
+ body = {
305
+ query = query,
306
+ variables = type(variables) == "table" and variables or {},
307
+ },
308
+ ctrl = type(ctrl) == "table" and ctrl or {},
309
+ })
310
+
311
+ if err ~= nil or type(res) ~= "table" then
312
+ return res, err
313
+ end
314
+
315
+ -- Errors are read BEFORE any status check: a GraphQL parse or validation
316
+ -- failure comes back as HTTP 400 carrying the standard { errors = {...} }
317
+ -- body, and the raw path represents a non-2xx as ok=false with no err — so
318
+ -- returning early on status would discard the server's own diagnostics,
319
+ -- which are the only useful part of that response.
320
+ local errors = vs.getpath(res, "data.errors")
321
+
322
+ if type(errors) == "table" and 0 < #errors then
323
+ local msg = vs.getprop(errors[1], "message")
324
+ if type(msg) ~= "string" or msg == "" then
325
+ msg = "graphql error"
326
+ end
327
+ res.ok = false
328
+ res.err = "ProjectNameSDK: graphql: " .. msg
329
+ res.graphql = errors
330
+ end
331
+
332
+ return res, nil
333
+ end
334
+
335
+
251
336
  -- <[SLOT]>
252
337
 
253
338
 
@@ -94,6 +94,10 @@ let test_with (testopts : value) (sdkopts : value) : sdk_client =
94
94
  let direct (client : sdk_client) (fetchargs : value) : value =
95
95
  Sdk_features.direct client fetchargs
96
96
 
97
+ let graphql (client : sdk_client) (query : string) (variables : value)
98
+ (ctrl : value) : value =
99
+ Sdk_features.graphql client query variables ctrl
100
+
97
101
  let prepare (client : sdk_client) (fetchargs : value) : value =
98
102
  Sdk_features.prepare client fetchargs
99
103
  `)
@@ -172,8 +172,41 @@ sub prepare {
172
172
  return $fetchdef;
173
173
  }
174
174
 
175
+ # Raw endpoint access is operator-controllable, like every entity op.
176
+ # Blocking it means denying BOTH the 'direct' and 'graphql' tokens, since
177
+ # either one reaches the same endpoint.
175
178
  sub direct {
176
179
  my ($self, $fetchargs) = @_;
180
+
181
+ return $self->_op_denied('direct') unless $self->_op_allowed('direct');
182
+
183
+ return $self->_raw_request($fetchargs);
184
+ }
185
+
186
+ # Is this raw-access op permitted by the SDK's allow.op option?
187
+ sub _op_allowed {
188
+ my ($self, $op) = @_;
189
+ my $allow = ProjectNameHelpers::gpath($self->{options}, 'allow.op');
190
+ return (defined $allow && !ref $allow && index($allow, $op) >= 0) ? 1 : 0;
191
+ }
192
+
193
+ sub _op_denied {
194
+ my ($self, $op) = @_;
195
+ my $allow = ProjectNameHelpers::gpath($self->{options}, 'allow.op');
196
+ $allow = '' unless defined $allow && !ref $allow;
197
+ return {
198
+ 'ok' => 0,
199
+ 'err' => "ProjectNameSDK: $op: operation not allowed by" .
200
+ " SDK option allow.op value: \"$allow\"",
201
+ };
202
+ }
203
+
204
+ # Ungated request path shared by direct and graphql, each of which checks its
205
+ # own allow.op token first. Private, rather than a flag on fetchargs: a
206
+ # caller-supplied marker would let anyone opt straight back out of the gate
207
+ # by passing it.
208
+ sub _raw_request {
209
+ my ($self, $fetchargs) = @_;
177
210
  my $utility = $self->{_utility};
178
211
 
179
212
  # direct() is the raw-HTTP escape hatch: it always returns a result hash
@@ -240,6 +273,53 @@ sub direct {
240
273
  };
241
274
  }
242
275
 
276
+ # Raw GraphQL access: the pressure valve that makes the generated surface's
277
+ # deliberate omissions (per-call selection sets, typed filter builders,
278
+ # batching, subscriptions) livable — the whole schema stays reachable.
279
+ #
280
+ # Thin wrapper over the same prepare/fetch path direct uses, with the one
281
+ # thing raw direct cannot do for GraphQL: a GraphQL failure rides HTTP 200 as
282
+ # a top-level `errors` array, so status alone would report a failed query as
283
+ # ok.
284
+ #
285
+ # NOTE: like direct, this bypasses the feature pipeline — no retry, ratelimit
286
+ # or paging features apply.
287
+ sub graphql {
288
+ my ($self, $query, $variables, $ctrl) = @_;
289
+
290
+ return $self->_op_denied('graphql') unless $self->_op_allowed('graphql');
291
+
292
+ my $res = $self->_raw_request({
293
+ 'method' => 'POST',
294
+ 'headers' => { 'content-type' => 'application/json' },
295
+ 'body' => {
296
+ 'query' => defined $query ? $query : '',
297
+ 'variables' => (ref $variables eq 'HASH') ? $variables : {},
298
+ },
299
+ 'ctrl' => (ref $ctrl eq 'HASH') ? $ctrl : {},
300
+ });
301
+
302
+ return $res unless ref $res eq 'HASH';
303
+
304
+ # Errors are read BEFORE any status check: a GraphQL parse or validation
305
+ # failure comes back as HTTP 400 carrying the standard { errors: [...] }
306
+ # body, and the raw path represents a non-2xx as ok:0 with no err — so
307
+ # returning early on status would discard the server's own diagnostics,
308
+ # which are the only useful part of that response.
309
+ my $errors = ProjectNameHelpers::gpath($res, 'data.errors');
310
+
311
+ if (ref $errors eq 'ARRAY' && 0 < scalar @$errors) {
312
+ my $first = $errors->[0];
313
+ my $msg = (ref $first eq 'HASH') ? $first->{'message'} : undef;
314
+ $msg = 'graphql error' unless defined $msg && $msg ne '';
315
+ $res->{'ok'} = 0;
316
+ $res->{'err'} = "ProjectNameSDK: graphql: $msg";
317
+ $res->{'graphql'} = $errors;
318
+ }
319
+
320
+ return $res;
321
+ }
322
+
243
323
  # <[SLOT]>
244
324
 
245
325
  sub test {
@@ -166,7 +166,41 @@ class ProjectNameSDK
166
166
  return $fetchdef;
167
167
  }
168
168
 
169
+ // Raw endpoint access is operator-controllable, like every entity op.
170
+ // Blocking it means denying BOTH the 'direct' and 'graphql' tokens,
171
+ // since either one reaches the same endpoint.
169
172
  public function direct(array $fetchargs = []): mixed
173
+ {
174
+ if (!$this->op_allowed("direct")) {
175
+ return $this->op_denied("direct");
176
+ }
177
+
178
+ return $this->raw_request($fetchargs);
179
+ }
180
+
181
+ // Is this raw-access op permitted by the SDK's allow.op option?
182
+ private function op_allowed(string $op): bool
183
+ {
184
+ $allow_op = Struct::getpath($this->options, "allow.op");
185
+ return is_string($allow_op) && str_contains($allow_op, $op);
186
+ }
187
+
188
+ private function op_denied(string $op): array
189
+ {
190
+ $allow_op = Struct::getpath($this->options, "allow.op");
191
+ return [
192
+ "ok" => false,
193
+ "err" => new ProjectNameError($op . "_allow",
194
+ "ProjectNameSDK: " . $op . ": operation not allowed by" .
195
+ " SDK option allow.op value: \"" . (string)$allow_op . "\""),
196
+ ];
197
+ }
198
+
199
+ // Ungated request path shared by direct and graphql, each of which
200
+ // checks its own allow.op token first. Private, rather than a flag on
201
+ // fetchargs: a caller-supplied marker would let anyone opt straight back
202
+ // out of the gate by passing it.
203
+ private function raw_request(array $fetchargs = []): mixed
170
204
  {
171
205
  $utility = $this->_utility;
172
206
 
@@ -237,6 +271,58 @@ class ProjectNameSDK
237
271
  ];
238
272
  }
239
273
 
274
+ // Raw GraphQL access: the pressure valve that makes the generated
275
+ // surface's deliberate omissions (per-call selection sets, typed filter
276
+ // builders, batching, subscriptions) livable — the whole schema stays
277
+ // reachable.
278
+ //
279
+ // Thin wrapper over the same prepare/fetch path direct uses, with the
280
+ // one thing raw direct cannot do for GraphQL: a GraphQL failure rides
281
+ // HTTP 200 as a top-level `errors` array, so status alone would report
282
+ // a failed query as ok.
283
+ //
284
+ // NOTE: like direct, this bypasses the feature pipeline — no retry,
285
+ // ratelimit or paging features apply.
286
+ public function graphql(string $query, ?array $variables = null, ?array $ctrl = null): mixed
287
+ {
288
+ if (!$this->op_allowed("graphql")) {
289
+ return $this->op_denied("graphql");
290
+ }
291
+
292
+ $res = $this->raw_request([
293
+ "method" => "POST",
294
+ "headers" => ["content-type" => "application/json"],
295
+ "body" => ["query" => $query, "variables" => $variables ?? []],
296
+ "ctrl" => $ctrl ?? [],
297
+ ]);
298
+
299
+ if (!is_array($res)) {
300
+ return $res;
301
+ }
302
+
303
+ // Errors are read BEFORE any status check: a GraphQL parse or
304
+ // validation failure comes back as HTTP 400 carrying the standard
305
+ // { errors: [...] } body, and the raw path represents a non-2xx as
306
+ // ok:false with no err — so returning early on status would discard
307
+ // the server's own diagnostics, which are the only useful part of
308
+ // that response.
309
+ $errors = Struct::getpath($res, "data.errors");
310
+
311
+ if (is_array($errors) && 0 < count($errors)) {
312
+ $first = is_array($errors[0]) ? $errors[0] : [];
313
+ $msg = $first["message"] ?? "";
314
+ if (!is_string($msg) || "" === $msg) {
315
+ $msg = "graphql error";
316
+ }
317
+ $res["ok"] = false;
318
+ $res["err"] = new ProjectNameError("graphql_error",
319
+ "ProjectNameSDK: graphql: " . $msg);
320
+ $res["graphql"] = $errors;
321
+ }
322
+
323
+ return $res;
324
+ }
325
+
240
326
  // <[SLOT]>
241
327
 
242
328
  public static function test(?array $testopts = null, ?array $sdkopts = null): self
@@ -41,14 +41,20 @@ const Entity = cmp(function Entity(props: any) {
41
41
  typeNames.push(opTypeName(entity.Name, opname))
42
42
  }
43
43
  })
44
- const typesModule = model.const.Name.toLowerCase() + '_types'
44
+ // The generated dataclasses live inside the SDK package alongside
45
+ // everything else, so the import is package-qualified.
46
+ const typesModule = model.const.Name.toLowerCase() + '_sdk.' +
47
+ model.const.Name.toLowerCase() + '_types'
45
48
  const typeImport =
46
49
  'from ' + typesModule + ' import (\n ' +
47
50
  typeNames.join(',\n ') + ',\n)'
48
51
 
49
52
  const ff = Path.normalize(__dirname + '/../../../src/cmp/py/fragment/')
50
53
 
51
- // Entity files go to entity/ folder
54
+ // Entity files go to <name>_sdk/entity/ — inside the SDK package, not at
55
+ // the language root. See the note in Main_py.ts: a top-level `entity`
56
+ // package is shadowable by any entity.py sitting beside the caller.
57
+ Folder({ name: model.const.Name.toLowerCase() + '_sdk' }, () => {
52
58
  Folder({ name: 'entity' }, () => {
53
59
 
54
60
  File({ name: entity.name + '_entity.' + target.ext }, () => {
@@ -95,6 +101,7 @@ const Entity = cmp(function Entity(props: any) {
95
101
 
96
102
  })
97
103
  })
104
+ })
98
105
  })
99
106
 
100
107
 
@@ -20,7 +20,7 @@ const MainEntity = cmp(async function MainEntity(props: any) {
20
20
  Content(`
21
21
  def ${entity.Name}(self, data=None) -> "${cls}":
22
22
  """Entity factory: client.${entity.Name}().list() / client.${entity.Name}().load({"id": ...})."""
23
- from entity.${entity.name}_entity import ${cls}
23
+ from ${model.const.Name.toLowerCase()}_sdk.entity.${entity.name}_entity import ${cls}
24
24
  return ${cls}(self, data)
25
25
 
26
26
  `)
@@ -34,21 +34,47 @@ const Main = cmp(async function Main(props: any) {
34
34
  const entity: ModelEntity = getModelPath(model, `main.${KIT}.entity`)
35
35
  const feature = getModelPath(model, `main.${KIT}.feature`)
36
36
 
37
+ // The one package directory everything the SDK owns lives in.
38
+ const pkgdir = model.const.Name.toLowerCase() + '_sdk'
39
+
37
40
  Package({ target })
38
41
 
39
42
  Gitignore({})
40
43
 
41
- // Copy tm/py files with replacements
44
+ // Root-level statics only (Makefile, LICENSE, test/). The runtime
45
+ // packages live under tm/py/pkg and are copied INSIDE the SDK package
46
+ // below.
42
47
  Copy({
43
48
  from: 'tm/' + target.name,
44
- exclude: [/src\//],
49
+ exclude: [/src\//, /pkg\//],
50
+ replace: {
51
+ ...props.ctx$.stdrep,
52
+ }
53
+ })
54
+
55
+ // Everything the SDK owns lives inside ONE package directory.
56
+ //
57
+ // core/, entity/, feature/ and utility/ used to sit at the language root
58
+ // as top-level importable names. `core`, `entity` and `utility` are all
59
+ // real PyPI distributions AND common scratch filenames, and Python puts
60
+ // the working directory first on sys.path — so a single utility.py beside
61
+ // a notebook shadowed ours and the SDK died on
62
+ // `No module named 'utility.voxgig_struct'`. Nesting them behind the
63
+ // model-named package makes that impossible.
64
+ //
65
+ // The public import is unchanged: `from <name>_sdk import <Name>SDK`,
66
+ // because <name>_sdk.py becomes <name>_sdk/__init__.py.
67
+ Folder({ name: pkgdir }, () => {
68
+
69
+ Copy({
70
+ from: 'tm/' + target.name + '/pkg',
45
71
  replace: {
46
72
  ...props.ctx$.stdrep,
47
73
  }
48
74
  })
49
75
 
50
76
  // Generate main SDK file
51
- File({ name: model.const.Name.toLowerCase() + '_sdk.' + target.ext }, () => {
77
+ File({ name: '__init__.' + target.ext }, () => {
52
78
 
53
79
  Fragment(
54
80
  {
@@ -94,7 +120,7 @@ from typing import TYPE_CHECKING
94
120
  if TYPE_CHECKING:
95
121
  `)
96
122
  each(entity, (ent: any) => {
97
- Content(` from entity.${ent.name}_entity import ${entityClassName(ent, entityCollection(model))}
123
+ Content(` from ${model.const.Name.toLowerCase()}_sdk.entity.${ent.name}_entity import ${entityClassName(ent, entityCollection(model))}
98
124
  `)
99
125
  })
100
126
  }
@@ -119,13 +145,13 @@ if TYPE_CHECKING:
119
145
  File({ name: 'features.' + target.ext }, () => {
120
146
  Content(`# ${model.const.Name} SDK feature factory
121
147
 
122
- from feature.base_feature import ${model.const.Name}BaseFeature
148
+ from ${model.const.Name.toLowerCase()}_sdk.feature.base_feature import ${model.const.Name}BaseFeature
123
149
  `)
124
150
 
125
151
  each(feature, (feat: any) => {
126
152
  if (feat.name !== 'base') {
127
153
  const fname = feat.name.charAt(0).toUpperCase() + feat.name.slice(1)
128
- Content(`from feature.${feat.name}_feature import ${model.const.Name}${fname}Feature
154
+ Content(`from ${model.const.Name.toLowerCase()}_sdk.feature.${feat.name}_feature import ${model.const.Name}${fname}Feature
129
155
  `)
130
156
  }
131
157
  })
@@ -187,6 +213,8 @@ def _make_feature(name):
187
213
  })
188
214
  })
189
215
 
216
+ })
217
+
190
218
  })
191
219
 
192
220
 
@@ -62,16 +62,13 @@ Homepage = "${repoUrl}"
62
62
  Repository = "${repoUrl}"
63
63
  Issues = "${issuesUrl}"
64
64
 
65
- # Ship the top-level single-file modules (setuptools find only discovers
66
- # package dirs, never these) so the documented import actually installs.
67
- # ${model.const.Name.toLowerCase()}_types holds the generated @dataclass models.
68
- [tool.setuptools]
69
- py-modules = ["${model.const.Name.toLowerCase()}_sdk", "${model.const.Name.toLowerCase()}_types", "config", "features"]
70
-
71
- # Explicit package list — setuptools auto-discovery refuses to pick when
72
- # multiple top-level dirs (core/entity/feature/utility) are present.
65
+ # ONE package. core/entity/feature/utility were previously top-level packages;
66
+ # those names are real PyPI distributions and common scratch filenames, and
67
+ # Python searches the working directory first, so any of them beside the
68
+ # caller silently shadowed the SDK's own. They now live inside
69
+ # ${model.const.Name.toLowerCase()}_sdk/ where nothing can reach them.
73
70
  [tool.setuptools.packages.find]
74
- include = ["core*", "entity*", "feature*", "utility*"]
71
+ include = ["${model.const.Name.toLowerCase()}_sdk*"]
75
72
 
76
73
  # Ship the PEP 561 py.typed marker(s) so the inline type hints reach consumers.
77
74
  [tool.setuptools.package-data]
@@ -137,9 +137,9 @@ const TestDirect = cmp(function TestDirect(props: any) {
137
137
  import json
138
138
  import pytest
139
139
 
140
- from utility.voxgig_struct import voxgig_struct as vs
140
+ from ${model.const.Name.toLowerCase()}_sdk.utility.voxgig_struct import voxgig_struct as vs
141
141
  from ${model.const.Name.toLowerCase()}_sdk import ${model.const.Name}SDK
142
- from core import helpers
142
+ from ${model.const.Name.toLowerCase()}_sdk.core import helpers
143
143
  from test import runner
144
144
 
145
145
 
@@ -94,9 +94,9 @@ import time
94
94
 
95
95
  import pytest
96
96
 
97
- from utility.voxgig_struct import voxgig_struct as vs
97
+ from ${model.const.Name.toLowerCase()}_sdk.utility.voxgig_struct import voxgig_struct as vs
98
98
  from ${model.const.Name.toLowerCase()}_sdk import ${model.const.Name}SDK
99
- from core import helpers
99
+ from ${model.const.Name.toLowerCase()}_sdk.core import helpers
100
100
 
101
101
  _TEST_DIR = os.path.dirname(os.path.abspath(__file__))
102
102
  from test import runner
@@ -130,7 +130,7 @@ ${hasList ? `
130
130
  assert len(seen) == 3
131
131
 
132
132
  # Inbound: streaming active -> yields each item from the feature.
133
- from config import make_config
133
+ from ${model.const.Name.toLowerCase()}_sdk.config import make_config
134
134
  cfg = make_config()
135
135
  if isinstance(cfg.get("feature"), dict) and "streaming" in cfg["feature"]:
136
136
  sdk = ${model.const.Name}SDK.test(
@@ -2,8 +2,8 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from utility.voxgig_struct import voxgig_struct as vs
6
- from core import helpers
5
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
6
+ from projectname_sdk.core import helpers
7
7
  # #TypeImports
8
8
 
9
9
 
@@ -1,5 +1,5 @@
1
- from utility.voxgig_struct import voxgig_struct as vs
2
- from core import helpers
1
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
2
+ from projectname_sdk.core import helpers
3
3
 
4
4
  entity_create_op = None
5
5
 
@@ -1,5 +1,5 @@
1
- from utility.voxgig_struct import voxgig_struct as vs
2
- from core import helpers
1
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
2
+ from projectname_sdk.core import helpers
3
3
 
4
4
  entity_load_op = None
5
5
 
@@ -1,5 +1,5 @@
1
- from utility.voxgig_struct import voxgig_struct as vs
2
- from core import helpers
1
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
2
+ from projectname_sdk.core import helpers
3
3
 
4
4
  entity_remove_op = None
5
5
 
@@ -1,5 +1,5 @@
1
- from utility.voxgig_struct import voxgig_struct as vs
2
- from core import helpers
1
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
2
+ from projectname_sdk.core import helpers
3
3
 
4
4
  entity_update_op = None
5
5
 
@@ -1,16 +1,16 @@
1
1
  # ProjectName SDK
2
2
 
3
- from utility.voxgig_struct import voxgig_struct as vs
4
- from core.utility_type import ProjectNameUtility
5
- from core.spec import ProjectNameSpec
6
- from core import helpers
3
+ from projectname_sdk.utility.voxgig_struct import voxgig_struct as vs
4
+ from projectname_sdk.core.utility_type import ProjectNameUtility
5
+ from projectname_sdk.core.spec import ProjectNameSpec
6
+ from projectname_sdk.core import helpers
7
7
 
8
8
  # Load utility registration (populates Utility._registrar)
9
- from utility import register
9
+ from projectname_sdk.utility import register
10
10
 
11
11
  # Load features
12
- from feature.base_feature import ProjectNameBaseFeature
13
- from features import _make_feature
12
+ from projectname_sdk.feature.base_feature import ProjectNameBaseFeature
13
+ from projectname_sdk.features import _make_feature
14
14
 
15
15
 
16
16
  class ProjectNameSDK:
@@ -23,7 +23,7 @@ class ProjectNameSDK:
23
23
  utility = ProjectNameUtility()
24
24
  self._utility = utility
25
25
 
26
- from config import make_config
26
+ from projectname_sdk.config import make_config
27
27
  config = make_config()
28
28
 
29
29
  self._rootctx = utility.make_context({
@@ -155,7 +155,34 @@ class ProjectNameSDK:
155
155
 
156
156
  return fetchdef
157
157
 
158
+ # Raw endpoint access is operator-controllable, like every entity op.
159
+ # Blocking it means denying BOTH the 'direct' and 'graphql' tokens, since
160
+ # either one reaches the same endpoint.
158
161
  def direct(self, fetchargs=None):
162
+ if not self._op_allowed("direct"):
163
+ return self._op_denied("direct")
164
+
165
+ return self._raw_request(fetchargs)
166
+
167
+ # Is this raw-access op permitted by the SDK's allow.op option?
168
+ def _op_allowed(self, op):
169
+ allow_op = vs.getpath(self.options, "allow.op")
170
+ return isinstance(allow_op, str) and op in allow_op
171
+
172
+ def _op_denied(self, op):
173
+ allow_op = vs.getpath(self.options, "allow.op")
174
+ return {
175
+ "ok": False,
176
+ "err": Exception(
177
+ "ProjectNameSDK: " + op + ": operation not allowed by"
178
+ ' SDK option allow.op value: "' + str(allow_op) + '"'),
179
+ }
180
+
181
+ # Ungated request path shared by direct and graphql, each of which checks
182
+ # its own allow.op token first. Private, rather than a flag on fetchargs:
183
+ # a caller-supplied marker would let anyone opt straight back out of the
184
+ # gate by passing it.
185
+ def _raw_request(self, fetchargs=None):
159
186
  utility = self._utility
160
187
 
161
188
  try:
@@ -222,6 +249,46 @@ class ProjectNameSDK:
222
249
  "err": ctx.make_error("direct_invalid", "invalid response type"),
223
250
  }
224
251
 
252
+ # Raw GraphQL access: the pressure valve that makes the generated
253
+ # surface's deliberate omissions (per-call selection sets, typed filter
254
+ # builders, batching, subscriptions) livable — the whole schema stays
255
+ # reachable.
256
+ #
257
+ # Thin wrapper over the same prepare/fetch path direct uses, with the one
258
+ # thing raw direct cannot do for GraphQL: a GraphQL failure rides HTTP 200
259
+ # as a top-level `errors` array, so status alone would report a failed
260
+ # query as ok.
261
+ #
262
+ # NOTE: like direct, this bypasses the feature pipeline — no retry,
263
+ # ratelimit or paging features apply.
264
+ def graphql(self, query, variables=None, ctrl=None):
265
+ if not self._op_allowed("graphql"):
266
+ return self._op_denied("graphql")
267
+
268
+ res = self._raw_request({
269
+ "method": "POST",
270
+ "headers": {"content-type": "application/json"},
271
+ "body": {"query": query, "variables": variables or {}},
272
+ "ctrl": ctrl or {},
273
+ })
274
+
275
+ # Errors are read BEFORE any status check: a GraphQL parse or
276
+ # validation failure comes back as HTTP 400 carrying the standard
277
+ # { errors: [...] } body, and the raw path represents a non-2xx as
278
+ # ok:False with no err — so returning early on status would discard
279
+ # the server's own diagnostics, which are the only useful part of
280
+ # that response.
281
+ errors = vs.getpath(res, "data.errors")
282
+
283
+ if isinstance(errors, list) and 0 < len(errors):
284
+ first = errors[0] if isinstance(errors[0], dict) else {}
285
+ msg = first.get("message") or "graphql error"
286
+ res["ok"] = False
287
+ res["err"] = Exception("ProjectNameSDK: graphql: " + str(msg))
288
+ res["graphql"] = errors
289
+
290
+ return res
291
+
225
292
  # <[SLOT]>
226
293
 
227
294
  @classmethod