@voxgig/sdkgen 1.3.17 → 1.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/Deploy.js +16 -16
- package/dist/cmp/Deploy.js.map +1 -1
- package/dist/cmp/Entity.js +5 -1
- package/dist/cmp/Entity.js.map +1 -1
- package/dist/cmp/Feature.js +2 -1
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/ReadmeTop.js +13 -11
- package/dist/cmp/ReadmeTop.js.map +1 -1
- package/dist/helpers/canonType.js +8 -3
- package/dist/helpers/canonType.js.map +1 -1
- package/dist/helpers/collectDeps.d.ts +1 -1
- package/dist/helpers/collectDeps.js +36 -13
- package/dist/helpers/collectDeps.js.map +1 -1
- package/dist/helpers/naming.d.ts +5 -1
- package/dist/helpers/naming.js +118 -0
- package/dist/helpers/naming.js.map +1 -1
- package/dist/helpers/opShape.d.ts +3 -1
- package/dist/helpers/opShape.js +87 -8
- package/dist/helpers/opShape.js.map +1 -1
- package/dist/helpers/serverVars.d.ts +10 -0
- package/dist/helpers/serverVars.js +87 -0
- package/dist/helpers/serverVars.js.map +1 -0
- package/dist/sdkgen.d.ts +4 -3
- package/dist/sdkgen.js +11 -2
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -10
- package/project/.sdk/model/target/cpp.aontu +4 -4
- package/project/.sdk/model/target/go-cli.aontu +17 -17
- package/project/.sdk/model/target/go-mcp.aontu +11 -11
- package/project/.sdk/model/target/go.aontu +1 -1
- package/project/.sdk/model/target/java.aontu +4 -4
- package/project/.sdk/model/target/kotlin.aontu +4 -4
- package/project/.sdk/model/target/lean.aontu +51 -0
- package/project/.sdk/model/target/scala.aontu +4 -4
- package/project/.sdk/src/cmp/c/EntityTypes_c.ts +3 -4
- package/project/.sdk/src/cmp/c/Entity_c.ts +3 -3
- package/project/.sdk/src/cmp/c/ReadmeExamplesTest_c.ts +24 -7
- package/project/.sdk/src/cmp/c/TestDirect_c.ts +3 -3
- package/project/.sdk/src/cmp/c/TestEntity_c.ts +1 -1
- package/project/.sdk/src/cmp/clojure/Entity_clojure.ts +1 -1
- package/project/.sdk/src/cmp/clojure/ReadmeExamplesTest_clojure.ts +19 -8
- package/project/.sdk/src/cmp/cpp/EntityTypes_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/Entity_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/MainEntity_cpp.ts +2 -2
- package/project/.sdk/src/cmp/cpp/ReadmeExamplesTest_cpp.ts +136 -0
- package/project/.sdk/src/cmp/cpp/TestDirect_cpp.ts +3 -3
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +4 -0
- package/project/.sdk/src/cmp/csharp/EntityTypes_csharp.ts +2 -3
- package/project/.sdk/src/cmp/csharp/Entity_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/MainEntity_csharp.ts +2 -2
- package/project/.sdk/src/cmp/csharp/Package_csharp.ts +1 -1
- package/project/.sdk/src/cmp/csharp/ReadmeExamplesTest_csharp.ts +13 -1
- package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +3 -3
- package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +22 -15
- package/project/.sdk/src/cmp/dart/EntityTypes_dart.ts +2 -3
- package/project/.sdk/src/cmp/dart/Entity_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/MainEntity_dart.ts +2 -2
- package/project/.sdk/src/cmp/dart/Main_dart.ts +3 -3
- package/project/.sdk/src/cmp/dart/Package_dart.ts +1 -1
- package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +4 -4
- package/project/.sdk/src/cmp/elixir/EntityTypes_elixir.ts +2 -3
- package/project/.sdk/src/cmp/elixir/Entity_elixir.ts +1 -1
- package/project/.sdk/src/cmp/elixir/ReadmeExamplesTest_elixir.ts +21 -3
- package/project/.sdk/src/cmp/go/Config_go.ts +14 -2
- package/project/.sdk/src/cmp/go/EntityTypes_go.ts +110 -18
- package/project/.sdk/src/cmp/go/Entity_go.ts +3 -3
- package/project/.sdk/src/cmp/go/Main_go.ts +7 -6
- package/project/.sdk/src/cmp/go/Package_go.ts +1 -1
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +3 -3
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +1 -1
- package/project/.sdk/src/cmp/go/utility_go.ts +25 -0
- package/project/.sdk/src/cmp/go-cli/Main_go-cli.ts +62 -35
- package/project/.sdk/src/cmp/go-cli/fragment/main.fragment.go +7 -7
- package/project/.sdk/src/cmp/go-cli/fragment/words.fragment.go +21 -18
- package/project/.sdk/src/cmp/go-mcp/Main_go-mcp.ts +9 -1
- package/project/.sdk/src/cmp/haskell/ReadmeExamplesTest_haskell.ts +28 -18
- package/project/.sdk/src/cmp/java/EntityTypes_java.ts +2 -3
- package/project/.sdk/src/cmp/java/Entity_java.ts +3 -3
- package/project/.sdk/src/cmp/java/MainEntity_java.ts +2 -2
- package/project/.sdk/src/cmp/java/Package_java.ts +1 -1
- package/project/.sdk/src/cmp/java/ReadmeExamplesTest_java.ts +23 -1
- package/project/.sdk/src/cmp/java/TestDirect_java.ts +3 -3
- package/project/.sdk/src/cmp/js/Config_js.ts +11 -0
- package/project/.sdk/src/cmp/js/EntityTypes_js.ts +2 -3
- package/project/.sdk/src/cmp/js/Entity_js.ts +3 -3
- package/project/.sdk/src/cmp/js/MainEntity_js.ts +2 -2
- package/project/.sdk/src/cmp/js/Main_js.ts +2 -2
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +4 -4
- package/project/.sdk/src/cmp/js/fragment/Config.fragment.js +2 -2
- package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +4 -0
- package/project/.sdk/src/cmp/kotlin/EntityTypes_kotlin.ts +2 -3
- package/project/.sdk/src/cmp/kotlin/Entity_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/kotlin/MainEntity_kotlin.ts +2 -2
- package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +1 -1
- package/project/.sdk/src/cmp/kotlin/ReadmeExamplesTest_kotlin.ts +27 -2
- package/project/.sdk/src/cmp/kotlin/TestDirect_kotlin.ts +3 -3
- package/project/.sdk/src/cmp/lean/Config_lean.ts +88 -0
- package/project/.sdk/src/cmp/lean/Entity_lean.ts +9 -0
- package/project/.sdk/src/cmp/lean/Gitignore_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Main_lean.ts +120 -0
- package/project/.sdk/src/cmp/lean/Package_lean.ts +68 -0
- package/project/.sdk/src/cmp/lean/ReadmeEntity_lean.ts +29 -0
- package/project/.sdk/src/cmp/lean/ReadmeExplanation_lean.ts +19 -0
- package/project/.sdk/src/cmp/lean/ReadmeHowto_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +38 -0
- package/project/.sdk/src/cmp/lean/ReadmeIntro_lean.ts +25 -0
- package/project/.sdk/src/cmp/lean/ReadmeModel_lean.ts +24 -0
- package/project/.sdk/src/cmp/lean/ReadmeOptions_lean.ts +22 -0
- package/project/.sdk/src/cmp/lean/ReadmeQuick_lean.ts +50 -0
- package/project/.sdk/src/cmp/lean/ReadmeRef_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopHowto_lean.ts +16 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopQuick_lean.ts +23 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +18 -0
- package/project/.sdk/src/cmp/lean/Test_lean.ts +207 -0
- package/project/.sdk/src/cmp/lean/utility_lean.ts +78 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +10 -1
- package/project/.sdk/src/cmp/lua/EntityTypes_lua.ts +2 -3
- package/project/.sdk/src/cmp/lua/Entity_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +1 -1
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +3 -3
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +1 -1
- package/project/.sdk/src/cmp/ocaml/ReadmeExamplesTest_ocaml.ts +29 -14
- package/project/.sdk/src/cmp/perl/Entity_perl.ts +3 -3
- package/project/.sdk/src/cmp/perl/MainEntity_perl.ts +2 -2
- package/project/.sdk/src/cmp/perl/Package_perl.ts +1 -1
- package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +3 -3
- package/project/.sdk/src/cmp/php/Config_php.ts +13 -2
- package/project/.sdk/src/cmp/php/EntityTypes_php.ts +2 -3
- package/project/.sdk/src/cmp/php/Entity_php.ts +3 -3
- package/project/.sdk/src/cmp/php/MainEntity_php.ts +2 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +1 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +3 -3
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +1 -1
- package/project/.sdk/src/cmp/py/Config_py.ts +10 -1
- package/project/.sdk/src/cmp/py/EntityTypes_py.ts +2 -3
- package/project/.sdk/src/cmp/py/Entity_py.ts +3 -3
- package/project/.sdk/src/cmp/py/MainEntity_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Main_py.ts +2 -2
- package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +3 -3
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +1 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +12 -1
- package/project/.sdk/src/cmp/rb/EntityTypes_rb.ts +15 -5
- package/project/.sdk/src/cmp/rb/Entity_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/MainEntity_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/Package_rb.ts +2 -2
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +3 -3
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +1 -1
- package/project/.sdk/src/cmp/rust/EntityBase_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/EntityTypes_rust.ts +3 -4
- package/project/.sdk/src/cmp/rust/Entity_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/MainEntity_rust.ts +2 -2
- package/project/.sdk/src/cmp/rust/Package_rust.ts +1 -1
- package/project/.sdk/src/cmp/rust/ReadmeExamplesTest_rust.ts +22 -10
- package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +3 -3
- package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +25 -18
- package/project/.sdk/src/cmp/scala/EntityTypes_scala.ts +2 -3
- package/project/.sdk/src/cmp/scala/Entity_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/MainEntity_scala.ts +2 -2
- package/project/.sdk/src/cmp/scala/ReadmeExamplesTest_scala.ts +22 -3
- package/project/.sdk/src/cmp/scala/TestDirect_scala.ts +3 -3
- package/project/.sdk/src/cmp/scala/Test_scala.ts +1 -1
- package/project/.sdk/src/cmp/swift/EntityTypes_swift.ts +12 -6
- package/project/.sdk/src/cmp/swift/Entity_swift.ts +3 -3
- package/project/.sdk/src/cmp/swift/MainEntity_swift.ts +2 -2
- package/project/.sdk/src/cmp/swift/Package_swift.ts +1 -1
- package/project/.sdk/src/cmp/swift/ReadmeExamplesTest_swift.ts +18 -1
- package/project/.sdk/src/cmp/swift/TestDirect_swift.ts +1 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +11 -0
- package/project/.sdk/src/cmp/ts/EntityTypes_ts.ts +2 -3
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -3
- package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/Main_ts.ts +2 -2
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +4 -4
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +2 -2
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +4 -0
- package/project/.sdk/src/cmp/zig/Entity_zig.ts +3 -3
- package/project/.sdk/src/cmp/zig/MainEntity_zig.ts +2 -2
- package/project/.sdk/src/cmp/zig/Package_zig.ts +10 -2
- package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +8 -16
- package/project/.sdk/tm/csharp/Makefile +6 -6
- package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +10 -28
- package/project/.sdk/tm/dart/Makefile +3 -3
- package/project/.sdk/tm/dart/test/primary_test.dart +7 -0
- package/project/.sdk/tm/go/Makefile +6 -6
- package/project/.sdk/tm/go/feature/test_feature.go +33 -1
- package/project/.sdk/tm/go/test/primary_utility_test.go +46 -42
- package/project/.sdk/tm/go/test/runner_test.go +30 -1
- package/project/.sdk/tm/go/utility/make_options.go +48 -0
- package/project/.sdk/tm/java/Makefile +6 -6
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +7 -24
- package/project/.sdk/tm/js/Makefile +6 -6
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +18 -1
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -1
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +13 -0
- package/project/.sdk/tm/kotlin/Makefile +6 -6
- package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +7 -20
- package/project/.sdk/tm/lean/LICENSE +21 -0
- package/project/.sdk/tm/lean/VERSION +1 -0
- package/project/.sdk/tm/lean/src/SdkFeature.lean +171 -0
- package/project/.sdk/tm/lean/src/SdkFeatures.lean +602 -0
- package/project/.sdk/tm/lean/src/SdkJson.lean +134 -0
- package/project/.sdk/tm/lean/src/SdkRuntime.lean +356 -0
- package/project/.sdk/tm/lean/src/SdkUtility.lean +617 -0
- package/project/.sdk/tm/lean/src/VoxgigStruct.lean +2880 -0
- package/project/.sdk/tm/lean/src/Vregex.lean +412 -0
- package/project/.sdk/tm/lean/src/feature/README.md +5 -0
- package/project/.sdk/tm/lean/src/feature/audit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/base/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/cache/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/clienttrack/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/debug/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/idempotency/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/log/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/metrics/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/netsim/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/paging/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/proxy/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/ratelimit/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/rbac/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/retry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/streaming/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/telemetry/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/test/.gitkeep +0 -0
- package/project/.sdk/tm/lean/src/feature/timeout/.gitkeep +0 -0
- package/project/.sdk/tm/lean/test/StructCorpus.lean +697 -0
- package/project/.sdk/tm/lean/test/TFeature.lean +268 -0
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +349 -0
- package/project/.sdk/tm/lua/Makefile +7 -7
- package/project/.sdk/tm/lua/feature/test_feature.lua +29 -1
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +14 -8
- package/project/.sdk/tm/lua/utility/make_options.lua +39 -0
- package/project/.sdk/tm/perl/Makefile +6 -6
- package/project/.sdk/tm/perl/t/primary_utility.t +8 -17
- package/project/.sdk/tm/php/Makefile +6 -6
- package/project/.sdk/tm/php/feature/TestFeature.php +30 -2
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +14 -7
- package/project/.sdk/tm/php/utility/MakeOptions.php +44 -0
- package/project/.sdk/tm/py/Makefile +6 -6
- package/project/.sdk/tm/py/feature/test_feature.py +28 -1
- package/project/.sdk/tm/py/test/test_primary_utility.py +18 -18
- package/project/.sdk/tm/py/utility/make_options.py +42 -0
- package/project/.sdk/tm/rb/Makefile +6 -6
- package/project/.sdk/tm/rb/feature/test_feature.rb +24 -1
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +11 -8
- package/project/.sdk/tm/rb/utility/make_options.rb +37 -0
- package/project/.sdk/tm/rust/Makefile +6 -6
- package/project/.sdk/tm/rust/tests/common/mod.rs +37 -1
- package/project/.sdk/tm/rust/tests/primary_utility_test.rs +12 -26
- package/project/.sdk/tm/swift/Makefile +6 -6
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +7 -8
- package/project/.sdk/tm/ts/Makefile +6 -6
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +18 -1
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +39 -1
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +69 -21
- package/src/cmp/Deploy.ts +16 -16
- package/src/cmp/Entity.ts +5 -1
- package/src/cmp/Feature.ts +2 -1
- package/src/cmp/ReadmeTop.ts +13 -11
- package/src/helpers/canonType.ts +8 -3
- package/src/helpers/collectDeps.ts +39 -12
- package/src/helpers/naming.ts +130 -0
- package/src/helpers/opShape.ts +99 -12
- package/src/helpers/serverVars.ts +105 -0
- package/src/sdkgen.ts +12 -3
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
/- ProjectName SDK feature catalog: the concrete features.
|
|
2
|
+
|
|
3
|
+
Each constructor returns a `Feature` closing over its own state refs. A
|
|
4
|
+
feature either wraps the transport (retry, timeout, ratelimit, cache, proxy,
|
|
5
|
+
netsim, test) or handles pipeline hooks (idempotency, rbac, metrics,
|
|
6
|
+
telemetry, debug, audit, clienttrack, paging, streaming) — or both.
|
|
7
|
+
|
|
8
|
+
Observable state is recorded in the client's `track` buckets under the
|
|
9
|
+
feature's own name, so behaviour is assertable from tests. -/
|
|
10
|
+
|
|
11
|
+
import VoxgigStruct
|
|
12
|
+
import SdkJson
|
|
13
|
+
import SdkUtility
|
|
14
|
+
import SdkFeature
|
|
15
|
+
|
|
16
|
+
open VoxgigStruct
|
|
17
|
+
open SdkFeature
|
|
18
|
+
|
|
19
|
+
namespace SdkFeatures
|
|
20
|
+
|
|
21
|
+
def gp := SdkUtility.gp
|
|
22
|
+
def sp := SdkUtility.sp
|
|
23
|
+
def gpS := SdkUtility.gpS
|
|
24
|
+
def vs := SdkUtility.vs
|
|
25
|
+
def isNov := SdkUtility.isNov
|
|
26
|
+
def truthy := SdkUtility.truthy
|
|
27
|
+
|
|
28
|
+
def statusOf (v : Value) : Float :=
|
|
29
|
+
match v with
|
|
30
|
+
| .map _ => 0.0
|
|
31
|
+
| _ => 0.0
|
|
32
|
+
|
|
33
|
+
def numOf (v : Value) (d : Float) : Float :=
|
|
34
|
+
match v with
|
|
35
|
+
| .num n => n
|
|
36
|
+
| _ => d
|
|
37
|
+
|
|
38
|
+
/-- Append a value to a struct list held at `key` on `parent`. -/
|
|
39
|
+
def appendTo (parent : Value) (key : String) (v : Value) : SIO Unit := do
|
|
40
|
+
match (← gp parent key) with
|
|
41
|
+
| .list i => do
|
|
42
|
+
let items ← listItems i
|
|
43
|
+
sp parent key (← newList (items.push v))
|
|
44
|
+
| _ => sp parent key (← newList #[v])
|
|
45
|
+
|
|
46
|
+
-- ---------------------------------------------------------------------------
|
|
47
|
+
-- base / log
|
|
48
|
+
-- ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
def baseFeature : SIO Feature := do
|
|
51
|
+
pure { name := "base" }
|
|
52
|
+
|
|
53
|
+
def logFeature : SIO Feature := do
|
|
54
|
+
pure { name := "log"
|
|
55
|
+
, hook := fun stage ctx => do
|
|
56
|
+
if stage == "PreRequest" then do
|
|
57
|
+
let b ← trackCtx ctx "log" (newMap #[("calls", .num 0.0)])
|
|
58
|
+
bumpNum b "calls" 1.0 }
|
|
59
|
+
|
|
60
|
+
-- ---------------------------------------------------------------------------
|
|
61
|
+
-- retry
|
|
62
|
+
-- ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
def retryFeature : SIO Feature := do
|
|
65
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
66
|
+
let retryable (res : Value) (err : Option Value) (statuses : Array Float) : Bool :=
|
|
67
|
+
match err with
|
|
68
|
+
| some _ => true
|
|
69
|
+
| none =>
|
|
70
|
+
match res with
|
|
71
|
+
| .noval => true
|
|
72
|
+
| _ => false
|
|
73
|
+
pure { name := "retry"
|
|
74
|
+
, init := fun ctx opts => do
|
|
75
|
+
let om ← toOptsMap opts
|
|
76
|
+
optsR.set om
|
|
77
|
+
if (← optActive opts) then do
|
|
78
|
+
let client ← clientOf ctx
|
|
79
|
+
let inner ← getFetcher client
|
|
80
|
+
setFetcher client fun c u f => do
|
|
81
|
+
let o ← optsR.get
|
|
82
|
+
let retries := (← optInt o "retries" 2).toNat
|
|
83
|
+
let minDelay ← optNum o "minDelay" 50.0
|
|
84
|
+
let maxDelay ← optNum o "maxDelay" 2000.0
|
|
85
|
+
let factor ← optNum o "factor" 2.0
|
|
86
|
+
let mut attempt := 0
|
|
87
|
+
let mut out ← inner c u f
|
|
88
|
+
while attempt < retries do
|
|
89
|
+
let statusV ← gp out.1 "status"
|
|
90
|
+
let st := numOf statusV 0.0
|
|
91
|
+
let bad := (out.2.isSome) || st >= 500.0 || st == 429.0 || st == 408.0
|
|
92
|
+
if !bad then break
|
|
93
|
+
let mut delay := minDelay
|
|
94
|
+
for _ in [0:attempt] do delay := delay * factor
|
|
95
|
+
sleepMs (if delay > maxDelay then maxDelay else delay)
|
|
96
|
+
let b ← trackCtx c "retry" (newMap #[("attempts", .num 0.0)])
|
|
97
|
+
bumpNum b "attempts" 1.0
|
|
98
|
+
out ← inner c u f
|
|
99
|
+
attempt := attempt + 1
|
|
100
|
+
pure out }
|
|
101
|
+
|
|
102
|
+
-- ---------------------------------------------------------------------------
|
|
103
|
+
-- timeout
|
|
104
|
+
-- ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
def timeoutFeature : SIO Feature := do
|
|
107
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
108
|
+
pure { name := "timeout"
|
|
109
|
+
, init := fun ctx opts => do
|
|
110
|
+
let om ← toOptsMap opts
|
|
111
|
+
optsR.set om
|
|
112
|
+
if (← optActive opts) then do
|
|
113
|
+
let client ← clientOf ctx
|
|
114
|
+
let inner ← getFetcher client
|
|
115
|
+
setFetcher client fun c u f => do
|
|
116
|
+
let o ← optsR.get
|
|
117
|
+
let ms ← optNum o "ms" 30000.0
|
|
118
|
+
if ms <= 0.0 then inner c u f
|
|
119
|
+
else do
|
|
120
|
+
sp f "timeout" (.num (ms / 1000.0))
|
|
121
|
+
let start ← nowMs
|
|
122
|
+
let out ← inner c u f
|
|
123
|
+
let elapsed := (← nowMs) - start
|
|
124
|
+
if elapsed > ms then do
|
|
125
|
+
let b ← trackCtx c "timeout" (newMap #[("count", .num 0.0), ("ms", .num ms)])
|
|
126
|
+
bumpNum b "count" 1.0
|
|
127
|
+
let e ← SdkUtility.mkErr "timeout"
|
|
128
|
+
("Request exceeded timeout of " ++ numToString ms ++ "ms")
|
|
129
|
+
pure (.noval, some e)
|
|
130
|
+
else pure out }
|
|
131
|
+
|
|
132
|
+
-- ---------------------------------------------------------------------------
|
|
133
|
+
-- ratelimit (token bucket)
|
|
134
|
+
-- ---------------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
def ratelimitFeature : SIO Feature := do
|
|
137
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
138
|
+
let tokensR ← IO.mkRef (0.0 : Float)
|
|
139
|
+
let lastR ← IO.mkRef (0.0 : Float)
|
|
140
|
+
pure { name := "ratelimit"
|
|
141
|
+
, init := fun ctx opts => do
|
|
142
|
+
let om ← toOptsMap opts
|
|
143
|
+
optsR.set om
|
|
144
|
+
if (← optActive opts) then do
|
|
145
|
+
let rate ← optNum om "rate" 5.0
|
|
146
|
+
let burst ← optNum om "burst" rate
|
|
147
|
+
tokensR.set burst
|
|
148
|
+
lastR.set (← nowMs)
|
|
149
|
+
let client ← clientOf ctx
|
|
150
|
+
let inner ← getFetcher client
|
|
151
|
+
setFetcher client fun c u f => do
|
|
152
|
+
let o ← optsR.get
|
|
153
|
+
let r ← optNum o "rate" 5.0
|
|
154
|
+
let b ← optNum o "burst" r
|
|
155
|
+
let now ← nowMs
|
|
156
|
+
let elapsed := now - (← lastR.get)
|
|
157
|
+
lastR.set now
|
|
158
|
+
let tk0 := (← tokensR.get) + (elapsed / 1000.0) * r
|
|
159
|
+
let tk := if tk0 > b then b else tk0
|
|
160
|
+
if tk >= 1.0 then tokensR.set (tk - 1.0)
|
|
161
|
+
else do
|
|
162
|
+
let waitMs := ((1.0 - tk) / r) * 1000.0
|
|
163
|
+
let bucket ← trackCtx c "ratelimit"
|
|
164
|
+
(newMap #[("throttled", .num 0.0), ("waitMs", .num 0.0)])
|
|
165
|
+
bumpNum bucket "throttled" 1.0
|
|
166
|
+
bumpNum bucket "waitMs" waitMs
|
|
167
|
+
sleepMs waitMs
|
|
168
|
+
lastR.set (← nowMs)
|
|
169
|
+
tokensR.set 0.0
|
|
170
|
+
inner c u f }
|
|
171
|
+
|
|
172
|
+
-- ---------------------------------------------------------------------------
|
|
173
|
+
-- cache
|
|
174
|
+
-- ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
def cacheFeature : SIO Feature := do
|
|
177
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
178
|
+
let storeR ← IO.mkRef (← emptyMap)
|
|
179
|
+
pure { name := "cache"
|
|
180
|
+
, init := fun ctx opts => do
|
|
181
|
+
let om ← toOptsMap opts
|
|
182
|
+
optsR.set om
|
|
183
|
+
if (← optActive opts) then do
|
|
184
|
+
storeR.set (← emptyMap)
|
|
185
|
+
let client ← clientOf ctx
|
|
186
|
+
let inner ← getFetcher client
|
|
187
|
+
setFetcher client fun c u f => do
|
|
188
|
+
let o ← optsR.get
|
|
189
|
+
let meth := upper (← gpS f "method")
|
|
190
|
+
let methods ← optStrList o "methods" #["GET"]
|
|
191
|
+
if !(methods.map upper).contains (if meth == "" then "GET" else meth) then
|
|
192
|
+
inner c u f
|
|
193
|
+
else do
|
|
194
|
+
let key := meth ++ " " ++ u
|
|
195
|
+
let store ← storeR.get
|
|
196
|
+
let now ← nowMs
|
|
197
|
+
let hit ← gp store key
|
|
198
|
+
let fresh := match hit with
|
|
199
|
+
| .map _ => true
|
|
200
|
+
| _ => false
|
|
201
|
+
let expiry := numOf (← gp hit "expiry") 0.0
|
|
202
|
+
if fresh && expiry > now then do
|
|
203
|
+
let b ← trackCtx c "cache"
|
|
204
|
+
(newMap #[("hit", .num 0.0), ("miss", .num 0.0), ("bypass", .num 0.0)])
|
|
205
|
+
bumpNum b "hit" 1.0
|
|
206
|
+
pure ((← gp hit "snapshot"), none)
|
|
207
|
+
else do
|
|
208
|
+
let out ← inner c u f
|
|
209
|
+
let st := numOf (← gp out.1 "status") 0.0
|
|
210
|
+
let ok := out.2.isNone && st >= 200.0 && st < 300.0
|
|
211
|
+
let b ← trackCtx c "cache"
|
|
212
|
+
(newMap #[("hit", .num 0.0), ("miss", .num 0.0), ("bypass", .num 0.0)])
|
|
213
|
+
if ok then do
|
|
214
|
+
let ttl ← optNum o "ttl" 5000.0
|
|
215
|
+
let snap ← clone out.1
|
|
216
|
+
let entry ← newMap #[("expiry", .num (now + ttl)), ("snapshot", snap)]
|
|
217
|
+
sp store key entry
|
|
218
|
+
bumpNum b "miss" 1.0
|
|
219
|
+
else bumpNum b "bypass" 1.0
|
|
220
|
+
pure out }
|
|
221
|
+
|
|
222
|
+
-- ---------------------------------------------------------------------------
|
|
223
|
+
-- idempotency
|
|
224
|
+
-- ---------------------------------------------------------------------------
|
|
225
|
+
|
|
226
|
+
def idempotencyFeature : SIO Feature := do
|
|
227
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
228
|
+
pure { name := "idempotency"
|
|
229
|
+
, init := fun _ opts => do optsR.set (← toOptsMap opts)
|
|
230
|
+
, hook := fun stage ctx => do
|
|
231
|
+
if stage == "PreRequest" then do
|
|
232
|
+
let o ← optsR.get
|
|
233
|
+
let specV ← gp ctx "spec"
|
|
234
|
+
match specV with
|
|
235
|
+
| .map _ => do
|
|
236
|
+
let methods ← optStrList o "methods" #["POST", "PUT", "PATCH", "DELETE"]
|
|
237
|
+
let meth := upper (← gpS specV "method")
|
|
238
|
+
let ops ← optStrList o "ops" #["create", "update", "remove"]
|
|
239
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
240
|
+
if (methods.map upper).contains meth || ops.contains opname then do
|
|
241
|
+
let header ← optStr o "header" "Idempotency-Key"
|
|
242
|
+
let hdrs ← SdkUtility.gpMap specV "headers"
|
|
243
|
+
if isNov (← headerCI hdrs header) then do
|
|
244
|
+
let key ← genId
|
|
245
|
+
sp hdrs header (.str key)
|
|
246
|
+
let b ← trackCtx ctx "idempotency"
|
|
247
|
+
(newMap #[("issued", .num 0.0), ("last", .noval)])
|
|
248
|
+
bumpNum b "issued" 1.0
|
|
249
|
+
sp b "last" (.str key)
|
|
250
|
+
| _ => pure () }
|
|
251
|
+
|
|
252
|
+
-- ---------------------------------------------------------------------------
|
|
253
|
+
-- rbac (PrePoint short-circuit)
|
|
254
|
+
-- ---------------------------------------------------------------------------
|
|
255
|
+
|
|
256
|
+
def rbacFeature : SIO Feature := do
|
|
257
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
258
|
+
pure { name := "rbac"
|
|
259
|
+
, init := fun _ opts => do optsR.set (← toOptsMap opts)
|
|
260
|
+
, hook := fun stage ctx => do
|
|
261
|
+
if stage == "PrePoint" then do
|
|
262
|
+
let o ← optsR.get
|
|
263
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
264
|
+
let perms ← optStrList o "perms" #[]
|
|
265
|
+
let rules ← gp o "rules"
|
|
266
|
+
let required ← gpS rules opname
|
|
267
|
+
let deny := truthy (← gp o "deny")
|
|
268
|
+
let needed := if required != "" then required else (if deny then "<default-deny>" else "")
|
|
269
|
+
let allowed := needed == "" || perms.contains needed
|
|
270
|
+
let b ← trackCtx ctx "rbac"
|
|
271
|
+
(newMap #[("allowed", .num 0.0), ("denied", .num 0.0), ("last", .noval)])
|
|
272
|
+
bumpNum b (if allowed then "allowed" else "denied") 1.0
|
|
273
|
+
sp b "last" (.str needed)
|
|
274
|
+
if !allowed then do
|
|
275
|
+
let e ← SdkUtility.mkErr "rbac_denied"
|
|
276
|
+
("Permission \"" ++ needed ++ "\" required for operation \"" ++ opname ++ "\"")
|
|
277
|
+
let out ← SdkUtility.gpMap ctx "out"
|
|
278
|
+
sp out "point" e }
|
|
279
|
+
|
|
280
|
+
-- ---------------------------------------------------------------------------
|
|
281
|
+
-- metrics
|
|
282
|
+
-- ---------------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
def metricsFeature : SIO Feature := do
|
|
285
|
+
let startR ← IO.mkRef (0.0 : Float)
|
|
286
|
+
pure { name := "metrics"
|
|
287
|
+
, hook := fun stage ctx => do
|
|
288
|
+
let mk : SIO Value := do
|
|
289
|
+
let tot ← newMap #[("count", .num 0.0), ("ok", .num 0.0), ("err", .num 0.0),
|
|
290
|
+
("totalMs", .num 0.0), ("maxMs", .num 0.0)]
|
|
291
|
+
let ops ← emptyMap
|
|
292
|
+
newMap #[("total", tot), ("ops", ops)]
|
|
293
|
+
if stage == "PreRequest" then startR.set (← nowMs)
|
|
294
|
+
else if stage == "PreDone" then do
|
|
295
|
+
let m ← trackCtx ctx "metrics" mk
|
|
296
|
+
let dur := (← nowMs) - (← startR.get)
|
|
297
|
+
let total ← gp m "total"
|
|
298
|
+
let res ← gp ctx "result"
|
|
299
|
+
let ok := truthy (← gp res "ok")
|
|
300
|
+
bumpNum total "count" 1.0
|
|
301
|
+
bumpNum total (if ok then "ok" else "err") 1.0
|
|
302
|
+
bumpNum total "totalMs" dur
|
|
303
|
+
if dur > numOf (← gp total "maxMs") 0.0 then sp total "maxMs" (.num dur)
|
|
304
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
305
|
+
let ops ← gp m "ops"
|
|
306
|
+
let key := (← gpS (← gp ctx "op") "entity") ++ "." ++ opname
|
|
307
|
+
let opb ← (match (← gp ops key) with
|
|
308
|
+
| .map i => pure (Value.map i)
|
|
309
|
+
| _ => do
|
|
310
|
+
let b ← newMap #[("count", .num 0.0), ("ok", .num 0.0), ("err", .num 0.0),
|
|
311
|
+
("totalMs", .num 0.0), ("maxMs", .num 0.0)]
|
|
312
|
+
sp ops key b
|
|
313
|
+
pure b)
|
|
314
|
+
bumpNum opb "count" 1.0
|
|
315
|
+
bumpNum opb (if ok then "ok" else "err") 1.0
|
|
316
|
+
bumpNum opb "totalMs" dur }
|
|
317
|
+
|
|
318
|
+
-- ---------------------------------------------------------------------------
|
|
319
|
+
-- telemetry (spans)
|
|
320
|
+
-- ---------------------------------------------------------------------------
|
|
321
|
+
|
|
322
|
+
def telemetryFeature : SIO Feature := do
|
|
323
|
+
let spanR ← IO.mkRef (Value.noval)
|
|
324
|
+
pure { name := "telemetry"
|
|
325
|
+
, hook := fun stage ctx => do
|
|
326
|
+
let mk : SIO Value := do
|
|
327
|
+
let sp0 ← emptyList
|
|
328
|
+
newMap #[("spans", sp0), ("active", .num 0.0)]
|
|
329
|
+
if stage == "PrePoint" then do
|
|
330
|
+
let t ← trackCtx ctx "telemetry" mk
|
|
331
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
332
|
+
let sid ← genId
|
|
333
|
+
let s ← newMap #[("id", .str ("s" ++ sid)), ("name", .str opname),
|
|
334
|
+
("start", .num (← nowMs)), ("ok", .bool false)]
|
|
335
|
+
spanR.set s
|
|
336
|
+
appendTo t "spans" s
|
|
337
|
+
bumpNum t "active" 1.0
|
|
338
|
+
else if stage == "PreDone" then do
|
|
339
|
+
let s ← spanR.get
|
|
340
|
+
match s with
|
|
341
|
+
| .map _ => do
|
|
342
|
+
let t ← trackCtx ctx "telemetry" mk
|
|
343
|
+
let endMs ← nowMs
|
|
344
|
+
sp s "end" (.num endMs)
|
|
345
|
+
sp s "durationMs" (.num (endMs - numOf (← gp s "start") 0.0))
|
|
346
|
+
sp s "ok" (.bool (truthy (← gp (← gp ctx "result") "ok")))
|
|
347
|
+
bumpNum t "active" (-1.0)
|
|
348
|
+
| _ => pure () }
|
|
349
|
+
|
|
350
|
+
-- ---------------------------------------------------------------------------
|
|
351
|
+
-- debug (redacted request/response log)
|
|
352
|
+
-- ---------------------------------------------------------------------------
|
|
353
|
+
|
|
354
|
+
def debugFeature : SIO Feature := do
|
|
355
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
356
|
+
let entryR ← IO.mkRef (Value.noval)
|
|
357
|
+
pure { name := "debug"
|
|
358
|
+
, init := fun _ opts => do optsR.set (← toOptsMap opts)
|
|
359
|
+
, hook := fun stage ctx => do
|
|
360
|
+
let mk : SIO Value := do
|
|
361
|
+
let es ← emptyList
|
|
362
|
+
newMap #[("entries", es)]
|
|
363
|
+
if stage == "PreRequest" then do
|
|
364
|
+
let o ← optsR.get
|
|
365
|
+
let d ← trackCtx ctx "debug" mk
|
|
366
|
+
let patterns ← optStrList o "redact"
|
|
367
|
+
#["authorization", "cookie", "set-cookie", "api-key", "apikey",
|
|
368
|
+
"x-api-key", "idempotency-key"]
|
|
369
|
+
let specV ← gp ctx "spec"
|
|
370
|
+
let hdrs ← gp specV "headers"
|
|
371
|
+
let safe ← emptyMap
|
|
372
|
+
match hdrs with
|
|
373
|
+
| .map i =>
|
|
374
|
+
for k in (← keysof (.map i)) do
|
|
375
|
+
if patterns.contains (lower k) then sp safe k (.str "<redacted>")
|
|
376
|
+
else sp safe k (← gp (.map i) k)
|
|
377
|
+
| _ => pure ()
|
|
378
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
379
|
+
let e ← newMap #[("op", .str opname), ("start", .num (← nowMs)),
|
|
380
|
+
("headers", safe), ("ok", .bool false)]
|
|
381
|
+
entryR.set e
|
|
382
|
+
appendTo d "entries" e
|
|
383
|
+
else if stage == "PreDone" then do
|
|
384
|
+
let e ← entryR.get
|
|
385
|
+
match e with
|
|
386
|
+
| .map _ => do
|
|
387
|
+
let endMs ← nowMs
|
|
388
|
+
sp e "durationMs" (.num (endMs - numOf (← gp e "start") 0.0))
|
|
389
|
+
let res ← gp ctx "result"
|
|
390
|
+
sp e "ok" (.bool (truthy (← gp res "ok")))
|
|
391
|
+
sp e "status" (← gp res "status")
|
|
392
|
+
| _ => pure () }
|
|
393
|
+
|
|
394
|
+
-- ---------------------------------------------------------------------------
|
|
395
|
+
-- audit
|
|
396
|
+
-- ---------------------------------------------------------------------------
|
|
397
|
+
|
|
398
|
+
def auditFeature : SIO Feature := do
|
|
399
|
+
pure { name := "audit"
|
|
400
|
+
, hook := fun stage ctx => do
|
|
401
|
+
if stage == "PreDone" then do
|
|
402
|
+
let a ← trackCtx ctx "audit" (do let rs ← emptyList; newMap #[("records", rs)])
|
|
403
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
404
|
+
let res ← gp ctx "result"
|
|
405
|
+
let rec0 ← newMap #[("op", .str opname),
|
|
406
|
+
("entity", ← gp (← gp ctx "op") "entity"),
|
|
407
|
+
("ok", .bool (truthy (← gp res "ok"))),
|
|
408
|
+
("at", .num (← nowMs))]
|
|
409
|
+
appendTo a "records" rec0 }
|
|
410
|
+
|
|
411
|
+
-- ---------------------------------------------------------------------------
|
|
412
|
+
-- clienttrack (request/session identity headers)
|
|
413
|
+
-- ---------------------------------------------------------------------------
|
|
414
|
+
|
|
415
|
+
def clienttrackFeature : SIO Feature := do
|
|
416
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
417
|
+
let sessionR ← IO.mkRef ""
|
|
418
|
+
pure { name := "clienttrack"
|
|
419
|
+
, init := fun _ opts => do
|
|
420
|
+
optsR.set (← toOptsMap opts)
|
|
421
|
+
if (← sessionR.get) == "" then sessionR.set ("s-" ++ (← genId))
|
|
422
|
+
, hook := fun stage ctx => do
|
|
423
|
+
if stage == "PreRequest" then do
|
|
424
|
+
let o ← optsR.get
|
|
425
|
+
let nm ← optStr o "clientName" "ProjectName-SDK"
|
|
426
|
+
let ver ← optStr o "clientVersion" "0.0.1"
|
|
427
|
+
let rid := "r-" ++ (← genId)
|
|
428
|
+
let session ← sessionR.get
|
|
429
|
+
let specV ← gp ctx "spec"
|
|
430
|
+
let hdrs ← SdkUtility.gpMap specV "headers"
|
|
431
|
+
let hopt ← gp o "headers"
|
|
432
|
+
let reqH ← optStr hopt "request" "X-Request-Id"
|
|
433
|
+
let sesH ← optStr hopt "session" "X-Session-Id"
|
|
434
|
+
let cliH ← optStr hopt "client" "X-Client"
|
|
435
|
+
if isNov (← headerCI hdrs reqH) then sp hdrs reqH (.str rid)
|
|
436
|
+
if isNov (← headerCI hdrs sesH) then sp hdrs sesH (.str session)
|
|
437
|
+
if isNov (← headerCI hdrs cliH) then sp hdrs cliH (.str (nm ++ "/" ++ ver))
|
|
438
|
+
let b ← trackCtx ctx "clienttrack"
|
|
439
|
+
(newMap #[("session", .str session), ("requests", .num 0.0),
|
|
440
|
+
("clientName", .str nm)])
|
|
441
|
+
bumpNum b "requests" 1.0
|
|
442
|
+
sp b "lastRequestId" (.str rid) }
|
|
443
|
+
|
|
444
|
+
-- ---------------------------------------------------------------------------
|
|
445
|
+
-- paging / streaming
|
|
446
|
+
-- ---------------------------------------------------------------------------
|
|
447
|
+
|
|
448
|
+
def pagingFeature : SIO Feature := do
|
|
449
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
450
|
+
pure { name := "paging"
|
|
451
|
+
, init := fun _ opts => do optsR.set (← toOptsMap opts)
|
|
452
|
+
, hook := fun stage ctx => do
|
|
453
|
+
if stage == "PreSpec" then do
|
|
454
|
+
let o ← optsR.get
|
|
455
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
456
|
+
if opname == "list" then do
|
|
457
|
+
let sizeKey ← optStr o "sizeParam" "limit"
|
|
458
|
+
let pageKey ← optStr o "pageParam" "page"
|
|
459
|
+
let sizeV ← gp o "size"
|
|
460
|
+
let specV ← gp ctx "spec"
|
|
461
|
+
match specV with
|
|
462
|
+
| .map _ => do
|
|
463
|
+
let q ← SdkUtility.gpMap specV "query"
|
|
464
|
+
if !(isNov sizeV) then sp q sizeKey sizeV
|
|
465
|
+
let pageV ← gp o "page"
|
|
466
|
+
if !(isNov pageV) then sp q pageKey pageV
|
|
467
|
+
let b ← trackCtx ctx "paging"
|
|
468
|
+
(newMap #[("pages", .num 0.0), ("items", .num 0.0)])
|
|
469
|
+
bumpNum b "pages" 1.0
|
|
470
|
+
| _ => pure ()
|
|
471
|
+
else if stage == "PreDone" then do
|
|
472
|
+
let opname ← SdkUtility.opnameOf ctx
|
|
473
|
+
if opname == "list" then do
|
|
474
|
+
let res ← gp ctx "result"
|
|
475
|
+
let n ← (match (← gp res "resdata") with
|
|
476
|
+
| .list i => do pure (← listItems i).size
|
|
477
|
+
| _ => pure 0)
|
|
478
|
+
let b ← trackCtx ctx "paging"
|
|
479
|
+
(newMap #[("pages", .num 0.0), ("items", .num 0.0)])
|
|
480
|
+
bumpNum b "items" n.toFloat }
|
|
481
|
+
|
|
482
|
+
def streamingFeature : SIO Feature := do
|
|
483
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
484
|
+
pure { name := "streaming"
|
|
485
|
+
, init := fun _ opts => do optsR.set (← toOptsMap opts)
|
|
486
|
+
, hook := fun stage ctx => do
|
|
487
|
+
if stage == "PreDone" then do
|
|
488
|
+
let res ← gp ctx "result"
|
|
489
|
+
let items ← gp res "resdata"
|
|
490
|
+
match items with
|
|
491
|
+
| .list i => do
|
|
492
|
+
let its ← listItems i
|
|
493
|
+
let b ← trackCtx ctx "streaming"
|
|
494
|
+
(newMap #[("emitted", .num 0.0), ("chunks", .num 0.0)])
|
|
495
|
+
bumpNum b "emitted" its.size.toFloat
|
|
496
|
+
bumpNum b "chunks" 1.0
|
|
497
|
+
| _ => pure () }
|
|
498
|
+
|
|
499
|
+
-- ---------------------------------------------------------------------------
|
|
500
|
+
-- proxy
|
|
501
|
+
-- ---------------------------------------------------------------------------
|
|
502
|
+
|
|
503
|
+
def proxyFeature : SIO Feature := do
|
|
504
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
505
|
+
pure { name := "proxy"
|
|
506
|
+
, init := fun ctx opts => do
|
|
507
|
+
let om ← toOptsMap opts
|
|
508
|
+
optsR.set om
|
|
509
|
+
if (← optActive opts) then do
|
|
510
|
+
let client ← clientOf ctx
|
|
511
|
+
let inner ← getFetcher client
|
|
512
|
+
setFetcher client fun c u f => do
|
|
513
|
+
let o ← optsR.get
|
|
514
|
+
let purl ← gpS o "url"
|
|
515
|
+
if purl == "" then inner c u f
|
|
516
|
+
else do
|
|
517
|
+
sp f "proxy" (.str purl)
|
|
518
|
+
let proxies ← newMap #[("http", .str purl), ("https", .str purl)]
|
|
519
|
+
sp f "proxies" proxies
|
|
520
|
+
let b ← trackCtx c "proxy"
|
|
521
|
+
(newMap #[("routed", .num 0.0), ("url", .str purl)])
|
|
522
|
+
bumpNum b "routed" 1.0
|
|
523
|
+
inner c u f }
|
|
524
|
+
|
|
525
|
+
-- ---------------------------------------------------------------------------
|
|
526
|
+
-- netsim (offline / latency / failStatus simulation)
|
|
527
|
+
-- ---------------------------------------------------------------------------
|
|
528
|
+
|
|
529
|
+
def netsimFeature : SIO Feature := do
|
|
530
|
+
let optsR ← IO.mkRef (← emptyMap)
|
|
531
|
+
let seedR ← IO.mkRef (12345 : Nat)
|
|
532
|
+
let callR ← IO.mkRef (0 : Nat)
|
|
533
|
+
pure { name := "netsim"
|
|
534
|
+
, init := fun ctx opts => do
|
|
535
|
+
let om ← toOptsMap opts
|
|
536
|
+
optsR.set om
|
|
537
|
+
if (← optActive opts) then do
|
|
538
|
+
let client ← clientOf ctx
|
|
539
|
+
let inner ← getFetcher client
|
|
540
|
+
setFetcher client fun c u f => do
|
|
541
|
+
let o ← optsR.get
|
|
542
|
+
let call := (← callR.get) + 1
|
|
543
|
+
callR.set call
|
|
544
|
+
let applied ← emptyMap
|
|
545
|
+
let b ← trackCtx c "netsim"
|
|
546
|
+
(do let ap ← emptyList; newMap #[("calls", .num 0.0), ("applied", ap)])
|
|
547
|
+
bumpNum b "calls" 1.0
|
|
548
|
+
-- deterministic LCG for latency jitter
|
|
549
|
+
let s := ((← seedR.get) * 1103515245 + 12345) % 2147483648
|
|
550
|
+
seedR.set s
|
|
551
|
+
let lat ← optNum o "latency" 0.0
|
|
552
|
+
if lat > 0.0 then sleepMs lat
|
|
553
|
+
if truthy (← gp o "offline") then do
|
|
554
|
+
sp applied "offline" (.bool true)
|
|
555
|
+
appendTo b "applied" applied
|
|
556
|
+
let e ← SdkUtility.mkErr "netsim_offline"
|
|
557
|
+
("Simulated network offline (URL was: \"" ++ u ++ "\")")
|
|
558
|
+
pure (.noval, some e)
|
|
559
|
+
else do
|
|
560
|
+
let fs ← optNum o "failStatus" 0.0
|
|
561
|
+
if fs > 0.0 then do
|
|
562
|
+
sp applied "failStatus" (.num fs)
|
|
563
|
+
appendTo b "applied" applied
|
|
564
|
+
let resp ← newMap #[("status", .num fs), ("statusText", .str "Simulated"),
|
|
565
|
+
("body", ← emptyMap)]
|
|
566
|
+
pure (resp, none)
|
|
567
|
+
else do
|
|
568
|
+
appendTo b "applied" applied
|
|
569
|
+
inner c u f }
|
|
570
|
+
|
|
571
|
+
-- ---------------------------------------------------------------------------
|
|
572
|
+
-- the catalog
|
|
573
|
+
-- ---------------------------------------------------------------------------
|
|
574
|
+
|
|
575
|
+
/-- Every feature by name (the factory the client uses). -/
|
|
576
|
+
def makeFeature (name : String) : SIO Feature :=
|
|
577
|
+
match name with
|
|
578
|
+
| "log" => logFeature
|
|
579
|
+
| "retry" => retryFeature
|
|
580
|
+
| "timeout" => timeoutFeature
|
|
581
|
+
| "ratelimit" => ratelimitFeature
|
|
582
|
+
| "cache" => cacheFeature
|
|
583
|
+
| "idempotency" => idempotencyFeature
|
|
584
|
+
| "rbac" => rbacFeature
|
|
585
|
+
| "metrics" => metricsFeature
|
|
586
|
+
| "telemetry" => telemetryFeature
|
|
587
|
+
| "debug" => debugFeature
|
|
588
|
+
| "audit" => auditFeature
|
|
589
|
+
| "clienttrack" => clienttrackFeature
|
|
590
|
+
| "paging" => pagingFeature
|
|
591
|
+
| "streaming" => streamingFeature
|
|
592
|
+
| "proxy" => proxyFeature
|
|
593
|
+
| "netsim" => netsimFeature
|
|
594
|
+
| _ => baseFeature
|
|
595
|
+
|
|
596
|
+
/-- The catalog order: transport wrappers compose in this order. -/
|
|
597
|
+
def featureNames : Array String :=
|
|
598
|
+
#["log", "rbac", "idempotency", "clienttrack", "paging", "streaming",
|
|
599
|
+
"metrics", "telemetry", "debug", "audit",
|
|
600
|
+
"cache", "ratelimit", "timeout", "retry", "proxy", "netsim"]
|
|
601
|
+
|
|
602
|
+
end SdkFeatures
|