@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,1575 @@
1
+ // VENDORED: @voxgig/plugin 0.1.6 (go/plugin/host.go)
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 (§5), extension points (§6), and
5
+ * resource capture (§8).
6
+ *
7
+ * TWO RULES SHAPE EVERY METHOD BELOW.
8
+ *
9
+ * Transitions are SEQUENTIAL (§5.2). One at a time, in call order, never
10
+ * 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 (§18's portability budget). A transition
16
+ * settles by running the state machine to a fixed point, not by
17
+ * suspending on a promise. Every port must be able to do the same, and
18
+ * fourteen of them will not have JavaScript's event loop. */
19
+
20
+ package plugin
21
+
22
+ import (
23
+ "fmt"
24
+ "sort"
25
+ "sync"
26
+ )
27
+
28
+ type PointSpec = Spec
29
+
30
+ type HostOptions struct {
31
+ Catalog *Catalog
32
+ Reserved []string
33
+ Keys Keys
34
+ Defaults map[string]any
35
+ Profile string
36
+ Points map[string]Spec
37
+ // Dependency is §11.3. `restart` (the default) treats provider
38
+ // replacement as an ordinary runtime operation: deactivate the old
39
+ // store, activate the new one, and everything that depended on it
40
+ // rides through, having released the old one's resources in between.
41
+ //
42
+ // `hold` is the strict reading — deactivating a required instance is
43
+ // `plugin_dependency_held`, naming the holders. NOT the default,
44
+ // because a station that cannot swap a provider without a restart
45
+ // has lost the argument for having a plugin system.
46
+ Dependency string
47
+ }
48
+
49
+ // Live is one instance's record. The exported half is what
50
+ // introspection reads; the rest is the host's.
51
+ type Live struct {
52
+ Ref string
53
+ Status Status
54
+ Pos int
55
+ Seq int
56
+ Options map[string]any
57
+ State map[string]any
58
+ // Inner is set when this instance is itself a host (§6.5).
59
+ Inner *Host
60
+
61
+ def Definition
62
+ order *OrderBlock
63
+ // selected is §11.4's ALWAYS-RELUCTANT rebinding made concrete: the
64
+ // provider ref this instance's activation actually chose, per
65
+ // requirement name. "A satisfied requirement is not re-bound while
66
+ // it stays satisfied" is a statement about a REMEMBERED choice —
67
+ // re-ranking on every question silently re-points a live consumer at
68
+ // any better newcomer, and then losing the provider it was really
69
+ // using does not restart it. Captured at activate, cleared on exit.
70
+ selected map[string]string
71
+ // barred is §9.6's `active: false` — "declares it and bars it: it
72
+ // appears in `host.list()`, and `activate` and `ready` on it fail
73
+ // rather than quietly doing nothing". THE BAR OUTLIVES THE APPLY
74
+ // THAT SET IT: a flag consulted only while `apply` ran let a later
75
+ // direct `Ready` bring the instance live.
76
+ barred bool
77
+ // unmet holds requirements this instance declared but has not been
78
+ // given.
79
+ unmet []string
80
+ // scope holds the resources the instance scope holds, newest last —
81
+ // unwound in REVERSE, because that is the only order in which
82
+ // teardown mirrors setup (§8.3).
83
+ scope []func()
84
+ // bindings are declared in `define`, inserted only when activation
85
+ // SUCCEEDS (§8.1). Holding them until then is what makes a failed
86
+ // activate leave nothing behind.
87
+ bindings []Bound
88
+ // exports are declared in `define`, and VISIBLE while merely
89
+ // `loaded` (§11): they are data, and hiding them would make the
90
+ // loaded state useless for introspection.
91
+ exports map[string]any
92
+ provides []Provided
93
+ }
94
+
95
+ type Event struct {
96
+ Ref string `json:"ref"`
97
+ Event string `json:"event"`
98
+ Seq int `json:"seq"`
99
+ Status Status `json:"status"`
100
+ }
101
+
102
+ type Observable struct {
103
+ Status map[string]Status `json:"status"`
104
+ Open int `json:"open"`
105
+ Log []string `json:"log"`
106
+ Result any `json:"result"`
107
+ }
108
+
109
+ type Host struct {
110
+ opts HostOptions
111
+ catalog *Catalog
112
+ reserved []string
113
+ points map[string]Spec
114
+ dependency string
115
+
116
+ // coordinated is set for the duration of a bulk teardown, so `held`
117
+ // knows this is a coordinated operation rather than an ad-hoc
118
+ // deactivation.
119
+ coordinated bool
120
+
121
+ // §18: "a port uses its idiom (a mutex in Go/Rust/Java, the GIL
122
+ // where that is enough)". §5.2 makes transitions SEQUENTIAL — one at
123
+ // a time, in call order, never interleaved — and `intransition`
124
+ // cannot deliver that: it is set inside `run`, so two goroutines
125
+ // both pass `guard` and both run a callback. This holds for the
126
+ // WHOLE public transition, reconciliation included, which is the
127
+ // unit §5.2 names.
128
+ //
129
+ // It is NOT reentrant, and must not be: a transition attempted from
130
+ // inside a lifecycle callback is `plugin_reentrant`, and `enter`
131
+ // answers that without ever blocking. Below the door the unlocked
132
+ // bodies (`declare`, `load`, `activate`, …) call each other, so the
133
+ // lock is taken exactly once per public call.
134
+ mu sync.Mutex
135
+
136
+ inst map[string]*Live
137
+ log []string
138
+ // events is §14: the lifecycle event record. `seq` distinguishes ONE
139
+ // INCARNATION of stripe$test from the next, which is the whole
140
+ // reason it is not `pos` (§4 rule 4).
141
+ events []Event
142
+ seqn int
143
+ open int
144
+ intransition bool
145
+ // phase is WHICH callback is running, not merely that one is. §8.1
146
+ // puts resource capture in `activate` and §8.3 says `Release`
147
+ // outside `activate` is `plugin_release_scope` — and `intransition`
148
+ // alone cannot tell `activate` from `define`, so it admitted an
149
+ // Acquire in `define` whose scope `Unload` would never unwind.
150
+ phase string
151
+ }
152
+
153
+ func MakeHost(options HostOptions) *Host {
154
+ h := &Host{
155
+ opts: options,
156
+ catalog: options.Catalog,
157
+ reserved: options.Reserved,
158
+ points: options.Points,
159
+ dependency: or(options.Dependency, "restart"),
160
+ inst: map[string]*Live{},
161
+ log: []string{},
162
+ events: []Event{},
163
+ }
164
+ if nil == h.catalog {
165
+ h.catalog, _ = MakeCatalog()
166
+ }
167
+ if nil == h.points {
168
+ h.points = map[string]Spec{}
169
+ }
170
+ return h
171
+ }
172
+
173
+ func (h *Host) Catalog() *Catalog { return h.catalog }
174
+
175
+ // --- observation -----------------------------------------------------
176
+
177
+ // List is introspection, and introspection NEVER advances the state
178
+ // (§5.2). A status page must not be a way to accidentally import twenty
179
+ // packages.
180
+ func (h *Host) List() map[string]Status {
181
+ out := map[string]Status{}
182
+ for _, r := range sortedkeys(h.inst) {
183
+ out[r] = h.inst[r].Status
184
+ }
185
+ return out
186
+ }
187
+
188
+ // Instance is the introspection lookup. A MALFORMED REF IS
189
+ // `plugin_bad_name` HERE TOO: the canonical calls `canonref`, which
190
+ // raises, and a port that swallowed the parse failure answered the
191
+ // ordinary "no such instance" instead — a different answer to a
192
+ // different question. `nil, nil` is the well-formed-but-absent case.
193
+ func (h *Host) Instance(ref string) (*Live, error) {
194
+ r, err := CanonRef(ref)
195
+ if nil != err {
196
+ return nil, err
197
+ }
198
+ return h.inst[r], nil
199
+ }
200
+
201
+ func (h *Host) Trace() []Event { return append([]Event{}, h.events...) }
202
+
203
+ func (h *Host) Observable(result any) Observable {
204
+ return Observable{
205
+ Status: h.List(),
206
+ Open: h.open,
207
+ Log: append([]string{}, h.log...),
208
+ Result: result,
209
+ }
210
+ }
211
+
212
+ // --- the state machine -----------------------------------------------
213
+
214
+ func (h *Host) guard() error {
215
+ if h.intransition {
216
+ return Fail("plugin_reentrant",
217
+ "transition attempted from inside a lifecycle callback", nil)
218
+ }
219
+ return nil
220
+ }
221
+
222
+ // enter is the door every PUBLIC transition goes through, and the only
223
+ // place `h.mu` is taken. It returns the matching release.
224
+ //
225
+ // The two rules it has to serve pull in opposite directions. §5.2 wants
226
+ // transitions SEQUENTIAL, which is a lock; and §5.2 also wants a
227
+ // transition attempted from INSIDE a lifecycle callback to answer
228
+ // `plugin_reentrant`, which is the one caller that must not block —
229
+ // it is the goroutine already holding the lock, so blocking is a
230
+ // deadlock.
231
+ //
232
+ // TryLock separates them as far as Go allows. Taking the lock proves
233
+ // nothing else is in flight, so the call cannot be reentrant. Failing to
234
+ // take it means SOMEONE holds it, and `intransition` says whether that
235
+ // someone is running a callback — the only state from which a reentrant
236
+ // call can arise.
237
+ //
238
+ // THE RESIDUAL WINDOW IS REAL AND IS NOT PAPERED OVER: a genuinely
239
+ // concurrent caller that arrives while a callback is running gets
240
+ // `plugin_reentrant` instead of waiting, because Go exposes no goroutine
241
+ // identity to tell the two apart. It is a refusal with a code, not a
242
+ // corruption, and it is strictly better than the interleaving an
243
+ // unlocked host allowed; a host that needs the other answer should
244
+ // serialise its own calls. See AGENTS.md.
245
+ func (h *Host) enter() (func(), error) {
246
+ if h.mu.TryLock() {
247
+ return h.mu.Unlock, nil
248
+ }
249
+ if err := h.guard(); nil != err {
250
+ return nil, err
251
+ }
252
+ h.mu.Lock()
253
+ return h.mu.Unlock, nil
254
+ }
255
+
256
+ func (h *Host) need(ref string) (*Live, error) {
257
+ r, err := CanonRef(ref)
258
+ if nil != err {
259
+ return nil, err
260
+ }
261
+ e := h.inst[r]
262
+ if nil == e {
263
+ return nil, Fail("plugin_not_loaded", "no such instance: "+r,
264
+ map[string]any{"ref": r})
265
+ }
266
+ return e, nil
267
+ }
268
+
269
+ func (h *Host) checkreserved(ref string) error {
270
+ return checkreservedref(ref, h.reserved)
271
+ }
272
+
273
+ func (h *Host) run(e *Live, fn func(*Inst) error, at string) error {
274
+ h.log = append(h.log, e.Ref+":"+at)
275
+ h.events = append(h.events, Event{Ref: e.Ref, Event: at, Seq: e.Seq, Status: e.Status})
276
+ if nil == fn {
277
+ return nil
278
+ }
279
+ h.intransition = true
280
+ h.phase = at
281
+ defer func() { h.intransition = false; h.phase = "" }()
282
+ err := fn(h.api(e))
283
+ if nil == err {
284
+ return nil
285
+ }
286
+ // §12: `plugin_define_failed` and its three siblings are "a callback
287
+ // raised; wraps the cause". AN ERROR THAT ALREADY CARRIES A CODE
288
+ // KEEPS IT — the code is the error's identity, and a plugin
289
+ // returning `store_unreachable` must not have it rewritten. Only a
290
+ // code-less error is wrapped, which is the ordinary case for a
291
+ // callback that let a library error through.
292
+ if "" != CodeOf(err) {
293
+ return err
294
+ }
295
+ return Fail("plugin_"+at+"_failed",
296
+ e.Ref+" raised in "+at+": "+err.Error(),
297
+ map[string]any{"ref": e.Ref, "cause": err.Error()})
298
+ }
299
+
300
+ // Inst is what a definition's callbacks see. Deliberately not the
301
+ // internal record: a plugin that could reach `Status` could also write
302
+ // it.
303
+ type Inst struct {
304
+ h *Host
305
+ e *Live
306
+ }
307
+
308
+ func (h *Host) api(e *Live) *Inst { return &Inst{h: h, e: e} }
309
+
310
+ func (i *Inst) Ref() string { return i.e.Ref }
311
+ func (i *Inst) Name() string { return refname(i.e.Ref) }
312
+ func (i *Inst) Tag() string { r, _ := ParseRef(i.e.Ref); return r.Tag }
313
+ func (i *Inst) Options() map[string]any { return i.e.Options }
314
+ func (i *Inst) State() map[string]any { return i.e.State }
315
+ func (i *Inst) Host() *Host { return i.h }
316
+
317
+ // Release registers a foreign resource the host did not hand out (§8.3);
318
+ // host calls are recorded automatically.
319
+ func (i *Inst) Release(fn func()) error {
320
+ // §8.3: "`inst.release` outside `activate` is
321
+ // `plugin_release_scope`". `intransition` is true in `define` too,
322
+ // and a scope entry registered there is never unwound.
323
+ if "activate" != i.h.phase {
324
+ return Fail("plugin_release_scope", "release called outside activate", nil)
325
+ }
326
+ // SYMMETRIC WITH Acquire, and it has to be: `open` counts the
327
+ // resources CURRENTLY HELD, so an entry that is registered and then
328
+ // unwound must leave the count where it found it.
329
+ done := false
330
+ h := i.h
331
+ i.e.scope = append(i.e.scope, func() {
332
+ if !done {
333
+ done = true
334
+ h.open -= 1
335
+ fn()
336
+ }
337
+ })
338
+ h.open += 1
339
+ return nil
340
+ }
341
+
342
+ // Acquire is the synthetic counter the driver owns, so "what is open" is
343
+ // data rather than an assertion each port words differently.
344
+ //
345
+ // Returns its own release, so a plugin can hand one back early. The
346
+ // scope still holds the entry and unwinding it twice is a no-op —
347
+ // releasing early must not make teardown wrong.
348
+ func (i *Inst) Acquire() (func(), error) {
349
+ // §8.1: resources are "acquired during `activate` — the scope's
350
+ // actual job". Same reason as `Release` above.
351
+ if "activate" != i.h.phase {
352
+ return nil, Fail("plugin_release_scope", "acquire called outside activate", nil)
353
+ }
354
+ done := false
355
+ h := i.h
356
+ rel := func() {
357
+ if !done {
358
+ done = true
359
+ h.open -= 1
360
+ }
361
+ }
362
+ i.e.scope = append(i.e.scope, rel)
363
+ h.open += 1
364
+ return rel, nil
365
+ }
366
+
367
+ // Bind attaches a function to a host point. Declared in `define`; the
368
+ // host inserts it only after `activate` returns successfully (§8.1),
369
+ // which is why a failing activate leaves no live binding behind.
370
+ func (i *Inst) Bind(point string, fn BindFn, band int) error {
371
+ // §12's `plugin_bind_scope`: "binding declared outside `define`".
372
+ // §8.1 puts binding DECLARATION in `define` and INSERTION at a
373
+ // successful activate, and the guard was the half nobody wrote — so
374
+ // a binding added from `activate` went live without being part of
375
+ // the loaded definition, and a deactivate/activate cycle appended
376
+ // it again. The code was in the table before anything raised it.
377
+ if "define" != i.h.phase {
378
+ return Fail("plugin_bind_scope", "bind called outside define: "+point,
379
+ map[string]any{"ref": i.e.Ref, "point": point})
380
+ }
381
+ if _, ok := i.h.points[point]; !ok {
382
+ return Fail("plugin_point_unknown", "no such point: "+point,
383
+ map[string]any{"point": point})
384
+ }
385
+ i.e.bindings = append(i.e.bindings, Bound{Ref: i.e.Ref, Point: point, Fn: fn, Band: band})
386
+ return nil
387
+ }
388
+
389
+ // Export publishes a value for other plugins and for the application
390
+ // (§11).
391
+ func (i *Inst) Export(key string, value any) { i.e.exports[key] = value }
392
+
393
+ // Provides declares what this instance can do for others (§11.1).
394
+ func (i *Inst) Provides(p Provided) { i.e.provides = append(i.e.provides, p) }
395
+
396
+ type Position struct {
397
+ Index int `json:"index"`
398
+ Count int `json:"count"`
399
+ Outermost bool `json:"outermost"`
400
+ Innermost bool `json:"innermost"`
401
+ }
402
+
403
+ /* Position reports where this binding landed (§6.6) — the plugin-side
404
+ * counterpart to a host pin. Station found that a plugin can need to
405
+ * KNOW it is in the right place: its middleware must sit immediately
406
+ * outside the base transport or its "wire truth" events are fiction.
407
+ *
408
+ * THE HOST DOES NOT POLICE THIS; it just makes the fact available. A
409
+ * plugin that requires a position it did not get fails loudly rather
410
+ * than reporting nonsense — and that is the plugin's call, because only
411
+ * it knows what its position means. Verification tells a plugin it was
412
+ * misplaced; a pin (§7) stops the misplacement from being expressible at
413
+ * all. The two are not substitutes. */
414
+ func (i *Inst) Position(point string) (Position, error) {
415
+ return i.h.PositionOf(i.e.Ref, point)
416
+ }
417
+
418
+ /* Nest: AN INSTANCE MAY ITSELF BE A HOST (§6.5), and THE OUTER ONE OWNS
419
+ * THE INNER ONE'S LIFETIME. Registering the teardown in the instance
420
+ * scope is what makes that true rather than aspirational: the inner host
421
+ * closes when the outer instance deactivates, in the same reverse unwind
422
+ * as every other resource. */
423
+ func (i *Inst) Nest(nestopts HostOptions) (*Host, error) {
424
+ if !i.h.intransition {
425
+ return nil, Fail("plugin_release_scope", "nest called outside a lifecycle callback", nil)
426
+ }
427
+ inner := MakeHost(nestopts)
428
+ i.e.scope = append(i.e.scope, func() { inner.Close() })
429
+ i.e.Inner = inner
430
+ return inner, nil
431
+ }
432
+
433
+ // AutoTag is EXPLICIT (§4 rule 3). `Declare("stripe", {Tag: "?"})`
434
+ // assigns the LOWEST UNUSED POSITIVE INTEGER tag and returns the
435
+ // assigned pair. Without `"?"`, a collision is an error.
436
+ //
437
+ // It needs a host because it must know what is already declared, which
438
+ // is why it cannot live in the pure `ref` section — the correction P1.7
439
+ // made to §15.3.
440
+ func (h *Host) AutoTag(name string) (string, error) {
441
+ for n := 1; ; n++ {
442
+ cand, err := FormatRef(name, itoa(n))
443
+ if nil != err {
444
+ return "", err
445
+ }
446
+ if _, taken := h.inst[cand]; !taken {
447
+ return cand, nil
448
+ }
449
+ }
450
+ }
451
+
452
+ type DeclareSpec struct {
453
+ Definition string
454
+ Options map[string]any
455
+ Order *OrderBlock
456
+ Pos *int
457
+ Tag string
458
+ // HostOwned is §9.1: "The host declares those instances itself,
459
+ // after the user merge, and always wins." Set ONLY by HostDeclare.
460
+ HostOwned bool
461
+ }
462
+
463
+ func (h *Host) Declare(ref string, spec DeclareSpec) (*Live, error) {
464
+ leave, err := h.enter()
465
+ if nil != err {
466
+ return nil, err
467
+ }
468
+ defer leave()
469
+ return h.declare(ref, spec)
470
+ }
471
+
472
+ // declare and its siblings are the UNLOCKED bodies. The public
473
+ // transitions call each other — `ready` walks declare/load/activate,
474
+ // `apply` walks all four — and a Go mutex is not reentrant, so the lock
475
+ // is taken once at the door and never again below it.
476
+ func (h *Host) declare(ref string, spec DeclareSpec) (*Live, error) {
477
+ if "?" == spec.Tag {
478
+ r, err := CanonRef(ref)
479
+ if nil != err {
480
+ return nil, err
481
+ }
482
+ ref, err = h.AutoTag(refname(r))
483
+ if nil != err {
484
+ return nil, err
485
+ }
486
+ }
487
+ r, err := CanonRef(ref)
488
+ if nil != err {
489
+ return nil, err
490
+ }
491
+ if !spec.HostOwned {
492
+ if err := h.checkreserved(r); nil != err {
493
+ return nil, err
494
+ }
495
+ }
496
+ defname := or(spec.Definition, refname(r))
497
+ def, ok := h.catalog.Get(defname)
498
+ if !ok {
499
+ return nil, Fail("plugin_unknown_definition", "not in catalog: "+defname,
500
+ map[string]any{"name": defname})
501
+ }
502
+
503
+ if existing := h.inst[r]; nil != existing {
504
+ // §4 rule 1: a pair addresses at most one instance. Re-declaring
505
+ // the SAME definition is the idempotent case; a different one is
506
+ // a duplicate, not a silent overwrite (seneca) and not an
507
+ // impossibility (sdkgen).
508
+ if existing.def.Name != def.Name {
509
+ return nil, Fail("plugin_ref_duplicate", "instance already declared: "+r,
510
+ map[string]any{"ref": r})
511
+ }
512
+ return existing, nil
513
+ }
514
+
515
+ pos := len(h.inst)
516
+ if nil != spec.Pos {
517
+ pos = *spec.Pos
518
+ }
519
+ options := spec.Options
520
+ if nil == options {
521
+ options = map[string]any{}
522
+ }
523
+ e := &Live{
524
+ Ref: r, def: def, Status: StatusDeclared,
525
+ Pos: pos, Seq: h.seqn,
526
+ Options: options,
527
+ State: map[string]any{},
528
+ selected: map[string]string{},
529
+ order: spec.Order, unmet: []string{}, scope: []func(){},
530
+ bindings: []Bound{}, exports: map[string]any{}, provides: []Provided{},
531
+ }
532
+ h.seqn++
533
+ h.inst[r] = e
534
+ return e, nil
535
+ }
536
+
537
+ // HostDeclare is §9.1's host-owned path: a host that reserves a name
538
+ // MUST still be able to declare the instance it reserved.
539
+ //
540
+ // THE BOUNDARY IS BY METHOD, NOT BY CALLER, and that is a real limit: no
541
+ // language here can tell the embedding host from a plugin holding the
542
+ // same host object. What reservation protects is CONFIGURATION —
543
+ // documents, overlays, `VOXGIG_PLUGIN_*`, construction options and
544
+ // ordinary Declare/Load/Options — and all of that still checks.
545
+ func (h *Host) HostDeclare(ref string, spec DeclareSpec) (*Live, error) {
546
+ leave, err := h.enter()
547
+ if nil != err {
548
+ return nil, err
549
+ }
550
+ defer leave()
551
+ spec.HostOwned = true
552
+ return h.declare(ref, spec)
553
+ }
554
+
555
+ func (h *Host) Load(ref string, spec DeclareSpec) (*Live, error) {
556
+ leave, err := h.enter()
557
+ if nil != err {
558
+ return nil, err
559
+ }
560
+ defer leave()
561
+ return h.load(ref, spec)
562
+ }
563
+
564
+ func (h *Host) load(ref string, spec DeclareSpec) (*Live, error) {
565
+ e, err := h.declare(ref, spec)
566
+ if nil != err {
567
+ return nil, err
568
+ }
569
+ if StatusDeclared != e.Status {
570
+ return e, nil // idempotent in the trivial direction
571
+ }
572
+ if nil != spec.Options {
573
+ e.Options = spec.Options
574
+ }
575
+ if err := h.run(e, e.def.Define, "define"); nil != err {
576
+ e.Status = StatusFailed
577
+ return nil, err
578
+ }
579
+ e.Status = StatusLoaded
580
+
581
+ // AT LOAD, and before anything runs: a cycle through
582
+ // restart-causing requirements does not settle, and the only safe
583
+ // time to report a non-terminating reconcile is before it starts
584
+ // (§11.3). `provides` is populated by `define`, which has just run,
585
+ // so this is the first moment the graph is complete.
586
+ if err := CheckCycle(h.graphnodes()); nil != err {
587
+ e.Status = StatusFailed
588
+ return nil, err
589
+ }
590
+ return e, nil
591
+ }
592
+
593
+ // graphnodes is the requirement graph as plain data, for the pure
594
+ // detector.
595
+ func (h *Host) graphnodes() []DependNode {
596
+ out := []DependNode{}
597
+ for _, r := range sortedkeys(h.inst) {
598
+ names := []string{}
599
+ for _, p := range h.inst[r].provides {
600
+ names = append(names, p.Name)
601
+ }
602
+ out = append(out, DependNode{
603
+ Ref: r, Provides: names, Requires: Requirements(h.inst[r].Options)})
604
+ }
605
+ return out
606
+ }
607
+
608
+ func (h *Host) Activate(ref string) (*Live, error) {
609
+ leave, err := h.enter()
610
+ if nil != err {
611
+ return nil, err
612
+ }
613
+ defer leave()
614
+ return h.activate(ref)
615
+ }
616
+
617
+ func (h *Host) activate(ref string) (*Live, error) {
618
+ e, err := h.need(ref)
619
+ if nil != err {
620
+ return nil, err
621
+ }
622
+ if StatusLive == e.Status {
623
+ return e, nil // no-op returning success
624
+ }
625
+ if StatusFailed == e.Status {
626
+ return nil, Fail("plugin_bad_state", "instance has failed: "+e.Ref,
627
+ map[string]any{"ref": e.Ref})
628
+ }
629
+ // §9.6: `active: false` bars the instance from running, and the bar
630
+ // is on the INSTANCE rather than on the apply that set it. `Ready`
631
+ // reaches this through `activate`, so one guard covers both verbs
632
+ // the design names.
633
+ if e.barred {
634
+ return nil, Fail("plugin_inactive",
635
+ "instance is barred by active: false: "+e.Ref,
636
+ map[string]any{"ref": e.Ref})
637
+ }
638
+ if StatusDeclared == e.Status {
639
+ if _, err := h.load(e.Ref, DeclareSpec{}); nil != err {
640
+ return nil, err
641
+ }
642
+ }
643
+
644
+ // A declared requirement that is not live means `pending`:
645
+ // activation is a STANDING REQUEST, not a one-shot event.
646
+ if unmet := h.unmetof(e); 0 < len(unmet) {
647
+ e.unmet = unmet
648
+ e.Status = StatusPending
649
+ return e, nil
650
+ }
651
+
652
+ if err := h.run(e, e.def.Activate, "activate"); nil != err {
653
+ // Unwind whatever the partial activation captured, in reverse.
654
+ h.unwind(e)
655
+ e.Status = StatusFailed
656
+ return nil, err
657
+ }
658
+ // §11.4: THE SELECTION IS MADE HERE, once, and remembered. Every
659
+ // later question — the cascade, `hold`, `unmet` — reads it back
660
+ // rather than re-ranking, which is what "always-reluctant" means.
661
+ for _, r := range Requirements(e.Options) {
662
+ h.chosen(e, r, true)
663
+ }
664
+ e.Status = StatusLive
665
+ h.reconcile()
666
+ return e, nil
667
+ }
668
+
669
+ func (h *Host) Deactivate(ref string) (*Live, error) {
670
+ leave, err := h.enter()
671
+ if nil != err {
672
+ return nil, err
673
+ }
674
+ defer leave()
675
+ return h.deactivate(ref)
676
+ }
677
+
678
+ func (h *Host) deactivate(ref string) (*Live, error) {
679
+ e, err := h.need(ref)
680
+ if nil != err {
681
+ return nil, err
682
+ }
683
+ if StatusLoaded == e.Status || StatusDeclared == e.Status {
684
+ return e, nil
685
+ }
686
+
687
+ // §5.2: `Unload` is THE ONLY TRANSITION OUT OF `failed`.
688
+ if StatusFailed == e.Status {
689
+ return nil, Fail("plugin_bad_state", "instance has failed: "+e.Ref,
690
+ map[string]any{"ref": e.Ref})
691
+ }
692
+
693
+ if StatusPending == e.Status {
694
+ // DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (§5.2). It
695
+ // never reached activate, so it holds no scope and no live
696
+ // bindings; running the definition's deactivate there would be
697
+ // teardown without matching setup, which plugins are not written
698
+ // to survive and which could fail an instance that had done
699
+ // nothing wrong. It cannot fail.
700
+ e.Status = StatusLoaded
701
+ e.unmet = []string{}
702
+ return e, nil
703
+ }
704
+
705
+ if err := h.held(e); nil != err {
706
+ return nil, err
707
+ }
708
+ h.cascade(e, map[string]bool{})
709
+
710
+ if err := h.run(e, e.def.Deactivate, "deactivate"); nil != err {
711
+ h.unwind(e)
712
+ e.Status = StatusFailed
713
+ return nil, err
714
+ }
715
+ if err := h.releasecheck(e, h.unwind(e)); nil != err {
716
+ return nil, err
717
+ }
718
+ e.Status = StatusLoaded
719
+ h.reconcile()
720
+ return e, nil
721
+ }
722
+
723
+ func (h *Host) Unload(ref string) error {
724
+ leave, err := h.enter()
725
+ if nil != err {
726
+ return err
727
+ }
728
+ defer leave()
729
+ return h.unload(ref)
730
+ }
731
+
732
+ func (h *Host) unload(ref string) error {
733
+ e, err := h.need(ref)
734
+ if nil != err {
735
+ return err
736
+ }
737
+ if StatusLive == e.Status || StatusPending == e.Status {
738
+ if StatusLive == e.Status {
739
+ if err := h.held(e); nil != err {
740
+ return err
741
+ }
742
+ h.cascade(e, map[string]bool{})
743
+ if err := h.run(e, e.def.Deactivate, "deactivate"); nil != err {
744
+ // §5.2: ANY failure during a transition lands the
745
+ // instance in `failed`, with the scope STILL FULLY
746
+ // UNWOUND — and the instance STAYS REGISTERED, because
747
+ // `failed` is a state an operator has to be able to see.
748
+ h.unwind(e)
749
+ e.Status = StatusFailed
750
+ return err
751
+ }
752
+ if err := h.releasecheck(e, h.unwind(e)); nil != err {
753
+ return err
754
+ }
755
+ }
756
+ e.Status = StatusLoaded
757
+ }
758
+ if StatusLoaded == e.Status || StatusFailed == e.Status {
759
+ err := h.run(e, e.def.Close, "close")
760
+ delete(h.inst, e.Ref)
761
+ return err
762
+ }
763
+ delete(h.inst, e.Ref)
764
+ return nil
765
+ }
766
+
767
+ // Ready runs the whole forward path in one call (§5.1). §15.2's verb
768
+ // list omits this; §5.1 defines it and §15.3's `declare` row requires
769
+ // the corpus to pin it, so the list was incomplete rather than excluding
770
+ // it (DOCS.md §4.2).
771
+ func (h *Host) Ready(ref string) (*Live, error) {
772
+ leave, err := h.enter()
773
+ if nil != err {
774
+ return nil, err
775
+ }
776
+ defer leave()
777
+ return h.ready(ref)
778
+ }
779
+
780
+ func (h *Host) ready(ref string) (*Live, error) {
781
+ r, err := CanonRef(ref)
782
+ if nil != err {
783
+ return nil, err
784
+ }
785
+ if _, has := h.inst[r]; !has {
786
+ if _, err := h.declare(r, DeclareSpec{}); nil != err {
787
+ return nil, err
788
+ }
789
+ }
790
+ if StatusDeclared == h.inst[r].Status {
791
+ if _, err := h.load(r, DeclareSpec{}); nil != err {
792
+ return nil, err
793
+ }
794
+ }
795
+ return h.activate(r)
796
+ }
797
+
798
+ // unwind: bindings go live only when activation succeeds (§8.1), so the
799
+ // teardown is the exact inverse: reverse order, always.
800
+ // unwind runs the scope in reverse and returns the errors it raised.
801
+ // §8.3: "A failing release does not stop the rest. Every entry runs, in
802
+ // reverse order, whatever any of them does; the errors are collected and
803
+ // raised as one `plugin_release_failed`."
804
+ //
805
+ // A Go release is `func()` and cannot return an error, so it signals
806
+ // failure by PANICKING — which is what a Go author's `defer f.Close()`
807
+ // wrapper does when it has nowhere to put the error, and which is
808
+ // recovered here rather than taking the host down.
809
+ // A selection belongs to ONE activation (§11.4). Leaving `live` by any
810
+ // door drops it, so the next activation ranks afresh — keeping it would
811
+ // make a consumer prefer a provider it never actually ran against.
812
+ func (h *Host) unwind(e *Live) []string {
813
+ e.selected = map[string]string{}
814
+ errors := []string{}
815
+ for i := len(e.scope) - 1; 0 <= i; i-- {
816
+ errors = append(errors, callrelease(e.scope[i])...)
817
+ }
818
+ e.scope = []func(){}
819
+ return errors
820
+ }
821
+
822
+ func callrelease(fn func()) (out []string) {
823
+ defer func() {
824
+ if r := recover(); nil != r {
825
+ out = []string{fmt.Sprint(r)}
826
+ }
827
+ }()
828
+ fn()
829
+ return nil
830
+ }
831
+
832
+ // releasecheck is §8.3: "A failed release ends the instance in `failed`,
833
+ // exactly as a failed callback does (§5.2) — a release that raised may
834
+ // have leaked, and an instance that may be holding resources it cannot
835
+ // account for must not be reactivated."
836
+ func (h *Host) releasecheck(e *Live, errors []string) error {
837
+ if 0 == len(errors) {
838
+ return nil
839
+ }
840
+ e.Status = StatusFailed
841
+ return Fail("plugin_release_failed",
842
+ "release failed for "+e.Ref+": "+join(errors, "; "),
843
+ map[string]any{"ref": e.Ref, "cause": errors})
844
+ }
845
+
846
+ /* unmetof: A REQUIREMENT IS ON A CAPABILITY, not on a ref (§11.1) — it
847
+ * is a dependency on something that can do the job, and which instance
848
+ * is doing it is exactly the configuration detail a plugin must not care
849
+ * about. A bare string is shorthand for `{name}`.
850
+ *
851
+ * A ref satisfies too, because a host that genuinely needs a specific
852
+ * instance should not have to invent a capability for it. */
853
+ func (h *Host) unmetof(e *Live) []string {
854
+ out := []string{}
855
+ for _, r := range Requirements(e.Options) {
856
+ if !GatesActivation(r) {
857
+ continue
858
+ }
859
+ if 0 == len(h.providersof(r)) {
860
+ out = append(out, r.Name)
861
+ }
862
+ }
863
+ return out
864
+ }
865
+
866
+ /* boundproviders: the instance currently SELECTED for each of this one's
867
+ * restart-causing requirements. A BINDING IS TO AN INSTANCE, not to a
868
+ * capability (§11.1), and that is what decides behaviour when the bound
869
+ * provider leaves while another match remains: the selected one going
870
+ * away restarts a `static` consumer even though a survivor is available.
871
+ * It is not silently re-pointed — `static` is the plugin saying in
872
+ * writing that it cannot survive a provider swap, and a survivor being
873
+ * available does not make the swap survivable. */
874
+ // chosen is §11.4's always-reluctant selection, and the ONE place a
875
+ // provider is picked for a live instance. If this instance already
876
+ // selected a provider for `req` and that provider is STILL a candidate,
877
+ // it keeps it — a better-ranked newcomer does not take it. `remember`
878
+ // is false for the questions asked ABOUT an instance rather than BY it:
879
+ // introspection must not create a binding.
880
+ func (h *Host) chosen(e *Live, req Required, remember bool) string {
881
+ cands := h.providersof(req)
882
+ if 0 == len(cands) {
883
+ return ""
884
+ }
885
+ if held, has := e.selected[req.Name]; has {
886
+ for _, c := range cands {
887
+ if c.Ref == held {
888
+ return held
889
+ }
890
+ }
891
+ }
892
+ if remember {
893
+ e.selected[req.Name] = cands[0].Ref
894
+ }
895
+ return cands[0].Ref
896
+ }
897
+
898
+ func (h *Host) boundproviders(e *Live) []string {
899
+ out := []string{}
900
+ for _, r := range Requirements(e.Options) {
901
+ if !RestartsOnLoss(r) {
902
+ continue
903
+ }
904
+ if ref := h.chosen(e, r, false); "" != ref && !hasstring(out, ref) {
905
+ out = append(out, ref)
906
+ }
907
+ }
908
+ return out
909
+ }
910
+
911
+ // consumersof: live instances whose selected provider is `ref` and which
912
+ // would be restarted by losing it.
913
+ func (h *Host) consumersof(ref string) []string {
914
+ out := []string{}
915
+ for _, r := range sortedkeys(h.inst) {
916
+ c := h.inst[r]
917
+ if r != ref && StatusLive == c.Status && hasstring(h.boundproviders(c), ref) {
918
+ out = append(out, r)
919
+ }
920
+ }
921
+ return out
922
+ }
923
+
924
+ // holdersof answers §11.3's `hold` question, which is a DIFFERENT
925
+ // question from the cascade's — and reading it off `consumersof`
926
+ // answered the cascade's.
927
+ //
928
+ // The cascade wants the edges that RESTART (mandatory-static and
929
+ // optional-static), because a restart is what it performs. `hold` says
930
+ // "deactivating a REQUIRED instance is `plugin_dependency_held`", and
931
+ // required is cardinality: GatesActivation, not RestartsOnLoss. The two
932
+ // sets differ in both directions and each difference was a real bug.
933
+ //
934
+ // A MANDATORY-DYNAMIC consumer was excluded, so the strictest policy
935
+ // let a provider go that a live consumer could not do without —
936
+ // `dynamic` promises survival of a SWAP, and under `hold` there is no
937
+ // swap, so the consumer falls back to `pending`.
938
+ //
939
+ // An OPTIONAL-STATIC consumer was included, so `hold` refused a
940
+ // deactivation on behalf of an instance that had said in writing it
941
+ // does not need the thing.
942
+ func (h *Host) holdersof(ref string) []string {
943
+ out := []string{}
944
+ for _, r := range sortedkeys(h.inst) {
945
+ c := h.inst[r]
946
+ if r == ref || StatusLive != c.Status {
947
+ continue
948
+ }
949
+ for _, req := range Requirements(c.Options) {
950
+ if !GatesActivation(req) {
951
+ continue
952
+ }
953
+ if h.chosen(c, req, false) == ref {
954
+ out = append(out, r)
955
+ break
956
+ }
957
+ }
958
+ }
959
+ return out
960
+ }
961
+
962
+ func (h *Host) providersof(req Required) []Candidate {
963
+ cands := []Candidate{}
964
+ want := canon(req.Name)
965
+ for _, ref := range sortedkeys(h.inst) {
966
+ t := h.inst[ref]
967
+ if StatusLive != t.Status {
968
+ continue
969
+ }
970
+ // A ref satisfies directly.
971
+ if ref == want {
972
+ cands = append(cands, Candidate{Ref: ref, Pos: t.Pos, Provides: Provided{Name: req.Name}})
973
+ continue
974
+ }
975
+ for _, p := range t.provides {
976
+ if p.Name == req.Name {
977
+ cands = append(cands, Candidate{Ref: ref, Pos: t.Pos, Provides: p})
978
+ }
979
+ }
980
+ }
981
+ return ResolveCapability(req, cands)
982
+ }
983
+
984
+ /* CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (§11.3).
985
+ *
986
+ * The cascade is part of the provider's own deactivation and runs BEFORE
987
+ * the provider's `deactivate` callback and scope unwind, so a consumer's
988
+ * teardown can still call the thing it depends on — flushing a buffer to
989
+ * the store it is about to lose is exactly what a `deactivate` callback
990
+ * is for, and a cascade that fired after the provider was already gone
991
+ * would make that impossible.
992
+ *
993
+ * Order: consumers deepest-first, then the provider. `Unload` and
994
+ * `Close` inherit it, UNDER EITHER DEPENDENCY POLICY, which is what
995
+ * makes apply's reverse-load-order teardown safe even when a document
996
+ * happens to list a consumer before its provider. */
997
+ func (h *Host) cascade(provider *Live, seen map[string]bool) {
998
+ if seen[provider.Ref] {
999
+ return
1000
+ }
1001
+ seen[provider.Ref] = true
1002
+
1003
+ for _, r := range h.consumersof(provider.Ref) {
1004
+ c := h.inst[r]
1005
+ if StatusLive != c.Status {
1006
+ continue
1007
+ }
1008
+ h.cascade(c, seen) // deepest-first
1009
+ bad := nil != h.run(c, c.def.Deactivate, "deactivate")
1010
+ errors := h.unwind(c)
1011
+ if bad || 0 < len(errors) {
1012
+ // §5.2: ANY failure during a transition lands the instance in
1013
+ // `failed`. Marking it `pending` handed it straight back to
1014
+ // `reconcile`, which would activate it again the moment the
1015
+ // provider returned.
1016
+ c.Status = StatusFailed
1017
+ continue
1018
+ }
1019
+ c.Status = StatusPending
1020
+ c.unmet = h.unmetof(c)
1021
+ }
1022
+ }
1023
+
1024
+ /* held is A GUARD ON AD-HOC DEACTIVATION, NOT ON COORDINATED TEARDOWN.
1025
+ * In a bulk operation that is removing the holders too — `Close()`, or
1026
+ * an `Apply` plan whose own steps deactivate them — it is suspended for
1027
+ * exactly those holders, and the teardown still runs consumers before
1028
+ * providers.
1029
+ *
1030
+ * Otherwise `Close()` under `hold` would raise on the first provider it
1031
+ * reached whenever a document happened to list a consumer after it,
1032
+ * which is the policy refusing to allow the one teardown it has no
1033
+ * reason to object to. */
1034
+ func (h *Host) held(e *Live) error {
1035
+ if "hold" != h.dependency {
1036
+ return nil
1037
+ }
1038
+ if h.coordinated {
1039
+ return nil
1040
+ }
1041
+ holders := h.holdersof(e.Ref)
1042
+ if 0 == len(holders) {
1043
+ return nil
1044
+ }
1045
+ return Fail("plugin_dependency_held",
1046
+ "instance is required by live consumers: "+e.Ref,
1047
+ map[string]any{"ref": e.Ref, "holders": holders})
1048
+ }
1049
+
1050
+ /* reconcile is EAGER: run to a fixed point rather than scheduling.
1051
+ *
1052
+ * Two directions, and both are the reason `pending` exists. Activation
1053
+ * is a STANDING REQUEST, not a one-shot event: a pending instance whose
1054
+ * requirement arrives activates without being asked again, and a LIVE
1055
+ * instance whose requirement is lost goes back to pending —
1056
+ * recursively, through its own consumers. */
1057
+ func (h *Host) reconcile() {
1058
+ rounds := 0
1059
+ for moved := true; moved; {
1060
+ moved = false
1061
+ rounds++
1062
+ if 1000 < rounds {
1063
+ break
1064
+ }
1065
+
1066
+ // Losses first, so a cascade settles in one pass rather than
1067
+ // alternating with re-activations.
1068
+ for _, r := range sortedkeys(h.inst) {
1069
+ e := h.inst[r]
1070
+ if StatusLive != e.Status {
1071
+ continue
1072
+ }
1073
+ lost := []Required{}
1074
+ for _, q := range Requirements(e.Options) {
1075
+ if GatesActivation(q) && 0 == len(h.providersof(q)) {
1076
+ lost = append(lost, q)
1077
+ }
1078
+ }
1079
+ if 0 == len(lost) {
1080
+ continue
1081
+ }
1082
+ // POLICY IS PER REQUIREMENT, not per instance (§11.3): only
1083
+ // the definition that has the requirement knows what it can
1084
+ // cope with, and one instance may hold both a `static` and a
1085
+ // `dynamic` one. A `dynamic` requirement whose provider is
1086
+ // gone leaves the consumer LIVE and notified; it is a
1087
+ // statement about surviving a swap, so it does not restart
1088
+ // here.
1089
+ restarts := false
1090
+ for _, q := range lost {
1091
+ if RestartsOnLoss(q) {
1092
+ restarts = true
1093
+ }
1094
+ }
1095
+ if !restarts {
1096
+ continue
1097
+ }
1098
+ bad := nil != h.run(e, e.def.Deactivate, "deactivate")
1099
+ errors := h.unwind(e)
1100
+ if bad || 0 < len(errors) {
1101
+ e.Status = StatusFailed
1102
+ moved = true
1103
+ continue
1104
+ }
1105
+ e.Status = StatusPending
1106
+ e.unmet = h.unmetof(e)
1107
+ moved = true
1108
+ }
1109
+
1110
+ for _, r := range sortedkeys(h.inst) {
1111
+ e := h.inst[r]
1112
+ if StatusPending != e.Status {
1113
+ continue
1114
+ }
1115
+ if 0 < len(h.unmetof(e)) {
1116
+ continue
1117
+ }
1118
+ if err := h.run(e, e.def.Activate, "activate"); nil != err {
1119
+ h.unwind(e)
1120
+ e.Status = StatusFailed
1121
+ moved = true
1122
+ continue
1123
+ }
1124
+ e.Status = StatusLive
1125
+ e.unmet = []string{}
1126
+ moved = true
1127
+ }
1128
+ }
1129
+ }
1130
+
1131
+ // --- ordering --------------------------------------------------------
1132
+
1133
+ func (h *Host) Order(point string) ([]string, error) {
1134
+ // Sorted by declaration SEQUENCE, which is what makes §7's sort
1135
+ // deterministic here. §7 breaks ties by `pos`, and two instances CAN
1136
+ // share one — `Declare` defaults `Pos` to the registry size, so an
1137
+ // unload followed by a fresh declare reuses a surviving instance's.
1138
+ // Past that the canonical fell through to its map's insertion order;
1139
+ // a Go map has none, and sorting by REF gave the opposite answer.
1140
+ // `Seq` IS that order, made explicit — in the canonical too.
1141
+ refs := sortedkeys(h.inst)
1142
+ sort.SliceStable(refs, func(i, j int) bool {
1143
+ return h.inst[refs[i]].Seq < h.inst[refs[j]].Seq
1144
+ })
1145
+ bindings := []Binding{}
1146
+ for _, r := range refs {
1147
+ if StatusLive != h.inst[r].Status {
1148
+ continue
1149
+ }
1150
+ bindings = append(bindings, Binding{Ref: r, Pos: h.inst[r].Pos, Order: h.inst[r].order})
1151
+ }
1152
+ var pin Pin
1153
+ if "" != point {
1154
+ if spec, ok := h.points[point]; ok {
1155
+ pin = spec.Pin
1156
+ }
1157
+ }
1158
+ return ResolveOrder(bindings, pin)
1159
+ }
1160
+
1161
+ // --- points ----------------------------------------------------------
1162
+
1163
+ // bound returns the live bindings on a point, in resolved order.
1164
+ // Recomputed on any change to the live set (§7) rather than cached at
1165
+ // startup — the bug a host discovers only when something deactivates in
1166
+ // production.
1167
+ func (h *Host) bound(point string) ([]Bound, error) {
1168
+ ranked, err := h.Order(point)
1169
+ if nil != err {
1170
+ return nil, err
1171
+ }
1172
+ out := []Bound{}
1173
+ for _, ref := range ranked {
1174
+ e := h.inst[ref]
1175
+ // The band is the INSTANCE's ordering block (§7), stamped by the
1176
+ // host. A plugin passing its own would be ranking itself above
1177
+ // the order its document declared.
1178
+ band := 0
1179
+ if nil != e.order && nil != e.order.Band {
1180
+ band = *e.order.Band
1181
+ }
1182
+ for _, b := range e.bindings {
1183
+ if b.Point == point {
1184
+ stamped := b
1185
+ stamped.Band = band
1186
+ out = append(out, stamped)
1187
+ }
1188
+ }
1189
+ }
1190
+ return out, nil
1191
+ }
1192
+
1193
+ func (h *Host) pointspec(point string, want Kind) (Spec, error) {
1194
+ spec, ok := h.points[point]
1195
+ if !ok {
1196
+ return Spec{}, Fail("plugin_point_unknown", "no such point: "+point,
1197
+ map[string]any{"point": point})
1198
+ }
1199
+ if KindHook == want {
1200
+ // A point with no declared kind is a hook, which is what makes
1201
+ // `{}` the minimal point declaration.
1202
+ if "" != spec.Kind && KindHook != spec.Kind {
1203
+ return Spec{}, Fail("plugin_point_kind", "point is not a hook: "+point,
1204
+ map[string]any{"point": point, "kind": string(spec.Kind)})
1205
+ }
1206
+ return spec, nil
1207
+ }
1208
+ if spec.Kind != want {
1209
+ return Spec{}, Fail("plugin_point_kind", "point is not a "+string(want)+": "+point,
1210
+ map[string]any{"point": point, "kind": string(spec.Kind)})
1211
+ }
1212
+ return spec, nil
1213
+ }
1214
+
1215
+ func (h *Host) Emit(point string, arg any) (any, error) {
1216
+ spec, err := h.pointspec(point, KindHook)
1217
+ if nil != err {
1218
+ return nil, err
1219
+ }
1220
+ bindings, err := h.bound(point)
1221
+ if nil != err {
1222
+ return nil, err
1223
+ }
1224
+ mode := spec.Mode
1225
+ if "" == mode {
1226
+ mode = ModeEmit
1227
+ }
1228
+ return Emit(bindings, mode, arg)
1229
+ }
1230
+
1231
+ func (h *Host) Call(point string, args ...any) (any, error) {
1232
+ spec, err := h.pointspec(point, KindChain)
1233
+ if nil != err {
1234
+ return nil, err
1235
+ }
1236
+ bindings, err := h.bound(point)
1237
+ if nil != err {
1238
+ return nil, err
1239
+ }
1240
+ base := spec.Base
1241
+ if nil == base {
1242
+ base = func(a ...any) any {
1243
+ if 0 == len(a) {
1244
+ return nil
1245
+ }
1246
+ return a[0]
1247
+ }
1248
+ }
1249
+ return Compose(bindings, base)(args...), nil
1250
+ }
1251
+
1252
+ func (h *Host) Provide(point string, args ...any) (any, error) {
1253
+ spec, err := h.pointspec(point, KindProvider)
1254
+ if nil != err {
1255
+ return nil, err
1256
+ }
1257
+ bindings, err := h.bound(point)
1258
+ if nil != err {
1259
+ return nil, err
1260
+ }
1261
+ pick, err := Provider(bindings, spec)
1262
+ if nil != err {
1263
+ return nil, err
1264
+ }
1265
+ if nil == pick.Winner {
1266
+ return spec.Default, nil
1267
+ }
1268
+ return pick.Winner.Fn(args...), nil
1269
+ }
1270
+
1271
+ // Shadowed makes the losers VISIBLE rather than silently ignored (§6.3).
1272
+ func (h *Host) Shadowed(point string) ([]string, error) {
1273
+ spec, ok := h.points[point]
1274
+ if !ok {
1275
+ return []string{}, nil
1276
+ }
1277
+ bindings, err := h.bound(point)
1278
+ if nil != err {
1279
+ return nil, err
1280
+ }
1281
+ pick, err := Provider(bindings, spec)
1282
+ if nil != err {
1283
+ return nil, err
1284
+ }
1285
+ return pick.Shadowed, nil
1286
+ }
1287
+
1288
+ func (h *Host) Exports(spec string) (any, error) {
1289
+ all := []Exported{}
1290
+ for _, ref := range sortedkeys(h.inst) {
1291
+ e := h.inst[ref]
1292
+ // Exports of a `loaded` (not live) instance are VISIBLE (§11).
1293
+ if StatusDeclared == e.Status || StatusFailed == e.Status {
1294
+ continue
1295
+ }
1296
+ for _, k := range sortedkeys(e.exports) {
1297
+ all = append(all, Exported{Ref: ref, Key: k, Value: e.exports[k]})
1298
+ }
1299
+ }
1300
+ return ResolveExport(spec, all)
1301
+ }
1302
+
1303
+ // Capability lists the live providers of a capability, best-first
1304
+ // (§11.1).
1305
+ func (h *Host) Capability(name string) []string {
1306
+ cands := []Candidate{}
1307
+ for _, ref := range sortedkeys(h.inst) {
1308
+ e := h.inst[ref]
1309
+ if StatusLive != e.Status {
1310
+ continue
1311
+ }
1312
+ for _, p := range e.provides {
1313
+ if p.Name == name {
1314
+ cands = append(cands, Candidate{Ref: ref, Pos: e.Pos, Provides: p})
1315
+ }
1316
+ }
1317
+ }
1318
+ out := []string{}
1319
+ for _, c := range ResolveCapability(Required{Name: name}, cands) {
1320
+ out = append(out, c.Ref)
1321
+ }
1322
+ return out
1323
+ }
1324
+
1325
+ // --- documents -------------------------------------------------------
1326
+
1327
+ // Apply is §9.6: "load what is missing, UNLOAD WHAT IS GONE, patch what
1328
+ // changed, and move activation state to match", with the stated
1329
+ // ordering — "deactivations and unloads first (reverse load order), then
1330
+ // loads, then activations in load order".
1331
+ //
1332
+ // FOUR PHASES, NOT ONE INTERLEAVED LOOP. An earlier draft walked the
1333
+ // document once, which never looked at instances the new document had
1334
+ // DROPPED — so an integration removed from a config reload stayed live
1335
+ // with its bindings and resources.
1336
+ func (h *Host) Apply(doc any, profile string) error {
1337
+ leave, err := h.enter()
1338
+ if nil != err {
1339
+ return err
1340
+ }
1341
+ defer leave()
1342
+ return h.apply(doc, profile)
1343
+ }
1344
+
1345
+ func (h *Host) apply(doc any, profile string) error {
1346
+ profile = or(profile, h.opts.Profile)
1347
+ norm, err := NormalizeConfig(NormalizeInput{
1348
+ Doc: doc, Profile: profile, Keys: h.opts.Keys, Reserved: h.reserved,
1349
+ })
1350
+ if nil != err {
1351
+ return err
1352
+ }
1353
+
1354
+ want := norm.Order
1355
+ optionsof := map[string]map[string]any{}
1356
+ for _, ref := range want {
1357
+ options, err := ResolveOptions(ResolveInput{
1358
+ Ref: ref, Doc: doc, Profile: profile,
1359
+ Shape: h.shapeof(ref), HostDefaults: h.opts.Defaults[refname(ref)],
1360
+ })
1361
+ if nil != err {
1362
+ return err
1363
+ }
1364
+ optionsof[ref] = options
1365
+ }
1366
+
1367
+ // wantlive: should this ref be LIVE after the apply? False for a ref
1368
+ // the document declares lazy or inactive AND for one it does not
1369
+ // name at all — which is what makes "unload what is gone" and
1370
+ // "unload what was toggled off" one rule rather than two.
1371
+ wantlive := func(ref string) bool {
1372
+ ent, has := norm.Instance[ref]
1373
+ return has && ent.Active && "eager" == ent.Start
1374
+ }
1375
+
1376
+ // --- phase 1: deactivations and unloads, in REVERSE load order ---
1377
+ drop := []string{}
1378
+ for _, ref := range sortedkeys(h.inst) {
1379
+ if StatusDeclared == h.inst[ref].Status {
1380
+ continue
1381
+ }
1382
+ if !wantlive(ref) {
1383
+ drop = append(drop, ref)
1384
+ }
1385
+ }
1386
+ // Highest `pos` first, ref-descending for a tie, so a consumer
1387
+ // declared after its provider goes down first.
1388
+ sort.SliceStable(drop, func(i, j int) bool {
1389
+ a, b := h.inst[drop[i]], h.inst[drop[j]]
1390
+ if a.Pos != b.Pos {
1391
+ return a.Pos > b.Pos
1392
+ }
1393
+ return drop[i] > drop[j]
1394
+ })
1395
+ for _, ref := range drop {
1396
+ if err := h.unload(ref); nil != err {
1397
+ return err
1398
+ }
1399
+ }
1400
+
1401
+ // --- phase 2: declare and patch EVERYTHING, in load order --------
1402
+ for _, ref := range want {
1403
+ ent := norm.Instance[ref]
1404
+ pos := ent.Pos
1405
+ // NO OPTIONS HERE, and the omission is the fix rather than an
1406
+ // oversight. `declare` ADOPTS the options map it is handed as
1407
+ // the instance's own, so passing the resolved map made target
1408
+ // and source THE SAME MAP in the refill below — which cleared
1409
+ // its own source and left a first-time instance with no options
1410
+ // at all. `declare` makes its own empty map and the refill fills
1411
+ // it, so both paths are now one path.
1412
+ if _, err := h.declare(ref, DeclareSpec{
1413
+ Order: ent.Order, Pos: &pos}); nil != err {
1414
+ return err
1415
+ }
1416
+ // The bar is REASSERTED ON EVERY APPLY, in both directions — a
1417
+ // document that turns the instance back on clears it, which is
1418
+ // the whole point of a config switch.
1419
+ h.inst[ref].barred = !ent.Active
1420
+ // REFILL rather than REBIND. A definition's callbacks close over
1421
+ // the options map they were handed at `define`; replacing the
1422
+ // reference here would leave every binding reading the values the
1423
+ // first apply gave it.
1424
+ refill(h.inst[ref].Options, optionsof[ref])
1425
+ h.inst[ref].order = ent.Order
1426
+ h.inst[ref].Pos = ent.Pos
1427
+ }
1428
+
1429
+ // --- phase 3: loads, in load order -------------------------------
1430
+ // ONLY THE EAGER, ACTIVE ONES: "a document of twenty lazy instances
1431
+ // is twenty map entries and no executed code" (§9.6).
1432
+ for _, ref := range want {
1433
+ if wantlive(ref) {
1434
+ if _, err := h.load(ref, DeclareSpec{}); nil != err {
1435
+ return err
1436
+ }
1437
+ }
1438
+ }
1439
+
1440
+ // --- phase 4: activations, in load order -------------------------
1441
+ for _, ref := range want {
1442
+ if wantlive(ref) {
1443
+ if _, err := h.activate(ref); nil != err {
1444
+ return err
1445
+ }
1446
+ }
1447
+ }
1448
+ return nil
1449
+ }
1450
+
1451
+ func (h *Host) shapeof(ref string) any {
1452
+ def, ok := h.catalog.Get(refname(ref))
1453
+ if !ok {
1454
+ return nil
1455
+ }
1456
+ return def.Shape
1457
+ }
1458
+
1459
+ func (h *Host) SetOptions(ref string, patch map[string]any) error {
1460
+ leave, err := h.enter()
1461
+ if nil != err {
1462
+ return err
1463
+ }
1464
+ defer leave()
1465
+ return h.setoptions(ref, patch)
1466
+ }
1467
+
1468
+ func (h *Host) setoptions(ref string, patch map[string]any) error {
1469
+ e, err := h.need(ref)
1470
+ if nil != err {
1471
+ return err
1472
+ }
1473
+ previous := map[string]any{}
1474
+ for k, v := range e.Options {
1475
+ previous[k] = v
1476
+ }
1477
+ resolved, err := ResolveOptions(ResolveInput{
1478
+ Ref: e.Ref, Shape: h.shapeof(e.Ref), Doc: map[string]any{},
1479
+ Patch: shallowmerge(previous, patch)})
1480
+ if nil != err {
1481
+ return err
1482
+ }
1483
+ refill(e.Options, resolved)
1484
+ if StatusLive == e.Status {
1485
+ if nil != e.def.Reconfigure {
1486
+ h.intransition = true
1487
+ err := e.def.Reconfigure(h.api(e), e.Options, previous)
1488
+ h.intransition = false
1489
+ return err
1490
+ }
1491
+ // Always correct and sometimes expensive; `reconfigure` exists
1492
+ // to make the common case cheap (§9.4).
1493
+ if _, err := h.deactivate(e.Ref); nil != err {
1494
+ return err
1495
+ }
1496
+ if _, err := h.activate(e.Ref); nil != err {
1497
+ return err
1498
+ }
1499
+ }
1500
+ return nil
1501
+ }
1502
+
1503
+ // refill empties the target and refills it, so callers holding the
1504
+ // reference see the new values.
1505
+ func refill(target map[string]any, source map[string]any) {
1506
+ for k := range target {
1507
+ delete(target, k)
1508
+ }
1509
+ for k, v := range source {
1510
+ target[k] = v
1511
+ }
1512
+ }
1513
+
1514
+ func shallowmerge(a map[string]any, b map[string]any) map[string]any {
1515
+ out := map[string]any{}
1516
+ for k, v := range a {
1517
+ out[k] = v
1518
+ }
1519
+ for k, v := range b {
1520
+ out[k] = v
1521
+ }
1522
+ return out
1523
+ }
1524
+
1525
+ func (h *Host) Close() error {
1526
+ leave, err := h.enter()
1527
+ if nil != err {
1528
+ return err
1529
+ }
1530
+ defer leave()
1531
+ return h.closeall()
1532
+ }
1533
+
1534
+ func (h *Host) closeall() error {
1535
+ // A bulk teardown removing the holders too, so `hold` is suspended
1536
+ // for exactly those holders (§11.3) - while the consumers-first
1537
+ // cascade still runs, which is the half that matters.
1538
+ h.coordinated = true
1539
+ defer func() { h.coordinated = false }()
1540
+ refs := sortedkeys(h.inst)
1541
+ for i := len(refs) - 1; 0 <= i; i-- {
1542
+ if err := h.unload(refs[i]); nil != err {
1543
+ return err
1544
+ }
1545
+ }
1546
+ return nil
1547
+ }
1548
+
1549
+ // PositionOf is the same record §6.6 gives a plugin about itself,
1550
+ // reachable from outside for the corpus. A plugin asks via
1551
+ // `inst.Position(point)`.
1552
+ func (h *Host) PositionOf(ref string, point string) (Position, error) {
1553
+ e := h.inst[canon(ref)]
1554
+ if nil == e {
1555
+ return Position{}, Fail("plugin_not_loaded", "no such instance: "+ref,
1556
+ map[string]any{"ref": ref})
1557
+ }
1558
+ ranked, err := h.Order(point)
1559
+ if nil != err {
1560
+ return Position{}, err
1561
+ }
1562
+ index := indexof(ranked, e.Ref)
1563
+ return Position{
1564
+ Index: index, Count: len(ranked),
1565
+ // §6.2 composes b1(b2(b3(base))) with the FIRST binding
1566
+ // OUTERMOST, so these are not index 0 and index count-1 the
1567
+ // other way round. Getting this backwards is the exact error the
1568
+ // positional pin vocabulary exists to prevent.
1569
+ Outermost: 0 == index,
1570
+ Innermost: index == len(ranked)-1,
1571
+ }, nil
1572
+ }
1573
+
1574
+ // Define adds a definition to this host's catalog.
1575
+ func (h *Host) Define(def Definition) error { return h.catalog.Add(def) }