@voxgig/sdkgen 4.8.2 → 4.9.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 (407) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/action/doctor.d.ts +1 -0
  3. package/dist/action/doctor.js +50 -2
  4. package/dist/action/doctor.js.map +1 -1
  5. package/dist/helpers/naming.js +4 -2
  6. package/dist/helpers/naming.js.map +1 -1
  7. package/dist/tsconfig.tsbuildinfo +1 -1
  8. package/model/sdkgen.aon +21 -0
  9. package/package.json +1 -1
  10. package/project/.sdk/model/feature/secrets.aon +120 -18
  11. package/project/.sdk/model/target/c.aon +10 -0
  12. package/project/.sdk/model/target/clojure.aon +13 -0
  13. package/project/.sdk/model/target/cpp.aon +10 -0
  14. package/project/.sdk/model/target/csharp.aon +9 -0
  15. package/project/.sdk/model/target/dart.aon +10 -0
  16. package/project/.sdk/model/target/elixir.aon +9 -0
  17. package/project/.sdk/model/target/go.aon +13 -0
  18. package/project/.sdk/model/target/java.aon +9 -0
  19. package/project/.sdk/model/target/js.aon +7 -0
  20. package/project/.sdk/model/target/kotlin.aon +9 -0
  21. package/project/.sdk/model/target/lean.aon +17 -0
  22. package/project/.sdk/model/target/lua.aon +8 -0
  23. package/project/.sdk/model/target/ocaml.aon +9 -0
  24. package/project/.sdk/model/target/perl.aon +8 -0
  25. package/project/.sdk/model/target/php.aon +8 -0
  26. package/project/.sdk/model/target/py.aon +13 -0
  27. package/project/.sdk/model/target/rb.aon +8 -0
  28. package/project/.sdk/model/target/rust.aon +10 -0
  29. package/project/.sdk/model/target/scala.aon +21 -2
  30. package/project/.sdk/model/target/swift.aon +18 -0
  31. package/project/.sdk/model/target/ts.aon +13 -0
  32. package/project/.sdk/model/target/zig.aon +9 -0
  33. package/project/.sdk/src/cmp/clojure/Package_clojure.ts +9 -2
  34. package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +3 -0
  35. package/project/.sdk/src/cmp/dart/Test_dart.ts +2 -0
  36. package/project/.sdk/src/cmp/elixir/Package_elixir.ts +4 -1
  37. package/project/.sdk/src/cmp/go/Config_go.ts +59 -2
  38. package/project/.sdk/src/cmp/go/Main_go.ts +8 -2
  39. package/project/.sdk/src/cmp/java/Test_java.ts +6 -5
  40. package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +6 -5
  41. package/project/.sdk/src/cmp/lean/Package_lean.ts +23 -0
  42. package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +1 -0
  43. package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +1 -0
  44. package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
  45. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +7 -3
  46. package/project/.sdk/src/cmp/py/Config_py.ts +82 -1
  47. package/project/.sdk/src/cmp/py/Main_py.ts +44 -0
  48. package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +2 -0
  49. package/project/.sdk/src/cmp/swift/Main_swift.ts +10 -0
  50. package/project/.sdk/src/cmp/swift/Package_swift.ts +13 -1
  51. package/project/.sdk/src/cmp/ts/Config_ts.ts +42 -17
  52. package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +13 -1
  53. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +13 -1
  54. package/project/.sdk/src/cmp/zig/Package_zig.ts +15 -11
  55. package/project/.sdk/src/cmp/zig/fragment/Entity.fragment.zig +3 -3
  56. package/project/.sdk/src/cmp/zig/fragment/EntityListOp.fragment.zig +3 -3
  57. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +3 -3
  58. package/project/.sdk/src/cmp/zig/utility_zig.ts +50 -1
  59. package/project/.sdk/tm/c/Makefile +38 -3
  60. package/project/.sdk/tm/c/tests/omni_resolver.h +361 -0
  61. package/project/.sdk/tm/c/tests/omni_smoke_test.c +237 -0
  62. package/project/.sdk/tm/c/tests/primary_corpus_test.c +205 -284
  63. package/project/.sdk/tm/c/tests/struct_corpus_test.c +292 -212
  64. package/project/.sdk/tm/c/tests/vendor/omni/json.c +811 -0
  65. package/project/.sdk/tm/c/tests/vendor/omni/omni.h +240 -0
  66. package/project/.sdk/tm/c/tests/vendor/omni/runner.c +940 -0
  67. package/project/.sdk/tm/c/tests/vendor/omni/util.c +351 -0
  68. package/project/.sdk/tm/c/utility/struct/utility.c +7 -2
  69. package/project/.sdk/tm/clojure/test/sdk/test/omni.clj +401 -0
  70. package/project/.sdk/tm/clojure/test/sdk/test/omni_smoke.clj +81 -0
  71. package/project/.sdk/tm/clojure/test/sdk/test/primary.clj +92 -58
  72. package/project/.sdk/tm/clojure/test/sdk/test/struct_corpus.clj +122 -149
  73. package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +8 -3
  74. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/json.clj +145 -0
  75. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/runner.clj +445 -0
  76. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/util.clj +145 -0
  77. package/project/.sdk/tm/cpp/Makefile +5 -1
  78. package/project/.sdk/tm/cpp/test/omni_resolver.hpp +473 -0
  79. package/project/.sdk/tm/cpp/test/omni_smoke_test.cpp +209 -0
  80. package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +243 -184
  81. package/project/.sdk/tm/cpp/test/runner_support.hpp +68 -181
  82. package/project/.sdk/tm/cpp/test/struct_corpus_test.cpp +183 -56
  83. package/project/.sdk/tm/cpp/test/vendor/omni/json.hpp +406 -0
  84. package/project/.sdk/tm/cpp/test/vendor/omni/omni.hpp +751 -0
  85. package/project/.sdk/tm/cpp/test/vendor/omni/util.hpp +256 -0
  86. package/project/.sdk/tm/cpp/utility/pipeline.hpp +7 -1
  87. package/project/.sdk/tm/csharp/test/OmniResolver.cs +491 -0
  88. package/project/.sdk/tm/csharp/test/OmniSmokeTest.cs +106 -0
  89. package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +299 -316
  90. package/project/.sdk/tm/csharp/test/Runner.cs +104 -269
  91. package/project/.sdk/tm/csharp/test/StructUtilityTest.cs +535 -724
  92. package/project/.sdk/tm/csharp/test/vendor/omni/Runner.cs +864 -0
  93. package/project/.sdk/tm/csharp/test/vendor/omni/Util.cs +347 -0
  94. package/project/.sdk/tm/csharp/utility/MakeSpec.cs +3 -1
  95. package/project/.sdk/tm/csharp/utility/PrepareMethod.cs +6 -1
  96. package/project/.sdk/tm/csharp/utility/struct/Struct.cs +21 -5
  97. package/project/.sdk/tm/dart/test/omni.dart +520 -0
  98. package/project/.sdk/tm/dart/test/omni_smoke_test.dart +143 -0
  99. package/project/.sdk/tm/dart/test/primary_test.dart +86 -28
  100. package/project/.sdk/tm/dart/test/struct_test.dart +438 -11
  101. package/project/.sdk/tm/dart/test/vendor/omni/omni.dart +7 -0
  102. package/project/.sdk/tm/dart/test/vendor/omni/runner.dart +653 -0
  103. package/project/.sdk/tm/dart/test/vendor/omni/util.dart +232 -0
  104. package/project/.sdk/tm/elixir/Makefile +11 -3
  105. package/project/.sdk/tm/elixir/test/omni_smoke_test.exs +117 -0
  106. package/project/.sdk/tm/elixir/test/primary_utility_test.exs +341 -16
  107. package/project/.sdk/tm/elixir/test/struct_corpus_test.exs +554 -9
  108. package/project/.sdk/tm/elixir/test/support/omni.ex +377 -0
  109. package/project/.sdk/tm/elixir/test/vendor/omni/json.ex +122 -0
  110. package/project/.sdk/tm/elixir/test/vendor/omni/runner.ex +623 -0
  111. package/project/.sdk/tm/elixir/test/vendor/omni/util.ex +187 -0
  112. package/project/.sdk/tm/go/core/context.go +32 -16
  113. package/project/.sdk/tm/go/feature/secrets/plugin/capability.go +261 -0
  114. package/project/.sdk/tm/go/feature/secrets/plugin/catalog.go +78 -0
  115. package/project/.sdk/tm/go/feature/secrets/plugin/config.go +652 -0
  116. package/project/.sdk/tm/go/feature/secrets/plugin/depend.go +250 -0
  117. package/project/.sdk/tm/go/feature/secrets/plugin/env.go +194 -0
  118. package/project/.sdk/tm/go/feature/secrets/plugin/export.go +80 -0
  119. package/project/.sdk/tm/go/feature/secrets/plugin/graph.go +238 -0
  120. package/project/.sdk/tm/go/feature/secrets/plugin/host.go +1575 -0
  121. package/project/.sdk/tm/go/feature/secrets/plugin/order.go +248 -0
  122. package/project/.sdk/tm/go/feature/secrets/plugin/point.go +184 -0
  123. package/project/.sdk/tm/go/feature/secrets/plugin/ref.go +123 -0
  124. package/project/.sdk/tm/go/feature/secrets/plugin/resolve.go +79 -0
  125. package/project/.sdk/tm/go/feature/secrets/plugin/types.go +296 -0
  126. package/project/.sdk/tm/go/feature/secrets/plugin/util.go +87 -0
  127. package/project/.sdk/tm/go/feature/secrets/plugin/version.go +161 -0
  128. package/project/.sdk/tm/go/feature/secrets/plugins/aws/aws.go +292 -0
  129. package/project/.sdk/tm/go/feature/secrets/plugins/aws/sigv4.go +201 -0
  130. package/project/.sdk/tm/go/feature/secrets/plugins/azuresecrets/azuresecrets.go +187 -0
  131. package/project/.sdk/tm/go/feature/secrets/plugins/boru/boru.go +184 -0
  132. package/project/.sdk/tm/go/feature/secrets/plugins/doppler/doppler.go +114 -0
  133. package/project/.sdk/tm/go/feature/secrets/plugins/gcpsecrets/gcpsecrets.go +156 -0
  134. package/project/.sdk/tm/go/feature/secrets/plugins/hashicorp/hashicorp.go +208 -0
  135. package/project/.sdk/tm/go/feature/secrets/plugins/httpjson/httpjson.go +241 -0
  136. package/project/.sdk/tm/go/feature/secrets/plugins/infisical/infisical.go +150 -0
  137. package/project/.sdk/tm/go/feature/secrets/plugins/onepassword/onepassword.go +152 -0
  138. package/project/.sdk/tm/go/feature/secrets/plugins/secretspec/secretspec.go +143 -0
  139. package/project/.sdk/tm/go/feature/secrets/sekreto/addr.go +120 -0
  140. package/project/.sdk/tm/go/feature/secrets/sekreto/providers.go +442 -0
  141. package/project/.sdk/tm/go/feature/secrets/sekreto/sekreto.go +714 -0
  142. package/project/.sdk/tm/go/feature/secrets_feature.go +675 -0
  143. package/project/.sdk/tm/go/src/feature/secrets/.gitkeep +0 -0
  144. package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +799 -0
  145. package/project/.sdk/tm/go/test/omni/omni.go +902 -0
  146. package/project/.sdk/tm/go/test/omni/util.go +381 -0
  147. package/project/.sdk/tm/go/test/omniresolver_test.go +748 -0
  148. package/project/.sdk/tm/go/test/omnismoke_test.go +112 -0
  149. package/project/.sdk/tm/go/test/primary_utility_test.go +123 -191
  150. package/project/.sdk/tm/go/test/struct_utility_test.go +323 -16
  151. package/project/.sdk/tm/go/test/testsupport_test.go +294 -0
  152. package/project/.sdk/tm/go/utility/make_options.go +8 -1
  153. package/project/.sdk/tm/go/utility/prepare_method.go +5 -1
  154. package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +2 -2
  155. package/project/.sdk/tm/java/test/OmniResolver.java +355 -0
  156. package/project/.sdk/tm/java/test/OmniSmokeTest.java +99 -0
  157. package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +254 -280
  158. package/project/.sdk/tm/java/test/RunnerSupport.java +9 -194
  159. package/project/.sdk/tm/java/test/StructCorpusTest.java +119 -42
  160. package/project/.sdk/tm/java/test/vendor/omni/Json.java +287 -0
  161. package/project/.sdk/tm/java/test/vendor/omni/Runner.java +851 -0
  162. package/project/.sdk/tm/java/test/vendor/omni/Util.java +322 -0
  163. package/project/.sdk/tm/java/utility/MakeSpec.java +3 -1
  164. package/project/.sdk/tm/java/utility/PrepareMethod.java +5 -5
  165. package/project/.sdk/tm/java/utility/struct/Struct.java +17 -4
  166. package/project/.sdk/tm/js/src/utility/StructUtility.js +3 -3
  167. package/project/.sdk/tm/js/test/omni.js +251 -0
  168. package/project/.sdk/tm/js/test/omni.test.js +105 -0
  169. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +6 -2
  170. package/project/.sdk/tm/js/test/utility/StructUtility.test.js +27 -2
  171. package/project/.sdk/tm/js/test/vendor/omni/index.js +77 -0
  172. package/project/.sdk/tm/js/test/vendor/omni/runner.js +628 -0
  173. package/project/.sdk/tm/js/test/vendor/omni/util.js +229 -0
  174. package/project/.sdk/tm/kotlin/core/Utility.kt +1 -1
  175. package/project/.sdk/tm/kotlin/test/OmniResolver.kt +343 -0
  176. package/project/.sdk/tm/kotlin/test/OmniSmokeTest.kt +100 -0
  177. package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +244 -262
  178. package/project/.sdk/tm/kotlin/test/RunnerSupport.kt +9 -178
  179. package/project/.sdk/tm/kotlin/test/StructCorpusTest.kt +121 -32
  180. package/project/.sdk/tm/kotlin/test/vendor/omni/Json.kt +264 -0
  181. package/project/.sdk/tm/kotlin/test/vendor/omni/Runner.kt +615 -0
  182. package/project/.sdk/tm/kotlin/test/vendor/omni/Util.kt +139 -0
  183. package/project/.sdk/tm/kotlin/utility/MakeSpecUrl.kt +6 -3
  184. package/project/.sdk/tm/kotlin/utility/Prepare.kt +6 -6
  185. package/project/.sdk/tm/kotlin/utility/struct/Struct.kt +18 -2
  186. package/project/.sdk/tm/lean/Makefile +12 -5
  187. package/project/.sdk/tm/lean/src/SdkUtility.lean +14 -1
  188. package/project/.sdk/tm/lean/test/OmniResolver.lean +358 -0
  189. package/project/.sdk/tm/lean/test/OmniSmoke.lean +174 -0
  190. package/project/.sdk/tm/lean/test/StructCorpus.lean +245 -574
  191. package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +155 -291
  192. package/project/.sdk/tm/lean/test/vendor/omni/Omni.lean +997 -0
  193. package/project/.sdk/tm/lua/test/omni.lua +456 -0
  194. package/project/.sdk/tm/lua/test/omni_smoke_test.lua +103 -0
  195. package/project/.sdk/tm/lua/test/primary_utility_test.lua +250 -509
  196. package/project/.sdk/tm/lua/test/struct_utility_test.lua +161 -70
  197. package/project/.sdk/tm/lua/test/vendor/omni/json.lua +268 -0
  198. package/project/.sdk/tm/lua/test/vendor/omni/regex.lua +385 -0
  199. package/project/.sdk/tm/lua/test/vendor/omni/runner.lua +641 -0
  200. package/project/.sdk/tm/lua/test/vendor/omni/util.lua +282 -0
  201. package/project/.sdk/tm/lua/utility/prepare_method.lua +5 -1
  202. package/project/.sdk/tm/lua/utility/struct/regex.lua +663 -0
  203. package/project/.sdk/tm/lua/utility/struct/struct.lua +660 -420
  204. package/project/.sdk/tm/ocaml/Makefile +37 -12
  205. package/project/.sdk/tm/ocaml/test/omni_resolver.ml +284 -0
  206. package/project/.sdk/tm/ocaml/test/omni_smoke_test.ml +169 -0
  207. package/project/.sdk/tm/ocaml/test/primary_utility_test.ml +84 -100
  208. package/project/.sdk/tm/ocaml/test/struct_corpus.ml +225 -201
  209. package/project/.sdk/tm/ocaml/test/vendor/omni/omni.ml +1157 -0
  210. package/project/.sdk/tm/perl/lib/Voxgig/Struct.pm +88 -12
  211. package/project/.sdk/tm/perl/t/omni.pm +647 -0
  212. package/project/.sdk/tm/perl/t/omni_smoke.t +87 -0
  213. package/project/.sdk/tm/perl/t/primary_utility.t +189 -487
  214. package/project/.sdk/tm/perl/t/struct_utility.t +455 -389
  215. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Runner.pm +649 -0
  216. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Util.pm +253 -0
  217. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni.pm +24 -0
  218. package/project/.sdk/tm/perl/utility/prepare_method.pm +7 -2
  219. package/project/.sdk/tm/php/test/Omni.php +691 -0
  220. package/project/.sdk/tm/php/test/OmniSmokeTest.php +93 -0
  221. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +210 -571
  222. package/project/.sdk/tm/php/test/StructUtilityTest.php +320 -342
  223. package/project/.sdk/tm/php/test/vendor/omni/Runner.php +644 -0
  224. package/project/.sdk/tm/php/test/vendor/omni/Util.php +283 -0
  225. package/project/.sdk/tm/php/utility/MakeSpec.php +10 -3
  226. package/project/.sdk/tm/php/utility/PrepareBody.php +7 -1
  227. package/project/.sdk/tm/php/utility/PrepareMethod.php +6 -2
  228. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/__init__.py +36 -0
  229. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/capability.py +141 -0
  230. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/catalog.py +50 -0
  231. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/config.py +333 -0
  232. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/depend.py +198 -0
  233. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/env.py +147 -0
  234. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/export.py +52 -0
  235. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/graph.py +139 -0
  236. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/host.py +1053 -0
  237. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/order.py +171 -0
  238. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/point.py +95 -0
  239. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/ref.py +116 -0
  240. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/resolve.py +59 -0
  241. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/types.py +87 -0
  242. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/version.py +112 -0
  243. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/__init__.py +76 -0
  244. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/addr.py +116 -0
  245. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/aws.py +192 -0
  246. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/azuresecrets.py +120 -0
  247. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/boru.py +140 -0
  248. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/doppler.py +62 -0
  249. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/gcpsecrets.py +101 -0
  250. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/hashicorp.py +151 -0
  251. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/httpjson.py +115 -0
  252. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/infisical.py +90 -0
  253. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/onepassword.py +101 -0
  254. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/secretspec.py +119 -0
  255. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/sigv4.py +125 -0
  256. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/providers.py +211 -0
  257. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/sekreto.py +475 -0
  258. package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +467 -0
  259. package/project/.sdk/tm/py/pkg/utility/prepare_method.py +5 -1
  260. package/project/.sdk/tm/py/pkg/utility/voxgig_struct/__init__.py +0 -2
  261. package/project/.sdk/tm/py/pkg/utility/voxgig_struct/voxgig_struct.py +780 -529
  262. package/project/.sdk/tm/py/src/feature/secrets/.gitkeep +0 -0
  263. package/project/.sdk/tm/py/test/feature/__init__.py +0 -0
  264. package/project/.sdk/tm/py/test/feature/secrets/__init__.py +0 -0
  265. package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +337 -0
  266. package/project/.sdk/tm/py/test/omni.py +415 -0
  267. package/project/.sdk/tm/py/test/test_omni_smoke.py +74 -0
  268. package/project/.sdk/tm/py/test/test_primary_utility.py +144 -668
  269. package/project/.sdk/tm/py/test/test_struct_utility.py +74 -27
  270. package/project/.sdk/tm/py/test/voxgig_omni/__init__.py +62 -0
  271. package/project/.sdk/tm/py/test/voxgig_omni/runner.py +580 -0
  272. package/project/.sdk/tm/py/test/voxgig_omni/util.py +252 -0
  273. package/project/.sdk/tm/rb/test/omni.rb +505 -0
  274. package/project/.sdk/tm/rb/test/omni_smoke_test.rb +72 -0
  275. package/project/.sdk/tm/rb/test/primary_utility_test.rb +174 -560
  276. package/project/.sdk/tm/rb/test/struct_utility_test.rb +13 -7
  277. package/project/.sdk/tm/rb/test/vendor/omni/runner.rb +493 -0
  278. package/project/.sdk/tm/rb/test/vendor/omni/util.rb +199 -0
  279. package/project/.sdk/tm/rb/test/vendor/omni/voxgig_omni.rb +15 -0
  280. package/project/.sdk/tm/rb/utility/prepare_method.rb +5 -1
  281. package/project/.sdk/tm/rust/tests/common/mod.rs +19 -242
  282. package/project/.sdk/tm/rust/tests/omni_resolver/mod.rs +888 -0
  283. package/project/.sdk/tm/rust/tests/omni_smoke_test.rs +286 -0
  284. package/project/.sdk/tm/rust/tests/primary_utility_test.rs +318 -312
  285. package/project/.sdk/tm/rust/tests/struct_utility_test.rs +66 -28
  286. package/project/.sdk/tm/rust/tests/vendor/omni/json.rs +412 -0
  287. package/project/.sdk/tm/rust/tests/vendor/omni/mod.rs +38 -0
  288. package/project/.sdk/tm/rust/tests/vendor/omni/regex.rs +392 -0
  289. package/project/.sdk/tm/rust/tests/vendor/omni/runner.rs +1001 -0
  290. package/project/.sdk/tm/rust/tests/vendor/omni/util.rs +161 -0
  291. package/project/.sdk/tm/rust/utility/prepare_method.rs +5 -1
  292. package/project/.sdk/tm/scala/Makefile +16 -6
  293. package/project/.sdk/tm/scala/sdktest/OmniResolver.scala +497 -0
  294. package/project/.sdk/tm/scala/sdktest/OmniSmoke.scala +192 -0
  295. package/project/.sdk/tm/scala/sdktest/PrimaryCorpus.scala +47 -19
  296. package/project/.sdk/tm/scala/sdktest/StructCorpus.scala +0 -0
  297. package/project/.sdk/tm/scala/sdktest/vendor/omni/Json.scala +229 -0
  298. package/project/.sdk/tm/scala/sdktest/vendor/omni/Runner.scala +552 -0
  299. package/project/.sdk/tm/scala/sdktest/vendor/omni/Util.scala +104 -0
  300. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Constants.swift +10 -0
  301. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Inject.swift +28 -5
  302. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Injection.swift +5 -1
  303. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Minor.swift +4 -1
  304. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Validate.swift +15 -5
  305. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +6 -1
  306. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/OmniResolver.swift +474 -0
  307. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/OmniSmokeTest.swift +107 -0
  308. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +141 -178
  309. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/Runner.swift +17 -113
  310. package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/StructUtilityTest.swift +295 -446
  311. package/project/.sdk/tm/swift/Tests/vendor/omni/Json.swift +364 -0
  312. package/project/.sdk/tm/swift/Tests/vendor/omni/Runner.swift +730 -0
  313. package/project/.sdk/tm/swift/Tests/vendor/omni/Util.swift +162 -0
  314. package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +7 -0
  315. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Capability.ts +148 -0
  316. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Catalog.ts +55 -0
  317. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Config.ts +344 -0
  318. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Depend.ts +205 -0
  319. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Env.ts +138 -0
  320. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Export.ts +46 -0
  321. package/project/.sdk/tm/ts/src/feature/secrets/plugin/FeatureHost.ts +349 -0
  322. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Graph.ts +181 -0
  323. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Host.ts +1132 -0
  324. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Order.ts +177 -0
  325. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Point.ts +119 -0
  326. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Ref.ts +102 -0
  327. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Resolve.ts +61 -0
  328. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Types.ts +112 -0
  329. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Version.ts +100 -0
  330. package/project/.sdk/tm/ts/src/feature/secrets/plugin/index.ts +37 -0
  331. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +163 -30
  332. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +27 -22
  333. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/aws.ts +26 -36
  334. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/azuresecrets.ts +19 -21
  335. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/boru.ts +36 -17
  336. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/doppler.ts +14 -21
  337. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/gcpsecrets.ts +27 -27
  338. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/hashicorp.ts +25 -39
  339. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/httpjson.ts +99 -0
  340. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/infisical.ts +14 -16
  341. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/onepassword.ts +15 -22
  342. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/secretspec.ts +98 -0
  343. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{Sigv4.ts → plugins/sigv4.ts} +7 -6
  344. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +97 -23
  345. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/builtin.ts +37 -0
  346. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +4 -17
  347. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +4 -16
  348. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +11 -25
  349. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +6 -23
  350. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +106 -39
  351. package/project/.sdk/tm/ts/src/utility/StructUtility.ts +3 -3
  352. package/project/.sdk/tm/ts/test/omni.ts +104 -32
  353. package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +27 -0
  354. package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +32 -5
  355. package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +2 -2
  356. package/project/.sdk/tm/ts/test/vendor/omni/index.ts +2 -2
  357. package/project/.sdk/tm/zig/Makefile +15 -1
  358. package/project/.sdk/tm/zig/build.zig +23 -5
  359. package/project/.sdk/tm/zig/core/helpers.zig +52 -11
  360. package/project/.sdk/tm/zig/core/mem.zig +17 -1
  361. package/project/.sdk/tm/zig/core/utility.zig +23 -19
  362. package/project/.sdk/tm/zig/feature/audit.zig +2 -2
  363. package/project/.sdk/tm/zig/feature/cache.zig +2 -2
  364. package/project/.sdk/tm/zig/feature/debug.zig +5 -5
  365. package/project/.sdk/tm/zig/feature/netsim.zig +2 -2
  366. package/project/.sdk/tm/zig/feature/paging.zig +2 -2
  367. package/project/.sdk/tm/zig/feature/proxy.zig +15 -8
  368. package/project/.sdk/tm/zig/feature/streaming.zig +5 -5
  369. package/project/.sdk/tm/zig/feature/support.zig +3 -3
  370. package/project/.sdk/tm/zig/feature/telemetry.zig +5 -5
  371. package/project/.sdk/tm/zig/feature/test.zig +10 -5
  372. package/project/.sdk/tm/zig/test/fh.zig +10 -10
  373. package/project/.sdk/tm/zig/test/gotcha_test.zig +5 -5
  374. package/project/.sdk/tm/zig/test/omniresolver.zig +515 -0
  375. package/project/.sdk/tm/zig/test/omnismoke_test.zig +284 -0
  376. package/project/.sdk/tm/zig/test/pipeline_test.zig +8 -8
  377. package/project/.sdk/tm/zig/test/primary_utility_test.zig +145 -155
  378. package/project/.sdk/tm/zig/test/struct_corpus.zig +264 -187
  379. package/project/.sdk/tm/zig/test/vendor/omni/omni.zig +1314 -0
  380. package/project/.sdk/tm/zig/test/vendor/omni/regex.zig +446 -0
  381. package/project/.sdk/tm/zig/utility/voxgigstruct/regex.zig +7 -4
  382. package/project/.sdk/tm/zig/utility/voxgigstruct/struct.zig +356 -157
  383. package/project/sdkgen-package.json +1 -1
  384. package/src/action/doctor.ts +66 -2
  385. package/src/helpers/naming.ts +4 -2
  386. package/project/.sdk/tm/c/tests/runner.h +0 -274
  387. package/project/.sdk/tm/cpp/test/struct_runner.hpp +0 -314
  388. package/project/.sdk/tm/csharp/test/StructRunner.cs +0 -276
  389. package/project/.sdk/tm/dart/test/runner.dart +0 -406
  390. package/project/.sdk/tm/dart/test/struct_corpus.dart +0 -531
  391. package/project/.sdk/tm/elixir/test/support/struct_corpus.ex +0 -1088
  392. package/project/.sdk/tm/go/test/runner_test.go +0 -629
  393. package/project/.sdk/tm/go/test/struct_runner_test.go +0 -1094
  394. package/project/.sdk/tm/java/test/StructRunner.java +0 -281
  395. package/project/.sdk/tm/js/test/runner.js +0 -387
  396. package/project/.sdk/tm/kotlin/test/StructRunner.kt +0 -177
  397. package/project/.sdk/tm/lua/test/struct_runner.lua +0 -602
  398. package/project/.sdk/tm/ocaml/test/corpus_runner.ml +0 -185
  399. package/project/.sdk/tm/perl/t/struct_runner.pm +0 -275
  400. package/project/.sdk/tm/php/test/StructRunner.php +0 -275
  401. package/project/.sdk/tm/py/test/struct_runner.py +0 -411
  402. package/project/.sdk/tm/rb/test/struct_runner.rb +0 -309
  403. package/project/.sdk/tm/rust/tests/struct_runner/mod.rs +0 -424
  404. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +0 -90
  405. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +0 -66
  406. package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +0 -188
  407. package/project/.sdk/tm/zig/test/struct_runner.zig +0 -464
@@ -0,0 +1,1053 @@
1
+ # VENDORED: @voxgig/plugin 0.1.6 (python/voxgig_plugin/host.py)
2
+ # Source: https://github.com/voxgig/plugin @ b48ae643eb0eb56c5ebe3198da98cecdf6a7f7fc [tag: sdk-20260907-0029-0]
3
+ # License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ """The host: the lifecycle state machine (section 5), extension points
5
+ (section 6), and resource capture (section 8).
6
+
7
+ TWO RULES SHAPE EVERY METHOD BELOW.
8
+
9
+ Transitions are SEQUENTIAL (section 5.2). One at a time, in call order,
10
+ never interleaved; a transition triggered from inside a lifecycle callback
11
+ is `plugin_reentrant`. A hard rule, because it is the only way the
12
+ semantics can be identical in Go, in Ruby and in single-threaded
13
+ JavaScript.
14
+
15
+ Reconciliation is EAGER (section 18's portability budget). A transition
16
+ settles by running the state machine to a fixed point, not by suspending
17
+ on a promise. Every port must be able to do the same, and fourteen of them
18
+ will not have JavaScript's event loop.
19
+ """
20
+
21
+ from .types import fail
22
+ from .ref import canon_ref, try_ref, format_ref, parse_ref
23
+ from .catalog import make_catalog
24
+ from .order import resolve_order
25
+ from .point import emit as fanout, compose, provider as pickone
26
+ from .export import resolve_export
27
+ from .capability import resolve_capability
28
+ from .config import normalize_config, resolve_options
29
+ from .depend import checkcycle, gatesactivation, requirements, restartsonloss
30
+
31
+
32
+ def make_host(options=None):
33
+ return Host(options)
34
+
35
+
36
+ class Inst:
37
+ """What a definition's callbacks see. Deliberately not the internal
38
+ record: a plugin that could reach `status` could also write it."""
39
+
40
+ def __init__(self, host, entry):
41
+ self._host = host
42
+ self._entry = entry
43
+ self.ref = entry['ref']
44
+ self.name = parse_ref(entry['ref'])['name']
45
+ self.tag = parse_ref(entry['ref'])['tag']
46
+
47
+ @property
48
+ def options(self):
49
+ return self._entry['options']
50
+
51
+ @property
52
+ def state(self):
53
+ return self._entry['state']
54
+
55
+ def host(self):
56
+ return self._host
57
+
58
+ def release(self, fn):
59
+ """Foreign resources the host did not hand out are registered
60
+ explicitly (section 8.3); host calls are recorded automatically.
61
+
62
+ SYMMETRIC WITH `acquire`, and it has to be: `open` counts the
63
+ resources CURRENTLY HELD, so an entry that is registered and then
64
+ unwound must leave the count where it found it.
65
+ """
66
+ # Section 8.3: "`inst.release` outside `activate` is
67
+ # `plugin_release_scope`". `_intransition` is true in `define`
68
+ # too, and a scope entry registered there is never unwound.
69
+ if 'activate' != self._host._phase:
70
+ fail('plugin_release_scope', 'release called outside activate')
71
+ host = self._host
72
+ done = [False]
73
+
74
+ def unwrap():
75
+ if not done[0]:
76
+ done[0] = True
77
+ host._open -= 1
78
+ fn()
79
+
80
+ self._entry['scope'].append(unwrap)
81
+ host._open += 1
82
+
83
+ def acquire(self):
84
+ """The synthetic counter the driver owns, so "what is open" is
85
+ data rather than an assertion each port words differently.
86
+
87
+ Returns its own release, so a plugin can hand one back early. The
88
+ scope still holds the entry and unwinding it twice is a no-op -
89
+ releasing early must not make teardown wrong.
90
+ """
91
+ # Section 8.1: resources are "acquired during `activate` - the
92
+ # scope's actual job". Same reason as `release` above.
93
+ if 'activate' != self._host._phase:
94
+ fail('plugin_release_scope', 'acquire called outside activate')
95
+ host = self._host
96
+ done = [False]
97
+
98
+ def rel():
99
+ if not done[0]:
100
+ done[0] = True
101
+ host._open -= 1
102
+
103
+ self._entry['scope'].append(rel)
104
+ host._open += 1
105
+ return rel
106
+
107
+ def bind(self, point, fn, band=None):
108
+ """Bind into a host point. Declared in `define`; the host inserts
109
+ it only after `activate` returns successfully (section 8.1), which
110
+ is why a failing activate leaves no live binding behind.
111
+
112
+ Section 12 has carried `plugin_bind_scope` - "binding declared
113
+ outside `define`" - since before anything raised it. The guard
114
+ was the half nobody wrote, so a binding added from `activate`
115
+ went live without being part of the loaded definition, and a
116
+ deactivate/activate cycle appended it again.
117
+ """
118
+ if 'define' != self._host._phase:
119
+ fail('plugin_bind_scope', 'bind called outside define: ' + point,
120
+ {'ref': self.ref, 'point': point})
121
+ if point not in self._host._points:
122
+ fail('plugin_point_unknown', 'no such point: ' + point,
123
+ {'point': point})
124
+ self._entry['bindings'].append(
125
+ {'ref': self.ref, 'point': point, 'fn': fn, 'band': band or 0})
126
+
127
+ def export(self, key, value):
128
+ """Published for other plugins and for the application (section
129
+ 11)."""
130
+ self._entry['exports'][key] = value
131
+
132
+ def provides(self, prov):
133
+ """What this instance can do for others (section 11.1)."""
134
+ self._entry['provides'].append(prov)
135
+
136
+ def position(self, point):
137
+ """Where this binding landed (section 6.6) - the plugin-side
138
+ counterpart to a host pin. Station found that a plugin can need to
139
+ KNOW it is in the right place: its middleware must sit immediately
140
+ outside the base transport or its "wire truth" events are fiction.
141
+
142
+ THE HOST DOES NOT POLICE THIS; it just makes the fact available. A
143
+ plugin that requires a position it did not get fails loudly rather
144
+ than reporting nonsense - and that is the plugin's call, because
145
+ only it knows what its position means. Verification tells a plugin
146
+ it was misplaced; a pin (section 7) stops the misplacement from
147
+ being expressible at all. The two are not substitutes.
148
+ """
149
+ return self._host.positionof(self.ref, point)
150
+
151
+ def nest(self, nestopts=None):
152
+ """AN INSTANCE MAY ITSELF BE A HOST (section 6.5), and THE OUTER
153
+ ONE OWNS THE INNER ONE'S LIFETIME. Registering the teardown in the
154
+ instance scope is what makes that true rather than aspirational:
155
+ the inner host closes when the outer instance deactivates, in the
156
+ same reverse unwind as every other resource."""
157
+ if not self._host._intransition:
158
+ fail('plugin_release_scope',
159
+ 'nest called outside a lifecycle callback')
160
+ inner = Host(nestopts)
161
+ self._entry['scope'].append(lambda: inner.close())
162
+ self._entry['inner'] = inner
163
+ return inner
164
+
165
+
166
+ class Host:
167
+ def __init__(self, options=None):
168
+ self._opts = options or {}
169
+ self._dependency = self._opts.get('dependency') or 'restart'
170
+ # Set for the duration of a bulk teardown, so `_held` knows this
171
+ # is a coordinated operation rather than an ad-hoc deactivation.
172
+ self._coordinated = False
173
+
174
+ self.catalog = self._opts.get('catalog') or make_catalog()
175
+ self._reserved = self._opts.get('reserved') or []
176
+ self._points = self._opts.get('points') or {}
177
+
178
+ self._inst = {}
179
+ self._log = []
180
+ # Section 14: the lifecycle event record. `seq` distinguishes ONE
181
+ # INCARNATION of stripe$test from the next, which is the whole
182
+ # reason it is not `pos` (section 4 rule 4).
183
+ self._events = []
184
+ self._seqn = 0
185
+ self._open = 0
186
+ self._intransition = False
187
+ # WHICH callback is running, not merely that one is. Section 8.1
188
+ # puts resource capture in `activate` and 8.3 says `release`
189
+ # outside `activate` is `plugin_release_scope` - and
190
+ # `_intransition` alone cannot tell `activate` from `define`, so
191
+ # it admitted an acquire in `define` whose scope `unload` would
192
+ # never unwind.
193
+ self._phase = None
194
+
195
+ # --- observation --------------------------------------------------
196
+
197
+ def list(self):
198
+ """Introspection NEVER advances the state (section 5.2). A status
199
+ page must not be a way to accidentally import twenty packages."""
200
+ return {r: self._inst[r]['status'] for r in sorted(self._inst)}
201
+
202
+ def instance(self, ref):
203
+ return self._inst.get(canon_ref(ref))
204
+
205
+ def trace(self):
206
+ return list(self._events)
207
+
208
+ def observable(self, result=None):
209
+ return {
210
+ 'status': self.list(),
211
+ 'open': self._open,
212
+ 'log': list(self._log),
213
+ 'result': None if None is result else result,
214
+ }
215
+
216
+ # --- the state machine --------------------------------------------
217
+
218
+ def _guard(self):
219
+ if self._intransition:
220
+ fail('plugin_reentrant',
221
+ 'transition attempted from inside a lifecycle callback')
222
+
223
+ def _need(self, ref):
224
+ r = canon_ref(ref)
225
+ entry = self._inst.get(r)
226
+ if not entry:
227
+ fail('plugin_not_loaded', 'no such instance: ' + r, {'ref': r})
228
+ return entry
229
+
230
+ def _checkreserved(self, ref):
231
+ if 0 == len(self._reserved):
232
+ return
233
+ if parse_ref(ref)['name'] in self._reserved:
234
+ fail('plugin_ref_reserved', 'ref is reserved by the host: ' + ref,
235
+ {'ref': ref})
236
+
237
+ def _run(self, entry, callback, at):
238
+ fn = entry['def'].get(callback)
239
+ self._log.append(entry['ref'] + ':' + at)
240
+ self._events.append({'ref': entry['ref'], 'event': at,
241
+ 'seq': entry['seq'], 'status': entry['status']})
242
+ if not callable(fn):
243
+ return
244
+ self._intransition = True
245
+ self._phase = at
246
+ try:
247
+ fn(Inst(self, entry))
248
+ except Exception as err:
249
+ # Section 12: `plugin_define_failed` and its three siblings
250
+ # are "a callback raised; wraps the cause". AN ERROR THAT
251
+ # ALREADY CARRIES A CODE KEEPS IT - the code is the error's
252
+ # identity, and a plugin raising `store_unreachable` must not
253
+ # have it rewritten. Only a code-less error is wrapped, which
254
+ # is the ordinary case for a callback that let a library
255
+ # error escape.
256
+ if getattr(err, 'code', None):
257
+ raise
258
+ fail('plugin_' + at + '_failed',
259
+ entry['ref'] + ' raised in ' + at + ': ' + str(err),
260
+ {'ref': entry['ref'], 'cause': str(err)})
261
+ finally:
262
+ self._intransition = False
263
+ self._phase = None
264
+
265
+ def autotag(self, name):
266
+ """AUTO-TAGGING IS EXPLICIT (section 4 rule 3).
267
+ `declare('stripe', {'tag': '?'})` assigns the LOWEST UNUSED
268
+ POSITIVE INTEGER tag and returns the assigned pair. Without `'?'`,
269
+ a collision is an error.
270
+
271
+ It needs a host because it must know what is already declared,
272
+ which is why it cannot live in the pure `ref` section - the
273
+ correction P1.7 made to section 15.3.
274
+ """
275
+ n = 1
276
+ while True:
277
+ cand = format_ref(name, str(n))
278
+ if cand not in self._inst:
279
+ return cand
280
+ n += 1
281
+
282
+ def declare(self, ref, spec=None):
283
+ spec = spec or {}
284
+ if '?' == spec.get('tag'):
285
+ ref = self.autotag(parse_ref(canon_ref(ref))['name'])
286
+ r = canon_ref(ref)
287
+ if not spec.get('hostowned'):
288
+ self._checkreserved(r)
289
+ defname = spec.get('definition') or parse_ref(r)['name']
290
+ definition = self.catalog.get(defname)
291
+ if not definition:
292
+ fail('plugin_unknown_definition', 'not in catalog: ' + defname,
293
+ {'name': defname})
294
+
295
+ existing = self._inst.get(r)
296
+ if existing:
297
+ # Section 4 rule 1: a pair addresses at most one instance.
298
+ # Re-declaring the SAME definition is the idempotent case; a
299
+ # different one is a duplicate, not a silent overwrite
300
+ # (seneca) and not an impossibility (sdkgen).
301
+ if existing['def']['name'] != definition['name']:
302
+ fail('plugin_ref_duplicate',
303
+ 'instance already declared: ' + r, {'ref': r})
304
+ return existing
305
+
306
+ entry = {
307
+ 'ref': r, 'def': definition, 'status': 'declared',
308
+ 'pos': len(self._inst) if None is spec.get('pos') else spec['pos'],
309
+ 'seq': self._seqn,
310
+ 'options': {} if None is spec.get('options') else spec['options'],
311
+ 'state': {},
312
+ # Section 11.4's ALWAYS-RELUCTANT rebinding made concrete: the
313
+ # provider ref this instance's activation actually chose, per
314
+ # requirement name. "A satisfied requirement is not re-bound
315
+ # while it stays satisfied" is a statement about a REMEMBERED
316
+ # choice - re-ranking on every question silently re-points a
317
+ # live consumer at any better newcomer, and then losing the
318
+ # provider it was really using does not restart it.
319
+ 'selected': {},
320
+ 'order': spec.get('order'), 'unmet': [], 'scope': [],
321
+ 'bindings': [], 'exports': {}, 'provides': [], 'inner': None,
322
+ }
323
+ self._seqn += 1
324
+ self._inst[r] = entry
325
+ return entry
326
+
327
+ def hostdeclare(self, ref, spec=None):
328
+ """Section 9.1: a host that reserves a name MUST still be able to
329
+ declare the instance it reserved - "The host declares those
330
+ instances itself, after the user merge, and always wins."
331
+
332
+ THE BOUNDARY IS BY METHOD, NOT BY CALLER, and that is a real
333
+ limit: no language here can tell the embedding host from a plugin
334
+ holding the same host object. What reservation protects is
335
+ CONFIGURATION - documents, overlays, `VOXGIG_PLUGIN_*`,
336
+ construction options and ordinary declare/load/options - and all
337
+ of that still checks.
338
+ """
339
+ self._guard()
340
+ spec = dict(spec or {})
341
+ spec['hostowned'] = True
342
+ return self.declare(ref, spec)
343
+
344
+ def load(self, ref, spec=None):
345
+ self._guard()
346
+ spec = spec or {}
347
+ entry = self.declare(ref, spec)
348
+ if 'declared' != entry['status']:
349
+ return entry # idempotent in the trivial direction
350
+ # PRESENCE, NOT TRUTHINESS. An empty map is falsy in Python and
351
+ # truthy in JavaScript, so `if spec.get('options')` refused to
352
+ # apply `options: {}` - which is how a caller CLEARS what
353
+ # `declare` set, and which every other port did.
354
+ if None is not spec.get('options'):
355
+ entry['options'] = spec['options']
356
+ try:
357
+ self._run(entry, 'define', 'define')
358
+ except Exception:
359
+ entry['status'] = 'failed'
360
+ raise
361
+ entry['status'] = 'loaded'
362
+
363
+ # AT LOAD, and before anything runs: a cycle through
364
+ # restart-causing requirements does not settle, and the only safe
365
+ # time to report a non-terminating reconcile is before it starts
366
+ # (section 11.3). `provides` is populated by `define`, which has
367
+ # just run, so this is the first moment the graph is complete.
368
+ try:
369
+ checkcycle(self._graphnodes())
370
+ except Exception:
371
+ entry['status'] = 'failed'
372
+ raise
373
+ return entry
374
+
375
+ def _graphnodes(self):
376
+ """The requirement graph as plain data, for the pure detector."""
377
+ return [
378
+ {'ref': r,
379
+ 'provides': [p['name'] for p in self._inst[r]['provides']],
380
+ 'requires': requirements(self._inst[r]['options'])}
381
+ for r in sorted(self._inst)
382
+ ]
383
+
384
+ def activate(self, ref):
385
+ self._guard()
386
+ entry = self._need(ref)
387
+ if 'live' == entry['status']:
388
+ return entry # no-op returning success
389
+ if 'failed' == entry['status']:
390
+ fail('plugin_bad_state', 'instance has failed: ' + entry['ref'],
391
+ {'ref': entry['ref']})
392
+ # Section 9.6: `active: false` bars the instance from running, and
393
+ # the bar is on the INSTANCE rather than on the apply that set it.
394
+ # `ready` reaches this through `activate`, so one guard covers
395
+ # both verbs the design names.
396
+ if entry.get('barred'):
397
+ fail('plugin_inactive',
398
+ 'instance is barred by active: false: ' + entry['ref'],
399
+ {'ref': entry['ref']})
400
+ if 'declared' == entry['status']:
401
+ self.load(entry['ref'])
402
+
403
+ # A declared requirement that is not live means `pending`:
404
+ # activation is a STANDING REQUEST, not a one-shot event.
405
+ unmet = self._unmetof(entry)
406
+ if 0 < len(unmet):
407
+ entry['unmet'] = unmet
408
+ entry['status'] = 'pending'
409
+ return entry
410
+
411
+ try:
412
+ self._run(entry, 'activate', 'activate')
413
+ except Exception:
414
+ # Unwind whatever the partial activation captured, in reverse.
415
+ self._unwind(entry)
416
+ entry['status'] = 'failed'
417
+ raise
418
+ # Section 11.4: THE SELECTION IS MADE HERE, once, and remembered.
419
+ # Every later question - the cascade, `hold`, `unmet` - reads it
420
+ # back rather than re-ranking, which is what "always-reluctant"
421
+ # means.
422
+ for req in requirements(entry['options']):
423
+ self._chosen(entry, req, True)
424
+ entry['status'] = 'live'
425
+ self._reconcile()
426
+ return entry
427
+
428
+ def deactivate(self, ref):
429
+ self._guard()
430
+ entry = self._need(ref)
431
+ if entry['status'] in ('loaded', 'declared'):
432
+ return entry
433
+
434
+ # Section 5.2: `unload` is THE ONLY TRANSITION OUT OF `failed`.
435
+ if 'failed' == entry['status']:
436
+ fail('plugin_bad_state', 'instance has failed: ' + entry['ref'],
437
+ {'ref': entry['ref']})
438
+
439
+ if 'pending' == entry['status']:
440
+ # DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (section
441
+ # 5.2). It never reached activate, so it holds no scope and no
442
+ # live bindings; running the definition's deactivate there
443
+ # would be teardown without matching setup, which plugins are
444
+ # not written to survive and which could fail an instance that
445
+ # had done nothing wrong. It cannot fail.
446
+ entry['status'] = 'loaded'
447
+ entry['unmet'] = []
448
+ return entry
449
+
450
+ self._held(entry)
451
+ self._cascade(entry, {})
452
+
453
+ try:
454
+ self._run(entry, 'deactivate', 'deactivate')
455
+ except Exception:
456
+ self._unwind(entry)
457
+ entry['status'] = 'failed'
458
+ raise
459
+ self._releasecheck(entry, self._unwind(entry))
460
+ entry['status'] = 'loaded'
461
+ self._reconcile()
462
+ return entry
463
+
464
+ def unload(self, ref):
465
+ self._guard()
466
+ entry = self._need(ref)
467
+ if entry['status'] in ('live', 'pending'):
468
+ if 'live' == entry['status']:
469
+ self._held(entry)
470
+ self._cascade(entry, {})
471
+ try:
472
+ self._run(entry, 'deactivate', 'deactivate')
473
+ except Exception:
474
+ # Section 5.2: ANY failure during a transition lands
475
+ # the instance in `failed`, with the scope STILL FULLY
476
+ # UNWOUND - and the instance STAYS REGISTERED, because
477
+ # `failed` is a state an operator has to be able to
478
+ # see.
479
+ self._unwind(entry)
480
+ entry['status'] = 'failed'
481
+ raise
482
+ self._releasecheck(entry, self._unwind(entry))
483
+ entry['status'] = 'loaded'
484
+ if entry['status'] in ('loaded', 'failed'):
485
+ try:
486
+ self._run(entry, 'close', 'close')
487
+ finally:
488
+ del self._inst[entry['ref']]
489
+ return
490
+ del self._inst[entry['ref']]
491
+
492
+ def ready(self, ref):
493
+ """Runs the whole forward path in one call (section 5.1). Section
494
+ 15.2's verb list omits this; 5.1 defines it and 15.3's `declare`
495
+ row requires the corpus to pin it, so the list was incomplete
496
+ rather than excluding it (DOCS.md section 4.2)."""
497
+ self._guard()
498
+ r = canon_ref(ref)
499
+ if r not in self._inst:
500
+ self.declare(r)
501
+ if 'declared' == self._inst[r]['status']:
502
+ self.load(r)
503
+ return self.activate(r)
504
+
505
+ def _unwind(self, entry):
506
+ """Bindings go live only when activation succeeds (section 8.1),
507
+ so the teardown is the exact inverse: reverse order, always.
508
+
509
+ Returns the errors the scope raised. Section 8.3: "A failing
510
+ release does not stop the rest. Every entry runs, in reverse
511
+ order, whatever any of them does; the errors are collected and
512
+ raised as one `plugin_release_failed`."
513
+ """
514
+ # A selection belongs to ONE activation (section 11.4). Leaving
515
+ # `live` by any door drops it, so the next activation ranks
516
+ # afresh - keeping it would make a consumer prefer a provider it
517
+ # never actually ran against.
518
+ entry['selected'] = {}
519
+ errors = []
520
+ for i in range(len(entry['scope']) - 1, -1, -1):
521
+ try:
522
+ entry['scope'][i]()
523
+ except Exception as err:
524
+ errors.append(err)
525
+ entry['scope'] = []
526
+ return errors
527
+
528
+ def _releasecheck(self, entry, errors):
529
+ """Section 8.3: "A failed release ends the instance in `failed`,
530
+ exactly as a failed callback does (5.2) - a release that raised
531
+ may have leaked, and an instance that may be holding resources it
532
+ cannot account for must not be reactivated."
533
+ """
534
+ if 0 == len(errors):
535
+ return
536
+ entry['status'] = 'failed'
537
+ causes = [str(e) for e in errors]
538
+ fail('plugin_release_failed',
539
+ 'release failed for ' + entry['ref'] + ': ' + '; '.join(causes),
540
+ {'ref': entry['ref'], 'cause': causes})
541
+
542
+ def _unmetof(self, entry):
543
+ """A REQUIREMENT IS ON A CAPABILITY, not on a ref (section 11.1) -
544
+ it is a dependency on something that can do the job, and which
545
+ instance is doing it is exactly the configuration detail a plugin
546
+ must not care about. A bare string is shorthand for `{name}`.
547
+
548
+ A ref satisfies too, because a host that genuinely needs a
549
+ specific instance should not have to invent a capability for it.
550
+ """
551
+ return [
552
+ req['name'] for req in requirements(entry['options'])
553
+ if gatesactivation(req) and 0 == len(self._providersof(req))
554
+ ]
555
+
556
+ def _boundproviders(self, entry):
557
+ """The instance currently SELECTED for each of this one's
558
+ restart-causing requirements. A BINDING IS TO AN INSTANCE, not to
559
+ a capability (section 11.1), and that is what decides behaviour
560
+ when the bound provider leaves while another match remains: the
561
+ selected one going away restarts a `static` consumer even though a
562
+ survivor is available. It is not silently re-pointed - `static` is
563
+ the plugin saying in writing that it cannot survive a provider
564
+ swap, and a survivor being available does not make the swap
565
+ survivable."""
566
+ out = []
567
+ for req in requirements(entry['options']):
568
+ if not restartsonloss(req):
569
+ continue
570
+ ref = self._chosen(entry, req, False)
571
+ if None is not ref and ref not in out:
572
+ out.append(ref)
573
+ return out
574
+
575
+ def _consumersof(self, ref):
576
+ """Live instances whose selected provider is `ref` and which would
577
+ be restarted by losing it."""
578
+ return [
579
+ r for r in sorted(self._inst)
580
+ if r != ref and 'live' == self._inst[r]['status']
581
+ and ref in self._boundproviders(self._inst[r])
582
+ ]
583
+
584
+ def _chosen(self, entry, req, remember):
585
+ """Section 11.4's always-reluctant selection, and the ONE place a
586
+ provider is picked for a live instance.
587
+
588
+ If this instance already selected a provider for `req` and that
589
+ provider is STILL a candidate, it keeps it - a better-ranked
590
+ newcomer does not take it. `remember` is false for the questions
591
+ asked ABOUT an instance rather than BY it: introspection must not
592
+ create a binding.
593
+ """
594
+ cands = self._providersof(req)
595
+ if 0 == len(cands):
596
+ return None
597
+ held = entry['selected'].get(req['name'])
598
+ if None is not held and any(c['ref'] == held for c in cands):
599
+ return held
600
+ if remember:
601
+ entry['selected'][req['name']] = cands[0]['ref']
602
+ return cands[0]['ref']
603
+
604
+ def _holdersof(self, ref):
605
+ """Section 11.3's `hold` asks a DIFFERENT question from the
606
+ cascade, and reading it off `_consumersof` answered the
607
+ cascade's.
608
+
609
+ The cascade wants the edges that RESTART - mandatory-static and
610
+ optional-static - because a restart is what it performs. `hold`
611
+ says "deactivating a REQUIRED instance is
612
+ `plugin_dependency_held`", and required is cardinality:
613
+ `gatesactivation`, not `restartsonloss`. The two sets differ in
614
+ both directions and each difference was a real bug.
615
+
616
+ A MANDATORY-DYNAMIC consumer was excluded, so the strictest
617
+ policy let a provider go that a live consumer could not do
618
+ without - `dynamic` promises survival of a SWAP, and under
619
+ `hold` there is no swap, so the consumer falls back to
620
+ `pending`.
621
+
622
+ An OPTIONAL-STATIC consumer was included, so `hold` refused a
623
+ deactivation on behalf of an instance that had said in writing
624
+ it does not need the thing.
625
+ """
626
+ out = []
627
+ for r in sorted(self._inst):
628
+ consumer = self._inst[r]
629
+ if r == ref or 'live' != consumer['status']:
630
+ continue
631
+ for req in requirements(consumer['options']):
632
+ if not gatesactivation(req):
633
+ continue
634
+ if self._chosen(consumer, req, False) == ref:
635
+ out.append(r)
636
+ break
637
+ return out
638
+
639
+ def _providersof(self, req):
640
+ cands = []
641
+ # ASK WHETHER THE NAME IS A REF, do not assume it. A requirement
642
+ # name is a CAPABILITY name first (section 11.1) and capability
643
+ # names are free-form, so `2fa` is a legal one that no ref could
644
+ # be called. A bare try/except around `canon_ref` did the same job
645
+ # here, but only here - and it read as defensive rather than as
646
+ # the rule, so `dependencycycle` and `graph.candidates` did not
647
+ # get it. `try_ref` is that rule, named, and used in all three.
648
+ want = try_ref(req['name'])
649
+ for ref in sorted(self._inst):
650
+ target = self._inst[ref]
651
+ if 'live' != target['status']:
652
+ continue
653
+ # A ref satisfies directly.
654
+ if ref == want:
655
+ cands.append({'ref': ref, 'pos': target['pos'],
656
+ 'provides': {'name': req['name']}})
657
+ continue
658
+ for prov in target['provides']:
659
+ if prov.get('name') == req['name']:
660
+ cands.append({'ref': ref, 'pos': target['pos'],
661
+ 'provides': prov})
662
+ return resolve_capability(req, cands)
663
+
664
+ def _cascade(self, provider, seen):
665
+ """CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (section 11.3).
666
+
667
+ The cascade is part of the provider's own deactivation and runs
668
+ BEFORE the provider's `deactivate` callback and scope unwind, so a
669
+ consumer's teardown can still call the thing it depends on -
670
+ flushing a buffer to the store it is about to lose is exactly what
671
+ a `deactivate` callback is for, and a cascade that fired after the
672
+ provider was already gone would make that impossible.
673
+
674
+ Order: consumers deepest-first, then the provider. `unload` and
675
+ `close` inherit it, UNDER EITHER DEPENDENCY POLICY, which is what
676
+ makes apply's reverse-load-order teardown safe even when a
677
+ document happens to list a consumer before its provider.
678
+ """
679
+ if seen.get(provider['ref']):
680
+ return
681
+ seen[provider['ref']] = True
682
+
683
+ for ref in self._consumersof(provider['ref']):
684
+ consumer = self._inst[ref]
685
+ if 'live' != consumer['status']:
686
+ continue
687
+ self._cascade(consumer, seen) # deepest-first
688
+ bad = False
689
+ try:
690
+ self._run(consumer, 'deactivate', 'deactivate')
691
+ except Exception:
692
+ bad = True
693
+ errors = self._unwind(consumer)
694
+ if bad or 0 < len(errors):
695
+ # Section 5.2: ANY failure during a transition lands the
696
+ # instance in `failed`. Marking it `pending` handed it
697
+ # straight back to `_reconcile`, which would activate it
698
+ # again the moment the provider returned.
699
+ consumer['status'] = 'failed'
700
+ continue
701
+ consumer['status'] = 'pending'
702
+ consumer['unmet'] = self._unmetof(consumer)
703
+
704
+ def _held(self, entry):
705
+ """The hold check is A GUARD ON AD-HOC DEACTIVATION, NOT ON
706
+ COORDINATED TEARDOWN. In a bulk operation that is removing the
707
+ holders too - `close()`, or an `apply` plan whose own steps
708
+ deactivate them - it is suspended for exactly those holders, and
709
+ the teardown still runs consumers before providers.
710
+
711
+ Otherwise `close()` under `hold` would raise on the first provider
712
+ it reached whenever a document happened to list a consumer after
713
+ it, which is the policy refusing to allow the one teardown it has
714
+ no reason to object to.
715
+ """
716
+ if 'hold' != self._dependency:
717
+ return
718
+ if self._coordinated:
719
+ return
720
+ holders = self._holdersof(entry['ref'])
721
+ if 0 == len(holders):
722
+ return
723
+ fail('plugin_dependency_held',
724
+ 'instance is required by live consumers: ' + entry['ref'],
725
+ {'ref': entry['ref'], 'holders': holders})
726
+
727
+ def _reconcile(self):
728
+ """EAGER reconciliation: run to a fixed point rather than
729
+ scheduling.
730
+
731
+ Two directions, and both are the reason `pending` exists.
732
+ Activation is a STANDING REQUEST, not a one-shot event: a pending
733
+ instance whose requirement arrives activates without being asked
734
+ again, and a LIVE instance whose requirement is lost goes back to
735
+ pending - recursively, through its own consumers.
736
+ """
737
+ moved = True
738
+ rounds = 0
739
+ while moved:
740
+ moved = False
741
+ rounds += 1
742
+ if 1000 < rounds:
743
+ break
744
+
745
+ # Losses first, so a cascade settles in one pass rather than
746
+ # alternating with re-activations.
747
+ for ref in sorted(self._inst):
748
+ entry = self._inst[ref]
749
+ if 'live' != entry['status']:
750
+ continue
751
+ lost = [q for q in requirements(entry['options'])
752
+ if gatesactivation(q)
753
+ and 0 == len(self._providersof(q))]
754
+ if 0 == len(lost):
755
+ continue
756
+ # POLICY IS PER REQUIREMENT, not per instance (section
757
+ # 11.3): only the definition that has the requirement
758
+ # knows what it can cope with, and one instance may hold
759
+ # both a `static` and a `dynamic` one. A `dynamic`
760
+ # requirement whose provider is gone leaves the consumer
761
+ # LIVE and notified; it is a statement about surviving a
762
+ # swap, so it does not restart here.
763
+ if not any(restartsonloss(q) for q in lost):
764
+ continue
765
+ bad = False
766
+ try:
767
+ self._run(entry, 'deactivate', 'deactivate')
768
+ except Exception:
769
+ bad = True
770
+ errors = self._unwind(entry)
771
+ if bad or 0 < len(errors):
772
+ entry['status'] = 'failed'
773
+ moved = True
774
+ continue
775
+ entry['status'] = 'pending'
776
+ entry['unmet'] = self._unmetof(entry)
777
+ moved = True
778
+
779
+ for ref in sorted(self._inst):
780
+ entry = self._inst[ref]
781
+ if 'pending' != entry['status']:
782
+ continue
783
+ if 0 < len(self._unmetof(entry)):
784
+ continue
785
+ try:
786
+ self._run(entry, 'activate', 'activate')
787
+ entry['status'] = 'live'
788
+ entry['unmet'] = []
789
+ moved = True
790
+ except Exception:
791
+ self._unwind(entry)
792
+ entry['status'] = 'failed'
793
+ moved = True
794
+
795
+ # --- ordering -----------------------------------------------------
796
+
797
+ def order(self, point=None):
798
+ # Sorted by declaration SEQUENCE, which is what makes the
799
+ # section 7 sort's fall-through deterministic in a language whose
800
+ # maps have no insertion order. Section 7 breaks ties by `pos`;
801
+ # two instances CAN share one - `declare` defaults `pos` to the
802
+ # registry size, so an unload followed by a fresh declare reuses
803
+ # a surviving instance's - and past that this was falling through
804
+ # to dict order. `seq` is that order, made explicit.
805
+ live = [r for r in self._inst if 'live' == self._inst[r]['status']]
806
+ live.sort(key=lambda r: self._inst[r]['seq'])
807
+ bindings = [
808
+ {'ref': r, 'pos': self._inst[r]['pos'],
809
+ 'order': self._inst[r]['order']}
810
+ for r in live
811
+ ]
812
+ spec = self._points.get(point) if point else None
813
+ return resolve_order(bindings, spec.get('pin') if spec else None)
814
+
815
+ # --- points -------------------------------------------------------
816
+
817
+ def _bound(self, point):
818
+ """Live bindings on a point, in resolved order. Recomputed on any
819
+ change to the live set (section 7) rather than cached at startup -
820
+ the bug a host discovers only when something deactivates in
821
+ production."""
822
+ out = []
823
+ for ref in self.order(point):
824
+ entry = self._inst[ref]
825
+ # The band is the INSTANCE's ordering block (section 7),
826
+ # stamped by the host. A plugin passing its own would be
827
+ # ranking itself above the order its document declared.
828
+ block = entry['order'] or {}
829
+ band = block.get('band')
830
+ band = band if isinstance(band, int) and not isinstance(band, bool) else 0
831
+ for b in entry['bindings']:
832
+ if b['point'] == point:
833
+ out.append(dict(b, band=band))
834
+ return out
835
+
836
+ def _pointspec(self, point, want):
837
+ spec = self._points.get(point)
838
+ if None is spec:
839
+ fail('plugin_point_unknown', 'no such point: ' + point,
840
+ {'point': point})
841
+ kind = spec.get('kind')
842
+ if 'hook' == want:
843
+ # A point with no declared kind is a hook, which is what makes
844
+ # `{}` the minimal point declaration.
845
+ if kind and 'hook' != kind:
846
+ fail('plugin_point_kind', 'point is not a hook: ' + point,
847
+ {'point': point, 'kind': kind})
848
+ return spec
849
+ if kind != want:
850
+ fail('plugin_point_kind',
851
+ 'point is not a ' + want + ': ' + point,
852
+ {'point': point, 'kind': kind})
853
+ return spec
854
+
855
+ def emit(self, point, arg=None):
856
+ spec = self._pointspec(point, 'hook')
857
+ return fanout(self._bound(point), spec.get('mode') or 'emit', arg)
858
+
859
+ def call(self, point, *args):
860
+ spec = self._pointspec(point, 'chain')
861
+ base = spec.get('base') or (lambda *a: a[0] if 0 < len(a) else None)
862
+ return compose(self._bound(point), base)(*args)
863
+
864
+ def provider(self, point, *args):
865
+ spec = self._pointspec(point, 'provider')
866
+ pick = pickone(self._bound(point), spec)
867
+ if not pick['winner']:
868
+ return spec.get('default')
869
+ return pick['winner']['fn'](*args)
870
+
871
+ def shadowed(self, point):
872
+ """The losers are VISIBLE rather than silently ignored (section
873
+ 6.3)."""
874
+ spec = self._points.get(point)
875
+ if None is spec:
876
+ return []
877
+ return pickone(self._bound(point), spec)['shadowed']
878
+
879
+ def exports(self, spec):
880
+ allof = []
881
+ for ref in sorted(self._inst):
882
+ entry = self._inst[ref]
883
+ # Exports of a `loaded` (not live) instance are VISIBLE
884
+ # (section 11).
885
+ if entry['status'] in ('declared', 'failed'):
886
+ continue
887
+ for key in sorted(entry['exports']):
888
+ allof.append({'ref': ref, 'key': key,
889
+ 'value': entry['exports'][key]})
890
+ return resolve_export(spec, allof)
891
+
892
+ def capability(self, name):
893
+ """The live providers of a capability, best-first (section
894
+ 11.1)."""
895
+ cands = []
896
+ for ref in sorted(self._inst):
897
+ entry = self._inst[ref]
898
+ if 'live' != entry['status']:
899
+ continue
900
+ for prov in entry['provides']:
901
+ if prov.get('name') == name:
902
+ cands.append({'ref': ref, 'pos': entry['pos'],
903
+ 'provides': prov})
904
+ return [c['ref'] for c in resolve_capability({'name': name}, cands)]
905
+
906
+ # --- documents ----------------------------------------------------
907
+
908
+ def apply(self, doc, profile=None):
909
+ """Section 9.6: "load what is missing, UNLOAD WHAT IS GONE, patch
910
+ what changed, and move activation state to match", with the
911
+ stated ordering - "deactivations and unloads first (reverse load
912
+ order), then loads, then activations in load order".
913
+
914
+ FOUR PHASES, NOT ONE INTERLEAVED LOOP. An earlier draft walked
915
+ the document once, which never looked at instances the new
916
+ document had DROPPED - so an integration removed from a config
917
+ reload stayed live with its bindings and resources.
918
+ """
919
+ self._guard()
920
+ profile = profile or self._opts.get('profile')
921
+ norm = normalize_config({
922
+ 'doc': doc, 'profile': profile,
923
+ 'keys': self._opts.get('keys'), 'reserved': self._reserved,
924
+ })
925
+
926
+ want = norm['order']
927
+ defaults = self._opts.get('defaults') or {}
928
+ optionsof = {}
929
+ for ref in want:
930
+ optionsof[ref] = resolve_options({
931
+ 'ref': ref, 'doc': doc, 'profile': profile,
932
+ 'shape': self._shapeof(ref),
933
+ 'hostdefaults': defaults.get(parse_ref(ref)['name']),
934
+ })
935
+
936
+ def wantlive(ref):
937
+ """Should this ref be LIVE after the apply? False for a ref
938
+ the document declares lazy or inactive AND for one it does
939
+ not name at all - which is what makes "unload what is gone"
940
+ and "unload what was toggled off" one rule rather than two."""
941
+ ent = norm['instance'].get(ref)
942
+ return None is not ent and ent['active'] and 'eager' == ent['start']
943
+
944
+ # --- phase 1: deactivations and unloads, REVERSE load order ---
945
+ drop = [r for r in self._inst
946
+ if 'declared' != self._inst[r]['status'] and not wantlive(r)]
947
+ # Highest `pos` first, ref-descending for a tie, so a consumer
948
+ # declared after its provider goes down first.
949
+ drop.sort(key=lambda r: (-self._inst[r]['pos'],
950
+ tuple(-ord(c) for c in r)))
951
+ for ref in drop:
952
+ self.unload(ref)
953
+
954
+ # --- phase 2: declare and patch EVERYTHING, in load order -----
955
+ for ref in want:
956
+ ent = norm['instance'][ref]
957
+ # NO OPTIONS HERE, and the omission is the fix rather than
958
+ # an oversight. `declare` ADOPTS the options map it is handed
959
+ # as the instance's own, so passing the resolved map made
960
+ # target and source THE SAME MAP in the refill below - which
961
+ # cleared its own source and left a first-time instance with
962
+ # no options at all. `declare` makes its own empty map and
963
+ # the refill fills it, so both paths are now one path.
964
+ self.declare(ref, {'order': ent.get('order'), 'pos': ent['pos']})
965
+ # The bar is REASSERTED ON EVERY APPLY, in both directions - a
966
+ # document that turns the instance back on clears it, which is
967
+ # the whole point of a config switch.
968
+ self._inst[ref]['barred'] = not ent['active']
969
+ # REFILL rather than REBIND. A definition's callbacks close
970
+ # over the options map they were handed at `define`.
971
+ refill(self._inst[ref]['options'], optionsof[ref])
972
+ self._inst[ref]['order'] = ent.get('order')
973
+ self._inst[ref]['pos'] = ent['pos']
974
+
975
+ # --- phase 3: loads, in load order ----------------------------
976
+ # ONLY THE EAGER, ACTIVE ONES: "a document of twenty lazy
977
+ # instances is twenty map entries and no executed code" (9.6).
978
+ for ref in want:
979
+ if wantlive(ref):
980
+ self.load(ref)
981
+
982
+ # --- phase 4: activations, in load order ----------------------
983
+ for ref in want:
984
+ if wantlive(ref):
985
+ self.activate(ref)
986
+
987
+ def _shapeof(self, ref):
988
+ definition = self.catalog.get(parse_ref(ref)['name'])
989
+ return definition.get('shape') if definition else None
990
+
991
+ def options(self, ref, patch):
992
+ self._guard()
993
+ entry = self._need(ref)
994
+ previous = dict(entry['options'])
995
+ refill(entry['options'], resolve_options({
996
+ 'ref': entry['ref'], 'shape': self._shapeof(entry['ref']),
997
+ 'doc': {}, 'patch': dict(previous, **(patch or {})),
998
+ }))
999
+ if 'live' == entry['status']:
1000
+ reconfigure = entry['def'].get('reconfigure')
1001
+ if callable(reconfigure):
1002
+ self._intransition = True
1003
+ try:
1004
+ reconfigure(Inst(self, entry), entry['options'], previous)
1005
+ finally:
1006
+ self._intransition = False
1007
+ else:
1008
+ # Always correct and sometimes expensive; `reconfigure`
1009
+ # exists to make the common case cheap (section 9.4).
1010
+ self.deactivate(entry['ref'])
1011
+ self.activate(entry['ref'])
1012
+
1013
+ def close(self):
1014
+ # A bulk teardown removing the holders too, so `hold` is suspended
1015
+ # for exactly those holders (section 11.3) - while the
1016
+ # consumers-first cascade still runs, which is the half that
1017
+ # matters.
1018
+ self._coordinated = True
1019
+ try:
1020
+ for ref in reversed(sorted(self._inst)):
1021
+ self.unload(ref)
1022
+ finally:
1023
+ self._coordinated = False
1024
+
1025
+ def positionof(self, ref, point):
1026
+ """The same record section 6.6 gives a plugin about itself,
1027
+ reachable from outside for the corpus. A plugin asks via
1028
+ `inst.position(point)`."""
1029
+ entry = self._inst.get(canon_ref(ref))
1030
+ if not entry:
1031
+ fail('plugin_not_loaded', 'no such instance: ' + ref,
1032
+ {'ref': ref})
1033
+ ranked = self.order(point)
1034
+ index = ranked.index(entry['ref']) if entry['ref'] in ranked else -1
1035
+ return {
1036
+ 'index': index, 'count': len(ranked),
1037
+ # Section 6.2 composes b1(b2(b3(base))) with the FIRST binding
1038
+ # OUTERMOST, so these are not index 0 and index count-1 the
1039
+ # other way round. Getting this backwards is the exact error
1040
+ # the positional pin vocabulary exists to prevent.
1041
+ 'outermost': 0 == index,
1042
+ 'innermost': index == len(ranked) - 1,
1043
+ }
1044
+
1045
+ def define(self, definition):
1046
+ self.catalog.add(definition)
1047
+
1048
+
1049
+ def refill(target, source):
1050
+ """Empty the target and refill it, so callers holding the reference
1051
+ see the new values."""
1052
+ target.clear()
1053
+ target.update(source or {})