Documentation
¶
Overview ¶
Package pushflo is a Go client SDK for the PushFlo real-time messaging service (https://pushflo.dev), mirroring the ergonomics of the official TypeScript SDK.
It provides:
- Client: a WebSocket subscriber with auto-reconnect, heartbeat, and per-channel subscriptions (publish keys, "pub_...").
- Publisher: REST publishing with retry and jittered backoff (secret keys, "sec_..."), including PublishSealed for end-to-end encrypted payloads.
- Management: the privileged API surface (management keys, "mgmt_..."), kept separate from the publish path.
The subpackage envelope adds a transport-agnostic end-to-end encryption layer (X25519 sealed box + Ed25519 signature) so the relay only ever carries ciphertext it cannot read, forge, or replay.
The WebSocket wire frames and REST endpoint are reconstructed from the public SDK's behavior and are isolated in protocol.go and publisher.go; confirm them against the PushFlo server before production use.
Index ¶
- Constants
- Variables
- func IsValidChannelSlug(s string) bool
- func ToChannelSlug(s string) string
- type AuthenticationError
- type Channel
- type ChannelInput
- type Client
- func (c *Client) Connect(ctx context.Context) error
- func (c *Client) Destroy()
- func (c *Client) Disconnect() error
- func (c *Client) IsConnected() bool
- func (c *Client) OnConnected(fn func(clientID string))
- func (c *Client) OnConnectionChange(fn func(ConnectionState))
- func (c *Client) OnDisconnected(fn func(reason string))
- func (c *Client) OnError(fn func(error))
- func (c *Client) OnMessage(fn func(Message))
- func (c *Client) State() ConnectionState
- func (c *Client) Subscribe(channel string, h SubscriptionHandlers) (*Subscription, error)
- type ClientOptions
- type ConnectionError
- type ConnectionState
- type Error
- type Management
- func (m *Management) CreateChannel(ctx context.Context, in ChannelInput) (*Channel, error)
- func (m *Management) CreateProject(ctx context.Context, in Project) (*Project, error)
- func (m *Management) DeleteChannel(ctx context.Context, slug string) error
- func (m *Management) GetChannel(ctx context.Context, slug string) (*Channel, error)
- func (m *Management) GetMessageHistory(ctx context.Context, channel string, page, pageSize int) ([]Message, *Pagination, error)
- func (m *Management) ListChannels(ctx context.Context, page, pageSize int) ([]Channel, *Pagination, error)
- func (m *Management) ListProjects(ctx context.Context) ([]Project, *Pagination, error)
- func (m *Management) UpdateChannel(ctx context.Context, slug string, in ChannelInput) (*Channel, error)
- type ManagementOptions
- type Message
- type NetworkError
- type Pagination
- type Project
- type PublishOption
- type PublishResult
- type Publisher
- func (p *Publisher) Publish(ctx context.Context, channel string, content any, opts ...PublishOption) (*PublishResult, error)
- func (p *Publisher) PublishRaw(ctx context.Context, channel string, content json.RawMessage, ...) (*PublishResult, error)
- func (p *Publisher) PublishSealed(ctx context.Context, channel string, sealer *envelope.Sealer, v any, ...) (*PublishResult, error)
- type PublisherOptions
- type SlugValidation
- type Subscription
- type SubscriptionHandlers
- type ValidationError
Constants ¶
const DefaultBaseURL = "https://api.pushflo.dev"
DefaultBaseURL is the PushFlo API base. The WS endpoint is derived from it.
const DefaultConsoleURL = "https://console.pushflo.dev"
DefaultConsoleURL is the PushFlo Console API base, used for channel and project management (the realtime API at DefaultBaseURL only handles publish/subscribe and message history).
Variables ¶
var ErrNotImplemented = errors.New("pushflo: management API not implemented yet")
ErrNotImplemented is returned by the management surface until it is built out.
Functions ¶
func IsValidChannelSlug ¶
IsValidChannelSlug reports whether s is a valid channel slug.
func ToChannelSlug ¶
ToChannelSlug converts an arbitrary string into a valid slug: lowercased, invalid characters replaced with hyphens, consecutive hyphens collapsed, leading/trailing hyphens trimmed, and truncated to 128 characters.
Types ¶
type AuthenticationError ¶
type AuthenticationError struct {
// contains filtered or unexported fields
}
AuthenticationError signals an invalid or missing API key. Not retryable.
type ChannelInput ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a PushFlo subscriber, mirroring PushFloClient from the TS SDK. It is safe for concurrent use.
func NewClient ¶
func NewClient(ctx context.Context, opts ClientOptions) (*Client, error)
NewClient builds a Client. If AutoReconnect is desired it should be set on opts; NewClient enables it by default. When opts.AutoConnect is true it dials using ctx before returning.
func (*Client) Connect ¶
Connect establishes the connection. It returns after the server's "connected" frame has been received (mirroring the official SDK, which does not treat socket-open as connected), or with an error on failure/timeout. Subsequent drops are handled by the reconnect loop when AutoReconnect is on.
func (*Client) Destroy ¶
func (c *Client) Destroy()
Destroy tears down the client and clears all subscriptions and handlers.
func (*Client) Disconnect ¶
Disconnect closes the connection and suppresses auto-reconnect. The client can be reused by calling Connect again.
func (*Client) IsConnected ¶
IsConnected reports whether the client is currently connected.
func (*Client) OnConnected ¶
OnConnected registers a handler fired when a connection is established. The server-assigned client ID is passed when available.
func (*Client) OnConnectionChange ¶
func (c *Client) OnConnectionChange(fn func(ConnectionState))
OnConnectionChange registers a callback fired on every state transition.
func (*Client) OnDisconnected ¶
OnDisconnected registers a handler fired when the connection drops.
func (*Client) State ¶
func (c *Client) State() ConnectionState
State returns the current connection state.
func (*Client) Subscribe ¶
func (c *Client) Subscribe(channel string, h SubscriptionHandlers) (*Subscription, error)
Subscribe subscribes to a channel. The channel slug is validated locally before any network call. If the client is connected the subscribe frame is sent immediately; otherwise it is (re)sent automatically on the next connect.
type ClientOptions ¶
type ClientOptions struct {
PublishKey string // required, "pub_..."
BaseURL string // default DefaultBaseURL
AutoConnect bool // if true, NewClient dials immediately
Debug bool // verbose logging via Logger
ConnectionTimeout time.Duration // default 30s
HeartbeatInterval time.Duration // default 25s
AutoReconnect bool // default true
MaxReconnectAttempts int // 0 = infinite (default)
ReconnectDelay time.Duration // initial backoff, default 1s
MaxReconnectDelay time.Duration // backoff ceiling, default 30s
Logger *log.Logger // default log.Default()
}
ClientOptions configures a subscriber Client. Only PublishKey is required; zero-valued fields fall back to the defaults noted below.
type ConnectionError ¶
type ConnectionError struct {
// contains filtered or unexported fields
}
ConnectionError signals a WebSocket connection problem. Retryable.
type ConnectionState ¶
type ConnectionState string
ConnectionState mirrors the states exposed by the TypeScript SDK.
const ( StateDisconnected ConnectionState = "disconnected" StateConnecting ConnectionState = "connecting" StateConnected ConnectionState = "connected" StateError ConnectionState = "error" )
type Error ¶
type Error struct {
Code string
Message string
Retryable bool
// Err is an optional wrapped cause.
Err error
}
Error is the base error type, mirroring PushFloError in the TS SDK. Use errors.As to inspect the concrete kind.
type Management ¶
type Management struct {
// contains filtered or unexported fields
}
Management performs privileged channel/project/history operations using a management (mgmt_) key. It is intentionally separate from Publisher so the high-privilege key and its larger API surface stay out of the common publish path — an executor or a publish-only service never links this.
This is a deliberate stub: the method set mirrors the TS SDK server client so the privilege boundary and call sites exist now, but the REST calls are TODO until there is a real need to drive these programmatically.
func NewManagement ¶
func NewManagement(opts ManagementOptions) (*Management, error)
NewManagement builds a Management client.
func (*Management) CreateChannel ¶
func (m *Management) CreateChannel(ctx context.Context, in ChannelInput) (*Channel, error)
func (*Management) CreateProject ¶
func (*Management) DeleteChannel ¶
func (m *Management) DeleteChannel(ctx context.Context, slug string) error
func (*Management) GetChannel ¶
func (*Management) GetMessageHistory ¶
func (m *Management) GetMessageHistory(ctx context.Context, channel string, page, pageSize int) ([]Message, *Pagination, error)
func (*Management) ListChannels ¶
func (m *Management) ListChannels(ctx context.Context, page, pageSize int) ([]Channel, *Pagination, error)
func (*Management) ListProjects ¶
func (m *Management) ListProjects(ctx context.Context) ([]Project, *Pagination, error)
func (*Management) UpdateChannel ¶
func (m *Management) UpdateChannel(ctx context.Context, slug string, in ChannelInput) (*Channel, error)
type ManagementOptions ¶
type ManagementOptions struct {
ManagementKey string // required, "mgmt_..."
// BaseURL defaults to DefaultConsoleURL: channel/project CRUD lives on
// the Console API, not the realtime API (confirmed against the official
// SDK's PushFloServer).
BaseURL string
Timeout time.Duration
Debug bool
}
ManagementOptions configures a Management client.
type Message ¶
type Message struct {
ID string `json:"id"`
Channel string `json:"channel"`
EventType string `json:"eventType"`
ClientID string `json:"clientId"`
Content json.RawMessage `json:"content"`
Timestamp time.Time `json:"timestamp"`
}
Message is a message received on a channel.
Content is kept as json.RawMessage so callers decide how to decode it — this is also the field the envelope layer treats as the encrypted blob when you wrap payloads (see the envelope package).
type NetworkError ¶
type NetworkError struct {
// contains filtered or unexported fields
}
NetworkError signals an HTTP/transport failure. Retryability varies.
type Pagination ¶
type PublishOption ¶
type PublishOption func(*publishConfig)
PublishOption customizes a single publish call.
func WithEventType ¶
func WithEventType(t string) PublishOption
WithEventType sets the message event type.
type PublishResult ¶
type PublishResult struct {
ID string `json:"id"`
ChannelSlug string `json:"channelSlug"`
EventType string `json:"eventType"`
ClientID string `json:"clientId"`
// Delivered is the number of subscribers the message reached.
Delivered int `json:"delivered"`
// CreatedAt is an ISO 8601 timestamp of when the message was published.
CreatedAt string `json:"createdAt"`
}
PublishResult is returned on a successful publish.
type Publisher ¶
type Publisher struct {
// contains filtered or unexported fields
}
Publisher publishes messages to channels using a secret (sec_) key.
func NewPublisher ¶
func NewPublisher(opts PublisherOptions) (*Publisher, error)
NewPublisher builds a Publisher.
func (*Publisher) Publish ¶
func (p *Publisher) Publish(ctx context.Context, channel string, content any, opts ...PublishOption) (*PublishResult, error)
Publish sends content (marshaled to JSON) to a channel.
func (*Publisher) PublishRaw ¶
func (p *Publisher) PublishRaw(ctx context.Context, channel string, content json.RawMessage, opts ...PublishOption) (*PublishResult, error)
PublishRaw publishes a pre-marshaled JSON content payload.
func (*Publisher) PublishSealed ¶
func (p *Publisher) PublishSealed(ctx context.Context, channel string, sealer *envelope.Sealer, v any, meta envelope.Meta, opts ...PublishOption) (*PublishResult, error)
PublishSealed encrypts and signs v with the given Sealer, then publishes the resulting envelope as the message content. This is the symmetric counterpart to envelope.Opener on the receiving side — the relay only sees ciphertext.
type PublisherOptions ¶
type PublisherOptions struct {
SecretKey string // required, "sec_..."
BaseURL string // default DefaultBaseURL
Timeout time.Duration // per-request timeout, default 30s
RetryAttempts int // additional attempts on retryable errors, default 3
Debug bool
HTTPClient *http.Client // optional; overrides Timeout if set
}
PublisherOptions configures a Publisher. Only SecretKey is required.
type SlugValidation ¶
SlugValidation is the detailed result of ValidateChannelSlug.
func ValidateChannelSlug ¶
func ValidateChannelSlug(s string) SlugValidation
ValidateChannelSlug validates s and, when invalid, returns a reason and a best-effort corrected suggestion.
type Subscription ¶
type Subscription struct {
// contains filtered or unexported fields
}
Subscription represents an active channel subscription.
func (*Subscription) Channel ¶
func (s *Subscription) Channel() string
Channel returns the subscribed channel slug.
func (*Subscription) Unsubscribe ¶
func (s *Subscription) Unsubscribe() error
Unsubscribe cancels the subscription.
type SubscriptionHandlers ¶
type SubscriptionHandlers struct {
OnMessage func(Message)
OnError func(error)
OnSubscribed func()
OnUnsubscribed func()
}
SubscriptionHandlers are the per-subscription callbacks.
type ValidationError ¶
type ValidationError struct {
// contains filtered or unexported fields
}
ValidationError signals invalid input (e.g. a bad channel slug). Not retryable.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package envelope adds an end-to-end encryption layer on top of any transport (PushFlo channels, HTTP, a message queue, ...).
|
Package envelope adds an end-to-end encryption layer on top of any transport (PushFlo channels, HTTP, a message queue, ...). |
|
examples
|
|
|
executor
command
Command executor is a reference API-test executor: it subscribes to a control channel, decrypts each pushed job with the envelope layer, runs the HTTP request(s) locally with full timing capture, and prints a structured result.
|
Command executor is a reference API-test executor: it subscribes to a control channel, decrypts each pushed job with the envelope layer, runs the HTTP request(s) locally with full timing capture, and prints a structured result. |
|
keygen
command
Command keygen generates key material for the encrypted envelope layer.
|
Command keygen generates key material for the encrypted envelope layer. |
|
subscribe
command
Command subscribe is a minimal PushFlo subscriber.
|
Command subscribe is a minimal PushFlo subscriber. |