Shared transport for the three registries: the one settings
resolver (per-call opts first, then context variables, then
defaults), a typed HttpError, JSON GETs, and query-string
building that drops unset values.
| opts key | Context variable | Default |
|---|---|---|
user-agent | company-registry.sec.user-agent | none: SEC calls fail without it |
api-key | company-registry.companies-house.api-key | none: Companies House calls fail without it |
companies-house-base-url | company-registry.companies-house.base-url | https://api.company-information.service.gov.uk |
document-base-url | company-registry.companies-house.document-base-url | https://document-api.company-information.service.gov.uk |
gleif-base-url | company-registry.gleif.base-url | https://api.gleif.org/api/v1 |
sources | company-registry.sources | ["gleif", "sec", "companies-house"] minus any without credentials |
Per-call credentials. api-key and user-agent in opts are
masked in call records and never written to context, so parallel
flows and tenants in one run don't see each other's keys. Present but
blank or null, either one is an error, never a fallback to context. A
per-call companies-house-base-url or document-base-url needs an
api-key in the same opts: the context key is never sent to a
per-call URL. GLEIF takes no credential, so gleif-base-url needs
none.
Context Vars
company-registry.sec.user-agentcompany-registry.companies-house.api-keycompany-registry.companies-house.base-urlcompany-registry.companies-house.document-base-urlcompany-registry.gleif.base-urlcompany-registry.sources
Values
COMPANIES_HOUSE_BASE
COMPANIES_HOUSE_BASE: Str "https://api.company-information.service.gov.uk"
CREDENTIAL_KEYS
CREDENTIAL_KEYS: Vec [
"api-key",
"user-agent"
]
DOCUMENT_BASE
DOCUMENT_BASE: Str "https://document-api.company-information.service.gov.uk"
GLEIF_BASE
GLEIF_BASE: Str "https://api.gleif.org/api/v1"
KEYED_URL_KEYS
KEYED_URL_KEYS: Vec [
"companies-house-base-url",
"document-base-url"
]
PACKAGE_AGENT
PACKAGE_AGENT: Str "hot-dev-company-registry-pkg/0.1 (+https://hot.dev)"
Functions
as-list
fn (v: Any): Vec?
body-detail
fn (body: Any): Str?
columns-to-rows
fn (columns: Map, limit: Int): Vec<Map>
Turn a columnar Map ({a: [1, 2], b: [3, 4]}, as in EDGAR's
filings.recent) into a Vec of row Maps ([{a: 1, b: 3}, {a: 2, b: 4}]), at most limit rows. Columns shorter than the first are
padded with null. Pure.
get-json
fn (source: Str, url: Str, headers: Map): Any
GET a JSON resource and return the decoded body, or an Err carrying HttpError.
get-json-or-null
fn (source: Str, url: Str, headers: Map): Any
get-json, but a 404 gives null (an absent parent, a missing filing) instead of an Err.
given
fn (v: Any): Bool
True for a non-null value that is not a blank string.
http-error
fn (source: Str, response: ::hot::http/HttpResponse, url: Str): HttpError
Build an HttpError from a non-2xx response. Exposed for testing; every request uses it.
is-not-found
fn (e: Any): Bool
True when e is an HttpError with status 404.
path-segment
fn (value: Any): Str
Percent-encode one path segment.
pick
fn (opts: Map, key: Str, ctx-key: Str, default: Any): Any
query-string
fn (params: Map): Str
Build a ?a=1&b=2 suffix from a Map, dropping null and blank values (pure); "" when nothing remains. Keys may contain brackets (filter[fulltext], page[size]) and are encoded.
request
fn (source: Str, method: Str, url: Str, headers: Map): ::hot::http/HttpResponse
GET (or another method) a registry URL with headers, returning the
HttpResponse on 2xx or an Err carrying HttpError. source names
the registry in errors. A transport failure passes through as its
own Err.
require-api-key
fn (cfg: Map): Str
The Companies House API key from resolved settings, or an Err naming where to set it.
require-user-agent
fn (cfg: Map): Str
The SEC User-Agent from resolved settings, or an Err explaining that SEC requires one with contact details.
resolve
fn (opts: Map): Map
Resolve settings for one call: {user-agent, api-key, companies-house-base-url, document-base-url, gleif-base-url, sources}. Values in opts win over context; a credential in opts
is used for that call only and comes back unchanged. An Err when a
credential is in opts but blank or null, or when opts has a
Companies House URL without api-key.
Example
cfg ::company-registry::api/resolve({api-key: tenant.ch-key})
retry-after
fn (headers: Map): Int?
strip-slash
fn (url: Str): Str
Types
HttpError
HttpError type {
source: Str,
status: Int,
url: Str,
headers: Map,
body: Any,
retry-after: Int?,
message: Str
}
A non-2xx registry response. source is "gleif", "sec" or
"companies-house"; url the requested URL (registries take no
credentials in URLs); retry-after the parsed Retry-After seconds
on 429s; message a one-line summary that never includes
credentials.