Documentation
¶
Index ¶
- Constants
- func ExtractDomain(rawURL string) (string, error)
- func GenerateID(domain, rawPath string) string
- func NormalizePathStructure(path string) string
- type Action
- type ActionParam
- type ActionRequirements
- type ActionResult
- type BodyTemplate
- type Endpoint
- type EntityField
- type ExtractionField
- type ExtractionRules
- type FieldSchema
- type Param
- type ResponseSchema
- type Runtime
- type Schema
- func FromExtractionRules(targetURL string, rules *ExtractionRules) *Schema
- func FromJSON(data []byte) (*Schema, error)
- func FromNextData(targetURL string) *Schema
- func FromNextDataWithPaths(targetURL string, paths map[string]string) *Schema
- func MatchURL(rawURL string, schemas []Schema) *Schema
- func MergeAPISchemas(existing, incoming *Schema) *Schema
- type SessionConfig
- type TableRowField
- type TableRowsConfig
- type Variable
Constants ¶
const ( ActionKindAPICall = "api_call" ActionKindSearch = "search" ActionKindPaginate = "paginate" ActionKindSubmitForm = "submit_form" )
Action kind constants describe what the agent is trying to do.
const ( ActionTransportAPICall = "api_call" ActionTransportHTTPGet = "http_get" ActionTransportHTTPPostForm = "http_post_form" )
Action transport constants describe how the action is executed.
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.
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.
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 ¶
ExtractDomain extracts the host from a raw URL string.
func GenerateID ¶
GenerateID produces a deterministic ID from domain and raw path. Uses SHA256 of "domain:normalizedPath", returns first 8 bytes hex-encoded.
func NormalizePathStructure ¶
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
NeedsBootstrap reports whether the runtime has bootstrap JS to run.
func (*Runtime) NeedsSigner ¶ added in v0.1.6
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 FromNextData ¶
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 ¶
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 ¶
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 ¶
MergeAPISchemas combines two API schemas for the same route family. Existing schema identity is preserved so cache upgrades overwrite in place.
func (Schema) IsAPISchema ¶
IsAPISchema returns true if this schema contains API endpoints. Handles legacy schemas without SchemaType by checking Endpoints.
func (Schema) IsCSSSchema ¶
IsCSSSchema returns true if this schema contains CSS extraction rules.
func (Schema) IsHTMLExtraction ¶
IsHTMLExtraction returns true if this schema uses HTML content extraction (CSS selectors, table rows, or __NEXT_DATA__) rather than API endpoints.
func (Schema) IsNextDataSchema ¶
IsNextDataSchema returns true if this schema uses __NEXT_DATA__ extraction from Next.js SSR pages.
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.