namespace ZB.MOM.WW.ScadaBridge.InboundAPI; public class InboundApiOptions { /// /// Default cap on the inbound API request body, in bytes. /// public const long DefaultMaxRequestBodyBytes = 1L * 1024 * 1024; // 1 MiB /// Default timeout for inbound API method execution before the request is cancelled. public TimeSpan DefaultMethodTimeout { get; set; } = TimeSpan.FromSeconds(30); /// /// Maximum accepted request body size for POST /api/{methodName}. /// Requests whose body exceeds this are rejected with HTTP 413 before being /// buffered into a . The inbound API /// has no rate limiting (a deliberate design choice), so an explicit, modest cap /// bounds per-request allocations. /// public long MaxRequestBodyBytes { get; set; } = DefaultMaxRequestBodyBytes; /// /// Server-side HMAC pepper for inbound-API bearer credentials, bound from /// ScadaBridge:InboundApi:ApiKeyPepper. /// /// Auth re-arch: the legacy SQL Server hashing path that consumed this /// property was retired. The pepper itself is still required — the shared /// ZB.MOM.WW.Auth.ApiKeys verifier reads the SAME configuration key /// (PepperSecretName in the Host composition root points at it) to pepper /// the SQLite-stored keys. It is a secret: supply a strong, random value /// (≥ 16 characters), DIFFERENT per environment, via a secret store and never /// hard-coded. This property is retained so the section still binds cleanly; the /// value is consumed by the library verifier, not by AddInboundAPI. /// /// public string ApiKeyPepper { get; set; } = string.Empty; /// /// How long a resolved /// ApiMethod row (found OR not-found) is served from /// before the next request re-fetches it from the repository. The /// ScriptArtifactChangeSubscriber/IScriptArtifactChangeBus pipeline /// invalidates a specific method's entry immediately on a bundle-import change (the fast /// path); this TTL is the self-healing fallback for changes the bus does not cover (e.g. /// an operator edit via the Management API/UI, which does not publish a bus notification), /// bounding staleness without requiring every mutation path to remember to invalidate. /// Short by design — the whole point is to absorb repeated-request-storm SQL, not to /// serve minutes-old method definitions. /// public TimeSpan ApiMethodCacheTtl { get; set; } = TimeSpan.FromSeconds(5); /// /// Standby-node forwarding (2026-08-28): the HTTP base URLs of the OTHER central /// node(s) — e.g. ["http://scadabridge-central-b:5000"] on central-a — that a /// standby relays POST /api/{methodName} to instead of answering 503 /// STANDBY_NODE. Tried in order; the first peer that is not itself a standby /// serves the call. Empty (the default) keeps the pre-forwarding behaviour: a standby /// refuses with 503. Method scripts still execute only on the active node — the /// standby is a pure relay (see ). Each entry /// must be an absolute http/https URL; never list this node's own address /// (it would cost one wasted round-trip per call — the loop guard stops it bouncing). /// public List StandbyForwardPeerEndpoints { get; set; } = new(); /// /// End-to-end relay budget spanning connection, permitted standby retries and response /// consumption. Size it for the longest method execution plus network overhead. A send /// whose response is lost or times out returns OUTCOME_UNKNOWN and is never replayed. /// Default 60 s. /// public TimeSpan StandbyForwardTimeout { get; set; } = TimeSpan.FromSeconds(60); /// Default value of , also used when no options instance is available. public const int DefaultMaxLogLinesPerRun = 200; /// /// Flow Debugger step logs (design 2026-09-09 D7): how many Log.* lines ONE traced /// method execution may turn into ScriptTrace/ScriptLog audit rows. Past the cap the /// lines are dropped from the trace — they still reach the node's ILogger — and the /// run ends with a single runtime-sourced warning row naming the dropped count, so a /// truncated trace is never silently short. Untraced executions emit no rows at all and are /// therefore unaffected by this value. Must be greater than zero. /// public int MaxLogLinesPerRun { get; set; } = DefaultMaxLogLinesPerRun; }