Documentation
¶
Overview ¶
Package devserver — Stripe mock backend.
This file implements just enough of Stripe's HTTP API to round-trip cleanly through the official stripe-go SDK. Apps point stripe-go at the dev proxy via stripe.SetBackend(...) with BackendConfig.URL = "<HAMR_DEV_URL>/__hamr/stripe", and stripe-go appends paths like /v1/checkout/sessions to that base.
The mock is dev-only and has no production safeguards beyond the gating done by hamr.toml [dev.stripe].
Index ¶
- Constants
- Variables
- func CheckLatestVersion(ctx context.Context, currentVersion string, onResult func(latest string))
- func ComposeArgs(dc *DockerCompose) []string
- func HamrDevTag() string
- func ListenAndServeProxy(addr string, handler http.Handler) (*http.Server, net.Listener, error)
- func MCPAreaNames() []string
- func MakefileTargetsFromPath(path string) ([]string, error)
- func NewProxyHandler(target string, broker *SSEBroker, errorState *ErrorState, logBuf *LogBuffer, ...) http.Handler
- func PrefsPathFor(configPath string) string
- func ResolveEnvRewrites(dir string) ([]string, error)
- func RewriteValueForWalks(dir, value string) string
- func RunMockServe(ctx context.Context, logger *slog.Logger) error
- func WaitForConfigChangeOrQuit(ctx context.Context, path string, hotkeys <-chan HotkeyAction) error
- type Config
- type ConsoleFrame
- type ConsoleSink
- type Daemon
- type DevActions
- func (a *DevActions) CheckRestart() error
- func (a *DevActions) DockerComposes() []DockerCompose
- func (a *DevActions) DockerWipe(dc *DockerCompose, service string)
- func (a *DevActions) ErrorState() *ErrorState
- func (a *DevActions) RebuildAll()
- func (a *DevActions) RegisterRoutes(mux *http.ServeMux)
- func (a *DevActions) RestartServer() bool
- type DevConfig
- type DockerCompose
- type Duration
- type EmailConfig
- type ErrorState
- type FileEvent
- type Graph
- type HotkeyAction
- type HotkeySource
- type LogBuffer
- type LogLine
- type MCPConfig
- type MCPHandshake
- type MailMock
- func (m *MailMock) Clear()
- func (m *MailMock) Delete(id string) bool
- func (m *MailMock) Get(id string) *mailMessage
- func (m *MailMock) List() []*mailMessage
- func (m *MailMock) RegisterIngestRoutes(mux *http.ServeMux)
- func (m *MailMock) RegisterRoutes(mux *http.ServeMux)
- func (m *MailMock) RegisterUIRoutes(mux *http.ServeMux)
- func (m *MailMock) SetStatus(id, status, note string) bool
- type MailMockOptions
- type MockProvider
- type MountedMock
- type Option
- func WithActionsHook(fn func(*DevActions)) Option
- func WithConfigPath(path string) Option
- func WithDockerLogSinks(sinks map[string]io.Writer) Option
- func WithHotkeys(h HotkeySource) Option
- func WithLogWriter(w io.Writer) Option
- func WithLogger(l *slog.Logger) Option
- func WithMCPLogHook(fn func(line string)) Option
- func WithMCPStatusHook(fn func(enabled bool, tools int)) Option
- func WithNoProxy(v bool) Option
- func WithProcessOutput(stdout, stderr io.Writer) Option
- func WithProxyURLHook(fn func(string)) Option
- func WithVerbose(v bool) Option
- type ProcessManager
- func (pm *ProcessManager) ClearCallbacks()
- func (pm *ProcessManager) RunCommand(ctx context.Context, rule *WatchRule) (string, error)
- func (pm *ProcessManager) SetFileLog(w io.Writer)
- func (pm *ProcessManager) SetInjectedEnv(env []string)
- func (pm *ProcessManager) SetLogOutput(buf *LogBuffer, broker *SSEBroker)
- func (pm *ProcessManager) SetOutputSinks(stdout, stderr io.Writer)
- func (pm *ProcessManager) StartProcess(ctx context.Context, rule *WatchRule) error
- func (pm *ProcessManager) StopAll()
- type ProxyConfig
- type ReloadScope
- type RequestLog
- type RequestLogEntry
- type Runner
- type SMSConfig
- type SMSMock
- func (m *SMSMock) Clear()
- func (m *SMSMock) Delete(id string) bool
- func (m *SMSMock) Get(id string) *smsMessage
- func (m *SMSMock) List() []*smsMessage
- func (m *SMSMock) RegisterIngestRoutes(mux *http.ServeMux)
- func (m *SMSMock) RegisterRoutes(mux *http.ServeMux)
- func (m *SMSMock) RegisterUIRoutes(mux *http.ServeMux)
- func (m *SMSMock) SetStatus(id, status, note string) bool
- type SMSMockOptions
- type SSEBroker
- type SSEEvent
- type StringOrSlice
- type StripeAccountSummary
- type StripeConfig
- type StripeLineItemSummary
- type StripeMock
- func (m *StripeMock) FireEvent(ctx context.Context, eventType string, dataObject map[string]any) error
- func (m *StripeMock) RegisterAPIRoutes(mux *http.ServeMux)
- func (m *StripeMock) RegisterRoutes(mux *http.ServeMux)
- func (m *StripeMock) RegisterUIRoutes(mux *http.ServeMux)
- func (m *StripeMock) SetWebhookEndpoint(ep WebhookEndpoint)
- type StripeMockOptions
- type StripeObjectSummary
- type StripeSessionSummary
- type StripeStateSummary
- type VersionStatus
- type WatchRule
- type Watcher
- type WebhookEndpoint
Constants ¶
const MCPHandshakeFile = ".hamr/dev.json"
MCPHandshakeFile is the per-project runtime descriptor the `hamr mcp` bridge reads to find and authenticate to this dev server. Mode 0600, gitignored. Path is relative to the project root.
const PrefsFileName = ".pref.hamr.toml"
PrefsFileName is the per-developer override read from the same directory as the main config. Gitignored by the scaffold: it holds preferences a developer wants locally without imposing them on the team.
Variables ¶
var ErrConfigReload = errors.New("config changed, reloading")
ErrConfigReload is returned by Run when the config file changes. The caller should reload the config and call Run again.
var ErrRestart = errors.New("restart requested")
ErrRestart is returned by Run when a restart is requested explicitly (the TUI's R hotkey or the dev.restart MCP tool). Identical handling to ErrConfigReload — the caller reloads the config and calls Run again — but a distinct sentinel so the caller can say why it is restarting.
Functions ¶
func CheckLatestVersion ¶
CheckLatestVersion checks GitHub for the latest hamr release and calls onResult with the latest version string if it is newer than current. The check runs in a goroutine and is best-effort — network errors are silently ignored.
func ComposeArgs ¶
func ComposeArgs(dc *DockerCompose) []string
ComposeArgs returns the `docker` arguments hamr itself uses for a compose entry — project directory, base file, and the generated port-walk override when one exists. Exported so `hamr compose` can hand external callers the same merged config the dev server is running, instead of them merging the base file alone and reconciling the stack back onto un-walked ports.
Paths are relative to the project root, so the caller must run docker from there.
func HamrDevTag ¶
func HamrDevTag() string
HamrDevTag returns the colored [hamr dev] tag string for use outside the logger.
func ListenAndServeProxy ¶
ListenAndServeProxy starts the proxy server. It blocks until the context is cancelled or an error occurs. Kept for tests and external callers that don't need the +1-on-busy port walking — the dev runner uses listenWalk + serveProxy directly so it can react to EADDRINUSE before constructing the handler.
func MCPAreaNames ¶
func MCPAreaNames() []string
MCPAreaNames returns every configurable [dev.mcp.access] area in a stable order. Exported for the `hamr setup` picker, which needs the canonical list without duplicating it.
func MakefileTargetsFromPath ¶
MakefileTargetsFromPath reads the Makefile at path and returns its declared target names in the order they appear. Pattern rules (containing '%'), variables (lines with ':=' / '+=' / '?='), comments, and recipe lines (starting with a tab) are ignored. The function does not parse includes or expand variables — the dev TUI's run overlay just needs the human-visible target list, not full make semantics.
Returns ([]string{}, nil) when the file does not exist so callers can gate UI on a non-error empty list.
func NewProxyHandler ¶
func NewProxyHandler(target string, broker *SSEBroker, errorState *ErrorState, logBuf *LogBuffer, actions *DevActions, mailMock *MailMock, smsMock *SMSMock, stripeMock *StripeMock, console *ConsoleSink, gateway *mcpGateway, requestLog *RequestLog, injectReload bool) http.Handler
NewProxyHandler creates an HTTP handler that reverse-proxies to the target address, optionally injecting the live reload script into HTML responses. The SSE broker handler is mounted at /__hamr/reload. If errorState is non-nil, HTML requests are intercepted with an error page when there are active build errors. If mailMock is non-nil, the mail inbox UI and ingest endpoint are mounted under /__hamr/mail. If smsMock is non-nil, the SMS equivalents are mounted under /__hamr/sms. If console is non-nil, the browser console transport is mounted as a WebSocket at /__hamr/console; the injected reload script connects to it and pipes window.console.* + uncaught errors back into the dev TUI/log.
func PrefsPathFor ¶
PrefsPathFor returns the override path that pairs with the given config file — a sibling of it, so `hamr dev --config /elsewhere/hamr.toml` reads /elsewhere/.pref.hamr.toml.
func ResolveEnvRewrites ¶
ResolveEnvRewrites loads .hamr/walks.json and .env from dir, applies the active port-walk rewrite rules, and returns the rewritten KEY=VALUE pairs the spawned-children injection would emit. Empty result (nil, nil) when nothing walked or no .env present — consumers can use the result unconditionally; an empty slice makes their downstream a no-op.
This is the canonical entry point for callers outside the package (cmd/env, etc.). Match rules and limitations are documented on the per-rule helpers.
func RewriteValueForWalks ¶
RewriteValueForWalks applies the active port-walk rewrites to a single value (typically one read out of .env by hamr sync). Returns the value unchanged when no walks file is present or when nothing in the value matches a walked port. Errors loading walks.json are swallowed: a malformed file shouldn't break a CLI invocation that has a perfectly good fallback in the literal value the caller already has.
func RunMockServe ¶
RunMockServe stands up the selected mocks and serves until ctx is cancelled. Selection and all configuration come from environment variables.
func WaitForConfigChangeOrQuit ¶
func WaitForConfigChangeOrQuit(ctx context.Context, path string, hotkeys <-chan HotkeyAction) error
WaitForConfigChangeOrQuit blocks until the file at path is written or created (returns nil), ctx is cancelled, a HotkeyQuit comes in (returns context.Canceled), or a HotkeyRestart comes in (returns ErrRestart — retry now). Restart is honored here because a parse error is not the only reason the last attempt failed: the config can be valid and startup still fail on a clashing port or a bad .env, and neither of those touches hamr.toml, so waiting on a file write would hang forever. Other hotkeys are silently consumed. A nil hotkeys channel is safe (blocks forever).
Types ¶
type Config ¶
type Config struct {
Dev DevConfig `toml:"dev"`
Proxy ProxyConfig `toml:"proxy"`
// ProxyConfigured is true when [proxy] was explicitly present in the TOML.
// When false, the proxy is not started and no defaults are applied.
ProxyConfigured bool `toml:"-"`
}
Config is the top-level hamr.toml configuration.
func LoadConfig ¶
LoadConfig reads and parses a hamr.toml file, merges the per-developer .pref.hamr.toml override over it if present, applies defaults, and validates.
func LoadConfigNoPrefs ¶
LoadConfigNoPrefs is LoadConfig without the .pref.hamr.toml merge. Use it anywhere the loaded values are written back to hamr.toml — merging first would promote a developer's gitignored local preference into the team's committed config.
type ConsoleFrame ¶
type ConsoleFrame struct {
// Level is one of: "log", "info", "debug", "warn", "error".
// Internal categories the JS may send for non-console events:
// "rejection" (unhandled promise), "resource" (load failure),
// "csp" (CSP violation). Only "warn" and "error" get a colored
// uppercase level label in the rendered line; every other value
// (including the internal categories) renders without a label so
// the line stays scannable. This matches the backend slog handler's
// convention.
Level string `json:"level"`
// Msg is the rendered text (args joined client-side, objects already
// JSON-stringified, capped per-arg by the JS serializer).
Msg string `json:"msg"`
// Src is an optional source location, used only for uncaught errors
// where the file:line:col is load-bearing. Plain console.* calls
// leave it empty.
Src string `json:"src,omitempty"`
}
ConsoleFrame is one log entry sent up by the browser. The field set is kept narrow on purpose: anything more (timestamps, URLs, multi-tab IDs) goes through a different conversation.
type ConsoleSink ¶
type ConsoleSink struct {
// contains filtered or unexported fields
}
ConsoleSink is the dev-server side of the browser-console transport. It owns the WS endpoint and a single io.Writer (the same multiwriter the dev slog handler uses) so frames land in TUI tab 0 and the rolling dev_logs.txt file alongside backend events, in arrival order.
func NewConsoleSink ¶
func NewConsoleSink(w io.Writer, filterHamr bool) *ConsoleSink
NewConsoleSink wires the sink to the same writer as the dev logger. Pass filterHamr=true to drop frames whose msg contains "[hamr]" (i.e. hamr's own reload-script chatter); default is to show everything.
func (*ConsoleSink) Handler ¶
func (c *ConsoleSink) Handler() http.Handler
Handler returns the WS upgrade handler. Mount at /__hamr/console. Each frame on the wire is JSON; the wire format accepts either a single ConsoleFrame object or an array (the JS client batches small bursts to keep frame count down). Unparseable payloads are dropped silently — dev-only, not worth surfacing to the user.
Origin gating is the coder/websocket default: Origin must equal Host. In dev that's always true (the JS is injected by the same proxy that serves the WS). External callers hitting the endpoint cross-origin will be rejected at upgrade.
func (*ConsoleSink) Snapshot ¶
func (c *ConsoleSink) Snapshot(level, contains string, tail int) []consoleLine
Snapshot returns up to tail recent frames matching the level (exact, case- insensitive) and contains (substring on msg) filters, oldest first.
func (*ConsoleSink) Write ¶
func (c *ConsoleSink) Write(f ConsoleFrame)
Write renders a single frame and emits it through the dev writer. Empty messages and (when filtering) hamr-prefixed messages are dropped. Exported so tests can drive formatting without standing up a WS server.
type Daemon ¶
type Daemon struct {
Name string `toml:"name"`
Cmd string `toml:"cmd"`
Dir string `toml:"dir"`
Env []string `toml:"env"`
}
Daemon defines a long-running background process started once at launch.
type DevActions ¶
type DevActions struct {
// contains filtered or unexported fields
}
DevActions encapsulates API action handlers for the dev panel.
func (*DevActions) CheckRestart ¶ added in v0.36.0
func (a *DevActions) CheckRestart() error
CheckRestart reports whether a restart would be accepted right now, returning nil when it would and an explanation when it would not — no live runner, or the current run is still inside the restart cooldown. It changes nothing, so a caller can answer first and restart afterwards.
func (*DevActions) DockerComposes ¶
func (a *DevActions) DockerComposes() []DockerCompose
DockerComposes returns the configured docker compose entries the runner is managing.
func (*DevActions) DockerWipe ¶
func (a *DevActions) DockerWipe(dc *DockerCompose, service string)
DockerWipe triggers a "down -v + up -d" cycle for the given compose entry, removing volumes. When service is "" the whole entry is wiped; otherwise only that service. Runs synchronously on the calling goroutine — TUI callers should dispatch in a goroutine to keep the UI responsive.
func (*DevActions) ErrorState ¶
func (a *DevActions) ErrorState() *ErrorState
ErrorState returns the underlying error state so non-HTTP consumers (the TUI runtime) can subscribe to error changes.
func (*DevActions) RebuildAll ¶
func (a *DevActions) RebuildAll()
RebuildAll enqueues every watch rule onto the scheduler, which resolves topological order and dependency gating itself. Used by the hotkey system to trigger a full rebuild.
func (*DevActions) RegisterRoutes ¶
func (a *DevActions) RegisterRoutes(mux *http.ServeMux)
RegisterRoutes registers the action API endpoints on the given mux.
func (*DevActions) RestartServer ¶ added in v0.36.0
func (a *DevActions) RestartServer() bool
RestartServer asks the runner to tear down and re-run its entire startup lifecycle — docker compose, port resolution, .env injection, builds, daemons, watcher — without exiting the TUI. Use it for state the runner only reads at startup: a clashing port, an edited .env, a container that came up wrong. Returns false when no live runner is attached.
Returns as soon as the request is queued, not when the restart completes: the proxy that carried an MCP call is one of the things torn down, so the caller has to get its response out first.
ponytail: between teardown and the next Run's writeWalks(".", nil), walks.json still holds the old run's port rewrites — so `hamr env --export` (and the scaffold Makefile targets that shell it) can report pre-restart ports for a second or two. Same window config reload has always had. Clear walks at teardown instead if that ever bites.
type DevConfig ¶
type DevConfig struct {
Watch []WatchRule `toml:"watch"`
Daemons []Daemon `toml:"daemon"`
DockerCompose []DockerCompose `toml:"docker_compose"`
LogFile string `toml:"log_file"`
LogFileMaxLines int `toml:"log_file_max_lines"`
ProxyListen string `toml:"proxy_listen"`
ProxyTarget string `toml:"proxy_target"`
InjectReload *bool `toml:"inject_reload"`
Email EmailConfig `toml:"email"`
SMS SMSConfig `toml:"sms"`
Stripe StripeConfig `toml:"stripe"`
MCP MCPConfig `toml:"mcp"`
// DarkFilter sets the initial state of the dev-panel "Dark filter"
// toggle: an invert(1) hue-rotate(180deg) CSS filter over the proxied
// site so a light-mode app is bearable to work on. Default false. The
// panel toggle flips it at runtime in the hamr dev process only — the
// value is never written back to hamr.toml.
DarkFilter bool `toml:"dark_filter"`
// HamrConsoleCapture toggles the entire browser-console transport
// (window.console.* + uncaught errors + unhandled rejections +
// resource-load failures + CSP violations → /__hamr/console WS →
// `[site:console]` lines in the dev TUI / log file). Default true
// (nil pointer): on by default in fresh scaffolds. Set false to skip
// mounting the WS endpoint and to tell the injected reload script
// not to patch console or open a connection — zero overhead.
HamrConsoleCapture *bool `toml:"hamr_console_capture"`
// HamrConsoleFilter, when true, drops browser console frames whose
// message contains "[hamr]" — i.e. logs emitted by hamr's own injected
// reload script. Default false: show everything the browser sees,
// including hamr's own chatter. Flip true if the per-save chatter
// (`[hamr] live reload connected`, `[hamr] page swapped`, etc.) is
// noisy enough to drown out app-side logs. No effect when
// HamrConsoleCapture is false.
HamrConsoleFilter bool `toml:"hamr_console_filter"`
// PortWalk toggles the +1-on-busy walk for hamr-managed ports
// (proxy.listen, proxy.target / spawned-app PORT, and docker-compose
// host-port publishes). Default true: when a port is busy hamr walks +1
// up to a small cap and logs a WARN per shift, so two `hamr dev`
// instances on the same machine don't collide. Set false to disable
// walking and fail fast on EADDRINUSE — useful when CI or external
// tooling pins a specific port and would mis-target if hamr silently
// shifted.
PortWalk *bool `toml:"port_walk"`
}
DevConfig holds the [dev] table with watch rules and daemons.
func (DevConfig) HamrConsoleCaptureEnabled ¶
HamrConsoleCaptureEnabled returns whether the browser-console transport is on. Defaults to true when the field is unset (nil) — opt-out, not opt-in.
func (DevConfig) PortWalkEnabled ¶
PortWalkEnabled returns whether the +1-on-busy port walk is enabled. Defaults to true when the field is unset (nil) — opt-out, not opt-in.
type DockerCompose ¶
type DockerCompose struct {
Name string `toml:"name"`
File string `toml:"file"`
Services []string `toml:"services"`
KeepRunning bool `toml:"keep_running"`
WaitReady bool `toml:"wait_ready"`
Env []string `toml:"env"`
}
DockerCompose declares a docker compose file that hamr ensures is running.
type Duration ¶
Duration wraps time.Duration with TOML unmarshaling that accepts an integer (milliseconds) or a Go duration string like "200ms".
func (*Duration) UnmarshalTOML ¶
UnmarshalTOML implements the toml.Unmarshaler interface.
type EmailConfig ¶
type EmailConfig struct {
Enabled bool `toml:"enabled"`
MaxMessages int `toml:"max_messages"` // default 500
MaxMessageBytes int64 `toml:"max_message_bytes"` // default 10MiB
Persist *bool `toml:"persist"` // default true
PersistPath string `toml:"persist_path"` // default ".hamr/mail/inbox.mbox"
}
EmailConfig holds the [dev.email] table for the mail mock. When Enabled is true, hamr dev runs an email inbox at /__hamr/mail on the reverse proxy. Requires [proxy] to be configured.
Persistence defaults to on: the inbox is mirrored to an mbox file at PersistPath so it survives hamr dev restart. Set Persist=false for an ephemeral in-memory-only inbox.
func (EmailConfig) PersistEnabled ¶
func (c EmailConfig) PersistEnabled() bool
PersistEnabled returns whether persistence is on. Defaults to true when the field is unset (nil).
func (EmailConfig) ResolvedPersistPath ¶
func (c EmailConfig) ResolvedPersistPath() string
ResolvedPersistPath returns PersistPath with the default applied.
type ErrorState ¶
type ErrorState struct {
// contains filtered or unexported fields
}
ErrorState tracks active build/process errors in a thread-safe manner. The proxy reads it to decide whether to serve the error page; devserver writes it on build failure / success.
func (*ErrorState) Clear ¶
func (e *ErrorState) Clear(rule string)
Clear removes the error for the given rule.
func (*ErrorState) HasErrors ¶
func (e *ErrorState) HasErrors() bool
HasErrors returns true if any rule has an active error.
func (*ErrorState) OnChange ¶
func (e *ErrorState) OnChange(fn func())
OnChange registers a callback that fires after Set or Clear modifies state.
func (*ErrorState) RuleNames ¶
func (e *ErrorState) RuleNames() []string
RuleNames returns the sorted names of rules with active errors.
func (*ErrorState) Set ¶
func (e *ErrorState) Set(rule, output string)
Set records a build/process error for the given rule.
func (*ErrorState) Snapshot ¶
func (e *ErrorState) Snapshot() map[string]string
Snapshot returns a copy of the current errors map.
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph tracks dependency relationships and coordinates execution order between watch rules using channels for signaling.
func NewGraph ¶
NewGraph builds a dependency graph from the given watch rules. It assumes rules have already been validated (no cycles, no unknown deps).
func (*Graph) MarkRunning ¶
MarkRunning resets the named rule's done channel so dependees will block.
func (*Graph) TopologicalOrder ¶
TopologicalOrder returns rule names in an order that respects dependencies (dependencies come before dependees).
type HotkeyAction ¶
type HotkeyAction int
HotkeyAction represents a user-triggered hotkey action.
const ( HotkeyRebuild HotkeyAction = iota HotkeyOpenBrowser HotkeyQuit HotkeyMCPToggle // HotkeyRestart tears the dev server down and re-runs its whole startup // lifecycle (docker compose, port resolution, .env injection, builds, // daemons, watcher) in-place, leaving the TUI running. The escape hatch // for state the runner only reads at startup: a clashing port, an edited // .env, a container that came up wrong. HotkeyRestart )
type HotkeySource ¶
type HotkeySource interface {
Actions() <-chan HotkeyAction
}
HotkeySource emits hotkey actions for the dev runner to consume. The TUI implements this with a bubbletea-backed adapter; the runner reads from Actions() in its event loop. A nil channel means no source is attached and the loop should never fire on it.
type LogBuffer ¶
type LogBuffer struct {
// contains filtered or unexported fields
}
LogBuffer is a thread-safe ring buffer that keeps the last N log lines.
func NewLogBuffer ¶
NewLogBuffer creates a new LogBuffer capped at max lines.
type LogLine ¶
type LogLine struct {
Rule string `json:"rule"`
Text string `json:"text"`
Color string `json:"color,omitempty"`
Time time.Time `json:"time"`
}
LogLine is a single line of process output tagged with its rule name.
type MCPConfig ¶
type MCPConfig struct {
// Enabled is the initial runtime state at launch. The TUI kill-switch can
// flip the live gateway without rewriting this. Default false.
Enabled bool `toml:"enabled"`
// Access maps a functional area (dev, logs, docker, mail, sms, build, stripe) to
// a level ("read", "write", or "deny"). "write" implies "read". Areas absent
// from the map are denied. With no table at all, zero tools are exposed.
Access map[string]string `toml:"access"`
// MakeTargets constrains make.run to a named subset. Empty = every Makefile
// target is allowed (the permissive default).
MakeTargets []string `toml:"make_targets"`
// MakeWait bounds how long make.run blocks before returning a "still
// running, poll logs" result. Default 20s when unset.
MakeWait Duration `toml:"make_wait"`
// LogFile is the MCP audit log path. Default ".hamr/mcp_logs.txt"; set to
// "none" to disable the audit log.
LogFile string `toml:"log_file"`
}
MCPConfig holds the [dev.mcp] table — the gateway that lets an AI agent drive hamr dev through the `hamr mcp` stdio bridge. Off by default; opt-in.
The bridge connects over the existing localhost /__hamr/* HTTP API, authenticated by a per-run token (see the gateway). Permissions are granted per functional area at read/write/deny granularity via Access; an area not granted exposes none of its tools.
func (MCPConfig) EnabledTools ¶
EnabledTools returns the set of tool names the Access map exposes. Unknown areas/levels are ignored here (validate() rejects them at load time).
func (MCPConfig) MakeTargetAllowed ¶
MakeTargetAllowed reports whether make.run may run the given target. Empty MakeTargets means every target is allowed.
func (MCPConfig) ResolvedLogFile ¶
ResolvedLogFile returns the audit-log path with the default applied, or "" when the audit log is disabled ("none").
func (MCPConfig) ResolvedMakeWait ¶
ResolvedMakeWait returns the make.run bounded-wait duration, defaulting to 20s when unset or non-positive.
func (MCPConfig) ToolAllowed ¶
ToolAllowed reports whether the named tool is exposed by the current Access map. The gateway uses this to enforce permissions per call.
type MCPHandshake ¶
MCPHandshake is the JSON written to .hamr/dev.json by an enabled gateway and read by the `hamr mcp` bridge — the single source of truth for the wire format the two share.
func ReadMCPHandshake ¶
func ReadMCPHandshake(projectRoot string) (MCPHandshake, error)
ReadMCPHandshake loads the handshake descriptor from projectRoot. Returns a clear error when the file is absent (dev server not running / MCP disabled).
type MailMock ¶
type MailMock struct {
// contains filtered or unexported fields
}
MailMock is a dev-only email inbox. Messages arrive via /__hamr/mail/ingest (POST JSON), are stored in a ring buffer, and are viewable at /__hamr/mail on the reverse proxy. If persistPath is set, the inbox is mirrored to an mbox file on disk so it survives hamr dev restart.
func NewMailMock ¶
func NewMailMock(opts MailMockOptions) *MailMock
NewMailMock returns a MailMock with the given options. If PersistPath is non-empty, any existing inbox at that path is loaded and subsequent changes are mirrored there. Load failures are reported via OnPersistError (if set) but never fatal — the in-memory inbox starts empty.
func (*MailMock) Get ¶
Get returns a deep copy of the message with the given id, or nil if not found. The copy decouples callers from concurrent mutation.
func (*MailMock) List ¶
func (m *MailMock) List() []*mailMessage
List returns a newest-first snapshot of the inbox. Messages are deep-copied so callers can read fields without racing concurrent mutators (SetStatus).
func (*MailMock) RegisterIngestRoutes ¶
RegisterIngestRoutes mounts the SMTP capture sink. handleIngest is server-to-server (no browser Origin) — intentionally NOT origin-guarded; see guardUnsafe.
func (*MailMock) RegisterRoutes ¶
RegisterRoutes mounts both the UI and the ingest endpoint on mux. Do not register twice on the same mux — http.ServeMux panics on duplicate patterns.
func (*MailMock) RegisterUIRoutes ¶
RegisterUIRoutes mounts the human-facing inbox UI. Split from the ingest sink so the two can live on separate listeners (see `hamr mock-serve`).
func (*MailMock) SetStatus ¶
SetStatus marks a stored message as having a particular outcome. Used by the UI to simulate post-hoc bounce/delay on an already-captured message. Allowed values: "failed", "delayed" ("delivered" is the implicit default set at ingest and cannot be re-applied here). Unknown values are rejected.
Persistence: rewrites the whole mbox file (status is in the headers).
type MailMockOptions ¶
type MailMockOptions struct {
MaxMessages int // default 500
MaxMessageBytes int64 // default 10 MiB
PersistPath string // "" disables persistence
OnPersistError func(error) // invoked on disk write/read errors; nil is silent
}
MailMockOptions configures a MailMock at construction.
type MockProvider ¶
type MockProvider struct {
Name string
Build func(logger *slog.Logger) (*MountedMock, error)
}
MockProvider registers one mock. Each provider reads its own HAMR_* env vars in Build. Adding a new mock is one entry in mockProviders.
type MountedMock ¶
type MountedMock struct {
RegisterAPI func(*http.ServeMux) // app-facing (stripe /v1, mail/sms ingest)
RegisterUI func(*http.ServeMux) // human-facing dashboards
}
MountedMock is what a provider returns: the route registrations for each surface. Either may be nil if a mock has no routes on that surface.
type Option ¶
type Option func(*Runner)
Option configures a Runner.
func WithActionsHook ¶
func WithActionsHook(fn func(*DevActions)) Option
WithActionsHook registers a callback that fires once Run has constructed its DevActions object. The TUI uses this to capture a reference for dispatching actions (e.g. docker wipe) that aren't expressible through the scalar HotkeyAction enum. The hook fires on the runner goroutine; copy the pointer and return — do not block.
func WithConfigPath ¶
WithConfigPath sets the config file path so the runner can watch it for changes.
func WithDockerLogSinks ¶
WithDockerLogSinks subscribes one writer per `[[dev.docker_compose]]` entry to that stack's `docker compose logs -f` output. Keys in the map are the same `name` field hamr.toml uses; entries without a writer are skipped (no follower spawned).
The runner manages follower lifetime: started once an entry has been brought up, restarted automatically if the follower exits early (typically because `docker compose down -v` from a wipe killed it), stopped on shutdown via the runner ctx.
func WithHotkeys ¶
func WithHotkeys(h HotkeySource) Option
WithHotkeys wires the bubbletea-backed HotkeySource that feeds q / r / o into Run's event loop. The TUI runtime owns the source's lifecycle.
func WithLogWriter ¶
WithLogWriter overrides the base writer used by the runner's default slog handler (defaults to os.Stderr). The file logger fan-out, when enabled, remains on top. TUI mode wires this to a viewport-backed sink so the runner's own log lines render inside the TUI instead of corrupting the frame.
func WithMCPLogHook ¶
WithMCPLogHook registers a callback that receives a one-line summary of every MCP request the gateway handles, so the TUI can render a dedicated MCP tab. Fires on the gateway's request goroutine; do not block.
func WithMCPStatusHook ¶
WithMCPStatusHook registers a callback that receives the MCP gateway's state (enabled, exposed-tool count) at startup and on every M-toggle, so the TUI can render its indicator. Fires on the runner goroutine; do not block.
func WithProcessOutput ¶
WithProcessOutput redirects child-process stdout/stderr away from the terminal into the given writers. Internally calls SetOutputSinks on the ProcessManager once it's constructed inside Run. Used by the TUI runtime.
func WithProxyURLHook ¶
WithProxyURLHook registers a callback that fires once the reverse proxy has bound (after any +1-on-busy port walking) so the caller can publish the actual reachable URL to its UI surface. The TUI runtime uses this to push the URL into a bubbletea message. The hook fires on the runner goroutine; copy the string and return — do not block.
type ProcessManager ¶
type ProcessManager struct {
OnProcessExit func(rule string, err error, output string)
// contains filtered or unexported fields
}
ProcessManager handles running one-shot commands and long-running processes.
func NewProcessManager ¶
func NewProcessManager(logger *slog.Logger) *ProcessManager
NewProcessManager creates a new process manager.
func (*ProcessManager) ClearCallbacks ¶
func (pm *ProcessManager) ClearCallbacks()
ClearCallbacks disables all process exit callbacks. Used during shutdown to prevent spurious build_error events.
func (*ProcessManager) RunCommand ¶
RunCommand runs a one-shot command to completion. Stdout and stderr are streamed through the logger, and the captured tail output is returned regardless of exit status (alongside the error on failure) — callers that only care about output on error can ignore it on success, while one-shot tools (e.g. the MCP make.run) can surface it.
func (*ProcessManager) SetFileLog ¶
func (pm *ProcessManager) SetFileLog(w io.Writer)
SetFileLog enables writing prefixed process output to a rolling file logger.
func (*ProcessManager) SetInjectedEnv ¶
func (pm *ProcessManager) SetInjectedEnv(env []string)
SetInjectedEnv configures vars hamr will inject into every spawned rule process. Rule-level Env still overrides on key conflict (last-wins via buildEnv). Used to feed scaffolded apps the mock URLs hamr is hosting (e.g. HAMR_STRIPE_MOCK_URL=http://localhost:3000) so the scaffold's main.go doesn't need to hardcode those URLs and they automatically track hamr.toml's [proxy].listen.
func (*ProcessManager) SetLogOutput ¶
func (pm *ProcessManager) SetLogOutput(buf *LogBuffer, broker *SSEBroker)
SetLogOutput enables streaming process output to a LogBuffer and SSE broker.
func (*ProcessManager) SetOutputSinks ¶
func (pm *ProcessManager) SetOutputSinks(stdout, stderr io.Writer)
SetOutputSinks redirects subprocess stdout/stderr away from the terminal (os.Stdout / os.Stderr) into the given writers. The file logger fan-out configured via SetFileLog is preserved on top. Pass nil writers to clear.
Used by the TUI runtime so child output flows into a bubbletea-managed viewport instead of corrupting the rendered frame.
func (*ProcessManager) StartProcess ¶
func (pm *ProcessManager) StartProcess(ctx context.Context, rule *WatchRule) error
StartProcess starts a long-running process, killing any previous instance. The process is tracked and can be stopped via StopAll.
func (*ProcessManager) StopAll ¶
func (pm *ProcessManager) StopAll()
StopAll gracefully stops all tracked processes.
type ProxyConfig ¶
type ProxyConfig struct {
Listen string `toml:"listen"`
Target string `toml:"target"`
InjectReload *bool `toml:"inject_reload"`
}
ProxyConfig holds the [proxy] table.
type ReloadScope ¶
type ReloadScope string
ReloadScope controls what kind of browser reload a rule triggers. Values: "full", "css", "none", or a boolean (true="full", false="none").
const ( ReloadFull ReloadScope = "full" ReloadCSS ReloadScope = "css" ReloadNone ReloadScope = "none" )
func (*ReloadScope) UnmarshalTOML ¶
func (r *ReloadScope) UnmarshalTOML(data any) error
UnmarshalTOML implements the toml.Unmarshaler interface.
type RequestLog ¶
type RequestLog struct {
// contains filtered or unexported fields
}
RequestLog is a thread-safe ring buffer of recent proxy requests, feeding the MCP http.read tool. It captures every request the proxy serves — proxied app traffic, static assets, the /__hamr/* endpoints, and the SSE/WS streams — which is the view the app's own access log can't give (the app never sees proxy-handled routes, and skips /static).
func NewRequestLog ¶
func NewRequestLog(max int) *RequestLog
NewRequestLog creates a request log capped at max entries.
func (*RequestLog) Record ¶
func (rl *RequestLog) Record(e RequestLogEntry)
Record appends a completed entry, trimming the oldest once over capacity.
func (*RequestLog) Snapshot ¶
func (rl *RequestLog) Snapshot() []RequestLogEntry
Snapshot returns a copy of all buffered entries (oldest first).
type RequestLogEntry ¶
type RequestLogEntry struct {
Time time.Time `json:"time"`
Method string `json:"method"`
Path string `json:"path"`
Status int `json:"status"`
DurationMs int64 `json:"durationMs"`
}
RequestLogEntry is one observed HTTP request through the dev proxy.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner is the top-level dev server orchestrator.
type SMSConfig ¶
type SMSConfig struct {
Enabled bool `toml:"enabled"`
MaxMessages int `toml:"max_messages"` // default 500
Persist *bool `toml:"persist"` // default true
PersistPath string `toml:"persist_path"` // default ".hamr/sms/inbox.jsonl"
}
SMSConfig holds the [dev.sms] table for the SMS mock. When Enabled is true, hamr dev runs an SMS inbox at /__hamr/sms on the reverse proxy. Requires [proxy] to be configured.
Persistence defaults to on: the inbox is mirrored to a JSONL file at PersistPath so it survives hamr dev restart. Set Persist=false for an ephemeral in-memory-only inbox.
func (SMSConfig) PersistEnabled ¶
PersistEnabled returns whether persistence is on. Defaults to true when the field is unset (nil) — matches the email mock's behaviour.
func (SMSConfig) ResolvedPersistPath ¶
ResolvedPersistPath returns PersistPath with the default applied.
type SMSMock ¶
type SMSMock struct {
// contains filtered or unexported fields
}
SMSMock is a dev-only SMS inbox. Messages arrive via /__hamr/sms/ingest (POST JSON), are stored in a ring buffer, and are viewable at /__hamr/sms on the reverse proxy. If persistPath is set, the inbox is mirrored to a JSONL file on disk so it survives hamr dev restart.
func NewSMSMock ¶
func NewSMSMock(opts SMSMockOptions) *SMSMock
NewSMSMock returns an SMSMock with the given options. If PersistPath is non-empty, any existing inbox at that path is loaded and subsequent changes are mirrored there. Load failures are reported via OnPersistError (if set) but never fatal — the in-memory inbox starts empty.
func (*SMSMock) List ¶
func (m *SMSMock) List() []*smsMessage
List returns a newest-first snapshot of the inbox. Messages are copied so callers can read fields without racing concurrent mutators (SetStatus).
func (*SMSMock) RegisterIngestRoutes ¶
RegisterIngestRoutes mounts the capture sink. handleIngest is server-to-server (no browser Origin) — intentionally NOT origin-guarded; see guardUnsafe.
func (*SMSMock) RegisterRoutes ¶
RegisterRoutes mounts both the UI and the ingest endpoint on mux. Do not register twice on the same mux — http.ServeMux panics on duplicate patterns.
func (*SMSMock) RegisterUIRoutes ¶
RegisterUIRoutes mounts the human-facing inbox UI. Split from the ingest sink so the two can live on separate listeners (see `hamr mock-serve`).
func (*SMSMock) SetStatus ¶
SetStatus marks a stored message as having a particular outcome. Used by the UI to simulate post-hoc failure/delay on an already-captured message. Allowed values: "failed", "delayed" ("delivered" is the implicit default set at ingest and cannot be re-applied here). Unknown values are rejected.
Persistence: rewrites the whole JSONL file.
type SMSMockOptions ¶
type SMSMockOptions struct {
MaxMessages int // default 500
PersistPath string // "" disables persistence
OnPersistError func(error) // invoked on disk write/read errors; nil is silent
}
SMSMockOptions configures an SMSMock at construction.
type SSEBroker ¶
type SSEBroker struct {
// contains filtered or unexported fields
}
SSEBroker manages SSE client connections and broadcasts events.
func NewSSEBroker ¶
func NewSSEBroker(rules []WatchRule, daemons []Daemon, dockerCompose []DockerCompose, mailMockEnabled, smsMockEnabled, stripeMockEnabled, consoleCaptureEnabled, darkFilter bool) *SSEBroker
NewSSEBroker creates a new SSE broker. The provided watch rules, daemons, and docker compose entries are serialized once and sent to each client on connect as a "config" event. The mock flags decide which mock-shortcut buttons the dev panel renders. consoleCaptureEnabled toggles the browser-console transport client-side: true tells the injected reload script to patch console + open /__hamr/console; false tells it to do nothing. darkFilter seeds the dark comfort filter state (see SSEBroker.darkFilter).
func (*SSEBroker) Broadcast ¶
Broadcast sends an event to all connected clients. Non-blocking: if a client's buffer is full, the event is dropped for that client.
func (*SSEBroker) ClientCount ¶
ClientCount returns the number of connected SSE clients.
func (*SSEBroker) Handler ¶
func (b *SSEBroker) Handler() http.HandlerFunc
Handler returns an http.HandlerFunc that serves SSE connections.
type SSEEvent ¶
type SSEEvent struct {
Type string // event type (e.g., "reload", "css")
Data string // event data
}
SSEEvent is a server-sent event.
type StringOrSlice ¶
type StringOrSlice []string
StringOrSlice accepts either a single string or a list of strings in TOML.
func (*StringOrSlice) UnmarshalTOML ¶
func (s *StringOrSlice) UnmarshalTOML(data any) error
UnmarshalTOML implements the toml.Unmarshaler interface.
type StripeAccountSummary ¶
type StripeConfig ¶
type StripeConfig struct {
Enabled bool `toml:"enabled"`
WebhookURL string `toml:"webhook_url"` // required when Enabled
WebhookSecret string `toml:"webhook_secret"` // required when Enabled
Persist *bool `toml:"persist"` // default true
PersistPath string `toml:"persist_path"` // default ".hamr/stripe/state.json"
}
StripeConfig holds the [dev.stripe] table for the local Stripe mock. When Enabled is true, hamr dev mounts a Stripe-compatible HTTP backend on the proxy mux at /v1/* so real stripe-go clients can talk to it via stripe.SetBackend(...) pointing at the proxy URL. Requires [proxy] to be configured (the API and dev UI both live on the proxy mux).
The mock is dev-only: no production safeguards. Apps gate by leaving STRIPE_MOCK unset in production so stripe-go reaches api.stripe.com.
Webhook delivery: when an outcome is recorded (paid/failed/cancelled), the mock fires a real signed webhook to WebhookURL with WebhookSecret, exactly as Stripe would. The app's existing webhook handler (using stripe-go's webhook.ConstructEvent) verifies and processes it unchanged.
func (StripeConfig) PersistEnabled ¶
func (c StripeConfig) PersistEnabled() bool
PersistEnabled returns whether persistence is on. Defaults to true when the field is unset (nil) — matches the email mock's behaviour.
func (StripeConfig) ResolvedPersistPath ¶
func (c StripeConfig) ResolvedPersistPath() string
ResolvedPersistPath returns PersistPath with the default applied.
type StripeLineItemSummary ¶
type StripeMock ¶
type StripeMock struct {
// contains filtered or unexported fields
}
StripeMock is a dev-only in-memory Stripe backend. Routes implement enough of /v1/* for stripe-go to round-trip CheckoutSession create/retrieve.
func NewStripeMock ¶
func NewStripeMock(opts StripeMockOptions) *StripeMock
NewStripeMock returns a mock backend, loading any persisted state if PersistPath is set. Load failures are reported via OnPersistError but never fatal — the in-memory state simply starts empty.
All log lines from the mock are prefixed with [hamr:stripe] (via the "component" slog attr that the dev handler interprets as a tag override) so they're distinguishable from the rest of `hamr dev`'s output.
func (*StripeMock) FireEvent ¶
func (m *StripeMock) FireEvent(ctx context.Context, eventType string, dataObject map[string]any) error
FireEvent delivers a signed Stripe webhook to the configured endpoint. The dataObject is the Stripe resource that triggered the event (e.g. a serialized CheckoutSession for a checkout.session.completed event); it is embedded under data.object exactly as Stripe would do.
Returns nil when no endpoint is configured (silent drop). On delivery failure or non-2xx response, returns an error so callers can log/surface. This call is synchronous — for fire-and-forget semantics, wrap in a goroutine.
func (*StripeMock) RegisterAPIRoutes ¶
func (m *StripeMock) RegisterAPIRoutes(mux *http.ServeMux)
RegisterAPIRoutes mounts the Stripe API endpoints on mux. The mux MUST be served at the root of its listener (e.g. on a dedicated stripe-only port) because stripe-go validates that req.URL.Path starts with /v1 and rejects anything served under a sub-path.
POST /v1/checkout/sessions — create session
GET /v1/checkout/sessions/{id} — retrieve session
func (*StripeMock) RegisterRoutes ¶
func (m *StripeMock) RegisterRoutes(mux *http.ServeMux)
RegisterRoutes mounts all Stripe mock endpoints (API + UI) on mux.
func (*StripeMock) RegisterUIRoutes ¶
func (m *StripeMock) RegisterUIRoutes(mux *http.ServeMux)
RegisterUIRoutes mounts the dev-facing checkout page + outcome handler on mux. These routes live on the proxy mux (/__hamr/* namespace), separate from the Stripe-API routes which require a path-free root and run on the dedicated stripe listener.
GET /__hamr/stripe/checkout?session=<id> — pick-an-outcome page POST /__hamr/stripe/complete — record outcome, fire webhook, redirect
func (*StripeMock) SetWebhookEndpoint ¶
func (m *StripeMock) SetWebhookEndpoint(ep WebhookEndpoint)
SetWebhookEndpoint configures the destination + signing secret for events fired via FireEvent. Replaces any previously configured endpoint. An endpoint with empty URL or Secret silently drops events at FireEvent time — useful so callers don't have to gate every fire.
type StripeMockOptions ¶
type StripeMockOptions struct {
// BaseURL is the proxy origin (scheme + host + port) used to build the
// hosted-checkout URL returned in CheckoutSession.URL. Required.
BaseURL string
// Logger receives errors from async webhook fanout. Defaults to slog.Default().
Logger *slog.Logger
// PersistPath enables JSON-file persistence of all in-memory state.
// When set, state is loaded on construction (corrupt/missing files are
// silently tolerated) and the entire state is atomically rewritten on
// every mutation. Empty = in-memory only.
PersistPath string
// OnPersistError is invoked whenever a load or write fails. Typically
// wired to a slog.Warn so dev failures surface in `hamr dev` output.
// Nil = silent.
OnPersistError func(error)
}
StripeMockOptions configures a StripeMock at construction.
type StripeObjectSummary ¶
type StripeSessionSummary ¶
type StripeSessionSummary struct {
ID string `json:"id"`
Status string `json:"status"`
Amount int64 `json:"amount"`
Currency string `json:"currency"`
URL string `json:"url"`
LineItems []StripeLineItemSummary `json:"lineItems,omitempty"`
}
StripeSessionSummary adds the hosted-checkout URL and line items so an agent can verify it's acting on the right session before completing/expiring it.
type StripeStateSummary ¶
type StripeStateSummary struct {
Sessions []StripeSessionSummary `json:"sessions"`
PaymentIntents []StripeObjectSummary `json:"paymentIntents"`
Payouts []StripeObjectSummary `json:"payouts"`
Refunds []StripeObjectSummary `json:"refunds"`
Accounts []StripeAccountSummary `json:"accounts"`
}
StripeStateSummary is the read-only snapshot returned by stripe.list.
type VersionStatus ¶
type VersionStatus int
VersionStatus indicates the CLI-vs-project version state.
const ( VersionOK VersionStatus = iota // versions match or no project version VersionDev // CLI is a dev build VersionMismatch // CLI major.minor differs from project VersionUpdate // newer version available on GitHub )
type WatchRule ¶
type WatchRule struct {
Name string `toml:"name"`
Watch StringOrSlice `toml:"watch"`
Ignore StringOrSlice `toml:"ignore"`
Cmd string `toml:"cmd"`
Run string `toml:"run"`
Dir string `toml:"dir"`
Depends StringOrSlice `toml:"depends"`
Debounce Duration `toml:"debounce"`
Reload ReloadScope `toml:"reload"`
Env []string `toml:"env"`
}
WatchRule defines a single watch/build/run rule.
Dir sets the working directory for cmd and run, relative to the directory hamr dev runs in. It does NOT affect watch/ignore globs — those stay root-relative regardless, so a rule can watch the whole repo while building inside a subdirectory.
type Watcher ¶
type Watcher struct {
// contains filtered or unexported fields
}
Watcher watches the filesystem for changes and emits FileEvents.
func NewWatcher ¶
NewWatcher creates a file watcher for the given rules. root is the base directory to watch (typically ".").
func (*Watcher) Done ¶
func (w *Watcher) Done() <-chan struct{}
Done returns a channel that is closed when the watcher loop exits.
type WebhookEndpoint ¶
WebhookEndpoint is where signed events are delivered. URL is the absolute HTTP(S) URL of the app's webhook handler; Secret is the shared signing secret used to compute the Stripe-Signature header.
Source Files
¶
- actions.go
- composeinspect.go
- composeports.go
- config.go
- configwatch.go
- console.go
- devserver.go
- envinject.go
- errorpage.go
- errorstate.go
- filelog.go
- graph.go
- hotkeys.go
- log.go
- logbuffer.go
- logwriter.go
- mailmock.go
- mailmock_mbox.go
- mailmock_page.go
- makefile.go
- mcpaudit.go
- mcpconfig.go
- mcpgateway.go
- mcpgateway_tools.go
- mcptypes.go
- mockserve.go
- portwalk.go
- process.go
- proxy.go
- requestlog.go
- smsmock.go
- smsmock_page.go
- sse.go
- stripemock.go
- stripemock_account.go
- stripemock_account_page.go
- stripemock_charge.go
- stripemock_clone.go
- stripemock_dashboard.go
- stripemock_form.go
- stripemock_mcp.go
- stripemock_page.go
- stripemock_paymentintent.go
- stripemock_paymentintent_page.go
- stripemock_payout.go
- stripemock_payout_page.go
- stripemock_persist.go
- stripemock_refund.go
- stripemock_webhook.go
- version_status.go
- versioncheck.go
- walks.go
- watcher.go