// NOTE: GENERATED by github.com/mjl-/sherpats, DO NOT MODIFY

namespace api {

// CheckResult is the analysis of a domain, its actual configuration (DNS, TLS,
// connectivity) and the mox configuration. It includes configuration instructions
// (e.g. DNS records), and warnings and errors encountered.
export interface CheckResult {
	Domain: string
	DNSSEC: DNSSECResult
	IPRev: IPRevCheckResult
	MX: MXCheckResult
	TLS: TLSCheckResult
	DANE: DANECheckResult
	SPF: SPFCheckResult
	DKIM: DKIMCheckResult
	DMARC: DMARCCheckResult
	HostTLSRPT: TLSRPTCheckResult
	DomainTLSRPT: TLSRPTCheckResult
	MTASTS: MTASTSCheckResult
	SRVConf: SRVConfCheckResult
	Autoconf: AutoconfCheckResult
	Autodiscover: AutodiscoverCheckResult
}

export interface DNSSECResult {
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface IPRevCheckResult {
	Hostname: Domain  // This hostname, IPs must resolve back to this.
	IPNames?: { [key: string]: string[] | null }  // IP to names.
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

// Domain is a domain name, with one or more labels, with at least an ASCII
// representation, and for IDNA non-ASCII domains a unicode representation.
// The ASCII string must be used for DNS lookups. The strings do not have a
// trailing dot. When using with StrictResolver, add the trailing dot.
export interface Domain {
	ASCII: string  // A non-unicode domain, e.g. with A-labels (xn--...) or NR-LDH (non-reserved letters/digits/hyphens) labels. Always in lower case. No trailing dot.
	Unicode: string  // Name as U-labels. Empty if this is an ASCII-only domain. No trailing dot.
}

export interface MXCheckResult {
	Records?: MX[] | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface MX {
	Host: string
	Pref: number
	IPs?: string[] | null
}

export interface TLSCheckResult {
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface DANECheckResult {
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface SPFCheckResult {
	DomainTXT: string
	DomainRecord?: SPFRecord | null
	HostTXT: string
	HostRecord?: SPFRecord | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface SPFRecord {
	Version: string  // Must be "spf1".
	Directives?: Directive[] | null  // An IP is evaluated against each directive until a match is found.
	Redirect: string  // Modifier that redirects SPF checks to other domain after directives did not match. Optional. For "redirect=".
	Explanation: string  // Modifier for creating a user-friendly error message when an IP results in status "fail".
	Other?: Modifier[] | null  // Other modifiers.
}

// Directive consists of a mechanism that describes how to check if an IP matches,
// an (optional) qualifier indicating the policy for a match, and optional
// parameters specific to the mechanism.
export interface Directive {
	Qualifier: string  // Sets the result if this directive matches. "" and "+" are "pass", "-" is "fail", "?" is "neutral", "~" is "softfail".
	Mechanism: string  // "all", "include", "a", "mx", "ptr", "ip4", "ip6", "exists".
	DomainSpec: string  // For include, a, mx, ptr, exists. Always in lower-case when parsed using ParseRecord.
	IPstr: string  // Original string for IP, always with /subnet.
	IP4CIDRLen?: number | null  // For a, mx, ip4.
	IP6CIDRLen?: number | null  // For a, mx, ip6.
}

// Modifier provides additional information for a policy.
// "redirect" and "exp" are not represented as a Modifier but explicitly in a Record.
export interface Modifier {
	Key: string  // Key is case-insensitive.
	Value: string
}

export interface DKIMCheckResult {
	Records?: DKIMRecord[] | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface DKIMRecord {
	Selector: string
	TXT: string
	Record?: Record | null
}

// Record is a DKIM DNS record, served on <selector>._domainkey.<domain> for a
// given selector and domain (s= and d= in the DKIM-Signature).
// 
// The record is a semicolon-separated list of "="-separated field value pairs.
// Strings should be compared case-insensitively, e.g. k=ed25519 is equivalent to k=ED25519.
// 
// Example:
// 
// 	v=DKIM1;h=sha256;k=ed25519;p=ln5zd/JEX4Jy60WAhUOv33IYm2YZMyTQAdr9stML504=
export interface Record {
	Version: string  // Version, fixed "DKIM1" (case sensitive). Field "v".
	Hashes?: string[] | null  // Acceptable hash algorithms, e.g. "sha1", "sha256". Optional, defaults to all algorithms. Field "h".
	Key: string  // Key type, "rsa" or "ed25519". Optional, default "rsa". Field "k".
	Notes: string  // Debug notes. Field "n".
	Pubkey?: string | null  // Public key, as base64 in record. If empty, the key has been revoked. Field "p".
	Services?: string[] | null  // Service types. Optional, default "*" for all services. Other values: "email". Field "s".
	Flags?: string[] | null  // Flags, colon-separated. Optional, default is no flags. Other values: "y" for testing DKIM, "s" for "i=" must have same domain as "d" in signatures. Field "t".
}

export interface DMARCCheckResult {
	Domain: string
	TXT: string
	Record?: DMARCRecord | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface DMARCRecord {
	Version: string  // "v=DMARC1", fixed.
	Policy: DMARCPolicy  // Required, for "p=".
	SubdomainPolicy: DMARCPolicy  // Like policy but for subdomains. Optional, for "sp=".
	AggregateReportAddresses?: URI[] | null  // Optional, for "rua=". Destination addresses for aggregate reports.
	FailureReportAddresses?: URI[] | null  // Optional, for "ruf=". Destination addresses for failure reports.
	ADKIM: Align  // Alignment: "r" (default) for relaxed or "s" for simple. For "adkim=".
	ASPF: Align  // Alignment: "r" (default) for relaxed or "s" for simple. For "aspf=".
	AggregateReportingInterval: number  // In seconds, default 86400. For "ri="
	FailureReportingOptions?: string[] | null  // "0" (default), "1", "d", "s". For "fo=".
	ReportingFormat?: string[] | null  // "afrf" (default). For "rf=".
	Percentage: number  // Between 0 and 100, default 100. For "pct=". Policy applies randomly to this percentage of messages.
}

// URI is a destination address for reporting.
export interface URI {
	Address: string  // Should start with "mailto:".
	MaxSize: number  // Optional maximum message size, subject to Unit.
	Unit: string  // "" (b), "k", "m", "g", "t" (case insensitive), unit size, where k is 2^10 etc.
}

export interface TLSRPTCheckResult {
	TXT: string
	Record?: TLSRPTRecord | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface TLSRPTRecord {
	Version: string  // "TLSRPTv1", for "v=".
	RUAs?: (RUA[] | null)[] | null  // Aggregate reporting URI, for "rua=". "rua=" can occur multiple times, each can be a list.
	Extensions?: Extension[] | null
}

// Extension is an additional key/value pair for a TLSRPT record.
export interface Extension {
	Key: string
	Value: string
}

export interface MTASTSCheckResult {
	TXT: string
	Record?: MTASTSRecord | null
	PolicyText: string
	Policy?: Policy | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface MTASTSRecord {
	Version: string  // "STSv1", for "v=". Required.
	ID: string  // Record version, for "id=". Required.
	Extensions?: Pair[] | null  // Optional extensions.
}

// Pair is an extension key/value pair in a MTA-STS DNS record or policy.
export interface Pair {
	Key: string
	Value: string
}

// Policy is an MTA-STS policy as served at "https://mta-sts.<domain>/.well-known/mta-sts.txt".
export interface Policy {
	Version: string  // "STSv1"
	Mode: Mode
	MX?: STSMX[] | null
	MaxAgeSeconds: number  // How long this policy can be cached. Suggested values are in weeks or more.
	Extensions?: Pair[] | null
}

// STSMX is an allowlisted MX host name/pattern.
// todo: find a way to name this just STSMX without getting duplicate names for "MX" in the sherpa api.
export interface STSMX {
	Wildcard: boolean  // "*." wildcard, e.g. if a subdomain matches. A wildcard must match exactly one label. *.example.com matches mail.example.com, but not example.com, and not foor.bar.example.com.
	Domain: Domain
}

export interface SRVConfCheckResult {
	SRVs?: { [key: string]: SRV[] | null }  // Service (e.g. "_imaps") to records.
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

// An SRV represents a single DNS SRV record.
export interface SRV {
	Target: string
	Port: number
	Priority: number
	Weight: number
}

export interface AutoconfCheckResult {
	ClientSettingsDomainIPs?: string[] | null
	IPs?: string[] | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface AutodiscoverCheckResult {
	Records?: AutodiscoverSRV[] | null
	Errors?: string[] | null
	Warnings?: string[] | null
	Instructions?: string[] | null
}

export interface AutodiscoverSRV {
	Target: string
	Port: number
	Priority: number
	Weight: number
	IPs?: string[] | null
}

// PolicyRecord is a cached policy or absence of a policy.
export interface PolicyRecord {
	Domain: string  // Domain name, with unicode characters.
	Inserted: Date
	ValidEnd: Date
	LastUpdate: Date  // Policies are refreshed on use and periodically.
	LastUse: Date
	Backoff: boolean
	RecordID: string  // As retrieved from DNS.
	Version: string  // "STSv1"
	Mode: Mode
	MX?: STSMX[] | null
	MaxAgeSeconds: number  // How long this policy can be cached. Suggested values are in weeks or more.
	Extensions?: Pair[] | null
	PolicyText: string  // Text that make up the policy, as retrieved. We didn't store this in the past. If empty, policy can be reconstructed from Policy field. Needed by TLSRPT.
}

// TLSReportRecord is a TLS report as a database record, including information
// about the sender.
// 
// todo: should be named just Record, but it would cause a sherpa type name conflict.
export interface TLSReportRecord {
	ID: number
	Domain: string  // Policy domain to which the TLS report applies. Unicode.
	FromDomain: string
	MailFrom: string
	HostReport: boolean  // Report for host TLSRPT record, as opposed to domain TLSRPT record.
	Report: Report
}

// Report is a TLSRPT report.
export interface Report {
	OrganizationName: string
	DateRange: TLSRPTDateRange
	ContactInfo: string
	ReportID: string
	Policies?: Result[] | null
}

// note: with TLSRPT prefix to prevent clash in sherpadoc types.
export interface TLSRPTDateRange {
	Start: Date
	End: Date
}

export interface Result {
	Policy: ResultPolicy
	Summary: Summary
	FailureDetails?: FailureDetails[] | null
}

export interface ResultPolicy {
	Type: PolicyType
	String?: string[] | null
	Domain: string  // ASCII/A-labels, ../rfc/8460:704
	MXHost?: string[] | null
}

export interface Summary {
	TotalSuccessfulSessionCount: number
	TotalFailureSessionCount: number
}

export interface FailureDetails {
	ResultType: ResultType
	SendingMTAIP: string
	ReceivingMXHostname: string
	ReceivingMXHelo: string
	ReceivingIP: string
	FailedSessionCount: number
	AdditionalInformation: string
	FailureReasonCode: string
}

// TLSRPTSummary presents TLS reporting statistics for a single domain
// over a period.
export interface TLSRPTSummary {
	PolicyDomain: Domain
	Success: number
	Failure: number
	ResultTypeCounts?: { [key: string]: number }
}

// DomainFeedback is a single report stored in the database.
export interface DomainFeedback {
	ID: number
	Domain: string  // Domain where DMARC DNS record was found, could be organizational domain.
	FromDomain: string  // Domain in From-header.
	Version: string
	ReportMetadata: ReportMetadata
	PolicyPublished: PolicyPublished
	Records?: ReportRecord[] | null
}

export interface ReportMetadata {
	OrgName: string
	Email: string
	ExtraContactInfo: string
	ReportID: string
	DateRange: DateRange
	Errors?: string[] | null
}

export interface DateRange {
	Begin: number
	End: number
}

// PolicyPublished is the policy as found in DNS for the domain.
export interface PolicyPublished {
	Domain: string  // Domain is where DMARC record was found, not necessarily message From. Reports we generate use unicode names, incoming reports may have either ASCII-only or Unicode domains.
	ADKIM: Alignment
	ASPF: Alignment
	Policy: Disposition
	SubdomainPolicy: Disposition
	Percentage: number
	ReportingOptions: string
}

export interface ReportRecord {
	Row: Row
	Identifiers: Identifiers
	AuthResults: AuthResults
}

export interface Row {
	SourceIP: string  // SourceIP must match the pattern ((1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]).){3} (1?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])| ([A-Fa-f0-9]{1,4}:){7}[A-Fa-f0-9]{1,4}
	Count: number
	PolicyEvaluated: PolicyEvaluated
}

export interface PolicyEvaluated {
	Disposition: Disposition
	DKIM: DMARCResult
	SPF: DMARCResult
	Reasons?: PolicyOverrideReason[] | null
}

export interface PolicyOverrideReason {
	Type: PolicyOverride
	Comment: string
}

export interface Identifiers {
	EnvelopeTo: string
	EnvelopeFrom: string
	HeaderFrom: string
}

export interface AuthResults {
	DKIM?: DKIMAuthResult[] | null
	SPF?: SPFAuthResult[] | null
}

export interface DKIMAuthResult {
	Domain: string
	Selector: string
	Result: DKIMResult
	HumanResult: string
}

export interface SPFAuthResult {
	Domain: string
	Scope: SPFDomainScope
	Result: SPFResult
}

// DMARCSummary presents DMARC aggregate reporting statistics for a single domain
// over a period.
export interface DMARCSummary {
	Domain: string
	Total: number
	DispositionNone: number
	DispositionQuarantine: number
	DispositionReject: number
	DKIMFail: number
	SPFFail: number
	PolicyOverrides?: { [key: string]: number }
}

// Reverse is the result of a reverse lookup.
export interface Reverse {
	Hostnames?: string[] | null
}

// ClientConfigs holds the client configuration for IMAP/Submission for a
// domain.
export interface ClientConfigs {
	Entries?: ClientConfigsEntry[] | null
}

export interface ClientConfigsEntry {
	Protocol: string
	Host: Domain
	Port: number
	Listener: string
	Note: string
}

// Msg is a message in the queue.
// 
// Use MakeMsg to make a message with fields that Add needs. Add will further set
// queueing related fields.
export interface Msg {
	ID: number
	Queued: Date
	SenderAccount: string  // Failures are delivered back to this local account. Also used for routing.
	SenderLocalpart: Localpart  // Should be a local user and domain.
	SenderDomain: IPDomain
	RecipientLocalpart: Localpart  // Typically a remote user and domain.
	RecipientDomain: IPDomain
	RecipientDomainStr: string  // For filtering.
	Attempts: number  // Next attempt is based on last attempt and exponential back off based on attempts.
	MaxAttempts: number  // Max number of attempts before giving up. If 0, then the default of 8 attempts is used instead.
	DialedIPs?: { [key: string]: IP[] | null }  // For each host, the IPs that were dialed. Used for IP selection for later attempts.
	NextAttempt: Date  // For scheduling.
	LastAttempt?: Date | null
	LastError: string
	Has8bit: boolean  // Whether message contains bytes with high bit set, determines whether 8BITMIME SMTP extension is needed.
	SMTPUTF8: boolean  // Whether message requires use of SMTPUTF8.
	IsDMARCReport: boolean  // Delivery failures for DMARC reports are handled differently.
	IsTLSReport: boolean  // Delivery failures for TLS reports are handled differently.
	Size: number  // Full size of message, combined MsgPrefix with contents of message file.
	MessageID: string  // Used when composing a DSN, in its References header.
	MsgPrefix?: string | null
	DSNUTF8?: string | null  // If set, this message is a DSN and this is a version using utf-8, for the case the remote MTA supports smtputf8. In this case, Size and MsgPrefix are not relevant.
	Transport: string  // If non-empty, the transport to use for this message. Can be set through cli or admin interface. If empty (the default for a submitted message), regular routing rules apply.
	RequireTLS?: boolean | null  // RequireTLS influences TLS verification during delivery.  If nil, the recipient domain policy is followed (MTA-STS and/or DANE), falling back to optional opportunistic non-verified STARTTLS.  If RequireTLS is true (through SMTP REQUIRETLS extension or webmail submit), MTA-STS or DANE is required, as well as REQUIRETLS support by the next hop server.  If RequireTLS is false (through messag header "TLS-Required: No"), the recipient domain's policy is ignored if it does not lead to a successful TLS connection, i.e. falling back to SMTP delivery with unverified STARTTLS or plain text.
	FutureReleaseRequest: string  // For DSNs, where the original FUTURERELEASE value must be included as per-message field. This field should be of the form "for;" plus interval, or "until;" plus utc date-time.
}

// IPDomain is an ip address, a domain, or empty.
export interface IPDomain {
	IP: IP
	Domain: Domain
}

// WebserverConfig is the combination of WebDomainRedirects and WebHandlers
// from the domains.conf configuration file.
export interface WebserverConfig {
	WebDNSDomainRedirects?: (Domain[] | null)[] | null  // From server to frontend.
	WebDomainRedirects?: (string[] | null)[] | null  // From frontend to server, it's not convenient to create dns.Domain in the frontend.
	WebHandlers?: WebHandler[] | null
}

export interface WebHandler {
	LogName: string
	Domain: string
	PathRegexp: string
	DontRedirectPlainHTTP: boolean
	Compress: boolean
	WebStatic?: WebStatic | null
	WebRedirect?: WebRedirect | null
	WebForward?: WebForward | null
	Name: string  // Either LogName, or numeric index if LogName was empty. Used instead of LogName in logging/metrics.
	DNSDomain: Domain
}

export interface WebStatic {
	StripPrefix: string
	Root: string
	ListFiles: boolean
	ContinueNotFound: boolean
	ResponseHeaders?: { [key: string]: string }
}

export interface WebRedirect {
	BaseURL: string
	OrigPathRegexp: string
	ReplacePath: string
	StatusCode: number
}

export interface WebForward {
	StripPath: boolean
	URL: string
	ResponseHeaders?: { [key: string]: string }
}

// Transport is a method to delivery a message. At most one of the fields can
// be non-nil. The non-nil field represents the type of transport. For a
// transport with all fields nil, regular email delivery is done.
export interface Transport {
	Submissions?: TransportSMTP | null
	Submission?: TransportSMTP | null
	SMTP?: TransportSMTP | null
	Socks?: TransportSocks | null
}

// TransportSMTP delivers messages by "submission" (SMTP, typically
// authenticated) to the queue of a remote host (smarthost), or by relaying
// (SMTP, typically unauthenticated).
export interface TransportSMTP {
	Host: string
	Port: number
	STARTTLSInsecureSkipVerify: boolean
	NoSTARTTLS: boolean
	Auth?: SMTPAuth | null
}

// SMTPAuth hold authentication credentials used when delivering messages
// through a smarthost.
export interface SMTPAuth {
	Username: string
	Password: string
	Mechanisms?: string[] | null
}

export interface TransportSocks {
	Address: string
	RemoteIPs?: string[] | null
	RemoteHostname: string
}

// EvaluationStat summarizes stored evaluations, for inclusion in an upcoming
// aggregate report, for a domain.
export interface EvaluationStat {
	Domain: Domain
	Dispositions?: string[] | null
	Count: number
	SendReport: boolean
}

// Evaluation is the result of an evaluation of a DMARC policy, to be included
// in a DMARC report.
export interface Evaluation {
	ID: number
	PolicyDomain: string  // Domain where DMARC policy was found, could be the organizational domain while evaluation was for a subdomain. Unicode. Same as domain found in PolicyPublished. A separate field for its index.
	Evaluated: Date  // Time of evaluation, determines which report (covering whole hours) this evaluation will be included in.
	Optional: boolean  // If optional, this evaluation is not a reason to send a DMARC report, but it will be included when a report is sent due to other non-optional evaluations. Set for evaluations of incoming DMARC reports. We don't want such deliveries causing us to send a report, or we would keep exchanging reporting messages forever. Also set for when evaluation is a DMARC reject for domains we haven't positively interacted with, to prevent being used to flood an unsuspecting domain with reports.
	IntervalHours: number  // Effective aggregate reporting interval in hours. Between 1 and 24, rounded up from seconds from policy to first number that can divide 24.
	Addresses?: string[] | null  // "rua" in DMARC record, we only store evaluations for records with aggregate reporting addresses, so always non-empty.
	PolicyPublished: PolicyPublished  // Policy used for evaluation. We don't store the "fo" field for failure reporting options, since we don't send failure reports for individual messages.
	SourceIP: string  // For "row" in a report record.
	Disposition: Disposition
	AlignedDKIMPass: boolean
	AlignedSPFPass: boolean
	OverrideReasons?: PolicyOverrideReason[] | null
	EnvelopeTo: string  // For "identifiers" in a report record.
	EnvelopeFrom: string
	HeaderFrom: string
	DKIMResults?: DKIMAuthResult[] | null  // For "auth_results" in a report record.
	SPFResults?: SPFAuthResult[] | null
}

// SuppressAddress is a reporting address for which outgoing DMARC reports
// will be suppressed for a period.
export interface SuppressAddress {
	ID: number
	Inserted: Date
	ReportingAddress: string
	Until: Date
	Comment: string
}

// TLSResult is stored in the database to track TLS results per policy domain, day
// and recipient domain. These records will be included in TLS reports.
export interface TLSResult {
	ID: number
	PolicyDomain: string  // Domain potentially with TLSRPT DNS record, with addresses that will receive reports. Either a recipient domain (for MTA-STS policies) or an (MX) host (for DANE policies). Unicode.
	DayUTC: string  // DayUTC is of the form yyyymmdd.
	RecipientDomain: string  // Reports are sent per recipient domain and per MX host. For reports to a recipient domain, we type send a result for MTA-STS and one or more MX host (DANE) results. Unicode.
	Created: Date
	Updated: Date
	IsHost: boolean  // Result is for MX host (DANE), not recipient domain (MTA-STS).
	SendReport: boolean  // Whether to send a report. TLS results for delivering messages with TLS reports will be recorded, but will not cause a report to be sent.
	SentToRecipientDomain: boolean  // Set after sending to recipient domain, before sending results to policy domain (after which the record is removed).
	RecipientDomainReportingAddresses?: string[] | null  // Reporting addresses from the recipient domain TLSRPT record, not necessarily those we sent to (e.g. due to failure). Used to leave results to MX target (DANE) policy domains out that were already sent in the report to the recipient domain, so we don't report twice.
	SentToPolicyDomain: boolean  // Set after sending report to policy domain.
	Results?: Result[] | null  // Results is updated for each TLS attempt.
}

// TLSRPTSuppressAddress is a reporting address for which outgoing TLS reports
// will be suppressed for a period.
export interface TLSRPTSuppressAddress {
	ID: number
	Inserted: Date
	ReportingAddress: string
	Until: Date
	Comment: string
}

export type CSRFToken = string

// Policy as used in DMARC DNS record for "p=" or "sp=".
export enum DMARCPolicy {
	PolicyEmpty = "",  // Only for the optional Record.SubdomainPolicy.
	PolicyNone = "none",
	PolicyQuarantine = "quarantine",
	PolicyReject = "reject",
}

// Align specifies the required alignment of a domain name.
export enum Align {
	AlignStrict = "s",  // Strict requires an exact domain name match.
	AlignRelaxed = "r",  // Relaxed requires either an exact or subdomain name match.
}

// RUA is a reporting address with scheme and special characters ",", "!" and
// ";" not encoded.
export type RUA = string

// Mode indicates how the policy should be interpreted.
export enum Mode {
	ModeEnforce = "enforce",  // Policy must be followed, i.e. deliveries must fail if a TLS connection cannot be made.
	ModeTesting = "testing",  // In case TLS cannot be negotiated, plain SMTP can be used, but failures must be reported, e.g. with TLSRPT.
	ModeNone = "none",  // In case MTA-STS is not or no longer implemented.
}

// PolicyType indicates the policy success/failure results are for.
export enum PolicyType {
	TLSA = "tlsa",  // For DANE, against a mail host (not recipient domain).
	STS = "sts",  // For MTA-STS, against a recipient domain (not a mail host).
	// Recipient domain did not have MTA-STS policy, or mail host (TSLA base domain)
	// did not have DANE TLSA records.
	NoPolicyFound = "no-policy-found",
}

// ResultType represents a TLS error.
export enum ResultType {
	ResultSTARTTLSNotSupported = "starttls-not-supported",
	ResultCertificateHostMismatch = "certificate-host-mismatch",
	ResultCertificateExpired = "certificate-expired",
	ResultTLSAInvalid = "tlsa-invalid",
	ResultDNSSECInvalid = "dnssec-invalid",
	ResultDANERequired = "dane-required",
	ResultCertificateNotTrusted = "certificate-not-trusted",
	ResultSTSPolicyInvalid = "sts-policy-invalid",
	ResultSTSWebPKIInvalid = "sts-webpki-invalid",
	ResultValidationFailure = "validation-failure",  // Other error.
	ResultSTSPolicyFetch = "sts-policy-fetch-error",
}

// Alignment is the identifier alignment.
export enum Alignment {
	AlignmentAbsent = "",
	AlignmentRelaxed = "r",  // Subdomains match the DMARC from-domain.
	AlignmentStrict = "s",  // Only exact from-domain match.
}

// Disposition is the requested action for a DMARC fail as specified in the
// DMARC policy in DNS.
export enum Disposition {
	DispositionAbsent = "",
	DispositionNone = "none",
	DispositionQuarantine = "quarantine",
	DispositionReject = "reject",
}

// DMARCResult is the final validation and alignment verdict for SPF and DKIM.
export enum DMARCResult {
	DMARCAbsent = "",
	DMARCPass = "pass",
	DMARCFail = "fail",
}

// PolicyOverride is a reason the requested DMARC policy from the DNS record
// was not applied.
export enum PolicyOverride {
	PolicyOverrideForwarded = "forwarded",
	PolicyOverrideSampledOut = "sampled_out",
	PolicyOverrideTrustedForwarder = "trusted_forwarder",
	PolicyOverrideMailingList = "mailing_list",
	PolicyOverrideLocalPolicy = "local_policy",
	PolicyOverrideOther = "other",
}

export enum DKIMResult {
	DKIMAbsent = "",
	DKIMNone = "none",
	DKIMPass = "pass",
	DKIMFail = "fail",
	DKIMPolicy = "policy",
	DKIMNeutral = "neutral",
	DKIMTemperror = "temperror",
	DKIMPermerror = "permerror",
}

export enum SPFDomainScope {
	SPFDomainScopeAbsent = "",
	SPFDomainScopeHelo = "helo",  // SMTP EHLO
	SPFDomainScopeMailFrom = "mfrom",  // SMTP "MAIL FROM".
}

export enum SPFResult {
	SPFAbsent = "",
	SPFNone = "none",
	SPFNeutral = "neutral",
	SPFPass = "pass",
	SPFFail = "fail",
	SPFSoftfail = "softfail",
	SPFTemperror = "temperror",
	SPFPermerror = "permerror",
}

// Localpart is a decoded local part of an email address, before the "@".
// For quoted strings, values do not hold the double quote or escaping backslashes.
// An empty string can be a valid localpart.
export type Localpart = string

// An IP is a single IP address, a slice of bytes.
// Functions in this package accept either 4-byte (IPv4)
// or 16-byte (IPv6) slices as input.
// 
// Note that in this documentation, referring to an
// IP address as an IPv4 address or an IPv6 address
// is a semantic property of the address, not just the
// length of the byte slice: a 16-byte slice can still
// be an IPv4 address.
export type IP = string

export const structTypes: {[typename: string]: boolean} = {"AuthResults":true,"AutoconfCheckResult":true,"AutodiscoverCheckResult":true,"AutodiscoverSRV":true,"CheckResult":true,"ClientConfigs":true,"ClientConfigsEntry":true,"DANECheckResult":true,"DKIMAuthResult":true,"DKIMCheckResult":true,"DKIMRecord":true,"DMARCCheckResult":true,"DMARCRecord":true,"DMARCSummary":true,"DNSSECResult":true,"DateRange":true,"Directive":true,"Domain":true,"DomainFeedback":true,"Evaluation":true,"EvaluationStat":true,"Extension":true,"FailureDetails":true,"IPDomain":true,"IPRevCheckResult":true,"Identifiers":true,"MTASTSCheckResult":true,"MTASTSRecord":true,"MX":true,"MXCheckResult":true,"Modifier":true,"Msg":true,"Pair":true,"Policy":true,"PolicyEvaluated":true,"PolicyOverrideReason":true,"PolicyPublished":true,"PolicyRecord":true,"Record":true,"Report":true,"ReportMetadata":true,"ReportRecord":true,"Result":true,"ResultPolicy":true,"Reverse":true,"Row":true,"SMTPAuth":true,"SPFAuthResult":true,"SPFCheckResult":true,"SPFRecord":true,"SRV":true,"SRVConfCheckResult":true,"STSMX":true,"Summary":true,"SuppressAddress":true,"TLSCheckResult":true,"TLSRPTCheckResult":true,"TLSRPTDateRange":true,"TLSRPTRecord":true,"TLSRPTSummary":true,"TLSRPTSuppressAddress":true,"TLSReportRecord":true,"TLSResult":true,"Transport":true,"TransportSMTP":true,"TransportSocks":true,"URI":true,"WebForward":true,"WebHandler":true,"WebRedirect":true,"WebStatic":true,"WebserverConfig":true}
export const stringsTypes: {[typename: string]: boolean} = {"Align":true,"Alignment":true,"CSRFToken":true,"DKIMResult":true,"DMARCPolicy":true,"DMARCResult":true,"Disposition":true,"IP":true,"Localpart":true,"Mode":true,"PolicyOverride":true,"PolicyType":true,"RUA":true,"ResultType":true,"SPFDomainScope":true,"SPFResult":true}
export const intsTypes: {[typename: string]: boolean} = {}
export const types: TypenameMap = {
	"CheckResult": {"Name":"CheckResult","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"DNSSEC","Docs":"","Typewords":["DNSSECResult"]},{"Name":"IPRev","Docs":"","Typewords":["IPRevCheckResult"]},{"Name":"MX","Docs":"","Typewords":["MXCheckResult"]},{"Name":"TLS","Docs":"","Typewords":["TLSCheckResult"]},{"Name":"DANE","Docs":"","Typewords":["DANECheckResult"]},{"Name":"SPF","Docs":"","Typewords":["SPFCheckResult"]},{"Name":"DKIM","Docs":"","Typewords":["DKIMCheckResult"]},{"Name":"DMARC","Docs":"","Typewords":["DMARCCheckResult"]},{"Name":"HostTLSRPT","Docs":"","Typewords":["TLSRPTCheckResult"]},{"Name":"DomainTLSRPT","Docs":"","Typewords":["TLSRPTCheckResult"]},{"Name":"MTASTS","Docs":"","Typewords":["MTASTSCheckResult"]},{"Name":"SRVConf","Docs":"","Typewords":["SRVConfCheckResult"]},{"Name":"Autoconf","Docs":"","Typewords":["AutoconfCheckResult"]},{"Name":"Autodiscover","Docs":"","Typewords":["AutodiscoverCheckResult"]}]},
	"DNSSECResult": {"Name":"DNSSECResult","Docs":"","Fields":[{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"IPRevCheckResult": {"Name":"IPRevCheckResult","Docs":"","Fields":[{"Name":"Hostname","Docs":"","Typewords":["Domain"]},{"Name":"IPNames","Docs":"","Typewords":["{}","[]","string"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"Domain": {"Name":"Domain","Docs":"","Fields":[{"Name":"ASCII","Docs":"","Typewords":["string"]},{"Name":"Unicode","Docs":"","Typewords":["string"]}]},
	"MXCheckResult": {"Name":"MXCheckResult","Docs":"","Fields":[{"Name":"Records","Docs":"","Typewords":["[]","MX"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"MX": {"Name":"MX","Docs":"","Fields":[{"Name":"Host","Docs":"","Typewords":["string"]},{"Name":"Pref","Docs":"","Typewords":["int32"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]}]},
	"TLSCheckResult": {"Name":"TLSCheckResult","Docs":"","Fields":[{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"DANECheckResult": {"Name":"DANECheckResult","Docs":"","Fields":[{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"SPFCheckResult": {"Name":"SPFCheckResult","Docs":"","Fields":[{"Name":"DomainTXT","Docs":"","Typewords":["string"]},{"Name":"DomainRecord","Docs":"","Typewords":["nullable","SPFRecord"]},{"Name":"HostTXT","Docs":"","Typewords":["string"]},{"Name":"HostRecord","Docs":"","Typewords":["nullable","SPFRecord"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"SPFRecord": {"Name":"SPFRecord","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Directives","Docs":"","Typewords":["[]","Directive"]},{"Name":"Redirect","Docs":"","Typewords":["string"]},{"Name":"Explanation","Docs":"","Typewords":["string"]},{"Name":"Other","Docs":"","Typewords":["[]","Modifier"]}]},
	"Directive": {"Name":"Directive","Docs":"","Fields":[{"Name":"Qualifier","Docs":"","Typewords":["string"]},{"Name":"Mechanism","Docs":"","Typewords":["string"]},{"Name":"DomainSpec","Docs":"","Typewords":["string"]},{"Name":"IPstr","Docs":"","Typewords":["string"]},{"Name":"IP4CIDRLen","Docs":"","Typewords":["nullable","int32"]},{"Name":"IP6CIDRLen","Docs":"","Typewords":["nullable","int32"]}]},
	"Modifier": {"Name":"Modifier","Docs":"","Fields":[{"Name":"Key","Docs":"","Typewords":["string"]},{"Name":"Value","Docs":"","Typewords":["string"]}]},
	"DKIMCheckResult": {"Name":"DKIMCheckResult","Docs":"","Fields":[{"Name":"Records","Docs":"","Typewords":["[]","DKIMRecord"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"DKIMRecord": {"Name":"DKIMRecord","Docs":"","Fields":[{"Name":"Selector","Docs":"","Typewords":["string"]},{"Name":"TXT","Docs":"","Typewords":["string"]},{"Name":"Record","Docs":"","Typewords":["nullable","Record"]}]},
	"Record": {"Name":"Record","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Hashes","Docs":"","Typewords":["[]","string"]},{"Name":"Key","Docs":"","Typewords":["string"]},{"Name":"Notes","Docs":"","Typewords":["string"]},{"Name":"Pubkey","Docs":"","Typewords":["nullable","string"]},{"Name":"Services","Docs":"","Typewords":["[]","string"]},{"Name":"Flags","Docs":"","Typewords":["[]","string"]}]},
	"DMARCCheckResult": {"Name":"DMARCCheckResult","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"TXT","Docs":"","Typewords":["string"]},{"Name":"Record","Docs":"","Typewords":["nullable","DMARCRecord"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"DMARCRecord": {"Name":"DMARCRecord","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Policy","Docs":"","Typewords":["DMARCPolicy"]},{"Name":"SubdomainPolicy","Docs":"","Typewords":["DMARCPolicy"]},{"Name":"AggregateReportAddresses","Docs":"","Typewords":["[]","URI"]},{"Name":"FailureReportAddresses","Docs":"","Typewords":["[]","URI"]},{"Name":"ADKIM","Docs":"","Typewords":["Align"]},{"Name":"ASPF","Docs":"","Typewords":["Align"]},{"Name":"AggregateReportingInterval","Docs":"","Typewords":["int32"]},{"Name":"FailureReportingOptions","Docs":"","Typewords":["[]","string"]},{"Name":"ReportingFormat","Docs":"","Typewords":["[]","string"]},{"Name":"Percentage","Docs":"","Typewords":["int32"]}]},
	"URI": {"Name":"URI","Docs":"","Fields":[{"Name":"Address","Docs":"","Typewords":["string"]},{"Name":"MaxSize","Docs":"","Typewords":["uint64"]},{"Name":"Unit","Docs":"","Typewords":["string"]}]},
	"TLSRPTCheckResult": {"Name":"TLSRPTCheckResult","Docs":"","Fields":[{"Name":"TXT","Docs":"","Typewords":["string"]},{"Name":"Record","Docs":"","Typewords":["nullable","TLSRPTRecord"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"TLSRPTRecord": {"Name":"TLSRPTRecord","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"RUAs","Docs":"","Typewords":["[]","[]","RUA"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Extension"]}]},
	"Extension": {"Name":"Extension","Docs":"","Fields":[{"Name":"Key","Docs":"","Typewords":["string"]},{"Name":"Value","Docs":"","Typewords":["string"]}]},
	"MTASTSCheckResult": {"Name":"MTASTSCheckResult","Docs":"","Fields":[{"Name":"TXT","Docs":"","Typewords":["string"]},{"Name":"Record","Docs":"","Typewords":["nullable","MTASTSRecord"]},{"Name":"PolicyText","Docs":"","Typewords":["string"]},{"Name":"Policy","Docs":"","Typewords":["nullable","Policy"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"MTASTSRecord": {"Name":"MTASTSRecord","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"ID","Docs":"","Typewords":["string"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Pair"]}]},
	"Pair": {"Name":"Pair","Docs":"","Fields":[{"Name":"Key","Docs":"","Typewords":["string"]},{"Name":"Value","Docs":"","Typewords":["string"]}]},
	"Policy": {"Name":"Policy","Docs":"","Fields":[{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Mode","Docs":"","Typewords":["Mode"]},{"Name":"MX","Docs":"","Typewords":["[]","STSMX"]},{"Name":"MaxAgeSeconds","Docs":"","Typewords":["int32"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Pair"]}]},
	"STSMX": {"Name":"STSMX","Docs":"","Fields":[{"Name":"Wildcard","Docs":"","Typewords":["bool"]},{"Name":"Domain","Docs":"","Typewords":["Domain"]}]},
	"SRVConfCheckResult": {"Name":"SRVConfCheckResult","Docs":"","Fields":[{"Name":"SRVs","Docs":"","Typewords":["{}","[]","SRV"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"SRV": {"Name":"SRV","Docs":"","Fields":[{"Name":"Target","Docs":"","Typewords":["string"]},{"Name":"Port","Docs":"","Typewords":["uint16"]},{"Name":"Priority","Docs":"","Typewords":["uint16"]},{"Name":"Weight","Docs":"","Typewords":["uint16"]}]},
	"AutoconfCheckResult": {"Name":"AutoconfCheckResult","Docs":"","Fields":[{"Name":"ClientSettingsDomainIPs","Docs":"","Typewords":["[]","string"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"AutodiscoverCheckResult": {"Name":"AutodiscoverCheckResult","Docs":"","Fields":[{"Name":"Records","Docs":"","Typewords":["[]","AutodiscoverSRV"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
	"AutodiscoverSRV": {"Name":"AutodiscoverSRV","Docs":"","Fields":[{"Name":"Target","Docs":"","Typewords":["string"]},{"Name":"Port","Docs":"","Typewords":["uint16"]},{"Name":"Priority","Docs":"","Typewords":["uint16"]},{"Name":"Weight","Docs":"","Typewords":["uint16"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]}]},
	"PolicyRecord": {"Name":"PolicyRecord","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Inserted","Docs":"","Typewords":["timestamp"]},{"Name":"ValidEnd","Docs":"","Typewords":["timestamp"]},{"Name":"LastUpdate","Docs":"","Typewords":["timestamp"]},{"Name":"LastUse","Docs":"","Typewords":["timestamp"]},{"Name":"Backoff","Docs":"","Typewords":["bool"]},{"Name":"RecordID","Docs":"","Typewords":["string"]},{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Mode","Docs":"","Typewords":["Mode"]},{"Name":"MX","Docs":"","Typewords":["[]","STSMX"]},{"Name":"MaxAgeSeconds","Docs":"","Typewords":["int32"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Pair"]},{"Name":"PolicyText","Docs":"","Typewords":["string"]}]},
	"TLSReportRecord": {"Name":"TLSReportRecord","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"FromDomain","Docs":"","Typewords":["string"]},{"Name":"MailFrom","Docs":"","Typewords":["string"]},{"Name":"HostReport","Docs":"","Typewords":["bool"]},{"Name":"Report","Docs":"","Typewords":["Report"]}]},
	"Report": {"Name":"Report","Docs":"","Fields":[{"Name":"OrganizationName","Docs":"","Typewords":["string"]},{"Name":"DateRange","Docs":"","Typewords":["TLSRPTDateRange"]},{"Name":"ContactInfo","Docs":"","Typewords":["string"]},{"Name":"ReportID","Docs":"","Typewords":["string"]},{"Name":"Policies","Docs":"","Typewords":["[]","Result"]}]},
	"TLSRPTDateRange": {"Name":"TLSRPTDateRange","Docs":"","Fields":[{"Name":"Start","Docs":"","Typewords":["timestamp"]},{"Name":"End","Docs":"","Typewords":["timestamp"]}]},
	"Result": {"Name":"Result","Docs":"","Fields":[{"Name":"Policy","Docs":"","Typewords":["ResultPolicy"]},{"Name":"Summary","Docs":"","Typewords":["Summary"]},{"Name":"FailureDetails","Docs":"","Typewords":["[]","FailureDetails"]}]},
	"ResultPolicy": {"Name":"ResultPolicy","Docs":"","Fields":[{"Name":"Type","Docs":"","Typewords":["PolicyType"]},{"Name":"String","Docs":"","Typewords":["[]","string"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"MXHost","Docs":"","Typewords":["[]","string"]}]},
	"Summary": {"Name":"Summary","Docs":"","Fields":[{"Name":"TotalSuccessfulSessionCount","Docs":"","Typewords":["int64"]},{"Name":"TotalFailureSessionCount","Docs":"","Typewords":["int64"]}]},
	"FailureDetails": {"Name":"FailureDetails","Docs":"","Fields":[{"Name":"ResultType","Docs":"","Typewords":["ResultType"]},{"Name":"SendingMTAIP","Docs":"","Typewords":["string"]},{"Name":"ReceivingMXHostname","Docs":"","Typewords":["string"]},{"Name":"ReceivingMXHelo","Docs":"","Typewords":["string"]},{"Name":"ReceivingIP","Docs":"","Typewords":["string"]},{"Name":"FailedSessionCount","Docs":"","Typewords":["int64"]},{"Name":"AdditionalInformation","Docs":"","Typewords":["string"]},{"Name":"FailureReasonCode","Docs":"","Typewords":["string"]}]},
	"TLSRPTSummary": {"Name":"TLSRPTSummary","Docs":"","Fields":[{"Name":"PolicyDomain","Docs":"","Typewords":["Domain"]},{"Name":"Success","Docs":"","Typewords":["int64"]},{"Name":"Failure","Docs":"","Typewords":["int64"]},{"Name":"ResultTypeCounts","Docs":"","Typewords":["{}","int64"]}]},
	"DomainFeedback": {"Name":"DomainFeedback","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"FromDomain","Docs":"","Typewords":["string"]},{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"ReportMetadata","Docs":"","Typewords":["ReportMetadata"]},{"Name":"PolicyPublished","Docs":"","Typewords":["PolicyPublished"]},{"Name":"Records","Docs":"","Typewords":["[]","ReportRecord"]}]},
	"ReportMetadata": {"Name":"ReportMetadata","Docs":"","Fields":[{"Name":"OrgName","Docs":"","Typewords":["string"]},{"Name":"Email","Docs":"","Typewords":["string"]},{"Name":"ExtraContactInfo","Docs":"","Typewords":["string"]},{"Name":"ReportID","Docs":"","Typewords":["string"]},{"Name":"DateRange","Docs":"","Typewords":["DateRange"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]}]},
	"DateRange": {"Name":"DateRange","Docs":"","Fields":[{"Name":"Begin","Docs":"","Typewords":["int64"]},{"Name":"End","Docs":"","Typewords":["int64"]}]},
	"PolicyPublished": {"Name":"PolicyPublished","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"ADKIM","Docs":"","Typewords":["Alignment"]},{"Name":"ASPF","Docs":"","Typewords":["Alignment"]},{"Name":"Policy","Docs":"","Typewords":["Disposition"]},{"Name":"SubdomainPolicy","Docs":"","Typewords":["Disposition"]},{"Name":"Percentage","Docs":"","Typewords":["int32"]},{"Name":"ReportingOptions","Docs":"","Typewords":["string"]}]},
	"ReportRecord": {"Name":"ReportRecord","Docs":"","Fields":[{"Name":"Row","Docs":"","Typewords":["Row"]},{"Name":"Identifiers","Docs":"","Typewords":["Identifiers"]},{"Name":"AuthResults","Docs":"","Typewords":["AuthResults"]}]},
	"Row": {"Name":"Row","Docs":"","Fields":[{"Name":"SourceIP","Docs":"","Typewords":["string"]},{"Name":"Count","Docs":"","Typewords":["int32"]},{"Name":"PolicyEvaluated","Docs":"","Typewords":["PolicyEvaluated"]}]},
	"PolicyEvaluated": {"Name":"PolicyEvaluated","Docs":"","Fields":[{"Name":"Disposition","Docs":"","Typewords":["Disposition"]},{"Name":"DKIM","Docs":"","Typewords":["DMARCResult"]},{"Name":"SPF","Docs":"","Typewords":["DMARCResult"]},{"Name":"Reasons","Docs":"","Typewords":["[]","PolicyOverrideReason"]}]},
	"PolicyOverrideReason": {"Name":"PolicyOverrideReason","Docs":"","Fields":[{"Name":"Type","Docs":"","Typewords":["PolicyOverride"]},{"Name":"Comment","Docs":"","Typewords":["string"]}]},
	"Identifiers": {"Name":"Identifiers","Docs":"","Fields":[{"Name":"EnvelopeTo","Docs":"","Typewords":["string"]},{"Name":"EnvelopeFrom","Docs":"","Typewords":["string"]},{"Name":"HeaderFrom","Docs":"","Typewords":["string"]}]},
	"AuthResults": {"Name":"AuthResults","Docs":"","Fields":[{"Name":"DKIM","Docs":"","Typewords":["[]","DKIMAuthResult"]},{"Name":"SPF","Docs":"","Typewords":["[]","SPFAuthResult"]}]},
	"DKIMAuthResult": {"Name":"DKIMAuthResult","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Selector","Docs":"","Typewords":["string"]},{"Name":"Result","Docs":"","Typewords":["DKIMResult"]},{"Name":"HumanResult","Docs":"","Typewords":["string"]}]},
	"SPFAuthResult": {"Name":"SPFAuthResult","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Scope","Docs":"","Typewords":["SPFDomainScope"]},{"Name":"Result","Docs":"","Typewords":["SPFResult"]}]},
	"DMARCSummary": {"Name":"DMARCSummary","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Total","Docs":"","Typewords":["int32"]},{"Name":"DispositionNone","Docs":"","Typewords":["int32"]},{"Name":"DispositionQuarantine","Docs":"","Typewords":["int32"]},{"Name":"DispositionReject","Docs":"","Typewords":["int32"]},{"Name":"DKIMFail","Docs":"","Typewords":["int32"]},{"Name":"SPFFail","Docs":"","Typewords":["int32"]},{"Name":"PolicyOverrides","Docs":"","Typewords":["{}","int32"]}]},
	"Reverse": {"Name":"Reverse","Docs":"","Fields":[{"Name":"Hostnames","Docs":"","Typewords":["[]","string"]}]},
	"ClientConfigs": {"Name":"ClientConfigs","Docs":"","Fields":[{"Name":"Entries","Docs":"","Typewords":["[]","ClientConfigsEntry"]}]},
	"ClientConfigsEntry": {"Name":"ClientConfigsEntry","Docs":"","Fields":[{"Name":"Protocol","Docs":"","Typewords":["string"]},{"Name":"Host","Docs":"","Typewords":["Domain"]},{"Name":"Port","Docs":"","Typewords":["int32"]},{"Name":"Listener","Docs":"","Typewords":["string"]},{"Name":"Note","Docs":"","Typewords":["string"]}]},
	"Msg": {"Name":"Msg","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Queued","Docs":"","Typewords":["timestamp"]},{"Name":"SenderAccount","Docs":"","Typewords":["string"]},{"Name":"SenderLocalpart","Docs":"","Typewords":["Localpart"]},{"Name":"SenderDomain","Docs":"","Typewords":["IPDomain"]},{"Name":"RecipientLocalpart","Docs":"","Typewords":["Localpart"]},{"Name":"RecipientDomain","Docs":"","Typewords":["IPDomain"]},{"Name":"RecipientDomainStr","Docs":"","Typewords":["string"]},{"Name":"Attempts","Docs":"","Typewords":["int32"]},{"Name":"MaxAttempts","Docs":"","Typewords":["int32"]},{"Name":"DialedIPs","Docs":"","Typewords":["{}","[]","IP"]},{"Name":"NextAttempt","Docs":"","Typewords":["timestamp"]},{"Name":"LastAttempt","Docs":"","Typewords":["nullable","timestamp"]},{"Name":"LastError","Docs":"","Typewords":["string"]},{"Name":"Has8bit","Docs":"","Typewords":["bool"]},{"Name":"SMTPUTF8","Docs":"","Typewords":["bool"]},{"Name":"IsDMARCReport","Docs":"","Typewords":["bool"]},{"Name":"IsTLSReport","Docs":"","Typewords":["bool"]},{"Name":"Size","Docs":"","Typewords":["int64"]},{"Name":"MessageID","Docs":"","Typewords":["string"]},{"Name":"MsgPrefix","Docs":"","Typewords":["nullable","string"]},{"Name":"DSNUTF8","Docs":"","Typewords":["nullable","string"]},{"Name":"Transport","Docs":"","Typewords":["string"]},{"Name":"RequireTLS","Docs":"","Typewords":["nullable","bool"]},{"Name":"FutureReleaseRequest","Docs":"","Typewords":["string"]}]},
	"IPDomain": {"Name":"IPDomain","Docs":"","Fields":[{"Name":"IP","Docs":"","Typewords":["IP"]},{"Name":"Domain","Docs":"","Typewords":["Domain"]}]},
	"WebserverConfig": {"Name":"WebserverConfig","Docs":"","Fields":[{"Name":"WebDNSDomainRedirects","Docs":"","Typewords":["[]","[]","Domain"]},{"Name":"WebDomainRedirects","Docs":"","Typewords":["[]","[]","string"]},{"Name":"WebHandlers","Docs":"","Typewords":["[]","WebHandler"]}]},
	"WebHandler": {"Name":"WebHandler","Docs":"","Fields":[{"Name":"LogName","Docs":"","Typewords":["string"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"PathRegexp","Docs":"","Typewords":["string"]},{"Name":"DontRedirectPlainHTTP","Docs":"","Typewords":["bool"]},{"Name":"Compress","Docs":"","Typewords":["bool"]},{"Name":"WebStatic","Docs":"","Typewords":["nullable","WebStatic"]},{"Name":"WebRedirect","Docs":"","Typewords":["nullable","WebRedirect"]},{"Name":"WebForward","Docs":"","Typewords":["nullable","WebForward"]},{"Name":"Name","Docs":"","Typewords":["string"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]}]},
	"WebStatic": {"Name":"WebStatic","Docs":"","Fields":[{"Name":"StripPrefix","Docs":"","Typewords":["string"]},{"Name":"Root","Docs":"","Typewords":["string"]},{"Name":"ListFiles","Docs":"","Typewords":["bool"]},{"Name":"ContinueNotFound","Docs":"","Typewords":["bool"]},{"Name":"ResponseHeaders","Docs":"","Typewords":["{}","string"]}]},
	"WebRedirect": {"Name":"WebRedirect","Docs":"","Fields":[{"Name":"BaseURL","Docs":"","Typewords":["string"]},{"Name":"OrigPathRegexp","Docs":"","Typewords":["string"]},{"Name":"ReplacePath","Docs":"","Typewords":["string"]},{"Name":"StatusCode","Docs":"","Typewords":["int32"]}]},
	"WebForward": {"Name":"WebForward","Docs":"","Fields":[{"Name":"StripPath","Docs":"","Typewords":["bool"]},{"Name":"URL","Docs":"","Typewords":["string"]},{"Name":"ResponseHeaders","Docs":"","Typewords":["{}","string"]}]},
	"Transport": {"Name":"Transport","Docs":"","Fields":[{"Name":"Submissions","Docs":"","Typewords":["nullable","TransportSMTP"]},{"Name":"Submission","Docs":"","Typewords":["nullable","TransportSMTP"]},{"Name":"SMTP","Docs":"","Typewords":["nullable","TransportSMTP"]},{"Name":"Socks","Docs":"","Typewords":["nullable","TransportSocks"]}]},
	"TransportSMTP": {"Name":"TransportSMTP","Docs":"","Fields":[{"Name":"Host","Docs":"","Typewords":["string"]},{"Name":"Port","Docs":"","Typewords":["int32"]},{"Name":"STARTTLSInsecureSkipVerify","Docs":"","Typewords":["bool"]},{"Name":"NoSTARTTLS","Docs":"","Typewords":["bool"]},{"Name":"Auth","Docs":"","Typewords":["nullable","SMTPAuth"]}]},
	"SMTPAuth": {"Name":"SMTPAuth","Docs":"","Fields":[{"Name":"Username","Docs":"","Typewords":["string"]},{"Name":"Password","Docs":"","Typewords":["string"]},{"Name":"Mechanisms","Docs":"","Typewords":["[]","string"]}]},
	"TransportSocks": {"Name":"TransportSocks","Docs":"","Fields":[{"Name":"Address","Docs":"","Typewords":["string"]},{"Name":"RemoteIPs","Docs":"","Typewords":["[]","string"]},{"Name":"RemoteHostname","Docs":"","Typewords":["string"]}]},
	"EvaluationStat": {"Name":"EvaluationStat","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["Domain"]},{"Name":"Dispositions","Docs":"","Typewords":["[]","string"]},{"Name":"Count","Docs":"","Typewords":["int32"]},{"Name":"SendReport","Docs":"","Typewords":["bool"]}]},
	"Evaluation": {"Name":"Evaluation","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"PolicyDomain","Docs":"","Typewords":["string"]},{"Name":"Evaluated","Docs":"","Typewords":["timestamp"]},{"Name":"Optional","Docs":"","Typewords":["bool"]},{"Name":"IntervalHours","Docs":"","Typewords":["int32"]},{"Name":"Addresses","Docs":"","Typewords":["[]","string"]},{"Name":"PolicyPublished","Docs":"","Typewords":["PolicyPublished"]},{"Name":"SourceIP","Docs":"","Typewords":["string"]},{"Name":"Disposition","Docs":"","Typewords":["Disposition"]},{"Name":"AlignedDKIMPass","Docs":"","Typewords":["bool"]},{"Name":"AlignedSPFPass","Docs":"","Typewords":["bool"]},{"Name":"OverrideReasons","Docs":"","Typewords":["[]","PolicyOverrideReason"]},{"Name":"EnvelopeTo","Docs":"","Typewords":["string"]},{"Name":"EnvelopeFrom","Docs":"","Typewords":["string"]},{"Name":"HeaderFrom","Docs":"","Typewords":["string"]},{"Name":"DKIMResults","Docs":"","Typewords":["[]","DKIMAuthResult"]},{"Name":"SPFResults","Docs":"","Typewords":["[]","SPFAuthResult"]}]},
	"SuppressAddress": {"Name":"SuppressAddress","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Inserted","Docs":"","Typewords":["timestamp"]},{"Name":"ReportingAddress","Docs":"","Typewords":["string"]},{"Name":"Until","Docs":"","Typewords":["timestamp"]},{"Name":"Comment","Docs":"","Typewords":["string"]}]},
	"TLSResult": {"Name":"TLSResult","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"PolicyDomain","Docs":"","Typewords":["string"]},{"Name":"DayUTC","Docs":"","Typewords":["string"]},{"Name":"RecipientDomain","Docs":"","Typewords":["string"]},{"Name":"Created","Docs":"","Typewords":["timestamp"]},{"Name":"Updated","Docs":"","Typewords":["timestamp"]},{"Name":"IsHost","Docs":"","Typewords":["bool"]},{"Name":"SendReport","Docs":"","Typewords":["bool"]},{"Name":"SentToRecipientDomain","Docs":"","Typewords":["bool"]},{"Name":"RecipientDomainReportingAddresses","Docs":"","Typewords":["[]","string"]},{"Name":"SentToPolicyDomain","Docs":"","Typewords":["bool"]},{"Name":"Results","Docs":"","Typewords":["[]","Result"]}]},
	"TLSRPTSuppressAddress": {"Name":"TLSRPTSuppressAddress","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Inserted","Docs":"","Typewords":["timestamp"]},{"Name":"ReportingAddress","Docs":"","Typewords":["string"]},{"Name":"Until","Docs":"","Typewords":["timestamp"]},{"Name":"Comment","Docs":"","Typewords":["string"]}]},
	"CSRFToken": {"Name":"CSRFToken","Docs":"","Values":null},
	"DMARCPolicy": {"Name":"DMARCPolicy","Docs":"","Values":[{"Name":"PolicyEmpty","Value":"","Docs":""},{"Name":"PolicyNone","Value":"none","Docs":""},{"Name":"PolicyQuarantine","Value":"quarantine","Docs":""},{"Name":"PolicyReject","Value":"reject","Docs":""}]},
	"Align": {"Name":"Align","Docs":"","Values":[{"Name":"AlignStrict","Value":"s","Docs":""},{"Name":"AlignRelaxed","Value":"r","Docs":""}]},
	"RUA": {"Name":"RUA","Docs":"","Values":null},
	"Mode": {"Name":"Mode","Docs":"","Values":[{"Name":"ModeEnforce","Value":"enforce","Docs":""},{"Name":"ModeTesting","Value":"testing","Docs":""},{"Name":"ModeNone","Value":"none","Docs":""}]},
	"PolicyType": {"Name":"PolicyType","Docs":"","Values":[{"Name":"TLSA","Value":"tlsa","Docs":""},{"Name":"STS","Value":"sts","Docs":""},{"Name":"NoPolicyFound","Value":"no-policy-found","Docs":""}]},
	"ResultType": {"Name":"ResultType","Docs":"","Values":[{"Name":"ResultSTARTTLSNotSupported","Value":"starttls-not-supported","Docs":""},{"Name":"ResultCertificateHostMismatch","Value":"certificate-host-mismatch","Docs":""},{"Name":"ResultCertificateExpired","Value":"certificate-expired","Docs":""},{"Name":"ResultTLSAInvalid","Value":"tlsa-invalid","Docs":""},{"Name":"ResultDNSSECInvalid","Value":"dnssec-invalid","Docs":""},{"Name":"ResultDANERequired","Value":"dane-required","Docs":""},{"Name":"ResultCertificateNotTrusted","Value":"certificate-not-trusted","Docs":""},{"Name":"ResultSTSPolicyInvalid","Value":"sts-policy-invalid","Docs":""},{"Name":"ResultSTSWebPKIInvalid","Value":"sts-webpki-invalid","Docs":""},{"Name":"ResultValidationFailure","Value":"validation-failure","Docs":""},{"Name":"ResultSTSPolicyFetch","Value":"sts-policy-fetch-error","Docs":""}]},
	"Alignment": {"Name":"Alignment","Docs":"","Values":[{"Name":"AlignmentAbsent","Value":"","Docs":""},{"Name":"AlignmentRelaxed","Value":"r","Docs":""},{"Name":"AlignmentStrict","Value":"s","Docs":""}]},
	"Disposition": {"Name":"Disposition","Docs":"","Values":[{"Name":"DispositionAbsent","Value":"","Docs":""},{"Name":"DispositionNone","Value":"none","Docs":""},{"Name":"DispositionQuarantine","Value":"quarantine","Docs":""},{"Name":"DispositionReject","Value":"reject","Docs":""}]},
	"DMARCResult": {"Name":"DMARCResult","Docs":"","Values":[{"Name":"DMARCAbsent","Value":"","Docs":""},{"Name":"DMARCPass","Value":"pass","Docs":""},{"Name":"DMARCFail","Value":"fail","Docs":""}]},
	"PolicyOverride": {"Name":"PolicyOverride","Docs":"","Values":[{"Name":"PolicyOverrideForwarded","Value":"forwarded","Docs":""},{"Name":"PolicyOverrideSampledOut","Value":"sampled_out","Docs":""},{"Name":"PolicyOverrideTrustedForwarder","Value":"trusted_forwarder","Docs":""},{"Name":"PolicyOverrideMailingList","Value":"mailing_list","Docs":""},{"Name":"PolicyOverrideLocalPolicy","Value":"local_policy","Docs":""},{"Name":"PolicyOverrideOther","Value":"other","Docs":""}]},
	"DKIMResult": {"Name":"DKIMResult","Docs":"","Values":[{"Name":"DKIMAbsent","Value":"","Docs":""},{"Name":"DKIMNone","Value":"none","Docs":""},{"Name":"DKIMPass","Value":"pass","Docs":""},{"Name":"DKIMFail","Value":"fail","Docs":""},{"Name":"DKIMPolicy","Value":"policy","Docs":""},{"Name":"DKIMNeutral","Value":"neutral","Docs":""},{"Name":"DKIMTemperror","Value":"temperror","Docs":""},{"Name":"DKIMPermerror","Value":"permerror","Docs":""}]},
	"SPFDomainScope": {"Name":"SPFDomainScope","Docs":"","Values":[{"Name":"SPFDomainScopeAbsent","Value":"","Docs":""},{"Name":"SPFDomainScopeHelo","Value":"helo","Docs":""},{"Name":"SPFDomainScopeMailFrom","Value":"mfrom","Docs":""}]},
	"SPFResult": {"Name":"SPFResult","Docs":"","Values":[{"Name":"SPFAbsent","Value":"","Docs":""},{"Name":"SPFNone","Value":"none","Docs":""},{"Name":"SPFNeutral","Value":"neutral","Docs":""},{"Name":"SPFPass","Value":"pass","Docs":""},{"Name":"SPFFail","Value":"fail","Docs":""},{"Name":"SPFSoftfail","Value":"softfail","Docs":""},{"Name":"SPFTemperror","Value":"temperror","Docs":""},{"Name":"SPFPermerror","Value":"permerror","Docs":""}]},
	"Localpart": {"Name":"Localpart","Docs":"","Values":null},
	"IP": {"Name":"IP","Docs":"","Values":[]},
}

export const parser = {
	CheckResult: (v: any) => parse("CheckResult", v) as CheckResult,
	DNSSECResult: (v: any) => parse("DNSSECResult", v) as DNSSECResult,
	IPRevCheckResult: (v: any) => parse("IPRevCheckResult", v) as IPRevCheckResult,
	Domain: (v: any) => parse("Domain", v) as Domain,
	MXCheckResult: (v: any) => parse("MXCheckResult", v) as MXCheckResult,
	MX: (v: any) => parse("MX", v) as MX,
	TLSCheckResult: (v: any) => parse("TLSCheckResult", v) as TLSCheckResult,
	DANECheckResult: (v: any) => parse("DANECheckResult", v) as DANECheckResult,
	SPFCheckResult: (v: any) => parse("SPFCheckResult", v) as SPFCheckResult,
	SPFRecord: (v: any) => parse("SPFRecord", v) as SPFRecord,
	Directive: (v: any) => parse("Directive", v) as Directive,
	Modifier: (v: any) => parse("Modifier", v) as Modifier,
	DKIMCheckResult: (v: any) => parse("DKIMCheckResult", v) as DKIMCheckResult,
	DKIMRecord: (v: any) => parse("DKIMRecord", v) as DKIMRecord,
	Record: (v: any) => parse("Record", v) as Record,
	DMARCCheckResult: (v: any) => parse("DMARCCheckResult", v) as DMARCCheckResult,
	DMARCRecord: (v: any) => parse("DMARCRecord", v) as DMARCRecord,
	URI: (v: any) => parse("URI", v) as URI,
	TLSRPTCheckResult: (v: any) => parse("TLSRPTCheckResult", v) as TLSRPTCheckResult,
	TLSRPTRecord: (v: any) => parse("TLSRPTRecord", v) as TLSRPTRecord,
	Extension: (v: any) => parse("Extension", v) as Extension,
	MTASTSCheckResult: (v: any) => parse("MTASTSCheckResult", v) as MTASTSCheckResult,
	MTASTSRecord: (v: any) => parse("MTASTSRecord", v) as MTASTSRecord,
	Pair: (v: any) => parse("Pair", v) as Pair,
	Policy: (v: any) => parse("Policy", v) as Policy,
	STSMX: (v: any) => parse("STSMX", v) as STSMX,
	SRVConfCheckResult: (v: any) => parse("SRVConfCheckResult", v) as SRVConfCheckResult,
	SRV: (v: any) => parse("SRV", v) as SRV,
	AutoconfCheckResult: (v: any) => parse("AutoconfCheckResult", v) as AutoconfCheckResult,
	AutodiscoverCheckResult: (v: any) => parse("AutodiscoverCheckResult", v) as AutodiscoverCheckResult,
	AutodiscoverSRV: (v: any) => parse("AutodiscoverSRV", v) as AutodiscoverSRV,
	PolicyRecord: (v: any) => parse("PolicyRecord", v) as PolicyRecord,
	TLSReportRecord: (v: any) => parse("TLSReportRecord", v) as TLSReportRecord,
	Report: (v: any) => parse("Report", v) as Report,
	TLSRPTDateRange: (v: any) => parse("TLSRPTDateRange", v) as TLSRPTDateRange,
	Result: (v: any) => parse("Result", v) as Result,
	ResultPolicy: (v: any) => parse("ResultPolicy", v) as ResultPolicy,
	Summary: (v: any) => parse("Summary", v) as Summary,
	FailureDetails: (v: any) => parse("FailureDetails", v) as FailureDetails,
	TLSRPTSummary: (v: any) => parse("TLSRPTSummary", v) as TLSRPTSummary,
	DomainFeedback: (v: any) => parse("DomainFeedback", v) as DomainFeedback,
	ReportMetadata: (v: any) => parse("ReportMetadata", v) as ReportMetadata,
	DateRange: (v: any) => parse("DateRange", v) as DateRange,
	PolicyPublished: (v: any) => parse("PolicyPublished", v) as PolicyPublished,
	ReportRecord: (v: any) => parse("ReportRecord", v) as ReportRecord,
	Row: (v: any) => parse("Row", v) as Row,
	PolicyEvaluated: (v: any) => parse("PolicyEvaluated", v) as PolicyEvaluated,
	PolicyOverrideReason: (v: any) => parse("PolicyOverrideReason", v) as PolicyOverrideReason,
	Identifiers: (v: any) => parse("Identifiers", v) as Identifiers,
	AuthResults: (v: any) => parse("AuthResults", v) as AuthResults,
	DKIMAuthResult: (v: any) => parse("DKIMAuthResult", v) as DKIMAuthResult,
	SPFAuthResult: (v: any) => parse("SPFAuthResult", v) as SPFAuthResult,
	DMARCSummary: (v: any) => parse("DMARCSummary", v) as DMARCSummary,
	Reverse: (v: any) => parse("Reverse", v) as Reverse,
	ClientConfigs: (v: any) => parse("ClientConfigs", v) as ClientConfigs,
	ClientConfigsEntry: (v: any) => parse("ClientConfigsEntry", v) as ClientConfigsEntry,
	Msg: (v: any) => parse("Msg", v) as Msg,
	IPDomain: (v: any) => parse("IPDomain", v) as IPDomain,
	WebserverConfig: (v: any) => parse("WebserverConfig", v) as WebserverConfig,
	WebHandler: (v: any) => parse("WebHandler", v) as WebHandler,
	WebStatic: (v: any) => parse("WebStatic", v) as WebStatic,
	WebRedirect: (v: any) => parse("WebRedirect", v) as WebRedirect,
	WebForward: (v: any) => parse("WebForward", v) as WebForward,
	Transport: (v: any) => parse("Transport", v) as Transport,
	TransportSMTP: (v: any) => parse("TransportSMTP", v) as TransportSMTP,
	SMTPAuth: (v: any) => parse("SMTPAuth", v) as SMTPAuth,
	TransportSocks: (v: any) => parse("TransportSocks", v) as TransportSocks,
	EvaluationStat: (v: any) => parse("EvaluationStat", v) as EvaluationStat,
	Evaluation: (v: any) => parse("Evaluation", v) as Evaluation,
	SuppressAddress: (v: any) => parse("SuppressAddress", v) as SuppressAddress,
	TLSResult: (v: any) => parse("TLSResult", v) as TLSResult,
	TLSRPTSuppressAddress: (v: any) => parse("TLSRPTSuppressAddress", v) as TLSRPTSuppressAddress,
	CSRFToken: (v: any) => parse("CSRFToken", v) as CSRFToken,
	DMARCPolicy: (v: any) => parse("DMARCPolicy", v) as DMARCPolicy,
	Align: (v: any) => parse("Align", v) as Align,
	RUA: (v: any) => parse("RUA", v) as RUA,
	Mode: (v: any) => parse("Mode", v) as Mode,
	PolicyType: (v: any) => parse("PolicyType", v) as PolicyType,
	ResultType: (v: any) => parse("ResultType", v) as ResultType,
	Alignment: (v: any) => parse("Alignment", v) as Alignment,
	Disposition: (v: any) => parse("Disposition", v) as Disposition,
	DMARCResult: (v: any) => parse("DMARCResult", v) as DMARCResult,
	PolicyOverride: (v: any) => parse("PolicyOverride", v) as PolicyOverride,
	DKIMResult: (v: any) => parse("DKIMResult", v) as DKIMResult,
	SPFDomainScope: (v: any) => parse("SPFDomainScope", v) as SPFDomainScope,
	SPFResult: (v: any) => parse("SPFResult", v) as SPFResult,
	Localpart: (v: any) => parse("Localpart", v) as Localpart,
	IP: (v: any) => parse("IP", v) as IP,
}

// Admin exports web API functions for the admin web interface. All its methods are
// exported under api/. Function calls require valid HTTP Authentication
// credentials of a user.
let defaultOptions: ClientOptions = {slicesNullable: true, mapsNullable: true, nullableOptional: true}

export class Client {
	private baseURL: string
	public authState: AuthState
	public options: ClientOptions

	constructor() {
		this.authState = {}
		this.options = {...defaultOptions}
		this.baseURL = this.options.baseURL || defaultBaseURL
	}

	withAuthToken(token: string): Client {
		const c = new Client()
		c.authState.token = token
		c.options = this.options
		return c
	}

	withOptions(options: ClientOptions): Client {
		const c = new Client()
		c.authState = this.authState
		c.options = { ...this.options, ...options }
		return c
	}

	// LoginPrep returns a login token, and also sets it as cookie. Both must be
	// present in the call to Login.
	async LoginPrep(): Promise<string> {
		const fn: string = "LoginPrep"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["string"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as string
	}

	// Login returns a session token for the credentials, or fails with error code
	// "user:badLogin". Call LoginPrep to get a loginToken.
	async Login(loginToken: string, password: string): Promise<CSRFToken> {
		const fn: string = "Login"
		const paramTypes: string[][] = [["string"],["string"]]
		const returnTypes: string[][] = [["CSRFToken"]]
		const params: any[] = [loginToken, password]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as CSRFToken
	}

	// Logout invalidates the session token.
	async Logout(): Promise<void> {
		const fn: string = "Logout"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = []
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// CheckDomain checks the configuration for the domain, such as MX, SMTP STARTTLS,
	// SPF, DKIM, DMARC, TLSRPT, MTASTS, autoconfig, autodiscover.
	async CheckDomain(domainName: string): Promise<CheckResult> {
		const fn: string = "CheckDomain"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["CheckResult"]]
		const params: any[] = [domainName]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as CheckResult
	}

	// Domains returns all configured domain names, in UTF-8 for IDNA domains.
	async Domains(): Promise<Domain[] | null> {
		const fn: string = "Domains"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","Domain"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as Domain[] | null
	}

	// Domain returns the dns domain for a (potentially unicode as IDNA) domain name.
	async Domain(domain: string): Promise<Domain> {
		const fn: string = "Domain"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["Domain"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as Domain
	}

	// ParseDomain parses a domain, possibly an IDNA domain.
	async ParseDomain(domain: string): Promise<Domain> {
		const fn: string = "ParseDomain"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["Domain"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as Domain
	}

	// DomainLocalparts returns the encoded localparts and accounts configured in domain.
	async DomainLocalparts(domain: string): Promise<{ [key: string]: string }> {
		const fn: string = "DomainLocalparts"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["{}","string"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: string }
	}

	// Accounts returns the names of all configured accounts.
	async Accounts(): Promise<string[] | null> {
		const fn: string = "Accounts"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","string"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as string[] | null
	}

	// Account returns the parsed configuration of an account.
	async Account(account: string): Promise<{ [key: string]: any }> {
		const fn: string = "Account"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["{}","any"]]
		const params: any[] = [account]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: any }
	}

	// ConfigFiles returns the paths and contents of the static and dynamic configuration files.
	async ConfigFiles(): Promise<[string, string, string, string]> {
		const fn: string = "ConfigFiles"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["string"],["string"],["string"],["string"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [string, string, string, string]
	}

	// MTASTSPolicies returns all mtasts policies from the cache.
	async MTASTSPolicies(): Promise<PolicyRecord[] | null> {
		const fn: string = "MTASTSPolicies"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","PolicyRecord"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as PolicyRecord[] | null
	}

	// TLSReports returns TLS reports overlapping with period start/end, for the given
	// policy domain (or all domains if empty). The reports are sorted first by period
	// end (most recent first), then by policy domain.
	async TLSReports(start: Date, end: Date, policyDomain: string): Promise<TLSReportRecord[] | null> {
		const fn: string = "TLSReports"
		const paramTypes: string[][] = [["timestamp"],["timestamp"],["string"]]
		const returnTypes: string[][] = [["[]","TLSReportRecord"]]
		const params: any[] = [start, end, policyDomain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as TLSReportRecord[] | null
	}

	// TLSReportID returns a single TLS report.
	async TLSReportID(domain: string, reportID: number): Promise<TLSReportRecord> {
		const fn: string = "TLSReportID"
		const paramTypes: string[][] = [["string"],["int64"]]
		const returnTypes: string[][] = [["TLSReportRecord"]]
		const params: any[] = [domain, reportID]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as TLSReportRecord
	}

	// TLSRPTSummaries returns a summary of received TLS reports overlapping with
	// period start/end for one or all domains (when domain is empty).
	// The returned summaries are ordered by domain name.
	async TLSRPTSummaries(start: Date, end: Date, policyDomain: string): Promise<TLSRPTSummary[] | null> {
		const fn: string = "TLSRPTSummaries"
		const paramTypes: string[][] = [["timestamp"],["timestamp"],["string"]]
		const returnTypes: string[][] = [["[]","TLSRPTSummary"]]
		const params: any[] = [start, end, policyDomain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as TLSRPTSummary[] | null
	}

	// DMARCReports returns DMARC reports overlapping with period start/end, for the
	// given domain (or all domains if empty). The reports are sorted first by period
	// end (most recent first), then by domain.
	async DMARCReports(start: Date, end: Date, domain: string): Promise<DomainFeedback[] | null> {
		const fn: string = "DMARCReports"
		const paramTypes: string[][] = [["timestamp"],["timestamp"],["string"]]
		const returnTypes: string[][] = [["[]","DomainFeedback"]]
		const params: any[] = [start, end, domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as DomainFeedback[] | null
	}

	// DMARCReportID returns a single DMARC report.
	async DMARCReportID(domain: string, reportID: number): Promise<DomainFeedback> {
		const fn: string = "DMARCReportID"
		const paramTypes: string[][] = [["string"],["int64"]]
		const returnTypes: string[][] = [["DomainFeedback"]]
		const params: any[] = [domain, reportID]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as DomainFeedback
	}

	// DMARCSummaries returns a summary of received DMARC reports overlapping with
	// period start/end for one or all domains (when domain is empty).
	// The returned summaries are ordered by domain name.
	async DMARCSummaries(start: Date, end: Date, domain: string): Promise<DMARCSummary[] | null> {
		const fn: string = "DMARCSummaries"
		const paramTypes: string[][] = [["timestamp"],["timestamp"],["string"]]
		const returnTypes: string[][] = [["[]","DMARCSummary"]]
		const params: any[] = [start, end, domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as DMARCSummary[] | null
	}

	// LookupIP does a reverse lookup of ip.
	async LookupIP(ip: string): Promise<Reverse> {
		const fn: string = "LookupIP"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["Reverse"]]
		const params: any[] = [ip]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as Reverse
	}

	// DNSBLStatus returns the IPs from which outgoing connections may be made and
	// their current status in DNSBLs that are configured. The IPs are typically the
	// configured listen IPs, or otherwise IPs on the machines network interfaces, with
	// internal/private IPs removed.
	// 
	// The returned value maps IPs to per DNSBL statuses, where "pass" means not listed and
	// anything else is an error string, e.g. "fail: ..." or "temperror: ...".
	async DNSBLStatus(): Promise<{ [key: string]: { [key: string]: string } }> {
		const fn: string = "DNSBLStatus"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["{}","{}","string"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: { [key: string]: string } }
	}

	// DomainRecords returns lines describing DNS records that should exist for the
	// configured domain.
	async DomainRecords(domain: string): Promise<string[] | null> {
		const fn: string = "DomainRecords"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["[]","string"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as string[] | null
	}

	// DomainAdd adds a new domain and reloads the configuration.
	async DomainAdd(domain: string, accountName: string, localpart: string): Promise<void> {
		const fn: string = "DomainAdd"
		const paramTypes: string[][] = [["string"],["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [domain, accountName, localpart]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// DomainRemove removes an existing domain and reloads the configuration.
	async DomainRemove(domain: string): Promise<void> {
		const fn: string = "DomainRemove"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// AccountAdd adds existing a new account, with an initial email address, and
	// reloads the configuration.
	async AccountAdd(accountName: string, address: string): Promise<void> {
		const fn: string = "AccountAdd"
		const paramTypes: string[][] = [["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [accountName, address]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// AccountRemove removes an existing account and reloads the configuration.
	async AccountRemove(accountName: string): Promise<void> {
		const fn: string = "AccountRemove"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [accountName]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// AddressAdd adds a new address to the account, which must already exist.
	async AddressAdd(address: string, accountName: string): Promise<void> {
		const fn: string = "AddressAdd"
		const paramTypes: string[][] = [["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [address, accountName]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// AddressRemove removes an existing address.
	async AddressRemove(address: string): Promise<void> {
		const fn: string = "AddressRemove"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [address]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// SetPassword saves a new password for an account, invalidating the previous password.
	// Sessions are not interrupted, and will keep working. New login attempts must use the new password.
	// Password must be at least 8 characters.
	async SetPassword(accountName: string, password: string): Promise<void> {
		const fn: string = "SetPassword"
		const paramTypes: string[][] = [["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [accountName, password]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// SetAccountLimits set new limits on outgoing messages for an account.
	async SetAccountLimits(accountName: string, maxOutgoingMessagesPerDay: number, maxFirstTimeRecipientsPerDay: number, maxMsgSize: number): Promise<void> {
		const fn: string = "SetAccountLimits"
		const paramTypes: string[][] = [["string"],["int32"],["int32"],["int64"]]
		const returnTypes: string[][] = []
		const params: any[] = [accountName, maxOutgoingMessagesPerDay, maxFirstTimeRecipientsPerDay, maxMsgSize]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// ClientConfigsDomain returns configurations for email clients, IMAP and
	// Submission (SMTP) for the domain.
	async ClientConfigsDomain(domain: string): Promise<ClientConfigs> {
		const fn: string = "ClientConfigsDomain"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["ClientConfigs"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as ClientConfigs
	}

	// QueueList returns the messages currently in the outgoing queue.
	async QueueList(): Promise<Msg[] | null> {
		const fn: string = "QueueList"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","Msg"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as Msg[] | null
	}

	// QueueSize returns the number of messages currently in the outgoing queue.
	async QueueSize(): Promise<number> {
		const fn: string = "QueueSize"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["int32"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as number
	}

	// QueueKick initiates delivery of a message from the queue and sets the transport
	// to use for delivery.
	async QueueKick(id: number, transport: string): Promise<void> {
		const fn: string = "QueueKick"
		const paramTypes: string[][] = [["int64"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [id, transport]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// QueueDrop removes a message from the queue.
	async QueueDrop(id: number): Promise<void> {
		const fn: string = "QueueDrop"
		const paramTypes: string[][] = [["int64"]]
		const returnTypes: string[][] = []
		const params: any[] = [id]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// QueueSaveRequireTLS updates the requiretls field for a message in the queue,
	// to be used for the next delivery.
	async QueueSaveRequireTLS(id: number, requireTLS: boolean | null): Promise<void> {
		const fn: string = "QueueSaveRequireTLS"
		const paramTypes: string[][] = [["int64"],["nullable","bool"]]
		const returnTypes: string[][] = []
		const params: any[] = [id, requireTLS]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// LogLevels returns the current log levels.
	async LogLevels(): Promise<{ [key: string]: string }> {
		const fn: string = "LogLevels"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["{}","string"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: string }
	}

	// LogLevelSet sets a log level for a package.
	async LogLevelSet(pkg: string, levelStr: string): Promise<void> {
		const fn: string = "LogLevelSet"
		const paramTypes: string[][] = [["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [pkg, levelStr]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// LogLevelRemove removes a log level for a package, which cannot be the empty string.
	async LogLevelRemove(pkg: string): Promise<void> {
		const fn: string = "LogLevelRemove"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [pkg]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// CheckUpdatesEnabled returns whether checking for updates is enabled.
	async CheckUpdatesEnabled(): Promise<boolean> {
		const fn: string = "CheckUpdatesEnabled"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["bool"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as boolean
	}

	// WebserverConfig returns the current webserver config
	async WebserverConfig(): Promise<WebserverConfig> {
		const fn: string = "WebserverConfig"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["WebserverConfig"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as WebserverConfig
	}

	// WebserverConfigSave saves a new webserver config. If oldConf is not equal to
	// the current config, an error is returned.
	async WebserverConfigSave(oldConf: WebserverConfig, newConf: WebserverConfig): Promise<WebserverConfig> {
		const fn: string = "WebserverConfigSave"
		const paramTypes: string[][] = [["WebserverConfig"],["WebserverConfig"]]
		const returnTypes: string[][] = [["WebserverConfig"]]
		const params: any[] = [oldConf, newConf]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as WebserverConfig
	}

	// Transports returns the configured transports, for sending email.
	async Transports(): Promise<{ [key: string]: Transport }> {
		const fn: string = "Transports"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["{}","Transport"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: Transport }
	}

	// DMARCEvaluationStats returns a map of all domains with evaluations to a count of
	// the evaluations and whether those evaluations will cause a report to be sent.
	async DMARCEvaluationStats(): Promise<{ [key: string]: EvaluationStat }> {
		const fn: string = "DMARCEvaluationStats"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["{}","EvaluationStat"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as { [key: string]: EvaluationStat }
	}

	// DMARCEvaluationsDomain returns all evaluations for aggregate reports for the
	// domain, sorted from oldest to most recent.
	async DMARCEvaluationsDomain(domain: string): Promise<[Domain, Evaluation[] | null]> {
		const fn: string = "DMARCEvaluationsDomain"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["Domain"],["[]","Evaluation"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [Domain, Evaluation[] | null]
	}

	// DMARCRemoveEvaluations removes evaluations for a domain.
	async DMARCRemoveEvaluations(domain: string): Promise<void> {
		const fn: string = "DMARCRemoveEvaluations"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// DMARCSuppressAdd adds a reporting address to the suppress list. Outgoing
	// reports will be suppressed for a period.
	async DMARCSuppressAdd(reportingAddress: string, until: Date, comment: string): Promise<void> {
		const fn: string = "DMARCSuppressAdd"
		const paramTypes: string[][] = [["string"],["timestamp"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [reportingAddress, until, comment]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// DMARCSuppressList returns all reporting addresses on the suppress list.
	async DMARCSuppressList(): Promise<SuppressAddress[] | null> {
		const fn: string = "DMARCSuppressList"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","SuppressAddress"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as SuppressAddress[] | null
	}

	// DMARCSuppressRemove removes a reporting address record from the suppress list.
	async DMARCSuppressRemove(id: number): Promise<void> {
		const fn: string = "DMARCSuppressRemove"
		const paramTypes: string[][] = [["int64"]]
		const returnTypes: string[][] = []
		const params: any[] = [id]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// DMARCSuppressExtend updates the until field of a suppressed reporting address record.
	async DMARCSuppressExtend(id: number, until: Date): Promise<void> {
		const fn: string = "DMARCSuppressExtend"
		const paramTypes: string[][] = [["int64"],["timestamp"]]
		const returnTypes: string[][] = []
		const params: any[] = [id, until]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// TLSRPTResults returns all TLSRPT results in the database.
	async TLSRPTResults(): Promise<TLSResult[] | null> {
		const fn: string = "TLSRPTResults"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","TLSResult"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as TLSResult[] | null
	}

	// TLSRPTResultsPolicyDomain returns the TLS results for a domain.
	async TLSRPTResultsDomain(isRcptDom: boolean, policyDomain: string): Promise<[Domain, TLSResult[] | null]> {
		const fn: string = "TLSRPTResultsDomain"
		const paramTypes: string[][] = [["bool"],["string"]]
		const returnTypes: string[][] = [["Domain"],["[]","TLSResult"]]
		const params: any[] = [isRcptDom, policyDomain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [Domain, TLSResult[] | null]
	}

	// LookupTLSRPTRecord looks up a TLSRPT record and returns the parsed form, original txt
	// form from DNS, and error with the TLSRPT record as a string.
	async LookupTLSRPTRecord(domain: string): Promise<[TLSRPTRecord | null, string, string]> {
		const fn: string = "LookupTLSRPTRecord"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["nullable","TLSRPTRecord"],["string"],["string"]]
		const params: any[] = [domain]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [TLSRPTRecord | null, string, string]
	}

	// TLSRPTRemoveResults removes the TLS results for a domain for the given day. If
	// day is empty, all results are removed.
	async TLSRPTRemoveResults(isRcptDom: boolean, domain: string, day: string): Promise<void> {
		const fn: string = "TLSRPTRemoveResults"
		const paramTypes: string[][] = [["bool"],["string"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [isRcptDom, domain, day]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// TLSRPTSuppressAdd adds a reporting address to the suppress list. Outgoing
	// reports will be suppressed for a period.
	async TLSRPTSuppressAdd(reportingAddress: string, until: Date, comment: string): Promise<void> {
		const fn: string = "TLSRPTSuppressAdd"
		const paramTypes: string[][] = [["string"],["timestamp"],["string"]]
		const returnTypes: string[][] = []
		const params: any[] = [reportingAddress, until, comment]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// TLSRPTSuppressList returns all reporting addresses on the suppress list.
	async TLSRPTSuppressList(): Promise<TLSRPTSuppressAddress[] | null> {
		const fn: string = "TLSRPTSuppressList"
		const paramTypes: string[][] = []
		const returnTypes: string[][] = [["[]","TLSRPTSuppressAddress"]]
		const params: any[] = []
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as TLSRPTSuppressAddress[] | null
	}

	// TLSRPTSuppressRemove removes a reporting address record from the suppress list.
	async TLSRPTSuppressRemove(id: number): Promise<void> {
		const fn: string = "TLSRPTSuppressRemove"
		const paramTypes: string[][] = [["int64"]]
		const returnTypes: string[][] = []
		const params: any[] = [id]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// TLSRPTSuppressExtend updates the until field of a suppressed reporting address record.
	async TLSRPTSuppressExtend(id: number, until: Date): Promise<void> {
		const fn: string = "TLSRPTSuppressExtend"
		const paramTypes: string[][] = [["int64"],["timestamp"]]
		const returnTypes: string[][] = []
		const params: any[] = [id, until]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
	}

	// LookupCid turns an ID from a Received header into a cid as used in logging.
	async LookupCid(recvID: string): Promise<string> {
		const fn: string = "LookupCid"
		const paramTypes: string[][] = [["string"]]
		const returnTypes: string[][] = [["string"]]
		const params: any[] = [recvID]
		return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as string
	}
}

export const defaultBaseURL = (function() {
	let p = location.pathname
	if (p && p[p.length - 1] !== '/') {
		let l = location.pathname.split('/')
		l = l.slice(0, l.length - 1)
		p = '/' + l.join('/') + '/'
	}
	return location.protocol + '//' + location.host + p + 'api/'
})()

// NOTE: code below is shared between github.com/mjl-/sherpaweb and github.com/mjl-/sherpats.
// KEEP IN SYNC.

export const supportedSherpaVersion = 1

export interface Section {
	Name: string
	Docs: string
	Functions: Function[]
	Sections: Section[]
	Structs: Struct[]
	Ints: Ints[]
	Strings: Strings[]
	Version: string // only for top-level section
	SherpaVersion: number // only for top-level section
	SherpadocVersion: number // only for top-level section
}

export interface Function {
	Name: string
	Docs: string
	Params: Arg[]
	Returns: Arg[]
}

export interface Arg {
	Name: string
	Typewords: string[]
}

export interface Struct {
	Name: string
	Docs: string
	Fields: Field[]
}

export interface Field {
	Name: string
	Docs: string
	Typewords: string[]
}

export interface Ints {
	Name: string
	Docs: string
	Values: {
		Name: string
		Value: number
		Docs: string
	}[] | null
}

export interface Strings {
	Name: string
	Docs: string
	Values: {
		Name: string
		Value: string
		Docs: string
	}[] | null
}

export type NamedType = Struct | Strings | Ints
export type TypenameMap = { [k: string]: NamedType }

// verifyArg typechecks "v" against "typewords", returning a new (possibly modified) value for JSON-encoding.
// toJS indicate if the data is coming into JS. If so, timestamps are turned into JS Dates. Otherwise, JS Dates are turned into strings.
// allowUnknownKeys configures whether unknown keys in structs are allowed.
// types are the named types of the API.
export const verifyArg = (path: string, v: any, typewords: string[], toJS: boolean, allowUnknownKeys: boolean, types: TypenameMap, opts: ClientOptions): any => {
	return new verifier(types, toJS, allowUnknownKeys, opts).verify(path, v, typewords)
}

export const parse = (name: string, v: any): any => verifyArg(name, v, [name], true, false, types, defaultOptions)

class verifier {
	constructor(private types: TypenameMap, private toJS: boolean, private allowUnknownKeys: boolean, private opts: ClientOptions) {
	}

	verify(path: string, v: any, typewords: string[]): any {
		typewords = typewords.slice(0)
		const ww = typewords.shift()

		const error = (msg: string) => {
			if (path != '') {
				msg = path + ': ' + msg
			}
			throw new Error(msg)
		}

		if (typeof ww !== 'string') {
			error('bad typewords')
			return // should not be necessary, typescript doesn't see error always throws an exception?
		}
		const w: string = ww

		const ensure = (ok: boolean, expect: string): any => {
			if (!ok) {
				error('got ' + JSON.stringify(v) + ', expected ' + expect)
			}
			return v
		}

		switch (w) {
		case 'nullable':
			if (v === null || v === undefined && this.opts.nullableOptional) {
				return v
			}
			return this.verify(path, v, typewords)
		case '[]':
			if (v === null && this.opts.slicesNullable || v === undefined && this.opts.slicesNullable && this.opts.nullableOptional) {
				return v
			}
			ensure(Array.isArray(v), "array")
			return v.map((e: any, i: number) => this.verify(path + '[' + i + ']', e, typewords))
		case '{}':
			if (v === null && this.opts.mapsNullable || v === undefined && this.opts.mapsNullable && this.opts.nullableOptional) {
				return v
			}
			ensure(v !== null || typeof v === 'object', "object")
			const r: any = {}
			for (const k in v) {
				r[k] = this.verify(path + '.' + k, v[k], typewords)
			}
			return r
		}

		ensure(typewords.length == 0, "empty typewords")
		const t = typeof v
		switch (w) {
		case 'any':
			return v
		case 'bool':
			ensure(t === 'boolean', 'bool')
			return v
		case 'int8':
		case 'uint8':
		case 'int16':
		case 'uint16':
		case 'int32':
		case 'uint32':
		case 'int64':
		case 'uint64':
			ensure(t === 'number' && Number.isInteger(v), 'integer')
			return v
		case 'float32':
		case 'float64':
			ensure(t === 'number', 'float')
			return v
		case 'int64s':
		case 'uint64s':
			ensure(t === 'number' && Number.isInteger(v) || t === 'string', 'integer fitting in float without precision loss, or string')
			return '' + v
		case 'string':
			ensure(t === 'string', 'string')
			return v
		case 'timestamp':
			if (this.toJS) {
				ensure(t === 'string', 'string, with timestamp')
				const d = new Date(v)
				if (d instanceof Date && !isNaN(d.getTime())) {
					return d
				}
				error('invalid date ' + v)
			} else {
				ensure(t === 'object' && v !== null, 'non-null object')
				ensure(v.__proto__ === Date.prototype, 'Date')
				return v.toISOString()
			}
		}

		// We're left with named types.
		const nt = this.types[w]
		if (!nt) {
			error('unknown type ' + w)
		}
		if (v === null) {
			error('bad value ' + v + ' for named type ' + w)
		}

		if (structTypes[nt.Name]) {
			const t = nt as Struct
			if (typeof v !== 'object') {
				error('bad value ' + v + ' for struct ' + w)
			}

			const r: any = {}
			for (const f of t.Fields) {
				r[f.Name] = this.verify(path + '.' + f.Name, v[f.Name], f.Typewords)
			}
			// If going to JSON also verify no unknown fields are present.
			if (!this.allowUnknownKeys) {
				const known: { [key: string]: boolean } = {}
				for (const f of t.Fields) {
					known[f.Name] = true
				}
				Object.keys(v).forEach((k) => {
					if (!known[k]) {
						error('unknown key ' + k + ' for struct ' + w)
					}
				})
			}
			return r
		} else if (stringsTypes[nt.Name]) {
			const t = nt as Strings
			if (typeof v !== 'string') {
				error('mistyped value ' + v + ' for named strings ' + t.Name)
			}
			if (!t.Values || t.Values.length === 0) {
				return v
			}
			for (const sv of t.Values) {
				if (sv.Value === v) {
					return v
				}
			}
			error('unknkown value ' + v + ' for named strings ' + t.Name)
		} else if (intsTypes[nt.Name]) {
			const t = nt as Ints
			if (typeof v !== 'number' || !Number.isInteger(v)) {
				error('mistyped value ' + v + ' for named ints ' + t.Name)
			}
			if (!t.Values || t.Values.length === 0) {
				return v
			}
			for (const sv of t.Values) {
				if (sv.Value === v) {
					return v
				}
			}
			error('unknkown value ' + v + ' for named ints ' + t.Name)
		} else {
			throw new Error('unexpected named type ' + nt)
		}
	}
}


export interface ClientOptions {
	baseURL?: string
	aborter?: {abort?: () => void}
	timeoutMsec?: number
	skipParamCheck?: boolean
	skipReturnCheck?: boolean
	slicesNullable?: boolean
	mapsNullable?: boolean
	nullableOptional?: boolean
	csrfHeader?: string
	login?: (reason: string) => Promise<string>
}

export interface AuthState {
	token?: string // For csrf request header.
	loginPromise?: Promise<void> // To let multiple API calls wait for a single login attempt, not each opening a login popup.
}

const _sherpaCall = async (baseURL: string, authState: AuthState, options: ClientOptions, paramTypes: string[][], returnTypes: string[][], name: string, params: any[]): Promise<any> => {
	if (!options.skipParamCheck) {
		if (params.length !== paramTypes.length) {
			return Promise.reject({ message: 'wrong number of parameters in sherpa call, saw ' + params.length + ' != expected ' + paramTypes.length })
		}
		params = params.map((v: any, index: number) => verifyArg('params[' + index + ']', v, paramTypes[index], false, false, types, options))
	}
	const simulate = async (json: string) => {
		const config = JSON.parse(json || 'null') || {}
		const waitMinMsec = config.waitMinMsec || 0
		const waitMaxMsec = config.waitMaxMsec || 0
		const wait = Math.random() * (waitMaxMsec - waitMinMsec)
		const failRate = config.failRate || 0
		return new Promise<void>((resolve, reject) => {
			if (options.aborter) {
				options.aborter.abort = () => {
					reject({ message: 'call to ' + name + ' aborted by user', code: 'sherpa:aborted' })
					reject = resolve = () => { }
				}
			}
			setTimeout(() => {
				const r = Math.random()
				if (r < failRate) {
					reject({ message: 'injected failure on ' + name, code: 'server:injected' })
				} else {
					resolve()
				}
				reject = resolve = () => { }
			}, waitMinMsec + wait)
		})
	}
	// Only simulate when there is a debug string. Otherwise it would always interfere
	// with setting options.aborter.
	let json: string = ''
	try {
		json = window.localStorage.getItem('sherpats-debug') || ''
	} catch (err) {}
	if (json) {
		await simulate(json)
	}

	const fn = (resolve: (v: any) => void, reject: (v: any) => void) => {
		let resolve1 = (v: any) => {
			resolve(v)
			resolve1 = () => { }
			reject1 = () => { }
		}
		let reject1 = (v: { code: string, message: string }) => {
			if ((v.code === 'user:noAuth' || v.code === 'user:badAuth')  && options.login) {
				const login = options.login
				if (!authState.loginPromise) {
					authState.loginPromise = new Promise((aresolve, areject) => {
						login(v.code === 'user:badAuth' ? (v.message || '') : '')
						.then((token) => {
							authState.token = token
							authState.loginPromise = undefined
							aresolve()
						}, (err: any) => {
							authState.loginPromise = undefined
							areject(err)
						})
					})
				}
				authState.loginPromise
				.then(() => {
					fn(resolve, reject)
				}, (err: any) => {
					reject(err)
				})
				return
			}
			reject(v)
			resolve1 = () => { }
			reject1 = () => { }
		}

		const url = baseURL + name
		const req = new window.XMLHttpRequest()
		if (options.aborter) {
			options.aborter.abort = () => {
				req.abort()
				reject1({ code: 'sherpa:aborted', message: 'request aborted' })
			}
		}
		req.open('POST', url, true)
		if (options.csrfHeader && authState.token) {
			req.setRequestHeader(options.csrfHeader, authState.token)
		}
		if (options.timeoutMsec) {
			req.timeout = options.timeoutMsec
		}
		req.onload = () => {
			if (req.status !== 200) {
				if (req.status === 404) {
					reject1({ code: 'sherpa:badFunction', message: 'function does not exist' })
				} else {
					reject1({ code: 'sherpa:http', message: 'error calling function, HTTP status: ' + req.status })
				}
				return
			}

			let resp: any
			try {
				resp = JSON.parse(req.responseText)
			} catch (err) {
				reject1({ code: 'sherpa:badResponse', message: 'bad JSON from server' })
				return
			}
			if (resp && resp.error) {
				const err = resp.error
				reject1({ code: err.code, message: err.message })
				return
			} else if (!resp || !resp.hasOwnProperty('result')) {
				reject1({ code: 'sherpa:badResponse', message: "invalid sherpa response object, missing 'result'" })
				return
			}

			if (options.skipReturnCheck) {
				resolve1(resp.result)
				return
			}
			let result = resp.result
			try {
				if (returnTypes.length === 0) {
					if (result) {
						throw new Error('function ' + name + ' returned a value while prototype says it returns "void"')
					}
				} else if (returnTypes.length === 1) {
					result = verifyArg('result', result, returnTypes[0], true, true, types, options)
				} else {
					if (result.length != returnTypes.length) {
						throw new Error('wrong number of values returned by ' + name + ', saw ' + result.length + ' != expected ' + returnTypes.length)
					}
					result = result.map((v: any, index: number) => verifyArg('result[' + index + ']', v, returnTypes[index], true, true, types, options))
				}
			} catch (err) {
				let errmsg = 'bad types'
				if (err instanceof Error) {
					errmsg = err.message
				}
				reject1({ code: 'sherpa:badTypes', message: errmsg })
			}
			resolve1(result)
		}
		req.onerror = () => {
			reject1({ code: 'sherpa:connection', message: 'connection failed' })
		}
		req.ontimeout = () => {
			reject1({ code: 'sherpa:timeout', message: 'request timeout' })
		}
		req.setRequestHeader('Content-Type', 'application/json')
		try {
			req.send(JSON.stringify({ params: params }))
		} catch (err) {
			reject1({ code: 'sherpa:badData', message: 'cannot marshal to JSON' })
		}
	}
	return await new Promise(fn)
}

}
