// FILE: ./internal/sources/common/event.go package common import ( "time" "gitea.maximumdirect.net/ejr/feedkit/event" ) // SingleRawEvent constructs, validates, and returns a slice containing exactly one event. // // This removes repetitive "event envelope ceremony" from individual sources. // Sources remain responsible for: // - fetching bytes (raw payload) // - choosing Schema (raw schema identifier) // - computing Event.ID and (optional) EffectiveAt // // emittedAt is explicit so callers can compute IDs using the same timestamp (or // so tests can provide a stable value). func SingleRawEvent( kind event.Kind, sourceName string, schema string, id string, emittedAt time.Time, effectiveAt *time.Time, payload any, ) ([]event.Event, error) { if emittedAt.IsZero() { emittedAt = time.Now().UTC() } else { emittedAt = emittedAt.UTC() } e := event.Event{ ID: id, Kind: kind, Source: sourceName, EmittedAt: emittedAt, EffectiveAt: effectiveAt, // RAW schema (normalizer matches on this). Schema: schema, // Raw payload (usually json.RawMessage). Normalizer will decode and map to canonical model. Payload: payload, } if err := e.Validate(); err != nil { return nil, err } return []event.Event{e}, nil }