Documentation
¶
Overview ¶
Package signalgate forwards encrypted fingerprint events from your backend to the SignalGate antifraud service.
There are two calls, made at two points in your funnel. Check is synchronous and returns a verdict you can gate on, so you call it before the action you are protecting. Log is fire-and-forget telemetry, so you call it after the action completes. A typical flow uses both.
client, err := signalgate.New("pk_live_...")
if err != nil {
log.Fatal(err)
}
defer client.Close(5 * time.Second)
verdict, err := client.Check(event)
if err != nil {
log.Printf("check error: %v", err)
}
if verdict.Action == "block" {
return errors.New("blocked by SignalGate")
}
By default the client fails open: if a check times out or the service returns a 5xx, Check returns a synthesized allow with FailedOpen set rather than an error, so an outage cannot block your traffic. See WithFailOpen to change it.
This SDK performs no cryptography. The opaque encrypted payload comes from the SignalGate frontend SDK and is forwarded verbatim. The package has no third-party dependencies.
Full documentation: https://signalgate.ai/docs/go
Index ¶
Constants ¶
const ( DefaultCheckTimeoutMS = 3000 DefaultLogTimeoutMS = 1000 DefaultLogQueueCapacity = 10000 DefaultLogMaxRetries = 3 DefaultLogRetryBaseMS = 200 DefaultFailOpen = true )
Default configuration values, identical across every SignalGate SDK.
const ( SDKName = "signalgate-backend-sdk" Version = "0.1.0" APIVersion = "v0" )
Identifying constants for this SDK. Version is this package's own release line; the User-Agent embeds it.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type CheckResult ¶
type CheckResult struct {
Action string `json:"action"`
Score float64 `json:"score"`
RequestID string `json:"request_id"`
TenantID string `json:"tenant_id"`
Timestamp string `json:"timestamp"`
ProcessingTimeUS int64 `json:"processing_time_us"`
FailedOpen bool `json:"-"`
}
CheckResult is the immutable verdict returned by Check. FailedOpen is a local-only flag, never read from the wire; it is true only for a synthesized fail-open allow, which lets you tell a real allow from an outage.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the SDK facade. It is safe for concurrent use by multiple goroutines: every field is set once in New and never mutated afterward, except the closed flag, which is itself concurrency-safe.
Construct one with New and share it; the zero Client is not usable. Call Close at shutdown to drain queued Log events.
func New ¶
New constructs a Client. apiKey must be non-empty; every timeout and retry count must be non-negative; the log queue capacity must be greater than zero. Invalid configuration returns a *ConfigError. New starts exactly one background log-worker goroutine, so pair it with Close.
func (*Client) Check ¶
func (c *Client) Check(event Event) (CheckResult, error)
Check is the synchronous antifraud gate. Call it before the action you are gating and act on the returned verdict.
With fail-open enabled (the default), a timeout, network failure, 5xx, or unparseable response returns a synthesized allow with FailedOpen set and a nil error, so a SignalGate outage cannot block your traffic. A 4xx always propagates as a *ServerError, since it means the request itself was wrong — a bad or revoked API key, or a malformed event. Check does not retry.
func (*Client) Close ¶
Close shuts the client down within deadline, draining the log worker and counting anything left behind as log_dropped_total{reason="closed"}. It is idempotent, and closes the transport only if the client owns it (see WithTransport). A zero deadline defaults to five times the log timeout.
type ConfigError ¶
type ConfigError struct {
Message string
}
ConfigError is returned from New for invalid configuration, and by Check when the client is already closed.
func (*ConfigError) Error ¶
func (e *ConfigError) Error() string
type EncryptedPayload ¶
type EncryptedPayload struct {
Encrypted string `json:"encrypted"`
Timestamp int64 `json:"timestamp"`
Nonce string `json:"nonce"`
V *int `json:"v,omitempty"`
}
EncryptedPayload is the opaque, immutable fingerprint blob produced by the SignalGate frontend SDK. This SDK forwards it verbatim and never inspects or decrypts it. V is the outer payload version; when nil it is omitted from the wire entirely, never serialized as "v": null.
type Error ¶
type Error interface {
error
// contains filtered or unexported methods
}
Error is the sealed root of the SDK error taxonomy. Every error this SDK surfaces satisfies it, so callers can distinguish SDK errors from any other error in a chain. The unexported marker method keeps the hierarchy closed to this package, which means a type switch over the four concrete types below is exhaustive and stays exhaustive.
type Event ¶
type Event struct {
UserID string `json:"user_id"`
IP string `json:"ip"`
Method string `json:"method"`
Timestamp string `json:"timestamp"`
Payload EncryptedPayload `json:"payload"`
Custom map[string]any `json:"custom,omitempty"`
}
Event is the immutable input value for both Check and Log. Custom is an arbitrary object omitted from the wire when nil, never serialized as "custom": null.
Check and Log fire at different points in your funnel, so each call takes its own Event carrying its own freshly captured payload. Do not forward one byte-identical payload to both: the service's nonce-freshness guard rejects the second as a replay.
type HTTPResponse ¶
HTTPResponse is a parsed 2xx response. Body is the decoded JSON object (JSON numbers decode to float64, exactly as encoding/json would produce), matching what the real transport returns so fakes and production are interchangeable.
type HTTPTransport ¶
type HTTPTransport struct {
// contains filtered or unexported fields
}
HTTPTransport is the production transport, wrapping a single pooled HTTP client. It redacts Authorization in every log line.
func NewHTTPTransport ¶
func NewHTTPTransport(apiKey, userAgent string, logger Logger) *HTTPTransport
NewHTTPTransport builds the production transport.
func (*HTTPTransport) Close ¶
func (t *HTTPTransport) Close() error
Close releases the pooled connections.
func (*HTTPTransport) Post ¶
func (t *HTTPTransport) Post(url string, body map[string]any, opts PostOptions) (HTTPResponse, error)
Post is the production POST path: one attempt, JSON UTF-8, the required headers, a per-request deadline, and error classification into TimeoutError/NetworkError/ServerError.
type Logger ¶
type Logger interface {
Debug(msg string, fields map[string]any)
Info(msg string, fields map[string]any)
Warn(msg string, fields map[string]any)
Error(msg string, fields map[string]any)
}
Logger is the structured logging seam. Implementations receive a message and a bag of fields. The default is NoopLogger.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics holds thread-safe labeled counters. A counter is identified by its name plus the set of (key, value) label pairs; label ordering is irrelevant to identity. Increments are internal to the SDK; callers read via Get and Snapshot.
type NetworkError ¶
type NetworkError struct {
Message string
}
NetworkError is returned on DNS/TCP/TLS/I-O failures before a server response.
func (*NetworkError) Error ¶
func (e *NetworkError) Error() string
type NoopLogger ¶
type NoopLogger struct{}
NoopLogger discards everything. It is the default logger.
type Option ¶
type Option func(*clientOptions)
Option configures a Client at construction. See the With* functions.
func WithCheckTimeoutMS ¶
WithCheckTimeoutMS sets the per-request timeout for Check (default 3000).
func WithFailOpen ¶
WithFailOpen toggles fail-open for Check (default true).
func WithLogMaxRetries ¶
WithLogMaxRetries sets retries after the first log attempt (default 3 ⇒ 4 attempts).
func WithLogQueueCapacity ¶
WithLogQueueCapacity sets the bounded log-queue size (default 10000; must be > 0).
func WithLogRetryBaseMS ¶
WithLogRetryBaseMS sets the exponential backoff base in ms (default 200).
func WithLogTimeoutMS ¶
WithLogTimeoutMS sets the per-attempt timeout for each log delivery (default 1000).
func WithLogger ¶
WithLogger injects a structured Logger (default NoopLogger).
func WithTransport ¶
WithTransport injects a Transport, chiefly so tests can substitute a fake for the network. When set, the Client does not own the transport and will not Close it.
type PostOptions ¶
PostOptions carries the per-attempt HTTP knobs the Client hands the transport: the per-request timeout, the fresh X-Request-Id for this attempt, and the Idempotency-Key that stays stable across retries of one call.
type ServerError ¶
type ServerError struct {
StatusCode int
Code string
Message string
RequestID string
Details map[string]any
}
ServerError is returned on a non-2xx response carrying the service's error envelope. Its message renders as "[<status_code>] <code>: <message>".
func (*ServerError) Error ¶
func (e *ServerError) Error() string
type TimeoutError ¶
type TimeoutError struct {
Message string
}
TimeoutError is returned when a request exceeds its deadline.
func (*TimeoutError) Error ¶
func (e *TimeoutError) Error() string
type Transport ¶
type Transport interface {
Post(url string, body map[string]any, opts PostOptions) (HTTPResponse, error)
Close() error
}
Transport is the injectable HTTP seam, primarily so tests can substitute a fake for the network. Post performs one POST attempt: on a non-2xx it returns a *ServerError; on a deadline it returns a *TimeoutError; on a pre-response failure it returns a *NetworkError. See WithTransport.