builder

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package builder turns a structured payload into the raw string that gets encoded into a code, and parses that string back.

A Builder is the layer above the encoder: the encoder knows how to draw modules for a string, the builder knows that a Wi-Fi credential is spelled "WIFI:T:WPA;S:home;P:hunter2;;" and that the semicolon inside an SSID has to be escaped. Builders are registered by name in an init function and looked up through the registry, never through a switch in a caller, so adding a payload type is one new file plus one Register call.

Two invariants hold for every builder in this package:

  • Build is a pure function of its payload. No clock, no randomness, no network. The same payload always produces byte-identical output, which is what makes caching and the round-trip test possible.
  • Parse(Build(p)) recovers a payload that rebuilds to the same string. Parse is deliberately strict: it reports ok=false for anything that is not of its own form, so a caller can try every builder in turn to classify a scanned code.

Payloads arrive as any, in practice a map[string]any decoded from a JSON body or from query parameters, or one of the exported payload structs in this package. Both forms go through toMap, so a builder only ever sees a map, and unknown keys are rejected with a suggestion rather than silently ignored — a typo in "sbuject" must not produce a code missing its subject.

Index

Constants

View Source
const (
	// TypeString is a text field.
	TypeString = "string"
	// TypeBool is a boolean field; strings such as "true" are coerced.
	TypeBool = "bool"
	// TypeNumber is a numeric field; numeric strings are coerced.
	TypeNumber = "number"
)

Field value types, used in Field.Type.

View Source
const App = "app"

App is the registry name of the app-store-link builder.

View Source
const Bookmark = "bookmark"

Bookmark is the registry name of the MEBKM bookmark builder.

View Source
const Crypto = "crypto"

Crypto is the registry name of the cryptocurrency-payment builder.

View Source
const EPC = "epc"

EPC is the registry name of the SEPA credit-transfer builder.

View Source
const Email = "email"

Email is the registry name of the mailto builder.

View Source
const Event = "event"

Event is the registry name of the calendar-event builder.

View Source
const Geo = "geo"

Geo is the registry name of the geographic-location builder.

View Source
const Location = "location"

Location is the registry name of the Google Maps location builder.

View Source
const MeCard = "mecard"

MeCard is the registry name of the MECARD contact builder.

View Source
const OTP = "otp"

OTP is the registry name of the one-time-password builder.

View Source
const Raw = "raw"

Raw is the registry name of the unvalidated passthrough builder.

View Source
const SMS = "sms"

SMS is the registry name of the text-message builder.

View Source
const Tel = "tel"

Tel is the registry name of the telephone builder.

View Source
const Text = "text"

Text is the registry name of the plain-text builder.

View Source
const URL = "url"

URL is the registry name of the URL builder.

View Source
const VCard = "vcard"

VCard is the registry name of the contact-card builder.

View Source
const WhatsApp = "whatsapp"

WhatsApp is the registry name of the WhatsApp builder.

View Source
const WiFi = "wifi"

WiFi is the registry name of the Wi-Fi credential builder.

Variables

View Source
var (
	// ErrUnknownType means no builder is registered under that name.
	ErrUnknownType = errors.New("unknown payload type")
	// ErrInvalidPayload means the payload is structurally wrong for this
	// builder: an unknown field, a value of the wrong type, or a value that
	// violates the format's rules.
	ErrInvalidPayload = errors.New("payload invalid for this type")
	// ErrMissingField means a field the format requires was absent or empty.
	ErrMissingField = errors.New("required field missing")
)

Sentinel errors. The HTTP layer maps these onto stable error codes, so a caller can switch on the code rather than on message text.

Functions

func Names

func Names() []string

Names lists every registered payload type, sorted.

func Register

func Register(b Builder)

Register adds a builder under its own name. It panics on a duplicate, because two builders claiming one payload type is a programming error that must surface at startup rather than resolve arbitrarily.

Register is intended for init functions.

Types

type AppPayload

type AppPayload struct {
	Platform       string `json:"platform"`
	IOSID          string `json:"ios_id"`
	AndroidPackage string `json:"android_package"`
}

AppPayload carries a link to an application listing.

type BookmarkPayload

type BookmarkPayload struct {
	Title string `json:"title"`
	URL   string `json:"url"`
}

BookmarkPayload carries a titled link.

type Builder

type Builder interface {
	// Name is the registry key.
	Name() string
	// Build renders the payload as the raw string to encode.
	Build(payload any) (string, error)
	// Parse recovers a payload from a raw string. ok is false when the string
	// is not of this builder's form.
	Parse(raw string) (payload any, ok bool)
	// Fields describes the accepted payload fields, for /v1/build docs and
	// validation.
	Fields() []Field
}

Builder converts a structured payload to and from the raw string encoded into a code.

Implementations must be safe for concurrent use: one instance is shared across every request and holds no per-build state.

func All

func All() []Builder

All returns every registered builder, sorted by name. It backs GET /v1/build and the package-wide round-trip test, which is what catches a new builder added without one.

func Get

func Get(name string) (Builder, error)

Get returns the builder registered under name.

type CryptoPayload

type CryptoPayload struct {
	Coin    string  `json:"coin"`
	Address string  `json:"address"`
	Amount  float64 `json:"amount"`
	Label   string  `json:"label"`
	Message string  `json:"message"`
}

CryptoPayload carries a payment request.

type Describer

type Describer interface {
	// Describe reports what the builder made of the payload. The map is
	// serialised straight to JSON, so its keys are part of the API.
	Describe(payload any) (map[string]any, error)
}

Describer is an optional interface a Builder may implement to report what it understood about a payload, beyond the string it produced.

Most builders have nothing to add: a vCard is a vCard, and the payload the caller sent is the whole story. It exists for the builders that *detect* something — `location` infers whether it was handed an address, a coordinate pair, a plus code, or somebody else's map link, and a caller acting on that answer needs to see it and how confident the guess was.

The HTTP layer includes the result in GET /v1/build/{type} when a builder implements it, and omits the field entirely when it does not.

type EPCPayload

type EPCPayload struct {
	BIC         string  `json:"bic"`
	Name        string  `json:"name"`
	IBAN        string  `json:"iban"`
	Amount      float64 `json:"amount"`
	Purpose     string  `json:"purpose"`
	Reference   string  `json:"reference"`
	Remittance  string  `json:"remittance"`
	Information string  `json:"information"`
}

EPCPayload carries a SEPA credit transfer request.

type EmailPayload

type EmailPayload struct {
	Email   string `json:"email"`
	Subject string `json:"subject"`
	Body    string `json:"body"`
}

EmailPayload carries a pre-addressed message.

type EventPayload

type EventPayload struct {
	Summary     string `json:"summary"`
	Start       string `json:"start"`
	End         string `json:"end"`
	Location    string `json:"location"`
	Description string `json:"description"`
}

EventPayload carries a calendar event.

type Field

type Field struct {
	// Name is the payload key, snake_case to match both JSON bodies and
	// query parameters.
	Name string `json:"name"`
	// Type is the accepted value type: string, bool, or number. Query
	// parameters arrive as strings and are coerced, so "bool" also accepts
	// "true"/"false".
	Type string `json:"type"`
	// Description is one line of prose for the API docs.
	Description string `json:"description"`
	// Required reports whether Build fails without this field.
	Required bool `json:"required"`
	// Example is a value that is valid on its own and valid alongside every
	// other field's Example. It is empty for a field that conflicts with
	// another field's example, which is why the docs carry the sample in the
	// description instead.
	Example string `json:"example,omitempty"`
}

Field describes one accepted payload field. The slice a builder returns from Fields is what /v1/build serves as documentation and what validation uses to reject unknown keys, so the two can never drift apart.

type GeoPayload

type GeoPayload struct {
	Latitude  float64 `json:"latitude"`
	Longitude float64 `json:"longitude"`
	Altitude  float64 `json:"altitude"`
	Query     string  `json:"query"`
}

GeoPayload carries a point on the earth.

type LocationPayload

type LocationPayload struct {
	Location string `json:"location"`
	Origin   string `json:"origin"`
	Mode     string `json:"mode"`
	Zoom     int    `json:"zoom"`
	Language string `json:"language"`
	Region   string `json:"region"`
}

LocationPayload carries a place to open in Google Maps.

type MeCardPayload

type MeCardPayload struct {
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"`
	Phone       string `json:"phone"`
	PhoneRegion string `json:"phone_region"`
	Email       string `json:"email"`
	URL         string `json:"url"`
	Address     string `json:"address"`
	Note        string `json:"note"`
}

MeCardPayload carries a compact contact card.

type OTPPayload

type OTPPayload struct {
	Type      string  `json:"type"`
	Issuer    string  `json:"issuer"`
	Account   string  `json:"account"`
	Secret    string  `json:"secret"`
	Algorithm string  `json:"algorithm"`
	Digits    float64 `json:"digits"`
	Period    float64 `json:"period"`
	Counter   float64 `json:"counter"`
}

OTPPayload carries an authenticator enrolment.

The secret is the whole credential: anyone who reads it can generate codes for the account forever. It must never reach a log, a metric label, or an error message, which is why this type has a String method.

func (OTPPayload) String

func (p OTPPayload) String() string

String renders the payload with the secret redacted.

type RawPayload

type RawPayload struct {
	Data string `json:"data"`
}

RawPayload carries bytes that are already in their final form.

type SMSPayload

type SMSPayload struct {
	Phone   string `json:"phone"`
	Message string `json:"message"`
}

SMSPayload carries a pre-addressed text message.

type TelPayload

type TelPayload struct {
	Phone       string `json:"phone"`
	PhoneRegion string `json:"phone_region"`
}

TelPayload carries a telephone number.

type TextPayload

type TextPayload struct {
	Text string `json:"text"`
}

TextPayload carries free-form text.

type URLPayload

type URLPayload struct {
	URL      string `json:"url"`
	AllowAny bool   `json:"allow_any"`
}

URLPayload carries a link.

type VCardPayload

type VCardPayload struct {
	FirstName   string `json:"first_name"`
	LastName    string `json:"last_name"`
	Org         string `json:"org"`
	Title       string `json:"title"`
	Phone       string `json:"phone"`
	PhoneRegion string `json:"phone_region"`
	Mobile      string `json:"mobile"`
	Email       string `json:"email"`
	URL         string `json:"url"`
	Street      string `json:"street"`
	City        string `json:"city"`
	Region      string `json:"region"`
	PostalCode  string `json:"postal_code"`
	Country     string `json:"country"`
	Note        string `json:"note"`
}

VCardPayload carries a contact card.

type WhatsAppPayload

type WhatsAppPayload struct {
	Phone       string `json:"phone"`
	PhoneRegion string `json:"phone_region"`
	Message     string `json:"message"`
}

WhatsAppPayload carries a WhatsApp click-to-chat link.

type WiFiPayload

type WiFiPayload struct {
	SSID     string `json:"ssid"`
	Password string `json:"password"`
	Auth     string `json:"auth"`
	Hidden   bool   `json:"hidden"`
}

WiFiPayload carries a Wi-Fi network credential.

The password is a secret. It must never reach a log, a metric label, or an error message, which is why this type has a String method: a stray %v on the struct prints the redaction rather than the key to the network.

func (WiFiPayload) String

func (p WiFiPayload) String() string

String renders the payload with the password redacted.

Jump to

Keyboard shortcuts

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