app

package
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const (
	StatusPending   = "pending"
	StatusDelivered = "delivered"
	StatusDead      = "dead"
)
View Source
const (
	AbortHeader = "Webhook-Delivery"

	AbortHeaderValue = "abort-message"
)
View Source
const (
	CodeSealKeyMissing = "E_SEAL_KEY_MISSING"

	CodeSealFailed = "E_SEAL_FAILED"
)
View Source
const AutoDisableWindow = 5 * 24 * time.Hour
View Source
const EnvAllowPrivateTarget = "WEBHOOK_ALLOW_PRIVATE_TARGET"
View Source
const OldSecretTTL = whsign.OldSecretTTL

OldSecretTTL mirrors whsign.OldSecretTTL — the rotation window during which deliveries carry X-Signature-Old alongside X-Signature.

Variables

View Source
var ErrNotFound = errors.New("webhooks: not found")
View Source
var RetryBackoff = []time.Duration{
	1 * time.Minute,
	5 * time.Minute,
	30 * time.Minute,
	2 * time.Hour,
	6 * time.Hour,
}

Functions

func MintSecret

func MintSecret() (string, error)

func Sign

func Sign(secret string, timestamp time.Time, body []byte) string

The signing protocol lives in platform/whsign (a stdlib-only leaf so webhook RECEIVERS can import it without pulling the webhooks domain); these aliases keep the historical export surface of this package compiling.

func VerifySign

func VerifySign(secret string, timestamp time.Time, body []byte, signature string) bool

func VerifySignAny

func VerifySignAny(secrets []string, timestamp time.Time, body []byte, signature string) bool

func VerifySignWithWindow

func VerifySignWithWindow(secret string, ts time.Time, body []byte, signature string, maxAge time.Duration, now time.Time) bool

Types

type AdminDeliveryView

type AdminDeliveryView struct {
	Delivery
	WorkspaceID string `json:"workspace_id"`
	URL         string `json:"url"`
}

type AdminRepo

type AdminRepo interface {
	ListAllDeliveries(ctx context.Context, f DeliveryFilter, limit, offset int) ([]AdminDeliveryView, int, error)

	AdminRedeliver(ctx context.Context, deliveryID string) (AdminDeliveryView, error)
}

type Clock

type Clock func() time.Time

type Delivery

type Delivery struct {
	ID             string     `json:"id"`
	SubscriptionID string     `json:"subscription_id"`
	EventID        string     `json:"event_id"`
	EventType      string     `json:"event_type"`
	Status         string     `json:"status"`
	Attempts       int        `json:"attempts"`
	LastStatusCode int        `json:"last_status_code,omitempty"`
	LastError      string     `json:"last_error,omitempty"`
	DeliveredAt    *time.Time `json:"delivered_at,omitempty"`
	CreatedAt      time.Time  `json:"created_at"`
}

type DeliveryFilter

type DeliveryFilter struct {
	WorkspaceID string
	Status      string
}

type EventCatalog

type EventCatalog struct {
	// contains filtered or unexported fields
}

func NewEventCatalog

func NewEventCatalog() *EventCatalog

func (*EventCatalog) Has

func (c *EventCatalog) Has(eventType string) bool

func (*EventCatalog) List

func (c *EventCatalog) List() map[string]string

func (*EventCatalog) Register

func (c *EventCatalog) Register(eventType, description string)

type OutboundEvent

type OutboundEvent struct {
	ID      string
	Type    string
	Payload map[string]any
}

type PendingDelivery

type PendingDelivery struct {
	DeliveryID     string
	SubscriptionID string

	WorkspaceID string
	URL         string

	Secret    string
	EventID   string
	EventType string
	Payload   json.RawMessage
	Attempts  int

	OldSealed    string
	OldExpiresAt *time.Time
	OldPlain     string
}

type Repo

type Repo interface {
	CreateSubscription(ctx context.Context, sub Subscription, secret string) (Subscription, error)
	ListSubscriptions(ctx context.Context, workspaceID string) ([]Subscription, error)
	DeleteSubscription(ctx context.Context, workspaceID, id string) error

	GetSubscription(ctx context.Context, workspaceID, id string) (Subscription, bool, error)

	SetSubscriptionActive(ctx context.Context, workspaceID, id string, active bool, now time.Time) error

	RotateSecret(ctx context.Context, workspaceID, subscriptionID, newSealed string, oldExpiresAt, now time.Time) error

	FirstFailureAt(ctx context.Context, subscriptionID string) (*time.Time, error)

	EmitForEvent(ctx context.Context, workspaceID string, event OutboundEvent) (int, error)

	ClaimPending(ctx context.Context, batchSize int) ([]PendingDelivery, error)

	MarkDelivered(ctx context.Context, deliveryID string, statusCode int, now time.Time) error

	MarkRetry(ctx context.Context, deliveryID string, statusCode int, errMsg string, nextAt time.Time, dead bool) error
	ListDeliveries(ctx context.Context, workspaceID string, limit int) ([]Delivery, error)

	Redeliver(ctx context.Context, workspaceID, deliveryID string) (Delivery, error)

	EnqueuePing(ctx context.Context, workspaceID, subscriptionID string) error
}

type Secrets

type Secrets interface {
	Seal(plain string) (string, error)
	Unseal(stored string) (string, error)
}

type Subscription

type Subscription struct {
	ID          string    `json:"id"`
	WorkspaceID string    `json:"workspace_id"`
	EventTypes  []string  `json:"event_types"`
	URL         string    `json:"url"`
	Description string    `json:"description"`
	IsActive    bool      `json:"is_active"`
	CreatedAt   time.Time `json:"created_at"`
}

type WebhookService

type WebhookService struct {
	HTTPClient *http.Client
	// contains filtered or unexported fields
}

func NewWebhookService

func NewWebhookService(repo Repo, catalog *EventCatalog, log *slog.Logger, now Clock) *WebhookService

func (*WebhookService) AdminRedeliver

func (s *WebhookService) AdminRedeliver(ctx context.Context, deliveryID string) (AdminDeliveryView, error)

func (*WebhookService) Catalog

func (s *WebhookService) Catalog() *EventCatalog

func (*WebhookService) CreateSubscription

func (s *WebhookService) CreateSubscription(ctx context.Context, workspaceID, url, description string, eventTypes []string) (Subscription, string, error)

func (*WebhookService) DeleteSubscription

func (s *WebhookService) DeleteSubscription(ctx context.Context, workspaceID, id string) error

func (*WebhookService) DeliverPending

func (s *WebhookService) DeliverPending(ctx context.Context, batchSize int)

func (*WebhookService) Emit

func (s *WebhookService) Emit(ctx context.Context, workspaceID string, event OutboundEvent) (int, error)

func (*WebhookService) GetSubscription

func (s *WebhookService) GetSubscription(ctx context.Context, workspaceID, id string) (Subscription, bool, error)

func (*WebhookService) ListAllDeliveries

func (s *WebhookService) ListAllDeliveries(ctx context.Context, f DeliveryFilter, limit, offset int) ([]AdminDeliveryView, int, error)

func (*WebhookService) ListDeliveries

func (s *WebhookService) ListDeliveries(ctx context.Context, workspaceID string, limit int) ([]Delivery, error)

func (*WebhookService) ListSubscriptions

func (s *WebhookService) ListSubscriptions(ctx context.Context, workspaceID string) ([]Subscription, error)

func (*WebhookService) Ping

func (s *WebhookService) Ping(ctx context.Context, workspaceID, subscriptionID string) error

func (*WebhookService) Redeliver

func (s *WebhookService) Redeliver(ctx context.Context, workspaceID, deliveryID string) (Delivery, error)

func (*WebhookService) RotateSecret

func (s *WebhookService) RotateSecret(ctx context.Context, workspaceID, subscriptionID string) (string, error)

func (*WebhookService) SetSubscriptionActive

func (s *WebhookService) SetSubscriptionActive(ctx context.Context, workspaceID, subscriptionID string, active bool) error

func (*WebhookService) WithHTTPClient

func (s *WebhookService) WithHTTPClient(c *http.Client) *WebhookService

func (*WebhookService) WithHooks

func (*WebhookService) WithSecrets

func (s *WebhookService) WithSecrets(sec Secrets) *WebhookService

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL