@voxgig/sdkgen-langpack 0.0.1
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/.sdk/model/target/dart.aon +63 -0
- package/.sdk/model/target/haskell.aon +72 -0
- package/.sdk/model/target/lean.aon +91 -0
- package/.sdk/src/cmp/dart/Config_dart.ts +248 -0
- package/.sdk/src/cmp/dart/EntityBase_dart.ts +34 -0
- package/.sdk/src/cmp/dart/EntityOperation_dart.ts +43 -0
- package/.sdk/src/cmp/dart/EntityTypes_dart.ts +207 -0
- package/.sdk/src/cmp/dart/Entity_dart.ts +87 -0
- package/.sdk/src/cmp/dart/Gitignore_dart.ts +34 -0
- package/.sdk/src/cmp/dart/MainEntity_dart.ts +33 -0
- package/.sdk/src/cmp/dart/Main_dart.ts +178 -0
- package/.sdk/src/cmp/dart/Package_dart.ts +82 -0
- package/.sdk/src/cmp/dart/ReadmeEntity_dart.ts +177 -0
- package/.sdk/src/cmp/dart/ReadmeExamplesTest_dart.ts +238 -0
- package/.sdk/src/cmp/dart/ReadmeExplanation_dart.ts +53 -0
- package/.sdk/src/cmp/dart/ReadmeHowto_dart.ts +152 -0
- package/.sdk/src/cmp/dart/ReadmeInstall_dart.ts +59 -0
- package/.sdk/src/cmp/dart/ReadmeIntro_dart.ts +65 -0
- package/.sdk/src/cmp/dart/ReadmeModel_dart.ts +151 -0
- package/.sdk/src/cmp/dart/ReadmeOptions_dart.ts +63 -0
- package/.sdk/src/cmp/dart/ReadmeQuick_dart.ts +225 -0
- package/.sdk/src/cmp/dart/ReadmeRef_dart.ts +397 -0
- package/.sdk/src/cmp/dart/ReadmeTopHowto_dart.ts +24 -0
- package/.sdk/src/cmp/dart/ReadmeTopQuick_dart.ts +106 -0
- package/.sdk/src/cmp/dart/ReadmeTopTest_dart.ts +78 -0
- package/.sdk/src/cmp/dart/SdkError_dart.ts +42 -0
- package/.sdk/src/cmp/dart/TestDirect_dart.ts +516 -0
- package/.sdk/src/cmp/dart/TestEntity_dart.ts +628 -0
- package/.sdk/src/cmp/dart/Test_dart.ts +138 -0
- package/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +98 -0
- package/.sdk/src/cmp/dart/fragment/Config.fragment.dart +70 -0
- package/.sdk/src/cmp/dart/fragment/Direct.test.fragment.dart +25 -0
- package/.sdk/src/cmp/dart/fragment/Entity.fragment.dart +29 -0
- package/.sdk/src/cmp/dart/fragment/Entity.test.fragment.dart +28 -0
- package/.sdk/src/cmp/dart/fragment/EntityBase.fragment.dart +302 -0
- package/.sdk/src/cmp/dart/fragment/EntityCreateOp.fragment.dart +98 -0
- package/.sdk/src/cmp/dart/fragment/EntityListOp.fragment.dart +90 -0
- package/.sdk/src/cmp/dart/fragment/EntityLoadOp.fragment.dart +102 -0
- package/.sdk/src/cmp/dart/fragment/EntityRemoveOp.fragment.dart +108 -0
- package/.sdk/src/cmp/dart/fragment/EntityUpdateOp.fragment.dart +102 -0
- package/.sdk/src/cmp/dart/fragment/Main.fragment.dart +339 -0
- package/.sdk/src/cmp/dart/fragment/SdkError.fragment.dart +26 -0
- package/.sdk/src/cmp/dart/tsconfig.json +15 -0
- package/.sdk/src/cmp/dart/utility_dart.ts +155 -0
- package/.sdk/src/cmp/haskell/Config_haskell.ts +98 -0
- package/.sdk/src/cmp/haskell/Entity_haskell.ts +13 -0
- package/.sdk/src/cmp/haskell/Gitignore_haskell.ts +27 -0
- package/.sdk/src/cmp/haskell/Main_haskell.ts +123 -0
- package/.sdk/src/cmp/haskell/Package_haskell.ts +60 -0
- package/.sdk/src/cmp/haskell/ReadmeEntity_haskell.ts +186 -0
- package/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +135 -0
- package/.sdk/src/cmp/haskell/ReadmeExplanation_haskell.ts +48 -0
- package/.sdk/src/cmp/haskell/ReadmeHowto_haskell.ts +168 -0
- package/.sdk/src/cmp/haskell/ReadmeInstall_haskell.ts +51 -0
- package/.sdk/src/cmp/haskell/ReadmeIntro_haskell.ts +67 -0
- package/.sdk/src/cmp/haskell/ReadmeModel_haskell.ts +162 -0
- package/.sdk/src/cmp/haskell/ReadmeOptions_haskell.ts +74 -0
- package/.sdk/src/cmp/haskell/ReadmeQuick_haskell.ts +241 -0
- package/.sdk/src/cmp/haskell/ReadmeRef_haskell.ts +408 -0
- package/.sdk/src/cmp/haskell/ReadmeTopHowto_haskell.ts +31 -0
- package/.sdk/src/cmp/haskell/ReadmeTopQuick_haskell.ts +104 -0
- package/.sdk/src/cmp/haskell/ReadmeTopTest_haskell.ts +80 -0
- package/.sdk/src/cmp/haskell/Test_haskell.ts +297 -0
- package/.sdk/src/cmp/haskell/tsconfig.json +15 -0
- package/.sdk/src/cmp/haskell/utility_haskell.ts +166 -0
- package/.sdk/src/cmp/lean/Config_lean.ts +93 -0
- package/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
- package/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
- package/.sdk/src/cmp/lean/Main_lean.ts +120 -0
- package/.sdk/src/cmp/lean/Package_lean.ts +93 -0
- package/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
- package/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
- package/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
- package/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +39 -0
- package/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
- package/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
- package/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
- package/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
- package/.sdk/src/cmp/lean/ReadmeRef_lean.ts +40 -0
- package/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
- package/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
- package/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +19 -0
- package/.sdk/src/cmp/lean/Test_lean.ts +261 -0
- package/.sdk/src/cmp/lean/utility_lean.ts +129 -0
- package/.sdk/tm/dart/LICENSE +22 -0
- package/.sdk/tm/dart/Makefile +50 -0
- package/.sdk/tm/dart/lib/Context.dart +150 -0
- package/.sdk/tm/dart/lib/Control.dart +15 -0
- package/.sdk/tm/dart/lib/Operation.dart +31 -0
- package/.sdk/tm/dart/lib/Point.dart +51 -0
- package/.sdk/tm/dart/lib/Response.dart +32 -0
- package/.sdk/tm/dart/lib/Result.dart +39 -0
- package/.sdk/tm/dart/lib/Spec.dart +49 -0
- package/.sdk/tm/dart/lib/feature/audit/AuditFeature.dart +103 -0
- package/.sdk/tm/dart/lib/feature/base/BaseFeature.dart +76 -0
- package/.sdk/tm/dart/lib/feature/cache/CacheFeature.dart +152 -0
- package/.sdk/tm/dart/lib/feature/clienttrack/ClienttrackFeature.dart +104 -0
- package/.sdk/tm/dart/lib/feature/cost/CostFeature.dart +446 -0
- package/.sdk/tm/dart/lib/feature/debug/DebugFeature.dart +153 -0
- package/.sdk/tm/dart/lib/feature/idempotency/IdempotencyFeature.dart +92 -0
- package/.sdk/tm/dart/lib/feature/log/LogFeature.dart +85 -0
- package/.sdk/tm/dart/lib/feature/metrics/MetricsFeature.dart +103 -0
- package/.sdk/tm/dart/lib/feature/netsim/NetsimFeature.dart +186 -0
- package/.sdk/tm/dart/lib/feature/paging/PagingFeature.dart +240 -0
- package/.sdk/tm/dart/lib/feature/proxy/ProxyFeature.dart +118 -0
- package/.sdk/tm/dart/lib/feature/ratelimit/RatelimitFeature.dart +103 -0
- package/.sdk/tm/dart/lib/feature/rbac/RbacFeature.dart +121 -0
- package/.sdk/tm/dart/lib/feature/retry/RetryFeature.dart +155 -0
- package/.sdk/tm/dart/lib/feature/secrets/SecretsFeature.dart +649 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/capability.dart +105 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/catalog.dart +46 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/config.dart +297 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/depend.dart +198 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/env.dart +144 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/export.dart +58 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/graph.dart +160 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/host.dart +1067 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/order.dart +172 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/plugin.dart +23 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/point.dart +117 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/ref.dart +105 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/resolve.dart +58 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/types.dart +201 -0
- package/.sdk/tm/dart/lib/feature/secrets/plugin/version.dart +116 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/aws.dart +285 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/azuresecrets.dart +178 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/boru.dart +145 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/crypto.dart +194 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/doppler.dart +101 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/gcpsecrets.dart +143 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/hashicorp.dart +190 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/httpjson.dart +363 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/infisical.dart +149 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/onepassword.dart +146 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/secretspec.dart +116 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/plugins/sigv4.dart +237 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/addr.dart +138 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/json.dart +276 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/provider.dart +31 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/providers.dart +243 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/sekreto.dart +730 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/spec.dart +200 -0
- package/.sdk/tm/dart/lib/feature/secrets/sekreto/src/support.dart +217 -0
- package/.sdk/tm/dart/lib/feature/streaming/StreamingFeature.dart +97 -0
- package/.sdk/tm/dart/lib/feature/telemetry/TelemetryFeature.dart +136 -0
- package/.sdk/tm/dart/lib/feature/test/TestFeature.dart +328 -0
- package/.sdk/tm/dart/lib/feature/timeout/TimeoutFeature.dart +104 -0
- package/.sdk/tm/dart/lib/utility/CleanUtility.dart +12 -0
- package/.sdk/tm/dart/lib/utility/DoneUtility.dart +18 -0
- package/.sdk/tm/dart/lib/utility/ErrUtility.dart +46 -0
- package/.sdk/tm/dart/lib/utility/FeatureAddUtility.dart +35 -0
- package/.sdk/tm/dart/lib/utility/FeatureHookUtility.dart +20 -0
- package/.sdk/tm/dart/lib/utility/FeatureInitUtility.dart +9 -0
- package/.sdk/tm/dart/lib/utility/FetcherUtility.dart +104 -0
- package/.sdk/tm/dart/lib/utility/GraphqlUtility.dart +162 -0
- package/.sdk/tm/dart/lib/utility/MakeContextUtility.dart +6 -0
- package/.sdk/tm/dart/lib/utility/MakeErrorUtility.dart +71 -0
- package/.sdk/tm/dart/lib/utility/MakeFetchDefUtility.dart +42 -0
- package/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +233 -0
- package/.sdk/tm/dart/lib/utility/MakePointUtility.dart +130 -0
- package/.sdk/tm/dart/lib/utility/MakeRequestUtility.dart +66 -0
- package/.sdk/tm/dart/lib/utility/MakeResponseUtility.dart +59 -0
- package/.sdk/tm/dart/lib/utility/MakeResultUtility.dart +49 -0
- package/.sdk/tm/dart/lib/utility/MakeSpecUtility.dart +77 -0
- package/.sdk/tm/dart/lib/utility/MakeUrlUtility.dart +51 -0
- package/.sdk/tm/dart/lib/utility/ParamUtility.dart +56 -0
- package/.sdk/tm/dart/lib/utility/PrepareAuthUtility.dart +46 -0
- package/.sdk/tm/dart/lib/utility/PrepareBodyUtility.dart +19 -0
- package/.sdk/tm/dart/lib/utility/PrepareHeadersUtility.dart +11 -0
- package/.sdk/tm/dart/lib/utility/PrepareMethodUtility.dart +30 -0
- package/.sdk/tm/dart/lib/utility/PrepareParamsUtility.dart +23 -0
- package/.sdk/tm/dart/lib/utility/PreparePathUtility.dart +9 -0
- package/.sdk/tm/dart/lib/utility/PrepareQueryUtility.dart +18 -0
- package/.sdk/tm/dart/lib/utility/ResultBasicUtility.dart +29 -0
- package/.sdk/tm/dart/lib/utility/ResultBodyUtility.dart +15 -0
- package/.sdk/tm/dart/lib/utility/ResultHeadersUtility.dart +18 -0
- package/.sdk/tm/dart/lib/utility/StructUtility.dart +127 -0
- package/.sdk/tm/dart/lib/utility/TransformRequestUtility.dart +28 -0
- package/.sdk/tm/dart/lib/utility/TransformResponseUtility.dart +44 -0
- package/.sdk/tm/dart/lib/utility/Utility.dart +239 -0
- package/.sdk/tm/dart/lib/utility/voxgig_struct.dart +2462 -0
- package/.sdk/tm/dart/src/feature/README.md +3 -0
- package/.sdk/tm/dart/src/feature/audit/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/base/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/cache/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/clienttrack/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/cost/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/debug/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/idempotency/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/log/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/metrics/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/netsim/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/paging/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/proxy/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/ratelimit/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/rbac/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/retry/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/secrets/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/streaming/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/telemetry/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/test/.gitkeep +0 -0
- package/.sdk/tm/dart/src/feature/timeout/.gitkeep +0 -0
- package/.sdk/tm/dart/test/custom_test.dart +65 -0
- package/.sdk/tm/dart/test/exists_test.dart +12 -0
- package/.sdk/tm/dart/test/feature/harness.dart +347 -0
- package/.sdk/tm/dart/test/feature/secrets/secrets_test.dart +1107 -0
- package/.sdk/tm/dart/test/feature_test.dart +1193 -0
- package/.sdk/tm/dart/test/harness.dart +153 -0
- package/.sdk/tm/dart/test/netsim_test.dart +48 -0
- package/.sdk/tm/dart/test/omni.dart +520 -0
- package/.sdk/tm/dart/test/omni_smoke_test.dart +143 -0
- package/.sdk/tm/dart/test/pipeline_test.dart +608 -0
- package/.sdk/tm/dart/test/primary_test.dart +476 -0
- package/.sdk/tm/dart/test/sdk-test-control.json +19 -0
- package/.sdk/tm/dart/test/struct_test.dart +468 -0
- package/.sdk/tm/dart/test/utility.dart +198 -0
- package/.sdk/tm/dart/test/vendor/omni/omni.dart +7 -0
- package/.sdk/tm/dart/test/vendor/omni/runner.dart +653 -0
- package/.sdk/tm/dart/test/vendor/omni/util.dart +232 -0
- package/.sdk/tm/haskell/LICENSE +21 -0
- package/.sdk/tm/haskell/Makefile +22 -0
- package/.sdk/tm/haskell/VERSION +1 -0
- package/.sdk/tm/haskell/src/SdkFeatures.hs +1440 -0
- package/.sdk/tm/haskell/src/SdkHelpers.hs +337 -0
- package/.sdk/tm/haskell/src/SdkJson.hs +111 -0
- package/.sdk/tm/haskell/src/SdkRuntime.hs +1279 -0
- package/.sdk/tm/haskell/src/SdkTypes.hs +195 -0
- package/.sdk/tm/haskell/src/VoxgigStruct.hs +2299 -0
- package/.sdk/tm/haskell/src/Vregex.hs +237 -0
- package/.sdk/tm/haskell/src/feature/README.md +5 -0
- package/.sdk/tm/haskell/src/feature/audit/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/base/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/cache/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/clienttrack/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/debug/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/idempotency/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/log/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/metrics/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/netsim/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/paging/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/proxy/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/ratelimit/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/rbac/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/retry/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/streaming/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/telemetry/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/test/.gitkeep +0 -0
- package/.sdk/tm/haskell/src/feature/timeout/.gitkeep +0 -0
- package/.sdk/tm/haskell/test/Harness.hs +281 -0
- package/.sdk/tm/haskell/test/OmniResolver.hs +252 -0
- package/.sdk/tm/haskell/test/Runner.hs +49 -0
- package/.sdk/tm/haskell/test/StructCorpus.hs +449 -0
- package/.sdk/tm/haskell/test/TCustomUtility.hs +38 -0
- package/.sdk/tm/haskell/test/TFeature.hs +794 -0
- package/.sdk/tm/haskell/test/TNetsim.hs +50 -0
- package/.sdk/tm/haskell/test/TPipeline.hs +334 -0
- package/.sdk/tm/haskell/test/TPrimaryCorpus.hs +263 -0
- package/.sdk/tm/haskell/test/TPrimaryUtility.hs +386 -0
- package/.sdk/tm/haskell/test/Testutil.hs +59 -0
- package/.sdk/tm/haskell/test/vendor/omni/Omni.hs +1147 -0
- package/.sdk/tm/lean/LICENSE +21 -0
- package/.sdk/tm/lean/Makefile +32 -0
- package/.sdk/tm/lean/VERSION +1 -0
- package/.sdk/tm/lean/src/SdkFeature.lean +171 -0
- package/.sdk/tm/lean/src/SdkFeatures.lean +787 -0
- package/.sdk/tm/lean/src/SdkJson.lean +134 -0
- package/.sdk/tm/lean/src/SdkRuntime.lean +374 -0
- package/.sdk/tm/lean/src/SdkUtility.lean +809 -0
- package/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
- package/.sdk/tm/lean/src/Vregex.lean +412 -0
- package/.sdk/tm/lean/src/feature/README.md +5 -0
- package/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/cost/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
- package/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
- package/.sdk/tm/lean/test/OmniResolver.lean +358 -0
- package/.sdk/tm/lean/test/OmniSmoke.lean +174 -0
- package/.sdk/tm/lean/test/StructCorpus.lean +368 -0
- package/.sdk/tm/lean/test/TFeature.lean +281 -0
- package/.sdk/tm/lean/test/TPrimaryUtility.lean +227 -0
- package/.sdk/tm/lean/test/vendor/omni/Omni.lean +997 -0
- package/LICENSE +21 -0
- package/README.md +104 -0
- package/package.json +78 -0
- package/sdkgen-package.json +22 -0
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
// VENDORED: @voxgig/sekreto sdk-20260908-1556-0 (dart/src/sekreto.dart)
|
|
2
|
+
// Source: https://github.com/voxgig/sekreto @ 1267ee2e5f49566bc92695bc9eb3a60ef4924998 [tag: sdk-20260908-1556-0]
|
|
3
|
+
// License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
|
|
4
|
+
// sekreto: one interface for secrets, wherever they live.
|
|
5
|
+
//
|
|
6
|
+
// A Sekreto is an ordered chain of providers. `get` asks each in turn and
|
|
7
|
+
// returns the first hit, so an app can be configured from environment
|
|
8
|
+
// variables in development and a vault in production without changing a
|
|
9
|
+
// line of its own code.
|
|
10
|
+
//
|
|
11
|
+
// THE CORE IMPORTS NO PLUGIN, IN ANY FORM. The four built-in kinds - env,
|
|
12
|
+
// memory, dotenv, file - read at most a local file; every other kind is a
|
|
13
|
+
// voxgig/plugin definition under `plugins/`, and a chain may name one only
|
|
14
|
+
// if the calling project handed it in through `plugins`. That is what keeps
|
|
15
|
+
// an SDK whose chain is `[dotenv, env]` from carrying AWS request signing
|
|
16
|
+
// and seven HTTP vault clients. Nothing under `src/` imports anything under
|
|
17
|
+
// `plugins/`, and `make check-core` proves it of the compiled artifact -
|
|
18
|
+
// the compiler's own dependency listing - rather than of the source.
|
|
19
|
+
// See docs/design/plugin-providers.md.
|
|
20
|
+
//
|
|
21
|
+
// A port of typescript/src/Sekreto.ts, which is canonical.
|
|
22
|
+
|
|
23
|
+
import 'dart:async';
|
|
24
|
+
|
|
25
|
+
import '../../plugin/plugin.dart' as plugin;
|
|
26
|
+
|
|
27
|
+
import 'provider.dart';
|
|
28
|
+
import 'providers.dart';
|
|
29
|
+
import 'spec.dart';
|
|
30
|
+
import 'support.dart';
|
|
31
|
+
|
|
32
|
+
/// A secret name: dot-separated lowercase segments, e.g. `api.token`.
|
|
33
|
+
typedef Name = String;
|
|
34
|
+
|
|
35
|
+
/// Anything sekreto refuses to do: a bad name, a missing secret, a provider
|
|
36
|
+
/// that could not be reached.
|
|
37
|
+
///
|
|
38
|
+
/// The message is the whole contract - there is no code and no cause, and
|
|
39
|
+
/// the shared spec pins the text of every one of them byte for byte.
|
|
40
|
+
class SekretoError implements Exception {
|
|
41
|
+
final String message;
|
|
42
|
+
|
|
43
|
+
SekretoError(this.message);
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
String toString() => message;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Drop a suffix if it is there. `.` and `_` both appear in names, so this
|
|
50
|
+
/// is spelled out rather than reached for through a regex.
|
|
51
|
+
String dropsuffix(String text, String suffix) =>
|
|
52
|
+
text.endsWith(suffix) ? text.substring(0, text.length - suffix.length) : text;
|
|
53
|
+
|
|
54
|
+
/// Split on the literal dot, KEEPING trailing empties, which Dart's `split`
|
|
55
|
+
/// does: `a.` is two segments, the second empty, so it is not a valid
|
|
56
|
+
/// one-segment name.
|
|
57
|
+
List<String> segments(String name) => name.split('.');
|
|
58
|
+
|
|
59
|
+
/// Is this a well-formed secret name?
|
|
60
|
+
///
|
|
61
|
+
/// A character scan, not a regex. The obvious `^[a-z0-9_]+$` is not the
|
|
62
|
+
/// check it looks like: in several regex flavours `$` also matches before a
|
|
63
|
+
/// final newline, and `api.token\n` is a spec case that must be false.
|
|
64
|
+
bool validname(Object? name) {
|
|
65
|
+
if (name is! String || name.isEmpty) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (final part in segments(name)) {
|
|
70
|
+
if (part.isEmpty) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (final unit in part.codeUnits) {
|
|
75
|
+
final ok = (0x61 <= unit && 0x7a >= unit) ||
|
|
76
|
+
(0x30 <= unit && 0x39 >= unit) ||
|
|
77
|
+
0x5f == unit;
|
|
78
|
+
if (!ok) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// The name, or a SekretoError. Every entry point checks its name here.
|
|
88
|
+
Name checkname(Object? name) {
|
|
89
|
+
if (!validname(name)) {
|
|
90
|
+
throw SekretoError('sekreto: invalid name: ${null == name ? '' : name}');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return name as String;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/// Uppercase the ASCII letters and nothing else.
|
|
97
|
+
///
|
|
98
|
+
/// Not `toUpperCase`: a locale-sensitive uppercase turns `i` into a dotted
|
|
99
|
+
/// capital in Turkish, and `api.token` would key `API_TOKEN` on one machine
|
|
100
|
+
/// and something else on another.
|
|
101
|
+
String _upper(String text) {
|
|
102
|
+
final out = StringBuffer();
|
|
103
|
+
|
|
104
|
+
for (final unit in text.codeUnits) {
|
|
105
|
+
out.writeCharCode(0x61 <= unit && 0x7a >= unit ? unit - 32 : unit);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return out.toString();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/// The environment-variable key for a name: `api.token` -> `API_TOKEN`.
|
|
112
|
+
///
|
|
113
|
+
/// The prefix is NOT uppercased: it is written the way the caller wants it
|
|
114
|
+
/// to appear.
|
|
115
|
+
String envkey(Object? name, [String? prefix]) =>
|
|
116
|
+
(prefix ?? '') + _upper(segments(checkname(name)).join('_'));
|
|
117
|
+
|
|
118
|
+
/// Where a name lives in a KV vault.
|
|
119
|
+
class VaultRef {
|
|
120
|
+
final String path;
|
|
121
|
+
final String field;
|
|
122
|
+
const VaultRef(this.path, this.field);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/// Where a name lives in a KV vault: `api.token` -> `api` / `token`.
|
|
126
|
+
///
|
|
127
|
+
/// A single-segment name has no path of its own, so it becomes a secret of
|
|
128
|
+
/// that name with the conventional field `value`.
|
|
129
|
+
VaultRef vaultref(Object? name) {
|
|
130
|
+
final parts = segments(checkname(name));
|
|
131
|
+
|
|
132
|
+
if (1 == parts.length) {
|
|
133
|
+
return VaultRef(parts[0], 'value');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return VaultRef(parts.sublist(0, parts.length - 1).join('/'), parts.last);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/// A name flattened to one segment: `api.token` -> `api_token` (GCP Secret
|
|
140
|
+
/// Manager, `_`) or `api-token` (Azure Key Vault, `-`).
|
|
141
|
+
///
|
|
142
|
+
/// Those stores have no path hierarchy and reject dots in ids, so the dots
|
|
143
|
+
/// become the store's conventional separator. With `-` as the separator,
|
|
144
|
+
/// underscores flatten too: Azure Key Vault's alphabet is letters, digits
|
|
145
|
+
/// and hyphens only, and a valid sekreto name like `with_underscore` must
|
|
146
|
+
/// still be representable there.
|
|
147
|
+
String flatname(Object? name, String sep) {
|
|
148
|
+
final flat = segments(checkname(name)).join(sep);
|
|
149
|
+
return '-' == sep ? flat.replaceAll('_', '-') : flat;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// The AWS SSM Parameter Store name for a name: dots become the path
|
|
153
|
+
/// hierarchy, rooted at `/` (or at a prefix): `db.pass.main` ->
|
|
154
|
+
/// `/db/pass/main`, or `/app/db/pass/main` under prefix `/app`.
|
|
155
|
+
String awsparam(Object? name, [String? prefix]) {
|
|
156
|
+
final checked = checkname(name);
|
|
157
|
+
|
|
158
|
+
var base = prefix ?? '';
|
|
159
|
+
if (base.isNotEmpty && !base.startsWith('/')) {
|
|
160
|
+
base = '/$base';
|
|
161
|
+
}
|
|
162
|
+
base = dropsuffix(base, '/');
|
|
163
|
+
|
|
164
|
+
return '$base/${segments(checked).join('/')}';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/// Parse `.env` text into a map of raw keys to values.
|
|
168
|
+
///
|
|
169
|
+
/// There is no `.env` standard, so this function is the specification.
|
|
170
|
+
/// Deliberately small: `KEY=value`, optional `export`, `#` comments on their
|
|
171
|
+
/// own line, and single- or double-quoted values (double quotes also
|
|
172
|
+
/// unescape `\n`, `\r`, `\t`, `\\` and `\"`). A line with no `=`, or with an
|
|
173
|
+
/// empty key, is skipped rather than refused - one malformed line must not
|
|
174
|
+
/// cost the rest of the file.
|
|
175
|
+
Map<String, String> parsedotenv(Object? text) {
|
|
176
|
+
final out = <String, String>{};
|
|
177
|
+
|
|
178
|
+
if (text is! String) {
|
|
179
|
+
return out;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (final rawline in text.split('\n')) {
|
|
183
|
+
final line = dropsuffix(rawline, '\r').trim();
|
|
184
|
+
|
|
185
|
+
if (line.isEmpty || line.startsWith('#')) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
final entry =
|
|
190
|
+
line.startsWith('export ') ? line.substring(7).trim() : line;
|
|
191
|
+
final eq = entry.indexOf('=');
|
|
192
|
+
|
|
193
|
+
if (0 >= eq) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
final key = entry.substring(0, eq).trim();
|
|
198
|
+
var value = entry.substring(eq + 1).trim();
|
|
199
|
+
|
|
200
|
+
if (2 <= value.length && value.startsWith('"') && value.endsWith('"')) {
|
|
201
|
+
value = unescape(value.substring(1, value.length - 1));
|
|
202
|
+
} else if (2 <= value.length &&
|
|
203
|
+
value.startsWith("'") &&
|
|
204
|
+
value.endsWith("'")) {
|
|
205
|
+
value = value.substring(1, value.length - 1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
out[key] = value;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return out;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/// The escapes a double-quoted `.env` value may carry. A scan, not a chain
|
|
215
|
+
/// of replacements: an unknown escape is kept whole, backslash and all, and
|
|
216
|
+
/// a trailing backslash is literal.
|
|
217
|
+
String unescape(String text) {
|
|
218
|
+
final out = StringBuffer();
|
|
219
|
+
var index = 0;
|
|
220
|
+
|
|
221
|
+
while (index < text.length) {
|
|
222
|
+
if (r'\' == text[index] && index + 1 < text.length) {
|
|
223
|
+
final next = text[index + 1];
|
|
224
|
+
index += 2;
|
|
225
|
+
|
|
226
|
+
switch (next) {
|
|
227
|
+
case 'n':
|
|
228
|
+
out.write('\n');
|
|
229
|
+
case 'r':
|
|
230
|
+
out.write('\r');
|
|
231
|
+
case 't':
|
|
232
|
+
out.write('\t');
|
|
233
|
+
case r'\':
|
|
234
|
+
out.write(r'\');
|
|
235
|
+
case '"':
|
|
236
|
+
out.write('"');
|
|
237
|
+
default:
|
|
238
|
+
out.write(r'\');
|
|
239
|
+
out.write(next);
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
out.write(text[index]);
|
|
243
|
+
index += 1;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return out.toString();
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/// Replace known secret values in text with `[redacted]`.
|
|
251
|
+
///
|
|
252
|
+
/// Only values of four characters or more are replaced: shorter ones are too
|
|
253
|
+
/// likely to appear in ordinary text, and redacting them would make logs
|
|
254
|
+
/// unreadable without making them safer.
|
|
255
|
+
String redact(Object? text, List<Object?>? values) {
|
|
256
|
+
var out = text is String ? text : '';
|
|
257
|
+
|
|
258
|
+
// A COPY is sorted: `values` belongs to the caller (it is the resolved
|
|
259
|
+
// history when called through Sekreto.redact), and sorting in place would
|
|
260
|
+
// reorder it. Longest first, so a value that contains a shorter one is
|
|
261
|
+
// replaced whole rather than left with a redacted fragment inside it.
|
|
262
|
+
final usable = values
|
|
263
|
+
?.whereType<String>()
|
|
264
|
+
.where((value) => 4 <= value.length)
|
|
265
|
+
.toList() ??
|
|
266
|
+
<String>[];
|
|
267
|
+
|
|
268
|
+
usable.sort((left, right) => right.length - left.length);
|
|
269
|
+
|
|
270
|
+
// A literal replace, never a regex: a secret containing metacharacters
|
|
271
|
+
// must not be interpreted as a pattern.
|
|
272
|
+
for (final value in usable) {
|
|
273
|
+
out = out.split(value).join('[redacted]');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/// The store name a provider answers to when nothing says otherwise.
|
|
280
|
+
///
|
|
281
|
+
/// `describe()` opens with the provider's kind - `hashicorp:...`,
|
|
282
|
+
/// `dotenv:...`, plain `env` - so the kind is the natural default, and a
|
|
283
|
+
/// custom provider gets a sensible name without implementing anything extra.
|
|
284
|
+
String storename(Provider provider) {
|
|
285
|
+
final described = provider.describe();
|
|
286
|
+
final mark = described.indexOf(':');
|
|
287
|
+
return -1 == mark ? described : described.substring(0, mark);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/// The message for a kind the catalog does not hold.
|
|
291
|
+
///
|
|
292
|
+
/// A kind sekreto has never heard of is a typo; a kind that exists as a
|
|
293
|
+
/// plugin but was not passed in is the split working as designed, and the
|
|
294
|
+
/// message names the fix. Collapsing the two was the first thing that made
|
|
295
|
+
/// the split confusing to use.
|
|
296
|
+
String unknownkind(String kind, plugin.Catalog catalog) =>
|
|
297
|
+
'sekreto: unknown provider kind: $kind'
|
|
298
|
+
' (available: ${catalog.names().join(', ')})'
|
|
299
|
+
'${KINDS.plugin.contains(kind) ? ' - $kind is a sekreto plugin, not built in: pass it in the plugins option' : ''}';
|
|
300
|
+
|
|
301
|
+
/// A SekretoError that crossed the plugin boundary comes back out as itself,
|
|
302
|
+
/// byte for byte. Anything else is not sekreto's to rewrite, and surfaces as
|
|
303
|
+
/// the host reports it, naming the instance.
|
|
304
|
+
Object unwrap(Object err) {
|
|
305
|
+
if (err is plugin.PluginError && ERROR_CODE == err.code) {
|
|
306
|
+
final cause = err.details['cause'];
|
|
307
|
+
if (cause is String) {
|
|
308
|
+
return SekretoError(cause);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return err;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/// One provider in the chain, under the store name it answers to, and the
|
|
316
|
+
/// ref of the plugin instance that built it - '' for a live provider handed
|
|
317
|
+
/// in directly, which no instance backs.
|
|
318
|
+
class _Entry {
|
|
319
|
+
final String store;
|
|
320
|
+
final String ref;
|
|
321
|
+
final Provider provider;
|
|
322
|
+
const _Entry(this.store, this.ref, this.provider);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/// One resolved value, with the store it came from.
|
|
326
|
+
class _Cached {
|
|
327
|
+
final String store;
|
|
328
|
+
final String name;
|
|
329
|
+
final String value;
|
|
330
|
+
const _Cached(this.store, this.name, this.value);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/// The secrets facade: a chain of providers plus a cache.
|
|
334
|
+
///
|
|
335
|
+
/// Two ways to read. `get` is transparent - it walks the chain and takes the
|
|
336
|
+
/// first hit, and the caller never learns which store answered. `getfrom` is
|
|
337
|
+
/// directed - it names the store, and only that store is asked. Use the
|
|
338
|
+
/// first for ordinary configuration, the second when *which* store holds a
|
|
339
|
+
/// secret is part of what you mean.
|
|
340
|
+
///
|
|
341
|
+
/// `providers` is the chain in resolution order. An entry is a declarative
|
|
342
|
+
/// `ProviderSpec` - which becomes a voxgig/plugin instance on `host` - or a
|
|
343
|
+
/// live `Provider` of your own, which does not.
|
|
344
|
+
///
|
|
345
|
+
/// `plugins` is the provider kinds beyond the four built-in ones that
|
|
346
|
+
/// `providers` may name. Static and explicit: the calling project imports
|
|
347
|
+
/// the definitions it needs and passes them here, and a kind it did not pass
|
|
348
|
+
/// is unknown to this Sekreto. A list handed to a constructor cannot be
|
|
349
|
+
/// erased by a compiler, which a registry filled at import can.
|
|
350
|
+
///
|
|
351
|
+
/// `names` gives the store names of the LIVE providers, positionally; an
|
|
352
|
+
/// entry left null or empty falls back to the provider's kind. A spec'd
|
|
353
|
+
/// provider carries its own `name`.
|
|
354
|
+
class Sekreto {
|
|
355
|
+
/// The definitions this Sekreto can build: the built-ins first, then what
|
|
356
|
+
/// `plugins` handed in. A plugin naming a built-in kind replaces it - a
|
|
357
|
+
/// host substituting an implementation, never an accident, because the
|
|
358
|
+
/// four names are documented.
|
|
359
|
+
final plugin.Catalog catalog;
|
|
360
|
+
|
|
361
|
+
/// The voxgig/plugin host every spec'd provider is an instance of. Read it
|
|
362
|
+
/// for introspection - `host.list()` names each store's ref and status -
|
|
363
|
+
/// and nothing on it advances the chain.
|
|
364
|
+
final plugin.Host host;
|
|
365
|
+
|
|
366
|
+
List<_Entry> _entries = [];
|
|
367
|
+
|
|
368
|
+
// A list, not a map: the store a value came from stays attached, and
|
|
369
|
+
// redaction order does not vary between runs.
|
|
370
|
+
final List<_Cached> _cache = [];
|
|
371
|
+
|
|
372
|
+
// Every value ever resolved, for redact(). Kept independently of the read
|
|
373
|
+
// cache so that redaction still works when caching is off - otherwise an
|
|
374
|
+
// uncached Sekreto would silently disable redact() and leak secrets to
|
|
375
|
+
// logs. Append-only for the object's life: neither refresh() nor close()
|
|
376
|
+
// clears it, because a value that has been in a log is still in that log.
|
|
377
|
+
final List<String> _seen = [];
|
|
378
|
+
|
|
379
|
+
final bool _docache;
|
|
380
|
+
|
|
381
|
+
/// A factory rather than a generative constructor, because the catalog is
|
|
382
|
+
/// built ONCE and both fields hold the same one: an initializer list
|
|
383
|
+
/// cannot share a value between two fields, and building it twice would
|
|
384
|
+
/// give `catalog` and the host's catalog separate identities - so a
|
|
385
|
+
/// definition added to one would be invisible to the other.
|
|
386
|
+
factory Sekreto({
|
|
387
|
+
List<Object?> providers = const [],
|
|
388
|
+
List<Object?> plugins = const [],
|
|
389
|
+
List<String?> names = const [],
|
|
390
|
+
bool cache = true,
|
|
391
|
+
}) {
|
|
392
|
+
final catalog = plugin.makeCatalog(_definitions(plugins));
|
|
393
|
+
final made =
|
|
394
|
+
Sekreto._(catalog, plugin.makeHost({'catalog': catalog}), cache);
|
|
395
|
+
|
|
396
|
+
for (var at = 0; at < providers.length; at++) {
|
|
397
|
+
final given = providers[at];
|
|
398
|
+
|
|
399
|
+
if (given is ProviderSpec) {
|
|
400
|
+
made._entries.add(made._declare(given));
|
|
401
|
+
} else if (given is Provider) {
|
|
402
|
+
final wanted = at < names.length ? names[at] : null;
|
|
403
|
+
final store =
|
|
404
|
+
(null == wanted || wanted.isEmpty) ? storename(given) : wanted;
|
|
405
|
+
made._entries.add(_Entry(store, '', given));
|
|
406
|
+
} else {
|
|
407
|
+
throw SekretoError(
|
|
408
|
+
'sekreto: not a provider or a provider spec: ${given ?? ''}',
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return made;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
Sekreto._(this.catalog, this.host, this._docache);
|
|
417
|
+
|
|
418
|
+
/// The catalog contents: the built-ins first, then what the caller passed.
|
|
419
|
+
///
|
|
420
|
+
/// A definition is checked HERE rather than left to plugin, which reports
|
|
421
|
+
/// it as `plugin_definition_name` - true, and no help at all to someone
|
|
422
|
+
/// who passed the provider instead of the definition that builds it. Each
|
|
423
|
+
/// plugin file exports both, one letter apart (`Hashicorp` the provider,
|
|
424
|
+
/// `hashicorp` the definition), so that mistake is the one to name.
|
|
425
|
+
static List<Definition> _definitions(List<Object?> plugins) {
|
|
426
|
+
final out = <Definition>[...BUILTINS];
|
|
427
|
+
|
|
428
|
+
for (final given in plugins) {
|
|
429
|
+
// A definition is a MAP of `name` and `define`, which is what makes a
|
|
430
|
+
// catalog a data structure a document could produce - and a document
|
|
431
|
+
// is decoded into whatever map type the decoder felt like. The check
|
|
432
|
+
// is therefore on the KEYS rather than on the type argument: dart's
|
|
433
|
+
// generics are covariant, so a literal `{'name': 'x'}`
|
|
434
|
+
// (Map<String, String>) and one carrying a closure
|
|
435
|
+
// (Map<String, Object>) are already Definitions, but a
|
|
436
|
+
// Map<dynamic, dynamic> holding exactly the same entries is not.
|
|
437
|
+
// Accepting it means copying into the shape the catalog wants.
|
|
438
|
+
if (given is Map && given.keys.every((key) => key is String)) {
|
|
439
|
+
final definition = Map<String, dynamic>.from(given);
|
|
440
|
+
|
|
441
|
+
if (definition['name'] is String) {
|
|
442
|
+
out.add(definition);
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (given is Provider) {
|
|
448
|
+
throw SekretoError(
|
|
449
|
+
'sekreto: not a plugin definition: a provider (${given.describe()})'
|
|
450
|
+
' - a definition builds a provider rather than being one:'
|
|
451
|
+
' pass the definition instead',
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
throw SekretoError('sekreto: not a plugin definition: ${given ?? ''}');
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return out;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/// One chain entry, as a plugin instance.
|
|
462
|
+
///
|
|
463
|
+
/// The instance is `kind` for a store named after its kind and
|
|
464
|
+
/// `kind$store` otherwise - `hashicorp$prod` and `hashicorp$test` coexist
|
|
465
|
+
/// - so `host.list()` reads like the chain. A ref that is already taken
|
|
466
|
+
/// gets a numbered tag from the host instead, because two providers MAY
|
|
467
|
+
/// share a store name (the spec says a directed read walks both) and an
|
|
468
|
+
/// instance ref may not: the repeat keeps its store name and takes
|
|
469
|
+
/// `memory$1`.
|
|
470
|
+
_Entry _declare(ProviderSpec spec) {
|
|
471
|
+
final kind = spec.kind;
|
|
472
|
+
|
|
473
|
+
if (!catalog.has(kind)) {
|
|
474
|
+
throw SekretoError(unknownkind(kind, catalog));
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
final given = spec.name;
|
|
478
|
+
final store = (null == given || given.isEmpty) ? kind : given;
|
|
479
|
+
|
|
480
|
+
if (!plugin.checkTag(store)) {
|
|
481
|
+
throw SekretoError('sekreto: invalid store name: $store');
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
final wanted = store == kind ? kind : plugin.formatRef(kind, store);
|
|
485
|
+
final taken = null != host.instance(wanted);
|
|
486
|
+
|
|
487
|
+
final declaration = <String, dynamic>{};
|
|
488
|
+
// plugin's own auto-tagging: the lowest unused positive integer,
|
|
489
|
+
// assigned by the host, so nothing here counts instances.
|
|
490
|
+
if (taken) {
|
|
491
|
+
declaration['tag'] = '?';
|
|
492
|
+
}
|
|
493
|
+
declaration['options'] = optionsof(spec);
|
|
494
|
+
|
|
495
|
+
final String ref;
|
|
496
|
+
|
|
497
|
+
try {
|
|
498
|
+
// `load` runs the definition's `define`, which builds the provider
|
|
499
|
+
// from the spec; `activate` takes the instance live. Nothing is
|
|
500
|
+
// contacted by either: a provider opens nothing until its first
|
|
501
|
+
// lookup.
|
|
502
|
+
final loaded = host.load(taken ? kind : wanted, declaration);
|
|
503
|
+
host.activate(loaded.ref);
|
|
504
|
+
ref = loaded.ref;
|
|
505
|
+
} catch (err) {
|
|
506
|
+
throw unwrap(err);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
final exported = host.exports('$ref/$PROVIDER_EXPORT');
|
|
510
|
+
|
|
511
|
+
// A definition whose `define` exported no provider - one that is not a
|
|
512
|
+
// `providerplugin` at all. plugin runs a `define` that is not a function
|
|
513
|
+
// silently, so without this the chain would carry a hole and the first
|
|
514
|
+
// lookup would blame the wrong thing.
|
|
515
|
+
if (exported is! Provider) {
|
|
516
|
+
throw SekretoError('sekreto: plugin $kind exported no provider');
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
return _Entry(store, ref, exported);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/// The secret, or a SekretoError if no provider has it.
|
|
523
|
+
FutureOr<String> get(Name name) {
|
|
524
|
+
final found = tryget(name);
|
|
525
|
+
|
|
526
|
+
if (found is Future<String?>) {
|
|
527
|
+
return found.then((value) => value ?? _nosecret(name));
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return found ?? _nosecret(name);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/// The secret, or null if no provider has it. Named `tryget` because
|
|
534
|
+
/// `try` is a Dart keyword.
|
|
535
|
+
FutureOr<String?> tryget(Name name) => _resolve('', name, _entries);
|
|
536
|
+
|
|
537
|
+
/// The secret from one named store, or a SekretoError if that store does
|
|
538
|
+
/// not have it.
|
|
539
|
+
FutureOr<String> getfrom(String store, Name name) {
|
|
540
|
+
final found = tryfrom(store, name);
|
|
541
|
+
|
|
542
|
+
if (found is Future<String?>) {
|
|
543
|
+
return found.then((value) => value ?? _nosecret('$store:$name'));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return found ?? _nosecret('$store:$name');
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/// The secret from one named store, or null if that store does not have
|
|
550
|
+
/// it.
|
|
551
|
+
///
|
|
552
|
+
/// Naming a store that is not in the chain is an error, not a miss:
|
|
553
|
+
/// `tryget` already means "this store may not have it", so it cannot also
|
|
554
|
+
/// mean "this store may not exist" without hiding a typo. Raised before
|
|
555
|
+
/// the name is validated, because a chain that cannot answer at all is the
|
|
556
|
+
/// larger mistake.
|
|
557
|
+
FutureOr<String?> tryfrom(String store, Name name) {
|
|
558
|
+
final matching =
|
|
559
|
+
_entries.where((entry) => store == entry.store).toList();
|
|
560
|
+
|
|
561
|
+
if (matching.isEmpty) {
|
|
562
|
+
throw SekretoError('sekreto: unknown store: $store');
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return _resolve(store, name, matching);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
Never _nosecret(String what) =>
|
|
569
|
+
throw SekretoError('sekreto: unknown secret: $what');
|
|
570
|
+
|
|
571
|
+
FutureOr<String?> _resolve(
|
|
572
|
+
String store, Name name, List<_Entry> useentries) {
|
|
573
|
+
// Validated first: before the cache, and before any provider is asked.
|
|
574
|
+
checkname(name);
|
|
575
|
+
|
|
576
|
+
if (_docache) {
|
|
577
|
+
for (final entry in _cache) {
|
|
578
|
+
if (store == entry.store && name == entry.name) {
|
|
579
|
+
return entry.value;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return _walk(store, name, useentries, 0);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
/// Walk the chain from [at], staying synchronous for as long as the
|
|
588
|
+
/// providers do. The first provider that answers with a Future hands the
|
|
589
|
+
/// rest of the walk to a continuation; a chain of purely local stores
|
|
590
|
+
/// never builds one.
|
|
591
|
+
///
|
|
592
|
+
/// THE WALK IS SEKRETO'S, NOT PLUGIN'S. voxgig/plugin has no async surface
|
|
593
|
+
/// - `compose()` is synchronous, deliberately, because its portability
|
|
594
|
+
/// budget spans twenty-three languages - and `bail` cannot express
|
|
595
|
+
/// first-hit here anyway: an async lookup returns a Future, which is
|
|
596
|
+
/// always a value, so every chain would stop at its first provider whether
|
|
597
|
+
/// or not it found the secret. plugin owns the catalog, the instances and
|
|
598
|
+
/// the lifecycle; sekreto owns this loop.
|
|
599
|
+
FutureOr<String?> _walk(
|
|
600
|
+
String store, Name name, List<_Entry> entries, int at) {
|
|
601
|
+
var index = at;
|
|
602
|
+
|
|
603
|
+
while (index < entries.length) {
|
|
604
|
+
final found = entries[index].provider.lookup(name);
|
|
605
|
+
|
|
606
|
+
if (found is Future<String?>) {
|
|
607
|
+
final next = index + 1;
|
|
608
|
+
return found.then((value) => null != value
|
|
609
|
+
? _hit(store, name, value)
|
|
610
|
+
: _walk(store, name, entries, next));
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// The empty string is a hit. Only null means "ask the next one".
|
|
614
|
+
if (null != found) {
|
|
615
|
+
return _hit(store, name, found);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
index++;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// A miss is never cached: the next read asks again.
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
String _hit(String store, Name name, String value) {
|
|
626
|
+
if (_docache) {
|
|
627
|
+
_cache.add(_Cached(store, name, value));
|
|
628
|
+
}
|
|
629
|
+
_seen.add(value);
|
|
630
|
+
return value;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/// Does any provider have this secret?
|
|
634
|
+
FutureOr<bool> has(Name name) {
|
|
635
|
+
final found = tryget(name);
|
|
636
|
+
|
|
637
|
+
if (found is Future<String?>) {
|
|
638
|
+
return found.then((value) => null != value);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return null != found;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/// Does this named store have this secret?
|
|
645
|
+
FutureOr<bool> hasin(String store, Name name) {
|
|
646
|
+
final found = tryfrom(store, name);
|
|
647
|
+
|
|
648
|
+
if (found is Future<String?>) {
|
|
649
|
+
return found.then((value) => null != value);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return null != found;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
/// Every named secret at once, read in order. A missing one is an error.
|
|
656
|
+
Future<Map<String, String>> all(List<Name> names) async {
|
|
657
|
+
final out = <String, String>{};
|
|
658
|
+
|
|
659
|
+
for (final name in names) {
|
|
660
|
+
out[name] = await get(name);
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
return out;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/// A description of each provider, in resolution order. Repeats are kept:
|
|
667
|
+
/// two entries of the same kind are two entries.
|
|
668
|
+
List<String> sources() =>
|
|
669
|
+
_entries.map((entry) => entry.provider.describe()).toList();
|
|
670
|
+
|
|
671
|
+
/// The name of each store that can be named by `getfrom`, in resolution
|
|
672
|
+
/// order and without repeats.
|
|
673
|
+
List<String> stores() {
|
|
674
|
+
final out = <String>[];
|
|
675
|
+
|
|
676
|
+
for (final entry in _entries) {
|
|
677
|
+
if (!out.contains(entry.store)) {
|
|
678
|
+
out.add(entry.store);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return out;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/// Replace every value this Sekreto has resolved with `[redacted]`.
|
|
686
|
+
///
|
|
687
|
+
/// Works whether or not caching is enabled: the redaction list is kept
|
|
688
|
+
/// independently of the read cache.
|
|
689
|
+
String redact(String text) =>
|
|
690
|
+
// The library function of the same name, which this method shadows.
|
|
691
|
+
_redactall(text, _seen);
|
|
692
|
+
|
|
693
|
+
/// Drop cached values, so the next read asks the providers again. The
|
|
694
|
+
/// redaction history is not touched.
|
|
695
|
+
void refresh() => _cache.clear();
|
|
696
|
+
|
|
697
|
+
/// Tear the chain down: every plugin instance is deactivated and unloaded,
|
|
698
|
+
/// in reverse, releasing whatever a provider acquired at activation.
|
|
699
|
+
/// Afterwards there are no stores, no sources and nothing to read - but
|
|
700
|
+
/// redaction still knows every value ever resolved, because those values
|
|
701
|
+
/// are still in whatever they were printed into.
|
|
702
|
+
void close() {
|
|
703
|
+
host.close();
|
|
704
|
+
_entries = [];
|
|
705
|
+
_cache.clear();
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/// Serialised without reaching a value: `cache` and `seen` are ordinary
|
|
709
|
+
/// fields, so anything deriving this from them would emit every secret
|
|
710
|
+
/// the process has read.
|
|
711
|
+
Map<String, Object?> toJson() => {'stores': stores()};
|
|
712
|
+
|
|
713
|
+
@override
|
|
714
|
+
String toString() => 'Sekreto { stores: [ ${stores().join(', ')} ] }';
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
String _redactall(String text, List<String> values) => redact(text, values);
|
|
718
|
+
|
|
719
|
+
/// Make a Sekreto from declarative provider specs - the same shape the
|
|
720
|
+
/// shared spec and an app's config file use.
|
|
721
|
+
///
|
|
722
|
+
/// `plugins` is the kinds beyond the four built-in ones that `specs` may
|
|
723
|
+
/// name: `sekreto(chain, plugins: allplugins)` for the lot,
|
|
724
|
+
/// `sekreto(chain, plugins: [hashicorp])` for one.
|
|
725
|
+
Sekreto sekreto(
|
|
726
|
+
List<ProviderSpec> specs, {
|
|
727
|
+
List<Object?> plugins = const [],
|
|
728
|
+
bool cache = true,
|
|
729
|
+
}) =>
|
|
730
|
+
Sekreto(providers: specs, plugins: plugins, cache: cache);
|