@voxgig/sdkgen 4.10.0 → 4.11.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 (304) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/package.json +1 -1
  3. package/project/.sdk/model/feature/secrets.aon +330 -0
  4. package/project/.sdk/model/target/c.aon +15 -2
  5. package/project/.sdk/model/target/cpp.aon +18 -0
  6. package/project/.sdk/model/target/lua.aon +17 -0
  7. package/project/.sdk/model/target/ocaml.aon +48 -5
  8. package/project/.sdk/model/target/zig.aon +30 -4
  9. package/project/.sdk/src/cmp/c/Config_c.ts +338 -1
  10. package/project/.sdk/src/cmp/c/Main_c.ts +57 -2
  11. package/project/.sdk/src/cmp/c/Package_c.ts +12 -2
  12. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +324 -2
  13. package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +2 -0
  14. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +62 -4
  15. package/project/.sdk/src/cmp/cpp/Package_cpp.ts +10 -0
  16. package/project/.sdk/src/cmp/lua/Config_lua.ts +88 -0
  17. package/project/.sdk/src/cmp/lua/Gitignore_lua.ts +4 -0
  18. package/project/.sdk/src/cmp/lua/Main_lua.ts +93 -3
  19. package/project/.sdk/src/cmp/lua/Package_lua.ts +60 -0
  20. package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +10 -0
  21. package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +183 -5
  22. package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +160 -3
  23. package/project/.sdk/src/cmp/ocaml/Package_ocaml.ts +25 -1
  24. package/project/.sdk/src/cmp/zig/Config_zig.ts +130 -9
  25. package/project/.sdk/src/cmp/zig/Main_zig.ts +208 -4
  26. package/project/.sdk/{tm/zig/build.zig → src/cmp/zig/fragment/Build.fragment.zig} +7 -0
  27. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +25 -0
  28. package/project/.sdk/{tm/zig/root.zig → src/cmp/zig/fragment/Root.fragment.zig} +9 -0
  29. package/project/.sdk/tm/c/Makefile +58 -9
  30. package/project/.sdk/tm/c/core/sdk.h +10 -0
  31. package/project/.sdk/tm/c/feature/secrets/plugin/capability.c +133 -0
  32. package/project/.sdk/tm/c/feature/secrets/plugin/capability.h +39 -0
  33. package/project/.sdk/tm/c/feature/secrets/plugin/catalog.c +83 -0
  34. package/project/.sdk/tm/c/feature/secrets/plugin/catalog.h +48 -0
  35. package/project/.sdk/tm/c/feature/secrets/plugin/config.c +413 -0
  36. package/project/.sdk/tm/c/feature/secrets/plugin/config.h +24 -0
  37. package/project/.sdk/tm/c/feature/secrets/plugin/depend.c +264 -0
  38. package/project/.sdk/tm/c/feature/secrets/plugin/depend.h +29 -0
  39. package/project/.sdk/tm/c/feature/secrets/plugin/env.c +220 -0
  40. package/project/.sdk/tm/c/feature/secrets/plugin/env.h +19 -0
  41. package/project/.sdk/tm/c/feature/secrets/plugin/export.c +97 -0
  42. package/project/.sdk/tm/c/feature/secrets/plugin/export.h +19 -0
  43. package/project/.sdk/tm/c/feature/secrets/plugin/graph.c +237 -0
  44. package/project/.sdk/tm/c/feature/secrets/plugin/graph.h +17 -0
  45. package/project/.sdk/tm/c/feature/secrets/plugin/host.c +1494 -0
  46. package/project/.sdk/tm/c/feature/secrets/plugin/host.h +135 -0
  47. package/project/.sdk/tm/c/feature/secrets/plugin/order.c +288 -0
  48. package/project/.sdk/tm/c/feature/secrets/plugin/order.h +18 -0
  49. package/project/.sdk/tm/c/feature/secrets/plugin/point.c +141 -0
  50. package/project/.sdk/tm/c/feature/secrets/plugin/point.h +80 -0
  51. package/project/.sdk/tm/c/feature/secrets/plugin/ref.c +170 -0
  52. package/project/.sdk/tm/c/feature/secrets/plugin/ref.h +52 -0
  53. package/project/.sdk/tm/c/feature/secrets/plugin/resolve.c +98 -0
  54. package/project/.sdk/tm/c/feature/secrets/plugin/resolve.h +18 -0
  55. package/project/.sdk/tm/c/feature/secrets/plugin/types.c +150 -0
  56. package/project/.sdk/tm/c/feature/secrets/plugin/types.h +104 -0
  57. package/project/.sdk/tm/c/feature/secrets/plugin/value.c +649 -0
  58. package/project/.sdk/tm/c/feature/secrets/plugin/value.h +135 -0
  59. package/project/.sdk/tm/c/feature/secrets/plugin/version.c +151 -0
  60. package/project/.sdk/tm/c/feature/secrets/plugin/version.h +34 -0
  61. package/project/.sdk/tm/c/feature/secrets/plugins/aws.c +281 -0
  62. package/project/.sdk/tm/c/feature/secrets/plugins/azuresecrets.c +207 -0
  63. package/project/.sdk/tm/c/feature/secrets/plugins/boru.c +164 -0
  64. package/project/.sdk/tm/c/feature/secrets/plugins/clock.c +75 -0
  65. package/project/.sdk/tm/c/feature/secrets/plugins/doppler.c +141 -0
  66. package/project/.sdk/tm/c/feature/secrets/plugins/encode.c +144 -0
  67. package/project/.sdk/tm/c/feature/secrets/plugins/gcpsecrets.c +177 -0
  68. package/project/.sdk/tm/c/feature/secrets/plugins/hashicorp.c +239 -0
  69. package/project/.sdk/tm/c/feature/secrets/plugins/httpjson.c +599 -0
  70. package/project/.sdk/tm/c/feature/secrets/plugins/infisical.c +165 -0
  71. package/project/.sdk/tm/c/feature/secrets/plugins/onepassword.c +194 -0
  72. package/project/.sdk/tm/c/feature/secrets/plugins/proc.c +233 -0
  73. package/project/.sdk/tm/c/feature/secrets/plugins/secretspec.c +125 -0
  74. package/project/.sdk/tm/c/feature/secrets/plugins/sekretoplugins.h +125 -0
  75. package/project/.sdk/tm/c/feature/secrets/plugins/sha256.c +270 -0
  76. package/project/.sdk/tm/c/feature/secrets/plugins/sigv4.c +382 -0
  77. package/project/.sdk/tm/c/feature/secrets/plugins/support.h +153 -0
  78. package/project/.sdk/tm/c/feature/secrets/plugins/tls.c +420 -0
  79. package/project/.sdk/tm/c/feature/secrets/sekreto/internal.h +86 -0
  80. package/project/.sdk/tm/c/feature/secrets/sekreto/json.c +721 -0
  81. package/project/.sdk/tm/c/feature/secrets/sekreto/providers.c +813 -0
  82. package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.c +944 -0
  83. package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.h +490 -0
  84. package/project/.sdk/tm/c/feature/secrets/sekreto/util.c +442 -0
  85. package/project/.sdk/tm/c/feature/secrets.c +797 -0
  86. package/project/.sdk/tm/c/feature/secrets.h +46 -0
  87. package/project/.sdk/tm/c/src/feature/secrets/.gitkeep +0 -0
  88. package/project/.sdk/tm/c/tests/feature/secrets/secrets_test.c +802 -0
  89. package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +38 -11
  90. package/project/.sdk/tm/clojure/test/sdk/test/feature/secrets.clj +40 -6
  91. package/project/.sdk/tm/cpp/Makefile +48 -4
  92. package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.cpp +121 -0
  93. package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.hpp +41 -0
  94. package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.cpp +60 -0
  95. package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.hpp +66 -0
  96. package/project/.sdk/tm/cpp/feature/secrets/plugin/config.cpp +376 -0
  97. package/project/.sdk/tm/cpp/feature/secrets/plugin/config.hpp +29 -0
  98. package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.cpp +230 -0
  99. package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.hpp +31 -0
  100. package/project/.sdk/tm/cpp/feature/secrets/plugin/env.cpp +205 -0
  101. package/project/.sdk/tm/cpp/feature/secrets/plugin/env.hpp +25 -0
  102. package/project/.sdk/tm/cpp/feature/secrets/plugin/export.cpp +84 -0
  103. package/project/.sdk/tm/cpp/feature/secrets/plugin/export.hpp +24 -0
  104. package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.cpp +222 -0
  105. package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.hpp +21 -0
  106. package/project/.sdk/tm/cpp/feature/secrets/plugin/host.cpp +1200 -0
  107. package/project/.sdk/tm/cpp/feature/secrets/plugin/host.hpp +250 -0
  108. package/project/.sdk/tm/cpp/feature/secrets/plugin/order.cpp +250 -0
  109. package/project/.sdk/tm/cpp/feature/secrets/plugin/order.hpp +22 -0
  110. package/project/.sdk/tm/cpp/feature/secrets/plugin/point.cpp +110 -0
  111. package/project/.sdk/tm/cpp/feature/secrets/plugin/point.hpp +79 -0
  112. package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.cpp +136 -0
  113. package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.hpp +60 -0
  114. package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.cpp +82 -0
  115. package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.hpp +25 -0
  116. package/project/.sdk/tm/cpp/feature/secrets/plugin/types.cpp +90 -0
  117. package/project/.sdk/tm/cpp/feature/secrets/plugin/types.hpp +65 -0
  118. package/project/.sdk/tm/cpp/feature/secrets/plugin/value.cpp +491 -0
  119. package/project/.sdk/tm/cpp/feature/secrets/plugin/value.hpp +120 -0
  120. package/project/.sdk/tm/cpp/feature/secrets/plugin/version.cpp +143 -0
  121. package/project/.sdk/tm/cpp/feature/secrets/plugin/version.hpp +36 -0
  122. package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.cpp +248 -0
  123. package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.hpp +30 -0
  124. package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.cpp +149 -0
  125. package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.hpp +23 -0
  126. package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.cpp +117 -0
  127. package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.hpp +27 -0
  128. package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.cpp +180 -0
  129. package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.hpp +52 -0
  130. package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.cpp +87 -0
  131. package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.hpp +23 -0
  132. package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.cpp +121 -0
  133. package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.hpp +23 -0
  134. package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.cpp +153 -0
  135. package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.hpp +23 -0
  136. package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.cpp +666 -0
  137. package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.hpp +160 -0
  138. package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.cpp +123 -0
  139. package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.hpp +23 -0
  140. package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.cpp +125 -0
  141. package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.hpp +23 -0
  142. package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.cpp +223 -0
  143. package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.hpp +47 -0
  144. package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.cpp +104 -0
  145. package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.hpp +27 -0
  146. package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.cpp +242 -0
  147. package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.hpp +58 -0
  148. package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.cpp +260 -0
  149. package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.hpp +47 -0
  150. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.cpp +476 -0
  151. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.hpp +89 -0
  152. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.cpp +312 -0
  153. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.hpp +263 -0
  154. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.cpp +354 -0
  155. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.hpp +111 -0
  156. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.cpp +613 -0
  157. package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.hpp +227 -0
  158. package/project/.sdk/tm/cpp/feature/secrets.hpp +745 -0
  159. package/project/.sdk/tm/cpp/src/feature/secrets/.gitkeep +0 -0
  160. package/project/.sdk/tm/cpp/test/feature/secrets/secrets_test.cpp +808 -0
  161. package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +34 -8
  162. package/project/.sdk/tm/csharp/test/feature/secrets/SecretsFeatureTest.cs +85 -0
  163. package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +17 -2
  164. package/project/.sdk/tm/elixir/test/feature/secrets/secrets_test.exs +41 -0
  165. package/project/.sdk/tm/go/feature/secrets_feature.go +32 -10
  166. package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +116 -0
  167. package/project/.sdk/tm/java/feature/SecretsFeature.java +33 -8
  168. package/project/.sdk/tm/java/test/feature/secrets/SecretsFeatureTest.java +64 -0
  169. package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +34 -11
  170. package/project/.sdk/tm/js/test/feature/secrets/Secrets.test.js +73 -0
  171. package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +32 -7
  172. package/project/.sdk/tm/kotlin/test/feature/secrets/SecretsTest.kt +69 -0
  173. package/project/.sdk/tm/lua/Makefile +15 -4
  174. package/project/.sdk/tm/lua/feature/secrets/native/sekretonet.c +806 -0
  175. package/project/.sdk/tm/lua/feature/secrets/plugin/capability.lua +135 -0
  176. package/project/.sdk/tm/lua/feature/secrets/plugin/catalog.lua +63 -0
  177. package/project/.sdk/tm/lua/feature/secrets/plugin/config.lua +361 -0
  178. package/project/.sdk/tm/lua/feature/secrets/plugin/depend.lua +232 -0
  179. package/project/.sdk/tm/lua/feature/secrets/plugin/env.lua +168 -0
  180. package/project/.sdk/tm/lua/feature/secrets/plugin/export.lua +66 -0
  181. package/project/.sdk/tm/lua/feature/secrets/plugin/graph.lua +194 -0
  182. package/project/.sdk/tm/lua/feature/secrets/plugin/host.lua +1190 -0
  183. package/project/.sdk/tm/lua/feature/secrets/plugin/json.lua +169 -0
  184. package/project/.sdk/tm/lua/feature/secrets/plugin/order.lua +207 -0
  185. package/project/.sdk/tm/lua/feature/secrets/plugin/point.lua +106 -0
  186. package/project/.sdk/tm/lua/feature/secrets/plugin/ref.lua +115 -0
  187. package/project/.sdk/tm/lua/feature/secrets/plugin/resolve.lua +78 -0
  188. package/project/.sdk/tm/lua/feature/secrets/plugin/types.lua +275 -0
  189. package/project/.sdk/tm/lua/feature/secrets/plugin/version.lua +131 -0
  190. package/project/.sdk/tm/lua/feature/secrets/plugin.lua +76 -0
  191. package/project/.sdk/tm/lua/feature/secrets/sekreto/addr.lua +124 -0
  192. package/project/.sdk/tm/lua/feature/secrets/sekreto/err.lua +47 -0
  193. package/project/.sdk/tm/lua/feature/secrets/sekreto/name.lua +315 -0
  194. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/aws.lua +228 -0
  195. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/azuresecrets.lua +137 -0
  196. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/boru.lua +124 -0
  197. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/crypto.lua +212 -0
  198. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/doppler.lua +89 -0
  199. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/gcpsecrets.lua +129 -0
  200. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/hashicorp.lua +154 -0
  201. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/httpjson.lua +248 -0
  202. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/infisical.lua +113 -0
  203. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/json.lua +449 -0
  204. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/net.lua +198 -0
  205. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/onepassword.lua +126 -0
  206. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/secretspec.lua +93 -0
  207. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/sigv4.lua +269 -0
  208. package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/support.lua +146 -0
  209. package/project/.sdk/tm/lua/feature/secrets/sekreto/providers.lua +346 -0
  210. package/project/.sdk/tm/lua/feature/secrets/sekreto.lua +479 -0
  211. package/project/.sdk/tm/lua/feature/secrets_feature.lua +690 -0
  212. package/project/.sdk/tm/lua/src/feature/secrets/.gitkeep +0 -0
  213. package/project/.sdk/tm/lua/test/extend_test.lua +105 -0
  214. package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +862 -0
  215. package/project/.sdk/tm/ocaml/Makefile +52 -8
  216. package/project/.sdk/tm/ocaml/feature/secrets/plugin/capability.ml +106 -0
  217. package/project/.sdk/tm/ocaml/feature/secrets/plugin/catalog.ml +43 -0
  218. package/project/.sdk/tm/ocaml/feature/secrets/plugin/config.ml +349 -0
  219. package/project/.sdk/tm/ocaml/feature/secrets/plugin/defs.ml +143 -0
  220. package/project/.sdk/tm/ocaml/feature/secrets/plugin/depend.ml +217 -0
  221. package/project/.sdk/tm/ocaml/feature/secrets/plugin/env.ml +197 -0
  222. package/project/.sdk/tm/ocaml/feature/secrets/plugin/export.ml +89 -0
  223. package/project/.sdk/tm/ocaml/feature/secrets/plugin/graph.ml +227 -0
  224. package/project/.sdk/tm/ocaml/feature/secrets/plugin/host.ml +1112 -0
  225. package/project/.sdk/tm/ocaml/feature/secrets/plugin/order.ml +202 -0
  226. package/project/.sdk/tm/ocaml/feature/secrets/plugin/point.ml +138 -0
  227. package/project/.sdk/tm/ocaml/feature/secrets/plugin/ref.ml +126 -0
  228. package/project/.sdk/tm/ocaml/feature/secrets/plugin/resolve.ml +62 -0
  229. package/project/.sdk/tm/ocaml/feature/secrets/plugin/types.ml +97 -0
  230. package/project/.sdk/tm/ocaml/feature/secrets/plugin/value.ml +387 -0
  231. package/project/.sdk/tm/ocaml/feature/secrets/plugin/version.ml +139 -0
  232. package/project/.sdk/tm/ocaml/feature/secrets/plugins/aws.ml +171 -0
  233. package/project/.sdk/tm/ocaml/feature/secrets/plugins/azuresecrets.ml +116 -0
  234. package/project/.sdk/tm/ocaml/feature/secrets/plugins/boru.ml +95 -0
  235. package/project/.sdk/tm/ocaml/feature/secrets/plugins/crypto.ml +149 -0
  236. package/project/.sdk/tm/ocaml/feature/secrets/plugins/doppler.ml +61 -0
  237. package/project/.sdk/tm/ocaml/feature/secrets/plugins/gcpsecrets.ml +93 -0
  238. package/project/.sdk/tm/ocaml/feature/secrets/plugins/hashicorp.ml +120 -0
  239. package/project/.sdk/tm/ocaml/feature/secrets/plugins/http.ml +421 -0
  240. package/project/.sdk/tm/ocaml/feature/secrets/plugins/httpjson.ml +66 -0
  241. package/project/.sdk/tm/ocaml/feature/secrets/plugins/infisical.ml +85 -0
  242. package/project/.sdk/tm/ocaml/feature/secrets/plugins/onepassword.ml +112 -0
  243. package/project/.sdk/tm/ocaml/feature/secrets/plugins/runcmd.ml +97 -0
  244. package/project/.sdk/tm/ocaml/feature/secrets/plugins/secretspec.ml +68 -0
  245. package/project/.sdk/tm/ocaml/feature/secrets/plugins/sigv4.ml +259 -0
  246. package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls.ml +44 -0
  247. package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls_stubs.c +358 -0
  248. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/json.ml +376 -0
  249. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/provider.ml +647 -0
  250. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/secret.ml +299 -0
  251. package/project/.sdk/tm/ocaml/feature/secrets/sekreto/sekreto.ml +347 -0
  252. package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +453 -0
  253. package/project/.sdk/tm/ocaml/src/feature/secrets/.gitkeep +0 -0
  254. package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +670 -0
  255. package/project/.sdk/tm/perl/feature/secrets_feature.pm +33 -12
  256. package/project/.sdk/tm/perl/t/feature/secrets/secrets.t +47 -0
  257. package/project/.sdk/tm/php/feature/SecretsFeature.php +30 -6
  258. package/project/.sdk/tm/php/test/feature/secrets/SecretsTest.php +98 -0
  259. package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +28 -6
  260. package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +114 -0
  261. package/project/.sdk/tm/rb/feature/secrets_feature.rb +28 -6
  262. package/project/.sdk/tm/rb/test/feature/secrets/secrets_feature_test.rb +93 -0
  263. package/project/.sdk/tm/rust/feature/secrets.rs +33 -10
  264. package/project/.sdk/tm/rust/tests/feature/secrets/main.rs +96 -0
  265. package/project/.sdk/tm/scala/feature/SecretsFeature.scala +29 -7
  266. package/project/.sdk/tm/scala/sdktest/feature/secrets/SecretsTestMain.scala +71 -0
  267. package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +35 -12
  268. package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +73 -0
  269. package/project/.sdk/tm/zig/feature/secrets/plugin/capability.zig +137 -0
  270. package/project/.sdk/tm/zig/feature/secrets/plugin/catalog.zig +90 -0
  271. package/project/.sdk/tm/zig/feature/secrets/plugin/config.zig +346 -0
  272. package/project/.sdk/tm/zig/feature/secrets/plugin/depend.zig +244 -0
  273. package/project/.sdk/tm/zig/feature/secrets/plugin/env.zig +201 -0
  274. package/project/.sdk/tm/zig/feature/secrets/plugin/export.zig +83 -0
  275. package/project/.sdk/tm/zig/feature/secrets/plugin/graph.zig +212 -0
  276. package/project/.sdk/tm/zig/feature/secrets/plugin/host.zig +1224 -0
  277. package/project/.sdk/tm/zig/feature/secrets/plugin/inst.zig +126 -0
  278. package/project/.sdk/tm/zig/feature/secrets/plugin/order.zig +228 -0
  279. package/project/.sdk/tm/zig/feature/secrets/plugin/plugin.zig +34 -0
  280. package/project/.sdk/tm/zig/feature/secrets/plugin/point.zig +166 -0
  281. package/project/.sdk/tm/zig/feature/secrets/plugin/ref.zig +147 -0
  282. package/project/.sdk/tm/zig/feature/secrets/plugin/resolve.zig +74 -0
  283. package/project/.sdk/tm/zig/feature/secrets/plugin/types.zig +140 -0
  284. package/project/.sdk/tm/zig/feature/secrets/plugin/value.zig +662 -0
  285. package/project/.sdk/tm/zig/feature/secrets/plugin/version.zig +139 -0
  286. package/project/.sdk/tm/zig/feature/secrets/plugins/aws.zig +294 -0
  287. package/project/.sdk/tm/zig/feature/secrets/plugins/azuresecrets.zig +222 -0
  288. package/project/.sdk/tm/zig/feature/secrets/plugins/boru.zig +188 -0
  289. package/project/.sdk/tm/zig/feature/secrets/plugins/doppler.zig +135 -0
  290. package/project/.sdk/tm/zig/feature/secrets/plugins/gcpsecrets.zig +170 -0
  291. package/project/.sdk/tm/zig/feature/secrets/plugins/hashicorp.zig +242 -0
  292. package/project/.sdk/tm/zig/feature/secrets/plugins/httpjson.zig +535 -0
  293. package/project/.sdk/tm/zig/feature/secrets/plugins/infisical.zig +167 -0
  294. package/project/.sdk/tm/zig/feature/secrets/plugins/onepassword.zig +202 -0
  295. package/project/.sdk/tm/zig/feature/secrets/plugins/secretspec.zig +160 -0
  296. package/project/.sdk/tm/zig/feature/secrets/plugins/sigv4.zig +336 -0
  297. package/project/.sdk/tm/zig/feature/secrets/sekreto/addr.zig +148 -0
  298. package/project/.sdk/tm/zig/feature/secrets/sekreto/builtins.zig +259 -0
  299. package/project/.sdk/tm/zig/feature/secrets/sekreto/provider.zig +440 -0
  300. package/project/.sdk/tm/zig/feature/secrets/sekreto/sekreto.zig +944 -0
  301. package/project/.sdk/tm/zig/feature/secrets.zig +854 -0
  302. package/project/.sdk/tm/zig/src/feature/secrets/.gitkeep +0 -0
  303. package/project/.sdk/tm/zig/test/feature/secrets/secrets_test.zig +891 -0
  304. package/project/sdkgen-package.json +1 -1
@@ -0,0 +1,1494 @@
1
+ // VENDORED: @voxgig/plugin sdk-20260908-1556-0 (c/src/host.c)
2
+ // Source: https://github.com/voxgig/plugin @ 48392f5e2b6d1434ee9b1a4a9a11f4480aaeb46a [tag: sdk-20260908-1556-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),
5
+ * and resource capture (§8). See host.h for the two rules that shape
6
+ * every function here. */
7
+
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+
12
+ #include "host.h"
13
+ #include "capability.h"
14
+ #include "config.h"
15
+ #include "depend.h"
16
+ #include "export.h"
17
+ #include "graph.h"
18
+ #include "order.h"
19
+ #include "ref.h"
20
+
21
+ typedef struct ScopeEntry {
22
+ ReleaseFn fn;
23
+ void *ctx;
24
+ bool done;
25
+ /* `acquire` and `release` both count toward `open`; a nested host's
26
+ * teardown does NOT — a teardown is not an acquisition, and the inner
27
+ * host keeps its own counter (`nest/open`). */
28
+ bool counts;
29
+ } ScopeEntry;
30
+
31
+ struct Inst {
32
+ const char *ref;
33
+ Definition *def;
34
+ const char *status;
35
+ double pos;
36
+ double seq;
37
+ Value *options;
38
+ Value *state;
39
+ Value *order;
40
+ /* §11.4's ALWAYS-RELUCTANT rebinding, made concrete: the provider ref
41
+ * this instance's activation actually selected, per requirement name.
42
+ * Recomputing the best candidate on every question silently re-points
43
+ * a live consumer at any better-ranked newcomer, and then losing the
44
+ * provider it was really using does not restart it. */
45
+ Value *selected;
46
+ /* §9.6's `active: false`. THE BAR OUTLIVES THE APPLY THAT SET IT: a
47
+ * flag consulted only while `apply` ran let a later direct `ready`
48
+ * bring the instance live, which is the config switch it exists to be
49
+ * silently ignored. */
50
+ bool barred;
51
+ Value *unmet;
52
+ ScopeEntry **scope;
53
+ size_t nscope;
54
+ size_t capscope;
55
+ /* Declared in `define`, inserted only when activation SUCCEEDS
56
+ * (§8.1). Holding them until then is what makes a failed activate
57
+ * leave nothing behind. */
58
+ Bound **bindings;
59
+ size_t nbindings;
60
+ size_t capbindings;
61
+ Host *inner;
62
+ /* Declared in `define`, and VISIBLE while merely `loaded` (§11): they
63
+ * are data, and hiding them would make the loaded state useless for
64
+ * introspection. */
65
+ Value *exports;
66
+ Value *provides;
67
+ Host *owner;
68
+ struct Inst *next;
69
+ };
70
+
71
+ struct Host {
72
+ Catalog *catalog;
73
+ Value *reserved;
74
+ Value *keys;
75
+ Value *defaults;
76
+ Value *profile;
77
+ Value *points;
78
+ HookFn *basefns;
79
+ Value *basepoints;
80
+ const char *dependency;
81
+ /* Set for the duration of a bulk teardown, so `held` knows this is a
82
+ * coordinated operation rather than an ad-hoc deactivation. */
83
+ bool coordinated;
84
+
85
+ Inst *first;
86
+ Value *log;
87
+ Value *events;
88
+ double seqn;
89
+ double open;
90
+ bool intransition;
91
+ /* WHICH callback is running, not merely that one is. §8.1 puts
92
+ * resource capture in `activate` and §8.3 says `release` outside
93
+ * `activate` is `plugin_release_scope` — and a boolean alone cannot
94
+ * tell `activate` from `define`, so it admitted an acquire in
95
+ * `define` whose scope `unload` would never unwind. */
96
+ const char *phase;
97
+ };
98
+
99
+ /* ------------------------------------------------------------------ */
100
+ /* registry helpers */
101
+ /* ------------------------------------------------------------------ */
102
+
103
+ static int bytewise(const void *a, const void *b) {
104
+ return strcmp(*(const char *const *)a, *(const char *const *)b);
105
+ }
106
+
107
+ /* Every instance ref, SORTED — the deterministic walk §4 rule 4
108
+ * requires in a language whose containers have no inherent order. */
109
+ static size_t sortedrefs(Host *h, const char ***out) {
110
+ size_t n = 0;
111
+ for (Inst *e = h->first; NULL != e; e = e->next) n++;
112
+ const char **refs = (const char **)arena_alloc(sizeof(char *) * (n + 1));
113
+ size_t i = 0;
114
+ for (Inst *e = h->first; NULL != e; e = e->next) refs[i++] = e->ref;
115
+ if (1 < n) qsort((void *)refs, n, sizeof(char *), bytewise);
116
+ *out = refs;
117
+ return n;
118
+ }
119
+
120
+ static Inst *findinst(Host *h, const char *ref) {
121
+ for (Inst *e = h->first; NULL != e; e = e->next) {
122
+ if (0 == strcmp(e->ref, ref)) return e;
123
+ }
124
+ return NULL;
125
+ }
126
+
127
+ static void removeinst(Host *h, Inst *target) {
128
+ Inst *prev = NULL;
129
+ for (Inst *e = h->first; NULL != e; e = e->next) {
130
+ if (e == target) {
131
+ if (NULL == prev) h->first = e->next;
132
+ else prev->next = e->next;
133
+ return;
134
+ }
135
+ prev = e;
136
+ }
137
+ }
138
+
139
+ static size_t instcount(Host *h) {
140
+ size_t n = 0;
141
+ for (Inst *e = h->first; NULL != e; e = e->next) n++;
142
+ return n;
143
+ }
144
+
145
+ Catalog *host_catalog(Host *h) { return h->catalog; }
146
+ void host_define(Host *h, Definition *def) { catalog_add(h->catalog, def); }
147
+
148
+ Host *makehost(HostOptions *opts) {
149
+ Host *h = (Host *)arena_alloc(sizeof(Host));
150
+ h->catalog = (NULL != opts && NULL != opts->catalog) ? opts->catalog : makecatalog();
151
+ h->reserved = (NULL != opts) ? opts->reserved : NULL;
152
+ h->keys = (NULL != opts) ? opts->keys : NULL;
153
+ h->defaults = (NULL != opts) ? opts->defaults : NULL;
154
+ h->profile = (NULL != opts) ? opts->profile : NULL;
155
+ h->points = (NULL != opts && vismap(opts->points)) ? opts->points : vmap();
156
+ h->basefns = (NULL != opts) ? opts->basefns : NULL;
157
+ h->basepoints = (NULL != opts) ? opts->basepoints : NULL;
158
+ h->dependency = (NULL != opts && NULL != opts->dependency) ? opts->dependency : "restart";
159
+ h->coordinated = false;
160
+ h->first = NULL;
161
+ h->log = vlist();
162
+ h->events = vlist();
163
+ h->seqn = 0;
164
+ h->open = 0;
165
+ h->intransition = false;
166
+ h->phase = NULL;
167
+ return h;
168
+ }
169
+
170
+ /* ------------------------------------------------------------------ */
171
+ /* observation */
172
+ /* ------------------------------------------------------------------ */
173
+
174
+ Value *host_list(Host *h) {
175
+ Value *out = vmap();
176
+ const char **refs;
177
+ size_t n = sortedrefs(h, &refs);
178
+ for (size_t i = 0; i < n; i++) {
179
+ vset(out, refs[i], vstr(findinst(h, refs[i])->status));
180
+ }
181
+ return out;
182
+ }
183
+
184
+ Inst *host_instance(Host *h, const char *ref) {
185
+ /* The VALIDATING canonicalizer, not the forgiving one: a lookup with
186
+ * a malformed ref is `plugin_bad_name`, not a miss
187
+ * (`declare/lookup#malformed`). Rust and swift both wrote this with
188
+ * `canon` and failed that entry. */
189
+ return findinst(h, canonref(vstr(ref)));
190
+ }
191
+
192
+ Inst *inst_of(Host *h, const char *ref) { return host_instance(h, ref); }
193
+
194
+ Value *host_observable(Host *h, Value *result, bool hasresult) {
195
+ Value *out = vmap();
196
+ vset(out, "status", host_list(h));
197
+ vset(out, "open", vnum(h->open));
198
+ Value *log = vlist();
199
+ for (size_t i = 0; i < vlen(h->log); i++) vpush(log, vat(h->log, i));
200
+ vset(out, "log", log);
201
+ vset(out, "result", (!hasresult || NULL == result) ? vnull() : result);
202
+ return out;
203
+ }
204
+
205
+ /* A COPY, not the live list: the canonical is `trace: () => events.slice()`, and `observable` already copies the log. Returning the live list lets a caller append to or delete from the host's own event record — application observation code fabricating or erasing lifecycle history. */
206
+ Value *host_trace(Host *h) {
207
+ Value *out = vlist();
208
+ for (size_t i = 0; i < vlen(h->events); i++) vpush(out, vat(h->events, i));
209
+ return out;
210
+ }
211
+
212
+ Value *inst_status(Inst *i) { return vstr(i->status); }
213
+ double inst_seq(Inst *i) { return i->seq; }
214
+ double inst_pos(Inst *i) { return i->pos; }
215
+ Host *inst_inner(Inst *i) { return i->inner; }
216
+ const char *inst_ref(Inst *i) { return i->ref; }
217
+ const char *inst_name(Inst *i) { return refname(i->ref); }
218
+ const char *inst_tag(Inst *i) {
219
+ const char *cut = strchr(i->ref, '$');
220
+ return NULL == cut ? "" : cut + 1;
221
+ }
222
+ Value *inst_options(Inst *i) { return i->options; }
223
+ Value *inst_state(Inst *i) { return i->state; }
224
+ Host *inst_host(Inst *i) { return i->owner; }
225
+
226
+ /* ------------------------------------------------------------------ */
227
+ /* guards */
228
+ /* ------------------------------------------------------------------ */
229
+
230
+ static void guard(Host *h) {
231
+ if (h->intransition) {
232
+ fail("plugin_reentrant",
233
+ "transition attempted from inside a lifecycle callback", NULL);
234
+ }
235
+ }
236
+
237
+ static Inst *need(Host *h, const char *ref) {
238
+ const char *r = canonref(vstr(ref));
239
+ Inst *e = findinst(h, r);
240
+ if (NULL == e) {
241
+ size_t sz = strlen(r) + 32;
242
+ char *text = (char *)arena_alloc(sz);
243
+ snprintf(text, sz, "no such instance: %s", r);
244
+ fail("plugin_not_loaded", text, details1("ref", vstr(r)));
245
+ }
246
+ return e;
247
+ }
248
+
249
+ static void checkreserved(Host *h, const char *ref) {
250
+ if (!vislist(h->reserved) || 0 == vlen(h->reserved)) return;
251
+ const char *name = refname(ref);
252
+ for (size_t i = 0; i < vlen(h->reserved); i++) {
253
+ Value *r = vat(h->reserved, i);
254
+ if (visstr(r) && 0 == strcmp(vasstr(r), name)) {
255
+ size_t sz = strlen(ref) + 48;
256
+ char *text = (char *)arena_alloc(sz);
257
+ snprintf(text, sz, "ref is reserved by the host: %s", ref);
258
+ fail("plugin_ref_reserved", text, details1("ref", vstr(ref)));
259
+ }
260
+ }
261
+ }
262
+
263
+ /* ------------------------------------------------------------------ */
264
+ /* scope */
265
+ /* ------------------------------------------------------------------ */
266
+
267
+ static void pushscope(Inst *e, ReleaseFn fn, void *ctx, bool counts) {
268
+ if (e->nscope == e->capscope) {
269
+ size_t cap = 0 == e->capscope ? 8 : e->capscope * 2;
270
+ ScopeEntry **grown = (ScopeEntry **)arena_alloc(sizeof(ScopeEntry *) * cap);
271
+ for (size_t i = 0; i < e->nscope; i++) grown[i] = e->scope[i];
272
+ e->scope = grown;
273
+ e->capscope = cap;
274
+ }
275
+ ScopeEntry *s = (ScopeEntry *)arena_alloc(sizeof(ScopeEntry));
276
+ s->fn = fn;
277
+ s->ctx = ctx;
278
+ s->done = false;
279
+ s->counts = counts;
280
+ e->scope[e->nscope++] = s;
281
+ }
282
+
283
+ /* A selection belongs to ONE activation (§11.4). Leaving `live` by any
284
+ * door drops it, so the next activation ranks afresh — keeping it would
285
+ * make a consumer prefer a provider it never actually ran against.
286
+ *
287
+ * Returns the errors the scope raised. §8.3: "A failing release does
288
+ * not stop the rest. Every entry runs, in reverse order, whatever any
289
+ * of them does; the errors are collected and raised as one
290
+ * `plugin_release_failed`." */
291
+ static Value *unwind(Host *h, Inst *e) {
292
+ e->selected = vmap();
293
+ Value *errors = vlist();
294
+ for (size_t k = e->nscope; 0 < k; k--) {
295
+ ScopeEntry *s = e->scope[k - 1];
296
+ if (s->done) continue;
297
+ s->done = true;
298
+ if (s->counts) h->open -= 1;
299
+ if (NULL == s->fn) continue;
300
+ CatchFrame f;
301
+ if (0 == PLUGIN_TRY(&f)) {
302
+ s->fn(s->ctx);
303
+ PLUGIN_END(&f);
304
+ }
305
+ else {
306
+ vpush(errors, vstr(plugin_caught()->message));
307
+ }
308
+ }
309
+ e->nscope = 0;
310
+ return errors;
311
+ }
312
+
313
+ /* §8.3: "A failed release ends the instance in `failed`, exactly as a
314
+ * failed callback does (§5.2) — a release that raised may have leaked,
315
+ * and an instance that may be holding resources it cannot account for
316
+ * must not be reactivated." */
317
+ static void releasecheck(Inst *e, Value *errors) {
318
+ if (0 == vlen(errors)) return;
319
+ e->status = "failed";
320
+ size_t sz = strlen(e->ref) + 64;
321
+ for (size_t i = 0; i < vlen(errors); i++) sz += strlen(vasstr(vat(errors, i))) + 4;
322
+ char *text = (char *)arena_alloc(sz);
323
+ size_t used = (size_t)snprintf(text, sz, "release failed for %s: ", e->ref);
324
+ for (size_t i = 0; i < vlen(errors); i++) {
325
+ used += (size_t)snprintf(text + used, sz - used, "%s%s",
326
+ 0 < i ? "; " : "", vasstr(vat(errors, i)));
327
+ }
328
+ Value *d = vmap();
329
+ vset(d, "ref", vstr(e->ref));
330
+ vset(d, "cause", errors);
331
+ fail("plugin_release_failed", text, d);
332
+ }
333
+
334
+ /* ------------------------------------------------------------------ */
335
+ /* the instance api */
336
+ /* ------------------------------------------------------------------ */
337
+
338
+ AcquireHandle *inst_acquire(Inst *e) {
339
+ /* §8.1: resources are "acquired during `activate` — the scope's
340
+ * actual job". */
341
+ if (NULL == e->owner->phase || 0 != strcmp(e->owner->phase, "activate")) {
342
+ fail("plugin_release_scope", "acquire called outside activate", NULL);
343
+ }
344
+ pushscope(e, NULL, NULL, true);
345
+ e->owner->open += 1;
346
+ return e->scope[e->nscope - 1];
347
+ }
348
+
349
+ /* Hand a resource back before teardown. Idempotent, and the scope keeps
350
+ * the entry: unwinding it again must be a no-op, or releasing early
351
+ * would make teardown wrong. */
352
+ void inst_giveback(Inst *e, AcquireHandle *handle) {
353
+ if (NULL == handle || handle->done) return;
354
+ handle->done = true;
355
+ if (handle->counts) e->owner->open -= 1;
356
+ }
357
+
358
+ void inst_release(Inst *e, ReleaseFn fn, void *ctx) {
359
+ /* §8.3: "`inst.release` outside `activate` is `plugin_release_scope`".
360
+ * Being in a transition is true in `define` too, and a scope entry
361
+ * registered there is never unwound — `unload` on a merely `loaded`
362
+ * instance does not unwind, because a loaded instance is not supposed
363
+ * to hold anything. */
364
+ if (NULL == e->owner->phase || 0 != strcmp(e->owner->phase, "activate")) {
365
+ fail("plugin_release_scope", "release called outside activate", NULL);
366
+ }
367
+ /* SYMMETRIC WITH `acquire`, and it has to be: `open` counts the
368
+ * resources CURRENTLY HELD, so an entry that is registered and then
369
+ * unwound must leave the count where it found it. Incrementing on
370
+ * registration and never decrementing made every `release` a
371
+ * permanent leak in the counter. */
372
+ pushscope(e, fn, ctx, true);
373
+ e->owner->open += 1;
374
+ }
375
+
376
+ void inst_bind(Inst *e, const char *point, HookFn hook, ChainFn chain,
377
+ void *ctx, Value *band) {
378
+ Host *h = e->owner;
379
+ /* §12's `plugin_bind_scope`: "binding declared outside `define`". §8.1
380
+ * puts binding declaration in `define` and insertion at a SUCCESSFUL
381
+ * activate, and the guard was the half that never got written — so a
382
+ * binding added from `activate` went live without being part of the
383
+ * loaded definition, and a deactivate/activate cycle appended it
384
+ * again. The code was in the table before anything raised it. */
385
+ if (NULL == h->phase || 0 != strcmp(h->phase, "define")) {
386
+ size_t sz = strlen(point) + 48;
387
+ char *text = (char *)arena_alloc(sz);
388
+ snprintf(text, sz, "bind called outside define: %s", point);
389
+ Value *d = vmap();
390
+ vset(d, "ref", vstr(e->ref));
391
+ vset(d, "point", vstr(point));
392
+ fail("plugin_bind_scope", text, d);
393
+ }
394
+ if (!vhas(h->points, point)) {
395
+ size_t sz = strlen(point) + 32;
396
+ char *text = (char *)arena_alloc(sz);
397
+ snprintf(text, sz, "no such point: %s", point);
398
+ fail("plugin_point_unknown", text, details1("point", vstr(point)));
399
+ }
400
+
401
+ if (e->nbindings == e->capbindings) {
402
+ size_t cap = 0 == e->capbindings ? 8 : e->capbindings * 2;
403
+ Bound **grown = (Bound **)arena_alloc(sizeof(Bound *) * cap);
404
+ for (size_t i = 0; i < e->nbindings; i++) grown[i] = e->bindings[i];
405
+ e->bindings = grown;
406
+ e->capbindings = cap;
407
+ }
408
+ Bound *b = (Bound *)arena_alloc(sizeof(Bound));
409
+ b->ref = e->ref;
410
+ b->point = arena_strdup(point);
411
+ b->band = visnum(band) ? vasnum(band) : 0.0;
412
+ b->hook = hook;
413
+ b->chain = chain;
414
+ b->ctx = ctx;
415
+ e->bindings[e->nbindings++] = b;
416
+ }
417
+
418
+ void inst_export(Inst *e, const char *key, Value *value) {
419
+ vset(e->exports, key, value);
420
+ }
421
+
422
+ void inst_provides(Inst *e, Value *p) { vpush(e->provides, p); }
423
+
424
+ /* The scope entry carries the inner host as its context — C's stand-in
425
+ * for the closure every other port writes here. */
426
+ static void closeinner(void *ctx) { host_close((Host *)ctx); }
427
+
428
+ Host *inst_nest(Inst *e, HostOptions *opts) {
429
+ Host *h = e->owner;
430
+ if (!h->intransition) {
431
+ fail("plugin_release_scope", "nest called outside a lifecycle callback", NULL);
432
+ }
433
+ /* AN INSTANCE MAY ITSELF BE A HOST (§6.5), and THE OUTER ONE OWNS THE
434
+ * INNER ONE'S LIFETIME. Registering the teardown in the instance
435
+ * scope is what makes that true rather than aspirational: the inner
436
+ * host closes when the outer instance deactivates, in the same
437
+ * reverse unwind as every other resource.
438
+ *
439
+ * It does NOT count toward `open` — a teardown is not an acquisition
440
+ * (`nest/open`). */
441
+ Host *inner = makehost(opts);
442
+ pushscope(e, closeinner, inner, false);
443
+ e->inner = inner;
444
+ return inner;
445
+ }
446
+
447
+ /* ------------------------------------------------------------------ */
448
+ /* running a callback */
449
+ /* ------------------------------------------------------------------ */
450
+
451
+ static void run(Host *h, Inst *e, const char *at) {
452
+ LifecycleFn fn = definition_callback(e->def, at);
453
+
454
+ size_t sz = strlen(e->ref) + strlen(at) + 2;
455
+ char *entry = (char *)arena_alloc(sz);
456
+ snprintf(entry, sz, "%s:%s", e->ref, at);
457
+ vpush(h->log, vstr(entry));
458
+
459
+ Value *ev = vmap();
460
+ vset(ev, "ref", vstr(e->ref));
461
+ vset(ev, "event", vstr(at));
462
+ vset(ev, "seq", vnum(e->seq));
463
+ vset(ev, "status", vstr(e->status));
464
+ vpush(h->events, ev);
465
+
466
+ if (NULL == fn) return;
467
+
468
+ h->intransition = true;
469
+ h->phase = at;
470
+
471
+ CatchFrame f;
472
+ if (0 == PLUGIN_TRY(&f)) {
473
+ fn(e);
474
+ PLUGIN_END(&f);
475
+ h->intransition = false;
476
+ h->phase = NULL;
477
+ return;
478
+ }
479
+
480
+ h->intransition = false;
481
+ h->phase = NULL;
482
+
483
+ /* §12: `plugin_define_failed` and its three siblings are "a callback
484
+ * raised; wraps the cause". AN ERROR THAT ALREADY CARRIES A CODE
485
+ * KEEPS IT — the code is the error's identity, and a plugin that
486
+ * raised `store_unreachable` must not have it rewritten. Only a
487
+ * code-less error is wrapped, which is the ordinary case for a
488
+ * callback that let a library error escape. */
489
+ if (NULL != plugin_caught()->code && '\0' != plugin_caught()->code[0] &&
490
+ 0 != strcmp(plugin_caught()->code, "plugin_bare")) {
491
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
492
+ }
493
+ size_t tsz = strlen(e->ref) + strlen(at) + strlen(plugin_caught()->text) + 48;
494
+ char *text = (char *)arena_alloc(tsz);
495
+ snprintf(text, tsz, "%s raised in %s: %s", e->ref, at, plugin_caught()->text);
496
+ char *code = (char *)arena_alloc(strlen(at) + 24);
497
+ snprintf(code, strlen(at) + 24, "plugin_%s_failed", at);
498
+ Value *d = vmap();
499
+ vset(d, "ref", vstr(e->ref));
500
+ vset(d, "cause", vstr(plugin_caught()->text));
501
+ fail(code, text, d);
502
+ }
503
+
504
+ /* ------------------------------------------------------------------ */
505
+ /* requirements and providers */
506
+ /* ------------------------------------------------------------------ */
507
+
508
+ static Value *providersof(Host *h, Value *req) {
509
+ Value *cands = vlist();
510
+ /* ASK WHETHER THE NAME IS A REF, do not assume it. A requirement name
511
+ * is a CAPABILITY name first (§11.1) and capability names are
512
+ * free-form, so `2fa` and `my cap` are legal ones that no ref could
513
+ * be called — and `canonref` RAISES on those, which made a perfectly
514
+ * legal document kill the host right here. */
515
+ Value *rname = vget(req, "name");
516
+ const char *asref = visstr(rname) ? tryref(vasstr(rname)) : NULL;
517
+
518
+ const char **refs;
519
+ size_t n = sortedrefs(h, &refs);
520
+ for (size_t i = 0; i < n; i++) {
521
+ Inst *t = findinst(h, refs[i]);
522
+ if (0 != strcmp(t->status, "live")) continue;
523
+ /* A ref satisfies directly. */
524
+ if (NULL != asref && 0 == strcmp(refs[i], asref)) {
525
+ Value *prov = vmap();
526
+ vset(prov, "name", rname);
527
+ Value *c = vmap();
528
+ vset(c, "ref", vstr(refs[i]));
529
+ vset(c, "pos", vnum(t->pos));
530
+ vset(c, "provides", prov);
531
+ vpush(cands, c);
532
+ continue;
533
+ }
534
+ for (size_t j = 0; j < vlen(t->provides); j++) {
535
+ Value *p = vat(t->provides, j);
536
+ if (vsame(vget(p, "name"), rname)) {
537
+ Value *c = vmap();
538
+ vset(c, "ref", vstr(refs[i]));
539
+ vset(c, "pos", vnum(t->pos));
540
+ vset(c, "provides", p);
541
+ vpush(cands, c);
542
+ }
543
+ }
544
+ }
545
+ return resolvecapability(req, cands);
546
+ }
547
+
548
+ static Value *unmetof(Host *h, Inst *e) {
549
+ Value *out = vlist();
550
+ Value *reqs = requirements(e->options);
551
+ for (size_t i = 0; i < vlen(reqs); i++) {
552
+ Value *r = vat(reqs, i);
553
+ if (!gatesactivation(r)) continue;
554
+ if (0 == vlen(providersof(h, r))) vpush(out, vget(r, "name"));
555
+ }
556
+ return out;
557
+ }
558
+
559
+ /* §11.4's always-reluctant selection, and the ONE place a provider is
560
+ * chosen for a live instance. "A satisfied requirement is not re-bound
561
+ * while it stays satisfied" is a statement about a REMEMBERED choice.
562
+ *
563
+ * `remember` is false for the questions asked ABOUT an instance rather
564
+ * than BY it — introspection must not create a binding. */
565
+ static const char *chosen(Host *h, Inst *e, Value *req, bool remember) {
566
+ Value *cands = providersof(h, req);
567
+ if (0 == vlen(cands)) return NULL;
568
+ const char *name = vasstr(vget(req, "name"));
569
+ Value *heldv = vget(e->selected, name);
570
+ if (visstr(heldv)) {
571
+ for (size_t i = 0; i < vlen(cands); i++) {
572
+ if (0 == strcmp(vasstr(vget(vat(cands, i), "ref")), vasstr(heldv))) {
573
+ return vasstr(heldv);
574
+ }
575
+ }
576
+ }
577
+ const char *first = vasstr(vget(vat(cands, 0), "ref"));
578
+ if (remember) vset(e->selected, name, vstr(first));
579
+ return first;
580
+ }
581
+
582
+ /* The instance currently SELECTED for each of this one's
583
+ * restart-causing requirements. A BINDING IS TO AN INSTANCE, not to a
584
+ * capability (§11.1): the selected one going away restarts a `static`
585
+ * consumer even though a survivor is available. */
586
+ static Value *boundproviders(Host *h, Inst *e) {
587
+ Value *out = vlist();
588
+ Value *reqs = requirements(e->options);
589
+ for (size_t i = 0; i < vlen(reqs); i++) {
590
+ Value *r = vat(reqs, i);
591
+ if (!restartsonloss(r)) continue;
592
+ const char *ref = chosen(h, e, r, false);
593
+ if (NULL == ref) continue;
594
+ bool dup = false;
595
+ for (size_t j = 0; j < vlen(out); j++) {
596
+ if (0 == strcmp(vasstr(vat(out, j)), ref)) { dup = true; break; }
597
+ }
598
+ if (!dup) vpush(out, vstr(ref));
599
+ }
600
+ return out;
601
+ }
602
+
603
+ static Value *consumersof(Host *h, const char *ref) {
604
+ Value *out = vlist();
605
+ const char **refs;
606
+ size_t n = sortedrefs(h, &refs);
607
+ for (size_t i = 0; i < n; i++) {
608
+ if (0 == strcmp(refs[i], ref)) continue;
609
+ Inst *c = findinst(h, refs[i]);
610
+ if (0 != strcmp(c->status, "live")) continue;
611
+ Value *bp = boundproviders(h, c);
612
+ for (size_t j = 0; j < vlen(bp); j++) {
613
+ if (0 == strcmp(vasstr(vat(bp, j)), ref)) { vpush(out, vstr(refs[i])); break; }
614
+ }
615
+ }
616
+ return out;
617
+ }
618
+
619
+ /* §11.3's `hold` asks a DIFFERENT question from the cascade.
620
+ *
621
+ * The cascade wants the edges that RESTART — mandatory-static and
622
+ * optional-static. `hold` says "deactivating a REQUIRED instance is
623
+ * `plugin_dependency_held`", and `required` is CARDINALITY:
624
+ * `gatesactivation`, not `restartsonloss`. The two sets differ in both
625
+ * directions and each difference was a real bug. */
626
+ static Value *holdersof(Host *h, const char *ref) {
627
+ Value *out = vlist();
628
+ const char **refs;
629
+ size_t n = sortedrefs(h, &refs);
630
+ for (size_t i = 0; i < n; i++) {
631
+ if (0 == strcmp(refs[i], ref)) continue;
632
+ Inst *c = findinst(h, refs[i]);
633
+ if (0 != strcmp(c->status, "live")) continue;
634
+ Value *reqs = requirements(c->options);
635
+ for (size_t j = 0; j < vlen(reqs); j++) {
636
+ Value *req = vat(reqs, j);
637
+ if (!gatesactivation(req)) continue;
638
+ const char *sel = chosen(h, c, req, false);
639
+ if (NULL != sel && 0 == strcmp(sel, ref)) { vpush(out, vstr(refs[i])); break; }
640
+ }
641
+ }
642
+ return out;
643
+ }
644
+
645
+ /* The hold check is A GUARD ON AD-HOC DEACTIVATION, NOT ON COORDINATED
646
+ * TEARDOWN. In a bulk operation that is removing the holders too, it is
647
+ * suspended — otherwise `close()` under `hold` would raise on the first
648
+ * provider it reached whenever a document happened to list a consumer
649
+ * after it, which is the policy refusing the one teardown it has no
650
+ * reason to object to. */
651
+ static void held(Host *h, Inst *e) {
652
+ if (0 != strcmp(h->dependency, "hold")) return;
653
+ if (h->coordinated) return;
654
+ Value *holders = holdersof(h, e->ref);
655
+ if (0 == vlen(holders)) return;
656
+ size_t sz = strlen(e->ref) + 64;
657
+ char *text = (char *)arena_alloc(sz);
658
+ snprintf(text, sz, "instance is required by live consumers: %s", e->ref);
659
+ Value *d = vmap();
660
+ vset(d, "ref", vstr(e->ref));
661
+ vset(d, "holders", holders);
662
+ fail("plugin_dependency_held", text, d);
663
+ }
664
+
665
+ /* The requirement graph as plain data, for the pure detector. */
666
+ static Value *graphnodes(Host *h) {
667
+ Value *out = vlist();
668
+ const char **refs;
669
+ size_t n = sortedrefs(h, &refs);
670
+ for (size_t i = 0; i < n; i++) {
671
+ Inst *e = findinst(h, refs[i]);
672
+ Value *provides = vlist();
673
+ for (size_t j = 0; j < vlen(e->provides); j++) {
674
+ vpush(provides, vget(vat(e->provides, j), "name"));
675
+ }
676
+ Value *node = vmap();
677
+ vset(node, "ref", vstr(refs[i]));
678
+ vset(node, "provides", provides);
679
+ vset(node, "requires", requirements(e->options));
680
+ vpush(out, node);
681
+ }
682
+ return out;
683
+ }
684
+
685
+ /* ------------------------------------------------------------------ */
686
+ /* ordering and points */
687
+ /* ------------------------------------------------------------------ */
688
+
689
+ Value *host_order(Host *h, const char *point) {
690
+ /* Sorted by declaration SEQUENCE, which is what makes the §7 sort's
691
+ * fall-through deterministic in a language whose containers have no
692
+ * insertion order. §7 breaks ties by `pos`; two instances CAN share
693
+ * one — `declare` defaults `pos` to the registry size, so an unload
694
+ * followed by a fresh declare reuses a surviving instance's — and
695
+ * past that the canonical was falling through to map order. `seq` is
696
+ * that order, made explicit. Found by review of the go port. */
697
+ size_t total = instcount(h);
698
+ Inst **live = (Inst **)arena_alloc(sizeof(Inst *) * (total + 1));
699
+ size_t n = 0;
700
+ for (Inst *e = h->first; NULL != e; e = e->next) {
701
+ if (0 == strcmp(e->status, "live")) live[n++] = e;
702
+ }
703
+ for (size_t i = 0; i + 1 < n; i++) {
704
+ for (size_t j = i + 1; j < n; j++) {
705
+ if (live[j]->seq < live[i]->seq) { Inst *t = live[i]; live[i] = live[j]; live[j] = t; }
706
+ }
707
+ }
708
+
709
+ Value *bindings = vlist();
710
+ for (size_t i = 0; i < n; i++) {
711
+ Value *b = vmap();
712
+ vset(b, "ref", vstr(live[i]->ref));
713
+ vset(b, "pos", vnum(live[i]->pos));
714
+ if (!visnull(live[i]->order)) vset(b, "order", live[i]->order);
715
+ vpush(bindings, b);
716
+ }
717
+
718
+ Value *spec = NULL == point ? NULL : vget(h->points, point);
719
+ return resolveorder(bindings, vismap(spec) ? vget(spec, "pin") : NULL);
720
+ }
721
+
722
+ Value *host_positionof(Host *h, const char *ref, const char *point) {
723
+ Value *ranked = host_order(h, point);
724
+ const char *r = canonref(vstr(ref));
725
+ double index = -1;
726
+ for (size_t i = 0; i < vlen(ranked); i++) {
727
+ if (0 == strcmp(vasstr(vat(ranked, i)), r)) { index = (double)i; break; }
728
+ }
729
+ Value *out = vmap();
730
+ vset(out, "index", vnum(index));
731
+ vset(out, "count", vnum((double)vlen(ranked)));
732
+ /* §6.2 composes b1(b2(b3(base))) with the FIRST binding OUTERMOST, so
733
+ * these are not index 0 and count-1 the other way round. Getting this
734
+ * backwards is the exact error the positional pin vocabulary exists
735
+ * to prevent. */
736
+ vset(out, "outermost", vbool(0 == index));
737
+ vset(out, "innermost", vbool(index == (double)vlen(ranked) - 1));
738
+ return out;
739
+ }
740
+
741
+ Value *inst_position(Inst *e, const char *point) {
742
+ return host_positionof(e->owner, e->ref, point);
743
+ }
744
+
745
+ /* Live bindings on a point, in resolved order. Recomputed on any change
746
+ * to the live set (§7) rather than cached at startup — the bug a host
747
+ * discovers only when something deactivates in production. */
748
+ static size_t boundon(Host *h, const char *point, Bound ***out) {
749
+ Value *ranked = host_order(h, point);
750
+ size_t cap = 8, n = 0;
751
+ Bound **list = (Bound **)arena_alloc(sizeof(Bound *) * cap);
752
+ for (size_t i = 0; i < vlen(ranked); i++) {
753
+ Inst *e = findinst(h, vasstr(vat(ranked, i)));
754
+ if (NULL == e) continue;
755
+ /* The band is the INSTANCE's ordering block (§7), stamped by the
756
+ * host. A plugin passing its own would be ranking itself above the
757
+ * order its document declared. */
758
+ Value *band = vget(e->order, "band");
759
+ double bandv = visnum(band) ? vasnum(band) : 0.0;
760
+ for (size_t j = 0; j < e->nbindings; j++) {
761
+ if (0 != strcmp(e->bindings[j]->point, point)) continue;
762
+ if (n == cap) {
763
+ cap *= 2;
764
+ Bound **grown = (Bound **)arena_alloc(sizeof(Bound *) * cap);
765
+ for (size_t k = 0; k < n; k++) grown[k] = list[k];
766
+ list = grown;
767
+ }
768
+ Bound *b = (Bound *)arena_alloc(sizeof(Bound));
769
+ *b = *e->bindings[j];
770
+ b->band = bandv;
771
+ list[n++] = b;
772
+ }
773
+ }
774
+ *out = list;
775
+ return n;
776
+ }
777
+
778
+ static Value *pointspec(Host *h, const char *point) {
779
+ Value *spec = vget(h->points, point);
780
+ if (!vhas(h->points, point)) {
781
+ size_t sz = strlen(point) + 32;
782
+ char *text = (char *)arena_alloc(sz);
783
+ snprintf(text, sz, "no such point: %s", point);
784
+ fail("plugin_point_unknown", text, details1("point", vstr(point)));
785
+ }
786
+ return vismap(spec) ? spec : vmap();
787
+ }
788
+
789
+ static void checkkind(Value *spec, const char *point, const char *want) {
790
+ Value *kind = vget(spec, "kind");
791
+ const char *k = visstr(kind) ? vasstr(kind) : NULL;
792
+ bool ok = (NULL == k) ? (0 == strcmp(want, "hook")) : (0 == strcmp(k, want));
793
+ if (ok) return;
794
+ size_t sz = strlen(point) + strlen(want) + 40;
795
+ char *text = (char *)arena_alloc(sz);
796
+ snprintf(text, sz, "point is not a %s: %s", want, point);
797
+ Value *d = vmap();
798
+ vset(d, "point", vstr(point));
799
+ vset(d, "kind", NULL == k ? vnull() : vstr(k));
800
+ fail("plugin_point_kind", text, d);
801
+ }
802
+
803
+ Value *host_emit(Host *h, const char *point, Value *arg) {
804
+ Value *spec = pointspec(h, point);
805
+ checkkind(spec, point, "hook");
806
+ Bound **bindings;
807
+ size_t n = boundon(h, point, &bindings);
808
+ Value *mode = vget(spec, "mode");
809
+ Value *errors = NULL;
810
+ Value *out = point_emit(bindings, n, visstr(mode) ? vasstr(mode) : "emit",
811
+ arg, &errors);
812
+ const char *m = visstr(mode) ? vasstr(mode) : "emit";
813
+ if (0 == strcmp(m, "emit")) return NULL;
814
+ if (0 == strcmp(m, "bail")) return out;
815
+ return errors;
816
+ }
817
+
818
+ static HookFn basefor(Host *h, const char *point) {
819
+ if (NULL == h->basefns || !vislist(h->basepoints)) return NULL;
820
+ for (size_t i = 0; i < vlen(h->basepoints); i++) {
821
+ if (0 == strcmp(vasstr(vat(h->basepoints, i)), point)) return h->basefns[i];
822
+ }
823
+ return NULL;
824
+ }
825
+
826
+ Value *host_call(Host *h, const char *point, Value *arg) {
827
+ Value *spec = pointspec(h, point);
828
+ checkkind(spec, point, "chain");
829
+ Bound **bindings;
830
+ size_t n = boundon(h, point, &bindings);
831
+ /* The host owns the base and a plugin cannot replace it (§6.2). One
832
+ * that wants to SUBSTITUTE rather than wrap binds innermost and
833
+ * simply does not call `next`. */
834
+ return point_call(bindings, n, basefor(h, point), NULL, arg);
835
+ }
836
+
837
+ Value *host_provider(Host *h, const char *point, Value *arg) {
838
+ Value *spec = pointspec(h, point);
839
+ checkkind(spec, point, "provider");
840
+ Bound **bindings;
841
+ size_t n = boundon(h, point, &bindings);
842
+ Value *shadow = NULL;
843
+ Bound *winner = point_provider(bindings, n,
844
+ vtruthy(vget(spec, "exclusive")), &shadow);
845
+ if (NULL == winner) return vget(spec, "default");
846
+ return winner->hook(arg, winner->ctx);
847
+ }
848
+
849
+ Value *host_shadowed(Host *h, const char *point) {
850
+ if (!vhas(h->points, point)) return vlist();
851
+ Value *spec = vget(h->points, point);
852
+ Bound **bindings;
853
+ size_t n = boundon(h, point, &bindings);
854
+ Value *shadow = NULL;
855
+ point_provider(bindings, n,
856
+ vismap(spec) && vtruthy(vget(spec, "exclusive")), &shadow);
857
+ return NULL == shadow ? vlist() : shadow;
858
+ }
859
+
860
+ Value *host_exports(Host *h, const char *spec) {
861
+ Value *all = vlist();
862
+ const char **refs;
863
+ size_t n = sortedrefs(h, &refs);
864
+ for (size_t i = 0; i < n; i++) {
865
+ Inst *e = findinst(h, refs[i]);
866
+ /* Exports of a `loaded` (not live) instance are VISIBLE (§11). */
867
+ if (0 == strcmp(e->status, "declared") || 0 == strcmp(e->status, "failed")) continue;
868
+ const char **keys;
869
+ size_t kn = vkeys(e->exports, &keys);
870
+ for (size_t j = 0; j < kn; j++) {
871
+ Value *ex = vmap();
872
+ vset(ex, "ref", vstr(refs[i]));
873
+ vset(ex, "key", vstr(keys[j]));
874
+ vset(ex, "value", vget(e->exports, keys[j]));
875
+ vpush(all, ex);
876
+ }
877
+ }
878
+ return resolveexport(vstr(spec), all);
879
+ }
880
+
881
+ Value *host_capability(Host *h, const char *name) {
882
+ Value *cands = vlist();
883
+ const char **refs;
884
+ size_t n = sortedrefs(h, &refs);
885
+ for (size_t i = 0; i < n; i++) {
886
+ Inst *e = findinst(h, refs[i]);
887
+ if (0 != strcmp(e->status, "live")) continue;
888
+ for (size_t j = 0; j < vlen(e->provides); j++) {
889
+ Value *p = vat(e->provides, j);
890
+ if (visstr(vget(p, "name")) && 0 == strcmp(vasstr(vget(p, "name")), name)) {
891
+ Value *c = vmap();
892
+ vset(c, "ref", vstr(refs[i]));
893
+ vset(c, "pos", vnum(e->pos));
894
+ vset(c, "provides", p);
895
+ vpush(cands, c);
896
+ }
897
+ }
898
+ }
899
+ Value *req = vmap();
900
+ vset(req, "name", vstr(name));
901
+ Value *ranked = resolvecapability(req, cands);
902
+ Value *out = vlist();
903
+ for (size_t i = 0; i < vlen(ranked); i++) vpush(out, vget(vat(ranked, i), "ref"));
904
+ return out;
905
+ }
906
+
907
+ /* ------------------------------------------------------------------ */
908
+ /* the state machine */
909
+ /* ------------------------------------------------------------------ */
910
+
911
+ static void reconcile(Host *h);
912
+
913
+ const char *host_autotag(Host *h, const char *name) {
914
+ /* AUTO-TAGGING IS EXPLICIT (§4 rule 3): the LOWEST UNUSED POSITIVE
915
+ * INTEGER tag. It needs a host because it must know what is already
916
+ * declared, which is why it cannot live in the pure `ref` section. */
917
+ for (int n = 1;; n++) {
918
+ char tag[32];
919
+ snprintf(tag, sizeof(tag), "%d", n);
920
+ const char *cand = formatref(vstr(name), vstr(tag));
921
+ if (NULL == findinst(h, cand)) return cand;
922
+ }
923
+ }
924
+
925
+ Inst *host_declare(Host *h, const char *ref, DeclareSpec *spec) {
926
+ const char *r;
927
+ if (NULL != spec && NULL != spec->tag && 0 == strcmp(spec->tag, "?")) {
928
+ r = host_autotag(h, refname(canonref(vstr(ref))));
929
+ }
930
+ else {
931
+ r = canonref(vstr(ref));
932
+ }
933
+
934
+ if (NULL == spec || !spec->hostowned) checkreserved(h, r);
935
+
936
+ const char *defname = (NULL != spec && NULL != spec->definition)
937
+ ? spec->definition : refname(r);
938
+ Definition *def = catalog_get(h->catalog, defname);
939
+ if (NULL == def) {
940
+ size_t sz = strlen(defname) + 32;
941
+ char *text = (char *)arena_alloc(sz);
942
+ snprintf(text, sz, "not in catalog: %s", defname);
943
+ fail("plugin_unknown_definition", text, details1("name", vstr(defname)));
944
+ }
945
+
946
+ Inst *existing = findinst(h, r);
947
+ if (NULL != existing) {
948
+ /* §4 rule 1: a pair addresses at most one instance. Re-declaring the
949
+ * SAME definition is the idempotent case; a different one is a
950
+ * duplicate, not a silent overwrite (seneca) and not an
951
+ * impossibility (sdkgen). */
952
+ if (0 != strcmp(existing->def->name, def->name)) {
953
+ size_t sz = strlen(r) + 40;
954
+ char *text = (char *)arena_alloc(sz);
955
+ snprintf(text, sz, "instance already declared: %s", r);
956
+ fail("plugin_ref_duplicate", text, details1("ref", vstr(r)));
957
+ }
958
+ return existing;
959
+ }
960
+
961
+ Inst *e = (Inst *)arena_alloc(sizeof(Inst));
962
+ e->ref = arena_strdup(r);
963
+ e->def = def;
964
+ e->status = "declared";
965
+ e->pos = (NULL != spec && spec->haspos) ? spec->pos : (double)instcount(h);
966
+ e->seq = h->seqn++;
967
+ /* NO OPTIONS ADOPTED HERE. `apply` resolves options and hands the map
968
+ * over; adopting the caller's map made target and source THE SAME MAP
969
+ * in the refill that follows, which cleared its own source and left a
970
+ * first-time instance with no options at all. */
971
+ e->options = (NULL != spec && vismap(spec->options)) ? spec->options : vmap();
972
+ e->state = vmap();
973
+ e->order = (NULL != spec) ? spec->order : NULL;
974
+ e->selected = vmap();
975
+ e->barred = false;
976
+ e->unmet = vlist();
977
+ e->scope = NULL;
978
+ e->nscope = 0;
979
+ e->capscope = 0;
980
+ e->bindings = NULL;
981
+ e->nbindings = 0;
982
+ e->capbindings = 0;
983
+ e->inner = NULL;
984
+ e->exports = vmap();
985
+ e->provides = vlist();
986
+ e->owner = h;
987
+ e->next = NULL;
988
+
989
+ Inst **tail = &h->first;
990
+ while (NULL != *tail) tail = &(*tail)->next;
991
+ *tail = e;
992
+ return e;
993
+ }
994
+
995
+ Inst *host_load(Host *h, const char *ref, DeclareSpec *spec) {
996
+ guard(h);
997
+ Inst *e = host_declare(h, ref, spec);
998
+ if (0 != strcmp(e->status, "declared")) return e; /* idempotent */
999
+ /* PRESENT AND NOT NULL, not merely present. Every driver builds its
1000
+ * command spec with all four keys and a null for each absent one, so
1001
+ * a presence test reads an omitted `options` as an authored empty and
1002
+ * wipes the real ones. */
1003
+ if (NULL != spec && vismap(spec->options)) e->options = spec->options;
1004
+
1005
+ CatchFrame f;
1006
+ if (0 == PLUGIN_TRY(&f)) {
1007
+ run(h, e, "define");
1008
+ PLUGIN_END(&f);
1009
+ }
1010
+ else {
1011
+ e->status = "failed";
1012
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1013
+ }
1014
+ e->status = "loaded";
1015
+
1016
+ /* AT LOAD, and before anything runs: a cycle through restart-causing
1017
+ * requirements does not settle, and the only safe time to report a
1018
+ * non-terminating reconcile is before it starts (§11.3). `provides`
1019
+ * is populated by `define`, which has just run, so this is the first
1020
+ * moment the graph is complete. */
1021
+ if (0 == PLUGIN_TRY(&f)) {
1022
+ checkcycle(graphnodes(h));
1023
+ PLUGIN_END(&f);
1024
+ }
1025
+ else {
1026
+ e->status = "failed";
1027
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1028
+ }
1029
+ return e;
1030
+ }
1031
+
1032
+ /* CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (§11.3).
1033
+ *
1034
+ * The cascade is part of the provider's own deactivation and runs
1035
+ * BEFORE the provider's `deactivate` callback and scope unwind, so a
1036
+ * consumer's teardown can still call the thing it depends on — flushing
1037
+ * a buffer to the store it is about to lose is exactly what a
1038
+ * `deactivate` callback is for. */
1039
+ static void cascade(Host *h, Inst *provider, Value *seen) {
1040
+ if (vhas(seen, provider->ref)) return;
1041
+ vset(seen, provider->ref, vbool(true));
1042
+
1043
+ Value *cons = consumersof(h, provider->ref);
1044
+ for (size_t i = 0; i < vlen(cons); i++) {
1045
+ Inst *c = findinst(h, vasstr(vat(cons, i)));
1046
+ if (NULL == c || 0 != strcmp(c->status, "live")) continue;
1047
+ cascade(h, c, seen); /* deepest-first */
1048
+ /* VOLATILE, and this is a correctness requirement rather than a
1049
+ * warning to silence: C guarantees only that `volatile` locals keep
1050
+ * their value across a `longjmp`, so a flag set before the jump and
1051
+ * read after it is indeterminate without this. Every local that
1052
+ * straddles a PLUGIN_TRY in this file is marked, and gcc's
1053
+ * -Wclobbered is what finds the ones a reader would miss. */
1054
+ volatile bool bad = false;
1055
+ CatchFrame f;
1056
+ if (0 == PLUGIN_TRY(&f)) {
1057
+ run(h, c, "deactivate");
1058
+ PLUGIN_END(&f);
1059
+ }
1060
+ else {
1061
+ bad = true;
1062
+ }
1063
+ Value *errors = unwind(h, c);
1064
+ if (bad || 0 < vlen(errors)) {
1065
+ /* §5.2: ANY failure during a transition lands the instance in
1066
+ * `failed`, and a cascaded consumer is not an exception. Marking
1067
+ * it `pending` instead handed it straight back to `reconcile`,
1068
+ * which would activate it again the moment the provider returned
1069
+ * — the one thing `failed` exists to stop. */
1070
+ c->status = "failed";
1071
+ continue;
1072
+ }
1073
+ c->status = "pending";
1074
+ c->unmet = unmetof(h, c);
1075
+ }
1076
+ }
1077
+
1078
+ Inst *host_activate(Host *h, const char *ref) {
1079
+ guard(h);
1080
+ Inst *e = need(h, ref);
1081
+ if (0 == strcmp(e->status, "live")) return e; /* no-op returning success */
1082
+ if (0 == strcmp(e->status, "failed")) {
1083
+ size_t sz = strlen(e->ref) + 32;
1084
+ char *text = (char *)arena_alloc(sz);
1085
+ snprintf(text, sz, "instance has failed: %s", e->ref);
1086
+ fail("plugin_bad_state", text, details1("ref", vstr(e->ref)));
1087
+ }
1088
+ /* §9.6: `active: false` bars the instance from running, and the bar
1089
+ * is on the INSTANCE rather than on the apply that set it. `ready`
1090
+ * reaches this through `activate`, which is why one guard covers both
1091
+ * verbs the design names. */
1092
+ if (e->barred) {
1093
+ size_t sz = strlen(e->ref) + 48;
1094
+ char *text = (char *)arena_alloc(sz);
1095
+ snprintf(text, sz, "instance is barred by active: false: %s", e->ref);
1096
+ fail("plugin_inactive", text, details1("ref", vstr(e->ref)));
1097
+ }
1098
+ if (0 == strcmp(e->status, "declared")) host_load(h, e->ref, NULL);
1099
+
1100
+ /* A declared requirement that is not live means `pending`: activation
1101
+ * is a STANDING REQUEST, not a one-shot event. */
1102
+ Value *unmet = unmetof(h, e);
1103
+ if (0 < vlen(unmet)) {
1104
+ e->unmet = unmet;
1105
+ e->status = "pending";
1106
+ return e;
1107
+ }
1108
+
1109
+ CatchFrame f;
1110
+ if (0 == PLUGIN_TRY(&f)) {
1111
+ run(h, e, "activate");
1112
+ PLUGIN_END(&f);
1113
+ }
1114
+ else {
1115
+ /* Unwind whatever the partial activation captured, in reverse. */
1116
+ unwind(h, e);
1117
+ e->status = "failed";
1118
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1119
+ }
1120
+
1121
+ /* §11.4: THE SELECTION IS MADE HERE, once, and remembered. Every
1122
+ * later question — the cascade, `hold`, `unmet` — reads it back
1123
+ * rather than re-ranking, which is what "always-reluctant" means. */
1124
+ Value *reqs = requirements(e->options);
1125
+ for (size_t i = 0; i < vlen(reqs); i++) chosen(h, e, vat(reqs, i), true);
1126
+ e->status = "live";
1127
+ reconcile(h);
1128
+ return e;
1129
+ }
1130
+
1131
+ Inst *host_deactivate(Host *h, const char *ref) {
1132
+ guard(h);
1133
+ Inst *e = need(h, ref);
1134
+ if (0 == strcmp(e->status, "loaded") || 0 == strcmp(e->status, "declared")) return e;
1135
+
1136
+ /* §5.2: `unload` is THE ONLY TRANSITION OUT OF `failed`. Falling
1137
+ * through here ran the definition's `deactivate` on an instance that
1138
+ * never completed activation and, if that callback happened to
1139
+ * succeed, returned it to `loaded` — from where it could be activated
1140
+ * again, which is precisely what `failed` exists to prevent. */
1141
+ if (0 == strcmp(e->status, "failed")) {
1142
+ size_t sz = strlen(e->ref) + 32;
1143
+ char *text = (char *)arena_alloc(sz);
1144
+ snprintf(text, sz, "instance has failed: %s", e->ref);
1145
+ fail("plugin_bad_state", text, details1("ref", vstr(e->ref)));
1146
+ }
1147
+
1148
+ if (0 == strcmp(e->status, "pending")) {
1149
+ /* DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (§5.2). It never
1150
+ * reached activate, so it holds no scope and no live bindings;
1151
+ * running the definition's deactivate there would be teardown
1152
+ * without matching setup. It cannot fail. */
1153
+ e->status = "loaded";
1154
+ e->unmet = vlist();
1155
+ return e;
1156
+ }
1157
+
1158
+ held(h, e);
1159
+ cascade(h, e, vmap());
1160
+
1161
+ CatchFrame f;
1162
+ if (0 == PLUGIN_TRY(&f)) {
1163
+ run(h, e, "deactivate");
1164
+ PLUGIN_END(&f);
1165
+ }
1166
+ else {
1167
+ unwind(h, e);
1168
+ e->status = "failed";
1169
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1170
+ }
1171
+ releasecheck(e, unwind(h, e));
1172
+ e->status = "loaded";
1173
+ reconcile(h);
1174
+ return e;
1175
+ }
1176
+
1177
+ void host_unload(Host *h, const char *ref) {
1178
+ guard(h);
1179
+ Inst *e = need(h, ref);
1180
+ if (0 == strcmp(e->status, "live") || 0 == strcmp(e->status, "pending")) {
1181
+ if (0 == strcmp(e->status, "live")) {
1182
+ held(h, e);
1183
+ cascade(h, e, vmap());
1184
+ CatchFrame f;
1185
+ if (0 == PLUGIN_TRY(&f)) {
1186
+ run(h, e, "deactivate");
1187
+ PLUGIN_END(&f);
1188
+ }
1189
+ else {
1190
+ /* §5.2: ANY failure during a transition lands the instance in
1191
+ * `failed`, with the scope STILL FULLY UNWOUND. An earlier
1192
+ * draft let the raise propagate straight out of `unload`, which
1193
+ * left the instance `live` and its scope untouched — reporting
1194
+ * a failure while leaking exactly the resources the failure was
1195
+ * about. */
1196
+ unwind(h, e);
1197
+ e->status = "failed";
1198
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1199
+ }
1200
+ releasecheck(e, unwind(h, e));
1201
+ }
1202
+ e->status = "loaded";
1203
+ }
1204
+ if (0 == strcmp(e->status, "loaded") || 0 == strcmp(e->status, "failed")) {
1205
+ CatchFrame f;
1206
+ if (0 == PLUGIN_TRY(&f)) {
1207
+ run(h, e, "close");
1208
+ PLUGIN_END(&f);
1209
+ removeinst(h, e);
1210
+ return;
1211
+ }
1212
+ removeinst(h, e);
1213
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1214
+ }
1215
+ removeinst(h, e);
1216
+ }
1217
+
1218
+ Inst *host_ready(Host *h, const char *ref) {
1219
+ /* Runs the whole forward path in one call (§5.1). §15.2's verb list
1220
+ * omits this; §5.1 defines it and §15.3's `declare` row requires the
1221
+ * corpus to pin it, so the list was incomplete rather than excluding
1222
+ * it (DOCS.md §4.2). */
1223
+ guard(h);
1224
+ const char *r = canonref(vstr(ref));
1225
+ if (NULL == findinst(h, r)) host_declare(h, r, NULL);
1226
+ if (0 == strcmp(findinst(h, r)->status, "declared")) host_load(h, r, NULL);
1227
+ return host_activate(h, r);
1228
+ }
1229
+
1230
+ /* EAGER reconciliation: run to a fixed point rather than scheduling.
1231
+ *
1232
+ * Two directions, and both are the reason `pending` exists. Activation
1233
+ * is a STANDING REQUEST, not a one-shot event: a pending instance whose
1234
+ * requirement arrives activates without being asked again, and a LIVE
1235
+ * instance whose requirement is lost goes back to pending —
1236
+ * recursively, through its own consumers. */
1237
+ static void reconcile(Host *h) {
1238
+ bool moved = true;
1239
+ int rounds = 0;
1240
+ while (moved) {
1241
+ moved = false;
1242
+ if (1000 < ++rounds) break;
1243
+
1244
+ /* Losses first, so a cascade settles in one pass rather than
1245
+ * alternating with re-activations. */
1246
+ const char **refs;
1247
+ volatile size_t n = sortedrefs(h, &refs);
1248
+ for (volatile size_t i = 0; i < n; i++) {
1249
+ Inst *e = findinst(h, refs[i]);
1250
+ if (NULL == e || 0 != strcmp(e->status, "live")) continue;
1251
+ Value *reqs = requirements(e->options);
1252
+ Value *lost = vlist();
1253
+ for (size_t j = 0; j < vlen(reqs); j++) {
1254
+ Value *q = vat(reqs, j);
1255
+ if (!gatesactivation(q)) continue;
1256
+ if (0 == vlen(providersof(h, q))) vpush(lost, q);
1257
+ }
1258
+ if (0 == vlen(lost)) continue;
1259
+ /* POLICY IS PER REQUIREMENT, not per instance (§11.3): only the
1260
+ * definition that has the requirement knows what it can cope
1261
+ * with, and one instance may hold both a `static` and a `dynamic`
1262
+ * one. A `dynamic` requirement whose provider is gone leaves the
1263
+ * consumer LIVE and notified. */
1264
+ bool anyrestart = false;
1265
+ for (size_t j = 0; j < vlen(lost); j++) {
1266
+ if (restartsonloss(vat(lost, j))) { anyrestart = true; break; }
1267
+ }
1268
+ if (!anyrestart) continue;
1269
+
1270
+ volatile bool bad = false;
1271
+ CatchFrame f;
1272
+ if (0 == PLUGIN_TRY(&f)) {
1273
+ run(h, e, "deactivate");
1274
+ PLUGIN_END(&f);
1275
+ }
1276
+ else {
1277
+ bad = true;
1278
+ }
1279
+ Value *errors = unwind(h, e);
1280
+ if (bad || 0 < vlen(errors)) {
1281
+ e->status = "failed";
1282
+ moved = true;
1283
+ continue;
1284
+ }
1285
+ e->status = "pending";
1286
+ e->unmet = unmetof(h, e);
1287
+ moved = true;
1288
+ }
1289
+
1290
+ n = sortedrefs(h, &refs);
1291
+ for (volatile size_t i = 0; i < n; i++) {
1292
+ Inst *e = findinst(h, refs[i]);
1293
+ if (NULL == e || 0 != strcmp(e->status, "pending")) continue;
1294
+ if (0 < vlen(unmetof(h, e))) continue;
1295
+ CatchFrame f;
1296
+ if (0 == PLUGIN_TRY(&f)) {
1297
+ run(h, e, "activate");
1298
+ PLUGIN_END(&f);
1299
+ Value *reqs = requirements(e->options);
1300
+ for (size_t j = 0; j < vlen(reqs); j++) chosen(h, e, vat(reqs, j), true);
1301
+ e->status = "live";
1302
+ e->unmet = vlist();
1303
+ moved = true;
1304
+ }
1305
+ else {
1306
+ unwind(h, e);
1307
+ e->status = "failed";
1308
+ moved = true;
1309
+ }
1310
+ }
1311
+ }
1312
+ }
1313
+
1314
+ /* ------------------------------------------------------------------ */
1315
+ /* documents */
1316
+ /* ------------------------------------------------------------------ */
1317
+
1318
+ /* Empty the target and refill it, so callers holding the reference see
1319
+ * the new values. A definition's callbacks close over the options map
1320
+ * they were handed at `define`; replacing the reference would leave
1321
+ * every binding reading the values the first apply gave it. */
1322
+ static void refill(Value *target, Value *source) {
1323
+ const char **keys;
1324
+ size_t n = vkeys(target, &keys);
1325
+ for (size_t i = 0; i < n; i++) vdel(target, keys[i]);
1326
+ n = vkeys(source, &keys);
1327
+ for (size_t i = 0; i < n; i++) vset(target, keys[i], vget(source, keys[i]));
1328
+ }
1329
+
1330
+ static Value *shapeof(Host *h, const char *ref) {
1331
+ Definition *d = catalog_get(h->catalog, refname(ref));
1332
+ return NULL == d ? NULL : d->shape;
1333
+ }
1334
+
1335
+ void host_apply(Host *h, Value *doc, Value *profile) {
1336
+ guard(h);
1337
+ Value *in = vmap();
1338
+ vset(in, "doc", doc);
1339
+ vset(in, "profile", visnull(profile) ? h->profile : profile);
1340
+ vset(in, "keys", h->keys);
1341
+ vset(in, "reserved", h->reserved);
1342
+ Value *norm = normalizeconfig(in);
1343
+
1344
+ Value *want = vget(norm, "order");
1345
+ Value *optionsof = vmap();
1346
+ for (size_t i = 0; i < vlen(want); i++) {
1347
+ const char *ref = vasstr(vat(want, i));
1348
+ Value *oin = vmap();
1349
+ vset(oin, "ref", vstr(ref));
1350
+ vset(oin, "doc", doc);
1351
+ vset(oin, "profile", visnull(profile) ? h->profile : profile);
1352
+ vset(oin, "shape", shapeof(h, ref));
1353
+ if (vismap(h->defaults)) {
1354
+ vset(oin, "hostdefaults", vget(h->defaults, refname(ref)));
1355
+ }
1356
+ vset(optionsof, ref, resolveoptions(oin));
1357
+ }
1358
+
1359
+ /* --- phase 1: deactivations and unloads, in REVERSE load order --- */
1360
+ Value *instances = vget(norm, "instance");
1361
+ size_t total = instcount(h);
1362
+ const char **drop = (const char **)arena_alloc(sizeof(char *) * (total + 1));
1363
+ size_t ndrop = 0;
1364
+ for (Inst *e = h->first; NULL != e; e = e->next) {
1365
+ if (0 == strcmp(e->status, "declared")) continue;
1366
+ Value *ent = vget(instances, e->ref);
1367
+ bool wantlive = vismap(ent) && vtruthy(vget(ent, "active")) &&
1368
+ visstr(vget(ent, "start")) && 0 == strcmp(vasstr(vget(ent, "start")), "eager");
1369
+ if (!wantlive) drop[ndrop++] = e->ref;
1370
+ }
1371
+ /* Reverse load order: highest `pos` first, ref-descending for a tie,
1372
+ * so a consumer declared after its provider goes down first. */
1373
+ for (size_t i = 0; i + 1 < ndrop; i++) {
1374
+ for (size_t j = i + 1; j < ndrop; j++) {
1375
+ Inst *a = findinst(h, drop[i]);
1376
+ Inst *b = findinst(h, drop[j]);
1377
+ bool swap = (b->pos > a->pos) ||
1378
+ (b->pos == a->pos && 0 > strcmp(drop[j], drop[i]));
1379
+ if (swap) { const char *t = drop[i]; drop[i] = drop[j]; drop[j] = t; }
1380
+ }
1381
+ }
1382
+ for (size_t i = 0; i < ndrop; i++) host_unload(h, drop[i]);
1383
+
1384
+ /* --- phase 2: declare and patch EVERYTHING, in load order -------- */
1385
+ for (size_t i = 0; i < vlen(want); i++) {
1386
+ const char *ref = vasstr(vat(want, i));
1387
+ Value *ent = vget(instances, ref);
1388
+ DeclareSpec spec;
1389
+ memset(&spec, 0, sizeof(spec));
1390
+ spec.order = vget(ent, "order");
1391
+ spec.haspos = true;
1392
+ spec.pos = vasnum(vget(ent, "pos"));
1393
+ host_declare(h, ref, &spec);
1394
+ Inst *e = findinst(h, ref);
1395
+ /* The bar is REASSERTED ON EVERY APPLY, in both directions — a
1396
+ * document that turns the instance back on clears it, which is the
1397
+ * whole point of a config switch. */
1398
+ e->barred = !vtruthy(vget(ent, "active"));
1399
+ refill(e->options, vget(optionsof, ref));
1400
+ e->order = vget(ent, "order");
1401
+ e->pos = vasnum(vget(ent, "pos"));
1402
+ }
1403
+
1404
+ /* --- phase 3: loads, in load order ------------------------------- */
1405
+ for (size_t i = 0; i < vlen(want); i++) {
1406
+ const char *ref = vasstr(vat(want, i));
1407
+ Value *ent = vget(instances, ref);
1408
+ bool wantlive = vtruthy(vget(ent, "active")) &&
1409
+ visstr(vget(ent, "start")) && 0 == strcmp(vasstr(vget(ent, "start")), "eager");
1410
+ if (wantlive) host_load(h, ref, NULL);
1411
+ }
1412
+
1413
+ /* --- phase 4: activations, in load order ------------------------- */
1414
+ for (size_t i = 0; i < vlen(want); i++) {
1415
+ const char *ref = vasstr(vat(want, i));
1416
+ Value *ent = vget(instances, ref);
1417
+ bool wantlive = vtruthy(vget(ent, "active")) &&
1418
+ visstr(vget(ent, "start")) && 0 == strcmp(vasstr(vget(ent, "start")), "eager");
1419
+ if (wantlive) host_activate(h, ref);
1420
+ }
1421
+ }
1422
+
1423
+ void host_setoptions(Host *h, const char *ref, Value *patch) {
1424
+ guard(h);
1425
+ Inst *e = need(h, ref);
1426
+ Value *previous = vclone(e->options);
1427
+ Value *in = vmap();
1428
+ vset(in, "ref", vstr(e->ref));
1429
+ vset(in, "shape", shapeof(h, e->ref));
1430
+ vset(in, "doc", vmap());
1431
+ vset(in, "patch", plugin_merge(previous, patch));
1432
+ refill(e->options, resolveoptions(in));
1433
+
1434
+ if (0 != strcmp(e->status, "live")) return;
1435
+ if (NULL != e->def->reconfigure) {
1436
+ h->intransition = true;
1437
+ h->phase = "reconfigure";
1438
+ CatchFrame f;
1439
+ if (0 == PLUGIN_TRY(&f)) {
1440
+ e->def->reconfigure(e, e->options, previous);
1441
+ PLUGIN_END(&f);
1442
+ h->intransition = false;
1443
+ h->phase = NULL;
1444
+ return;
1445
+ }
1446
+ h->intransition = false;
1447
+ h->phase = NULL;
1448
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1449
+ }
1450
+ /* Always correct and sometimes expensive; `reconfigure` exists to
1451
+ * make the common case cheap (§9.4). */
1452
+ host_deactivate(h, e->ref);
1453
+ host_activate(h, e->ref);
1454
+ }
1455
+
1456
+ void host_close(Host *h) {
1457
+ /* A bulk teardown removing the holders too, so `hold` is suspended
1458
+ * for exactly those holders (§11.3) — while the consumers-first
1459
+ * cascade still runs, which is the half that matters. */
1460
+ h->coordinated = true;
1461
+ size_t total = instcount(h);
1462
+ const char **refs = (const char **)arena_alloc(sizeof(char *) * (total + 1));
1463
+ size_t n = 0;
1464
+ for (Inst *e = h->first; NULL != e; e = e->next) refs[n++] = e->ref;
1465
+ /* Reverse load order. */
1466
+ for (size_t i = 0; i + 1 < n; i++) {
1467
+ for (size_t j = i + 1; j < n; j++) {
1468
+ Inst *a = findinst(h, refs[i]);
1469
+ Inst *b = findinst(h, refs[j]);
1470
+ if (NULL == a || NULL == b) continue;
1471
+ bool swap = (b->pos > a->pos) ||
1472
+ (b->pos == a->pos && 0 > strcmp(refs[j], refs[i]));
1473
+ if (swap) { const char *t = refs[i]; refs[i] = refs[j]; refs[j] = t; }
1474
+ }
1475
+ }
1476
+ /* A COORDINATED FLAG THAT SURVIVES A RAISE IS A DISABLED GUARD. The
1477
+ * canonical wraps the teardown in `try/finally`; here an unload that
1478
+ * raises would skip the reset and leave the host permanently
1479
+ * `coordinated`, so a caller that catches the error and carries on
1480
+ * under `dependency: "hold"` gets ad-hoc deactivation with the holder
1481
+ * check silently off. Catch, reset, re-raise is C's `finally`. */
1482
+ volatile size_t i = 0;
1483
+ CatchFrame f;
1484
+ if (0 == PLUGIN_TRY(&f)) {
1485
+ for (; i < n; i++) {
1486
+ if (NULL != findinst(h, refs[i])) host_unload(h, refs[i]);
1487
+ }
1488
+ PLUGIN_END(&f);
1489
+ h->coordinated = false;
1490
+ return;
1491
+ }
1492
+ h->coordinated = false;
1493
+ fail(plugin_caught()->code, plugin_caught()->text, plugin_caught()->details);
1494
+ }