@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,1279 @@
|
|
|
1
|
+
-- ProjectName SDK runtime: the operation pipeline.
|
|
2
|
+
--
|
|
3
|
+
-- The context builder, all the `*Util` pipeline utilities (the dynamic donors'
|
|
4
|
+
-- utility/ layer), the utility bundle constructor, make_options and the
|
|
5
|
+
-- innermost transport (fetcher). Utilities are top-level IO functions that call
|
|
6
|
+
-- each other directly; the two members that vary per client — the transport
|
|
7
|
+
-- (`uFetcher`, wrapped by features) and `uParam` — are IORef cells so features
|
|
8
|
+
-- and tests can rebind them. Everything runs in IO because struct nodes are
|
|
9
|
+
-- IORef-backed and reference-stable.
|
|
10
|
+
|
|
11
|
+
module SdkRuntime where
|
|
12
|
+
|
|
13
|
+
import Control.Exception (throwIO)
|
|
14
|
+
import Control.Monad (forM_, when)
|
|
15
|
+
import Data.Bits ((.&.))
|
|
16
|
+
import Data.Char (isAlphaNum, toUpper)
|
|
17
|
+
import Data.IORef
|
|
18
|
+
import qualified Data.Map.Strict as Map
|
|
19
|
+
import Data.Maybe (isNothing)
|
|
20
|
+
import System.IO.Unsafe (unsafePerformIO)
|
|
21
|
+
import Text.Printf (printf)
|
|
22
|
+
|
|
23
|
+
import VoxgigStruct
|
|
24
|
+
( Value (..), InjArg (..), emptyList, emptyMap, mkList, mkMap
|
|
25
|
+
, getprop, getpropAlt, setprop, delprop, getpath, getelem, keysof, listItems
|
|
26
|
+
, items, clone, merge, validate, transform, select, size, isempty
|
|
27
|
+
, isnode, ismap, islist, isfunc, isNoval, isNullish, vint
|
|
28
|
+
, escurl, escre, stringify, walk, join )
|
|
29
|
+
import SdkTypes
|
|
30
|
+
import SdkHelpers
|
|
31
|
+
|
|
32
|
+
-- ------------------------------------------------------------------
|
|
33
|
+
-- random ids (no external dep; LCG)
|
|
34
|
+
-- ------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
{-# NOINLINE randSeed #-}
|
|
37
|
+
randSeed :: IORef Int
|
|
38
|
+
randSeed = unsafePerformIO (newIORef 123456789)
|
|
39
|
+
|
|
40
|
+
randInt :: Int -> IO Int
|
|
41
|
+
randInt n
|
|
42
|
+
| n <= 0 = pure 0
|
|
43
|
+
| otherwise = do
|
|
44
|
+
s <- readIORef randSeed
|
|
45
|
+
let s' = (s * 1103515245 + 12345) .&. 0x7fffffff
|
|
46
|
+
writeIORef randSeed s'
|
|
47
|
+
pure (s' `mod` n)
|
|
48
|
+
|
|
49
|
+
randHex4 :: IO String
|
|
50
|
+
randHex4 = printf "%04x" <$> randInt 0x10000
|
|
51
|
+
|
|
52
|
+
randId16 :: IO String
|
|
53
|
+
randId16 = concat <$> sequence [randHex4, randHex4, randHex4, randHex4]
|
|
54
|
+
|
|
55
|
+
nextCtxId :: IO String
|
|
56
|
+
nextCtxId = do n <- randInt 90000000; pure ("C" ++ show (10000000 + n))
|
|
57
|
+
|
|
58
|
+
escurlS :: String -> IO String
|
|
59
|
+
escurlS s = do r <- escurl (VStr s); pure (case r of VStr x -> x; _ -> s)
|
|
60
|
+
|
|
61
|
+
escreS :: String -> IO String
|
|
62
|
+
escreS s = do r <- escre (VStr s); pure (case r of VStr x -> x; _ -> s)
|
|
63
|
+
|
|
64
|
+
valEqScalar :: Value -> Value -> Bool
|
|
65
|
+
valEqScalar a b = case (a, b) of
|
|
66
|
+
(VNoval, VNoval) -> True
|
|
67
|
+
(VNull, VNull) -> True
|
|
68
|
+
(VNoval, VNull) -> True
|
|
69
|
+
(VNull, VNoval) -> True
|
|
70
|
+
(VStr x, VStr y) -> x == y
|
|
71
|
+
(VNum x, VNum y) -> x == y
|
|
72
|
+
(VBool x, VBool y) -> x == y
|
|
73
|
+
_ -> False
|
|
74
|
+
|
|
75
|
+
-- ------------------------------------------------------------------
|
|
76
|
+
-- context builder
|
|
77
|
+
-- ------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
clientOptionsMap :: Client -> IO Value
|
|
80
|
+
clientOptionsMap cl = do
|
|
81
|
+
o <- readIORef (clOptions cl)
|
|
82
|
+
c <- clone o
|
|
83
|
+
case c of VMap _ -> pure c; _ -> emptyMap
|
|
84
|
+
|
|
85
|
+
resolveOp :: Context -> String -> IO Operation
|
|
86
|
+
resolveOp ctx opname = do
|
|
87
|
+
ment <- readIORef (cEntity ctx)
|
|
88
|
+
let entname = maybe "_" eName ment
|
|
89
|
+
cacheKey = opCacheKey entname opname
|
|
90
|
+
m <- readIORef (cOpmap ctx)
|
|
91
|
+
case Map.lookup cacheKey m of
|
|
92
|
+
Just op -> pure op
|
|
93
|
+
Nothing ->
|
|
94
|
+
if opname == ""
|
|
95
|
+
then newOperation =<< emptyMap
|
|
96
|
+
else do
|
|
97
|
+
cfg <- readIORef (cConfig ctx)
|
|
98
|
+
opcfg <- getpathS cfg ("entity." ++ entname ++ ".op." ++ opname)
|
|
99
|
+
let inpt = if opname == "update" || opname == "create" then "data" else "match"
|
|
100
|
+
pts <- case opcfg of
|
|
101
|
+
VMap _ -> do p <- getp opcfg "points"; case p of VList _ -> pure p; _ -> emptyList
|
|
102
|
+
_ -> emptyList
|
|
103
|
+
opm <- jo [("entity", VStr entname), ("name", VStr opname), ("input", VStr inpt), ("points", pts)]
|
|
104
|
+
op <- newOperation opm
|
|
105
|
+
modifyIORef' (cOpmap ctx) (Map.insert cacheKey op)
|
|
106
|
+
pure op
|
|
107
|
+
|
|
108
|
+
makeContextImpl :: CtxSpec -> Maybe Context -> IO Context
|
|
109
|
+
makeContextImpl cs basectx = do
|
|
110
|
+
cid <- nextCtxId
|
|
111
|
+
|
|
112
|
+
client <- case csClient cs of
|
|
113
|
+
Just c -> pure (Just c)
|
|
114
|
+
Nothing -> maybe (pure Nothing) (readIORef . cClient) basectx
|
|
115
|
+
|
|
116
|
+
utility <- case csUtility cs of
|
|
117
|
+
Just u -> pure (Just u)
|
|
118
|
+
Nothing -> maybe (pure Nothing) (readIORef . cUtility) basectx
|
|
119
|
+
|
|
120
|
+
ctrl <- case csCtrl cs of
|
|
121
|
+
Just cr@(VMap _) -> do
|
|
122
|
+
c <- newControl
|
|
123
|
+
thr <- getp cr "throw_err"
|
|
124
|
+
case thr of
|
|
125
|
+
VBool b -> setp c "throw" (VBool b)
|
|
126
|
+
_ -> do t2 <- getp cr "throw"; case t2 of VBool b -> setp c "throw" (VBool b); _ -> pure ()
|
|
127
|
+
ex <- getp cr "explain"; case ex of VMap _ -> setp c "explain" ex; _ -> pure ()
|
|
128
|
+
ac <- getp cr "actor"; case ac of VNoval -> pure (); _ -> setp c "actor" ac
|
|
129
|
+
pg <- getp cr "paging"; case pg of VMap _ -> setp c "paging" pg; _ -> pure ()
|
|
130
|
+
pure c
|
|
131
|
+
_ -> maybe newControl (readIORef . cCtrl) basectx
|
|
132
|
+
|
|
133
|
+
meta <- case csMeta cs of
|
|
134
|
+
Just m@(VMap _) -> pure m
|
|
135
|
+
_ -> case basectx of
|
|
136
|
+
Just b -> do mv <- readIORef (cMeta b); case mv of VMap _ -> pure mv; _ -> emptyMap
|
|
137
|
+
Nothing -> emptyMap
|
|
138
|
+
|
|
139
|
+
config <- inheritMap (csConfig cs) (cConfig <$> basectx) VNoval
|
|
140
|
+
entopts <- inheritMap (csEntopts cs) (cEntopts <$> basectx) VNoval
|
|
141
|
+
options <- inheritMap (csOptions cs) (cOptions <$> basectx) VNoval
|
|
142
|
+
|
|
143
|
+
entity <- case csEntity cs of
|
|
144
|
+
Just e -> pure (Just e)
|
|
145
|
+
Nothing -> maybe (pure Nothing) (readIORef . cEntity) basectx
|
|
146
|
+
|
|
147
|
+
shared <- case csShared cs of
|
|
148
|
+
Just m@(VMap _) -> pure m
|
|
149
|
+
_ -> maybe (pure VNoval) (readIORef . cShared) basectx
|
|
150
|
+
|
|
151
|
+
opmapRef <- case csOpmap cs of
|
|
152
|
+
Just r -> pure r
|
|
153
|
+
Nothing -> case basectx of Just b -> pure (cOpmap b); Nothing -> newIORef Map.empty
|
|
154
|
+
|
|
155
|
+
dat <- mapOf (csData cs)
|
|
156
|
+
reqdata <- mapOf (csReqdata cs)
|
|
157
|
+
mtch <- mapOf (csMatch cs)
|
|
158
|
+
reqmatch <- mapOf (csReqmatch cs)
|
|
159
|
+
|
|
160
|
+
point <- case csPoint cs of
|
|
161
|
+
Just m@(VMap _) -> pure m
|
|
162
|
+
_ -> maybe (pure VNoval) (readIORef . cPoint) basectx
|
|
163
|
+
|
|
164
|
+
spec <- inheritObj (csSpec cs) (cSpec <$> basectx)
|
|
165
|
+
result <- inheritObj (csResult cs) (cResult <$> basectx)
|
|
166
|
+
response <- inheritObj (csResponse cs) (cResponse <$> basectx)
|
|
167
|
+
|
|
168
|
+
op0 <- newOperation =<< emptyMap
|
|
169
|
+
scratch <- emptyMap
|
|
170
|
+
out <- emptyMap
|
|
171
|
+
|
|
172
|
+
cOutR <- newIORef out
|
|
173
|
+
cCtrlR <- newIORef ctrl
|
|
174
|
+
cMetaR <- newIORef meta
|
|
175
|
+
cClientR <- newIORef client
|
|
176
|
+
cUtilR <- newIORef utility
|
|
177
|
+
cOpR <- newIORef op0
|
|
178
|
+
cPointR <- newIORef point
|
|
179
|
+
cConfigR <- newIORef config
|
|
180
|
+
cEntoptsR <- newIORef entopts
|
|
181
|
+
cOptionsR <- newIORef options
|
|
182
|
+
cResponseR <- newIORef response
|
|
183
|
+
cResultR <- newIORef result
|
|
184
|
+
cSpecR <- newIORef spec
|
|
185
|
+
cDataR <- newIORef dat
|
|
186
|
+
cReqdataR <- newIORef reqdata
|
|
187
|
+
cMatchR <- newIORef mtch
|
|
188
|
+
cReqmatchR <- newIORef reqmatch
|
|
189
|
+
cEntityR <- newIORef entity
|
|
190
|
+
cSharedR <- newIORef shared
|
|
191
|
+
cScratchR <- newIORef scratch
|
|
192
|
+
|
|
193
|
+
let ctx = Context
|
|
194
|
+
{ cId = cid, cOut = cOutR, cCtrl = cCtrlR, cMeta = cMetaR
|
|
195
|
+
, cClient = cClientR, cUtility = cUtilR, cOp = cOpR, cPoint = cPointR
|
|
196
|
+
, cConfig = cConfigR, cEntopts = cEntoptsR, cOptions = cOptionsR
|
|
197
|
+
, cOpmap = opmapRef, cResponse = cResponseR, cResult = cResultR
|
|
198
|
+
, cSpec = cSpecR, cData = cDataR, cReqdata = cReqdataR, cMatch = cMatchR
|
|
199
|
+
, cReqmatch = cReqmatchR, cEntity = cEntityR, cShared = cSharedR
|
|
200
|
+
, cScratch = cScratchR }
|
|
201
|
+
|
|
202
|
+
let opname = maybe "" id (csOpname cs)
|
|
203
|
+
op <- resolveOp ctx opname
|
|
204
|
+
writeIORef cOpR op
|
|
205
|
+
pure ctx
|
|
206
|
+
where
|
|
207
|
+
inheritMap mcs mbfield dflt = case mcs of
|
|
208
|
+
Just m@(VMap _) -> pure m
|
|
209
|
+
_ -> case mbfield of Just r -> readIORef r; Nothing -> pure dflt
|
|
210
|
+
inheritObj mcs mbfield = case mcs of
|
|
211
|
+
Just v -> pure v
|
|
212
|
+
_ -> case mbfield of Just r -> readIORef r; Nothing -> pure VNoval
|
|
213
|
+
mapOf mv = case mv of
|
|
214
|
+
Just d -> case toMap d of VMap _ -> pure d; _ -> emptyMap
|
|
215
|
+
Nothing -> emptyMap
|
|
216
|
+
|
|
217
|
+
-- ------------------------------------------------------------------
|
|
218
|
+
-- utilities
|
|
219
|
+
-- ------------------------------------------------------------------
|
|
220
|
+
|
|
221
|
+
cleanUtil :: Context -> Value -> IO Value
|
|
222
|
+
cleanUtil _ v = pure v
|
|
223
|
+
|
|
224
|
+
makeErrorUtil :: Context -> Maybe Value -> IO Value
|
|
225
|
+
makeErrorUtil ctx merr = do
|
|
226
|
+
op <- readIORef (cOp ctx)
|
|
227
|
+
let opname0 = opName op
|
|
228
|
+
opname = if opname0 == "" || opname0 == "_" then "unknown operation" else opname0
|
|
229
|
+
resultV <- readIORef (cResult ctx)
|
|
230
|
+
result <- case resultV of VMap _ -> pure resultV; _ -> newResult =<< emptyMap
|
|
231
|
+
setp result "ok" (VBool False)
|
|
232
|
+
err <- case merr of
|
|
233
|
+
Just e -> pure e
|
|
234
|
+
Nothing -> do
|
|
235
|
+
re <- getp result "err"; isE <- isErr re
|
|
236
|
+
if isE then pure re else mkErr "unknown" "unknown error"
|
|
237
|
+
em <- errMsg err
|
|
238
|
+
let msg = "ProjectNameSDK: " ++ opname ++ ": " ++ em
|
|
239
|
+
setp result "err" VNoval
|
|
240
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
241
|
+
explain <- getp ctrl "explain"
|
|
242
|
+
case explain of
|
|
243
|
+
VMap _ -> do e2 <- jo [("message", VStr msg)]; setp explain "err" e2
|
|
244
|
+
_ -> pure ()
|
|
245
|
+
ecode <- errCode err
|
|
246
|
+
rv <- resultToValue result
|
|
247
|
+
specV <- readIORef (cSpec ctx)
|
|
248
|
+
sv <- case specV of VMap _ -> specToValue specV; _ -> pure VNoval
|
|
249
|
+
sdkErr <- jo [ ("__sdkerr__", VBool True), ("code", VStr ecode), ("message", VStr msg)
|
|
250
|
+
, ("result", rv), ("spec", sv) ]
|
|
251
|
+
setp ctrl "err" sdkErr
|
|
252
|
+
-- Fire PreUnexpected so observability features (metrics, telemetry, audit,
|
|
253
|
+
-- debug) close/record error paths that never reach PreDone (e.g. a PrePoint
|
|
254
|
+
-- rbac short-circuit). Fires after ctrl err is set so hooks can read the
|
|
255
|
+
-- error; features guard against double-recording when PreDone already fired.
|
|
256
|
+
featureHookUtil ctx "PreUnexpected"
|
|
257
|
+
thr <- getp ctrl "throw"
|
|
258
|
+
case thr of
|
|
259
|
+
VBool False -> getp result "resdata"
|
|
260
|
+
_ -> throwIO (SdkException sdkErr)
|
|
261
|
+
|
|
262
|
+
doneUtil :: Context -> IO Value
|
|
263
|
+
doneUtil ctx = do
|
|
264
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
265
|
+
explain <- getp ctrl "explain"
|
|
266
|
+
case explain of
|
|
267
|
+
VMap _ -> do
|
|
268
|
+
er <- getp explain "result"
|
|
269
|
+
case er of VMap _ -> delp er "err"; _ -> pure ()
|
|
270
|
+
_ -> pure ()
|
|
271
|
+
resultV <- readIORef (cResult ctx)
|
|
272
|
+
case resultV of
|
|
273
|
+
VMap _ -> do
|
|
274
|
+
ok <- getp resultV "ok"
|
|
275
|
+
if isTrueV ok then getp resultV "resdata" else makeErrorUtil ctx Nothing
|
|
276
|
+
_ -> makeErrorUtil ctx Nothing
|
|
277
|
+
|
|
278
|
+
-- ----- feature utilities -----
|
|
279
|
+
|
|
280
|
+
featureHookUtil :: Context -> String -> IO ()
|
|
281
|
+
featureHookUtil ctx name = do
|
|
282
|
+
mcl <- readIORef (cClient ctx)
|
|
283
|
+
case mcl of
|
|
284
|
+
Nothing -> pure ()
|
|
285
|
+
Just cl -> do fs <- readIORef (clFeatures cl); mapM_ (\f -> fHook f name ctx) fs
|
|
286
|
+
|
|
287
|
+
featureAddUtil :: Context -> Feature -> IO ()
|
|
288
|
+
featureAddUtil ctx f = do
|
|
289
|
+
cl <- cc ctx
|
|
290
|
+
fopts <- readIORef (fOptions f)
|
|
291
|
+
let posOpt k = do
|
|
292
|
+
v <- case fopts of VMap _ -> getp fopts k; _ -> pure VNoval
|
|
293
|
+
pure (case v of VStr s -> Just s; _ -> Nothing)
|
|
294
|
+
before <- posOpt "__before__"
|
|
295
|
+
after <- posOpt "__after__"
|
|
296
|
+
replace <- posOpt "__replace__"
|
|
297
|
+
feats <- readIORef (clFeatures cl)
|
|
298
|
+
let hasPos = before /= Nothing || after /= Nothing || replace /= Nothing
|
|
299
|
+
go _ [] = Nothing
|
|
300
|
+
go acc (ef : rest)
|
|
301
|
+
| before == Just (fName ef) = Just (reverse acc ++ (f : ef : rest))
|
|
302
|
+
| after == Just (fName ef) = Just (reverse acc ++ (ef : f : rest))
|
|
303
|
+
| replace == Just (fName ef) = Just (reverse acc ++ (f : rest))
|
|
304
|
+
| otherwise = go (ef : acc) rest
|
|
305
|
+
positioned = if hasPos then go [] feats else Nothing
|
|
306
|
+
case positioned of
|
|
307
|
+
Just l -> writeIORef (clFeatures cl) l
|
|
308
|
+
Nothing -> writeIORef (clFeatures cl) (feats ++ [f])
|
|
309
|
+
|
|
310
|
+
featureInitUtil :: Context -> Feature -> IO ()
|
|
311
|
+
featureInitUtil ctx f = do
|
|
312
|
+
let fname = fName f
|
|
313
|
+
opts <- readIORef (cOptions ctx)
|
|
314
|
+
fo <- getp opts "feature"
|
|
315
|
+
fopts <- case fo of
|
|
316
|
+
VMap _ -> do foo <- getp fo fname; case foo of VMap _ -> pure foo; _ -> emptyMap
|
|
317
|
+
_ -> emptyMap
|
|
318
|
+
active <- getp fopts "active"
|
|
319
|
+
when (isTrueV active) (fInit f ctx fopts)
|
|
320
|
+
|
|
321
|
+
-- ----- prepare / param -----
|
|
322
|
+
|
|
323
|
+
-- The API definition is authoritative: a POST-only or PATCH-based API
|
|
324
|
+
-- exposes `update` as POST or PATCH, not the PUT the op name implies. Only
|
|
325
|
+
-- fall back to the op-name convention when the point has no method.
|
|
326
|
+
prepareMethodUtil :: Context -> IO String
|
|
327
|
+
prepareMethodUtil ctx = do
|
|
328
|
+
point <- readIORef (cPoint ctx)
|
|
329
|
+
pm <- getp point "method"
|
|
330
|
+
case pm of
|
|
331
|
+
VStr m | not (null m) -> pure (map toUpper m)
|
|
332
|
+
_ -> do
|
|
333
|
+
op <- readIORef (cOp ctx)
|
|
334
|
+
pure $ case opName op of
|
|
335
|
+
"create" -> "POST"; "update" -> "PUT"; "load" -> "GET"
|
|
336
|
+
"list" -> "GET"; "remove" -> "DELETE"; "patch" -> "PATCH"
|
|
337
|
+
-- NO CATCH-ALL GET. The ts reference returns methodMap[key], which is
|
|
338
|
+
-- undefined for an op the map does not name — the request is then
|
|
339
|
+
-- rejected rather than silently issued. A `_ -> "GET"` here turned
|
|
340
|
+
-- every unrecognised op into a GET, which is both a divergence from
|
|
341
|
+
-- the corpus (which expects no method for opname "bad") and the more
|
|
342
|
+
-- dangerous of the two behaviours: a mistyped or unsupported op
|
|
343
|
+
-- quietly fetched. Found by the primary corpus on its first run.
|
|
344
|
+
_ -> ""
|
|
345
|
+
|
|
346
|
+
prepareHeadersUtil :: Context -> IO Value
|
|
347
|
+
prepareHeadersUtil ctx = do
|
|
348
|
+
cl <- cc ctx
|
|
349
|
+
options <- clientOptionsMap cl
|
|
350
|
+
h <- getp options "headers"
|
|
351
|
+
case h of
|
|
352
|
+
VNoval -> emptyMap
|
|
353
|
+
_ -> do c <- clone h; case c of VMap _ -> pure c; _ -> emptyMap
|
|
354
|
+
|
|
355
|
+
paramUtil :: Context -> Value -> IO Value
|
|
356
|
+
paramUtil ctx paramdef = do
|
|
357
|
+
point <- readIORef (cPoint ctx)
|
|
358
|
+
specV <- readIORef (cSpec ctx)
|
|
359
|
+
mtch <- readIORef (cMatch ctx)
|
|
360
|
+
reqmatch <- readIORef (cReqmatch ctx)
|
|
361
|
+
dat <- readIORef (cData ctx)
|
|
362
|
+
reqdata <- readIORef (cReqdata ctx)
|
|
363
|
+
key <- case paramdef of VStr s -> pure s; _ -> getStrD paramdef "name" ""
|
|
364
|
+
aliasV <- getp point "alias"
|
|
365
|
+
akey <- case aliasV of VMap _ -> getStrD aliasV key ""; _ -> pure ""
|
|
366
|
+
let orElse v act = if isNoval v then act else pure v
|
|
367
|
+
v1 <- getp reqmatch key
|
|
368
|
+
v2 <- orElse v1 (getp mtch key)
|
|
369
|
+
v3 <- if isNoval v2 && not (null akey)
|
|
370
|
+
then do
|
|
371
|
+
case specV of
|
|
372
|
+
VMap _ -> do sa <- getp specV "alias"; setp sa akey (VStr key)
|
|
373
|
+
_ -> pure ()
|
|
374
|
+
getp reqmatch akey
|
|
375
|
+
else pure v2
|
|
376
|
+
v4 <- orElse v3 (getp reqdata key)
|
|
377
|
+
v5 <- orElse v4 (getp dat key)
|
|
378
|
+
if isNoval v5 && not (null akey)
|
|
379
|
+
then do a <- getp reqdata akey; orElse a (getp dat akey)
|
|
380
|
+
else pure v5
|
|
381
|
+
|
|
382
|
+
prepareParamsUtil :: Context -> IO Value
|
|
383
|
+
prepareParamsUtil ctx = do
|
|
384
|
+
point <- readIORef (cPoint ctx)
|
|
385
|
+
args <- getp point "args"
|
|
386
|
+
params <- case args of
|
|
387
|
+
VMap _ -> do p <- getp args "params"; case p of VList _ -> listItems p; _ -> pure []
|
|
388
|
+
_ -> pure []
|
|
389
|
+
out <- emptyMap
|
|
390
|
+
u <- cu ctx
|
|
391
|
+
pfn <- readIORef (uParam u)
|
|
392
|
+
forM_ params $ \pd -> do
|
|
393
|
+
v <- pfn ctx pd
|
|
394
|
+
when (not (isNoval v)) $
|
|
395
|
+
case pd of
|
|
396
|
+
VMap _ -> do nm <- getStrD pd "name" ""; when (nm /= "") (setp out nm v)
|
|
397
|
+
_ -> pure ()
|
|
398
|
+
pure out
|
|
399
|
+
|
|
400
|
+
preparePathUtil :: Context -> IO String
|
|
401
|
+
preparePathUtil ctx = do
|
|
402
|
+
point <- readIORef (cPoint ctx)
|
|
403
|
+
p <- getp point "parts"
|
|
404
|
+
parts <- case p of VList _ -> pure p; _ -> emptyList
|
|
405
|
+
join_ parts
|
|
406
|
+
|
|
407
|
+
prepareQueryUtil :: Context -> IO Value
|
|
408
|
+
prepareQueryUtil ctx = do
|
|
409
|
+
point <- readIORef (cPoint ctx)
|
|
410
|
+
rmV <- readIORef (cReqmatch ctx)
|
|
411
|
+
reqmatch <- case rmV of VMap _ -> pure rmV; _ -> emptyMap
|
|
412
|
+
pl <- getp point "params"
|
|
413
|
+
params <- case pl of VList _ -> listItems pl; _ -> pure []
|
|
414
|
+
let containsParam s = any (\v -> case v of VStr x -> x == s; _ -> False) params
|
|
415
|
+
out <- emptyMap
|
|
416
|
+
ks <- keysof reqmatch
|
|
417
|
+
forM_ ks $ \k -> do
|
|
418
|
+
v <- getp reqmatch k
|
|
419
|
+
when (not (isNoval v) && not (containsParam k)) (setp out k v)
|
|
420
|
+
pure out
|
|
421
|
+
|
|
422
|
+
prepareBodyUtil :: Context -> IO Value
|
|
423
|
+
prepareBodyUtil ctx = do
|
|
424
|
+
op <- readIORef (cOp ctx)
|
|
425
|
+
if opInput op == "data" then transformRequestUtil ctx else pure VNoval
|
|
426
|
+
|
|
427
|
+
-- ------------------------------------------------------------------
|
|
428
|
+
-- graphql (transport)
|
|
429
|
+
--
|
|
430
|
+
-- GraphQL transport. API-INDEPENDENT: every GraphQL SDK this generator
|
|
431
|
+
-- produces uses this code unchanged. The API-specific part — which
|
|
432
|
+
-- operations exist and what each one's document is — is model data, computed
|
|
433
|
+
-- once by apidef and emitted into Config.
|
|
434
|
+
--
|
|
435
|
+
-- Two jobs:
|
|
436
|
+
--
|
|
437
|
+
-- graphqlBodyUtil — build { query, variables } for a point, binding the
|
|
438
|
+
-- op's arguments to the document's declared variables.
|
|
439
|
+
--
|
|
440
|
+
-- graphqlErrorsUtil — lift a GraphQL failure into an SDK error. GraphQL
|
|
441
|
+
-- reports failures as a top-level `errors` array under
|
|
442
|
+
-- HTTP 200, so the status-driven path in resultBasic
|
|
443
|
+
-- never sees them.
|
|
444
|
+
-- ------------------------------------------------------------------
|
|
445
|
+
|
|
446
|
+
-- Content type every GraphQL-over-HTTP request uses.
|
|
447
|
+
graphqlContentType :: String
|
|
448
|
+
graphqlContentType = "application/json"
|
|
449
|
+
|
|
450
|
+
-- Map a GraphQL error to the same error codes the HTTP path produces, so a
|
|
451
|
+
-- caller handles auth or rate limiting identically on both transports.
|
|
452
|
+
-- Servers put the machine-readable code in `extensions.code`; Linear-style
|
|
453
|
+
-- APIs use `extensions.type`.
|
|
454
|
+
graphqlErrorCode :: Value -> IO String
|
|
455
|
+
graphqlErrorCode gqlerr = do
|
|
456
|
+
ext <- getp gqlerr "extensions"
|
|
457
|
+
c0 <- getStrD ext "code" ""
|
|
458
|
+
code <- if null c0 then getStrD ext "type" "" else pure c0
|
|
459
|
+
let raw = map toUpper code
|
|
460
|
+
pure $
|
|
461
|
+
if substrContains raw "AUTH" || substrContains raw "FORBIDDEN"
|
|
462
|
+
|| substrContains raw "UNAUTHENTICATED"
|
|
463
|
+
then "request_auth"
|
|
464
|
+
else if substrContains raw "RATELIMIT" || substrContains raw "RATE_LIMIT"
|
|
465
|
+
|| substrContains raw "TOO_MANY"
|
|
466
|
+
then "request_ratelimit"
|
|
467
|
+
else if substrContains raw "BAD_USER_INPUT"
|
|
468
|
+
|| substrContains raw "VALIDATION"
|
|
469
|
+
|| substrContains raw "INVALID"
|
|
470
|
+
then "request_invalid"
|
|
471
|
+
else "request_graphql"
|
|
472
|
+
|
|
473
|
+
-- Build the request body for a GraphQL point.
|
|
474
|
+
--
|
|
475
|
+
-- Variables come from the op's own arguments: a named variable binds to the
|
|
476
|
+
-- like-named argument (`from`), and the input-object variable (empty `from`)
|
|
477
|
+
-- takes the request data as a whole — which is what makes a generated
|
|
478
|
+
-- create/update call look exactly like its REST equivalent.
|
|
479
|
+
graphqlBodyUtil :: Context -> IO Value
|
|
480
|
+
graphqlBodyUtil ctx = do
|
|
481
|
+
point <- readIORef (cPoint ctx)
|
|
482
|
+
gql <- getp point "graphql"
|
|
483
|
+
case gql of
|
|
484
|
+
VMap _ -> do
|
|
485
|
+
-- reqmatch/reqdata hold the caller's arguments for THIS call;
|
|
486
|
+
-- data/match hold the entity's current state. Which pair depends on
|
|
487
|
+
-- whether the op takes match or data input. A named variable falls
|
|
488
|
+
-- back to the current state, so updating a loaded entity with just
|
|
489
|
+
-- {title} still binds the stored id the mutation requires.
|
|
490
|
+
op <- readIORef (cOp ctx)
|
|
491
|
+
let datainput = opInput op == "data"
|
|
492
|
+
rsV <- readIORef (if datainput then cReqdata ctx else cReqmatch ctx)
|
|
493
|
+
dsV <- readIORef (if datainput then cData ctx else cMatch ctx)
|
|
494
|
+
reqsrc <- case rsV of VMap _ -> pure rsV; _ -> emptyMap
|
|
495
|
+
datasrc <- case dsV of VMap _ -> pure dsV; _ -> emptyMap
|
|
496
|
+
variables <- emptyMap
|
|
497
|
+
vl <- getp gql "vars"
|
|
498
|
+
varlist <- case vl of VList _ -> listItems vl; _ -> pure []
|
|
499
|
+
forM_ varlist $ \spec -> case spec of
|
|
500
|
+
VMap _ -> do
|
|
501
|
+
name <- getStrD spec "name" ""
|
|
502
|
+
from <- getStrD spec "from" ""
|
|
503
|
+
when (not (null name)) $
|
|
504
|
+
if null from
|
|
505
|
+
then do
|
|
506
|
+
-- The input object IS the request body. Strip the action
|
|
507
|
+
-- selector, which is an SDK-side point discriminator, not an
|
|
508
|
+
-- API field.
|
|
509
|
+
body <- emptyMap
|
|
510
|
+
ks <- keysof reqsrc
|
|
511
|
+
forM_ ks $ \k -> when (k /= "$action") $ do
|
|
512
|
+
v <- getp reqsrc k
|
|
513
|
+
setp body k v
|
|
514
|
+
setp variables name body
|
|
515
|
+
else do
|
|
516
|
+
-- Only send variables the caller actually supplied: sending
|
|
517
|
+
-- an explicit null would clear a field on many APIs.
|
|
518
|
+
v0 <- getp reqsrc from
|
|
519
|
+
val <- if isNullish v0 then getp datasrc from else pure v0
|
|
520
|
+
when (not (isNullish val)) (setp variables name val)
|
|
521
|
+
_ -> pure ()
|
|
522
|
+
doc <- getp gql "doc"
|
|
523
|
+
jo [("query", doc), ("variables", variables)]
|
|
524
|
+
_ -> pure VNoval
|
|
525
|
+
|
|
526
|
+
-- Inspect a decoded GraphQL response body and record a failure when the
|
|
527
|
+
-- server reported one. Returns True when an error was recorded.
|
|
528
|
+
--
|
|
529
|
+
-- Partial data (`data` alongside `errors`) is treated as failure: the REST
|
|
530
|
+
-- surface has no partial-success concept, and silently returning half an
|
|
531
|
+
-- object would be worse than failing.
|
|
532
|
+
graphqlErrorsUtil :: Context -> IO Bool
|
|
533
|
+
graphqlErrorsUtil ctx = do
|
|
534
|
+
resultV <- readIORef (cResult ctx)
|
|
535
|
+
point <- readIORef (cPoint ctx)
|
|
536
|
+
kind <- getStrD point "kind" ""
|
|
537
|
+
case resultV of
|
|
538
|
+
VMap _ | kind == "graphql" -> do
|
|
539
|
+
body <- getp resultV "body"
|
|
540
|
+
ev <- getp body "errors"
|
|
541
|
+
errors <- case ev of VList _ -> listItems ev; _ -> pure []
|
|
542
|
+
if null errors
|
|
543
|
+
then pure False
|
|
544
|
+
else do
|
|
545
|
+
let firsterr = head errors
|
|
546
|
+
n = length errors
|
|
547
|
+
m0 <- getStrD firsterr "message" ""
|
|
548
|
+
let m1 = if null m0 then "graphql error" else m0
|
|
549
|
+
msg = if 1 < n then m1 ++ " (+" ++ show (n - 1) ++ " more)" else m1
|
|
550
|
+
code <- graphqlErrorCode firsterr
|
|
551
|
+
e <- mkErr code ("graphql: " ++ msg)
|
|
552
|
+
setp resultV "err" e
|
|
553
|
+
setp resultV "ok" (VBool False)
|
|
554
|
+
pure True
|
|
555
|
+
_ -> pure False
|
|
556
|
+
|
|
557
|
+
prepareAuthUtil :: Context -> UResult
|
|
558
|
+
prepareAuthUtil ctx = do
|
|
559
|
+
specV <- readIORef (cSpec ctx)
|
|
560
|
+
case specV of
|
|
561
|
+
VMap _ -> do
|
|
562
|
+
headers <- getp specV "headers"
|
|
563
|
+
cl <- cc ctx
|
|
564
|
+
options <- clientOptionsMap cl
|
|
565
|
+
authv <- getp options "auth"
|
|
566
|
+
case authv of
|
|
567
|
+
VNoval -> do delp headers "authorization"; pure (specV, Nothing)
|
|
568
|
+
VNull -> do delp headers "authorization"; pure (specV, Nothing)
|
|
569
|
+
_ -> do
|
|
570
|
+
apikey <- getpropAlt (VStr "__NOTFOUND__") options (VStr "apikey")
|
|
571
|
+
let isNotFound = case apikey of VStr "__NOTFOUND__" -> True; _ -> False
|
|
572
|
+
apikeyStr = case apikey of VStr s -> s; _ -> ""
|
|
573
|
+
if isNotFound || isNoval apikey || apikeyStr == ""
|
|
574
|
+
then do delp headers "authorization"; pure (specV, Nothing)
|
|
575
|
+
else do
|
|
576
|
+
apV <- getpathS options "auth.prefix"
|
|
577
|
+
let authPrefix = case apV of VStr s -> s; _ -> ""
|
|
578
|
+
authval = if authPrefix /= "" then authPrefix ++ " " ++ apikeyStr else apikeyStr
|
|
579
|
+
setp headers "authorization" (VStr authval)
|
|
580
|
+
pure (specV, Nothing)
|
|
581
|
+
_ -> do e <- mkErr "auth_no_spec" "Expected context spec property to be defined."; pure (VNoval, Just e)
|
|
582
|
+
|
|
583
|
+
-- ----- transforms / result helpers -----
|
|
584
|
+
|
|
585
|
+
transformRequestUtil :: Context -> IO Value
|
|
586
|
+
transformRequestUtil ctx = do
|
|
587
|
+
specV <- readIORef (cSpec ctx)
|
|
588
|
+
case specV of VMap _ -> setp specV "step" (VStr "reqform"); _ -> pure ()
|
|
589
|
+
point <- readIORef (cPoint ctx)
|
|
590
|
+
reqdata <- readIORef (cReqdata ctx)
|
|
591
|
+
tr <- toMap <$> getp point "transform"
|
|
592
|
+
case tr of
|
|
593
|
+
VMap _ -> do
|
|
594
|
+
reqform <- getp tr "req"
|
|
595
|
+
case reqform of
|
|
596
|
+
VNoval -> pure reqdata
|
|
597
|
+
_ -> do input <- jo [("reqdata", reqdata)]; transform INone input reqform
|
|
598
|
+
_ -> pure reqdata
|
|
599
|
+
|
|
600
|
+
transformResponseUtil :: Context -> IO Value
|
|
601
|
+
transformResponseUtil ctx = do
|
|
602
|
+
specV <- readIORef (cSpec ctx)
|
|
603
|
+
case specV of VMap _ -> setp specV "step" (VStr "resform"); _ -> pure ()
|
|
604
|
+
resultV <- readIORef (cResult ctx)
|
|
605
|
+
case resultV of
|
|
606
|
+
VMap _ -> do
|
|
607
|
+
ok <- getp resultV "ok"
|
|
608
|
+
if not (isTrueV ok) then pure VNoval
|
|
609
|
+
else do
|
|
610
|
+
point <- readIORef (cPoint ctx)
|
|
611
|
+
tr <- toMap <$> getp point "transform"
|
|
612
|
+
case tr of
|
|
613
|
+
VMap _ -> do
|
|
614
|
+
resform <- getp tr "res"
|
|
615
|
+
case resform of
|
|
616
|
+
VNoval -> pure VNoval
|
|
617
|
+
_ -> do
|
|
618
|
+
status <- getp resultV "status"
|
|
619
|
+
st <- getp resultV "statusText"
|
|
620
|
+
hdr <- getp resultV "headers"
|
|
621
|
+
body <- getp resultV "body"
|
|
622
|
+
errv <- getp resultV "err"
|
|
623
|
+
isE <- isErr errv
|
|
624
|
+
errOut <- if isE then do m <- getp errv "message"; jo [("message", m)] else pure VNoval
|
|
625
|
+
resdata <- getp resultV "resdata"
|
|
626
|
+
resmatch <- getp resultV "resmatch"
|
|
627
|
+
input <- jo [ ("ok", ok), ("status", status), ("statusText", st)
|
|
628
|
+
, ("headers", hdr), ("body", body), ("err", errOut)
|
|
629
|
+
, ("resdata", resdata), ("resmatch", resmatch) ]
|
|
630
|
+
rd <- transform INone input resform
|
|
631
|
+
setp resultV "resdata" rd
|
|
632
|
+
pure rd
|
|
633
|
+
_ -> pure VNoval
|
|
634
|
+
_ -> pure VNoval
|
|
635
|
+
|
|
636
|
+
resultBasicUtil :: Context -> IO ()
|
|
637
|
+
resultBasicUtil ctx = do
|
|
638
|
+
responseV <- readIORef (cResponse ctx)
|
|
639
|
+
resultV <- readIORef (cResult ctx)
|
|
640
|
+
case (responseV, resultV) of
|
|
641
|
+
(VMap _, VMap _) -> do
|
|
642
|
+
st <- getp responseV "status"
|
|
643
|
+
stt <- getp responseV "statusText"
|
|
644
|
+
setp resultV "status" st
|
|
645
|
+
setp resultV "statusText" stt
|
|
646
|
+
let status = toInt st
|
|
647
|
+
sttext = case stt of VStr s -> s; _ -> ""
|
|
648
|
+
if status >= 400
|
|
649
|
+
then do
|
|
650
|
+
let msg = "request: " ++ show status ++ ": " ++ sttext
|
|
651
|
+
prev <- getp resultV "err"
|
|
652
|
+
isE <- isErr prev
|
|
653
|
+
if isE
|
|
654
|
+
then do pm <- errMsg prev; e <- mkErr "request_status" (pm ++ ": " ++ msg); setp resultV "err" e
|
|
655
|
+
else do e <- mkErr "request_status" msg; setp resultV "err" e
|
|
656
|
+
else do
|
|
657
|
+
re <- getp responseV "err"
|
|
658
|
+
isE <- isErr re
|
|
659
|
+
when isE (setp resultV "err" re)
|
|
660
|
+
_ -> pure ()
|
|
661
|
+
|
|
662
|
+
resultBodyUtil :: Context -> IO ()
|
|
663
|
+
resultBodyUtil ctx = do
|
|
664
|
+
responseV <- readIORef (cResponse ctx)
|
|
665
|
+
resultV <- readIORef (cResult ctx)
|
|
666
|
+
case (responseV, resultV) of
|
|
667
|
+
(VMap _, VMap _) -> do
|
|
668
|
+
jsn <- getp responseV "json"
|
|
669
|
+
body <- getp responseV "body"
|
|
670
|
+
when (isCallable jsn && not (isNoval body)) $ do
|
|
671
|
+
d <- callJson jsn
|
|
672
|
+
setp resultV "body" d
|
|
673
|
+
_ -> pure ()
|
|
674
|
+
|
|
675
|
+
resultHeadersUtil :: Context -> IO ()
|
|
676
|
+
resultHeadersUtil ctx = do
|
|
677
|
+
resultV <- readIORef (cResult ctx)
|
|
678
|
+
case resultV of
|
|
679
|
+
VMap _ -> do
|
|
680
|
+
responseV <- readIORef (cResponse ctx)
|
|
681
|
+
case responseV of
|
|
682
|
+
VMap _ -> do
|
|
683
|
+
h <- getp responseV "headers"
|
|
684
|
+
case h of VMap _ -> setp resultV "headers" h; _ -> do em <- emptyMap; setp resultV "headers" em
|
|
685
|
+
_ -> do em <- emptyMap; setp resultV "headers" em
|
|
686
|
+
_ -> pure ()
|
|
687
|
+
|
|
688
|
+
-- ----- make_* pipeline stages -----
|
|
689
|
+
|
|
690
|
+
makePointUtil :: Context -> UResult
|
|
691
|
+
makePointUtil ctx = do
|
|
692
|
+
out <- readIORef (cOut ctx)
|
|
693
|
+
pre <- getp out "point"
|
|
694
|
+
isE <- isErr pre
|
|
695
|
+
if isE then pure (VNoval, Just pre)
|
|
696
|
+
else case pre of
|
|
697
|
+
VMap _ -> do writeIORef (cPoint ctx) pre; pure (pre, Nothing)
|
|
698
|
+
_ -> do
|
|
699
|
+
op <- readIORef (cOp ctx)
|
|
700
|
+
options <- readIORef (cOptions ctx)
|
|
701
|
+
av <- getpathS options "allow.op"
|
|
702
|
+
let allowOp = case av of VStr s -> s; _ -> ""
|
|
703
|
+
if not (substrContains allowOp (opName op))
|
|
704
|
+
then do
|
|
705
|
+
e <- mkErr "point_op_allow"
|
|
706
|
+
("Operation \"" ++ opName op ++ "\" not allowed by SDK option allow.op value: \"" ++ allowOp ++ "\"")
|
|
707
|
+
pure (VNoval, Just e)
|
|
708
|
+
else do
|
|
709
|
+
pts <- listItems (opPoints op)
|
|
710
|
+
case pts of
|
|
711
|
+
[] -> do e <- mkErr "point_no_points" ("Operation \"" ++ opName op ++ "\" has no endpoint definitions."); pure (VNoval, Just e)
|
|
712
|
+
[single] -> do writeIORef (cPoint ctx) single; pure (single, Nothing)
|
|
713
|
+
_ -> do
|
|
714
|
+
(reqsel, sel) <- if opInput op == "data"
|
|
715
|
+
then (,) <$> readIORef (cReqdata ctx) <*> readIORef (cData ctx)
|
|
716
|
+
else (,) <$> readIORef (cReqmatch ctx) <*> readIORef (cMatch ctx)
|
|
717
|
+
let isFound pt = do
|
|
718
|
+
selectDef <- toMap <$> getp pt "select"
|
|
719
|
+
existOk <- case selectDef of
|
|
720
|
+
VMap _ -> do
|
|
721
|
+
exist <- getp selectDef "exist"
|
|
722
|
+
case exist of
|
|
723
|
+
VList _ -> do
|
|
724
|
+
eks <- listItems exist
|
|
725
|
+
let chk found ek = if not found then pure False else do
|
|
726
|
+
let existkey = vstring ek
|
|
727
|
+
rv <- getp reqsel existkey; sv <- getp sel existkey
|
|
728
|
+
pure (not (isNoval rv && isNoval sv))
|
|
729
|
+
foldMB True chk eks
|
|
730
|
+
_ -> pure True
|
|
731
|
+
_ -> pure True
|
|
732
|
+
if not existOk then pure False
|
|
733
|
+
else do
|
|
734
|
+
reqAction <- getp reqsel "$action"
|
|
735
|
+
selectAction <- getp selectDef "$action"
|
|
736
|
+
pure (valEqScalar reqAction selectAction)
|
|
737
|
+
findMatch [] = pure Nothing
|
|
738
|
+
findMatch (pt : rest) = do
|
|
739
|
+
f <- isFound pt
|
|
740
|
+
if f then pure (Just pt) else findMatch rest
|
|
741
|
+
-- A record route ends in the record's identifier
|
|
742
|
+
-- (/boards/{id}); a cross-reference that also returns the
|
|
743
|
+
-- entity ends in the relationship's name
|
|
744
|
+
-- (/posts/{id}/author). That, then fewest segments, tells
|
|
745
|
+
-- the entity's own route from a cross-reference. The same
|
|
746
|
+
-- rule runs at generation time, in helpers/opShape.ts —
|
|
747
|
+
-- both sides must move together.
|
|
748
|
+
ptsLen pt = do
|
|
749
|
+
parts <- getp pt "parts"
|
|
750
|
+
case parts of
|
|
751
|
+
VList _ -> length <$> listItems parts
|
|
752
|
+
_ -> pure (0 :: Int)
|
|
753
|
+
terminalParam pt = do
|
|
754
|
+
parts <- getp pt "parts"
|
|
755
|
+
case parts of
|
|
756
|
+
VList _ -> do
|
|
757
|
+
items <- listItems parts
|
|
758
|
+
pure (case reverse items of
|
|
759
|
+
(lastp : _) -> case vstring lastp of
|
|
760
|
+
('{' : _) -> True
|
|
761
|
+
_ -> False
|
|
762
|
+
[] -> False)
|
|
763
|
+
_ -> pure False
|
|
764
|
+
betterOwn cand best = do
|
|
765
|
+
ct <- terminalParam cand
|
|
766
|
+
bt <- terminalParam best
|
|
767
|
+
if ct /= bt
|
|
768
|
+
then pure ct
|
|
769
|
+
else do
|
|
770
|
+
cl <- ptsLen cand
|
|
771
|
+
bl <- ptsLen best
|
|
772
|
+
pure (cl < bl)
|
|
773
|
+
ownPoint [] = pure VNoval
|
|
774
|
+
ownPoint (p0 : rest0) = go p0 rest0
|
|
775
|
+
where go best [] = pure best
|
|
776
|
+
go best (c : cs) = do
|
|
777
|
+
b <- betterOwn c best
|
|
778
|
+
go (if b then c else best) cs
|
|
779
|
+
matched <- findMatch pts
|
|
780
|
+
reqAction <- getp reqsel "$action"
|
|
781
|
+
chosen <- maybe (ownPoint pts) pure matched
|
|
782
|
+
-- select.exist can list more than the params needed to pick a
|
|
783
|
+
-- point, so nothing matched. A request naming an action gets
|
|
784
|
+
-- here only because that action's own point failed its exist
|
|
785
|
+
-- test, so it is unbuildable whatever we pick — refuse it
|
|
786
|
+
-- BEFORE the guard below, which compares the chosen point's
|
|
787
|
+
-- $action and would wave the request through whenever the
|
|
788
|
+
-- fallback lands on the action point itself.
|
|
789
|
+
if isNothing matched && not (isNoval reqAction)
|
|
790
|
+
then do
|
|
791
|
+
e <- mkErr "point_action_invalid" ("Operation \"" ++ opName op ++ "\" action \"" ++ vstring reqAction ++ "\" is not valid.")
|
|
792
|
+
pure (VNoval, Just e)
|
|
793
|
+
else if not (isNoval reqAction) && not (isNoval chosen)
|
|
794
|
+
then do
|
|
795
|
+
pointSelect <- toMap <$> getp chosen "select"
|
|
796
|
+
pointAction <- getp pointSelect "$action"
|
|
797
|
+
if not (valEqScalar reqAction pointAction)
|
|
798
|
+
then do e <- mkErr "point_action_invalid" ("Operation \"" ++ opName op ++ "\" action \"" ++ vstring reqAction ++ "\" is not valid."); pure (VNoval, Just e)
|
|
799
|
+
else do writeIORef (cPoint ctx) chosen; pure (chosen, Nothing)
|
|
800
|
+
else do writeIORef (cPoint ctx) chosen; pure (chosen, Nothing)
|
|
801
|
+
|
|
802
|
+
foldMB :: Bool -> (Bool -> a -> IO Bool) -> [a] -> IO Bool
|
|
803
|
+
foldMB acc _ [] = pure acc
|
|
804
|
+
foldMB acc f (x : xs) = do acc' <- f acc x; foldMB acc' f xs
|
|
805
|
+
|
|
806
|
+
makeSpecUtil :: Context -> UResult
|
|
807
|
+
makeSpecUtil ctx = do
|
|
808
|
+
out <- readIORef (cOut ctx)
|
|
809
|
+
pre <- getp out "spec"
|
|
810
|
+
isE <- isErr pre
|
|
811
|
+
if isE then pure (VNoval, Just pre)
|
|
812
|
+
else case pre of
|
|
813
|
+
VMap _ -> do writeIORef (cSpec ctx) pre; pure (pre, Nothing)
|
|
814
|
+
_ -> do
|
|
815
|
+
options <- readIORef (cOptions ctx)
|
|
816
|
+
base <- getStrD options "base" ""
|
|
817
|
+
prefix <- getStrD options "prefix" ""
|
|
818
|
+
suffix <- getStrD options "suffix" ""
|
|
819
|
+
point <- readIORef (cPoint ctx)
|
|
820
|
+
p <- getp point "parts"
|
|
821
|
+
parts <- case p of VList _ -> pure p; _ -> emptyList
|
|
822
|
+
specm <- jo [("base", VStr base), ("prefix", VStr prefix), ("parts", parts), ("suffix", VStr suffix), ("step", VStr "start")]
|
|
823
|
+
sp <- newSpec specm
|
|
824
|
+
writeIORef (cSpec ctx) sp
|
|
825
|
+
method <- prepareMethodUtil ctx
|
|
826
|
+
setp sp "method" (VStr method)
|
|
827
|
+
amv <- getpathS options "allow.method"
|
|
828
|
+
let allowMethod = case amv of VStr s -> s; _ -> ""
|
|
829
|
+
if not (substrContains allowMethod method)
|
|
830
|
+
then do e <- mkErr "spec_method_allow" ("Method \"" ++ method ++ "\" not allowed by SDK option allow.method value: \"" ++ allowMethod ++ "\""); pure (VNoval, Just e)
|
|
831
|
+
else do
|
|
832
|
+
params <- prepareParamsUtil ctx; setp sp "params" params
|
|
833
|
+
query <- prepareQueryUtil ctx; setp sp "query" query
|
|
834
|
+
headers <- prepareHeadersUtil ctx; setp sp "headers" headers
|
|
835
|
+
kind <- getStrD point "kind" ""
|
|
836
|
+
if kind == "graphql"
|
|
837
|
+
-- GraphQL addresses one endpoint: no path parts, no query string,
|
|
838
|
+
-- and the body carries the operation. prepareBody is skipped
|
|
839
|
+
-- deliberately — it only emits a body for data-input ops, whereas
|
|
840
|
+
-- every GraphQL op posts one, including load/list/remove.
|
|
841
|
+
then do
|
|
842
|
+
body <- graphqlBodyUtil ctx; setp sp "body" body
|
|
843
|
+
setp sp "path" (VStr "")
|
|
844
|
+
-- prepareQuery already copied the op's match arguments into the
|
|
845
|
+
-- query string. Those same values are bound as operation
|
|
846
|
+
-- variables, so leaving them would send /graphql?id=i1.
|
|
847
|
+
emptyq <- emptyMap; setp sp "query" emptyq
|
|
848
|
+
setp headers "content-type" (VStr graphqlContentType)
|
|
849
|
+
else do
|
|
850
|
+
body <- prepareBodyUtil ctx; setp sp "body" body
|
|
851
|
+
path <- preparePathUtil ctx; setp sp "path" (VStr path)
|
|
852
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
853
|
+
explain <- getp ctrl "explain"
|
|
854
|
+
case explain of { VMap _ -> do { snap <- specToValue sp; setp explain "spec" snap }; _ -> pure () }
|
|
855
|
+
(sp2, merr) <- prepareAuthUtil ctx
|
|
856
|
+
case merr of
|
|
857
|
+
Just e -> pure (VNoval, Just e)
|
|
858
|
+
Nothing -> do writeIORef (cSpec ctx) sp2; pure (sp2, Nothing)
|
|
859
|
+
|
|
860
|
+
makeUrlUtil :: Context -> UResult
|
|
861
|
+
makeUrlUtil ctx = do
|
|
862
|
+
specV <- readIORef (cSpec ctx)
|
|
863
|
+
resultV <- readIORef (cResult ctx)
|
|
864
|
+
case specV of
|
|
865
|
+
VMap _ -> case resultV of
|
|
866
|
+
VMap _ -> do
|
|
867
|
+
base <- getStrD specV "base" ""
|
|
868
|
+
prefix <- getStrD specV "prefix" ""
|
|
869
|
+
path <- getStrD specV "path" ""
|
|
870
|
+
suffix <- getStrD specV "suffix" ""
|
|
871
|
+
arr <- ja [VStr base, VStr prefix, VStr path, VStr suffix]
|
|
872
|
+
url0 <- join_ arr
|
|
873
|
+
resmatch <- emptyMap
|
|
874
|
+
params <- getp specV "params"
|
|
875
|
+
pks <- keysof params
|
|
876
|
+
url1 <- foldMS url0 pks $ \u k -> do
|
|
877
|
+
v <- getp params k
|
|
878
|
+
if isNoval v then pure u
|
|
879
|
+
else do enc <- escurlS (vstring v); setp resmatch k v; pure (strReplaceAll u ("{" ++ k ++ "}") enc)
|
|
880
|
+
query <- getp specV "query"
|
|
881
|
+
qks <- keysof query
|
|
882
|
+
(url2, _) <- foldMS2 (url1, "?") qks $ \(u, qsep) k -> do
|
|
883
|
+
v <- getp query k
|
|
884
|
+
if isNoval v then pure (u, qsep)
|
|
885
|
+
else do ek <- escurlS k; ev <- escurlS (vstring v); setp resmatch k v; pure (u ++ qsep ++ ek ++ "=" ++ ev, "&")
|
|
886
|
+
setp resultV "resmatch" resmatch
|
|
887
|
+
pure (VStr url2, Nothing)
|
|
888
|
+
_ -> do e <- mkErr "url_no_result" "Expected context result property to be defined."; pure (VStr "", Just e)
|
|
889
|
+
_ -> do e <- mkErr "url_no_spec" "Expected context spec property to be defined."; pure (VStr "", Just e)
|
|
890
|
+
|
|
891
|
+
foldMS :: b -> [a] -> (b -> a -> IO b) -> IO b
|
|
892
|
+
foldMS z xs f = go z xs where go acc [] = pure acc; go acc (y : ys) = do acc' <- f acc y; go acc' ys
|
|
893
|
+
|
|
894
|
+
foldMS2 :: (b, c) -> [a] -> ((b, c) -> a -> IO (b, c)) -> IO (b, c)
|
|
895
|
+
foldMS2 z xs f = go z xs where go acc [] = pure acc; go acc (y : ys) = do acc' <- f acc y; go acc' ys
|
|
896
|
+
|
|
897
|
+
makeFetchDefUtil :: Context -> UResult
|
|
898
|
+
makeFetchDefUtil ctx = do
|
|
899
|
+
specV <- readIORef (cSpec ctx)
|
|
900
|
+
case specV of
|
|
901
|
+
VMap _ -> do
|
|
902
|
+
resultV <- readIORef (cResult ctx)
|
|
903
|
+
case resultV of VMap _ -> pure (); _ -> do r <- newResult =<< emptyMap; writeIORef (cResult ctx) r
|
|
904
|
+
setp specV "step" (VStr "prepare")
|
|
905
|
+
(urlV, merr) <- makeUrlUtil ctx
|
|
906
|
+
case merr of
|
|
907
|
+
Just e -> pure (VNoval, Just e)
|
|
908
|
+
Nothing -> do
|
|
909
|
+
let url = vstring urlV
|
|
910
|
+
setp specV "url" (VStr url)
|
|
911
|
+
method <- getStrD specV "method" "GET"
|
|
912
|
+
headers <- getp specV "headers"
|
|
913
|
+
fetchdef <- jo [("url", VStr url), ("method", VStr method), ("headers", headers)]
|
|
914
|
+
body <- getp specV "body"
|
|
915
|
+
case body of
|
|
916
|
+
VNoval -> pure ()
|
|
917
|
+
VMap _ -> do bs <- jsonifyCompact body; setp fetchdef "body" (VStr bs)
|
|
918
|
+
_ -> setp fetchdef "body" body
|
|
919
|
+
pure (fetchdef, Nothing)
|
|
920
|
+
_ -> do e <- mkErr "fetchdef_no_spec" "Expected context spec property to be defined."; pure (VNoval, Just e)
|
|
921
|
+
|
|
922
|
+
makeRequestUtil :: Context -> UResult
|
|
923
|
+
makeRequestUtil ctx = do
|
|
924
|
+
out <- readIORef (cOut ctx)
|
|
925
|
+
pre <- getp out "request"
|
|
926
|
+
isE <- isErr pre
|
|
927
|
+
if isE then pure (VNoval, Just pre)
|
|
928
|
+
else case pre of
|
|
929
|
+
VMap _ -> pure (pre, Nothing)
|
|
930
|
+
_ -> do
|
|
931
|
+
response0 <- newResponse =<< emptyMap
|
|
932
|
+
result <- newResult =<< emptyMap
|
|
933
|
+
writeIORef (cResult ctx) result
|
|
934
|
+
specV <- readIORef (cSpec ctx)
|
|
935
|
+
case specV of
|
|
936
|
+
VMap _ -> do
|
|
937
|
+
(fetchdef, merr) <- makeFetchDefUtil ctx
|
|
938
|
+
case merr of
|
|
939
|
+
Just e -> do
|
|
940
|
+
setp response0 "err" e
|
|
941
|
+
writeIORef (cResponse ctx) response0
|
|
942
|
+
setp specV "step" (VStr "postrequest")
|
|
943
|
+
pure (response0, Nothing)
|
|
944
|
+
Nothing -> do
|
|
945
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
946
|
+
explain <- getp ctrl "explain"
|
|
947
|
+
case explain of VMap _ -> setp explain "fetchdef" fetchdef; _ -> pure ()
|
|
948
|
+
setp specV "step" (VStr "prerequest")
|
|
949
|
+
url <- getStrD fetchdef "url" ""
|
|
950
|
+
u <- cu ctx
|
|
951
|
+
fetcher <- readIORef (uFetcher u)
|
|
952
|
+
(fetched, fetchErr) <- fetcher ctx url fetchdef
|
|
953
|
+
response <- case fetchErr of
|
|
954
|
+
Just fe -> do setp response0 "err" fe; pure response0
|
|
955
|
+
Nothing ->
|
|
956
|
+
if isNoval fetched || isNullV fetched
|
|
957
|
+
then do r <- newResponse =<< emptyMap; e <- mkErr "request_no_response" "response: undefined"; setp r "err" e; pure r
|
|
958
|
+
else case fetched of
|
|
959
|
+
VMap _ -> newResponse fetched
|
|
960
|
+
_ -> do setp response0 "err" =<< mkErr "request_invalid_response" "response: invalid type"; pure response0
|
|
961
|
+
setp specV "step" (VStr "postrequest")
|
|
962
|
+
writeIORef (cResponse ctx) response
|
|
963
|
+
pure (response, Nothing)
|
|
964
|
+
_ -> do e <- mkErr "request_no_spec" "Expected context spec property to be defined."; pure (VNoval, Just e)
|
|
965
|
+
|
|
966
|
+
isNullV :: Value -> Bool
|
|
967
|
+
isNullV VNull = True
|
|
968
|
+
isNullV _ = False
|
|
969
|
+
|
|
970
|
+
makeResponseUtil :: Context -> UResult
|
|
971
|
+
makeResponseUtil ctx = do
|
|
972
|
+
out <- readIORef (cOut ctx)
|
|
973
|
+
pre <- getp out "response"
|
|
974
|
+
isE <- isErr pre
|
|
975
|
+
if isE then pure (VNoval, Just pre)
|
|
976
|
+
else case pre of
|
|
977
|
+
VMap _ -> pure (pre, Nothing)
|
|
978
|
+
_ -> do
|
|
979
|
+
specV <- readIORef (cSpec ctx)
|
|
980
|
+
responseV <- readIORef (cResponse ctx)
|
|
981
|
+
resultV <- readIORef (cResult ctx)
|
|
982
|
+
case specV of
|
|
983
|
+
VMap _ -> case responseV of
|
|
984
|
+
VMap _ -> case resultV of
|
|
985
|
+
VMap _ -> do
|
|
986
|
+
setp specV "step" (VStr "response")
|
|
987
|
+
resultBasicUtil ctx; resultHeadersUtil ctx; resultBodyUtil ctx
|
|
988
|
+
-- GraphQL reports failures as a top-level `errors` array under
|
|
989
|
+
-- HTTP 200, so resultBasic's status check never sees them. Lift
|
|
990
|
+
-- them here, before the response transform tries to unwrap data
|
|
991
|
+
-- that is not there.
|
|
992
|
+
_ <- graphqlErrorsUtil ctx
|
|
993
|
+
_ <- transformResponseUtil ctx
|
|
994
|
+
errv <- getp resultV "err"
|
|
995
|
+
isErrR <- isErr errv
|
|
996
|
+
when (not isErrR) (setp resultV "ok" (VBool True))
|
|
997
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
998
|
+
explain <- getp ctrl "explain"
|
|
999
|
+
case explain of { VMap _ -> do { snap <- resultToValue resultV; setp explain "result" snap }; _ -> pure () }
|
|
1000
|
+
pure (responseV, Nothing)
|
|
1001
|
+
_ -> do e <- mkErr "response_no_result" "Expected context result property to be defined."; pure (VNoval, Just e)
|
|
1002
|
+
_ -> do e <- mkErr "response_no_response" "Expected context response property to be defined."; pure (VNoval, Just e)
|
|
1003
|
+
_ -> do e <- mkErr "response_no_spec" "Expected context spec property to be defined."; pure (VNoval, Just e)
|
|
1004
|
+
|
|
1005
|
+
makeResultUtil :: Context -> UResult
|
|
1006
|
+
makeResultUtil ctx = do
|
|
1007
|
+
out <- readIORef (cOut ctx)
|
|
1008
|
+
pre <- getp out "result"
|
|
1009
|
+
isE <- isErr pre
|
|
1010
|
+
if isE then pure (VNoval, Just pre)
|
|
1011
|
+
else case pre of
|
|
1012
|
+
VMap _ -> pure (pre, Nothing)
|
|
1013
|
+
_ -> do
|
|
1014
|
+
op <- readIORef (cOp ctx)
|
|
1015
|
+
specV <- readIORef (cSpec ctx)
|
|
1016
|
+
resultV <- readIORef (cResult ctx)
|
|
1017
|
+
case specV of
|
|
1018
|
+
VMap _ -> case resultV of
|
|
1019
|
+
VMap _ -> do
|
|
1020
|
+
setp specV "step" (VStr "result")
|
|
1021
|
+
_ <- transformResponseUtil ctx
|
|
1022
|
+
when (opName op == "list") $ do
|
|
1023
|
+
resdata <- getp resultV "resdata"
|
|
1024
|
+
el <- emptyList
|
|
1025
|
+
setp resultV "resdata" el
|
|
1026
|
+
ment <- readIORef (cEntity ctx)
|
|
1027
|
+
case (resdata, ment) of
|
|
1028
|
+
(VList _, Just entity) -> do
|
|
1029
|
+
items0 <- listItems resdata
|
|
1030
|
+
entries <- mapM (\entry -> do
|
|
1031
|
+
ent <- eMake entity
|
|
1032
|
+
case entry of VMap _ -> eDataSet ent entry; _ -> pure ()
|
|
1033
|
+
pure entry) items0
|
|
1034
|
+
el2 <- mkList entries
|
|
1035
|
+
setp resultV "resdata" el2
|
|
1036
|
+
_ -> pure ()
|
|
1037
|
+
ctrl <- readIORef (cCtrl ctx)
|
|
1038
|
+
explain <- getp ctrl "explain"
|
|
1039
|
+
case explain of { VMap _ -> do { snap <- resultToValue resultV; setp explain "result" snap }; _ -> pure () }
|
|
1040
|
+
pure (resultV, Nothing)
|
|
1041
|
+
_ -> do e <- mkErr "result_no_result" "Expected context result property to be defined."; pure (VNoval, Just e)
|
|
1042
|
+
_ -> do e <- mkErr "result_no_spec" "Expected context spec property to be defined."; pure (VNoval, Just e)
|
|
1043
|
+
|
|
1044
|
+
-- ----- fetcher (innermost transport) -----
|
|
1045
|
+
|
|
1046
|
+
fetcherUtil :: Context -> String -> Value -> IO (Value, Maybe Value)
|
|
1047
|
+
fetcherUtil ctx fullurl fetchdef = do
|
|
1048
|
+
cl <- cc ctx
|
|
1049
|
+
mode <- readIORef (clMode cl)
|
|
1050
|
+
if mode /= "live"
|
|
1051
|
+
then do e <- mkErr "fetch_mode_block" ("Request blocked by mode: \"" ++ mode ++ "\" (URL was: \"" ++ fullurl ++ "\")"); pure (VNoval, Just e)
|
|
1052
|
+
else do
|
|
1053
|
+
options <- clientOptionsMap cl
|
|
1054
|
+
testActive <- getpathS options "feature.test.active"
|
|
1055
|
+
if isTrueV testActive
|
|
1056
|
+
then do e <- mkErr "fetch_test_block" ("Request blocked as test feature is active (URL was: \"" ++ fullurl ++ "\")"); pure (VNoval, Just e)
|
|
1057
|
+
else do
|
|
1058
|
+
sysFetch <- getpathS options "system.fetch"
|
|
1059
|
+
case sysFetch of
|
|
1060
|
+
VFunc _ -> do
|
|
1061
|
+
argsL <- ja [VStr fullurl, fetchdef]
|
|
1062
|
+
out <- callVfn sysFetch argsL
|
|
1063
|
+
errStr <- getStr out "__err__"
|
|
1064
|
+
case errStr of
|
|
1065
|
+
Just msg -> do e <- mkErr "fetch_system" msg; pure (VNoval, Just e)
|
|
1066
|
+
Nothing -> pure (out, Nothing)
|
|
1067
|
+
VNoval -> do e <- mkErr "fetch_no_transport" "No live HTTP transport in this build; provide options.system.fetch."; pure (VNoval, Just e)
|
|
1068
|
+
VNull -> do e <- mkErr "fetch_no_transport" "No live HTTP transport in this build; provide options.system.fetch."; pure (VNoval, Just e)
|
|
1069
|
+
_ -> do e <- mkErr "fetch_invalid" "system.fetch is not a valid function"; pure (VNoval, Just e)
|
|
1070
|
+
|
|
1071
|
+
-- ------------------------------------------------------------------
|
|
1072
|
+
-- make_options
|
|
1073
|
+
-- ------------------------------------------------------------------
|
|
1074
|
+
|
|
1075
|
+
optSpecValue :: IO Value
|
|
1076
|
+
optSpecValue = do
|
|
1077
|
+
auth <- jo [("prefix", VStr ""), ("basic", VBool False)]
|
|
1078
|
+
hdrs <- jo [("`$CHILD`", VStr "`$STRING`")]
|
|
1079
|
+
-- OpenAPI server-variable defaults, carried by the generated config whenever
|
|
1080
|
+
-- the spec's server URL is templated. Accepted here so validation does not
|
|
1081
|
+
-- reject the SDK's own config; the {name} substitution into base is a
|
|
1082
|
+
-- separate concern.
|
|
1083
|
+
srv <- jo [("`$CHILD`", VStr "")]
|
|
1084
|
+
allow <- jo [("method", VStr "GET,PUT,POST,PATCH,DELETE,OPTIONS"), ("op", VStr "create,update,load,list,remove,command,direct,graphql")]
|
|
1085
|
+
entChild <- do a <- emptyMap; jo [("`$OPEN`", VBool True), ("active", VBool False), ("alias", a)]
|
|
1086
|
+
ent <- jo [("`$CHILD`", entChild)]
|
|
1087
|
+
featChild <- jo [("`$OPEN`", VBool True), ("active", VBool False)]
|
|
1088
|
+
feat <- jo [("`$CHILD`", featChild)]
|
|
1089
|
+
utilm <- emptyMap
|
|
1090
|
+
sysm <- emptyMap
|
|
1091
|
+
testEnt <- jo [("`$OPEN`", VBool True)]
|
|
1092
|
+
test <- jo [("active", VBool False), ("entity", testEnt)]
|
|
1093
|
+
clean <- jo [("keys", VStr "key,token,id")]
|
|
1094
|
+
jo [ ("apikey", VStr ""), ("base", VStr "http://localhost:8000"), ("prefix", VStr ""), ("suffix", VStr "")
|
|
1095
|
+
, ("auth", auth), ("headers", hdrs), ("server", srv), ("allow", allow), ("entity", ent), ("feature", feat)
|
|
1096
|
+
, ("utility", utilm), ("system", sysm), ("test", test), ("clean", clean) ]
|
|
1097
|
+
|
|
1098
|
+
makeOptionsUtil :: Context -> IO Value
|
|
1099
|
+
makeOptionsUtil ctx = do
|
|
1100
|
+
optionsV <- readIORef (cOptions ctx)
|
|
1101
|
+
options <- case optionsV of VNoval -> emptyMap; v -> pure v
|
|
1102
|
+
customUtils <- getp options "utility"
|
|
1103
|
+
case customUtils of
|
|
1104
|
+
VMap _ -> do
|
|
1105
|
+
mu <- readIORef (cUtility ctx)
|
|
1106
|
+
case mu of
|
|
1107
|
+
Just u -> do ks <- keysof customUtils; forM_ ks $ \k -> do v <- getp customUtils k; c <- readIORef (uCustom u); setp c k v
|
|
1108
|
+
Nothing -> pure ()
|
|
1109
|
+
_ -> pure ()
|
|
1110
|
+
optsC <- clone options
|
|
1111
|
+
opts0 <- case optsC of VMap _ -> pure optsC; _ -> emptyMap
|
|
1112
|
+
-- Feature add-order. options.feature may be given as an ordered LIST of
|
|
1113
|
+
-- {name, active, ...opts} entries (list position = add order) or a
|
|
1114
|
+
-- {name => {opts}} map. Normalize a list to a map (so merge/validate/init
|
|
1115
|
+
-- are unchanged) and remember the explicit order; a map defaults to
|
|
1116
|
+
-- test-first so the `test` mock transport is the base of the wrapper chain.
|
|
1117
|
+
featureRaw <- getp opts0 "feature"
|
|
1118
|
+
explicitOrder <- case featureRaw of
|
|
1119
|
+
VList ref -> do
|
|
1120
|
+
entries <- readIORef ref
|
|
1121
|
+
fmap' <- emptyMap
|
|
1122
|
+
order <- fmap concat $ mapM (\entry -> case entry of
|
|
1123
|
+
VMap _ -> do
|
|
1124
|
+
nm <- getp entry "name"
|
|
1125
|
+
case nm of
|
|
1126
|
+
VStr name -> do
|
|
1127
|
+
fopts <- clone entry
|
|
1128
|
+
_ <- delprop fopts (VStr "name")
|
|
1129
|
+
setp fmap' name fopts
|
|
1130
|
+
pure [name]
|
|
1131
|
+
_ -> pure []
|
|
1132
|
+
_ -> pure []) entries
|
|
1133
|
+
setp opts0 "feature" fmap'
|
|
1134
|
+
pure (Just order)
|
|
1135
|
+
_ -> pure Nothing
|
|
1136
|
+
configV <- readIORef (cConfig ctx)
|
|
1137
|
+
config <- case configV of VMap _ -> pure configV; _ -> emptyMap
|
|
1138
|
+
cfgoptsV <- toMap <$> getp config "options"
|
|
1139
|
+
cfgopts <- case cfgoptsV of VMap _ -> pure cfgoptsV; _ -> emptyMap
|
|
1140
|
+
optspec <- optSpecValue
|
|
1141
|
+
sysFetch <- getpathS opts0 "system.fetch"
|
|
1142
|
+
em <- emptyMap
|
|
1143
|
+
mlist <- ja [em, cfgopts, opts0]
|
|
1144
|
+
merged <- merge mlist
|
|
1145
|
+
validated <- validate INone merged optspec
|
|
1146
|
+
opts <- case validated of VMap _ -> pure validated; _ -> emptyMap
|
|
1147
|
+
-- Resolve a templated base URL (e.g. https://{tenant_id}.hanko.io).
|
|
1148
|
+
-- Every placeholder must resolve to a non-empty value: from options.server
|
|
1149
|
+
-- (user), else the Config default. A placeholder that resolves to "" is a
|
|
1150
|
+
-- construction ERROR in live mode - the URL cannot work - but in test mode
|
|
1151
|
+
-- substitutes the deterministic value "test-<name>" so offline tests need no
|
|
1152
|
+
-- configuration. The SDK constructor has no error return, so a missing
|
|
1153
|
+
-- required variable THROWS: construction-time misconfiguration.
|
|
1154
|
+
baseV <- getp opts "base"
|
|
1155
|
+
case baseV of
|
|
1156
|
+
VStr base | '{' `elem` base -> do
|
|
1157
|
+
taV <- getpathS opts "test.active"
|
|
1158
|
+
faV <- getpathS opts "feature.test.active"
|
|
1159
|
+
-- Value has no Eq instance: match the constructor.
|
|
1160
|
+
let isTrue v = case v of VBool b -> b; _ -> False
|
|
1161
|
+
testmode = isTrue taV || isTrue faV
|
|
1162
|
+
server <- getp opts "server"
|
|
1163
|
+
mnV <- getpathS config "main.name"
|
|
1164
|
+
let sdkname = case mnV of VStr s | not (null s) -> s; _ -> "SDK"
|
|
1165
|
+
|
|
1166
|
+
-- Scanned by hand: a placeholder is `{` followed by [A-Za-z0-9_]+ and
|
|
1167
|
+
-- `}`; anything else is literal text, so a stray brace is left alone.
|
|
1168
|
+
let resolve [] = pure []
|
|
1169
|
+
resolve ('{' : rest) =
|
|
1170
|
+
let (name, tail') = span (\c -> isAlphaNum c || '_' == c) rest
|
|
1171
|
+
in case tail' of
|
|
1172
|
+
('}' : more) | not (null name) -> do
|
|
1173
|
+
valV <- case server of VMap _ -> getp server name; _ -> pure VNoval
|
|
1174
|
+
let val = case valV of VStr s -> s; _ -> ""
|
|
1175
|
+
sub <- if not (null val)
|
|
1176
|
+
then pure val
|
|
1177
|
+
else if testmode
|
|
1178
|
+
then pure ("test-" ++ name)
|
|
1179
|
+
else do
|
|
1180
|
+
e <- jo [ ("code", VStr "server_var_required")
|
|
1181
|
+
, ("msg", VStr (sdkname ++ ": the server variable '" ++
|
|
1182
|
+
name ++ "' is required: the API base URL is '" ++
|
|
1183
|
+
base ++ "' - pass server = { \"" ++ name ++
|
|
1184
|
+
"\": \"...\" } in the SDK options"))
|
|
1185
|
+
, ("sdk", VStr "ProjectName") ]
|
|
1186
|
+
throwIO (SdkException e)
|
|
1187
|
+
more' <- resolve more
|
|
1188
|
+
pure (sub ++ more')
|
|
1189
|
+
_ -> do r <- resolve rest; pure ('{' : r)
|
|
1190
|
+
resolve (c : rest) = do r <- resolve rest; pure (c : r)
|
|
1191
|
+
resolved <- resolve base
|
|
1192
|
+
setp opts "base" (VStr resolved)
|
|
1193
|
+
_ -> pure ()
|
|
1194
|
+
|
|
1195
|
+
when (not (isNoval sysFetch)) $ do
|
|
1196
|
+
sys <- getp opts "system"
|
|
1197
|
+
case sys of
|
|
1198
|
+
VMap _ -> setp sys "fetch" sysFetch
|
|
1199
|
+
_ -> do s <- jo [("fetch", sysFetch)]; setp opts "system" s
|
|
1200
|
+
ckv <- getpathS opts "clean.keys"
|
|
1201
|
+
let cleanKeys = case ckv of VStr s -> s; _ -> "key,token,id"
|
|
1202
|
+
parts <- fmap concat $ mapM (\p -> let t = strip p in if t == "" then pure [] else do e <- escreS t; pure [e]) (splitOnChar ',' cleanKeys)
|
|
1203
|
+
let keyre = intercalate' "|" parts
|
|
1204
|
+
cleanEmpty <- emptyMap
|
|
1205
|
+
derived <- jo [("clean", cleanEmpty)]
|
|
1206
|
+
when (keyre /= "") $ do cm <- jo [("keyre", VStr keyre)]; setp derived "clean" cm
|
|
1207
|
+
-- Resolve the feature add-order: an explicit list order (above) wins;
|
|
1208
|
+
-- otherwise order the map test-first, then the remaining names sorted
|
|
1209
|
+
-- (keysof returns sorted keys), so the result is deterministic.
|
|
1210
|
+
featureOrder <- case explicitOrder of
|
|
1211
|
+
Just ord -> pure ord
|
|
1212
|
+
Nothing -> do
|
|
1213
|
+
fmapV <- getp opts "feature"
|
|
1214
|
+
names <- case fmapV of VMap _ -> keysof fmapV; _ -> pure []
|
|
1215
|
+
pure $ if "test" `elem` names then "test" : filter (/= "test") names else names
|
|
1216
|
+
orderList <- ja (map VStr featureOrder)
|
|
1217
|
+
setp derived "featureorder" orderList
|
|
1218
|
+
setp opts "__derived__" derived
|
|
1219
|
+
pure opts
|
|
1220
|
+
|
|
1221
|
+
intercalate' :: String -> [String] -> String
|
|
1222
|
+
intercalate' _ [] = ""
|
|
1223
|
+
intercalate' _ [x] = x
|
|
1224
|
+
intercalate' sep (x : xs) = x ++ sep ++ intercalate' sep xs
|
|
1225
|
+
|
|
1226
|
+
-- ------------------------------------------------------------------
|
|
1227
|
+
-- struct api exposure (utility.struct)
|
|
1228
|
+
-- ------------------------------------------------------------------
|
|
1229
|
+
|
|
1230
|
+
structApiInstance :: StructApi
|
|
1231
|
+
structApiInstance = StructApi
|
|
1232
|
+
{ sGetprop = getprop
|
|
1233
|
+
, sSetprop = setprop
|
|
1234
|
+
, sGetpath = getpath INone
|
|
1235
|
+
, sGetelem = getelem
|
|
1236
|
+
, sClone = clone
|
|
1237
|
+
, sMerge = \l -> mkList l >>= merge
|
|
1238
|
+
, sItems = items
|
|
1239
|
+
, sKeysof = keysof
|
|
1240
|
+
, sSize = size
|
|
1241
|
+
, sIsempty = isempty
|
|
1242
|
+
, sStringify = stringify
|
|
1243
|
+
, sJsonify = jsonifyCompact
|
|
1244
|
+
, sEscurl = escurlS . vstring
|
|
1245
|
+
, sEscre = escreS . vstring
|
|
1246
|
+
, sTransform = transform INone
|
|
1247
|
+
, sValidate = validate INone
|
|
1248
|
+
, sSelect = select
|
|
1249
|
+
, sWalk = \fn v -> walk (Just fn) Nothing VNoval v
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
-- ------------------------------------------------------------------
|
|
1253
|
+
-- utility construction
|
|
1254
|
+
-- ------------------------------------------------------------------
|
|
1255
|
+
|
|
1256
|
+
newUtility :: IO Utility
|
|
1257
|
+
newUtility = do
|
|
1258
|
+
custom <- newIORef =<< emptyMap
|
|
1259
|
+
fetcher <- newIORef fetcherUtil
|
|
1260
|
+
param <- newIORef paramUtil
|
|
1261
|
+
pure Utility { uCustom = custom, uStruct = structApiInstance, uFetcher = fetcher, uParam = param }
|
|
1262
|
+
|
|
1263
|
+
copyUtility :: Utility -> IO Utility
|
|
1264
|
+
copyUtility src = do
|
|
1265
|
+
f <- readIORef (uFetcher src)
|
|
1266
|
+
p <- readIORef (uParam src)
|
|
1267
|
+
fetcher <- newIORef f
|
|
1268
|
+
param <- newIORef p
|
|
1269
|
+
srcCustom <- readIORef (uCustom src)
|
|
1270
|
+
custom <- emptyMap
|
|
1271
|
+
case srcCustom of
|
|
1272
|
+
VMap _ -> do ks <- keysof srcCustom; forM_ ks $ \k -> do v <- getp srcCustom k; setp custom k v
|
|
1273
|
+
_ -> pure ()
|
|
1274
|
+
customR <- newIORef custom
|
|
1275
|
+
pure Utility { uCustom = customR, uStruct = uStruct src, uFetcher = fetcher, uParam = param }
|
|
1276
|
+
|
|
1277
|
+
-- struct join helper: join parts with "/" as a URL path
|
|
1278
|
+
join_ :: Value -> IO String
|
|
1279
|
+
join_ arr = join arr (VStr "/") True
|