@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.
- package/bin/voxgig-sdkgen +1 -1
- package/package.json +1 -1
- package/project/.sdk/model/feature/secrets.aon +330 -0
- package/project/.sdk/model/target/c.aon +15 -2
- package/project/.sdk/model/target/cpp.aon +18 -0
- package/project/.sdk/model/target/lua.aon +17 -0
- package/project/.sdk/model/target/ocaml.aon +48 -5
- package/project/.sdk/model/target/zig.aon +30 -4
- package/project/.sdk/src/cmp/c/Config_c.ts +338 -1
- package/project/.sdk/src/cmp/c/Main_c.ts +57 -2
- package/project/.sdk/src/cmp/c/Package_c.ts +12 -2
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +324 -2
- package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +2 -0
- package/project/.sdk/src/cmp/cpp/Main_cpp.ts +62 -4
- package/project/.sdk/src/cmp/cpp/Package_cpp.ts +10 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +88 -0
- package/project/.sdk/src/cmp/lua/Gitignore_lua.ts +4 -0
- package/project/.sdk/src/cmp/lua/Main_lua.ts +93 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +60 -0
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +10 -0
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +183 -5
- package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +160 -3
- package/project/.sdk/src/cmp/ocaml/Package_ocaml.ts +25 -1
- package/project/.sdk/src/cmp/zig/Config_zig.ts +130 -9
- package/project/.sdk/src/cmp/zig/Main_zig.ts +208 -4
- package/project/.sdk/{tm/zig/build.zig → src/cmp/zig/fragment/Build.fragment.zig} +7 -0
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +25 -0
- package/project/.sdk/{tm/zig/root.zig → src/cmp/zig/fragment/Root.fragment.zig} +9 -0
- package/project/.sdk/tm/c/Makefile +58 -9
- package/project/.sdk/tm/c/core/sdk.h +10 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/capability.c +133 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/capability.h +39 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/catalog.c +83 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/catalog.h +48 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/config.c +413 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/config.h +24 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/depend.c +264 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/depend.h +29 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/env.c +220 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/env.h +19 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/export.c +97 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/export.h +19 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/graph.c +237 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/graph.h +17 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/host.c +1494 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/host.h +135 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/order.c +288 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/order.h +18 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/point.c +141 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/point.h +80 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/ref.c +170 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/ref.h +52 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/resolve.c +98 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/resolve.h +18 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/types.c +150 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/types.h +104 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/value.c +649 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/value.h +135 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/version.c +151 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/version.h +34 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/aws.c +281 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/azuresecrets.c +207 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/boru.c +164 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/clock.c +75 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/doppler.c +141 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/encode.c +144 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/gcpsecrets.c +177 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/hashicorp.c +239 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/httpjson.c +599 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/infisical.c +165 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/onepassword.c +194 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/proc.c +233 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/secretspec.c +125 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sekretoplugins.h +125 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sha256.c +270 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sigv4.c +382 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/support.h +153 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/tls.c +420 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/internal.h +86 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/json.c +721 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/providers.c +813 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.c +944 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.h +490 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/util.c +442 -0
- package/project/.sdk/tm/c/feature/secrets.c +797 -0
- package/project/.sdk/tm/c/feature/secrets.h +46 -0
- package/project/.sdk/tm/c/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/c/tests/feature/secrets/secrets_test.c +802 -0
- package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +38 -11
- package/project/.sdk/tm/clojure/test/sdk/test/feature/secrets.clj +40 -6
- package/project/.sdk/tm/cpp/Makefile +48 -4
- package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.cpp +121 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.hpp +41 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.cpp +60 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.hpp +66 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/config.cpp +376 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/config.hpp +29 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.cpp +230 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.hpp +31 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/env.cpp +205 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/env.hpp +25 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/export.cpp +84 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/export.hpp +24 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.cpp +222 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.hpp +21 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/host.cpp +1200 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/host.hpp +250 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/order.cpp +250 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/order.hpp +22 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/point.cpp +110 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/point.hpp +79 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.cpp +136 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.hpp +60 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.cpp +82 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.hpp +25 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/types.cpp +90 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/types.hpp +65 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/value.cpp +491 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/value.hpp +120 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/version.cpp +143 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/version.hpp +36 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.cpp +248 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.hpp +30 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.cpp +149 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.cpp +117 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.hpp +27 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.cpp +180 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.hpp +52 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.cpp +87 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.cpp +121 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.cpp +153 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.cpp +666 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.hpp +160 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.cpp +123 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.cpp +125 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.cpp +223 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.hpp +47 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.cpp +104 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.hpp +27 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.cpp +242 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.hpp +58 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.cpp +260 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.hpp +47 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.cpp +476 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.hpp +89 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.cpp +312 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.hpp +263 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.cpp +354 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.hpp +111 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.cpp +613 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.hpp +227 -0
- package/project/.sdk/tm/cpp/feature/secrets.hpp +745 -0
- package/project/.sdk/tm/cpp/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/cpp/test/feature/secrets/secrets_test.cpp +808 -0
- package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +34 -8
- package/project/.sdk/tm/csharp/test/feature/secrets/SecretsFeatureTest.cs +85 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +17 -2
- package/project/.sdk/tm/elixir/test/feature/secrets/secrets_test.exs +41 -0
- package/project/.sdk/tm/go/feature/secrets_feature.go +32 -10
- package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +116 -0
- package/project/.sdk/tm/java/feature/SecretsFeature.java +33 -8
- package/project/.sdk/tm/java/test/feature/secrets/SecretsFeatureTest.java +64 -0
- package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +34 -11
- package/project/.sdk/tm/js/test/feature/secrets/Secrets.test.js +73 -0
- package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +32 -7
- package/project/.sdk/tm/kotlin/test/feature/secrets/SecretsTest.kt +69 -0
- package/project/.sdk/tm/lua/Makefile +15 -4
- package/project/.sdk/tm/lua/feature/secrets/native/sekretonet.c +806 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/capability.lua +135 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/catalog.lua +63 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/config.lua +361 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/depend.lua +232 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/env.lua +168 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/export.lua +66 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/graph.lua +194 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/host.lua +1190 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/json.lua +169 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/order.lua +207 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/point.lua +106 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/ref.lua +115 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/resolve.lua +78 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/types.lua +275 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/version.lua +131 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin.lua +76 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/addr.lua +124 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/err.lua +47 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/name.lua +315 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/aws.lua +228 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/azuresecrets.lua +137 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/boru.lua +124 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/crypto.lua +212 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/doppler.lua +89 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/gcpsecrets.lua +129 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/hashicorp.lua +154 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/httpjson.lua +248 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/infisical.lua +113 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/json.lua +449 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/net.lua +198 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/onepassword.lua +126 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/secretspec.lua +93 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/sigv4.lua +269 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/support.lua +146 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/providers.lua +346 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto.lua +479 -0
- package/project/.sdk/tm/lua/feature/secrets_feature.lua +690 -0
- package/project/.sdk/tm/lua/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/lua/test/extend_test.lua +105 -0
- package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +862 -0
- package/project/.sdk/tm/ocaml/Makefile +52 -8
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/capability.ml +106 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/catalog.ml +43 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/config.ml +349 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/defs.ml +143 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/depend.ml +217 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/env.ml +197 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/export.ml +89 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/graph.ml +227 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/host.ml +1112 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/order.ml +202 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/point.ml +138 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/ref.ml +126 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/resolve.ml +62 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/types.ml +97 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/value.ml +387 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/version.ml +139 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/aws.ml +171 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/azuresecrets.ml +116 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/boru.ml +95 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/crypto.ml +149 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/doppler.ml +61 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/gcpsecrets.ml +93 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/hashicorp.ml +120 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/http.ml +421 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/httpjson.ml +66 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/infisical.ml +85 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/onepassword.ml +112 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/runcmd.ml +97 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/secretspec.ml +68 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/sigv4.ml +259 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls.ml +44 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls_stubs.c +358 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/json.ml +376 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/provider.ml +647 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/secret.ml +299 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/sekreto.ml +347 -0
- package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +453 -0
- package/project/.sdk/tm/ocaml/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +670 -0
- package/project/.sdk/tm/perl/feature/secrets_feature.pm +33 -12
- package/project/.sdk/tm/perl/t/feature/secrets/secrets.t +47 -0
- package/project/.sdk/tm/php/feature/SecretsFeature.php +30 -6
- package/project/.sdk/tm/php/test/feature/secrets/SecretsTest.php +98 -0
- package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +28 -6
- package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +114 -0
- package/project/.sdk/tm/rb/feature/secrets_feature.rb +28 -6
- package/project/.sdk/tm/rb/test/feature/secrets/secrets_feature_test.rb +93 -0
- package/project/.sdk/tm/rust/feature/secrets.rs +33 -10
- package/project/.sdk/tm/rust/tests/feature/secrets/main.rs +96 -0
- package/project/.sdk/tm/scala/feature/SecretsFeature.scala +29 -7
- package/project/.sdk/tm/scala/sdktest/feature/secrets/SecretsTestMain.scala +71 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +35 -12
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +73 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/capability.zig +137 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/catalog.zig +90 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/config.zig +346 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/depend.zig +244 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/env.zig +201 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/export.zig +83 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/graph.zig +212 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/host.zig +1224 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/inst.zig +126 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/order.zig +228 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/plugin.zig +34 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/point.zig +166 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/ref.zig +147 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/resolve.zig +74 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/types.zig +140 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/value.zig +662 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/version.zig +139 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/aws.zig +294 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/azuresecrets.zig +222 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/boru.zig +188 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/doppler.zig +135 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/gcpsecrets.zig +170 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/hashicorp.zig +242 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/httpjson.zig +535 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/infisical.zig +167 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/onepassword.zig +202 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/secretspec.zig +160 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/sigv4.zig +336 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/addr.zig +148 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/builtins.zig +259 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/provider.zig +440 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/sekreto.zig +944 -0
- package/project/.sdk/tm/zig/feature/secrets.zig +854 -0
- package/project/.sdk/tm/zig/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/zig/test/feature/secrets/secrets_test.zig +891 -0
- package/project/sdkgen-package.json +1 -1
|
@@ -0,0 +1,1190 @@
|
|
|
1
|
+
-- VENDORED: @voxgig/plugin sdk-20260908-1556-0 (lua/src/plugin/host.lua)
|
|
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 (section 5), extension points
|
|
5
|
+
-- (section 6), and resource capture (section 8).
|
|
6
|
+
--
|
|
7
|
+
-- TWO RULES SHAPE EVERY METHOD BELOW.
|
|
8
|
+
--
|
|
9
|
+
-- Transitions are SEQUENTIAL (section 5.2). One at a time, in call order,
|
|
10
|
+
-- never interleaved; a transition triggered from inside a lifecycle
|
|
11
|
+
-- callback is `plugin_reentrant`. A hard rule, because it is the only way
|
|
12
|
+
-- the semantics can be identical in Go, in Lua and in single-threaded
|
|
13
|
+
-- JavaScript.
|
|
14
|
+
--
|
|
15
|
+
-- Reconciliation is EAGER (section 18's portability budget). A transition
|
|
16
|
+
-- settles by running the state machine to a fixed point, not by suspending
|
|
17
|
+
-- on a promise.
|
|
18
|
+
--
|
|
19
|
+
-- A LUA TABLE HAS NO ORDER. Every walk of the registry here sorts its keys
|
|
20
|
+
-- first: `T.keys` is not tidiness, it is the difference between a
|
|
21
|
+
-- deterministic teardown and one that changes between runs.
|
|
22
|
+
|
|
23
|
+
local T = require 'feature.secrets.plugin.types'
|
|
24
|
+
local R = require 'feature.secrets.plugin.ref'
|
|
25
|
+
local Cat = require 'feature.secrets.plugin.catalog'
|
|
26
|
+
local Ord = require 'feature.secrets.plugin.order'
|
|
27
|
+
local Pt = require 'feature.secrets.plugin.point'
|
|
28
|
+
local Ex = require 'feature.secrets.plugin.export'
|
|
29
|
+
local Cap = require 'feature.secrets.plugin.capability'
|
|
30
|
+
local Cfg = require 'feature.secrets.plugin.config'
|
|
31
|
+
local Dep = require 'feature.secrets.plugin.depend'
|
|
32
|
+
|
|
33
|
+
local M = {}
|
|
34
|
+
|
|
35
|
+
-- ------------------------------------------------------------------
|
|
36
|
+
-- Inst - what a definition's callbacks see
|
|
37
|
+
-- ------------------------------------------------------------------
|
|
38
|
+
--
|
|
39
|
+
-- Deliberately not the internal record: a plugin that could reach `status`
|
|
40
|
+
-- could also write it.
|
|
41
|
+
|
|
42
|
+
local Inst = {}
|
|
43
|
+
Inst.__index = Inst
|
|
44
|
+
M.Inst = Inst
|
|
45
|
+
|
|
46
|
+
function Inst.new(host, entry)
|
|
47
|
+
local parsed = R.parse_ref(entry.ref)
|
|
48
|
+
return setmetatable({
|
|
49
|
+
host = host,
|
|
50
|
+
entry = entry,
|
|
51
|
+
ref = entry.ref,
|
|
52
|
+
name = parsed.name,
|
|
53
|
+
tag = parsed.tag,
|
|
54
|
+
}, Inst)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
-- The resolved options and the instance's own state, both LIVE: a lua
|
|
58
|
+
-- table is a reference, so a callback that keeps one sees what `apply` and
|
|
59
|
+
-- `options` write into it.
|
|
60
|
+
function Inst:options()
|
|
61
|
+
return self.entry.options
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
function Inst:state()
|
|
65
|
+
return self.entry.state
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
-- Foreign resources the host did not hand out are registered explicitly
|
|
69
|
+
-- (section 8.3); host calls are recorded automatically.
|
|
70
|
+
--
|
|
71
|
+
-- SYMMETRIC WITH `acquire`, and it has to be: `open` counts the resources
|
|
72
|
+
-- CURRENTLY HELD, so an entry that is registered and then unwound must
|
|
73
|
+
-- leave the count where it found it.
|
|
74
|
+
function Inst:release(fn)
|
|
75
|
+
-- Section 8.3: "`inst.release` outside `activate` is
|
|
76
|
+
-- `plugin_release_scope`". A flag saying merely that a transition is
|
|
77
|
+
-- running is true in `define` too, and a scope entry registered there is
|
|
78
|
+
-- never unwound.
|
|
79
|
+
if 'activate' ~= self.host.phase then
|
|
80
|
+
T.fail('plugin_release_scope', 'release called outside activate', nil)
|
|
81
|
+
end
|
|
82
|
+
local host = self.host
|
|
83
|
+
local done = false
|
|
84
|
+
table.insert(self.entry.scope, function()
|
|
85
|
+
if done then return end
|
|
86
|
+
done = true
|
|
87
|
+
host.open = host.open - 1
|
|
88
|
+
fn()
|
|
89
|
+
end)
|
|
90
|
+
host.open = host.open + 1
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
-- The synthetic counter the driver owns, so "what is open" is data rather
|
|
94
|
+
-- than an assertion each port words differently.
|
|
95
|
+
--
|
|
96
|
+
-- Returns its own release, so a plugin can hand one back early. The scope
|
|
97
|
+
-- still holds the entry and unwinding it twice is a no-op - releasing
|
|
98
|
+
-- early must not make teardown wrong.
|
|
99
|
+
function Inst:acquire()
|
|
100
|
+
-- Section 8.1: resources are "acquired during `activate` - the scope's
|
|
101
|
+
-- actual job". Same reason as `release` above.
|
|
102
|
+
if 'activate' ~= self.host.phase then
|
|
103
|
+
T.fail('plugin_release_scope', 'acquire called outside activate', nil)
|
|
104
|
+
end
|
|
105
|
+
local host = self.host
|
|
106
|
+
local done = false
|
|
107
|
+
local rel = function()
|
|
108
|
+
if done then return end
|
|
109
|
+
done = true
|
|
110
|
+
host.open = host.open - 1
|
|
111
|
+
end
|
|
112
|
+
table.insert(self.entry.scope, rel)
|
|
113
|
+
host.open = host.open + 1
|
|
114
|
+
return rel
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
-- Bind into a host point. Declared in `define`; the host inserts it only
|
|
118
|
+
-- after `activate` returns successfully (section 8.1), which is why a
|
|
119
|
+
-- failing activate leaves no live binding behind.
|
|
120
|
+
function Inst:bind(point, fn, band)
|
|
121
|
+
-- Section 12 has carried `plugin_bind_scope` - "binding declared outside
|
|
122
|
+
-- `define`" - since before anything raised it. Section 8.1 puts binding
|
|
123
|
+
-- DECLARATION in `define` and INSERTION at a successful activate, and
|
|
124
|
+
-- the guard was the half nobody wrote.
|
|
125
|
+
if 'define' ~= self.host.phase then
|
|
126
|
+
T.fail('plugin_bind_scope', 'bind called outside define: ' .. point,
|
|
127
|
+
T.map { ref = self.ref, point = point })
|
|
128
|
+
end
|
|
129
|
+
if not T.has(self.host.points, point) then
|
|
130
|
+
T.fail('plugin_point_unknown', 'no such point: ' .. point,
|
|
131
|
+
T.map { point = point })
|
|
132
|
+
end
|
|
133
|
+
table.insert(self.entry.bindings, {
|
|
134
|
+
ref = self.ref,
|
|
135
|
+
point = point,
|
|
136
|
+
fn = fn,
|
|
137
|
+
band = 'integer' == math.type(band) and band or 0,
|
|
138
|
+
})
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
-- Published for other plugins and for the application (section 11).
|
|
142
|
+
function Inst:export(key, value)
|
|
143
|
+
self.entry.exports[key] = value
|
|
144
|
+
self.entry.exportkeys[key] = true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
-- What this instance can do for others (section 11.1).
|
|
148
|
+
function Inst:provides(prov)
|
|
149
|
+
table.insert(self.entry.provides, prov)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
-- Where this binding landed (section 6.6) - the plugin-side counterpart to
|
|
153
|
+
-- a host pin. THE HOST DOES NOT POLICE THIS; it just makes the fact
|
|
154
|
+
-- available.
|
|
155
|
+
function Inst:position(point)
|
|
156
|
+
return self.host:positionof(self.ref, point)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
-- AN INSTANCE MAY ITSELF BE A HOST (section 6.5), and THE OUTER ONE OWNS
|
|
160
|
+
-- THE INNER ONE'S LIFETIME. Registering the teardown in the instance scope
|
|
161
|
+
-- is what makes that true rather than aspirational.
|
|
162
|
+
function Inst:nest(nestopts)
|
|
163
|
+
if not self.host.transition then
|
|
164
|
+
T.fail('plugin_release_scope', 'nest called outside a lifecycle callback',
|
|
165
|
+
nil)
|
|
166
|
+
end
|
|
167
|
+
local inner = M.make_host(nestopts)
|
|
168
|
+
table.insert(self.entry.scope, function() inner:close() end)
|
|
169
|
+
self.entry.inner = inner
|
|
170
|
+
return inner
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
-- ------------------------------------------------------------------
|
|
174
|
+
-- Host
|
|
175
|
+
-- ------------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
local Host = {}
|
|
178
|
+
Host.__index = Host
|
|
179
|
+
M.Host = Host
|
|
180
|
+
|
|
181
|
+
function M.make_host(options)
|
|
182
|
+
options = options or T.map {}
|
|
183
|
+
return setmetatable({
|
|
184
|
+
opts = options,
|
|
185
|
+
dependency = T.getv(options, 'dependency') or 'restart',
|
|
186
|
+
reserved = T.getv(options, 'reserved') or T.list {},
|
|
187
|
+
points = T.getv(options, 'points') or T.map {},
|
|
188
|
+
catalog = T.getv(options, 'catalog') or Cat.make_catalog {},
|
|
189
|
+
inst = {},
|
|
190
|
+
order_of = {}, -- refs, kept sorted, so every walk is stable
|
|
191
|
+
log = {},
|
|
192
|
+
-- Section 14: the lifecycle event record. `seq` distinguishes ONE
|
|
193
|
+
-- INCARNATION of stripe$test from the next, which is the whole reason
|
|
194
|
+
-- it is not `pos` (section 4 rule 4).
|
|
195
|
+
events = {},
|
|
196
|
+
seqn = 0,
|
|
197
|
+
open = 0,
|
|
198
|
+
transition = false,
|
|
199
|
+
-- WHICH callback is running, not merely that one is. Section 8.1 puts
|
|
200
|
+
-- resource capture in `activate` and 8.3 says `release` outside
|
|
201
|
+
-- `activate` is `plugin_release_scope` - and a bare flag cannot tell
|
|
202
|
+
-- `activate` from `define`, so it admitted an acquire in `define`
|
|
203
|
+
-- whose scope `unload` would never unwind.
|
|
204
|
+
phase = nil,
|
|
205
|
+
coordinated = false,
|
|
206
|
+
}, Host)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
-- The registry's refs, sorted. Lua tables have no order, so this is the
|
|
210
|
+
-- one walk every method uses.
|
|
211
|
+
function Host:refs()
|
|
212
|
+
local out = {}
|
|
213
|
+
for k in pairs(self.inst) do out[#out + 1] = k end
|
|
214
|
+
table.sort(out)
|
|
215
|
+
return out
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
function Host:define(definition)
|
|
219
|
+
self.catalog:add(definition)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
-- --- observation ------------------------------------------------
|
|
223
|
+
|
|
224
|
+
-- Introspection NEVER advances the state (section 5.2). A status page must
|
|
225
|
+
-- not be a way to accidentally import twenty packages.
|
|
226
|
+
function Host:list()
|
|
227
|
+
local out = T.map {}
|
|
228
|
+
for _, ref in ipairs(self:refs()) do
|
|
229
|
+
out[ref] = self.inst[ref].status
|
|
230
|
+
end
|
|
231
|
+
return out
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
-- The instance record, or nil when nothing is registered under that ref.
|
|
235
|
+
-- THE REF IS VALIDATED, not merely canonicalized: looking an instance up
|
|
236
|
+
-- by `"bad name"` is `plugin_bad_name`, not a quiet miss.
|
|
237
|
+
function Host:instance(ref)
|
|
238
|
+
return self.inst[R.canon_ref(ref)]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
function Host:trace()
|
|
242
|
+
local out = {}
|
|
243
|
+
for i, e in ipairs(self.events) do out[i] = e end
|
|
244
|
+
return T.list(out)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
function Host:observable(result)
|
|
248
|
+
local log = {}
|
|
249
|
+
for i, l in ipairs(self.log) do log[i] = l end
|
|
250
|
+
return T.map {
|
|
251
|
+
status = self:list(),
|
|
252
|
+
open = self.open,
|
|
253
|
+
log = T.list(log),
|
|
254
|
+
result = nil == result and T.NULL or result,
|
|
255
|
+
}
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
-- --- the state machine ------------------------------------------
|
|
259
|
+
|
|
260
|
+
function Host:guard()
|
|
261
|
+
if not self.transition then return end
|
|
262
|
+
T.fail('plugin_reentrant',
|
|
263
|
+
'transition attempted from inside a lifecycle callback', nil)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
function Host:need(ref)
|
|
267
|
+
local r = R.canon_ref(ref)
|
|
268
|
+
local entry = self.inst[r]
|
|
269
|
+
if nil == entry then
|
|
270
|
+
T.fail('plugin_not_loaded', 'no such instance: ' .. r, T.map { ref = r })
|
|
271
|
+
end
|
|
272
|
+
return entry
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
function Host:checkreserved(ref)
|
|
276
|
+
if 0 == T.len(self.reserved) then return end
|
|
277
|
+
local name = R.refname(ref)
|
|
278
|
+
for i = 1, T.len(self.reserved) do
|
|
279
|
+
if self.reserved[i] == name then
|
|
280
|
+
T.fail('plugin_ref_reserved', 'ref is reserved by the host: ' .. ref,
|
|
281
|
+
T.map { ref = ref })
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
function Host:run(entry, callback, at)
|
|
287
|
+
local fn = entry.def[callback]
|
|
288
|
+
table.insert(self.log, entry.ref .. ':' .. at)
|
|
289
|
+
table.insert(self.events, T.map {
|
|
290
|
+
ref = entry.ref, event = at, seq = entry.seq, status = entry.status,
|
|
291
|
+
})
|
|
292
|
+
if 'function' ~= type(fn) then return end
|
|
293
|
+
|
|
294
|
+
self.transition = true
|
|
295
|
+
self.phase = at
|
|
296
|
+
local ok, err = pcall(fn, Inst.new(self, entry))
|
|
297
|
+
self.transition = false
|
|
298
|
+
self.phase = nil
|
|
299
|
+
if ok then return end
|
|
300
|
+
|
|
301
|
+
-- Section 12: `plugin_define_failed` and its three siblings are "a
|
|
302
|
+
-- callback raised; wraps the cause". AN ERROR THAT ALREADY CARRIES A
|
|
303
|
+
-- CODE KEEPS IT - the code is the error's identity, and a plugin raising
|
|
304
|
+
-- `store_unreachable` must not have it rewritten. Only a code-less error
|
|
305
|
+
-- is wrapped.
|
|
306
|
+
if '' ~= T.codeof(err) then error(err, 0) end
|
|
307
|
+
|
|
308
|
+
T.fail('plugin_' .. at .. '_failed',
|
|
309
|
+
entry.ref .. ' raised in ' .. at .. ': ' .. T.message(err),
|
|
310
|
+
T.map { ref = entry.ref, cause = T.message(err) })
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
-- AUTO-TAGGING IS EXPLICIT (section 4 rule 3). `declare('stripe', {tag =
|
|
314
|
+
-- '?'})` assigns the LOWEST UNUSED POSITIVE INTEGER tag and returns the
|
|
315
|
+
-- assigned pair. Without `'?'`, a collision is an error.
|
|
316
|
+
function Host:autotag(name)
|
|
317
|
+
local n = 1
|
|
318
|
+
while true do
|
|
319
|
+
local cand = R.format_ref(name, tostring(n))
|
|
320
|
+
if nil == self.inst[cand] then return cand end
|
|
321
|
+
n = n + 1
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
function Host:count()
|
|
326
|
+
local n = 0
|
|
327
|
+
for _ in pairs(self.inst) do n = n + 1 end
|
|
328
|
+
return n
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
function Host:declare(ref, spec)
|
|
332
|
+
spec = spec or T.map {}
|
|
333
|
+
if '?' == T.getv(spec, 'tag') then
|
|
334
|
+
ref = self:autotag(R.refname(R.canon_ref(ref)))
|
|
335
|
+
end
|
|
336
|
+
local r = R.canon_ref(ref)
|
|
337
|
+
if not T.truthy(T.getv(spec, 'hostowned')) then
|
|
338
|
+
self:checkreserved(r)
|
|
339
|
+
end
|
|
340
|
+
local defname = T.getv(spec, 'definition') or R.refname(r)
|
|
341
|
+
local definition = self.catalog:get(defname)
|
|
342
|
+
if nil == definition then
|
|
343
|
+
T.fail('plugin_unknown_definition', 'not in catalog: ' .. defname,
|
|
344
|
+
T.map { name = defname })
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
local existing = self.inst[r]
|
|
348
|
+
if nil ~= existing then
|
|
349
|
+
-- Section 4 rule 1: a pair addresses at most one instance.
|
|
350
|
+
-- Re-declaring the SAME definition is the idempotent case; a different
|
|
351
|
+
-- one is a duplicate, not a silent overwrite (seneca) and not an
|
|
352
|
+
-- impossibility (sdkgen).
|
|
353
|
+
if existing.def.name ~= definition.name then
|
|
354
|
+
T.fail('plugin_ref_duplicate', 'instance already declared: ' .. r,
|
|
355
|
+
T.map { ref = r })
|
|
356
|
+
end
|
|
357
|
+
return existing
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
local pos = T.getv(spec, 'pos')
|
|
361
|
+
local entry = {
|
|
362
|
+
ref = r,
|
|
363
|
+
def = definition,
|
|
364
|
+
status = 'declared',
|
|
365
|
+
pos = nil == pos and self:count() or pos,
|
|
366
|
+
seq = self.seqn,
|
|
367
|
+
options = T.getv(spec, 'options') or T.map {},
|
|
368
|
+
state = T.map {},
|
|
369
|
+
order = T.getv(spec, 'order'),
|
|
370
|
+
unmet = {},
|
|
371
|
+
scope = {},
|
|
372
|
+
-- Section 11.4's ALWAYS-RELUCTANT rebinding made concrete: the
|
|
373
|
+
-- provider ref this instance's activation actually chose, per
|
|
374
|
+
-- requirement name. Re-ranking on every question silently re-points a
|
|
375
|
+
-- live consumer at any better newcomer, and then losing the provider
|
|
376
|
+
-- it was really using does not restart it.
|
|
377
|
+
selected = {},
|
|
378
|
+
bindings = {},
|
|
379
|
+
exports = T.map {},
|
|
380
|
+
exportkeys = {},
|
|
381
|
+
provides = {},
|
|
382
|
+
inner = nil,
|
|
383
|
+
barred = false,
|
|
384
|
+
}
|
|
385
|
+
self.seqn = self.seqn + 1
|
|
386
|
+
self.inst[r] = entry
|
|
387
|
+
return entry
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
-- Section 9.1: a host that reserves a name MUST still be able to declare
|
|
391
|
+
-- the instance it reserved - "The host declares those instances itself,
|
|
392
|
+
-- after the user merge, and always wins."
|
|
393
|
+
--
|
|
394
|
+
-- THE BOUNDARY IS BY METHOD, NOT BY CALLER, and that is a real limit: no
|
|
395
|
+
-- language here can tell the embedding host from a plugin holding the same
|
|
396
|
+
-- host object. What reservation protects is CONFIGURATION - documents,
|
|
397
|
+
-- overlays, `VOXGIG_PLUGIN_*`, construction options and ordinary
|
|
398
|
+
-- declare/load/options - and all of that still checks.
|
|
399
|
+
function Host:hostdeclare(ref, spec)
|
|
400
|
+
self:guard()
|
|
401
|
+
local owned = T.map {}
|
|
402
|
+
for k, v in pairs(spec or T.map {}) do owned[k] = v end
|
|
403
|
+
owned.hostowned = true
|
|
404
|
+
return self:declare(ref, owned)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
function Host:load(ref, spec)
|
|
408
|
+
self:guard()
|
|
409
|
+
spec = spec or T.map {}
|
|
410
|
+
local entry = self:declare(ref, spec)
|
|
411
|
+
if 'declared' ~= entry.status then return entry end -- idempotent
|
|
412
|
+
|
|
413
|
+
-- PRESENCE, NOT TRUTH: an empty options map must CLEAR what the instance
|
|
414
|
+
-- was declared with.
|
|
415
|
+
if T.has(spec, 'options') and T.NULL ~= spec.options then
|
|
416
|
+
entry.options = spec.options
|
|
417
|
+
end
|
|
418
|
+
local ok, err = pcall(function() self:run(entry, 'define', 'define') end)
|
|
419
|
+
if not ok then
|
|
420
|
+
entry.status = 'failed'
|
|
421
|
+
error(err, 0)
|
|
422
|
+
end
|
|
423
|
+
entry.status = 'loaded'
|
|
424
|
+
|
|
425
|
+
-- AT LOAD, and before anything runs: a cycle through restart-causing
|
|
426
|
+
-- requirements does not settle, and the only safe time to report a
|
|
427
|
+
-- non-terminating reconcile is before it starts (section 11.3).
|
|
428
|
+
-- `provides` is populated by `define`, which has just run, so this is
|
|
429
|
+
-- the first moment the graph is complete.
|
|
430
|
+
ok, err = pcall(function() Dep.checkcycle(self:graphnodes()) end)
|
|
431
|
+
if not ok then
|
|
432
|
+
entry.status = 'failed'
|
|
433
|
+
error(err, 0)
|
|
434
|
+
end
|
|
435
|
+
return entry
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
-- The requirement graph as plain data, for the pure detector.
|
|
439
|
+
function Host:graphnodes()
|
|
440
|
+
local out = {}
|
|
441
|
+
for _, ref in ipairs(self:refs()) do
|
|
442
|
+
local entry = self.inst[ref]
|
|
443
|
+
local provides = {}
|
|
444
|
+
for _, p in ipairs(entry.provides) do
|
|
445
|
+
provides[#provides + 1] = T.getv(p, 'name')
|
|
446
|
+
end
|
|
447
|
+
out[#out + 1] = {
|
|
448
|
+
ref = ref,
|
|
449
|
+
provides = provides,
|
|
450
|
+
requires = Dep.requirements(entry.options),
|
|
451
|
+
}
|
|
452
|
+
end
|
|
453
|
+
return out
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
function Host:activate(ref)
|
|
457
|
+
self:guard()
|
|
458
|
+
local entry = self:need(ref)
|
|
459
|
+
if 'live' == entry.status then return entry end -- no-op, success
|
|
460
|
+
|
|
461
|
+
if 'failed' == entry.status then
|
|
462
|
+
T.fail('plugin_bad_state', 'instance has failed: ' .. entry.ref,
|
|
463
|
+
T.map { ref = entry.ref })
|
|
464
|
+
end
|
|
465
|
+
-- Section 9.6: `active: false` bars the instance from running, and the
|
|
466
|
+
-- bar is on the INSTANCE rather than on the apply that set it. `ready`
|
|
467
|
+
-- reaches this through `activate`, so one guard covers both verbs the
|
|
468
|
+
-- design names.
|
|
469
|
+
if entry.barred then
|
|
470
|
+
T.fail('plugin_inactive',
|
|
471
|
+
'instance is barred by active: false: ' .. entry.ref,
|
|
472
|
+
T.map { ref = entry.ref })
|
|
473
|
+
end
|
|
474
|
+
if 'declared' == entry.status then
|
|
475
|
+
self:load(entry.ref)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
-- A declared requirement that is not live means `pending`: activation is
|
|
479
|
+
-- a STANDING REQUEST, not a one-shot event.
|
|
480
|
+
local unmet = self:unmetof(entry)
|
|
481
|
+
if 0 < #unmet then
|
|
482
|
+
entry.unmet = unmet
|
|
483
|
+
entry.status = 'pending'
|
|
484
|
+
return entry
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
local ok, err = pcall(function() self:run(entry, 'activate', 'activate') end)
|
|
488
|
+
if not ok then
|
|
489
|
+
-- Unwind whatever the partial activation captured, in reverse.
|
|
490
|
+
self:unwind(entry)
|
|
491
|
+
entry.status = 'failed'
|
|
492
|
+
error(err, 0)
|
|
493
|
+
end
|
|
494
|
+
-- Section 11.4: THE SELECTION IS MADE HERE, once, and remembered. Every
|
|
495
|
+
-- later question - the cascade, `hold`, `unmet` - reads it back rather
|
|
496
|
+
-- than re-ranking, which is what "always-reluctant" means.
|
|
497
|
+
for _, req in ipairs(Dep.requirements(entry.options)) do
|
|
498
|
+
self:chosen(entry, req, true)
|
|
499
|
+
end
|
|
500
|
+
entry.status = 'live'
|
|
501
|
+
self:reconcile()
|
|
502
|
+
return entry
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
function Host:deactivate(ref)
|
|
506
|
+
self:guard()
|
|
507
|
+
local entry = self:need(ref)
|
|
508
|
+
if 'loaded' == entry.status or 'declared' == entry.status then
|
|
509
|
+
return entry
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
-- Section 5.2: `unload` is THE ONLY TRANSITION OUT OF `failed`.
|
|
513
|
+
if 'failed' == entry.status then
|
|
514
|
+
T.fail('plugin_bad_state', 'instance has failed: ' .. entry.ref,
|
|
515
|
+
T.map { ref = entry.ref })
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
if 'pending' == entry.status then
|
|
519
|
+
-- DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (section 5.2). It
|
|
520
|
+
-- never reached activate, so it holds no scope and no live bindings;
|
|
521
|
+
-- running the definition's deactivate there would be teardown without
|
|
522
|
+
-- matching setup, which plugins are not written to survive and which
|
|
523
|
+
-- could fail an instance that had done nothing wrong. It cannot fail.
|
|
524
|
+
entry.status = 'loaded'
|
|
525
|
+
entry.unmet = {}
|
|
526
|
+
return entry
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
self:held(entry.ref)
|
|
530
|
+
self:cascade(entry.ref, {})
|
|
531
|
+
|
|
532
|
+
local ok, err = pcall(function()
|
|
533
|
+
self:run(entry, 'deactivate', 'deactivate')
|
|
534
|
+
end)
|
|
535
|
+
if not ok then
|
|
536
|
+
self:unwind(entry)
|
|
537
|
+
entry.status = 'failed'
|
|
538
|
+
error(err, 0)
|
|
539
|
+
end
|
|
540
|
+
self:releasecheck(entry, self:unwind(entry))
|
|
541
|
+
entry.status = 'loaded'
|
|
542
|
+
self:reconcile()
|
|
543
|
+
return entry
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
function Host:unload(ref)
|
|
547
|
+
self:guard()
|
|
548
|
+
local entry = self:need(ref)
|
|
549
|
+
if 'live' == entry.status or 'pending' == entry.status then
|
|
550
|
+
if 'live' == entry.status then
|
|
551
|
+
self:held(entry.ref)
|
|
552
|
+
self:cascade(entry.ref, {})
|
|
553
|
+
local ok, err = pcall(function()
|
|
554
|
+
self:run(entry, 'deactivate', 'deactivate')
|
|
555
|
+
end)
|
|
556
|
+
if not ok then
|
|
557
|
+
-- Section 5.2: ANY failure during a transition lands the instance
|
|
558
|
+
-- in `failed`, with the scope STILL FULLY UNWOUND - and the
|
|
559
|
+
-- instance STAYS REGISTERED, because `failed` is a state an
|
|
560
|
+
-- operator has to be able to see.
|
|
561
|
+
self:unwind(entry)
|
|
562
|
+
entry.status = 'failed'
|
|
563
|
+
error(err, 0)
|
|
564
|
+
end
|
|
565
|
+
self:releasecheck(entry, self:unwind(entry))
|
|
566
|
+
end
|
|
567
|
+
entry.status = 'loaded'
|
|
568
|
+
end
|
|
569
|
+
if 'loaded' == entry.status or 'failed' == entry.status then
|
|
570
|
+
local ok, err = pcall(function() self:run(entry, 'close', 'close') end)
|
|
571
|
+
self.inst[entry.ref] = nil
|
|
572
|
+
if not ok then error(err, 0) end
|
|
573
|
+
return
|
|
574
|
+
end
|
|
575
|
+
self.inst[entry.ref] = nil
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
-- Runs the whole forward path in one call (section 5.1).
|
|
579
|
+
function Host:ready(ref)
|
|
580
|
+
self:guard()
|
|
581
|
+
local r = R.canon_ref(ref)
|
|
582
|
+
if nil == self.inst[r] then self:declare(r) end
|
|
583
|
+
if 'declared' == self.inst[r].status then self:load(r) end
|
|
584
|
+
return self:activate(r)
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
-- Bindings go live only when activation succeeds (section 8.1), so the
|
|
588
|
+
-- teardown is the exact inverse: reverse order, always. Returns the errors
|
|
589
|
+
-- the scope raised. Section 8.3: "A failing release does not stop the
|
|
590
|
+
-- rest. Every entry runs, in reverse order, whatever any of them does; the
|
|
591
|
+
-- errors are collected and raised as one `plugin_release_failed`."
|
|
592
|
+
--
|
|
593
|
+
-- A selection belongs to ONE activation (section 11.4). Leaving `live` by
|
|
594
|
+
-- any door drops it, so the next activation ranks afresh - keeping it
|
|
595
|
+
-- would make a consumer prefer a provider it never actually ran against.
|
|
596
|
+
function Host:unwind(entry)
|
|
597
|
+
entry.selected = {}
|
|
598
|
+
local scope = entry.scope
|
|
599
|
+
entry.scope = {}
|
|
600
|
+
local errors = {}
|
|
601
|
+
for i = #scope, 1, -1 do
|
|
602
|
+
local ok, err = pcall(scope[i])
|
|
603
|
+
if not ok then errors[#errors + 1] = err end
|
|
604
|
+
end
|
|
605
|
+
return errors
|
|
606
|
+
end
|
|
607
|
+
|
|
608
|
+
-- Section 8.3: "A failed release ends the instance in `failed`, exactly as
|
|
609
|
+
-- a failed callback does (5.2) - a release that raised may have leaked,
|
|
610
|
+
-- and an instance that may be holding resources it cannot account for must
|
|
611
|
+
-- not be reactivated."
|
|
612
|
+
function Host:releasecheck(entry, errors)
|
|
613
|
+
if 0 == #errors then return end
|
|
614
|
+
entry.status = 'failed'
|
|
615
|
+
local causes = {}
|
|
616
|
+
for _, e in ipairs(errors) do causes[#causes + 1] = T.message(e) end
|
|
617
|
+
T.fail('plugin_release_failed',
|
|
618
|
+
'release failed for ' .. entry.ref .. ': '
|
|
619
|
+
.. table.concat(causes, '; '),
|
|
620
|
+
T.map { ref = entry.ref, cause = T.list(causes) })
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
-- A REQUIREMENT IS ON A CAPABILITY, not on a ref (section 11.1). A bare
|
|
624
|
+
-- string is shorthand for `{name}`. A ref satisfies too, because a host
|
|
625
|
+
-- that genuinely needs a specific instance should not have to invent a
|
|
626
|
+
-- capability for it.
|
|
627
|
+
function Host:unmetof(entry)
|
|
628
|
+
local out = {}
|
|
629
|
+
for _, req in ipairs(Dep.requirements(entry.options)) do
|
|
630
|
+
if Dep.gatesactivation(req) and 0 == #self:providersof(req) then
|
|
631
|
+
out[#out + 1] = T.getv(req, 'name')
|
|
632
|
+
end
|
|
633
|
+
end
|
|
634
|
+
return out
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
-- Section 11.4's always-reluctant selection, and the ONE place a provider
|
|
638
|
+
-- is picked for a live instance. If this instance already selected a
|
|
639
|
+
-- provider for `req` and that provider is STILL a candidate, it keeps it -
|
|
640
|
+
-- a better-ranked newcomer does not take it.
|
|
641
|
+
--
|
|
642
|
+
-- `remember` is false for the questions asked ABOUT an instance rather
|
|
643
|
+
-- than BY it: introspection must not create a binding.
|
|
644
|
+
function Host:chosen(entry, req, remember)
|
|
645
|
+
local cands = self:providersof(req)
|
|
646
|
+
if 0 == #cands then return nil end
|
|
647
|
+
|
|
648
|
+
local name = T.getv(req, 'name')
|
|
649
|
+
local held = entry.selected[name]
|
|
650
|
+
if nil ~= held then
|
|
651
|
+
for i = 1, #cands do
|
|
652
|
+
if T.getv(cands[i], 'ref') == held then return held end
|
|
653
|
+
end
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
local best = T.getv(cands[1], 'ref')
|
|
657
|
+
if remember then entry.selected[name] = best end
|
|
658
|
+
return best
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
function Host:boundproviders(entry)
|
|
662
|
+
local out = {}
|
|
663
|
+
local seen = {}
|
|
664
|
+
for _, req in ipairs(Dep.requirements(entry.options)) do
|
|
665
|
+
if Dep.restartsonloss(req) then
|
|
666
|
+
local ref = self:chosen(entry, req, false)
|
|
667
|
+
if nil ~= ref and not seen[ref] then
|
|
668
|
+
seen[ref] = true
|
|
669
|
+
out[#out + 1] = ref
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
end
|
|
673
|
+
return out
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
-- Live instances whose selected provider is `ref` and which would be
|
|
677
|
+
-- restarted by losing it.
|
|
678
|
+
function Host:consumersof(ref)
|
|
679
|
+
local out = {}
|
|
680
|
+
for _, r in ipairs(self:refs()) do
|
|
681
|
+
local c = self.inst[r]
|
|
682
|
+
if r ~= ref and 'live' == c.status then
|
|
683
|
+
for _, p in ipairs(self:boundproviders(c)) do
|
|
684
|
+
if p == ref then
|
|
685
|
+
out[#out + 1] = r
|
|
686
|
+
break
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
end
|
|
690
|
+
end
|
|
691
|
+
return out
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
-- Section 11.3's `hold` asks a DIFFERENT question from the cascade, and
|
|
695
|
+
-- reading it off `consumersof` answered the cascade's.
|
|
696
|
+
--
|
|
697
|
+
-- The cascade wants the edges that RESTART - mandatory-static and
|
|
698
|
+
-- optional-static - because a restart is what it performs. `hold` says
|
|
699
|
+
-- "deactivating a REQUIRED instance is `plugin_dependency_held`", and
|
|
700
|
+
-- required is cardinality: `gatesactivation`, not `restartsonloss`. The
|
|
701
|
+
-- two sets differ in both directions and each difference was a real bug.
|
|
702
|
+
function Host:holdersof(ref)
|
|
703
|
+
local out = {}
|
|
704
|
+
for _, r in ipairs(self:refs()) do
|
|
705
|
+
local c = self.inst[r]
|
|
706
|
+
if r ~= ref and 'live' == c.status then
|
|
707
|
+
for _, req in ipairs(Dep.requirements(c.options)) do
|
|
708
|
+
if Dep.gatesactivation(req) and ref == self:chosen(c, req, false) then
|
|
709
|
+
out[#out + 1] = r
|
|
710
|
+
break
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
end
|
|
714
|
+
end
|
|
715
|
+
return out
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
function Host:providersof(req)
|
|
719
|
+
local name = T.getv(req, 'name')
|
|
720
|
+
local want = R.canon(name)
|
|
721
|
+
local cands = {}
|
|
722
|
+
for _, ref in ipairs(self:refs()) do
|
|
723
|
+
local target = self.inst[ref]
|
|
724
|
+
if 'live' == target.status then
|
|
725
|
+
-- A ref satisfies directly.
|
|
726
|
+
if ref == want then
|
|
727
|
+
cands[#cands + 1] = T.map {
|
|
728
|
+
ref = ref, pos = target.pos, provides = T.map { name = name },
|
|
729
|
+
}
|
|
730
|
+
else
|
|
731
|
+
for _, prov in ipairs(target.provides) do
|
|
732
|
+
if T.same(T.getv(prov, 'name'), name) then
|
|
733
|
+
cands[#cands + 1] = T.map {
|
|
734
|
+
ref = ref, pos = target.pos, provides = prov,
|
|
735
|
+
}
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
return Cap.resolve_capability(req, T.list(cands))
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
-- CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (section 11.3).
|
|
745
|
+
--
|
|
746
|
+
-- The cascade is part of the provider's own deactivation and runs BEFORE
|
|
747
|
+
-- the provider's `deactivate` callback and scope unwind, so a consumer's
|
|
748
|
+
-- teardown can still call the thing it depends on - flushing a buffer to
|
|
749
|
+
-- the store it is about to lose is exactly what a `deactivate` callback is
|
|
750
|
+
-- for, and a cascade that fired after the provider was already gone would
|
|
751
|
+
-- make that impossible.
|
|
752
|
+
function Host:cascade(provider, seen)
|
|
753
|
+
if seen[provider] then return end
|
|
754
|
+
seen[provider] = true
|
|
755
|
+
|
|
756
|
+
for _, r in ipairs(self:consumersof(provider)) do
|
|
757
|
+
local consumer = self.inst[r]
|
|
758
|
+
if nil ~= consumer and 'live' == consumer.status then
|
|
759
|
+
self:cascade(r, seen) -- deepest-first
|
|
760
|
+
local ok = pcall(function()
|
|
761
|
+
self:run(consumer, 'deactivate', 'deactivate')
|
|
762
|
+
end)
|
|
763
|
+
local errors = self:unwind(consumer)
|
|
764
|
+
if not ok or 0 < #errors then
|
|
765
|
+
-- Section 5.2: ANY failure during a transition lands the instance
|
|
766
|
+
-- in `failed`. Marking it `pending` handed it straight back to
|
|
767
|
+
-- `reconcile`, which would activate it again the moment the
|
|
768
|
+
-- provider returned.
|
|
769
|
+
consumer.status = 'failed'
|
|
770
|
+
else
|
|
771
|
+
consumer.status = 'pending'
|
|
772
|
+
consumer.unmet = self:unmetof(consumer)
|
|
773
|
+
end
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
-- The hold check is A GUARD ON AD-HOC DEACTIVATION, NOT ON COORDINATED
|
|
779
|
+
-- TEARDOWN. In a bulk operation that is removing the holders too -
|
|
780
|
+
-- `close`, or an `apply` plan whose own steps deactivate them - it is
|
|
781
|
+
-- suspended for exactly those holders, and the teardown still runs
|
|
782
|
+
-- consumers before providers.
|
|
783
|
+
function Host:held(ref)
|
|
784
|
+
if 'hold' ~= self.dependency then return end
|
|
785
|
+
if self.coordinated then return end
|
|
786
|
+
|
|
787
|
+
local holders = self:holdersof(ref)
|
|
788
|
+
if 0 == #holders then return end
|
|
789
|
+
|
|
790
|
+
T.fail('plugin_dependency_held',
|
|
791
|
+
'instance is required by live consumers: ' .. ref,
|
|
792
|
+
T.map { ref = ref, holders = T.list(holders) })
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
-- EAGER reconciliation: run to a fixed point rather than scheduling.
|
|
796
|
+
--
|
|
797
|
+
-- Two directions, and both are the reason `pending` exists. Activation is
|
|
798
|
+
-- a STANDING REQUEST, not a one-shot event.
|
|
799
|
+
function Host:reconcile()
|
|
800
|
+
local moved = true
|
|
801
|
+
local rounds = 0
|
|
802
|
+
while moved do
|
|
803
|
+
moved = false
|
|
804
|
+
rounds = rounds + 1
|
|
805
|
+
if 1000 < rounds then break end
|
|
806
|
+
|
|
807
|
+
-- Losses first, so a cascade settles in one pass rather than
|
|
808
|
+
-- alternating with re-activations.
|
|
809
|
+
for _, r in ipairs(self:refs()) do
|
|
810
|
+
local entry = self.inst[r]
|
|
811
|
+
if nil ~= entry and 'live' == entry.status then
|
|
812
|
+
local lost = {}
|
|
813
|
+
for _, q in ipairs(Dep.requirements(entry.options)) do
|
|
814
|
+
if Dep.gatesactivation(q) and 0 == #self:providersof(q) then
|
|
815
|
+
lost[#lost + 1] = q
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
if 0 < #lost then
|
|
819
|
+
-- POLICY IS PER REQUIREMENT, not per instance (section 11.3). A
|
|
820
|
+
-- `dynamic` requirement whose provider is gone leaves the
|
|
821
|
+
-- consumer LIVE and notified.
|
|
822
|
+
local restarts = false
|
|
823
|
+
for _, q in ipairs(lost) do
|
|
824
|
+
if Dep.restartsonloss(q) then restarts = true break end
|
|
825
|
+
end
|
|
826
|
+
if restarts then
|
|
827
|
+
local ok = pcall(function()
|
|
828
|
+
self:run(entry, 'deactivate', 'deactivate')
|
|
829
|
+
end)
|
|
830
|
+
local errors = self:unwind(entry)
|
|
831
|
+
if not ok or 0 < #errors then
|
|
832
|
+
entry.status = 'failed'
|
|
833
|
+
else
|
|
834
|
+
entry.status = 'pending'
|
|
835
|
+
entry.unmet = self:unmetof(entry)
|
|
836
|
+
end
|
|
837
|
+
moved = true
|
|
838
|
+
end
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
for _, r in ipairs(self:refs()) do
|
|
844
|
+
local entry = self.inst[r]
|
|
845
|
+
if nil ~= entry and 'pending' == entry.status
|
|
846
|
+
and 0 == #self:unmetof(entry) then
|
|
847
|
+
local ok = pcall(function()
|
|
848
|
+
self:run(entry, 'activate', 'activate')
|
|
849
|
+
end)
|
|
850
|
+
if ok then
|
|
851
|
+
entry.status = 'live'
|
|
852
|
+
entry.unmet = {}
|
|
853
|
+
else
|
|
854
|
+
self:unwind(entry)
|
|
855
|
+
entry.status = 'failed'
|
|
856
|
+
end
|
|
857
|
+
moved = true
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
end
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
-- --- ordering ---------------------------------------------------
|
|
864
|
+
|
|
865
|
+
function Host:order(point)
|
|
866
|
+
-- Sorted by declaration SEQUENCE, which is what makes the section 7
|
|
867
|
+
-- sort's fall-through deterministic in a language whose maps have no
|
|
868
|
+
-- insertion order. Section 7 breaks ties by `pos`; two instances CAN
|
|
869
|
+
-- share one - `declare` defaults `pos` to the registry size, so an
|
|
870
|
+
-- unload followed by a fresh declare reuses a surviving instance's - and
|
|
871
|
+
-- past that this was falling through to table order. `seq` is that
|
|
872
|
+
-- order, made explicit.
|
|
873
|
+
local live = {}
|
|
874
|
+
for _, ref in ipairs(self:refs()) do
|
|
875
|
+
local entry = self.inst[ref]
|
|
876
|
+
if 'live' == entry.status then live[#live + 1] = entry end
|
|
877
|
+
end
|
|
878
|
+
live = T.stable_sort(live, function(a, b) return a.seq < b.seq end)
|
|
879
|
+
|
|
880
|
+
local bindings = {}
|
|
881
|
+
for _, entry in ipairs(live) do
|
|
882
|
+
bindings[#bindings + 1] = {
|
|
883
|
+
ref = entry.ref, pos = entry.pos, order = entry.order,
|
|
884
|
+
}
|
|
885
|
+
end
|
|
886
|
+
local pin
|
|
887
|
+
if nil ~= point then
|
|
888
|
+
pin = T.getv(T.getv(self.points, point) or T.map {}, 'pin')
|
|
889
|
+
end
|
|
890
|
+
return Ord.resolve_order(bindings, pin)
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
-- --- points -----------------------------------------------------
|
|
894
|
+
|
|
895
|
+
-- Live bindings on a point, in resolved order. Recomputed on any change to
|
|
896
|
+
-- the live set (section 7) rather than cached at startup - the bug a host
|
|
897
|
+
-- discovers only when something deactivates in production.
|
|
898
|
+
function Host:bound(point)
|
|
899
|
+
local out = {}
|
|
900
|
+
for _, ref in ipairs(self:order(point)) do
|
|
901
|
+
local entry = self.inst[ref]
|
|
902
|
+
-- The band is the INSTANCE's ordering block (section 7), stamped by
|
|
903
|
+
-- the host. A plugin passing its own would be ranking itself above the
|
|
904
|
+
-- order its document declared.
|
|
905
|
+
local block = T.ismap(entry.order) and entry.order or T.map {}
|
|
906
|
+
local band = T.getv(block, 'band')
|
|
907
|
+
band = 'integer' == math.type(band) and band or 0
|
|
908
|
+
for _, b in ipairs(entry.bindings) do
|
|
909
|
+
if b.point == point then
|
|
910
|
+
out[#out + 1] = { ref = b.ref, point = b.point, fn = b.fn, band = band }
|
|
911
|
+
end
|
|
912
|
+
end
|
|
913
|
+
end
|
|
914
|
+
return out
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
function Host:pointspec(point, want)
|
|
918
|
+
if not T.has(self.points, point) then
|
|
919
|
+
T.fail('plugin_point_unknown', 'no such point: ' .. tostring(point),
|
|
920
|
+
T.map { point = point })
|
|
921
|
+
end
|
|
922
|
+
local spec = self.points[point]
|
|
923
|
+
local kind = T.getv(spec, 'kind')
|
|
924
|
+
if 'hook' == want then
|
|
925
|
+
-- A point with no declared kind is a hook, which is what makes `{}`
|
|
926
|
+
-- the minimal point declaration.
|
|
927
|
+
if nil ~= kind and 'hook' ~= kind then
|
|
928
|
+
T.fail('plugin_point_kind', 'point is not a hook: ' .. point,
|
|
929
|
+
T.map { point = point, kind = kind })
|
|
930
|
+
end
|
|
931
|
+
return spec
|
|
932
|
+
end
|
|
933
|
+
if kind ~= want then
|
|
934
|
+
T.fail('plugin_point_kind', 'point is not a ' .. want .. ': ' .. point,
|
|
935
|
+
T.map { point = point, kind = kind })
|
|
936
|
+
end
|
|
937
|
+
return spec
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
function Host:emit(point, arg)
|
|
941
|
+
local spec = self:pointspec(point, 'hook')
|
|
942
|
+
return Pt.point_emit(self:bound(point), T.getv(spec, 'mode') or 'emit', arg)
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
function Host:call(point, ...)
|
|
946
|
+
local spec = self:pointspec(point, 'chain')
|
|
947
|
+
local base = T.getv(spec, 'base')
|
|
948
|
+
if 'function' ~= type(base) then
|
|
949
|
+
base = function(v) return v end
|
|
950
|
+
end
|
|
951
|
+
return Pt.compose(self:bound(point), base)(...)
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
function Host:provider(point, ...)
|
|
955
|
+
local spec = self:pointspec(point, 'provider')
|
|
956
|
+
local pick = Pt.point_provider(self:bound(point), spec)
|
|
957
|
+
if nil == pick.winner then return T.getv(spec, 'default') end
|
|
958
|
+
return pick.winner.fn(nil, ...)
|
|
959
|
+
end
|
|
960
|
+
|
|
961
|
+
-- The losers are VISIBLE rather than silently ignored (section 6.3).
|
|
962
|
+
function Host:shadowed(point)
|
|
963
|
+
if not T.has(self.points, point) then return T.list {} end
|
|
964
|
+
return Pt.point_provider(self:bound(point), self.points[point]).shadowed
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
function Host:exports(spec)
|
|
968
|
+
local all = {}
|
|
969
|
+
for _, ref in ipairs(self:refs()) do
|
|
970
|
+
local entry = self.inst[ref]
|
|
971
|
+
-- Exports of a `loaded` (not live) instance are VISIBLE (11).
|
|
972
|
+
if 'declared' ~= entry.status and 'failed' ~= entry.status then
|
|
973
|
+
local keys = {}
|
|
974
|
+
for k in pairs(entry.exportkeys) do keys[#keys + 1] = k end
|
|
975
|
+
table.sort(keys)
|
|
976
|
+
for _, k in ipairs(keys) do
|
|
977
|
+
all[#all + 1] = { ref = ref, key = k, value = entry.exports[k] }
|
|
978
|
+
end
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
return Ex.resolve_export(spec, all)
|
|
982
|
+
end
|
|
983
|
+
|
|
984
|
+
-- The live providers of a capability, best-first (section 11.1).
|
|
985
|
+
function Host:capability(name)
|
|
986
|
+
local cands = {}
|
|
987
|
+
for _, ref in ipairs(self:refs()) do
|
|
988
|
+
local entry = self.inst[ref]
|
|
989
|
+
if 'live' == entry.status then
|
|
990
|
+
for _, prov in ipairs(entry.provides) do
|
|
991
|
+
if T.getv(prov, 'name') == name then
|
|
992
|
+
cands[#cands + 1] = T.map {
|
|
993
|
+
ref = ref, pos = entry.pos, provides = prov,
|
|
994
|
+
}
|
|
995
|
+
end
|
|
996
|
+
end
|
|
997
|
+
end
|
|
998
|
+
end
|
|
999
|
+
local ranked = Cap.resolve_capability(T.map { name = name }, T.list(cands))
|
|
1000
|
+
local out = {}
|
|
1001
|
+
for i = 1, #ranked do out[#out + 1] = T.getv(ranked[i], 'ref') end
|
|
1002
|
+
return T.list(out)
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
-- --- documents --------------------------------------------------
|
|
1006
|
+
|
|
1007
|
+
function Host:shapeof(ref)
|
|
1008
|
+
local definition = self.catalog:get(R.refname(ref))
|
|
1009
|
+
if nil == definition then return nil end
|
|
1010
|
+
return definition.shape
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
-- Section 9.6: "load what is missing, UNLOAD WHAT IS GONE, patch what
|
|
1014
|
+
-- changed, and move activation state to match", with the stated ordering -
|
|
1015
|
+
-- "deactivations and unloads first (reverse load order), then loads, then
|
|
1016
|
+
-- activations in load order".
|
|
1017
|
+
--
|
|
1018
|
+
-- FOUR PHASES, NOT ONE INTERLEAVED LOOP. An earlier draft walked the
|
|
1019
|
+
-- document once, which never looked at instances the new document had
|
|
1020
|
+
-- DROPPED - so an integration removed from a config reload stayed live
|
|
1021
|
+
-- with its bindings and resources.
|
|
1022
|
+
function Host:apply(doc, profile)
|
|
1023
|
+
self:guard()
|
|
1024
|
+
if nil == profile then profile = T.getv(self.opts, 'profile') end
|
|
1025
|
+
|
|
1026
|
+
local norm = Cfg.normalize_config(T.map {
|
|
1027
|
+
doc = doc,
|
|
1028
|
+
profile = profile,
|
|
1029
|
+
keys = T.getv(self.opts, 'keys'),
|
|
1030
|
+
reserved = self.reserved,
|
|
1031
|
+
})
|
|
1032
|
+
|
|
1033
|
+
local want = {}
|
|
1034
|
+
for i = 1, T.len(norm.order) do want[#want + 1] = norm.order[i] end
|
|
1035
|
+
|
|
1036
|
+
local defaults = T.getv(self.opts, 'defaults') or T.map {}
|
|
1037
|
+
local optionsof = {}
|
|
1038
|
+
for _, ref in ipairs(want) do
|
|
1039
|
+
optionsof[ref] = Cfg.resolve_options(T.map {
|
|
1040
|
+
ref = ref,
|
|
1041
|
+
doc = doc,
|
|
1042
|
+
profile = profile,
|
|
1043
|
+
shape = self:shapeof(ref),
|
|
1044
|
+
hostdefaults = T.getv(defaults, R.refname(ref)),
|
|
1045
|
+
})
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
-- Should this ref be LIVE after the apply? False for a ref the document
|
|
1049
|
+
-- declares lazy or inactive AND for one it does not name at all - which
|
|
1050
|
+
-- is what makes "unload what is gone" and "unload what was toggled off"
|
|
1051
|
+
-- one rule rather than two.
|
|
1052
|
+
local function wantlive(ref)
|
|
1053
|
+
local ent = T.getv(norm.instance, ref)
|
|
1054
|
+
return nil ~= ent and T.truthy(T.getv(ent, 'active'))
|
|
1055
|
+
and 'eager' == T.getv(ent, 'start')
|
|
1056
|
+
end
|
|
1057
|
+
|
|
1058
|
+
-- --- phase 1: deactivations and unloads, REVERSE load order ----
|
|
1059
|
+
local drop = {}
|
|
1060
|
+
for _, ref in ipairs(self:refs()) do
|
|
1061
|
+
if 'declared' ~= self.inst[ref].status and not wantlive(ref) then
|
|
1062
|
+
drop[#drop + 1] = ref
|
|
1063
|
+
end
|
|
1064
|
+
end
|
|
1065
|
+
-- Highest `pos` first, ref-descending for a tie, so a consumer declared
|
|
1066
|
+
-- after its provider goes down first.
|
|
1067
|
+
local inst = self.inst
|
|
1068
|
+
table.sort(drop, function(a, b)
|
|
1069
|
+
if inst[a].pos ~= inst[b].pos then return inst[a].pos > inst[b].pos end
|
|
1070
|
+
return a > b
|
|
1071
|
+
end)
|
|
1072
|
+
for _, ref in ipairs(drop) do self:unload(ref) end
|
|
1073
|
+
|
|
1074
|
+
-- --- phase 2: declare and patch EVERYTHING, in load order ------
|
|
1075
|
+
for _, ref in ipairs(want) do
|
|
1076
|
+
local ent = T.getv(norm.instance, ref)
|
|
1077
|
+
-- NO OPTIONS HERE, and the omission is the fix rather than an
|
|
1078
|
+
-- oversight. `declare` ADOPTS the options table it is handed as the
|
|
1079
|
+
-- instance's own, so passing the resolved table made target and
|
|
1080
|
+
-- source THE SAME TABLE in the refill below - which cleared its own
|
|
1081
|
+
-- source and left a first-time instance with no options at all.
|
|
1082
|
+
-- `declare` makes its own empty table and the refill fills it, so
|
|
1083
|
+
-- both paths are now one path.
|
|
1084
|
+
self:declare(ref, T.map {
|
|
1085
|
+
order = T.getv(ent, 'order'),
|
|
1086
|
+
pos = T.getv(ent, 'pos'),
|
|
1087
|
+
})
|
|
1088
|
+
-- The bar is REASSERTED ON EVERY APPLY, in both directions - a
|
|
1089
|
+
-- document that turns the instance back on clears it, which is the
|
|
1090
|
+
-- whole point of a config switch.
|
|
1091
|
+
self.inst[ref].barred = not T.truthy(T.getv(ent, 'active'))
|
|
1092
|
+
-- REFILL rather than REBIND. A definition's callbacks close over the
|
|
1093
|
+
-- options table they were handed at `define`.
|
|
1094
|
+
local target = self.inst[ref].options
|
|
1095
|
+
for k in pairs(target) do target[k] = nil end
|
|
1096
|
+
for k, v in pairs(optionsof[ref]) do target[k] = v end
|
|
1097
|
+
self.inst[ref].order = T.getv(ent, 'order')
|
|
1098
|
+
self.inst[ref].pos = T.getv(ent, 'pos')
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
-- --- phase 3: loads, in load order -----------------------------
|
|
1102
|
+
-- ONLY THE EAGER, ACTIVE ONES: "a document of twenty lazy instances is
|
|
1103
|
+
-- twenty map entries and no executed code" (9.6).
|
|
1104
|
+
for _, ref in ipairs(want) do
|
|
1105
|
+
if wantlive(ref) then self:load(ref) end
|
|
1106
|
+
end
|
|
1107
|
+
|
|
1108
|
+
-- --- phase 4: activations, in load order -----------------------
|
|
1109
|
+
for _, ref in ipairs(want) do
|
|
1110
|
+
if wantlive(ref) then self:activate(ref) end
|
|
1111
|
+
end
|
|
1112
|
+
end
|
|
1113
|
+
|
|
1114
|
+
function Host:options(ref, patch)
|
|
1115
|
+
self:guard()
|
|
1116
|
+
local entry = self:need(ref)
|
|
1117
|
+
local previous = T.map {}
|
|
1118
|
+
for k, v in pairs(entry.options) do previous[k] = v end
|
|
1119
|
+
|
|
1120
|
+
local merged = T.map {}
|
|
1121
|
+
for k, v in pairs(previous) do merged[k] = v end
|
|
1122
|
+
for _, k in ipairs(T.keys(patch)) do merged[k] = patch[k] end
|
|
1123
|
+
|
|
1124
|
+
local resolved = Cfg.resolve_options(T.map {
|
|
1125
|
+
ref = entry.ref,
|
|
1126
|
+
shape = self:shapeof(entry.ref),
|
|
1127
|
+
doc = T.map {},
|
|
1128
|
+
patch = merged,
|
|
1129
|
+
})
|
|
1130
|
+
local target = entry.options
|
|
1131
|
+
for k in pairs(target) do target[k] = nil end
|
|
1132
|
+
for k, v in pairs(resolved) do target[k] = v end
|
|
1133
|
+
|
|
1134
|
+
if 'live' ~= entry.status then return end
|
|
1135
|
+
|
|
1136
|
+
local reconfigure = entry.def.reconfigure
|
|
1137
|
+
if 'function' == type(reconfigure) then
|
|
1138
|
+
self.transition = true
|
|
1139
|
+
local ok, err = pcall(reconfigure, Inst.new(self, entry), entry.options,
|
|
1140
|
+
previous)
|
|
1141
|
+
self.transition = false
|
|
1142
|
+
if not ok then error(err, 0) end
|
|
1143
|
+
else
|
|
1144
|
+
-- Always correct and sometimes expensive; `reconfigure` exists to make
|
|
1145
|
+
-- the common case cheap (section 9.4).
|
|
1146
|
+
self:deactivate(entry.ref)
|
|
1147
|
+
self:activate(entry.ref)
|
|
1148
|
+
end
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
function Host:close()
|
|
1152
|
+
-- A bulk teardown removing the holders too, so `hold` is suspended for
|
|
1153
|
+
-- exactly those holders (section 11.3) - while the consumers-first
|
|
1154
|
+
-- cascade still runs, which is the half that matters.
|
|
1155
|
+
self.coordinated = true
|
|
1156
|
+
local refs = self:refs()
|
|
1157
|
+
local ok, err = pcall(function()
|
|
1158
|
+
for i = #refs, 1, -1 do
|
|
1159
|
+
if nil ~= self.inst[refs[i]] then self:unload(refs[i]) end
|
|
1160
|
+
end
|
|
1161
|
+
end)
|
|
1162
|
+
self.coordinated = false
|
|
1163
|
+
if not ok then error(err, 0) end
|
|
1164
|
+
end
|
|
1165
|
+
|
|
1166
|
+
-- The same record section 6.6 gives a plugin about itself, reachable from
|
|
1167
|
+
-- outside for the corpus.
|
|
1168
|
+
function Host:positionof(ref, point)
|
|
1169
|
+
local entry = self.inst[R.canon(ref)]
|
|
1170
|
+
if nil == entry then
|
|
1171
|
+
T.fail('plugin_not_loaded', 'no such instance: ' .. tostring(ref),
|
|
1172
|
+
T.map { ref = ref })
|
|
1173
|
+
end
|
|
1174
|
+
local ranked = self:order(point)
|
|
1175
|
+
local index = -1
|
|
1176
|
+
for i = 1, #ranked do
|
|
1177
|
+
if ranked[i] == entry.ref then index = i - 1 break end
|
|
1178
|
+
end
|
|
1179
|
+
return T.map {
|
|
1180
|
+
index = index,
|
|
1181
|
+
count = #ranked,
|
|
1182
|
+
-- Section 6.2 composes b1(b2(b3(base))) with the FIRST binding
|
|
1183
|
+
-- OUTERMOST, so these are not index 0 and index count-1 the other way
|
|
1184
|
+
-- round.
|
|
1185
|
+
outermost = 0 == index,
|
|
1186
|
+
innermost = index == #ranked - 1,
|
|
1187
|
+
}
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
return M
|