@voxgig/sdkgen 4.32.0 → 4.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/helpers/naming.js +1 -1
- package/dist/helpers/naming.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/model/sdkgen.aontu +7 -1
- package/package.json +1 -1
- package/project/.sdk/model/feature/debug.aontu +3 -1
- package/project/.sdk/src/cmp/c/PrepareAuth_c.ts +8 -28
- package/project/.sdk/src/cmp/c/TestClean_c.ts +774 -0
- package/project/.sdk/src/cmp/c/Test_c.ts +3 -0
- package/project/.sdk/src/cmp/c/fragment/Entity.fragment.c +16 -5
- package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +1 -1
- package/project/.sdk/src/cmp/clojure/PrepareAuth_clojure.ts +3 -0
- package/project/.sdk/src/cmp/clojure/TestClean_clojure.ts +473 -0
- package/project/.sdk/src/cmp/clojure/Test_clojure.ts +6 -0
- package/project/.sdk/src/cmp/clojure/fragment/Entity.fragment.clj +18 -8
- package/project/.sdk/src/cmp/cpp/PrepareAuth_cpp.ts +3 -0
- package/project/.sdk/src/cmp/cpp/TestClean_cpp.ts +782 -0
- package/project/.sdk/src/cmp/cpp/TestEntity_cpp.ts +1 -1
- package/project/.sdk/src/cmp/cpp/Test_cpp.ts +2 -0
- package/project/.sdk/src/cmp/csharp/PrepareAuth_csharp.ts +3 -0
- package/project/.sdk/src/cmp/csharp/TestClean_csharp.ts +887 -0
- package/project/.sdk/src/cmp/csharp/Test_csharp.ts +2 -0
- package/project/.sdk/src/cmp/csharp/fragment/EntityBase.fragment.cs +68 -4
- package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +8 -2
- package/project/.sdk/src/cmp/csharp/fragment/SdkError.fragment.cs +49 -0
- package/project/.sdk/src/cmp/elixir/PrepareAuth_elixir.ts +3 -0
- package/project/.sdk/src/cmp/elixir/Schema_elixir.ts +20 -10
- package/project/.sdk/src/cmp/elixir/TestClean_elixir.ts +666 -0
- package/project/.sdk/src/cmp/elixir/Test_elixir.ts +4 -0
- package/project/.sdk/src/cmp/elixir/fragment/Main.fragment.ex +1 -1
- package/project/.sdk/src/cmp/elixir/fragment/Pipeline.fragment.ex +14 -2
- package/project/.sdk/src/cmp/go/PrepareAuth_go.ts +3 -0
- package/project/.sdk/src/cmp/go/TestClean_go.ts +804 -0
- package/project/.sdk/src/cmp/go/Test_go.ts +3 -0
- package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +54 -4
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +27 -2
- package/project/.sdk/src/cmp/java/PrepareAuth_java.ts +3 -0
- package/project/.sdk/src/cmp/java/TestClean_java.ts +884 -0
- package/project/.sdk/src/cmp/java/Test_java.ts +2 -0
- package/project/.sdk/src/cmp/java/fragment/EntityBase.fragment.java +56 -11
- package/project/.sdk/src/cmp/java/fragment/SdkError.fragment.java +36 -3
- package/project/.sdk/src/cmp/js/PrepareAuth_js.ts +3 -0
- package/project/.sdk/src/cmp/js/TestClean_js.ts +458 -0
- package/project/.sdk/src/cmp/js/Test_js.ts +2 -0
- package/project/.sdk/src/cmp/js/fragment/EntityBase.fragment.js +5 -4
- package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +7 -1
- package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +11 -2
- package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +17 -1
- package/project/.sdk/src/cmp/kotlin/Package_kotlin.ts +5 -0
- package/project/.sdk/src/cmp/kotlin/PrepareAuth_kotlin.ts +3 -0
- package/project/.sdk/src/cmp/kotlin/TestClean_kotlin.ts +654 -0
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +3 -0
- package/project/.sdk/src/cmp/kotlin/fragment/EntityBase.fragment.kt +44 -11
- package/project/.sdk/src/cmp/kotlin/fragment/SdkError.fragment.kt +31 -0
- package/project/.sdk/src/cmp/lua/PrepareAuth_lua.ts +3 -0
- package/project/.sdk/src/cmp/lua/TestClean_lua.ts +769 -0
- package/project/.sdk/src/cmp/lua/Test_lua.ts +3 -0
- package/project/.sdk/src/cmp/lua/fragment/Entity.fragment.lua +77 -1
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +49 -2
- package/project/.sdk/src/cmp/ocaml/Entity_ocaml.ts +3 -2
- package/project/.sdk/src/cmp/ocaml/PrepareAuth_ocaml.ts +4 -25
- package/project/.sdk/src/cmp/ocaml/TestClean_ocaml.ts +538 -0
- package/project/.sdk/src/cmp/ocaml/Test_ocaml.ts +5 -0
- package/project/.sdk/src/cmp/ocaml/fragment/RunOp.fragment.ml +16 -4
- package/project/.sdk/src/cmp/perl/PrepareAuth_perl.ts +3 -0
- package/project/.sdk/src/cmp/perl/TestClean_perl.ts +619 -0
- package/project/.sdk/src/cmp/perl/Test_perl.ts +3 -0
- package/project/.sdk/src/cmp/perl/fragment/Entity.fragment.pm +67 -5
- package/project/.sdk/src/cmp/perl/fragment/Main.fragment.pm +13 -1
- package/project/.sdk/src/cmp/php/PrepareAuth_php.ts +3 -0
- package/project/.sdk/src/cmp/php/TestClean_php.ts +809 -0
- package/project/.sdk/src/cmp/php/Test_php.ts +2 -0
- package/project/.sdk/src/cmp/php/fragment/Entity.fragment.php +96 -55
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +15 -2
- package/project/.sdk/src/cmp/py/PrepareAuth_py.ts +3 -0
- package/project/.sdk/src/cmp/py/TestClean_py.ts +549 -0
- package/project/.sdk/src/cmp/py/Test_py.ts +3 -0
- package/project/.sdk/src/cmp/py/fragment/Entity.fragment.py +83 -55
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +19 -3
- package/project/.sdk/src/cmp/rb/PrepareAuth_rb.ts +3 -0
- package/project/.sdk/src/cmp/rb/TestClean_rb.ts +535 -0
- package/project/.sdk/src/cmp/rb/Test_rb.ts +3 -0
- package/project/.sdk/src/cmp/rb/fragment/Entity.fragment.rb +108 -46
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +12 -1
- package/project/.sdk/src/cmp/rust/PrepareAuth_rust.ts +9 -45
- package/project/.sdk/src/cmp/rust/TestClean_rust.ts +881 -0
- package/project/.sdk/src/cmp/rust/Test_rust.ts +3 -0
- package/project/.sdk/src/cmp/rust/fragment/Entity.fragment.rs +14 -6
- package/project/.sdk/src/cmp/rust/fragment/Main.fragment.rs +17 -1
- package/project/.sdk/src/cmp/rust/fragment/SdkError.fragment.rs +34 -2
- package/project/.sdk/src/cmp/scala/PrepareAuth_scala.ts +3 -0
- package/project/.sdk/src/cmp/scala/TestClean_scala.ts +608 -0
- package/project/.sdk/src/cmp/scala/Test_scala.ts +3 -0
- package/project/.sdk/src/cmp/scala/fragment/EntityBase.fragment.scala +58 -6
- package/project/.sdk/src/cmp/swift/PrepareAuth_swift.ts +3 -0
- package/project/.sdk/src/cmp/swift/TestClean_swift.ts +671 -0
- package/project/.sdk/src/cmp/swift/Test_swift.ts +3 -0
- package/project/.sdk/src/cmp/swift/fragment/EntityBase.fragment.swift +10 -0
- package/project/.sdk/src/cmp/swift/fragment/Main.fragment.swift +16 -2
- package/project/.sdk/src/cmp/swift/fragment/SdkError.fragment.swift +47 -3
- package/project/.sdk/src/cmp/ts/PrepareAuth_ts.ts +3 -0
- package/project/.sdk/src/cmp/ts/TestClean_ts.ts +465 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +2 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityBase.fragment.ts +5 -4
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +7 -1
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +8 -2
- package/project/.sdk/src/cmp/ts/fragment/SdkError.fragment.ts +20 -2
- package/project/.sdk/src/cmp/zig/PrepareAuth_zig.ts +3 -0
- package/project/.sdk/src/cmp/zig/TestClean_zig.ts +791 -0
- package/project/.sdk/src/cmp/zig/Test_zig.ts +5 -0
- package/project/.sdk/src/cmp/zig/fragment/Build.fragment.zig +19 -0
- package/project/.sdk/src/cmp/zig/fragment/Entity.fragment.zig +14 -5
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +1 -1
- package/project/.sdk/tm/c/core/context.c +25 -0
- package/project/.sdk/tm/c/core/error.c +16 -0
- package/project/.sdk/tm/c/core/sdk.h +22 -0
- package/project/.sdk/tm/c/feature/audit.c +2 -0
- package/project/.sdk/tm/c/feature/cost.c +1 -0
- package/project/.sdk/tm/c/feature/debug.c +19 -29
- package/project/.sdk/tm/c/feature/log.c +21 -2
- package/project/.sdk/tm/c/feature/proxy.c +55 -3
- package/project/.sdk/tm/c/feature/secrets.c +7 -0
- package/project/.sdk/tm/c/feature/telemetry.c +2 -0
- package/project/.sdk/tm/c/tests/feature_test.c +2 -2
- package/project/.sdk/tm/c/utility/clean.c +530 -8
- package/project/.sdk/tm/c/utility/done.c +28 -12
- package/project/.sdk/tm/c/utility/make_error.c +4 -3
- package/project/.sdk/tm/c/utility/make_options.c +71 -45
- package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +15 -0
- package/project/.sdk/tm/clojure/src/sdk/client.clj +20 -4
- package/project/.sdk/tm/clojure/src/sdk/core.clj +319 -35
- package/project/.sdk/tm/clojure/src/sdk/features.clj +68 -30
- package/project/.sdk/tm/clojure/test/sdk/test/feature.clj +4 -2
- package/project/.sdk/tm/clojure/test/sdk/test/pipeline.clj +47 -20
- package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +4 -0
- package/project/.sdk/tm/cpp/core/types.hpp +93 -3
- package/project/.sdk/tm/cpp/feature/audit.hpp +1 -0
- package/project/.sdk/tm/cpp/feature/cost.hpp +1 -0
- package/project/.sdk/tm/cpp/feature/debug.hpp +20 -12
- package/project/.sdk/tm/cpp/feature/log.hpp +31 -9
- package/project/.sdk/tm/cpp/feature/proxy.hpp +52 -6
- package/project/.sdk/tm/cpp/feature/secrets.hpp +13 -0
- package/project/.sdk/tm/cpp/feature/telemetry.hpp +4 -2
- package/project/.sdk/tm/cpp/test/feature_test.cpp +2 -2
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +426 -51
- package/project/.sdk/tm/csharp/core/Context.cs +32 -0
- package/project/.sdk/tm/csharp/core/Utility.cs +2 -0
- package/project/.sdk/tm/csharp/feature/AuditFeature.cs +1 -0
- package/project/.sdk/tm/csharp/feature/CostFeature.cs +7 -5
- package/project/.sdk/tm/csharp/feature/DebugFeature.cs +19 -16
- package/project/.sdk/tm/csharp/feature/FeatureOptions.cs +16 -0
- package/project/.sdk/tm/csharp/feature/LogFeature.cs +4 -1
- package/project/.sdk/tm/csharp/feature/ProxyFeature.cs +26 -5
- package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +16 -0
- package/project/.sdk/tm/csharp/feature/TelemetryFeature.cs +4 -2
- package/project/.sdk/tm/csharp/test/FeatureTest.cs +2 -2
- package/project/.sdk/tm/csharp/utility/Clean.cs +440 -2
- package/project/.sdk/tm/csharp/utility/Done.cs +27 -11
- package/project/.sdk/tm/csharp/utility/MakeError.cs +19 -8
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +119 -29
- package/project/.sdk/tm/csharp/utility/MakeResponse.cs +21 -11
- package/project/.sdk/tm/csharp/utility/Register.cs +1 -0
- package/project/.sdk/tm/elixir/lib/projectname/context.ex +19 -0
- package/project/.sdk/tm/elixir/lib/projectname/entity_base.ex +22 -1
- package/project/.sdk/tm/elixir/lib/projectname/error.ex +24 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/audit.ex +2 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature/cost.ex +2 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature/debug.ex +13 -13
- package/project/.sdk/tm/elixir/lib/projectname/feature/log.ex +18 -5
- package/project/.sdk/tm/elixir/lib/projectname/feature/proxy.ex +19 -1
- package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +15 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/telemetry.ex +4 -2
- package/project/.sdk/tm/elixir/lib/projectname/feature.ex +22 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +464 -41
- package/project/.sdk/tm/elixir/test/feature_test.exs +3 -2
- package/project/.sdk/tm/go/core/context.go +42 -0
- package/project/.sdk/tm/go/core/error.go +30 -10
- package/project/.sdk/tm/go/core/utility_type.go +2 -0
- package/project/.sdk/tm/go/feature/audit_feature.go +1 -0
- package/project/.sdk/tm/go/feature/base_feature.go +12 -0
- package/project/.sdk/tm/go/feature/cost_feature.go +2 -2
- package/project/.sdk/tm/go/feature/debug_feature.go +14 -12
- package/project/.sdk/tm/go/feature/log_feature.go +13 -8
- package/project/.sdk/tm/go/feature/proxy_feature.go +26 -6
- package/project/.sdk/tm/go/feature/secrets_feature.go +19 -0
- package/project/.sdk/tm/go/feature/telemetry_feature.go +4 -2
- package/project/.sdk/tm/go/test/feature_test.go +2 -2
- package/project/.sdk/tm/go/utility/clean.go +585 -2
- package/project/.sdk/tm/go/utility/done.go +29 -9
- package/project/.sdk/tm/go/utility/make_error.go +51 -16
- package/project/.sdk/tm/go/utility/make_options.go +77 -36
- package/project/.sdk/tm/go/utility/register.go +12 -0
- package/project/.sdk/tm/java/core/Context.java +29 -0
- package/project/.sdk/tm/java/core/SdkClient.java +4 -2
- package/project/.sdk/tm/java/core/Utility.java +7 -0
- package/project/.sdk/tm/java/feature/AuditFeature.java +6 -0
- package/project/.sdk/tm/java/feature/CostFeature.java +5 -0
- package/project/.sdk/tm/java/feature/DebugFeature.java +25 -14
- package/project/.sdk/tm/java/feature/LogFeature.java +11 -4
- package/project/.sdk/tm/java/feature/ProxyFeature.java +41 -6
- package/project/.sdk/tm/java/feature/SecretsFeature.java +18 -0
- package/project/.sdk/tm/java/feature/TelemetryFeature.java +8 -2
- package/project/.sdk/tm/java/test/FeatureTest.java +2 -2
- package/project/.sdk/tm/java/utility/Clean.java +519 -1
- package/project/.sdk/tm/java/utility/Done.java +1 -1
- package/project/.sdk/tm/java/utility/MakeError.java +5 -1
- package/project/.sdk/tm/java/utility/MakeOptions.java +55 -31
- package/project/.sdk/tm/java/utility/Register.java +4 -0
- package/project/.sdk/tm/js/src/Context.js +5 -1
- package/project/.sdk/tm/js/src/Response.js +14 -1
- package/project/.sdk/tm/js/src/feature/audit/AuditFeature.js +2 -2
- package/project/.sdk/tm/js/src/feature/cost/CostFeature.js +2 -2
- package/project/.sdk/tm/js/src/feature/debug/DebugFeature.js +13 -7
- package/project/.sdk/tm/js/src/feature/log/LogFeature.js +9 -5
- package/project/.sdk/tm/js/src/feature/proxy/ProxyFeature.js +19 -1
- package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +14 -0
- package/project/.sdk/tm/js/src/feature/telemetry/TelemetryFeature.js +4 -2
- package/project/.sdk/tm/js/src/utility/CleanUtility.js +294 -21
- package/project/.sdk/tm/js/src/utility/DoneUtility.js +17 -5
- package/project/.sdk/tm/js/src/utility/MakeErrorUtility.js +18 -2
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +39 -15
- package/project/.sdk/tm/js/src/utility/Utility.js +4 -2
- package/project/.sdk/tm/js/test/feature/harness.js +11 -1
- package/project/.sdk/tm/js/test/feature.test.js +9 -2
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +25 -0
- package/project/.sdk/tm/kotlin/core/Context.kt +19 -0
- package/project/.sdk/tm/kotlin/core/SdkClient.kt +9 -2
- package/project/.sdk/tm/kotlin/core/Utility.kt +2 -0
- package/project/.sdk/tm/kotlin/feature/AuditFeature.kt +11 -9
- package/project/.sdk/tm/kotlin/feature/CostFeature.kt +8 -5
- package/project/.sdk/tm/kotlin/feature/DebugFeature.kt +15 -22
- package/project/.sdk/tm/kotlin/feature/LogFeature.kt +8 -4
- package/project/.sdk/tm/kotlin/feature/ProxyFeature.kt +26 -2
- package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +11 -0
- package/project/.sdk/tm/kotlin/feature/TelemetryFeature.kt +4 -2
- package/project/.sdk/tm/kotlin/test/FeatureTest.kt +2 -2
- package/project/.sdk/tm/kotlin/utility/CoreUtil.kt +447 -11
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +38 -31
- package/project/.sdk/tm/kotlin/utility/Register.kt +1 -0
- package/project/.sdk/tm/lua/core/context.lua +43 -0
- package/project/.sdk/tm/lua/core/error.lua +36 -1
- package/project/.sdk/tm/lua/core/utility_type.lua +4 -0
- package/project/.sdk/tm/lua/feature/audit_feature.lua +2 -2
- package/project/.sdk/tm/lua/feature/cost_feature.lua +2 -2
- package/project/.sdk/tm/lua/feature/debug_feature.lua +21 -17
- package/project/.sdk/tm/lua/feature/log_feature.lua +2 -1
- package/project/.sdk/tm/lua/feature/proxy_feature.lua +23 -1
- package/project/.sdk/tm/lua/feature/secrets_feature.lua +18 -0
- package/project/.sdk/tm/lua/feature/telemetry_feature.lua +4 -2
- package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +3 -2
- package/project/.sdk/tm/lua/test/feature_test.lua +10 -3
- package/project/.sdk/tm/lua/utility/clean.lua +426 -2
- package/project/.sdk/tm/lua/utility/clean_explain.lua +34 -0
- package/project/.sdk/tm/lua/utility/done.lua +1 -7
- package/project/.sdk/tm/lua/utility/make_error.lua +3 -1
- package/project/.sdk/tm/lua/utility/make_options.lua +76 -30
- package/project/.sdk/tm/lua/utility/register.lua +4 -1
- package/project/.sdk/tm/ocaml/Makefile +5 -1
- package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +12 -1
- package/project/.sdk/tm/ocaml/sdk_features.ml +78 -18
- package/project/.sdk/tm/ocaml/sdk_helpers.ml +27 -0
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +304 -26
- package/project/.sdk/tm/ocaml/sdk_types.ml +1 -0
- package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +3 -1
- package/project/.sdk/tm/ocaml/test/t_feature.ml +2 -2
- package/project/.sdk/tm/perl/core/context.pm +27 -0
- package/project/.sdk/tm/perl/core/error.pm +52 -5
- package/project/.sdk/tm/perl/feature/audit_feature.pm +2 -2
- package/project/.sdk/tm/perl/feature/cost_feature.pm +2 -2
- package/project/.sdk/tm/perl/feature/debug_feature.pm +17 -13
- package/project/.sdk/tm/perl/feature/log_feature.pm +3 -1
- package/project/.sdk/tm/perl/feature/proxy_feature.pm +21 -1
- package/project/.sdk/tm/perl/feature/secrets_feature.pm +20 -1
- package/project/.sdk/tm/perl/feature/telemetry_feature.pm +4 -2
- package/project/.sdk/tm/perl/t/feature.t +4 -2
- package/project/.sdk/tm/perl/utility/clean.pm +345 -1
- package/project/.sdk/tm/perl/utility/done.pm +24 -6
- package/project/.sdk/tm/perl/utility/make_error.pm +17 -4
- package/project/.sdk/tm/perl/utility/make_options.pm +33 -14
- package/project/.sdk/tm/php/core/Context.php +24 -1
- package/project/.sdk/tm/php/core/Error.php +34 -3
- package/project/.sdk/tm/php/core/UtilityType.php +4 -0
- package/project/.sdk/tm/php/feature/AuditFeature.php +2 -2
- package/project/.sdk/tm/php/feature/CostFeature.php +2 -2
- package/project/.sdk/tm/php/feature/DebugFeature.php +18 -9
- package/project/.sdk/tm/php/feature/LogFeature.php +5 -2
- package/project/.sdk/tm/php/feature/ProxyFeature.php +20 -1
- package/project/.sdk/tm/php/feature/SecretsFeature.php +18 -0
- package/project/.sdk/tm/php/feature/TelemetryFeature.php +4 -2
- package/project/.sdk/tm/php/test/FeatureTest.php +2 -2
- package/project/.sdk/tm/php/utility/Clean.php +438 -2
- package/project/.sdk/tm/php/utility/Done.php +14 -7
- package/project/.sdk/tm/php/utility/MakeError.php +9 -7
- package/project/.sdk/tm/php/utility/MakeOptions.php +62 -38
- package/project/.sdk/tm/php/utility/Register.php +2 -0
- package/project/.sdk/tm/py/pkg/core/context.py +17 -0
- package/project/.sdk/tm/py/pkg/core/error.py +42 -1
- package/project/.sdk/tm/py/pkg/core/utility_type.py +4 -0
- package/project/.sdk/tm/py/pkg/feature/audit_feature.py +2 -2
- package/project/.sdk/tm/py/pkg/feature/cost_feature.py +2 -2
- package/project/.sdk/tm/py/pkg/feature/debug_feature.py +17 -12
- package/project/.sdk/tm/py/pkg/feature/log_feature.py +2 -1
- package/project/.sdk/tm/py/pkg/feature/proxy_feature.py +18 -1
- package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +12 -0
- package/project/.sdk/tm/py/pkg/feature/telemetry_feature.py +4 -2
- package/project/.sdk/tm/py/pkg/utility/clean.py +311 -1
- package/project/.sdk/tm/py/pkg/utility/done.py +18 -5
- package/project/.sdk/tm/py/pkg/utility/make_error.py +9 -6
- package/project/.sdk/tm/py/pkg/utility/make_options.py +64 -25
- package/project/.sdk/tm/py/pkg/utility/make_response.py +19 -13
- package/project/.sdk/tm/py/pkg/utility/register.py +4 -2
- package/project/.sdk/tm/py/test/feature_harness.py +4 -0
- package/project/.sdk/tm/py/test/test_feature.py +2 -2
- package/project/.sdk/tm/py/test/test_primary_utility.py +1 -0
- package/project/.sdk/tm/rb/core/context.rb +28 -0
- package/project/.sdk/tm/rb/core/error.rb +30 -0
- package/project/.sdk/tm/rb/core/utility_type.rb +1 -1
- package/project/.sdk/tm/rb/feature/audit_feature.rb +2 -2
- package/project/.sdk/tm/rb/feature/cost_feature.rb +2 -2
- package/project/.sdk/tm/rb/feature/debug_feature.rb +15 -12
- package/project/.sdk/tm/rb/feature/log_feature.rb +3 -1
- package/project/.sdk/tm/rb/feature/proxy_feature.rb +25 -1
- package/project/.sdk/tm/rb/feature/secrets_feature.rb +17 -0
- package/project/.sdk/tm/rb/feature/telemetry_feature.rb +4 -2
- package/project/.sdk/tm/rb/test/feature_test.rb +4 -2
- package/project/.sdk/tm/rb/utility/clean.rb +312 -1
- package/project/.sdk/tm/rb/utility/done.rb +15 -5
- package/project/.sdk/tm/rb/utility/make_error.rb +13 -4
- package/project/.sdk/tm/rb/utility/make_options.rb +31 -12
- package/project/.sdk/tm/rb/utility/register.rb +2 -0
- package/project/.sdk/tm/rust/core/context.rs +55 -0
- package/project/.sdk/tm/rust/core/utility_type.rs +17 -0
- package/project/.sdk/tm/rust/feature/audit.rs +2 -0
- package/project/.sdk/tm/rust/feature/cost.rs +3 -2
- package/project/.sdk/tm/rust/feature/debug.rs +16 -16
- package/project/.sdk/tm/rust/feature/log.rs +42 -7
- package/project/.sdk/tm/rust/feature/proxy.rs +48 -2
- package/project/.sdk/tm/rust/feature/secrets.rs +12 -0
- package/project/.sdk/tm/rust/feature/telemetry.rs +2 -0
- package/project/.sdk/tm/rust/tests/feature_test.rs +2 -2
- package/project/.sdk/tm/rust/utility/clean.rs +446 -5
- package/project/.sdk/tm/rust/utility/done.rs +22 -12
- package/project/.sdk/tm/rust/utility/make_error.rs +4 -1
- package/project/.sdk/tm/rust/utility/make_options.rs +73 -19
- package/project/.sdk/tm/scala/Makefile +3 -1
- package/project/.sdk/tm/scala/core/Context.scala +16 -0
- package/project/.sdk/tm/scala/core/SdkClient.scala +14 -4
- package/project/.sdk/tm/scala/core/SdkError.scala +28 -0
- package/project/.sdk/tm/scala/core/Types.scala +3 -0
- package/project/.sdk/tm/scala/core/Utility.scala +2 -0
- package/project/.sdk/tm/scala/feature/AuditFeature.scala +16 -10
- package/project/.sdk/tm/scala/feature/CostFeature.scala +10 -5
- package/project/.sdk/tm/scala/feature/DebugFeature.scala +24 -21
- package/project/.sdk/tm/scala/feature/LogFeature.scala +9 -4
- package/project/.sdk/tm/scala/feature/ProxyFeature.scala +23 -2
- package/project/.sdk/tm/scala/feature/SecretsFeature.scala +14 -0
- package/project/.sdk/tm/scala/feature/TelemetryFeature.scala +9 -2
- package/project/.sdk/tm/scala/sdktest/SdkTestMain.scala +2 -2
- package/project/.sdk/tm/scala/utility/Make.scala +63 -20
- package/project/.sdk/tm/scala/utility/Misc.scala +358 -5
- package/project/.sdk/tm/scala/utility/Register.scala +1 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Context.swift +29 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/core/Utility.swift +2 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/AuditFeature.swift +10 -9
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/CostFeature.swift +7 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/DebugFeature.swift +19 -15
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/FeatureOptions.swift +16 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/LogFeature.swift +4 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/ProxyFeature.swift +20 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/SecretsFeature.swift +13 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/feature/TelemetryFeature.swift +4 -2
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeError.swift +15 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +58 -19
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Register.swift +1 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/ResultUtil.swift +391 -4
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/FeatureTest.swift +2 -2
- package/project/.sdk/tm/ts/src/Context.ts +5 -1
- package/project/.sdk/tm/ts/src/Response.ts +14 -1
- package/project/.sdk/tm/ts/src/feature/audit/AuditFeature.ts +2 -2
- package/project/.sdk/tm/ts/src/feature/cost/CostFeature.ts +2 -2
- package/project/.sdk/tm/ts/src/feature/debug/DebugFeature.ts +13 -7
- package/project/.sdk/tm/ts/src/feature/log/LogFeature.ts +9 -5
- package/project/.sdk/tm/ts/src/feature/proxy/ProxyFeature.ts +19 -1
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +12 -0
- package/project/.sdk/tm/ts/src/feature/telemetry/TelemetryFeature.ts +4 -2
- package/project/.sdk/tm/ts/src/utility/CleanUtility.ts +287 -9
- package/project/.sdk/tm/ts/src/utility/DoneUtility.ts +18 -5
- package/project/.sdk/tm/ts/src/utility/MakeErrorUtility.ts +18 -8
- package/project/.sdk/tm/ts/src/utility/MakeOptionsUtility.ts +38 -16
- package/project/.sdk/tm/ts/src/utility/Utility.ts +4 -2
- package/project/.sdk/tm/ts/test/feature/harness.ts +11 -1
- package/project/.sdk/tm/ts/test/feature.test.ts +9 -2
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +25 -0
- package/project/.sdk/tm/zig/core/context.zig +34 -0
- package/project/.sdk/tm/zig/core/error.zig +22 -1
- package/project/.sdk/tm/zig/core/utility.zig +403 -39
- package/project/.sdk/tm/zig/feature/audit.zig +4 -2
- package/project/.sdk/tm/zig/feature/cost.zig +3 -2
- package/project/.sdk/tm/zig/feature/debug.zig +20 -25
- package/project/.sdk/tm/zig/feature/log.zig +3 -1
- package/project/.sdk/tm/zig/feature/proxy.zig +47 -6
- package/project/.sdk/tm/zig/feature/secrets.zig +7 -0
- package/project/.sdk/tm/zig/feature/telemetry.zig +4 -2
- package/project/.sdk/tm/zig/test/feature_test.zig +2 -2
- package/project/sdkgen-package.json +1 -1
- package/src/helpers/naming.ts +1 -1
|
@@ -55,8 +55,327 @@ inline CtxPtr makeContext(const CtxSpec& cs, CtxPtr basectx) {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// ---- clean ------------------------------------------------------------
|
|
58
|
+
//
|
|
59
|
+
// Everything that leaves the pipeline passes through clean: the error, the
|
|
60
|
+
// explain record, the serialised context, and whatever a feature emits.
|
|
61
|
+
// Two layers: every registered secret VALUE (and its encoded forms) is
|
|
62
|
+
// replaced wherever it appears in a string, and every value under a
|
|
63
|
+
// sensitive KEY name is masked whatever it holds. Inside the pipeline data
|
|
64
|
+
// stays raw, so a hook can still read the header it must add to.
|
|
65
|
+
//
|
|
66
|
+
// The configuration is the derived clean block makeOptions builds
|
|
67
|
+
// (`options.__derived__.clean`): a plain map, so the registry list inside
|
|
68
|
+
// it stays mutable after construction - features register later.
|
|
69
|
+
|
|
70
|
+
constexpr int CLEAN_MAXDEPTH = 32;
|
|
71
|
+
|
|
72
|
+
inline std::string cleanBase64(const std::string& in) {
|
|
73
|
+
static const char* ALPHABET =
|
|
74
|
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
75
|
+
std::string out;
|
|
76
|
+
out.reserve(((in.size() + 2) / 3) * 4);
|
|
77
|
+
for (size_t i = 0; i < in.size(); i += 3) {
|
|
78
|
+
unsigned int v = static_cast<unsigned int>(static_cast<unsigned char>(in[i])) << 16;
|
|
79
|
+
if (i + 1 < in.size()) v |= static_cast<unsigned int>(static_cast<unsigned char>(in[i + 1])) << 8;
|
|
80
|
+
if (i + 2 < in.size()) v |= static_cast<unsigned int>(static_cast<unsigned char>(in[i + 2]));
|
|
81
|
+
out += ALPHABET[(v >> 18) & 0x3f];
|
|
82
|
+
out += ALPHABET[(v >> 12) & 0x3f];
|
|
83
|
+
out += (i + 1 < in.size()) ? ALPHABET[(v >> 6) & 0x3f] : '=';
|
|
84
|
+
out += (i + 2 < in.size()) ? ALPHABET[v & 0x3f] : '=';
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
inline std::string cleanNormkey(const std::string& key) {
|
|
90
|
+
std::string out;
|
|
91
|
+
for (char c : key) {
|
|
92
|
+
if ('-' == c || '_' == c) continue;
|
|
93
|
+
out.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
inline std::vector<std::string> cleanSplit(const Value& raw) {
|
|
99
|
+
std::vector<std::string> out;
|
|
100
|
+
if (raw.is_list()) {
|
|
101
|
+
for (const auto& v : *raw.as_list()) {
|
|
102
|
+
if (v.is_string() && !v.as_string().empty()) out.push_back(v.as_string());
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
std::string text = raw.is_string() ? raw.as_string() : "";
|
|
107
|
+
size_t start = 0;
|
|
108
|
+
while (start <= text.size()) {
|
|
109
|
+
size_t comma = text.find(',', start);
|
|
110
|
+
std::string tok = std::string::npos == comma ? text.substr(start)
|
|
111
|
+
: text.substr(start, comma - start);
|
|
112
|
+
size_t a = tok.find_first_not_of(" \t\r\n");
|
|
113
|
+
size_t b = tok.find_last_not_of(" \t\r\n");
|
|
114
|
+
tok = std::string::npos == a ? "" : tok.substr(a, b - a + 1);
|
|
115
|
+
if (!tok.empty()) out.push_back(tok);
|
|
116
|
+
if (std::string::npos == comma) break;
|
|
117
|
+
start = comma + 1;
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// The spec carries numbers as strings, so every target reads it alike.
|
|
123
|
+
inline long long cleanCount(const Value& v, long long dflt) {
|
|
124
|
+
if (v.is_number()) return 0 <= v.as_int() ? v.as_int() : dflt;
|
|
125
|
+
if (!v.is_string()) return dflt;
|
|
126
|
+
try {
|
|
127
|
+
size_t pos = 0;
|
|
128
|
+
long long n = std::stoll(v.as_string(), &pos);
|
|
129
|
+
return 0 <= n ? n : dflt;
|
|
130
|
+
} catch (...) {
|
|
131
|
+
return dflt;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The derived clean block, from the clean options merged over the spec.
|
|
136
|
+
inline Value makeCleanConfig(const Value& cleanopts) {
|
|
137
|
+
Value opts = cleanopts.is_map() ? cleanopts : vmap();
|
|
138
|
+
Value keys = vlist();
|
|
139
|
+
for (const auto& k : cleanSplit(getp(opts, "keys"))) {
|
|
140
|
+
std::string nk = cleanNormkey(k);
|
|
141
|
+
if (!nk.empty()) keys.as_list()->push_back(Value(nk));
|
|
142
|
+
}
|
|
143
|
+
Value mask = getp(opts, "mask");
|
|
144
|
+
long long min = cleanCount(getp(opts, "min"), 4);
|
|
145
|
+
Value cfg = vmap();
|
|
146
|
+
map_put(cfg, "active", Value(!is_false(getp(opts, "active"))));
|
|
147
|
+
map_put(cfg, "keys", keys);
|
|
148
|
+
map_put(cfg, "values", vlist());
|
|
149
|
+
map_put(cfg, "mask", mask.is_string() ? mask : Value("[redacted]"));
|
|
150
|
+
map_put(cfg, "hint", Value(cleanCount(getp(opts, "hint"), 0)));
|
|
151
|
+
map_put(cfg, "min", Value(1 > min ? 1LL : min));
|
|
152
|
+
return cfg;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// A context without options (makeError is reached with a bare one) falls
|
|
156
|
+
// back to the schema defaults, so nothing leaves raw for want of a
|
|
157
|
+
// constructor.
|
|
158
|
+
inline Value cleanConfig(CtxPtr ctx) {
|
|
159
|
+
Value derived = ctx ? Struct::getpath(ctx->options, {"__derived__", "clean"}) : Value::undef();
|
|
160
|
+
if (derived.is_map()) return derived;
|
|
161
|
+
return makeCleanConfig(getp(sharedOptspec(), "clean"));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// The encoded forms a value travels in: Basic and Bearer both carry base64,
|
|
165
|
+
// a query credential is percent-encoded, and a JSON dump escapes it.
|
|
166
|
+
inline std::vector<std::string> cleanForms(const std::string& value) {
|
|
167
|
+
std::vector<std::string> out{value};
|
|
168
|
+
auto add = [&out](const std::string& s) {
|
|
169
|
+
if (!s.empty() && std::find(out.begin(), out.end(), s) == out.end()) out.push_back(s);
|
|
170
|
+
};
|
|
171
|
+
add(cleanBase64(value));
|
|
172
|
+
add(Struct::escurl(Value(value)));
|
|
173
|
+
std::string json = vs::jsonify(Value(value), 0);
|
|
174
|
+
if (2 <= json.size()) add(json.substr(1, json.size() - 2));
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Register a secret value. Idempotent; shorter than `min` is not a secret
|
|
179
|
+
// the SDK can mask without blanking ordinary text.
|
|
180
|
+
inline void cleanAddCfg(const Value& cfg, const Value& value) {
|
|
181
|
+
if (!cfg.is_map() || !value.is_string()) return;
|
|
182
|
+
size_t min = static_cast<size_t>(cleanCount(getp(cfg, "min"), 4));
|
|
183
|
+
const std::string& raw = value.as_string();
|
|
184
|
+
if (raw.size() < min) return;
|
|
185
|
+
Value values = getp(cfg, "values");
|
|
186
|
+
if (!values.is_list()) {
|
|
187
|
+
values = vlist();
|
|
188
|
+
map_put(cfg, "values", values);
|
|
189
|
+
}
|
|
190
|
+
auto& list = *values.as_list();
|
|
191
|
+
bool changed = false;
|
|
192
|
+
for (const auto& form : cleanForms(raw)) {
|
|
193
|
+
if (form.size() < min) continue;
|
|
194
|
+
bool known = false;
|
|
195
|
+
for (const auto& v : list) {
|
|
196
|
+
if (v.is_string() && v.as_string() == form) { known = true; break; }
|
|
197
|
+
}
|
|
198
|
+
if (!known) {
|
|
199
|
+
list.push_back(Value(form));
|
|
200
|
+
changed = true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (changed) {
|
|
204
|
+
std::stable_sort(list.begin(), list.end(), [](const Value& a, const Value& b) {
|
|
205
|
+
return a.as_string().size() > b.as_string().size();
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
inline void cleanAdd(CtxPtr ctx, const Value& value) {
|
|
211
|
+
cleanAddCfg(cleanConfig(ctx), value);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
inline std::string cleanMaskValue(const Value& cfg, const std::string& value) {
|
|
215
|
+
std::string mask = as_str(getp(cfg, "mask"), "[redacted]");
|
|
216
|
+
size_t hint = static_cast<size_t>(cleanCount(getp(cfg, "hint"), 0));
|
|
217
|
+
if (0 < hint && value.size() > 2 * hint) return mask + value.substr(value.size() - hint);
|
|
218
|
+
return mask;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
inline std::string cleanString(const Value& cfg, const std::string& text) {
|
|
222
|
+
std::string out = text;
|
|
223
|
+
Value values = getp(cfg, "values");
|
|
224
|
+
if (!values.is_list()) return out;
|
|
225
|
+
for (const auto& v : *values.as_list()) {
|
|
226
|
+
if (!v.is_string() || v.as_string().empty()) continue;
|
|
227
|
+
if (std::string::npos != out.find(v.as_string())) {
|
|
228
|
+
out = replace_all(out, v.as_string(), cleanMaskValue(cfg, v.as_string()));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return out;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
inline bool cleanSensitiveKey(const Value& cfg, const Value& key) {
|
|
235
|
+
if (!key.is_string()) return false;
|
|
236
|
+
std::string nk = cleanNormkey(key.as_string());
|
|
237
|
+
Value keys = getp(cfg, "keys");
|
|
238
|
+
if (!keys.is_list()) return false;
|
|
239
|
+
for (const auto& k : *keys.as_list()) {
|
|
240
|
+
if (k.is_string() && std::string::npos != nk.find(k.as_string())) return true;
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// A registered value used as a property name is masked like any other
|
|
246
|
+
// string; names that mask alike take a counter, so none is lost.
|
|
247
|
+
inline std::string cleanName(const Value& cfg, const Value& out, const std::string& key) {
|
|
248
|
+
std::string name = cleanString(cfg, key);
|
|
249
|
+
if (name == key || !out.as_map()->contains(name)) return name;
|
|
250
|
+
int i = 1;
|
|
251
|
+
while (out.as_map()->contains(name + "#" + std::to_string(i))) i++;
|
|
252
|
+
return name + "#" + std::to_string(i);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// A plain-data copy of what is about to leave: functions are dropped,
|
|
256
|
+
// cycles are cut, and no live container is shared with the copy - masking
|
|
257
|
+
// the copy must never mask the pipeline's own spec.
|
|
258
|
+
inline Value cleanSnapshot(const Value& cfg, const Value& val, const Value& key, int depth,
|
|
259
|
+
std::vector<const void*>& seen) {
|
|
260
|
+
if (val.is_undef() || val.is_null()) return val;
|
|
261
|
+
|
|
262
|
+
if (val.is_string()) {
|
|
263
|
+
return Value(cleanSensitiveKey(cfg, key) ? cleanMaskValue(cfg, val.as_string())
|
|
264
|
+
: cleanString(cfg, val.as_string()));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (val.is_func() || val.is_sentinel()) return Value::undef();
|
|
268
|
+
|
|
269
|
+
if (!val.is_node()) {
|
|
270
|
+
return cleanSensitiveKey(cfg, key) ? getp(cfg, "mask") : val;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const void* id = val.is_list() ? static_cast<const void*>(val.as_list().get())
|
|
274
|
+
: static_cast<const void*>(val.as_map().get());
|
|
275
|
+
if (CLEAN_MAXDEPTH <= depth || std::find(seen.begin(), seen.end(), id) != seen.end()) {
|
|
276
|
+
return Value("[circular]");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (cleanSensitiveKey(cfg, key)) return getp(cfg, "mask");
|
|
280
|
+
|
|
281
|
+
seen.push_back(id);
|
|
282
|
+
Value out;
|
|
283
|
+
if (val.is_list()) {
|
|
284
|
+
out = vlist();
|
|
285
|
+
long long i = 0;
|
|
286
|
+
for (const auto& item : *val.as_list()) {
|
|
287
|
+
Value v = cleanSnapshot(cfg, item, Value(i++), depth + 1, seen);
|
|
288
|
+
if (!v.is_undef()) out.as_list()->push_back(v);
|
|
289
|
+
}
|
|
290
|
+
} else {
|
|
291
|
+
out = vmap();
|
|
292
|
+
for (const auto& kv : *val.as_map()) {
|
|
293
|
+
Value v = cleanSnapshot(cfg, kv.second, Value(kv.first), depth + 1, seen);
|
|
294
|
+
if (!v.is_undef()) map_put(out, cleanName(cfg, out, kv.first), v);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
seen.pop_back();
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
inline Value cleanValue(const Value& cfg, const Value& val) {
|
|
302
|
+
if (is_false(getp(cfg, "active"))) return val;
|
|
303
|
+
if (val.is_string()) return Value(cleanString(cfg, val.as_string()));
|
|
304
|
+
std::vector<const void*> seen;
|
|
305
|
+
return cleanSnapshot(cfg, val, Value::undef(), 0, seen);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Clean a value on its way out: a string is redacted; anything else comes
|
|
309
|
+
// back as a masked plain-data copy.
|
|
310
|
+
inline Value clean(CtxPtr ctx, const Value& val) {
|
|
311
|
+
return cleanValue(cleanConfig(ctx), val);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// An SdkError is cleaned IN PLACE: it is about to be thrown, and its
|
|
315
|
+
// identity matters to the caller.
|
|
316
|
+
inline void cleanError(CtxPtr ctx, const SdkErrorPtr& err) {
|
|
317
|
+
if (!err) return;
|
|
318
|
+
Value cfg = cleanConfig(ctx);
|
|
319
|
+
if (is_false(getp(cfg, "active"))) return;
|
|
320
|
+
err->msg = cleanString(cfg, err->msg);
|
|
321
|
+
err->code = cleanString(cfg, err->code);
|
|
322
|
+
err->result = cleanValue(cfg, err->result);
|
|
323
|
+
err->spec = cleanValue(cfg, err->spec);
|
|
324
|
+
}
|
|
58
325
|
|
|
59
|
-
|
|
326
|
+
// Every scalar under a sensitive name, at any depth and of any shape, is
|
|
327
|
+
// registered: a credential mistyped as a map or a number is still a
|
|
328
|
+
// credential, and the validation error that rejects it quotes it.
|
|
329
|
+
inline void cleanAddSensitiveIn(const Value& cfg, const Value& val, bool under, int depth,
|
|
330
|
+
std::vector<const void*>& seen) {
|
|
331
|
+
if (CLEAN_MAXDEPTH <= depth) return;
|
|
332
|
+
if (val.is_string() || val.is_number()) {
|
|
333
|
+
if (under) cleanAddCfg(cfg, val.is_string() ? val : Value(Struct::stringify(val)));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (!val.is_node()) return;
|
|
337
|
+
const void* id = val.is_list() ? static_cast<const void*>(val.as_list().get())
|
|
338
|
+
: static_cast<const void*>(val.as_map().get());
|
|
339
|
+
if (std::find(seen.begin(), seen.end(), id) != seen.end()) return;
|
|
340
|
+
seen.push_back(id);
|
|
341
|
+
if (val.is_list()) {
|
|
342
|
+
for (const auto& item : *val.as_list()) cleanAddSensitiveIn(cfg, item, under, depth + 1, seen);
|
|
343
|
+
} else {
|
|
344
|
+
for (const auto& kv : *val.as_map()) {
|
|
345
|
+
bool sub = under || cleanSensitiveKey(cfg, Value(kv.first));
|
|
346
|
+
cleanAddSensitiveIn(cfg, kv.second, sub, depth + 1, seen);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
inline void cleanAddSensitiveCfg(const Value& cfg, const Value& val) {
|
|
352
|
+
std::vector<const void*> seen;
|
|
353
|
+
cleanAddSensitiveIn(cfg, val, false, 0, seen);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
inline void cleanAddSensitive(CtxPtr ctx, const Value& val) {
|
|
357
|
+
cleanAddSensitiveCfg(cleanConfig(ctx), val);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Is this key name sensitive under the context's clean configuration?
|
|
361
|
+
inline bool cleanKey(CtxPtr ctx, const Value& key) {
|
|
362
|
+
return cleanSensitiveKey(cleanConfig(ctx), key);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// The explain record is the CALLER'S map (a control map is shared, not
|
|
366
|
+
// copied), so the cleaned copy is written back into it in place. err is
|
|
367
|
+
// pruned from its result, a toValue snapshot rather than the live result.
|
|
368
|
+
inline void cleanExplain(CtxPtr ctx) {
|
|
369
|
+
Value explain = ctx->ctrl ? ctx->ctrl->explain : Value::undef();
|
|
370
|
+
if (!explain.is_map()) return;
|
|
371
|
+
Value cleaned = clean(ctx, explain);
|
|
372
|
+
if (cleaned.is_map() && cleaned.as_map() != explain.as_map()) {
|
|
373
|
+
explain.as_map()->clear();
|
|
374
|
+
for (const auto& kv : *cleaned.as_map()) map_put(explain, kv.first, kv.second);
|
|
375
|
+
}
|
|
376
|
+
Value rm = Helpers::toMapAny(getp(explain, "result"));
|
|
377
|
+
if (rm.is_map()) map_remove(rm, "err");
|
|
378
|
+
}
|
|
60
379
|
|
|
61
380
|
// ---- makeError --------------------------------------------------------
|
|
62
381
|
|
|
@@ -75,6 +394,10 @@ inline Value makeError(CtxPtr ctx, SdkErrorPtr err) {
|
|
|
75
394
|
if (!err) err = result->err;
|
|
76
395
|
if (!err) err = ctx->makeError("unknown", "unknown error");
|
|
77
396
|
|
|
397
|
+
// The source error is cleaned too: it stays reachable through the
|
|
398
|
+
// response it came from.
|
|
399
|
+
cleanError(ctx, err);
|
|
400
|
+
|
|
78
401
|
std::string errmsg = err->getMessage();
|
|
79
402
|
std::string msg = "ProjectNameSDK: " + opname + ": " + errmsg;
|
|
80
403
|
|
|
@@ -82,41 +405,56 @@ inline Value makeError(CtxPtr ctx, SdkErrorPtr err) {
|
|
|
82
405
|
|
|
83
406
|
SpecPtr spec = ctx->spec;
|
|
84
407
|
|
|
408
|
+
std::string code = err->code;
|
|
409
|
+
|
|
410
|
+
auto sdkErr = std::make_shared<SdkError>(code, msg, ctx.get());
|
|
411
|
+
sdkErr->result = result->toValue();
|
|
412
|
+
sdkErr->spec = spec ? spec->toValue() : Value::undef();
|
|
413
|
+
sdkErr->status = result->status;
|
|
414
|
+
cleanError(ctx, sdkErr);
|
|
415
|
+
|
|
85
416
|
if (ctx->ctrl->explain.is_map()) {
|
|
86
417
|
Value errRecord = vmap();
|
|
87
|
-
map_put(errRecord, "
|
|
418
|
+
map_put(errRecord, "code", Value(sdkErr->code));
|
|
419
|
+
map_put(errRecord, "message", Value(sdkErr->msg));
|
|
88
420
|
map_put(ctx->ctrl->explain, "err", errRecord);
|
|
421
|
+
// A pipeline failure reaches here without passing done, so the record
|
|
422
|
+
// is cleaned on this path as well.
|
|
423
|
+
cleanExplain(ctx);
|
|
89
424
|
}
|
|
90
425
|
|
|
91
|
-
std::string code = err->code;
|
|
92
|
-
|
|
93
|
-
auto sdkErr = std::make_shared<SdkError>(code, msg, ctx.get());
|
|
94
|
-
sdkErr->result_obj = result;
|
|
95
|
-
sdkErr->spec_obj = spec;
|
|
96
|
-
|
|
97
426
|
ctx->ctrl->err = sdkErr;
|
|
98
427
|
|
|
99
428
|
// Fire PreUnexpected so observability features (metrics, telemetry, audit,
|
|
100
429
|
// debug) close/record error paths that never reach PreDone (e.g. a PrePoint
|
|
101
430
|
// rbac short-circuit). Fires after ctx->ctrl->err is set so hooks can read
|
|
102
431
|
// the error; features guard against double-recording when PreDone fired.
|
|
103
|
-
|
|
432
|
+
// What a hook throws here replaces the error, and leaves cleaned too.
|
|
433
|
+
SdkErrorPtr raised = sdkErr;
|
|
434
|
+
try {
|
|
435
|
+
featureHook(ctx, "PreUnexpected");
|
|
436
|
+
} catch (const SdkErrorPtr& hookerr) {
|
|
437
|
+
raised = hookerr;
|
|
438
|
+
} catch (const std::exception& e) {
|
|
439
|
+
raised = ctx->makeError("unexpected", e.what());
|
|
440
|
+
}
|
|
441
|
+
if (raised != sdkErr) {
|
|
442
|
+
cleanError(ctx, raised);
|
|
443
|
+
cleanExplain(ctx);
|
|
444
|
+
ctx->ctrl->err = raised;
|
|
445
|
+
}
|
|
104
446
|
|
|
105
447
|
if (is_false(ctx->ctrl->throwing)) {
|
|
106
448
|
return result->resdata;
|
|
107
449
|
}
|
|
108
450
|
|
|
109
|
-
throw
|
|
451
|
+
throw raised;
|
|
110
452
|
}
|
|
111
453
|
|
|
112
454
|
// ---- done -------------------------------------------------------------
|
|
113
455
|
|
|
114
456
|
inline Value done(CtxPtr ctx) {
|
|
115
|
-
|
|
116
|
-
Value explainResult = getp(ctx->ctrl->explain, "result");
|
|
117
|
-
Value rm = Helpers::toMapAny(explainResult);
|
|
118
|
-
if (rm.is_map()) map_remove(rm, "err");
|
|
119
|
-
}
|
|
457
|
+
cleanExplain(ctx);
|
|
120
458
|
|
|
121
459
|
if (ctx->result && ctx->result->ok) {
|
|
122
460
|
return ctx->result->resdata;
|
|
@@ -1164,6 +1502,44 @@ inline Value transformRequest(CtxPtr ctx) {
|
|
|
1164
1502
|
|
|
1165
1503
|
// ---- makeOptions ------------------------------------------------------
|
|
1166
1504
|
|
|
1505
|
+
inline Value optsNoEntity(const Value& settings) {
|
|
1506
|
+
if (!settings.is_map()) return settings;
|
|
1507
|
+
Value out = vmap();
|
|
1508
|
+
for (const auto& kv : *settings.as_map()) {
|
|
1509
|
+
if ("entity" != kv.first) map_put(out, kv.first, kv.second);
|
|
1510
|
+
}
|
|
1511
|
+
return out;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
// The options to scan for secrets. The feature map is keyed by feature
|
|
1515
|
+
// names, not field names, so it is scanned as a list: `secrets` must not
|
|
1516
|
+
// make every setting of that feature a secret. Entity blocks hold entity
|
|
1517
|
+
// settings and seeded records, never a credential, so none is scanned. The
|
|
1518
|
+
// raw scan still sees the feature list form, whose entries each carry `name`.
|
|
1519
|
+
inline Value optsWithout(const Value& opts, std::initializer_list<const char*> keys) {
|
|
1520
|
+
Value out = vmap();
|
|
1521
|
+
if (!opts.is_map()) return out;
|
|
1522
|
+
for (const auto& kv : *opts.as_map()) {
|
|
1523
|
+
bool skip = "entity" == kv.first;
|
|
1524
|
+
for (const char* k : keys) skip = skip || kv.first == k;
|
|
1525
|
+
if (skip) continue;
|
|
1526
|
+
if ("feature" == kv.first && (kv.second.is_map() || kv.second.is_list())) {
|
|
1527
|
+
Value list = vlist();
|
|
1528
|
+
if (kv.second.is_map()) {
|
|
1529
|
+
for (const auto& f : *kv.second.as_map()) list.as_list()->push_back(optsNoEntity(f.second));
|
|
1530
|
+
} else {
|
|
1531
|
+
for (const auto& f : *kv.second.as_list()) list.as_list()->push_back(optsNoEntity(f));
|
|
1532
|
+
}
|
|
1533
|
+
map_put(out, kv.first, list);
|
|
1534
|
+
} else if ("test" == kv.first) {
|
|
1535
|
+
map_put(out, kv.first, optsNoEntity(kv.second));
|
|
1536
|
+
} else {
|
|
1537
|
+
map_put(out, kv.first, kv.second);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
return out;
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1167
1543
|
inline Value makeOptions(CtxPtr ctx) {
|
|
1168
1544
|
Value options = ctx->options;
|
|
1169
1545
|
if (!options.is_map()) options = vmap();
|
|
@@ -1198,6 +1574,25 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1198
1574
|
map_remove(opts, "auth");
|
|
1199
1575
|
}
|
|
1200
1576
|
|
|
1577
|
+
Value config = ctx->config;
|
|
1578
|
+
if (!config.is_map()) config = vmap();
|
|
1579
|
+
Value cfgopts = Helpers::toMapAny(getp(config, "options"));
|
|
1580
|
+
if (!cfgopts.is_map()) cfgopts = vmap();
|
|
1581
|
+
|
|
1582
|
+
// The secret registry exists BEFORE validation, fed from the raw input, so
|
|
1583
|
+
// the constructor's own rejection of a mistyped credential is clean too.
|
|
1584
|
+
Value cleanraw = vlist({vmap()});
|
|
1585
|
+
for (const Value& src : {getp(sharedOptspec(), "clean"), getp(cfgopts, "clean"), getp(opts, "clean")}) {
|
|
1586
|
+
if (src.is_map()) cleanraw.as_list()->push_back(Struct::clone(src));
|
|
1587
|
+
}
|
|
1588
|
+
Value derivedClean = makeCleanConfig(Struct::merge(cleanraw));
|
|
1589
|
+
cleanAddSensitiveCfg(derivedClean, optsWithout(opts, {"clean"}));
|
|
1590
|
+
for (const Value& src : {cfgopts, opts}) {
|
|
1591
|
+
for (const auto& raw : cleanSplit(Struct::getpath(src, {"clean", "values"}))) {
|
|
1592
|
+
cleanAddCfg(derivedClean, Value(raw));
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1201
1596
|
// Feature add-order. options.feature may be an ordered list of
|
|
1202
1597
|
// { name, active, ...opts } entries (the list position IS the order in which
|
|
1203
1598
|
// features are added), or a { name: {opts} } map. Normalize a list to a map
|
|
@@ -1225,11 +1620,6 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1225
1620
|
}
|
|
1226
1621
|
}
|
|
1227
1622
|
|
|
1228
|
-
Value config = ctx->config;
|
|
1229
|
-
if (!config.is_map()) config = vmap();
|
|
1230
|
-
Value cfgopts = Helpers::toMapAny(getp(config, "options"));
|
|
1231
|
-
if (!cfgopts.is_map()) cfgopts = vmap();
|
|
1232
|
-
|
|
1233
1623
|
// THE OPTION SPEC IS GENERATED, NOT WRITTEN HERE.
|
|
1234
1624
|
//
|
|
1235
1625
|
// Built from the model: `main.kit.optspec` for the standard options, plus
|
|
@@ -1256,8 +1646,18 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1256
1646
|
Value merged = Struct::merge(mergeList);
|
|
1257
1647
|
|
|
1258
1648
|
Value vopts = vmap();
|
|
1259
|
-
|
|
1649
|
+
Value verrs = vlist();
|
|
1650
|
+
map_put(vopts, "errs", verrs);
|
|
1260
1651
|
Value validated = Struct::validate(merged, optspec, vopts);
|
|
1652
|
+
if (!verrs.as_list()->empty()) {
|
|
1653
|
+
std::string vmsg;
|
|
1654
|
+
for (const auto& e : *verrs.as_list()) {
|
|
1655
|
+
if (!vmsg.empty()) vmsg += " | ";
|
|
1656
|
+
vmsg += Struct::stringify(e);
|
|
1657
|
+
}
|
|
1658
|
+
throw std::make_shared<SdkError>("options_invalid",
|
|
1659
|
+
cleanString(derivedClean, "ProjectNameSDK: invalid options: " + vmsg), ctx.get());
|
|
1660
|
+
}
|
|
1261
1661
|
opts = validated;
|
|
1262
1662
|
|
|
1263
1663
|
// Restore the suppression the optspec default would otherwise erase.
|
|
@@ -1276,34 +1676,6 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1276
1676
|
}
|
|
1277
1677
|
}
|
|
1278
1678
|
|
|
1279
|
-
// Derived clean config.
|
|
1280
|
-
std::string cleanKeys = "key,token,id";
|
|
1281
|
-
Value ck = Struct::getpath(opts, {"clean", "keys"});
|
|
1282
|
-
if (ck.is_string()) cleanKeys = ck.as_string();
|
|
1283
|
-
|
|
1284
|
-
std::vector<std::string> parts;
|
|
1285
|
-
{
|
|
1286
|
-
size_t start = 0;
|
|
1287
|
-
while (start <= cleanKeys.size()) {
|
|
1288
|
-
size_t comma = cleanKeys.find(',', start);
|
|
1289
|
-
std::string tok = comma == std::string::npos ? cleanKeys.substr(start)
|
|
1290
|
-
: cleanKeys.substr(start, comma - start);
|
|
1291
|
-
// trim
|
|
1292
|
-
size_t a = tok.find_first_not_of(" \t");
|
|
1293
|
-
size_t b = tok.find_last_not_of(" \t");
|
|
1294
|
-
if (a != std::string::npos) tok = tok.substr(a, b - a + 1);
|
|
1295
|
-
else tok = "";
|
|
1296
|
-
if (!tok.empty()) parts.push_back(vs::escre(Value(tok)));
|
|
1297
|
-
if (comma == std::string::npos) break;
|
|
1298
|
-
start = comma + 1;
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
std::string keyre;
|
|
1302
|
-
for (size_t i = 0; i < parts.size(); i++) {
|
|
1303
|
-
if (i > 0) keyre += "|";
|
|
1304
|
-
keyre += parts[i];
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
1679
|
// Resolve the feature add-order: an explicit list order (above) wins;
|
|
1308
1680
|
// otherwise order the map test-first, then the remaining names sorted, so
|
|
1309
1681
|
// the outcome is deterministic and `test` is always the base transport.
|
|
@@ -1334,12 +1706,13 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1334
1706
|
for (const auto& n : featureOrder) orderList.as_list()->push_back(Value(n));
|
|
1335
1707
|
|
|
1336
1708
|
Value derived = vmap();
|
|
1337
|
-
Value derivedClean = vmap();
|
|
1338
|
-
if (!keyre.empty()) map_put(derivedClean, "keyre", Value(keyre));
|
|
1339
1709
|
map_put(derived, "clean", derivedClean);
|
|
1340
1710
|
map_put(derived, "featureorder", orderList);
|
|
1341
1711
|
map_put(opts, "__derived__", derived);
|
|
1342
1712
|
|
|
1713
|
+
// Again over the merged result: the config's own defaults can carry one.
|
|
1714
|
+
cleanAddSensitiveCfg(derivedClean, optsWithout(opts, {"clean", "__derived__"}));
|
|
1715
|
+
|
|
1343
1716
|
return opts;
|
|
1344
1717
|
}
|
|
1345
1718
|
|
|
@@ -1351,6 +1724,8 @@ inline Value makeOptions(CtxPtr ctx) {
|
|
|
1351
1724
|
|
|
1352
1725
|
inline void register_all(Utility& u) {
|
|
1353
1726
|
u.clean = util::clean;
|
|
1727
|
+
u.cleanAdd = util::cleanAdd;
|
|
1728
|
+
u.cleanExplain = util::cleanExplain;
|
|
1354
1729
|
u.done = util::done;
|
|
1355
1730
|
u.makeError = util::makeError;
|
|
1356
1731
|
u.featureAdd = util::featureAdd;
|
|
@@ -254,4 +254,36 @@ public class Context
|
|
|
254
254
|
{
|
|
255
255
|
return new ProjectNameError(code, msg, this);
|
|
256
256
|
}
|
|
257
|
+
|
|
258
|
+
// The record form: what the context says about the operation, never its
|
|
259
|
+
// client, options or config.
|
|
260
|
+
internal Dictionary<string, object?> RawRecord()
|
|
261
|
+
{
|
|
262
|
+
return new Dictionary<string, object?>
|
|
263
|
+
{
|
|
264
|
+
["id"] = Id,
|
|
265
|
+
["op"] = Op,
|
|
266
|
+
["spec"] = Spec,
|
|
267
|
+
["entity"] = Entity?.GetName(),
|
|
268
|
+
["result"] = Result,
|
|
269
|
+
["response"] = Response,
|
|
270
|
+
["meta"] = Meta,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// The serialised context leaves the pipeline (a logger, an error dump), so
|
|
275
|
+
// it is cleaned; the live fields stay raw for the pipeline's own use.
|
|
276
|
+
public Dictionary<string, object?> ToRecord()
|
|
277
|
+
{
|
|
278
|
+
var record = RawRecord();
|
|
279
|
+
var clean = Utility?.Clean;
|
|
280
|
+
return clean == null
|
|
281
|
+
? record
|
|
282
|
+
: clean(this, record) as Dictionary<string, object?> ?? record;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
public override string ToString()
|
|
286
|
+
{
|
|
287
|
+
return "Context " + StructUtils.Jsonify(ToRecord(), 0);
|
|
288
|
+
}
|
|
257
289
|
}
|
|
@@ -7,6 +7,7 @@ namespace ProjectNameSdk;
|
|
|
7
7
|
public class Utility
|
|
8
8
|
{
|
|
9
9
|
public Func<Context, object?, object?> Clean = null!;
|
|
10
|
+
public Action<Context, object?> CleanAdd = null!;
|
|
10
11
|
public Func<Context, object?> Done = null!;
|
|
11
12
|
public Func<Context, Exception?, object?> MakeError = null!;
|
|
12
13
|
public Action<Context, Feature.BaseFeature> FeatureAdd = null!;
|
|
@@ -55,6 +56,7 @@ public class Utility
|
|
|
55
56
|
var u = new Utility(true)
|
|
56
57
|
{
|
|
57
58
|
Clean = src.Clean,
|
|
59
|
+
CleanAdd = src.CleanAdd,
|
|
58
60
|
Done = src.Done,
|
|
59
61
|
MakeError = src.MakeError,
|
|
60
62
|
FeatureAdd = src.FeatureAdd,
|
|
@@ -340,15 +340,17 @@ public class CostFeature : BaseFeature
|
|
|
340
340
|
Bump(Actors, actor, amount);
|
|
341
341
|
|
|
342
342
|
_seq++;
|
|
343
|
+
// A typed record, so its strings are cleaned one by one rather than
|
|
344
|
+
// the record as a whole.
|
|
343
345
|
Last = new CostRecord
|
|
344
346
|
{
|
|
345
347
|
Seq = _seq,
|
|
346
|
-
Entity = entity,
|
|
347
|
-
Op = opname,
|
|
348
|
-
Actor = actor,
|
|
348
|
+
Entity = FcleanStr(ctx, entity),
|
|
349
|
+
Op = FcleanStr(ctx, opname),
|
|
350
|
+
Actor = FcleanStr(ctx, actor),
|
|
349
351
|
Amount = amount,
|
|
350
|
-
Currency = Currency,
|
|
351
|
-
Source = source,
|
|
352
|
+
Currency = FcleanStr(ctx, Currency),
|
|
353
|
+
Source = FcleanStr(ctx, source),
|
|
352
354
|
Attempts = pending.Attempts,
|
|
353
355
|
};
|
|
354
356
|
|