schema

package
v0.3.1 Latest Latest
Warning

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

Go to latest
Published: May 24, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ActionKindAPICall    = "api_call"
	ActionKindNavigate   = "navigate"
	ActionKindSearch     = "search"
	ActionKindPaginate   = "paginate"
	ActionKindSubmitForm = "submit_form"
)

Action kind constants describe what the agent is trying to do.

View Source
const (
	ActionTransportAPICall      = "api_call"
	ActionTransportHTTPGet      = "http_get"
	ActionTransportHTTPPostForm = "http_post_form"
)

Action transport constants describe how the action is executed.

View Source
const (
	ActionAuthPublicOnly = "public_only"
	ActionSessionNone    = "none"
	ActionSessionCookies = "cookie_jar"
	ActionJSNotRequired  = "not_required"
	ActionJSOptional     = "optional"
)

Action requirement constants are the CANONICAL values for the Auth, Session, and JS fields on ActionRequirements. Schemas SHOULD use these strings where possible so the registry can categorize actions consistently, but the fields are intentionally typed as plain strings (not enums) because real-world sites carry requirement semantics that don't fit a small closed set — "user_session" vs "cookie_jar" vs "api_key" vs "oauth2_bearer" all appear in pushed schemas. Validators may warn on unknown values but must not reject them outright.

View Source
const (
	StrategyCSS       = "css_selector" // default: all fields in one container
	StrategyTableRows = "table_rows"   // table layout: one item spans N <tr> rows
	StrategyNextData  = "next_data"    // Next.js __NEXT_DATA__ SSR payload
)

Extraction strategy constants.

View Source
const (
	SchemaTypeAPI = "api"
	SchemaTypeCSS = "css_selector"

	SchemaCoveragePartial  = "partial"
	SchemaCoverageComplete = "complete"
)

Schema type constants distinguish API schemas from CSS selector schemas.

Variables

This section is empty.

Functions

func ExtractDomain

func ExtractDomain(rawURL string) (string, error)

ExtractDomain extracts the host from a raw URL string.

func GenerateID

func GenerateID(domain, rawPath string) string

GenerateID produces a deterministic ID from domain and raw path. Uses SHA256 of "domain:normalizedPath", returns first 8 bytes hex-encoded.

func NormalizePathStructure

func NormalizePathStructure(path string) string

NormalizePathStructure replaces dynamic URL segments with {} placeholders and strips query strings.

Types

type Action

type Action struct {
	Name string `json:"name"`
	// Purpose is the user-voice one-liner the registry projects onto
	// the public card. Names what the action lets a caller do in a
	// sentence anyone (not just an engineer) could understand. Missing
	// purpose → action doesn't appear on the catalog card (by design —
	// the validator refuses to fabricate one from the paywalled
	// description). Example: "Save a tweet to the authenticated user's
	// drafts. Private — only visible to the signed-in account."
	Purpose     string            `json:"purpose,omitempty"`
	Description string            `json:"description,omitempty"`
	Kind        string            `json:"kind"`
	Transport   string            `json:"transport"`
	Method      string            `json:"method,omitempty"`
	URLTemplate string            `json:"url_template"`
	Headers     map[string]string `json:"headers,omitempty"`
	Params      []ActionParam     `json:"params,omitempty"`
	// BodyTemplate, if non-empty, is used verbatim as the request body
	// after {{var}} substitution. Substituted values are JSON-escaped so
	// user input can't break out of the surrounding JSON string. When
	// empty, the runner synthesizes a body by JSON-marshaling every
	// Param with in="body" — useful for flat APIs, but most real-world
	// endpoints need an explicit template.
	BodyTemplate string             `json:"body_template,omitempty"`
	Result       *ActionResult      `json:"result,omitempty"`
	Requirements ActionRequirements `json:"requirements,omitempty"`
	Confidence   float64            `json:"confidence,omitempty"`
	Source       string             `json:"source,omitempty"`
}

Action describes a browserless, agent-callable website interaction.

type ActionParam

type ActionParam struct {
	Name        string `json:"name"`
	In          string `json:"in"` // path, query, body, form, url
	Type        string `json:"type,omitempty"`
	Required    bool   `json:"required"`
	Default     string `json:"default,omitempty"`
	Description string `json:"description,omitempty"`
}

ActionParam describes one input accepted by an action.

type ActionRequirements

type ActionRequirements struct {
	Auth    string `json:"auth,omitempty"`
	Session string `json:"session,omitempty"`
	JS      string `json:"js,omitempty"`
}

ActionRequirements describes runtime constraints.

type ActionResult

type ActionResult struct {
	EntityType     string          `json:"entity_type,omitempty"`
	Fields         []string        `json:"fields,omitempty"`
	ResponseSchema *ResponseSchema `json:"response_schema,omitempty"`
}

ActionResult describes the shape of data expected back from an action.

type BodyTemplate

type BodyTemplate struct {
	ContentType string `json:"content_type"`
	Template    string `json:"template"`
}

BodyTemplate represents a request body template.

type Endpoint

type Endpoint struct {
	Name string `json:"name"`
	// Purpose is the user-voice one-liner that surfaces on the public
	// catalog card. Describes what data a caller can get from this
	// endpoint in a sentence anyone (not just an engineer) understands.
	// The technical how-to — selectors, parse paths, script-tag ids —
	// goes in Description, which stays paywalled inside the full
	// package. Missing purpose → endpoint is omitted from the public
	// card (the validator will not invent one from Description).
	Purpose         string            `json:"purpose,omitempty"`
	Description     string            `json:"description,omitempty"`
	Method          string            `json:"method"`
	URLTemplate     string            `json:"url_template"`
	Headers         map[string]string `json:"headers"`
	QueryParams     []Param           `json:"query_params,omitempty"`
	Body            *BodyTemplate     `json:"body,omitempty"`
	Variables       []Variable        `json:"variables"`
	IsPrimary       bool              `json:"is_primary"`
	Confidence      float64           `json:"confidence,omitempty"`
	ResponseMapping map[string]string `json:"response_mapping,omitempty"`
	ResponseSchema  *ResponseSchema   `json:"response_schema,omitempty"`
}

Endpoint represents a single API endpoint within a schema.

type EntityField

type EntityField struct {
	Name       string        `json:"name"`
	Selector   string        `json:"selector"`
	Selectors  []string      `json:"selectors,omitempty"`   // ordered fallback selectors
	Attribute  string        `json:"attribute,omitempty"`   // empty = text content
	Type       string        `json:"type"`                  // "string", "number", "list"
	Required   bool          `json:"required,omitempty"`    // triggers re-discovery if empty
	ItemFields []EntityField `json:"item_fields,omitempty"` // for list items
}

EntityField extracts a named piece of data with type information.

type ExtractionField

type ExtractionField struct {
	Name      string `json:"name"`
	Selector  string `json:"selector"`
	Attribute string `json:"attribute,omitempty"` // empty = text content
}

ExtractionField represents a named piece of data to extract using a CSS selector.

type ExtractionRules

type ExtractionRules struct {
	Strategy        string            `json:"strategy,omitempty"` // "css_selector" (default) or "table_rows"
	PageType        string            `json:"page_type"`          // "article", "profile", "product", "listing", "documentation", "generic"
	ContentSelector string            `json:"content_selector"`
	TitleSelector   string            `json:"title_selector,omitempty"`
	AuthorSelector  string            `json:"author_selector,omitempty"`
	DateSelector    string            `json:"date_selector,omitempty"`
	IgnoreSelectors []string          `json:"ignore_selectors,omitempty"`
	Fields          []ExtractionField `json:"fields,omitempty"`
	EntityFields    []EntityField     `json:"entity_fields,omitempty"`   // for css_selector strategy
	TableRows       *TableRowsConfig  `json:"table_rows,omitempty"`      // for table_rows strategy
	NextDataPaths   map[string]string `json:"next_data_paths,omitempty"` // named jq-style paths into __NEXT_DATA__ pageProps
}

ExtractionRules defines CSS selectors for extracting structured content from HTML pages. These rules are discovered by the LLM on first visit and cached so subsequent visits skip the LLM entirely.

func (*ExtractionRules) HasNextDataPaths

func (r *ExtractionRules) HasNextDataPaths() bool

HasNextDataPaths returns true if this extraction has named paths for targeted __NEXT_DATA__ sub-tree extraction.

type FieldSchema

type FieldSchema struct {
	Name   string        `json:"name"`
	Type   string        `json:"type"`             // "string", "number", "boolean", "object", "array", "null"
	Fields []FieldSchema `json:"fields,omitempty"` // for nested objects
	Items  *FieldSchema  `json:"items,omitempty"`  // for arrays: schema of each element
}

FieldSchema describes a single field within a response object.

type Param

type Param struct {
	Key      string `json:"key"`
	Value    string `json:"value"`
	Required bool   `json:"required"`
}

Param represents a query parameter.

type ResponseSchema

type ResponseSchema struct {
	Type   string        `json:"type"`             // "object", "array", "string", "number", "boolean"
	Fields []FieldSchema `json:"fields,omitempty"` // for object type
	Items  *FieldSchema  `json:"items,omitempty"`  // for array type: schema of each element
}

ResponseSchema describes the structure of an endpoint's JSON response. Inferred automatically during validation by sampling the response body.

func InferResponseSchema

func InferResponseSchema(body []byte) *ResponseSchema

InferResponseSchema examines a JSON response body and produces a ResponseSchema describing its structure. Returns nil for invalid JSON.

type Runtime added in v0.1.6

type Runtime struct {
	// BootstrapJS is source code defining a global `bootstrap(input)`
	// function. Runs when the session's cached state is missing or past
	// BootstrapTTLSeconds. Must return an object whose values are all
	// strings — every key becomes a field on the signer's State map.
	BootstrapJS string `json:"bootstrap_js,omitempty"`

	// SignerJS is source code defining a global `sign(input)` function.
	// Runs before each outgoing request. Returns `{url, headers}`: url
	// may be the input URL with extra query parameters appended (e.g.
	// TikTok's X-Bogus); headers are merged onto the request, overriding
	// same-named existing values.
	SignerJS string `json:"signer_js,omitempty"`

	// AllowedHosts restricts hermai.fetch inside BootstrapJS. Exact
	// hostname match, case-insensitive. Required when BootstrapJS calls
	// fetch — an empty list blocks every outbound call.
	AllowedHosts []string `json:"allowed_hosts,omitempty"`

	// BootstrapTTLSeconds is how long bootstrap state stays valid
	// before re-running. Zero means use the CLI default (3600 = 1h).
	// Schemas for sites with aggressive key rotation (TikTok's msToken)
	// should set this low; X is comfortable with an hour.
	BootstrapTTLSeconds int `json:"bootstrap_ttl_seconds,omitempty"`
}

Runtime describes the JavaScript the CLI runs to (a) bootstrap per-session state like animation keys and (b) sign each outgoing request. Both are optional — sites with no anti-bot signing (most GET schemas) don't need a Runtime at all.

The CLI's sandbox executes this JS in goja (see pkg/signer). Bootstrap JS gets fetch + HTML parsing capabilities gated by AllowedHosts; signer JS is a pure function of the per-request input plus the state bootstrap produced.

This type was added when we pivoted from compiled-in per-site bootstrap code to schema-resident JS: new Path-1 sites now ship as schemas rather than CLI releases.

func (*Runtime) NeedsBootstrap added in v0.1.6

func (r *Runtime) NeedsBootstrap() bool

NeedsBootstrap reports whether the runtime has bootstrap JS to run.

func (*Runtime) NeedsSigner added in v0.1.6

func (r *Runtime) NeedsSigner() bool

NeedsSigner reports whether the runtime has a per-request signer.

type Schema

type Schema struct {
	ID string `json:"id"`
	// Site is the canonical domain key the registry validator reads.
	// Set this on every new schema. Domain is retained for backward
	// compatibility with pre-2026-04 schemas that used it as the site
	// key, but any new code should populate Site. The hermai-api
	// validator accepts either and normalizes to Site.
	Site            string           `json:"site,omitempty"`
	Domain          string           `json:"domain,omitempty"`
	URLPattern      string           `json:"url_pattern"`
	SchemaType      string           `json:"schema_type,omitempty"` // "api" or "css_selector"
	Coverage        string           `json:"coverage,omitempty"`    // partial or complete
	Version         int              `json:"version"`
	CreatedAt       time.Time        `json:"created_at"`
	DiscoveredFrom  string           `json:"discovered_from"`
	Endpoints       []Endpoint       `json:"endpoints"`
	Actions         []Action         `json:"actions,omitempty"`
	ExtractionRules *ExtractionRules `json:"extraction_rules,omitempty"`
	Session         *SessionConfig   `json:"session,omitempty"`
	Runtime         *Runtime         `json:"runtime,omitempty"`
	RequiresStealth bool             `json:"requires_stealth,omitempty"`
}

Schema represents a discovered API schema for a domain's URL pattern.

func FromExtractionRules

func FromExtractionRules(targetURL string, rules *ExtractionRules) *Schema

FromExtractionRules creates a Schema from extraction rules and a target URL. The schema ID is generated from the domain and URL path pattern.

func FromJSON

func FromJSON(data []byte) (*Schema, error)

FromJSON deserializes JSON bytes into a Schema.

func FromNextData

func FromNextData(targetURL string) *Schema

FromNextData creates a Schema recording that a URL uses Next.js __NEXT_DATA__ for structured data. The extraction is deterministic — no CSS selectors or LLM analysis needed — so only the strategy is stored.

func FromNextDataWithPaths

func FromNextDataWithPaths(targetURL string, paths map[string]string) *Schema

FromNextDataWithPaths creates a __NEXT_DATA__ schema with named extraction paths. Each key in paths is a human-readable alias (e.g. "products"), and each value is a dot-path into pageProps (e.g. ".ssrQuery.hits"). When paths are present, extraction returns only the targeted sub-trees instead of the full pageProps blob.

URL pattern: Next.js pages under the same section share identical __NEXT_DATA__ key structures, so we wildcard all segments after the first one. E.g. /collections/all-products/mens → /collections/{}/{}. This lets one cached schema serve /collections/shorts/mens, /collections/all/womens, etc.

func MatchURL

func MatchURL(rawURL string, schemas []Schema) *Schema

MatchURL finds the best matching schema for a given URL. It normalizes the input URL path, then matches against each schema's URLPattern. Returns the most specific match, or nil if no schema matches.

func MergeAPISchemas

func MergeAPISchemas(existing, incoming *Schema) *Schema

MergeAPISchemas combines two API schemas for the same route family. Existing schema identity is preserved so cache upgrades overwrite in place.

func (Schema) IsAPISchema

func (s Schema) IsAPISchema() bool

IsAPISchema returns true if this schema contains API endpoints. Handles legacy schemas without SchemaType by checking Endpoints.

func (Schema) IsCSSSchema

func (s Schema) IsCSSSchema() bool

IsCSSSchema returns true if this schema contains CSS extraction rules.

func (Schema) IsHTMLExtraction

func (s Schema) IsHTMLExtraction() bool

IsHTMLExtraction returns true if this schema uses HTML content extraction (CSS selectors, table rows, or __NEXT_DATA__) rather than API endpoints.

func (Schema) IsNextDataSchema

func (s Schema) IsNextDataSchema() bool

IsNextDataSchema returns true if this schema uses __NEXT_DATA__ extraction from Next.js SSR pages.

func (Schema) ToJSON

func (s Schema) ToJSON() ([]byte, error)

ToJSON serializes the schema to indented JSON bytes.

type SessionConfig

type SessionConfig struct {
	// BootstrapURL is hit before data fetches to obtain session cookies/tokens.
	BootstrapURL    string `json:"bootstrap_url"`
	BootstrapMethod string `json:"bootstrap_method"` // GET or POST
	// CaptureHeaders lists response headers to extract and forward (e.g. X-CSRF-Token).
	CaptureHeaders []string `json:"capture_headers,omitempty"`
	// CaptureCookies lists cookie names to extract from Set-Cookie and forward.
	CaptureCookies []string `json:"capture_cookies,omitempty"`
	// StaticHeaders are fixed headers that don't change between sessions.
	StaticHeaders map[string]string `json:"static_headers,omitempty"`
	// ClearanceCookies are cookies obtained from a browser-based anti-bot
	// challenge solve. Persisted so subsequent requests can skip the browser.
	ClearanceCookies map[string]string `json:"clearance_cookies,omitempty"`
}

SessionConfig describes how to bootstrap a session before fetching data. Some APIs require cookies or tokens obtained from an initial page load. The fetcher hits the BootstrapURL first, extracts the specified cookies and headers, then carries them into subsequent data API calls.

type TableRowField

type TableRowField struct {
	Name      string `json:"name"`
	Row       int    `json:"row"` // 0-indexed row within the group
	Selector  string `json:"selector"`
	Attribute string `json:"attribute,omitempty"` // empty = text content
	Type      string `json:"type,omitempty"`      // "string" (default), "number"
	Required  bool   `json:"required,omitempty"`
}

TableRowField extracts a value from a specific row within a row group.

type TableRowsConfig

type TableRowsConfig struct {
	Container string          `json:"container"`  // CSS selector for the <table> or <tbody>
	GroupSize int             `json:"group_size"` // number of <tr> rows per logical item
	Fields    []TableRowField `json:"fields"`     // which row + selector for each field
}

TableRowsConfig defines extraction for table-based layouts where one logical item spans multiple consecutive <tr> rows.

type Variable

type Variable struct {
	Name    string `json:"name"`
	Source  string `json:"source"`
	Pattern string `json:"pattern"`
}

Variable represents a dynamic variable in a URL template.

Jump to

Keyboard shortcuts

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