package outpost import ( "context" "encoding/json" "errors" "fmt" "time" ) // EmitOption adjusts a message before it is appended. type EmitOption func(*Message) // ID sets the message ID. By default Emit generates one; set it when the // business object already has a stable identifier to reuse as the dedup key. func ID(id string) EmitOption { return func(m *Message) { m.ID = id } } // Key sets the grouping key, for example the recipient or user id. func Key(key string) EmitOption { return func(m *Message) { m.Key = key } } // Header sets one header. Headers are frozen after Emit. func Header(key, value string) EmitOption { return func(m *Message) { if m.Headers == nil { m.Headers = make(map[string]string, 1) } m.Headers[key] = value } } // AvailableAt delays delivery until t, for scheduled sends. func AvailableAt(t time.Time) EmitOption { return func(m *Message) { m.AvailableAt = t } } // Emit encodes v as JSON and appends it through a under the given name. func Emit(ctx context.Context, a Appender, name string, v any, opts ...EmitOption) error { if name == "" { return errors.New("outpost: empty message name") } if a == nil { return errors.New("outpost: nil appender") } payload, err := json.Marshal(v) if err != nil { return fmt.Errorf("outpost: encode %q: %w", name, err) } msg := Message{Name: name, Payload: payload, CreatedAt: time.Now()} for _, opt := range opts { opt(&msg) } if msg.ID == "" { if msg.ID, err = newID(); err != nil { return fmt.Errorf("outpost: generate id: %w", err) } } return a.Append(ctx, msg) }