@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,1224 @@
1
+ // VENDORED: @voxgig/plugin sdk-20260908-1556-0 (zig/src/host.zig)
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).
6
+ //!
7
+ //! TWO RULES SHAPE EVERY FUNCTION HERE.
8
+ //!
9
+ //! Transitions are SEQUENTIAL (§5.2). One at a time, in call order,
10
+ //! never interleaved; a transition triggered from inside a lifecycle
11
+ //! callback is `plugin_reentrant`. A hard rule, because it is the only
12
+ //! way the semantics can be identical in Go, in Ruby and in
13
+ //! single-threaded JavaScript — and in zig, which has no event loop to
14
+ //! hide behind.
15
+ //!
16
+ //! Reconciliation is EAGER (§18's portability budget). A transition
17
+ //! settles by running the state machine to a fixed point, not by
18
+ //! suspending on a promise.
19
+
20
+ const std = @import("std");
21
+ const v = @import("value.zig");
22
+ const t = @import("types.zig");
23
+ const cap = @import("capability.zig");
24
+ const catalog = @import("catalog.zig");
25
+ const cfg = @import("config.zig");
26
+ const dep = @import("depend.zig");
27
+ const exp = @import("export.zig");
28
+ const ord = @import("order.zig");
29
+ const point = @import("point.zig");
30
+ const ref = @import("ref.zig");
31
+ const model = @import("inst.zig");
32
+
33
+ pub const Inst = model.Inst;
34
+ pub const Host = model.Host;
35
+ pub const HostOptions = model.HostOptions;
36
+ pub const DeclareSpec = model.DeclareSpec;
37
+ pub const ScopeEntry = model.ScopeEntry;
38
+ pub const BaseFn = model.BaseFn;
39
+ pub const Definition = catalog.Definition;
40
+
41
+ // ---------------------------------------------------------------------
42
+ // construction and registry helpers
43
+ // ---------------------------------------------------------------------
44
+
45
+ pub fn makehost(o: HostOptions) *Host {
46
+ const h = v.arena().create(Host) catch @panic("oom");
47
+ h.* = .{
48
+ .catalog = o.catalog orelse catalog.makecatalog(),
49
+ .reserved = o.reserved,
50
+ .keys = o.keys,
51
+ .defaults = o.defaults,
52
+ .profile = o.profile,
53
+ .points = if (v.isMap(o.points)) o.points.? else v.vmap(),
54
+ .bases = o.bases,
55
+ .dependency = if (o.dependency.len == 0) "restart" else o.dependency,
56
+ .instances = v.List(*Inst).init(v.arena()),
57
+ .log = v.vlist(),
58
+ .events = v.vlist(),
59
+ };
60
+ return h;
61
+ }
62
+
63
+ pub fn define(h: *Host, d: *Definition) t.Err!void {
64
+ return h.catalog.add(d);
65
+ }
66
+
67
+ fn find(h: *Host, r: []const u8) ?*Inst {
68
+ for (h.instances.items) |e| {
69
+ if (std.mem.eql(u8, e.ref, r)) return e;
70
+ }
71
+ return null;
72
+ }
73
+
74
+ fn lessStr(_: void, a: []const u8, b: []const u8) bool {
75
+ return std.mem.order(u8, a, b) == .lt;
76
+ }
77
+
78
+ /// Every instance ref, SORTED — the deterministic walk §4 rule 4
79
+ /// requires in a language whose containers have no inherent order.
80
+ fn sortedrefs(h: *Host) [][]const u8 {
81
+ const out = v.arena().alloc([]const u8, h.instances.items.len) catch @panic("oom");
82
+ for (h.instances.items, 0..) |e, i| out[i] = e.ref;
83
+ std.mem.sort([]const u8, out, {}, lessStr);
84
+ return out;
85
+ }
86
+
87
+ // ---------------------------------------------------------------------
88
+ // observation
89
+ // ---------------------------------------------------------------------
90
+
91
+ pub fn list(h: *Host) *v.Value {
92
+ const out = v.vmap();
93
+ for (sortedrefs(h)) |r| {
94
+ if (find(h, r)) |e| v.set(out, r, v.vstr(e.status));
95
+ }
96
+ return out;
97
+ }
98
+
99
+ /// The VALIDATING canonicalizer, not the forgiving one: a lookup with a
100
+ /// malformed ref is `plugin_bad_name`, not a miss
101
+ /// (`declare/lookup#malformed`). Rust and swift both wrote this with
102
+ /// `canon` and failed that entry.
103
+ pub fn instance(h: *Host, r: []const u8) t.Err!?*Inst {
104
+ return find(h, try ref.canonrefs(r));
105
+ }
106
+
107
+ pub fn observable(h: *Host, result: ?*v.Value, hasresult: bool) *v.Value {
108
+ const out = v.vmap();
109
+ v.set(out, "status", list(h));
110
+ v.set(out, "open", v.vnum(h.open));
111
+ const lg = v.vlist();
112
+ for (v.items(h.log)) |x| v.push(lg, x);
113
+ v.set(out, "log", lg);
114
+ v.set(out, "result", if (!hasresult or result == null) v.vnull() else result);
115
+ return out;
116
+ }
117
+
118
+ /// 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.
119
+ pub fn trace(h: *Host) *v.Value {
120
+ const out = v.vlist();
121
+ for (v.items(h.events)) |x| v.push(out, x);
122
+ return out;
123
+ }
124
+
125
+ pub fn instname(e: *Inst) []const u8 {
126
+ return ref.refname(e.ref);
127
+ }
128
+
129
+ pub fn insttag(e: *Inst) []const u8 {
130
+ const cut = std.mem.indexOfScalar(u8, e.ref, '$') orelse return "";
131
+ return e.ref[cut + 1 ..];
132
+ }
133
+
134
+ // ---------------------------------------------------------------------
135
+ // guards
136
+ // ---------------------------------------------------------------------
137
+
138
+ fn guard(h: *Host) t.Err!void {
139
+ if (h.intransition) {
140
+ return t.fail("plugin_reentrant", "transition attempted from inside a lifecycle callback", null);
141
+ }
142
+ }
143
+
144
+ fn need(h: *Host, r0: []const u8) t.Err!*Inst {
145
+ const r = try ref.canonrefs(r0);
146
+ return find(h, r) orelse
147
+ t.fail("plugin_not_loaded", v.print("no such instance: {s}", .{r}), t.details1("ref", v.vstr(r)));
148
+ }
149
+
150
+ fn checkreserved(h: *Host, r: []const u8) t.Err!void {
151
+ if (!v.isList(h.reserved) or v.len(h.reserved) == 0) return;
152
+ const name = ref.refname(r);
153
+ for (v.items(h.reserved)) |x| {
154
+ if (v.isStr(x) and std.mem.eql(u8, v.asStr(x), name)) {
155
+ return t.fail("plugin_ref_reserved", v.print("ref is reserved by the host: {s}", .{r}), t.details1("ref", v.vstr(r)));
156
+ }
157
+ }
158
+ }
159
+
160
+ // ---------------------------------------------------------------------
161
+ // scope
162
+ // ---------------------------------------------------------------------
163
+
164
+ fn pushscope(e: *Inst, f: ?model.ReleaseFn, ctx: ?*anyopaque, counts: bool) *ScopeEntry {
165
+ const s = v.arena().create(ScopeEntry) catch @panic("oom");
166
+ s.* = .{ .fn_ = f, .ctx = ctx, .done = false, .counts = counts };
167
+ e.scope.append(s) catch @panic("oom");
168
+ return s;
169
+ }
170
+
171
+ /// A selection belongs to ONE activation (§11.4). Leaving `live` by any
172
+ /// door drops it, so the next activation ranks afresh — keeping it would
173
+ /// make a consumer prefer a provider it never actually ran against.
174
+ ///
175
+ /// Answers the errors the scope raised. §8.3: "A failing release does
176
+ /// not stop the rest. Every entry runs, in reverse order, whatever any
177
+ /// of them does; the errors are collected and raised as one
178
+ /// `plugin_release_failed`."
179
+ ///
180
+ /// A RELEASE CANNOT FAIL IN ZIG'S TYPE SYSTEM: `ReleaseFn` returns void,
181
+ /// because a release that could return an error would make every unwind
182
+ /// site fallible for a failure the contract says must not stop the rest.
183
+ /// The probe that must raise does so through the host's own error slot,
184
+ /// which `releasefailed` reads.
185
+ fn unwind(h: *Host, e: *Inst) *v.Value {
186
+ e.selected = v.vmap();
187
+ const errors = v.vlist();
188
+ var k = e.scope.items.len;
189
+ while (k > 0) {
190
+ k -= 1;
191
+ const s = e.scope.items[k];
192
+ if (s.done) continue;
193
+ s.done = true;
194
+ if (s.counts) h.open -= 1;
195
+ if (s.fn_) |f| {
196
+ release_error = null;
197
+ f(s.ctx);
198
+ if (release_error) |msg| v.push(errors, v.vstr(msg));
199
+ release_error = null;
200
+ }
201
+ }
202
+ e.scope.clearRetainingCapacity();
203
+ return errors;
204
+ }
205
+
206
+ /// The one channel a release has to report a failure, since it cannot
207
+ /// return one. Set by a release callback, read by `unwind`.
208
+ pub var release_error: ?[]const u8 = null;
209
+
210
+ /// §8.3: "A failed release ends the instance in `failed`, exactly as a
211
+ /// failed callback does (§5.2) — a release that raised may have leaked,
212
+ /// and an instance that may be holding resources it cannot account for
213
+ /// must not be reactivated."
214
+ fn releasecheck(e: *Inst, errors: *v.Value) t.Err!void {
215
+ if (v.len(errors) == 0) return;
216
+ e.status = "failed";
217
+ var why = v.List(u8).init(v.arena());
218
+ for (v.items(errors), 0..) |x, i| {
219
+ if (i > 0) why.appendSlice("; ") catch @panic("oom");
220
+ why.appendSlice(v.asStr(x)) catch @panic("oom");
221
+ }
222
+ const d = v.vmap();
223
+ v.set(d, "ref", v.vstr(e.ref));
224
+ v.set(d, "cause", errors);
225
+ return t.fail("plugin_release_failed", v.print("release failed for {s}: {s}", .{ e.ref, why.items }), d);
226
+ }
227
+
228
+ // ---------------------------------------------------------------------
229
+ // the instance api
230
+ // ---------------------------------------------------------------------
231
+
232
+ pub fn acquire(e: *Inst) t.Err!*ScopeEntry {
233
+ // §8.1: resources are "acquired during `activate` — the scope's
234
+ // actual job".
235
+ if (!std.mem.eql(u8, e.owner.phase, "activate")) {
236
+ return t.fail("plugin_release_scope", "acquire called outside activate", null);
237
+ }
238
+ const s = pushscope(e, null, null, true);
239
+ e.owner.open += 1;
240
+ return s;
241
+ }
242
+
243
+ /// Hand a resource back before teardown. Idempotent, and the scope keeps
244
+ /// the entry: unwinding it again must be a no-op, or releasing early
245
+ /// would make teardown wrong.
246
+ pub fn giveback(e: *Inst, s: *ScopeEntry) void {
247
+ if (s.done) return;
248
+ s.done = true;
249
+ if (s.counts) e.owner.open -= 1;
250
+ }
251
+
252
+ pub fn release(e: *Inst, f: ?model.ReleaseFn, ctx: ?*anyopaque) t.Err!void {
253
+ // §8.3: "`inst.release` outside `activate` is
254
+ // `plugin_release_scope`". Being in a transition is true in `define`
255
+ // too, and a scope entry registered there is never unwound —
256
+ // `unload` on a merely `loaded` instance does not unwind, because a
257
+ // loaded instance is not supposed to hold anything.
258
+ if (!std.mem.eql(u8, e.owner.phase, "activate")) {
259
+ return t.fail("plugin_release_scope", "release called outside activate", null);
260
+ }
261
+ // SYMMETRIC WITH `acquire`, and it has to be: `open` counts the
262
+ // resources CURRENTLY HELD, so an entry that is registered and then
263
+ // unwound must leave the count where it found it. Incrementing on
264
+ // registration and never decrementing made every `release` a
265
+ // permanent leak in the counter.
266
+ _ = pushscope(e, f, ctx, true);
267
+ e.owner.open += 1;
268
+ }
269
+
270
+ pub fn bind(
271
+ e: *Inst,
272
+ pt: []const u8,
273
+ hook: ?point.HookFn,
274
+ chain: ?point.ChainFn,
275
+ ctx: ?*anyopaque,
276
+ band: ?*v.Value,
277
+ ) t.Err!void {
278
+ const h = e.owner;
279
+ // §12's `plugin_bind_scope`: "binding declared outside `define`".
280
+ // §8.1 puts binding declaration in `define` and insertion at a
281
+ // SUCCESSFUL activate, and the guard was the half that never got
282
+ // written — so a binding added from `activate` went live without
283
+ // being part of the loaded definition, and a deactivate/activate
284
+ // cycle appended it again. The code was in the table before anything
285
+ // raised it.
286
+ if (!std.mem.eql(u8, h.phase, "define")) {
287
+ const d = v.vmap();
288
+ v.set(d, "ref", v.vstr(e.ref));
289
+ v.set(d, "point", v.vstr(pt));
290
+ return t.fail("plugin_bind_scope", v.print("bind called outside define: {s}", .{pt}), d);
291
+ }
292
+ if (!v.has(h.points, pt)) {
293
+ return t.fail("plugin_point_unknown", v.print("no such point: {s}", .{pt}), t.details1("point", v.vstr(pt)));
294
+ }
295
+ e.bindings.append(.{
296
+ .ref = e.ref,
297
+ .point = v.dupe(pt),
298
+ .band = if (v.isNum(band)) v.asNum(band) else 0,
299
+ .hook = hook,
300
+ .chain = chain,
301
+ .ctx = ctx,
302
+ }) catch @panic("oom");
303
+ }
304
+
305
+ pub fn exportvalue(e: *Inst, key: []const u8, value: ?*v.Value) void {
306
+ v.set(e.exports, key, value);
307
+ }
308
+
309
+ pub fn provides(e: *Inst, p: ?*v.Value) void {
310
+ v.push(e.provides, p);
311
+ }
312
+
313
+ // ---------------------------------------------------------------------
314
+ // running a callback
315
+ // ---------------------------------------------------------------------
316
+
317
+ fn run(h: *Host, e: *Inst, at: []const u8) t.Err!void {
318
+ const f = catalog.callbackFor(e.def, at);
319
+
320
+ v.push(h.log, v.vstr(v.print("{s}:{s}", .{ e.ref, at })));
321
+ const ev = v.vmap();
322
+ v.set(ev, "ref", v.vstr(e.ref));
323
+ v.set(ev, "event", v.vstr(at));
324
+ v.set(ev, "seq", v.vnum(e.seq));
325
+ v.set(ev, "status", v.vstr(e.status));
326
+ v.push(h.events, ev);
327
+
328
+ const cb = f orelse return;
329
+
330
+ h.intransition = true;
331
+ h.phase = at;
332
+ cb(e) catch {
333
+ h.intransition = false;
334
+ h.phase = "";
335
+ // TAKE FIRST. `pending` holds one error, and everything below
336
+ // this line can raise.
337
+ const err = t.take();
338
+ // §12: `plugin_define_failed` and its three siblings are "a
339
+ // callback raised; wraps the cause". AN ERROR THAT ALREADY
340
+ // CARRIES A CODE KEEPS IT — the code is the error's identity,
341
+ // and a plugin that raised `store_unreachable` must not have it
342
+ // rewritten. Only a code-less error is wrapped, which is the
343
+ // ordinary case for a callback that let a library error escape.
344
+ if (err.code.len > 0 and !std.mem.eql(u8, err.code, "plugin_bare")) {
345
+ return t.reraise(err);
346
+ }
347
+ const d = v.vmap();
348
+ v.set(d, "ref", v.vstr(e.ref));
349
+ v.set(d, "cause", v.vstr(err.text));
350
+ return t.fail(v.print("plugin_{s}_failed", .{at}), v.print("{s} raised in {s}: {s}", .{ e.ref, at, err.text }), d);
351
+ };
352
+ h.intransition = false;
353
+ h.phase = "";
354
+ }
355
+
356
+ // ---------------------------------------------------------------------
357
+ // requirements and providers
358
+ // ---------------------------------------------------------------------
359
+
360
+ fn providersof(h: *Host, req: ?*v.Value) *v.Value {
361
+ const cands = v.vlist();
362
+ // ASK WHETHER THE NAME IS A REF, do not assume it. A requirement
363
+ // name is a CAPABILITY name first (§11.1) and capability names are
364
+ // free-form, so `2fa` and `my cap` are legal ones that no ref could
365
+ // be called — and `canonref` FAILS on those, which made a perfectly
366
+ // legal document kill the host right here.
367
+ const rname = v.get(req, "name");
368
+ const asref = if (v.isStr(rname)) ref.tryref(v.asStr(rname)) else null;
369
+
370
+ for (sortedrefs(h)) |r| {
371
+ const tinst = find(h, r) orelse continue;
372
+ if (!std.mem.eql(u8, tinst.status, "live")) continue;
373
+ // A ref satisfies directly.
374
+ if (asref != null and std.mem.eql(u8, r, asref.?)) {
375
+ const prov = v.vmap();
376
+ v.set(prov, "name", rname);
377
+ const c = v.vmap();
378
+ v.set(c, "ref", v.vstr(r));
379
+ v.set(c, "pos", v.vnum(tinst.pos));
380
+ v.set(c, "provides", prov);
381
+ v.push(cands, c);
382
+ continue;
383
+ }
384
+ for (v.items(tinst.provides)) |p| {
385
+ if (v.same(v.get(p, "name"), rname)) {
386
+ const c = v.vmap();
387
+ v.set(c, "ref", v.vstr(r));
388
+ v.set(c, "pos", v.vnum(tinst.pos));
389
+ v.set(c, "provides", p);
390
+ v.push(cands, c);
391
+ }
392
+ }
393
+ }
394
+ return cap.resolvecapability(req, cands);
395
+ }
396
+
397
+ fn unmetof(h: *Host, e: *Inst) *v.Value {
398
+ const out = v.vlist();
399
+ for (v.items(dep.requirements(e.options))) |r| {
400
+ if (!dep.gatesactivation(r)) continue;
401
+ if (v.len(providersof(h, r)) == 0) v.push(out, v.get(r, "name"));
402
+ }
403
+ return out;
404
+ }
405
+
406
+ /// §11.4's always-reluctant selection, and the ONE place a provider is
407
+ /// chosen for a live instance. "A satisfied requirement is not re-bound
408
+ /// while it stays satisfied" is a statement about a REMEMBERED choice.
409
+ ///
410
+ /// `remember` is false for the questions asked ABOUT an instance rather
411
+ /// than BY it — introspection must not create a binding.
412
+ fn chosen(h: *Host, e: *Inst, req: ?*v.Value, remember: bool) ?[]const u8 {
413
+ const cands = providersof(h, req);
414
+ if (v.len(cands) == 0) return null;
415
+ const name = v.asStr(v.get(req, "name"));
416
+ const heldv = v.get(e.selected, name);
417
+ if (v.isStr(heldv)) {
418
+ for (v.items(cands)) |c| {
419
+ if (std.mem.eql(u8, v.asStr(v.get(c, "ref")), v.asStr(heldv))) return v.asStr(heldv);
420
+ }
421
+ }
422
+ const first = v.asStr(v.get(v.at(cands, 0), "ref"));
423
+ if (remember) v.set(e.selected, name, v.vstr(first));
424
+ return first;
425
+ }
426
+
427
+ /// The instance currently SELECTED for each of this one's
428
+ /// restart-causing requirements. A BINDING IS TO AN INSTANCE, not to a
429
+ /// capability (§11.1): the selected one going away restarts a `static`
430
+ /// consumer even though a survivor is available.
431
+ fn boundproviders(h: *Host, e: *Inst) [][]const u8 {
432
+ var out = v.List([]const u8).init(v.arena());
433
+ for (v.items(dep.requirements(e.options))) |r| {
434
+ if (!dep.restartsonloss(r)) continue;
435
+ const p = chosen(h, e, r, false) orelse continue;
436
+ var dup = false;
437
+ for (out.items) |x| {
438
+ if (std.mem.eql(u8, x, p)) {
439
+ dup = true;
440
+ break;
441
+ }
442
+ }
443
+ if (!dup) out.append(p) catch @panic("oom");
444
+ }
445
+ return out.items;
446
+ }
447
+
448
+ fn consumersof(h: *Host, r: []const u8) [][]const u8 {
449
+ var out = v.List([]const u8).init(v.arena());
450
+ for (sortedrefs(h)) |c| {
451
+ if (std.mem.eql(u8, c, r)) continue;
452
+ const ci = find(h, c) orelse continue;
453
+ if (!std.mem.eql(u8, ci.status, "live")) continue;
454
+ for (boundproviders(h, ci)) |p| {
455
+ if (std.mem.eql(u8, p, r)) {
456
+ out.append(c) catch @panic("oom");
457
+ break;
458
+ }
459
+ }
460
+ }
461
+ return out.items;
462
+ }
463
+
464
+ /// §11.3's `hold` asks a DIFFERENT question from the cascade.
465
+ ///
466
+ /// The cascade wants the edges that RESTART — mandatory-static and
467
+ /// optional-static. `hold` says "deactivating a REQUIRED instance is
468
+ /// `plugin_dependency_held`", and `required` is CARDINALITY:
469
+ /// `gatesactivation`, not `restartsonloss`. The two sets differ in both
470
+ /// directions and each difference was a real bug.
471
+ fn holdersof(h: *Host, r: []const u8) [][]const u8 {
472
+ var out = v.List([]const u8).init(v.arena());
473
+ for (sortedrefs(h)) |c| {
474
+ if (std.mem.eql(u8, c, r)) continue;
475
+ const ci = find(h, c) orelse continue;
476
+ if (!std.mem.eql(u8, ci.status, "live")) continue;
477
+ for (v.items(dep.requirements(ci.options))) |req| {
478
+ if (!dep.gatesactivation(req)) continue;
479
+ const sel = chosen(h, ci, req, false) orelse continue;
480
+ if (std.mem.eql(u8, sel, r)) {
481
+ out.append(c) catch @panic("oom");
482
+ break;
483
+ }
484
+ }
485
+ }
486
+ return out.items;
487
+ }
488
+
489
+ /// The hold check is A GUARD ON AD-HOC DEACTIVATION, NOT ON COORDINATED
490
+ /// TEARDOWN. In a bulk operation that is removing the holders too, it is
491
+ /// suspended — otherwise `close()` under `hold` would raise on the first
492
+ /// provider it reached whenever a document happened to list a consumer
493
+ /// after it, which is the policy refusing the one teardown it has no
494
+ /// reason to object to.
495
+ fn held(h: *Host, e: *Inst) t.Err!void {
496
+ if (!std.mem.eql(u8, h.dependency, "hold")) return;
497
+ if (h.coordinated) return;
498
+ const holders = holdersof(h, e.ref);
499
+ if (holders.len == 0) return;
500
+ const list_ = v.vlist();
501
+ for (holders) |x| v.push(list_, v.vstr(x));
502
+ const d = v.vmap();
503
+ v.set(d, "ref", v.vstr(e.ref));
504
+ v.set(d, "holders", list_);
505
+ return t.fail("plugin_dependency_held", v.print("instance is required by live consumers: {s}", .{e.ref}), d);
506
+ }
507
+
508
+ /// The requirement graph as plain data, for the pure detector.
509
+ fn graphnodes(h: *Host) *v.Value {
510
+ const out = v.vlist();
511
+ for (sortedrefs(h)) |r| {
512
+ const e = find(h, r) orelse continue;
513
+ const provs = v.vlist();
514
+ for (v.items(e.provides)) |p| v.push(provs, v.get(p, "name"));
515
+ const node = v.vmap();
516
+ v.set(node, "ref", v.vstr(r));
517
+ v.set(node, "provides", provs);
518
+ v.set(node, "requires", dep.requirements(e.options));
519
+ v.push(out, node);
520
+ }
521
+ return out;
522
+ }
523
+
524
+ // ---------------------------------------------------------------------
525
+ // ordering and points
526
+ // ---------------------------------------------------------------------
527
+
528
+ fn lessSeq(_: void, a: *Inst, b: *Inst) bool {
529
+ return a.seq < b.seq;
530
+ }
531
+
532
+ pub fn order(h: *Host, pt: []const u8) t.Err!*v.Value {
533
+ // Sorted by declaration SEQUENCE, which is what makes the §7 sort's
534
+ // fall-through deterministic in a language whose containers have no
535
+ // insertion order. §7 breaks ties by `pos`; two instances CAN share
536
+ // one — `declare` defaults `pos` to the registry size, so an unload
537
+ // followed by a fresh declare reuses a surviving instance's — and
538
+ // past that the canonical was falling through to map order. `seq` is
539
+ // that order, made explicit. Found by review of the go port.
540
+ var live = v.List(*Inst).init(v.arena());
541
+ for (h.instances.items) |e| {
542
+ if (std.mem.eql(u8, e.status, "live")) live.append(e) catch @panic("oom");
543
+ }
544
+ std.mem.sort(*Inst, live.items, {}, lessSeq);
545
+
546
+ const bindings = v.vlist();
547
+ for (live.items) |e| {
548
+ const b = v.vmap();
549
+ v.set(b, "ref", v.vstr(e.ref));
550
+ v.set(b, "pos", v.vnum(e.pos));
551
+ if (!v.isNull(e.order)) v.set(b, "order", e.order);
552
+ v.push(bindings, b);
553
+ }
554
+
555
+ const spec = if (pt.len == 0) v.vnull() else v.get(h.points, pt);
556
+ return ord.resolveorder(bindings, if (v.isMap(spec)) v.get(spec, "pin") else null);
557
+ }
558
+
559
+ pub fn positionof(h: *Host, r0: []const u8, pt: []const u8) t.Err!*v.Value {
560
+ const ranked = try order(h, pt);
561
+ const r = try ref.canonrefs(r0);
562
+ var index: f64 = -1;
563
+ for (v.items(ranked), 0..) |x, i| {
564
+ if (std.mem.eql(u8, v.asStr(x), r)) {
565
+ index = @floatFromInt(i);
566
+ break;
567
+ }
568
+ }
569
+ const out = v.vmap();
570
+ v.set(out, "index", v.vnum(index));
571
+ v.set(out, "count", v.vnum(@floatFromInt(v.len(ranked))));
572
+ // §6.2 composes b1(b2(b3(base))) with the FIRST binding OUTERMOST,
573
+ // so these are not index 0 and count-1 the other way round. Getting
574
+ // this backwards is the exact error the positional pin vocabulary
575
+ // exists to prevent.
576
+ v.set(out, "outermost", v.vbool(index == 0));
577
+ v.set(out, "innermost", v.vbool(index == @as(f64, @floatFromInt(v.len(ranked))) - 1));
578
+ return out;
579
+ }
580
+
581
+ pub fn position(e: *Inst, pt: []const u8) t.Err!*v.Value {
582
+ return positionof(e.owner, e.ref, pt);
583
+ }
584
+
585
+ /// Live bindings on a point, in resolved order. Recomputed on any change
586
+ /// to the live set (§7) rather than cached at startup — the bug a host
587
+ /// discovers only when something deactivates in production.
588
+ fn boundon(h: *Host, pt: []const u8) t.Err![]point.Bound {
589
+ const ranked = try order(h, pt);
590
+ var out = v.List(point.Bound).init(v.arena());
591
+ for (v.items(ranked)) |rv| {
592
+ const e = find(h, v.asStr(rv)) orelse continue;
593
+ // The band is the INSTANCE's ordering block (§7), stamped by the
594
+ // host. A plugin passing its own would be ranking itself above
595
+ // the order its document declared.
596
+ const band = v.get(e.order, "band");
597
+ const bandv: f64 = if (v.isNum(band)) v.asNum(band) else 0;
598
+ for (e.bindings.items) |b| {
599
+ if (!std.mem.eql(u8, b.point, pt)) continue;
600
+ var copy = b;
601
+ copy.band = bandv;
602
+ out.append(copy) catch @panic("oom");
603
+ }
604
+ }
605
+ return out.items;
606
+ }
607
+
608
+ fn pointspec(h: *Host, pt: []const u8) t.Err!*v.Value {
609
+ if (!v.has(h.points, pt)) {
610
+ return t.fail("plugin_point_unknown", v.print("no such point: {s}", .{pt}), t.details1("point", v.vstr(pt)));
611
+ }
612
+ const spec = v.get(h.points, pt);
613
+ return if (v.isMap(spec)) spec else v.vmap();
614
+ }
615
+
616
+ fn checkkind(spec: ?*v.Value, pt: []const u8, want: []const u8) t.Err!void {
617
+ const kind = v.get(spec, "kind");
618
+ const given = v.isStr(kind);
619
+ const ok = if (given) std.mem.eql(u8, v.asStr(kind), want) else std.mem.eql(u8, want, "hook");
620
+ if (ok) return;
621
+ const d = v.vmap();
622
+ v.set(d, "point", v.vstr(pt));
623
+ v.set(d, "kind", if (given) kind else v.vnull());
624
+ return t.fail("plugin_point_kind", v.print("point is not a {s}: {s}", .{ want, pt }), d);
625
+ }
626
+
627
+ pub fn emit(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
628
+ const spec = try pointspec(h, pt);
629
+ try checkkind(spec, pt, "hook");
630
+ const bindings = try boundon(h, pt);
631
+ const mode = v.get(spec, "mode");
632
+ const m = if (v.isStr(mode)) v.asStr(mode) else "emit";
633
+ const res = try point.pointemit(bindings, m, arg);
634
+ if (std.mem.eql(u8, m, "emit")) return null;
635
+ if (std.mem.eql(u8, m, "bail")) return res.value;
636
+ return res.errors;
637
+ }
638
+
639
+ pub fn call(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
640
+ const spec = try pointspec(h, pt);
641
+ try checkkind(spec, pt, "chain");
642
+ const bindings = try boundon(h, pt);
643
+ // The host owns the base and a plugin cannot replace it (§6.2). One
644
+ // that wants to SUBSTITUTE rather than wrap binds innermost and
645
+ // simply does not call `next`.
646
+ for (h.bases) |b| {
647
+ if (std.mem.eql(u8, b.point, pt)) return point.pointcall(bindings, b.func, null, arg);
648
+ }
649
+ return point.pointcall(bindings, null, null, arg);
650
+ }
651
+
652
+ pub fn provider(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
653
+ const spec = try pointspec(h, pt);
654
+ try checkkind(spec, pt, "provider");
655
+ const bindings = try boundon(h, pt);
656
+ const res = try point.pointprovider(bindings, v.truthy(v.get(spec, "exclusive")));
657
+ const w = res.winner orelse return v.get(spec, "default");
658
+ return w.hook.?(arg, w.ctx);
659
+ }
660
+
661
+ pub fn shadowed(h: *Host, pt: []const u8) t.Err!*v.Value {
662
+ if (!v.has(h.points, pt)) return v.vlist();
663
+ const spec = v.get(h.points, pt);
664
+ const bindings = try boundon(h, pt);
665
+ const res = try point.pointprovider(bindings, v.isMap(spec) and v.truthy(v.get(spec, "exclusive")));
666
+ return res.shadowed;
667
+ }
668
+
669
+ pub fn exports(h: *Host, spec: []const u8) t.Err!?*v.Value {
670
+ const all = v.vlist();
671
+ for (sortedrefs(h)) |r| {
672
+ const e = find(h, r) orelse continue;
673
+ // Exports of a `loaded` (not live) instance are VISIBLE (§11).
674
+ if (std.mem.eql(u8, e.status, "declared") or std.mem.eql(u8, e.status, "failed")) continue;
675
+ for (v.keys(e.exports)) |k| {
676
+ const ex = v.vmap();
677
+ v.set(ex, "ref", v.vstr(r));
678
+ v.set(ex, "key", v.vstr(k));
679
+ v.set(ex, "value", v.get(e.exports, k));
680
+ v.push(all, ex);
681
+ }
682
+ }
683
+ return exp.resolveexport(v.vstr(spec), all);
684
+ }
685
+
686
+ pub fn capability(h: *Host, name: []const u8) *v.Value {
687
+ const cands = v.vlist();
688
+ for (sortedrefs(h)) |r| {
689
+ const e = find(h, r) orelse continue;
690
+ if (!std.mem.eql(u8, e.status, "live")) continue;
691
+ for (v.items(e.provides)) |p| {
692
+ if (v.isStr(v.get(p, "name")) and std.mem.eql(u8, v.asStr(v.get(p, "name")), name)) {
693
+ const c = v.vmap();
694
+ v.set(c, "ref", v.vstr(r));
695
+ v.set(c, "pos", v.vnum(e.pos));
696
+ v.set(c, "provides", p);
697
+ v.push(cands, c);
698
+ }
699
+ }
700
+ }
701
+ const req = v.vmap();
702
+ v.set(req, "name", v.vstr(name));
703
+ const ranked = cap.resolvecapability(req, cands);
704
+ const out = v.vlist();
705
+ for (v.items(ranked)) |c| v.push(out, v.get(c, "ref"));
706
+ return out;
707
+ }
708
+
709
+ // ---------------------------------------------------------------------
710
+ // the state machine
711
+ // ---------------------------------------------------------------------
712
+
713
+ /// AUTO-TAGGING IS EXPLICIT (§4 rule 3): the LOWEST UNUSED POSITIVE
714
+ /// INTEGER tag. It needs a host because it must know what is already
715
+ /// declared, which is why it cannot live in the pure `ref` section.
716
+ pub fn autotag(h: *Host, name: []const u8) t.Err![]const u8 {
717
+ var n: i32 = 1;
718
+ while (true) : (n += 1) {
719
+ const cand = try ref.formatref(v.vstr(name), v.vstr(v.print("{d}", .{n})));
720
+ if (find(h, cand) == null) return cand;
721
+ }
722
+ }
723
+
724
+ pub fn declare(h: *Host, r0: []const u8, spec: DeclareSpec) t.Err!*Inst {
725
+ const r = if (std.mem.eql(u8, spec.tag, "?"))
726
+ try autotag(h, ref.refname(try ref.canonrefs(r0)))
727
+ else
728
+ try ref.canonrefs(r0);
729
+
730
+ if (!spec.hostowned) try checkreserved(h, r);
731
+
732
+ const defname = if (spec.definition.len == 0) ref.refname(r) else spec.definition;
733
+ const def = h.catalog.get(defname) orelse
734
+ return t.fail("plugin_unknown_definition", v.print("not in catalog: {s}", .{defname}), t.details1("name", v.vstr(defname)));
735
+
736
+ if (find(h, r)) |existing| {
737
+ // §4 rule 1: a pair addresses at most one instance. Re-declaring
738
+ // the SAME definition is the idempotent case; a different one is
739
+ // a duplicate, not a silent overwrite (seneca) and not an
740
+ // impossibility (sdkgen).
741
+ if (!std.mem.eql(u8, existing.def.name, def.name)) {
742
+ return t.fail("plugin_ref_duplicate", v.print("instance already declared: {s}", .{r}), t.details1("ref", v.vstr(r)));
743
+ }
744
+ return existing;
745
+ }
746
+
747
+ const e = v.arena().create(Inst) catch @panic("oom");
748
+ e.* = .{
749
+ .ref = v.dupe(r),
750
+ .def = def,
751
+ .status = "declared",
752
+ .pos = spec.pos orelse @floatFromInt(h.instances.items.len),
753
+ .seq = h.seqn,
754
+ // NO OPTIONS ADOPTED HERE. `apply` resolves options and hands
755
+ // the map over; adopting the caller's map made target and source
756
+ // THE SAME MAP in the refill that follows, which cleared its own
757
+ // source and left a first-time instance with no options at all.
758
+ .options = if (v.isMap(spec.options)) spec.options.? else v.vmap(),
759
+ .state = v.vmap(),
760
+ .order = spec.order,
761
+ .selected = v.vmap(),
762
+ .unmet = v.vlist(),
763
+ .scope = v.List(*ScopeEntry).init(v.arena()),
764
+ .bindings = v.List(point.Bound).init(v.arena()),
765
+ .exports = v.vmap(),
766
+ .provides = v.vlist(),
767
+ .owner = h,
768
+ };
769
+ h.seqn += 1;
770
+ h.instances.append(e) catch @panic("oom");
771
+ return e;
772
+ }
773
+
774
+ pub fn load(h: *Host, r: []const u8, spec: DeclareSpec) t.Err!*Inst {
775
+ try guard(h);
776
+ const e = try declare(h, r, spec);
777
+ if (!std.mem.eql(u8, e.status, "declared")) return e; // idempotent
778
+ // PRESENT AND NOT NULL, not merely present. Every driver builds its
779
+ // command spec with all four keys and a null for each absent one, so
780
+ // a presence test reads an omitted `options` as an authored empty
781
+ // and wipes the real ones.
782
+ if (v.isMap(spec.options)) e.options = spec.options.?;
783
+
784
+ run(h, e, "define") catch {
785
+ e.status = "failed";
786
+ return error.Plugin;
787
+ };
788
+ e.status = "loaded";
789
+
790
+ // AT LOAD, and before anything runs: a cycle through restart-causing
791
+ // requirements does not settle, and the only safe time to report a
792
+ // non-terminating reconcile is before it starts (§11.3). `provides`
793
+ // is populated by `define`, which has just run, so this is the first
794
+ // moment the graph is complete.
795
+ dep.checkcycle(graphnodes(h)) catch {
796
+ e.status = "failed";
797
+ return error.Plugin;
798
+ };
799
+ return e;
800
+ }
801
+
802
+ /// CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (§11.3).
803
+ ///
804
+ /// The cascade is part of the provider's own deactivation and runs
805
+ /// BEFORE the provider's `deactivate` callback and scope unwind, so a
806
+ /// consumer's teardown can still call the thing it depends on — flushing
807
+ /// a buffer to the store it is about to lose is exactly what a
808
+ /// `deactivate` callback is for.
809
+ fn cascade(h: *Host, prov: *Inst, seen: *v.Value) void {
810
+ if (v.has(seen, prov.ref)) return;
811
+ v.set(seen, prov.ref, v.vbool(true));
812
+
813
+ for (consumersof(h, prov.ref)) |cref| {
814
+ const c = find(h, cref) orelse continue;
815
+ if (!std.mem.eql(u8, c.status, "live")) continue;
816
+ cascade(h, c, seen); // deepest-first
817
+ var bad = false;
818
+ run(h, c, "deactivate") catch {
819
+ _ = t.take();
820
+ bad = true;
821
+ };
822
+ const errors = unwind(h, c);
823
+ if (bad or v.len(errors) > 0) {
824
+ // §5.2: ANY failure during a transition lands the instance
825
+ // in `failed`, and a cascaded consumer is not an exception.
826
+ // Marking it `pending` instead handed it straight back to
827
+ // `reconcile`, which would activate it again the moment the
828
+ // provider returned — the one thing `failed` exists to stop.
829
+ c.status = "failed";
830
+ continue;
831
+ }
832
+ c.status = "pending";
833
+ c.unmet = unmetof(h, c);
834
+ }
835
+ }
836
+
837
+ pub fn activate(h: *Host, r: []const u8) t.Err!*Inst {
838
+ try guard(h);
839
+ const e = try need(h, r);
840
+ if (std.mem.eql(u8, e.status, "live")) return e; // no-op returning success
841
+ if (std.mem.eql(u8, e.status, "failed")) {
842
+ return t.fail("plugin_bad_state", v.print("instance has failed: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
843
+ }
844
+ // §9.6: `active: false` bars the instance from running, and the bar
845
+ // is on the INSTANCE rather than on the apply that set it. `ready`
846
+ // reaches this through `activate`, which is why one guard covers
847
+ // both verbs the design names.
848
+ if (e.barred) {
849
+ return t.fail("plugin_inactive", v.print("instance is barred by active: false: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
850
+ }
851
+ if (std.mem.eql(u8, e.status, "declared")) _ = try load(h, e.ref, .{});
852
+
853
+ // A declared requirement that is not live means `pending`:
854
+ // activation is a STANDING REQUEST, not a one-shot event.
855
+ const unmet = unmetof(h, e);
856
+ if (v.len(unmet) > 0) {
857
+ e.unmet = unmet;
858
+ e.status = "pending";
859
+ return e;
860
+ }
861
+
862
+ run(h, e, "activate") catch {
863
+ // Unwind whatever the partial activation captured, in reverse.
864
+ const err = t.take();
865
+ _ = unwind(h, e);
866
+ e.status = "failed";
867
+ return t.reraise(err);
868
+ };
869
+
870
+ // §11.4: THE SELECTION IS MADE HERE, once, and remembered. Every
871
+ // later question — the cascade, `hold`, `unmet` — reads it back
872
+ // rather than re-ranking, which is what "always-reluctant" means.
873
+ for (v.items(dep.requirements(e.options))) |req| _ = chosen(h, e, req, true);
874
+ e.status = "live";
875
+ reconcile(h);
876
+ return e;
877
+ }
878
+
879
+ pub fn deactivate(h: *Host, r: []const u8) t.Err!*Inst {
880
+ try guard(h);
881
+ const e = try need(h, r);
882
+ if (std.mem.eql(u8, e.status, "loaded") or std.mem.eql(u8, e.status, "declared")) return e;
883
+
884
+ // §5.2: `unload` is THE ONLY TRANSITION OUT OF `failed`. Falling
885
+ // through here ran the definition's `deactivate` on an instance that
886
+ // never completed activation and, if that callback happened to
887
+ // succeed, returned it to `loaded` — from where it could be
888
+ // activated again, which is precisely what `failed` exists to
889
+ // prevent.
890
+ if (std.mem.eql(u8, e.status, "failed")) {
891
+ return t.fail("plugin_bad_state", v.print("instance has failed: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
892
+ }
893
+
894
+ if (std.mem.eql(u8, e.status, "pending")) {
895
+ // DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (§5.2). It
896
+ // never reached activate, so it holds no scope and no live
897
+ // bindings; running the definition's deactivate there would be
898
+ // teardown without matching setup. It cannot fail.
899
+ e.status = "loaded";
900
+ e.unmet = v.vlist();
901
+ return e;
902
+ }
903
+
904
+ try held(h, e);
905
+ cascade(h, e, v.vmap());
906
+
907
+ run(h, e, "deactivate") catch {
908
+ const err = t.take();
909
+ _ = unwind(h, e);
910
+ e.status = "failed";
911
+ return t.reraise(err);
912
+ };
913
+ try releasecheck(e, unwind(h, e));
914
+ e.status = "loaded";
915
+ reconcile(h);
916
+ return e;
917
+ }
918
+
919
+ fn removeinst(h: *Host, e: *Inst) void {
920
+ for (h.instances.items, 0..) |x, i| {
921
+ if (x == e) {
922
+ _ = h.instances.orderedRemove(i);
923
+ return;
924
+ }
925
+ }
926
+ }
927
+
928
+ pub fn unload(h: *Host, r: []const u8) t.Err!void {
929
+ try guard(h);
930
+ const e = try need(h, r);
931
+ if (std.mem.eql(u8, e.status, "live") or std.mem.eql(u8, e.status, "pending")) {
932
+ if (std.mem.eql(u8, e.status, "live")) {
933
+ try held(h, e);
934
+ cascade(h, e, v.vmap());
935
+ run(h, e, "deactivate") catch {
936
+ // §5.2: ANY failure during a transition lands the
937
+ // instance in `failed`, with the scope STILL FULLY
938
+ // UNWOUND. An earlier draft let the raise propagate
939
+ // straight out of `unload`, which left the instance
940
+ // `live` and its scope untouched — reporting a failure
941
+ // while leaking exactly the resources the failure was
942
+ // about.
943
+ const err = t.take();
944
+ _ = unwind(h, e);
945
+ e.status = "failed";
946
+ return t.reraise(err);
947
+ };
948
+ try releasecheck(e, unwind(h, e));
949
+ }
950
+ e.status = "loaded";
951
+ }
952
+ if (std.mem.eql(u8, e.status, "loaded") or std.mem.eql(u8, e.status, "failed")) {
953
+ run(h, e, "close") catch {
954
+ const err = t.take();
955
+ removeinst(h, e);
956
+ return t.reraise(err);
957
+ };
958
+ }
959
+ removeinst(h, e);
960
+ }
961
+
962
+ pub fn ready(h: *Host, r0: []const u8) t.Err!*Inst {
963
+ // Runs the whole forward path in one call (§5.1). §15.2's verb list
964
+ // omits this; §5.1 defines it and §15.3's `declare` row requires the
965
+ // corpus to pin it, so the list was incomplete rather than excluding
966
+ // it (DOCS.md §4.2).
967
+ try guard(h);
968
+ const r = try ref.canonrefs(r0);
969
+ if (find(h, r) == null) _ = try declare(h, r, .{});
970
+ if (find(h, r)) |e| {
971
+ if (std.mem.eql(u8, e.status, "declared")) _ = try load(h, r, .{});
972
+ }
973
+ return activate(h, r);
974
+ }
975
+
976
+ /// EAGER reconciliation: run to a fixed point rather than scheduling.
977
+ ///
978
+ /// Two directions, and both are the reason `pending` exists. Activation
979
+ /// is a STANDING REQUEST, not a one-shot event: a pending instance whose
980
+ /// requirement arrives activates without being asked again, and a LIVE
981
+ /// instance whose requirement is lost goes back to pending —
982
+ /// recursively, through its own consumers.
983
+ fn reconcile(h: *Host) void {
984
+ var moved = true;
985
+ var rounds: i32 = 0;
986
+ while (moved) {
987
+ moved = false;
988
+ rounds += 1;
989
+ if (rounds > 1000) break;
990
+
991
+ // Losses first, so a cascade settles in one pass rather than
992
+ // alternating with re-activations.
993
+ for (sortedrefs(h)) |r| {
994
+ const e = find(h, r) orelse continue;
995
+ if (!std.mem.eql(u8, e.status, "live")) continue;
996
+ const lost = v.vlist();
997
+ for (v.items(dep.requirements(e.options))) |q| {
998
+ if (!dep.gatesactivation(q)) continue;
999
+ if (v.len(providersof(h, q)) == 0) v.push(lost, q);
1000
+ }
1001
+ if (v.len(lost) == 0) continue;
1002
+ // POLICY IS PER REQUIREMENT, not per instance (§11.3): only
1003
+ // the definition that has the requirement knows what it can
1004
+ // cope with, and one instance may hold both a `static` and a
1005
+ // `dynamic` one. A `dynamic` requirement whose provider is
1006
+ // gone leaves the consumer LIVE and notified.
1007
+ var anyrestart = false;
1008
+ for (v.items(lost)) |q| {
1009
+ if (dep.restartsonloss(q)) {
1010
+ anyrestart = true;
1011
+ break;
1012
+ }
1013
+ }
1014
+ if (!anyrestart) continue;
1015
+
1016
+ var bad = false;
1017
+ run(h, e, "deactivate") catch {
1018
+ _ = t.take();
1019
+ bad = true;
1020
+ };
1021
+ const errors = unwind(h, e);
1022
+ if (bad or v.len(errors) > 0) {
1023
+ e.status = "failed";
1024
+ } else {
1025
+ e.status = "pending";
1026
+ e.unmet = unmetof(h, e);
1027
+ }
1028
+ moved = true;
1029
+ }
1030
+
1031
+ for (sortedrefs(h)) |r| {
1032
+ const e = find(h, r) orelse continue;
1033
+ if (!std.mem.eql(u8, e.status, "pending")) continue;
1034
+ if (v.len(unmetof(h, e)) > 0) continue;
1035
+ run(h, e, "activate") catch {
1036
+ _ = t.take();
1037
+ _ = unwind(h, e);
1038
+ e.status = "failed";
1039
+ moved = true;
1040
+ continue;
1041
+ };
1042
+ for (v.items(dep.requirements(e.options))) |req| _ = chosen(h, e, req, true);
1043
+ e.status = "live";
1044
+ e.unmet = v.vlist();
1045
+ moved = true;
1046
+ }
1047
+ }
1048
+ }
1049
+
1050
+ fn lessDropOrder(h: *Host, a: []const u8, b: []const u8) bool {
1051
+ const x = find(h, a) orelse return false;
1052
+ const y = find(h, b) orelse return false;
1053
+ // Reverse load order: highest `pos` first, ref-descending for a tie,
1054
+ // so a consumer declared after its provider goes down first.
1055
+ if (x.pos != y.pos) return x.pos > y.pos;
1056
+ return std.mem.order(u8, a, b) == .gt;
1057
+ }
1058
+
1059
+ const DropCtx = struct { h: *Host };
1060
+
1061
+ fn lessDrop(ctx: DropCtx, a: []const u8, b: []const u8) bool {
1062
+ return lessDropOrder(ctx.h, a, b);
1063
+ }
1064
+
1065
+ pub fn close(h: *Host) t.Err!void {
1066
+ // A bulk teardown removing the holders too, so `hold` is suspended
1067
+ // for exactly those holders (§11.3) — while the consumers-first
1068
+ // cascade still runs, which is the half that matters.
1069
+ // A COORDINATED FLAG THAT SURVIVES A RAISE IS A DISABLED GUARD. The
1070
+ // canonical wraps the teardown in try/finally; an unload that raises
1071
+ // would skip the reset and leave the host permanently `coordinated`,
1072
+ // so a caller that catches the error and carries on under
1073
+ // `dependency: "hold"` gets ad-hoc deactivation with the holder
1074
+ // check silently off.
1075
+ //
1076
+ // `defer` rather than a catch: the flag is cleared on every exit
1077
+ // from this function, so the raising path is not written twice.
1078
+ h.coordinated = true;
1079
+ defer h.coordinated = false;
1080
+ const refs = v.arena().alloc([]const u8, h.instances.items.len) catch @panic("oom");
1081
+ for (h.instances.items, 0..) |e, i| refs[i] = e.ref;
1082
+ std.mem.sort([]const u8, refs, DropCtx{ .h = h }, lessDrop);
1083
+ for (refs) |r| {
1084
+ if (find(h, r) != null) try unload(h, r);
1085
+ }
1086
+ }
1087
+
1088
+ /// The scope entry carries the inner host as its context — zig's
1089
+ /// stand-in for the closure every other port with closures writes here.
1090
+ fn closeinner(ctx: ?*anyopaque) void {
1091
+ const inner: *Host = @ptrCast(@alignCast(ctx.?));
1092
+ close(inner) catch {
1093
+ release_error = t.take().message;
1094
+ };
1095
+ }
1096
+
1097
+ /// AN INSTANCE MAY ITSELF BE A HOST (§6.5), and THE OUTER ONE OWNS THE
1098
+ /// INNER ONE'S LIFETIME. Registering the teardown in the instance scope
1099
+ /// is what makes that true rather than aspirational: the inner host
1100
+ /// closes when the outer instance deactivates, in the same reverse
1101
+ /// unwind as every other resource.
1102
+ ///
1103
+ /// It does NOT count toward `open` — a teardown is not an acquisition
1104
+ /// (`nest/open`).
1105
+ pub fn nest(e: *Inst, o: HostOptions) t.Err!*Host {
1106
+ if (!e.owner.intransition) {
1107
+ return t.fail("plugin_release_scope", "nest called outside a lifecycle callback", null);
1108
+ }
1109
+ const inner = makehost(o);
1110
+ _ = pushscope(e, closeinner, inner, false);
1111
+ e.inner = inner;
1112
+ return inner;
1113
+ }
1114
+
1115
+ // ---------------------------------------------------------------------
1116
+ // documents
1117
+ // ---------------------------------------------------------------------
1118
+
1119
+ /// Empty the target and refill it, so callers holding the reference see
1120
+ /// the new values. A definition's callbacks close over the options map
1121
+ /// they were handed at `define`; replacing the reference would leave
1122
+ /// every binding reading the values the first apply gave it.
1123
+ fn refill(target: *v.Value, source: ?*v.Value) void {
1124
+ for (v.keys(target)) |k| v.del(target, k);
1125
+ for (v.keys(source)) |k| v.set(target, k, v.get(source, k));
1126
+ }
1127
+
1128
+ fn shapeof(h: *Host, r: []const u8) ?*v.Value {
1129
+ const d = h.catalog.get(ref.refname(r)) orelse return null;
1130
+ return d.shape;
1131
+ }
1132
+
1133
+ fn wantlive(ent: ?*v.Value) bool {
1134
+ return v.isMap(ent) and v.truthy(v.get(ent, "active")) and
1135
+ std.mem.eql(u8, v.asStr(v.get(ent, "start")), "eager");
1136
+ }
1137
+
1138
+ pub fn apply(h: *Host, doc: ?*v.Value, profile: ?*v.Value) t.Err!void {
1139
+ try guard(h);
1140
+ const in = v.vmap();
1141
+ v.set(in, "doc", doc);
1142
+ v.set(in, "profile", if (v.isNull(profile)) h.profile else profile);
1143
+ v.set(in, "keys", h.keys);
1144
+ v.set(in, "reserved", h.reserved);
1145
+ const norm = try cfg.normalizeconfig(in);
1146
+
1147
+ const want = v.get(norm, "order");
1148
+ const optionsof = v.vmap();
1149
+ for (v.items(want)) |rv| {
1150
+ const r = v.asStr(rv);
1151
+ const oin = v.vmap();
1152
+ v.set(oin, "ref", v.vstr(r));
1153
+ v.set(oin, "doc", doc);
1154
+ v.set(oin, "profile", if (v.isNull(profile)) h.profile else profile);
1155
+ v.set(oin, "shape", shapeof(h, r));
1156
+ if (v.isMap(h.defaults)) v.set(oin, "hostdefaults", v.get(h.defaults, ref.refname(r)));
1157
+ v.set(optionsof, r, try cfg.resolveoptions(oin));
1158
+ }
1159
+
1160
+ // --- phase 1: deactivations and unloads, in REVERSE load order ---
1161
+ const instancespec = v.get(norm, "instance");
1162
+ var drop = v.List([]const u8).init(v.arena());
1163
+ for (h.instances.items) |e| {
1164
+ if (std.mem.eql(u8, e.status, "declared")) continue;
1165
+ if (!wantlive(v.get(instancespec, e.ref))) drop.append(e.ref) catch @panic("oom");
1166
+ }
1167
+ std.mem.sort([]const u8, drop.items, DropCtx{ .h = h }, lessDrop);
1168
+ for (drop.items) |r| try unload(h, r);
1169
+
1170
+ // --- phase 2: declare and patch EVERYTHING, in load order --------
1171
+ for (v.items(want)) |rv| {
1172
+ const r = v.asStr(rv);
1173
+ const ent = v.get(instancespec, r);
1174
+ const e = try declare(h, r, .{
1175
+ .order = v.get(ent, "order"),
1176
+ .pos = v.asNum(v.get(ent, "pos")),
1177
+ });
1178
+ // The bar is REASSERTED ON EVERY APPLY, in both directions — a
1179
+ // document that turns the instance back on clears it, which is
1180
+ // the whole point of a config switch.
1181
+ e.barred = !v.truthy(v.get(ent, "active"));
1182
+ refill(e.options, v.get(optionsof, r));
1183
+ e.order = v.get(ent, "order");
1184
+ e.pos = v.asNum(v.get(ent, "pos"));
1185
+ }
1186
+
1187
+ // --- phase 3: loads, then phase 4: activations, in load order ----
1188
+ for (v.items(want)) |rv| {
1189
+ if (wantlive(v.get(instancespec, v.asStr(rv)))) _ = try load(h, v.asStr(rv), .{});
1190
+ }
1191
+ for (v.items(want)) |rv| {
1192
+ if (wantlive(v.get(instancespec, v.asStr(rv)))) _ = try activate(h, v.asStr(rv));
1193
+ }
1194
+ }
1195
+
1196
+ pub fn setoptions(h: *Host, r: []const u8, patch: ?*v.Value) t.Err!void {
1197
+ try guard(h);
1198
+ const e = try need(h, r);
1199
+ const previous = v.clone(e.options);
1200
+ const in = v.vmap();
1201
+ v.set(in, "ref", v.vstr(e.ref));
1202
+ v.set(in, "shape", shapeof(h, e.ref));
1203
+ v.set(in, "doc", v.vmap());
1204
+ v.set(in, "patch", t.mergeValue(previous, patch));
1205
+ refill(e.options, try cfg.resolveoptions(in));
1206
+
1207
+ if (!std.mem.eql(u8, e.status, "live")) return;
1208
+ if (e.def.reconfigure) |f| {
1209
+ h.intransition = true;
1210
+ h.phase = "reconfigure";
1211
+ f(e, e.options, previous) catch {
1212
+ h.intransition = false;
1213
+ h.phase = "";
1214
+ return error.Plugin;
1215
+ };
1216
+ h.intransition = false;
1217
+ h.phase = "";
1218
+ return;
1219
+ }
1220
+ // Always correct and sometimes expensive; `reconfigure` exists to
1221
+ // make the common case cheap (§9.4).
1222
+ _ = try deactivate(h, e.ref);
1223
+ _ = try activate(h, e.ref);
1224
+ }