jmapc

package module
v0.12.0 Latest Latest
Warning

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

Go to latest
Published: Sep 6, 2026 License: MIT Imports: 17 Imported by: 0

README

English | 日本語




jmapc


jmapc is a JMAP compiler: you write the query, it writes the client.

GitHub Workflow Status GitHub Release Go Documentation Deepwiki Documentation

jmapc generates type-safe code from JMAP, in Go, Rust or TypeScript. Here's how it works:

  1. You write queries in JMAP.
  2. You run jmapc to generate code with type-safe interfaces to those queries.
  3. You write application code that calls the generated code.

Motivation

JMAP is built around one idea. A request carries several method calls, and a call may refer to the result of an earlier one, so a chain of dependent operations costs a single round trip:

{
  "using": [
    "urn:ietf:params:jmap:core",
    "urn:ietf:params:jmap:mail"
  ],
  "methodCalls": [
    [
      "Email/query",
      {
        "filter": {
          "inMailbox": "mbx1"
        }
      },
      "search"
    ],
    [
      "Email/get",
      {
        "#ids": {
          "resultOf": "search",
          "name": "Email/query",
          "path": "/ids"
        }
      },
      "fetch"
    ]
  ]
}

The ids never come back to the client, which is why a JMAP client does not look like a REST client, with a type per resource and a method per path.

Most clients expose this through a builder, which means learning JMAP and learning the builder. But the query is the part you care about; the client is not. So write the query, and let jmapc write the client — an approach it takes from sqlc.

Writing the query is all you do; jmapc takes on the parts that are tedious by hand and easy to get wrong.

  • Linting the query
  • A type-safe response
  • Exhaustive error handling

Result references are checked against the methods they point at, arguments against the data model, and property names against the type, so a misspelling fails the build before it ever reaches the server. The response decodes into a struct holding exactly the properties the query asked for, with no map[string]any to walk, so it is type-safe. JMAP fails at three levels — request, method, and record. The record level arrives as HTTP 200, which is easy to miss, but generated code checks it.

Install

You generate the client with go generate, so record it in the module that uses it:

go get -tool github.com/linyows/jmapc/cmd/jmapc

That pins a version in go.mod, and go tool jmapc runs it. Everyone who builds the project — and CI — then generates with the same version, which matters for a tool whose output is committed.

//go:generate go tool jmapc generate

To put it on your PATH instead:

go install github.com/linyows/jmapc/cmd/jmapc@latest

Or take a binary from the releases, which is how a Rust or TypeScript project installs it, having no Go toolchain to run go tool with.

Use

The file name is the name of the function to generate.

{
  "_doc": "ListInboxEmails returns the newest emails in one mailbox.",

  "methodCalls": [
    ["Email/query", {
      "_comment": "Find the ids of the matching emails.",
      "filter": {"inMailbox": "{{mailboxId}}"},
      "sort": [{"property": "receivedAt", "isAscending": false}],
      "limit": "{{limit}}"
    }, "search"],

    ["Email/get", {
      "_comment": "Fetch the message from its id.",
      "#ids": {"resultOf": "search", "name": "Email/query", "path": "/ids"},
      "properties": ["id", "subject", "from", "receivedAt"]
    }, "fetch"]
  ],

  "_returns": "fetch"
}

(queries/ListInboxEmails.jmap.json)

Generate:

jmapc generate                 # or: go generate ./...

Use it:

c := jmapc.New(jmapc.WellKnownURL("example.com"), jmapc.WithBearerToken(token))

res, err := jmapq.ListInboxEmails(ctx, c, jmapq.ListInboxEmailsParams{
	MailboxID: inbox,
	Limit:     25,
})
if err != nil {
	return err
}
for _, email := range res.List {
	fmt.Println(email.ReceivedAt, email.From[0].Email, *email.Subject)
}

res.List is []ListInboxEmailsFetchEmail, holding the four properties the query asked for and nothing else. Ask for another property and the struct grows; ask for one that does not exist and the build fails, with a suggestion.

bodyProperties narrows the parts of a message the same way, reaching through their sub-parts, and a property naming a header field is typed by the form it names: header:List-Id:asText is a *string, header:To:asAddresses a []jmapc.EmailAddress.

Generated names

The file name determines every name in the generated file, so it has to be a Go identifier: letters, digits and underscores, not starting with a digit. ListInboxEmails.jmap.json gives:

Generated Name
The function ListInboxEmails
Its parameters, where the query leaves any open ListInboxEmailsParams
A record whose properties the query narrows ListInboxEmailsFetchEmail, after the call id fetch, and ListInboxEmailsFetchEmailBodyPart for a narrowed body part
The response to a call returning that record ListInboxEmailsFetchResponse, after the call id fetch
The result, where _returns names no call ListInboxEmailsResult
The function that follows changes, where the query is watched SyncEmailsWatch
The walk over the parts of an answer, where the query is paged SearchEmailsPages
The file listinboxemails_gen.go

The call ids are the names in the generated code: a result holds one field per call, named after the id the query gave it, and the record and response types of a call that narrows are named the same way. Nothing is numbered by position, since a call id is unique within a request already and inserting a call ahead of another would otherwise move a name onto a different shape:

["Email/query", {...}, "search"],
["Email/get",   {...}, "fetch"]
res.Search.IDs      // the Email/query response
res.Fetch.List      // the Email/get response

A call id that is not an identifier — RFC 8620 allows any string — falls back to the method it invokes.

A call the query does not narrow answers with the shared type instead, so SendEmail returns *jmapc.EmailSubmissionSetResponse. Two queries in one package cannot take the same name, and a generated type whose name is already taken gains a number: ListInboxEmailsFetchEmail2.

Two calls of one query that read the same type through the same method and ask for the same properties describe one record, so they share one type, named after the first of them. Two names for one shape would make a caller convert between them to hand a record from one call to a function written for the other. Inserting a call that reads that same shape ahead of both moves the name to the new call, which the build reports; the shape a name stands for does not change.

A /set that creates gets a constant for each name it gives a record, since the response reports the record back under that name:

["Mailbox/set", {"create": {"newMailbox": {"name": "{{name}}"}}}, "make"]
res, err := jmapq.CreateMailbox(ctx, c, jmapq.CreateMailboxParams{Name: name})
...
created := res.Created[jmapq.CreateMailboxNewMailbox]

Without it the name appears in two files with no link between them, and renaming it in the query still builds: the lookup misses at run time instead. Rust writes CREATE_MAILBOX_NEW_MAILBOX and TypeScript createMailboxNewMailbox. A creation id the query leaves to the caller — {"{{creationId}}": ...} — has no constant, since the caller already has the name.

A query with no open parameters takes no Params argument at all — MailQuota(ctx, c), not MailQuota(ctx, c, MailQuotaParams{}) — so adding the first {{param}} to a query already in use changes the generated function's arity and breaks every call site. That is a deliberate trade for the common case of a query with no parameters reading like a plain function call, not an oversight.

Rust writes the function and its module in snake_case — list_inbox_emails in list_inbox_emails.rs — and keeps the type names above, except that an initialism becomes a word, since that is how Rust spells one: a UTCDate is a UtcDate. Properties are snake_case, with a serde rename wherever that is not the name on the wire.

TypeScript lowercases the first letter of the function and of the file — listInboxEmails in listInboxEmails.ts — and keeps the type names too.

Examples

example/queries holds twenty-five of these, over mail, contacts, calendars, sharing and filtering: searching, syncing from a known state, sending, creating a contact card, moving one occurrence of a recurring meeting without touching the rest of the series.

Rust

The same queries generate a Rust client:

jmapc generate -lang rust -out src/jmapq
use jmapq::list_inbox_emails::{list_inbox_emails, ListInboxEmailsParams};
use jmapq::Client;

let client = Client::with_bearer_token("https://example.com/.well-known/jmap", http, token);

let res = list_inbox_emails(&client, ListInboxEmailsParams {
    mailbox_id: inbox,
    limit: 25,
})
.await?;
for email in &res.list {
    println!("{} {:?}", email.received_at, email.subject);
}

The runtime comes with it — client.rs, types.rs, and the mod.rs that declares them beside the queries — so mod jmapq; is the whole of what a crate has to add. The generated code requires serde and serde_json and nothing else. Transmission is a Transport you implement over whichever HTTP client the program already has, so no HTTP stack, no TLS backend and no async runtime is added with it:

struct Http(reqwest::Client);

impl Transport for Http {
    async fn send(&self, req: HttpRequest) -> Result<HttpResponse, TransportError> {
        let mut out = self.0.request(req.method.parse()?, &req.url);
        for (name, value) in req.headers {
            out = out.header(name, value);
        }
        if let Some(body) = req.body {
            out = out.body(body);
        }
        let res = out.send().await?;
        Ok(HttpResponse {
            status: res.status().as_u16(),
            content_type: res
                .headers()
                .get("content-type")
                .and_then(|v| v.to_str().ok())
                .unwrap_or("")
                .to_string(),
            body: res.bytes().await?.to_vec(),
        })
    }
}

That is also where authentication that a bearer token does not cover belongs — a signature over the request, a token refreshed on expiry — since the transport is the last stage before a request is sent.

A nullable property is an Option, so subject is Option<String>. A union of shapes is an enum: a filter is Option<FilterOperatorOrEmailFilterCondition>, untagged, where Go has a struct of the same name with a field per shape. The primitives that carry a format rather than a shape are named aliases of String, so an Id and a TimeZoneId are distinguishable in a signature. And a record derives Default, so a type with fifty optional properties is built by naming the two that differ from the default and omitting the rest.

The generated code is already formatted the way rustfmt formats it, so cargo fmt over the crate changes nothing.

TypeScript

The same queries generate a TypeScript client:

jmapc generate -lang typescript -out src/jmapq
import { Client } from "./jmapq/client.js"
import { listInboxEmails } from "./jmapq/listInboxEmails.js"

const client = new Client("https://example.com/.well-known/jmap", { auth: token })

const res = await listInboxEmails(client, { mailboxId: inbox, limit: 25 })
for (const email of res.list) {
  console.log(email.receivedAt, email.from?.[0].email, email.subject)
}

The runtime comes with it — client.ts and types.ts are generated alongside the queries — so the output has no dependencies. The only platform requirement is fetch.

TypeScript expresses some things more precisely than Go. A nullable property is a union rather than a pointer, so subject is string | null. A union of shapes is written as one: a filter is FilterOperator | EmailFilterCondition | null, where Go has a struct with a field per shape. And the primitives that carry a format rather than a shape are named aliases of string, so an Id and a TimeZoneId cannot be swapped by accident.

Writing a query

A query file is a JMAP Request object, exactly as RFC 8620 defines it, plus four members jmapc reads and the JMAP server never sees.

A member beginning with an underscore is one the generator reads; everything else is the request as RFC 8620 defines it.

Member
methodCalls The calls, as [name, arguments, callId]. Required.
using The capabilities the request declares. Optional: derived from the methods called.
_doc The generated function's documentation. Optional.
_returns The call whose response the function returns. Optional: without it, every response is returned.
_createdIds Carry the creation ids of an earlier request in, and this request's out. Optional; see below.
_watches The call a generated client follows the changes of, so that it catches up whenever the server reports a change. Optional; see Push.
_pages The call a generated walk advances, so that a result returned one part at a time can be read in full. Optional; see Walking an answer that does not fit in one request.
_comment Why a call is there. Goes in that call's arguments; see below.

A query file is plain JSON, so jq can read it and an editor can check it. To record why a call is there, give its arguments a _comment.

Parameters

Write {{name}} where a value is left to the caller. Its Go type comes from the argument it stands in for, so {{limit}} in limit is a jmapc.UnsignedInt and {{mailboxId}} in inMailbox is a jmapc.ID. Use the same name twice and it becomes one field, checked for agreeing on its type.

An argument that may take either of two shapes becomes a struct with a field per shape, of which exactly one is set. A filter is where that matters, since it is either a boolean operator or a condition on the type being queried: {{filter}} in filter is a jmapc.FilterOperatorOrEmailFilterCondition.

jmapq.Search(ctx, c, jmapq.SearchParams{
	Filter: jmapc.FilterOperatorOrEmailFilterCondition{
		EmailFilterCondition: &jmapc.EmailFilterCondition{Text: "invoice"},
	},
})

Setting no field, or more than one, is an error where the request is encoded rather than something the server has to refuse. The conditions a FilterOperator combines stay []any: which condition type they hold depends on the type being queried, and the operator itself is written once for all of them.

A map key may be a parameter too, which is how a /set names the record to change:

["Email/set", {"update": {"{{emailId}}": {"keywords/$seen": true}}}, "mark"]

The braces are used rather than a $ prefix because JMAP keywords are themselves written with one, as in $seen.

An argument the caller may leave out

Write {{name?}} where the caller may leave the argument out altogether:

["Email/changes", {"sinceState": "{{sinceState}}", "maxChanges": "{{maxChanges?}}"}, "changes"]

Nothing supplied means the argument is not in the request, which is not the same as sending null. RFC 8620 makes the difference twice over: maxChanges absent is no cap, while maxChanges: 0 asks for nothing at all; and in a PatchObject a pointer set to null removes the property while a pointer that is not there leaves it alone. Without this, each argument that is only sometimes sent would need a query of its own, and n of them would need 2ⁿ.

The caller says "left out" the way the language already does. Go takes a pointer, or nothing where the type has a nil of its own:

limit := jmapc.UnsignedInt(25)
jmapq.FindPeople(ctx, c, jmapq.FindPeopleParams{Phrase: "ada", Limit: &limit})
jmapq.FindPeople(ctx, c, jmapq.FindPeopleParams{Phrase: "ada"}) // no limit argument

Rust wraps it in an Option, TypeScript makes the member optional (limit?: number), and jmapc run leaves the argument out when no -p names it.

Only a whole argument of a method call may be left out, and only where the parameter standing for it is used nowhere else, so that leaving it out has one meaning: this member is not there. A parameter inside a filter or an array is part of a larger value, and dropping it would leave a question the query does not answer, since an empty AND and no filter at all are different requests. For a filter whose shape varies, hand the whole filter over as one parameter instead.

Creation ids across requests

Referring to #draft within one request needs nothing: the server resolves it. Carrying a reference from one request into the next needs the ids to be carried between them, which _createdIds does.

{
  "_createdIds": true,
  "methodCalls": [
    ["Mailbox/set", {"create": {"box": {"name": "{{name}}"}}}, "make"],
    ["Email/set", {"update": {"{{emailId}}": {"mailboxIds/#box": true}}}, "file"]
  ]
}

The generated function takes them and reports them:

res, err := jmapq.FileIntoNewMailbox(ctx, c, params, carried)
// res.CreatedIDs goes to the next request.

RFC 8620 has this for proxies, which split one request across servers and need the references to still resolve. A query using it returns every response rather than one, since the ids belong to the request rather than to any call in it.

Account ids

Leave accountId out and the generated function fills it in from the primary account of the session, looking the session up once. Write "{{accountId}}" to make it a parameter instead.

Verification

Everything below is a compile-time failure rather than a server round trip:

  • the method exists, and is spelled the way the specification spells it
  • every argument belongs to the method, with the type the method requires
  • a back reference points at an earlier call, names that call's method correctly, and selects a value the target argument can accept
  • filter conditions are checked against the type being queried, including the ones nested inside AND, OR, and NOT operators
  • properties names properties the type has, and bodyProperties names properties an EmailBodyPart has
  • a property naming a header field asks for a parsed form the specification defines, so header:List-Id:asText is a string and header:To:asAddresses a list of addresses
  • a PatchObject points at properties the record being patched actually has, and sets them to values of the right type, its keys written the way RFC 8620 writes them: the leading / of the pointer is implicit, so a keyword is set at keywords/$seen rather than at /keywords/$seen
  • sort names properties the type can actually be sorted by, and supplies the extra member a comparator like hasKeyword needs
  • a property whose specification fixes the values it may take is given one of them, whether it is a string or the keys of a set like a participant's roles
  • ids, dates, and integers are well formed
  • the capabilities the request declares cover the methods it calls
  • a watched call is one that reports what changed since a state, and the state it continues from is supplied by the loop rather than written into the query
  • a paged call is one that returns part of a longer result and reports where the rest is, and where the next request starts is supplied by the walk

A misspelling produces a suggestion:

queries/BadQuery.jmap.json: methodCalls[0].arguments.filter.hasAttachmnt: EmailFilterCondition has no property "hasAttachmnt"
	did you mean "hasAttachment"?
queries/BadQuery.jmap.json: methodCalls[1].arguments.#ids.name: the referenced call is Email/query, but the reference names Email/get
	call "c0" invokes Email/query

Two queries that differ only in what they call their parameters and their calls are one query written twice, and jmapc says so rather than failing:

jmapc: ListArchiveEmails, ListInboxEmails are the same query under different names; one of them would do for all of them

Both are generated all the same, since a project may want two names for one request. It is worth knowing about because each name produces a set of generated types of its own.

jmapc check runs the checks without writing anything.

What only the server can report

Everything above is what the specifications say. What they leave to the server — which capabilities it has, which accounts it holds, how much it accepts in one request — a build cannot know, and a query that is right about JMAP and wrong about the server it runs against fails at run time. -session checks against a running server:

jmapc check -session jmap.example.com -token $JMAP_TOKEN
checked 25 queries against https://jmap.example.com/api/, as someone@example.com

What it reports:

  • a capability the request declares and the server does not advertise
  • an account the query names that the session does not hold, an account the session cannot fill in because it has no primary account for the capability, and an account that does not support what the call needs
  • more calls than maxCallsInRequest, more records than maxObjectsInGet, more changes than maxObjectsInSet, a request already larger than maxSizeRequest before its parameters are filled in
  • a collation the server does not compare strings with

What the query leaves to its caller is not checked: a parameter standing for a list of ids may be any length, and an assumption about it would report a problem in a query that is correct.

The session URL is the one value not read from the environment — -token and -user fall back to $JMAP_TOKEN and $JMAP_USER — because a check that reaches the network should be requested on the command line rather than triggered by whatever the environment happens to hold.

Editor support

The checks above run when jmapc does. Most of them can run while the query is being typed instead, because they are checks on the file itself, and a JSON file that names a schema is one an editor can already check and complete.

jmapc schema -out jmapc.schema.json

That writes a JSON Schema for the catalogue, vendor extensions and all. Point a query file at it:

{
  "$schema": "../jmapc.schema.json",
  "methodCalls": [["Email/query", {"filter": {"inMailbox": "{{mailboxId}}"}}, "search"]]
}

or point the editor at every query at once, which in VS Code is:

{
  "json.schemas": [
    {"fileMatch": ["*.jmap.json"], "url": "./jmapc.schema.json"}
  ]
}

Either way the editor completes a method name, offers the arguments that method takes and the properties the type has, and underlines a misspelling where it was written. A filter nested inside an AND is checked like one outside it, a comparator offers the properties the type can actually be sorted by, and a {{parameter}} is accepted anywhere a value goes.

What a schema cannot say is the part that depends on another call: that a back reference names an earlier call and selects a value the argument accepts. That stays jmapc's to check, which is why the editor is a first pass rather than a replacement for the build.

Sending a query

A query is worth trying before there is any code that calls it, so jmapc run sends one and prints what came back.

jmapc run ListInboxEmails -p mailboxId=mbx1 -p limit=25

A value is written the way its type requires. A String or an Id is the text itself, so nothing has to be quoted past the shell, and anything with a shape is JSON. A value the type does not accept is refused before anything is sent:

jmapc: parameter limit: "soon" is not a whole number

The server comes from -session, which takes the session URL or the host to find it under, and the credentials from -token or -user. Each falls back to an environment variable — $JMAP_SESSION_URL, $JMAP_TOKEN, $JMAP_USER — which is what keeps a token out of shell history. The account id a query leaves out is looked up in the session, exactly as the generated function looks it up, and -account overrides it.

-dry-run prints the request rather than sending it — the same request the generated function builds, which is the thing to look at when a server answers something unexpected:

jmapc run MarkEmailRead -dry-run -p emailId=m1
{
  "using": [
    "urn:ietf:params:jmap:core",
    "urn:ietf:params:jmap:mail"
  ],
  "methodCalls": [
    [
      "Email/set",
      {
        "accountId": "ACCOUNT_ID",
        "update": {
          "m1": {
            "keywords/$seen": true
          }
        }
      },
      "mark"
    ]
  ]
}

The account id is the one value a dry run cannot know, since it comes from a session it never fetches, so ACCOUNT_ID stands in for it and the run says so on standard error.

A run reads the response the way generated code does: a /set that answers 200 with a refusal in it is an error here too, printed after the response that carries it.

Configuration

Flags, or a jmapc.json beside your module:

{
  "queries": "queries",
  "out": "internal/jmapq",
  "package": "jmapq",
  "schemas": ["schema/notes.json"]
}

Errors at run time

JMAP fails at two levels, and so does the runtime.

A request-level failure, where the server rejected the request as a whole, is a *jmapc.RequestError carrying the problem type from RFC 8620 §3.6.1. The client catches some of these before sending: a capability the session does not advertise, or more calls than the server accepts.

A method-level failure is a jmapc.MethodErrors. JMAP runs the calls it can, so the response comes back alongside the error, and each error names the method and call id that failed rather than the bare "error" the wire format carries.

A generated function returns the same thing: the calls the server answered are decoded, the ones it did not run are left at their zero value, and the result is returned with the error. A chained query fails this way routinely — the call another depends on succeeds, and the dependent call cannot resolve its reference — and the first call's response usually explains why:

res, err := jmapq.DestroyThread(ctx, c, params)
if err != nil {
    if len(res.ThreadGet.NotFound) > 0 {
        return fmt.Errorf("no such thread: %s", res.ThreadGet.NotFound[0])
    }
    return err
}

The exception is a query naming one call in _returns: that call is the whole of the answer, so if it is the one that failed, there is nothing to return and the result is nil.

TypeScript throws rather than returning, so the decoded response is attached to the error. MethodErrors carries the response it came from, and result holds as much of what the query returns as the server answered. Read it as a Partial, since a call the server would not run is not in it at all:

try {
  await destroyThread(client, params)
} catch (e) {
  if (e instanceof MethodErrors) {
    const partial = e.result as Partial<DestroyThreadResult>
    if (partial.threadGet?.notFound?.length) {
      throw new Error(`no such thread: ${partial.threadGet.notFound[0]}`)
    }
  }
  throw e
}

Rust returns an Err, and attaches it there: MethodErrors::result returns the result the query would have returned, with a call the server did not run left at its default rather than missing, since Rust has Default for it:

if let Error::Method(failed) = &err {
    if let Some(out) = failed.result::<DestroyThreadResult>() {
        if !out.thread_get.not_found.is_empty() { /* which thread was missing */ }
    }
}

There is a third level, and it is the one most often missed. A /set answers 200 with no error in it and lists the records it would not act on:

["Email/set", {"notCreated": {"draft": {"type": "invalidProperties",
                                        "properties": ["subject"]}}}, "write"]

Read only the transport error and this is a success where nothing happened. Generated code checks it, so a refused record is a *jmapc.SetErrors:

res, err := jmapq.SendEmail(ctx, c, params)
if err != nil {
    var refused *jmapc.SetErrors
    if errors.As(err, &refused) {
        for _, f := range refused.Failures {
            log.Printf("%s: %v", f.Key, f.Err) // draft: invalidProperties [subject]
        }
    }
    return err
}

res is returned alongside the error, since the part of the request the server did carry out still happened. Calls the query does not name in _returns are checked too — naming one call should not exempt the others from the check.

In TypeScript the same failure is a thrown SetErrors, with the response on err.result. In Rust it is an Error::Set, and the response is retrieved with the type the function would have returned, through err.result::<T>().

Splitting a large /get

A /get naming more ids than the server's maxObjectsInGet is refused. WithSplitGets sends it in several requests instead, and joins the answers into the one response the caller asked for:

c := jmapc.New(url, jmapc.WithBearerToken(token), jmapc.WithSplitGets())

It is off by default, for two reasons. One call to Do then costs several round trips. And the records no longer arrive as one snapshot: each request is answered separately, and the account may change between them. Where the state a /get reports differs between requests, the joined response is returned together with a *jmapc.StateChanged, which errors.As reaches — the same shape as a method error, so a caller that needs one snapshot can fetch again and one that does not can ignore it.

Only the ids written into the query are counted, and two calls are sent as they are. One whose ids come from a back reference, since how many they resolve to is known to the server alone. And one that another call refers to, since a reference resolves within one request, and splitting the call it names would leave nothing to resolve against.

The ids that did not fit travel in further requests of their own, no more calls in one request than maxCallsInRequest allows. The rest of the query is sent once, in the first request, so the back references between its other calls resolve as they did before.

Tokens that expire

WithBearerToken holds one string for the life of the client. An OAuth 2.0 access token does not last that long, and replacing it means building another client, which discards the cached session and the count of the requests in flight along with it. WithTokenSource takes a function instead:

c := jmapc.New(url, jmapc.WithTokenSource(func(ctx context.Context) (jmapc.Token, error) {
	tok, err := oauthConfig.TokenSource(ctx, refreshToken).Token()
	if err != nil {
		return jmapc.Token{}, err
	}
	return jmapc.Token{Value: tok.AccessToken, Expiry: tok.Expiry}, nil
}))

The token is held until it expires. A source that reports an Expiry is called again shortly before it; one that reports none is called again only when a server answers 401. Requests arriving together share one call, so a source that exchanges a refresh token is not asked to do so several times at once — some servers accept a refresh token only once.

A 401 also sends that one request again, once, with a newly fetched token. A second 401 is reported to the caller, since a source returning a token the server does not accept is not resolved by sending the request again. This is separate from WithRetry, which retries what a server reported it did not carry out.

Retries

WithRetry retries when the server answers with HTTP 429 or 503.

c := jmapc.New(url, jmapc.WithBearerToken(token), jmapc.WithRetry(3))

The argument is how many attempts to make. The delay is the value of the server's Retry-After, or, where the server sends none, a delay that doubles from 0.2 seconds to 30 seconds.

Observability

WithObserver makes the client report what it does. The report affects neither the request sent nor the response received, and a hook left nil is never called.

c := jmapc.New(url, jmapc.WithBearerToken(token),
	jmapc.WithObserver(jmapc.SlogObserver(slog.Default())))

There are three hooks, and they nest. SlogObserver writes a debug record for each. Request covers one JMAP request: the calls it carries and its outcome. Attempt covers one HTTP request under it, which includes the session fetch a first request triggers and every retry. Wait covers a delay applied instead of sending — for one of the slots maxConcurrentRequests allows, or before a retry after a 429 or a 503.

Request   Email/query, Email/get
  Attempt GET  /.well-known/jmap  200
  Wait    for a slot, where the server accepts two requests at once
  Attempt POST /jmap/api          429
  Wait    for the two seconds of the server's Retry-After
  Attempt POST /jmap/api          200

An HTTP-level instrument already records the round trips, and where that is enough, WithHTTPClient takes a client with an instrumented transport. What it cannot record is the JMAP: which methods were sent together in one request, how long the caller waited for a slot, and that a call was refused although the request returned 200.

There is no dependency on OpenTelemetry, and none is needed. Request and Attempt return the context used for the operation they cover, so a span started in one becomes the parent of the spans started under it:

tracer := otel.Tracer("jmapc")

obs := &jmapc.Observer{
	Request: func(ctx context.Context, info jmapc.RequestInfo) (context.Context, func(jmapc.ResponseInfo)) {
		methods := make([]string, len(info.Calls))
		for i, call := range info.Calls {
			methods[i] = call.Name
		}
		ctx, span := tracer.Start(ctx, "jmap.request",
			trace.WithAttributes(attribute.StringSlice("jmap.methods", methods)))
		return ctx, func(done jmapc.ResponseInfo) {
			span.SetAttributes(attribute.Int("jmap.method_errors", len(done.Errors)))
			if done.Err != nil {
				span.RecordError(done.Err)
			}
			span.End()
		}
	},
	Attempt: func(ctx context.Context, info jmapc.AttemptInfo) (context.Context, func(jmapc.AttemptInfo, jmapc.Answer)) {
		ctx, span := tracer.Start(ctx, "jmap."+string(info.Kind),
			trace.WithAttributes(attribute.Int("http.attempt", info.Attempt)))
		return ctx, func(info jmapc.AttemptInfo, answer jmapc.Answer) {
			span.SetAttributes(attribute.Int("http.status_code", answer.Status))
			span.End()
		}
	},
}

Observer exists only in the Go client. In Rust and TypeScript, the equivalent belongs in the transport.

Testing

Testing the code you write around a generated client means answering a request that carries several method calls, some of which refer to the results of the others. A stub written by hand for one test either ignores that, and no longer resembles a server, or grows into this:

srv := jmaptest.New(t)
srv.Reply("Email/query", jmapc.EmailQueryResponse{
	AccountID: jmaptest.AccountID,
	IDs:       []jmapc.ID{"m1", "m2"},
})
srv.Handle("Email/get", func(c *jmaptest.Call) (any, error) {
	// The ids are the ones the query call answered with: the back reference
	// has already been resolved, the way a server resolves it.
	return emailsFor(c.IDs()), nil
})

res, err := jmapq.ListInboxEmails(ctx, srv.Client(), params)

What it removes from the test:

  • The back references. They are resolved as RFC 8620 defines, including the * that maps a path over a list, so a chained query reaches the handlers with resolved values.
  • The checking. The request is checked against the data model the same way the build checks a query, so a call with an argument no method has fails the test rather than passing quietly. jmaptest.WithoutChecks() disables it, for a method jmapc does not know.
  • The failures. srv.Fail for a method-level error, srv.FailRequest for a request rejected as a whole, and a /set response listing what it refused for the failure that answers 200.
  • What was requested. srv.Call("Email/query") is the last call to a method, srv.Calls() all of them, and srv.Requests() how many requests they took — which is how to check that calls were sent in one request rather than one at a time.
  • The push. srv.Push sends a state change to a watching client, which is what a watching query's loop waits for.

What it does not do is store anything. It is a server to test a client against rather than an implementation of JMAP: nothing a /set creates comes back from a later /get unless the test says it does.

A client is rarely converted all at once, and a half-converted one has two halves to answer in the same test: the generated half, which reaches the server through srv.Client(), and the half still written by hand, which posts to paths of its own. srv.Mux() is where those paths go, and srv.BaseURL() is what the other half is pointed at:

srv := jmaptest.New(t)
srv.Mux().HandleFunc("/jmap", myOldAPIHandler)
srv.Mux().HandleFunc("/jmap/session", myOldSessionHandler)

old := myOldClient(srv.BaseURL())

Where the other half already uses JMAP and only expects it at different paths — deriving the session and the API from a base URL of its own — mount jmaptest's own handlers there instead, and it answers under both paths:

srv.Mux().HandleFunc("/jmap/session", srv.ServeSession)
srv.Mux().HandleFunc("/jmap", srv.ServeAPI)

So jmaptest is worth adopting on the first method converted rather than the last.

Blobs

Attachments are not transferred through the API endpoint. They are uploaded and downloaded over plain HTTP, at the URLs the session advertises, and the runtime handles both:

info, err := c.Upload(ctx, accountID, "application/pdf", file)
// info.BlobID now goes into an Email/set that attaches it.

blob, err := c.Download(ctx, accountID, part.BlobID, &jmapc.DownloadOptions{
	Name: *part.Name,
	Type: part.Type,
})
defer blob.Close()

Both stream. Upload reads from an io.Reader and Download returns an io.ReadCloser, so an attachment larger than memory is copied from a file to the server, and from the server to a file, without being held in either direction. An upload larger than the server's maxSizeUpload fails before it is sent.

From and Length fetch part of a blob, which is how a download interrupted part way is resumed:

blob, err := c.Download(ctx, accountID, blobID, &jmapc.DownloadOptions{From: written})
...
blob.Range // the part that came back: 4096-8191 of 8192

They are sent as an HTTP Range header. JMAP defines none for the download endpoint, so a server is free to ignore it and answer with the whole blob; where that happens the download fails rather than returning content the caller would write at the wrong offset.

A server offering urn:ietf:params:jmap:blob can also create and read blobs through the API, which the endpoints cannot: Blob/upload puts a blob in the same request as the call that uses it, so the id never comes back to the client in between.

Walking an answer that does not fit in one request

A JMAP answer is often only part of an answer. A /query returns just the window of results the caller asked for, and says where that window sits in the full result. A /changes returns only as many changes as the server chooses to, and reports whether there are more.

Either way, getting the rest means sending another request, and what goes in it comes from the last answer: position for a /query, sinceState for a /changes. Naming a call in _pages generates that loop, called a walk, so it does not have to be written by hand.

The call named in _pages is the one the walk resends on each step. Where the next request should start — position for a /query, sinceState for a /changes — is managed by the walk rather than by the caller, so it is written as a parameter in the query:

{
  "_pages": "search",

  "methodCalls": [
    ["Email/query", {"filter": {"text": "{{phrase}}"}, "position": "{{position}}",
                     "limit": 50, "calculateTotal": true}, "search"],
    ["Email/get", {"#ids": {"resultOf": "search", "name": "Email/query", "path": "/ids"}}, "fetch"]
  ]
}

Go gets an iterator. Advancing it sends the next request:

for page, err := range jmapq.SearchEmailsPages(ctx, c, params) {
	if err != nil {
		return err
	}
	for _, email := range page.EmailGet.List {
		fmt.Println(*email.Subject)
	}
}

TypeScript gets an async generator that does the same, one step at a time. A failure throws as it does from the query itself:

for await (const page of searchEmailsPages(client, params)) {
  for (const email of page.emailGet.list) console.log(email.subject)
}

Rust gets a value that holds the current position, and advances the same way. A stream would require a crate to define one, and the generated code requires serde and nothing else:

let mut pages = search_emails_pages(params);
while let Some(page) = pages.next(&client).await? {
    for email in &page.email_get.list {
        println!("{:?}", email.subject);
    }
}

When a walk stops depends on what it is walking.

A /query walk starts from the position the parameters carry, so it can resume where a previous walk stopped. An empty window ends the walk instead of being yielded, so every page the walk yields holds at least one record. Where the call asked for the total, the walk also stops once the next request would be past that total.

A /changes walk yields even an answer reporting no changes, because that answer still carries the sinceState to continue from. It ends only when the server reports no further changes.

A watching query already repeats the request while the server reports more changes, so _watches and _pages are never written on the same query.

Push

An event reports which types in which accounts have changed, not what changed. A client that needs the changes therefore writes a loop: connect, request the changes since the state it holds, apply them, wait for the next event. That loop is the same every time and every part of it is a place for a mistake, so a query can request it.

_watches names the call the loop reads the state from, which has to be one that reports what changed since a state, as Email/changes does:

{
  "_watches": "changes",

  "methodCalls": [
    ["Email/changes", {"sinceState": "{{sinceState}}", "maxChanges": 128}, "changes"],
    ["Email/get", {"#ids": {"resultOf": "changes", "name": "Email/changes", "path": "/created"}}, "created"]
  ]
}

SyncEmails is generated as it would be anyway, and SyncEmailsWatch alongside it:

err := jmapq.SyncEmailsWatch(ctx, c, jmapq.SyncEmailsParams{SinceState: state},
	func(ctx context.Context, res *jmapq.SyncEmailsResult) error {
		for _, email := range res.EmailGet.List {
			fmt.Println("new:", *email.Subject)
		}
		state = res.EmailChanges.NewState // keep it, and start there next time
		return nil
	})

It starts from the state the parameters carry, and continues from the state each answer reports. What it removes from the caller:

  • A stream is a connection, not a subscription. When it drops, another is opened, resuming from the last event delivered, with a delay that doubles from a second to 30 seconds while the server is unreachable.
  • Changes made while no connection was open are not pushed, so every connection is followed by a catch-up.
  • A server returns as many changes as it chooses and sets hasMoreChanges, so the loop repeats the request until that is false.
  • An event about another account, another type, or a state the loop has already reached does not need a request. The last of those is the common case: a catch-up causes the server to push the state it has just received.

The loop runs until the context ends, which is the error it returns. An error from the callback stops the loop and is returned unchanged. A server that refuses the connection outright returns that error immediately rather than retrying, because retrying will not change a 403. jmapc.WithPing and jmapc.WithReconnect configure the two values worth tuning.

Underneath is Client.Watch, which takes the catch-up as a function and is what to call where the catching up is not one query:

err := c.Watch(ctx, accountID, "Email", state,
	func(ctx context.Context, since string) (newState string, more bool, err error) {
		// ... /changes from since, then whatever the ids call for
	})

Only the Go client follows a watch. Holding a connection open is the runtime's responsibility rather than the generated code's, and the Rust and TypeScript runtimes do not implement it; generating either from a watching query writes the query without the loop and reports that.

Below Watch is Client.EventSource, which opens the push endpoint and returns the events:

stream, err := c.EventSource(ctx, &jmapc.EventSourceOptions{
	Types: []string{"Email"},
	Ping:  30 * time.Second,
})
defer stream.Close()

for {
	change, err := stream.Next()
	if err != nil {
		break // reconnect, passing stream.LastEventID()
	}
	if state, ok := change.StateOf(accountID, "Email"); ok {
		_ = state
	}
}

This is the event source form of push, which suits a client that can hold a connection open. The other form registers a URL for the server to post to, which is what an app on a phone needs: see RegisterPush and ConfirmPush in example/queries. A subscription is not active when it is created — the server pushes a code to the URL, and the client sends it back with a PushSubscription/set before anything else is sent. jmapc.PushVerification decodes what arrives.

Vendor extensions

JMAP is meant to be extended: a server advertises a capability URI of its own, bringing types and methods jmapc does not know. Describe them in a schema file and queries against them are checked exactly as ones against Email are — back references, property names, sort orders and all.

{
  "capability": "urn:example:params:jmap:notes",
  "types": [
    {
      "name": "Note",
      "doc": "Note is a scrap of text the user keeps.",
      "properties": [
        {"name": "id", "type": "Id", "serverSet": true, "immutable": true, "doc": "The id of the note."},
        {"name": "title", "type": "String", "doc": "The note's title."}
      ],
      "methods": ["get", "changes", "set", "query"],
      "sort": [{"name": "createdAt", "doc": "Sorts by when the note was created."}]
    },
    {
      "name": "NoteFilterCondition",
      "doc": "NoteFilterCondition is a condition a note must satisfy to match a Note/query.",
      "properties": [{"name": "text", "type": "String", "doc": "Matches notes containing this text."}]
    }
  ]
}

Naming the six standard methods is enough to get them: their arguments and responses follow the shapes RFC 8620 fixes. A method that does not follow one is declared outright, with its arguments and response spelled out.

jmapc generate -schema schema/notes.json

Or list them in jmapc.json under "schemas".

Working on jmapc

go test ./...        # everything, including the end-to-end tests
go generate ./...    # regenerate the runtime types and every example client

The example is generated three times, once per language, into example/jmapq, example/rust/src/jmapq and example/ts. Go's tests cannot say whether the other two compile, so CI runs cargo fmt --check and cargo test over the Rust and tsc --strict over the TypeScript. Each of the two has a hand-written check beside the generated code, exercising the runtime against a stub: that the headers are sent, that authentication overrides them, that the session is cached, and that a /set answering 200 with a refusal in it is still an error.

The schema is checked the same way, and for the same reason: whether a validator accepts the example queries and refuses the mistakes the schema claims to catch is not something Go's tests can say. example/schema/check.mjs runs one, over a schema written from the catalogue as it stands.

The generator is run from source here, not through go tool, because this is the repository that defines it.

The runtime types and the example client are committed, and a test compares them against what the catalogue produces now, so a change to the data model that was not regenerated fails the build rather than going unnoticed. CI runs the same checks, plus gofmt, go vet, and govulncheck.

Coverage

JMAP is a family of specifications: a server advertises capability URIs, and each brings its own types and methods. These are the ones IANA lists, and where jmapc stands on each.

Capability Specification Supported
urn:ietf:params:jmap:core RFC 8620
urn:ietf:params:jmap:mail RFC 8621
urn:ietf:params:jmap:submission RFC 8621
urn:ietf:params:jmap:vacationresponse RFC 8621
urn:ietf:params:jmap:contacts RFC 9610
urn:ietf:params:jmap:calendars draft-ietf-jmap-calendars
urn:ietf:params:jmap:principals:availability draft-ietf-jmap-calendars
urn:ietf:params:jmap:principals RFC 9670
urn:ietf:params:jmap:principals:owner RFC 9670
urn:ietf:params:jmap:smimeverify RFC 9219
urn:ietf:params:jmap:blob RFC 9404
urn:ietf:params:jmap:quota RFC 9425
urn:ietf:params:jmap:sieve RFC 9661
urn:ietf:params:jmap:mdn RFC 9007
urn:ietf:params:jmap:webpush-vapid RFC 9749

Two of these store objects from specifications of their own: a contact card is a JSContact Card, and a calendar event is a JSCalendar JSEvent. Both name types that JMAP also names, and each other's too — there are three different Link types between them. So those carry a prefix: ContactEmailAddress is an address on a card, EmailAddress is one in a header field, and EventLink is a resource attached to a meeting. Each type's documentation gives the name its specification uses.

JSCalendar also brings time types JMAP does not have. An event's start is a LocalDateTime with no zone, and its duration is an ISO 8601 Duration, because "P1D" across a daylight saving change is not always 24 hours. Both are checked in a query, so a start written with a Z on the end, or a duration written as 90m, fails to build.

Not every capability brings types of its own. S/MIME verification adds four properties to Email and nothing else, so a query needs it without any method name saying so. jmapc works out which capabilities the properties a query touches belong to, and declares them: ask for smimeStatus and urn:ietf:params:jmap:smimeverify appears in using on its own.

Some define neither types nor methods, only a value for the client. VAPID is one, and that value is a key. Those are read from the session, and Session.Capability reads any of them, including one jmapc does not know.

vapid, err := session.WebPushVAPID()
// vapid.ApplicationServerKey goes to the push service when subscribing there.

var limits struct{ MaxSizeScript int `json:"maxSizeScript"` }
err = session.Accounts[accountID].Capability(jmapc.CapabilitySieve, &limits)

A capability that is not built in can still be used: describe its types in a schema file and queries against them are checked like any other. That is the same mechanism a vendor extension uses, and the work is declarative — no Go to write.

Methods

81 methods, all of them checked and generated the same way.

Type Methods
Mailbox get changes set query queryChanges
Thread get changes
Email get changes set copy query queryChanges import parse
SearchSnippet get
Identity get changes set
EmailSubmission get changes set query queryChanges
VacationResponse get set
AddressBook get changes set
ContactCard get changes set copy query queryChanges
Calendar get changes set
CalendarEvent get changes set copy query queryChanges parse
CalendarEventNotification get changes set query queryChanges
ParticipantIdentity get changes set
Principal get changes set query queryChanges getAvailability
ShareNotification get changes set query queryChanges
Quota get changes query queryChanges
SieveScript get set query validate
MDN send parse
Blob copy upload get lookup
PushSubscription get set
Core echo

What is not checked

One thing, and it is on purpose.

Open sets are not checked, deliberately. Where a specification fixes the values a property takes, jmapc checks them. Where it leaves the set open — a mailbox role, an email keyword, a Content-Disposition — it does not, because rejecting a value the server would have accepted is worse than letting a typo through.

Generation

internal/spec is a plain Go declaration of the data model, and the runtime types in types_gen.go are generated from the same catalogue the queries are checked against, so the two cannot drift apart.

Documentation

Overview

Package jmapc is the runtime for clients generated from JMAP queries.

JMAP is built around one idea: a request carries several method calls, and a call may refer to the result of an earlier one, so that a chain of dependent operations costs a single round trip. Fetching the newest messages in a mailbox is one request holding an Email/query and an Email/get, with the ids passing between them on the server.

Most clients expose that through a builder, which means learning both JMAP and the builder. jmapc takes the other route. You write the JMAP request itself, in a file next to your code; the jmapc command checks it against the JMAP data model and writes a Go function that sends it and decodes the reply into types that hold exactly the properties you asked for. What you learn is JMAP.

This package is what the generated code calls: it holds the client, the request and response types, the errors JMAP defines, and the Go form of the JMAP data types.

Getting started

Write a query in queries/ListInboxEmails.jmap.json:

{
  "_doc": "ListInboxEmails returns the newest emails in one mailbox.",
  "methodCalls": [
    ["Email/query", {
      "filter": {"inMailbox": "{{mailboxId}}"},
      "sort": [{"property": "receivedAt", "isAscending": false}],
      "limit": "{{limit}}"
    }, "search"],
    ["Email/get", {
      "#ids": {"resultOf": "search", "name": "Email/query", "path": "/ids"},
      "properties": ["id", "subject", "from", "receivedAt"]
    }, "fetch"]
  ],
  "_returns": "fetch"
}

Generate the client:

go run github.com/linyows/jmapc/cmd/jmapc generate

Then call it:

c := jmapc.New(jmapc.WellKnownURL("example.com"), jmapc.WithBearerToken(token))
res, err := jmapq.ListInboxEmails(ctx, c, jmapq.ListInboxEmailsParams{
	MailboxID: inbox,
	Limit:     25,
})

Authentication

WithBearerToken sends a fixed token. WithTokenSource takes a function instead, for a token that expires: the client calls it when it has no token, shortly before the one it holds expires, and when a server answers 401, and requests arriving together share one call.

Splitting a large /get

WithSplitGets sends a /get naming more ids than the server's maxObjectsInGet in several requests and joins the answers, at the cost of several round trips and of the records no longer arriving as one snapshot. Where the state differs between those requests, the joined response is returned together with a StateChanged.

Blobs

Attachments do not go through the API endpoint. Client.Upload and Client.Download exchange them over plain HTTP at the URLs the session advertises, and an upload larger than the server accepts fails before it is sent. Both stream, so an attachment larger than memory is never held in it.

DownloadOptions From and Length fetch part of a blob, as an HTTP Range header, which is how a download interrupted part way is resumed.

Push

Client.EventSource opens the server's push endpoint and reports which types in which accounts have changed. An event reports only that, not what changed, so the client follows up with a /changes call. A stream is a connection, not a subscription that outlives the network: treat an error from EventStream.Next as a signal to reconnect, passing the stream's EventStream.LastEventID so that nothing is missed in between.

Observability

WithObserver takes an Observer, which receives a report of what the client does and affects none of it: the JMAP calls of each request and their outcome, each HTTP request under it, and each delay for a slot or before a retry. SlogObserver writes those records to a log/slog.Logger. The hooks return the context used for the operation they cover, so a tracer can start a span in one and have the spans under it become its children.

Errors

JMAP fails at two levels, and so does this package. A request-level failure, where the server rejected the request as a whole, is a RequestError. A method-level failure, where some calls ran and others did not, is a MethodErrors; the response is returned alongside it, because the calls that did run still have results worth reading.

Index

Constants

View Source
const (
	ErrTypeUnknownCapability = "urn:ietf:params:jmap:error:unknownCapability"
	ErrTypeNotJSON           = "urn:ietf:params:jmap:error:notJSON"
	ErrTypeNotRequest        = "urn:ietf:params:jmap:error:notRequest"
	ErrTypeLimit             = "urn:ietf:params:jmap:error:limit"
)

Request-level error types defined by RFC 8620, Section 3.6.1.

View Source
const (
	ErrServerUnavailable = "serverUnavailable"
	ErrServerFail        = "serverFail"
	ErrServerPartialFail = "serverPartialFail"
	ErrUnknownMethod     = "unknownMethod"
	ErrInvalidArguments  = "invalidArguments"
	ErrInvalidResultRef  = "invalidResultReference"
	ErrForbidden         = "forbidden"
	ErrAccountNotFound   = "accountNotFound"
	ErrAccountNotSupport = "accountNotSupportedByMethod"
	ErrAccountReadOnly   = "accountReadOnly"
	ErrRequestTooLarge   = "requestTooLarge"
	ErrCannotCalcChanges = "cannotCalculateChanges"
	ErrStateMismatch     = "stateMismatch"
	ErrUnsupportedFilter = "unsupportedFilter"
	ErrUnsupportedSort   = "unsupportedSort"
	ErrOverQuota         = "overQuota"
	ErrTooLarge          = "tooLarge"
	ErrRateLimit         = "rateLimit"
	ErrNotFound          = "notFound"
	ErrInvalidPatch      = "invalidPatch"
	ErrWillDestroy       = "willDestroy"
	ErrInvalidProperties = "invalidProperties"
	ErrSingleton         = "singleton"
)

Method-level error types defined by RFC 8620, Section 3.6.2.

View Source
const (
	CapabilityCore       = "urn:ietf:params:jmap:core"
	CapabilityMail       = "urn:ietf:params:jmap:mail"
	CapabilitySubmission = "urn:ietf:params:jmap:submission"
	CapabilityVacation   = "urn:ietf:params:jmap:vacationresponse"
	CapabilityContacts   = "urn:ietf:params:jmap:contacts"
	CapabilityCalendars  = "urn:ietf:params:jmap:calendars"
	// CapabilityCalendarsParse covers CalendarEvent/parse, which a server may
	// support without supporting the rest of the calendar model.
	CapabilityCalendarsParse = "urn:ietf:params:jmap:calendars:parse"
	// CapabilityAvailability covers Principal/getAvailability.
	CapabilityAvailability = "urn:ietf:params:jmap:principals:availability"
	CapabilityPrincipals   = "urn:ietf:params:jmap:principals"
	// CapabilitySMIMEVerify adds the S/MIME verification properties to an
	// Email; it defines no types or methods of its own.
	CapabilitySMIMEVerify = "urn:ietf:params:jmap:smimeverify"
	// CapabilityBlob brings blob creation, reading and lookup into the API,
	// alongside the upload and download endpoints of the core specification.
	CapabilityBlob = "urn:ietf:params:jmap:blob"
	// CapabilityQuota reports the limits an account is under and how much of
	// each is used.
	CapabilityQuota = "urn:ietf:params:jmap:quota"
	// CapabilitySieve manages the filtering scripts the server runs on
	// incoming mail.
	CapabilitySieve = "urn:ietf:params:jmap:sieve"
	// CapabilityMDN sends and reads the receipts that report what became of a
	// message.
	CapabilityMDN = "urn:ietf:params:jmap:mdn"
	// CapabilityWebPushVAPID states that the server authenticates itself to a
	// push service with VAPID. It defines no types and no methods: the value
	// it carries is a key, held in the session.
	CapabilityWebPushVAPID = "urn:ietf:params:jmap:webpush-vapid"
	// CapabilityPrincipalsOwner appears only in an account's capabilities,
	// where it names the principal that owns the account.
	CapabilityPrincipalsOwner = "urn:ietf:params:jmap:principals:owner"
)

Capability URIs defined by the core specification and by JMAP for Mail.

View Source
const DefaultUserAgent = "jmapc/0.1 (+https://github.com/linyows/jmapc)"

DefaultUserAgent identifies this client to servers.

Variables

This section is empty.

Functions

func WellKnownURL

func WellKnownURL(host string) string

WellKnownURL returns the session resource URL to start autodiscovery from, as described in RFC 8620, Section 2.2. The host may be given bare ("example.com") or as a URL ("https://example.com").

Types

type Account

type Account struct {
	// Name is a user-facing label for the account.
	Name string `json:"name"`
	// IsPersonal reports whether the account belongs to the authenticated user
	// rather than being shared with them.
	IsPersonal bool `json:"isPersonal"`
	// IsReadOnly reports whether the user may only read from this account.
	IsReadOnly bool `json:"isReadOnly"`
	// AccountCapabilities gives per-account limits, keyed by capability URI.
	AccountCapabilities map[string]json.RawMessage `json:"accountCapabilities"`
}

Account describes one account exposed by the session.

func (*Account) Capability added in v0.2.0

func (a *Account) Capability(uri string, dest any) error

Capability decodes this account's entry for a capability into dest. Several capabilities state their per-account limits here rather than in the session: the largest script, the largest blob, how many of each are allowed.

type AddedItem

type AddedItem struct {
	// The id of the record that entered the result list.
	ID ID `json:"id,omitzero"`

	// The index in the result list to insert the id at.
	Index UnsignedInt `json:"index,omitzero"`
}

AddedItem is an id to insert into a cached query result, with the index to insert it at.

type Address

type Address struct {
	// The addr-spec of the address, with no display name and no angle brackets.
	Email string `json:"email,omitzero"`

	// The SMTP parameters to send with the address, keyed by parameter name,
	// with null for one that takes no value.
	Parameters map[string]*string `json:"parameters,omitzero"`
}

Address is an SMTP envelope address, with the parameters to send alongside it.

A request using this type must declare urn:ietf:params:jmap:submission.

type AddressBook

type AddressBook struct {
	// The id of the address book.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The user-visible name of the address book, at most 255 octets of UTF-8.
	Name string `json:"name,omitzero"`

	// A longer description of what the address book holds.
	Description *string `json:"description,omitzero"`

	// A hint for where to place the address book in a list of them.
	//
	// The server assumes 0 when this property is omitted.
	SortOrder UnsignedInt `json:"sortOrder,omitzero"`

	// Whether this is the address book a card goes into when the client does not
	// say. Exactly one address book in an account has this set.
	//
	// The server sets this property; it may not be set by the client.
	IsDefault bool `json:"isDefault,omitzero"`

	// Whether the user has subscribed to the address book.
	IsSubscribed bool `json:"isSubscribed,omitzero"`

	// Who else the address book is shared with, keyed by principal id, and what
	// each may do.
	ShareWith map[ID]AddressBookRights `json:"shareWith,omitzero"`

	// What the authenticated user may do with the address book.
	//
	// The server sets this property; it may not be set by the client.
	MyRights AddressBookRights `json:"myRights,omitzero"`
}

AddressBook is a named collection of contact cards.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookChangesArguments

type AddressBookChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// AddressBook/get or AddressBook/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

AddressBookChangesArguments holds the arguments of the AddressBook/changes method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookChangesResponse

type AddressBookChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

AddressBookChangesResponse holds the response to the AddressBook/changes method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookGetArguments

type AddressBookGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

AddressBookGetArguments holds the arguments of the AddressBook/get method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookGetResponse

type AddressBookGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with AddressBook/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []AddressBook `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

AddressBookGetResponse holds the response to the AddressBook/get method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookRights

type AddressBookRights struct {
	// Whether the user may read the cards in the address book.
	MayRead bool `json:"mayRead,omitzero"`

	// Whether the user may create, modify, and destroy cards in it.
	MayWrite bool `json:"mayWrite,omitzero"`

	// Whether the user may change who else it is shared with.
	MayShare bool `json:"mayShare,omitzero"`

	// Whether the user may delete the address book itself.
	MayDelete bool `json:"mayDelete,omitzero"`
}

AddressBookRights says what the authenticated user may do with an address book.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookSetArguments

type AddressBookSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]AddressBook `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// Whether destroying an address book may also destroy the cards in it. If
	// false, destroying one that is not empty fails with an
	// addressBookHasContents error.
	//
	// The server assumes false when this property is omitted.
	OnDestroyRemoveContents bool `json:"onDestroyRemoveContents,omitzero"`

	// The id of the address book to make the default once the other changes
	// succeed.
	OnSuccessSetIsDefault *ID `json:"onSuccessSetIsDefault,omitzero"`
}

AddressBookSetArguments holds the arguments of the AddressBook/set method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type AddressBookSetResponse

type AddressBookSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*AddressBook `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*AddressBook `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

AddressBookSetResponse holds the response to the AddressBook/set method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type Answer added in v0.12.0

type Answer struct {
	// Status is the HTTP status, and zero where no response was received.
	Status int
	// Duration is how long the attempt took.
	Duration time.Duration
	// Err is the transport error, and nil where a response was received. A
	// 4xx or 5xx status is not an error here.
	Err error
}

Answer is the outcome of one attempt.

type AttemptInfo added in v0.12.0

type AttemptInfo struct {
	// Kind says what the request is for.
	Kind RequestKind
	// Method and URL are the HTTP method and the address, with any credentials
	// removed from the URL.
	Method string
	URL    string
	// Attempt counts from one, and is higher only for a retry.
	Attempt int
}

AttemptInfo describes one HTTP request the client sends.

type Blob

type Blob struct {
	// ReadCloser carries the blob's content.
	io.ReadCloser
	// Type is the media type the server served the blob as.
	Type string
	// Size is the size in octets of what is being read, which is the size of
	// the part where a range was requested, or -1 where the server did not
	// report it.
	Size int64
	// Range is the part of the blob the server returned, and is nil where the
	// whole of it was requested.
	Range *BlobRange
	// Name is the filename from the Content-Disposition header, if the server
	// sent one. It is whatever the server sent, which may be a path rather
	// than a name: take the base of it before writing anything under it.
	Name string
}

Blob is a blob being downloaded. The caller must close it.

The content is read from the server as it is read from here, so a blob larger than memory is written straight to a file without being held.

type BlobCopyArguments

type BlobCopyArguments struct {
	// The id of the account to copy blobs from.
	FromAccountID ID `json:"fromAccountId,omitzero"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the blobs to copy.
	BlobIDs []ID `json:"blobIds,omitzero"`
}

BlobCopyArguments holds the arguments of the Blob/copy method.

type BlobCopyResponse

type BlobCopyResponse struct {
	// The id of the account the blobs were copied from.
	FromAccountID ID `json:"fromAccountId"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A map of the blob id in the source account to the id the blob has in the
	// destination account.
	Copied map[ID]ID `json:"copied"`

	// A map of blob id to the reason it could not be copied.
	NotCopied map[ID]SetError `json:"notCopied"`
}

BlobCopyResponse holds the response to the Blob/copy method.

type BlobData added in v0.2.0

type BlobData struct {
	// The id of the blob.
	ID ID `json:"id,omitzero"`

	// The octets as text, or null where they are not valid UTF-8.
	DataAsText *string `json:"data:asText,omitzero"`

	// The octets as base64, which works whatever they hold.
	DataAsBase64 string `json:"data:asBase64,omitzero"`

	// Whether the octets asked for as text were not valid UTF-8.
	//
	// The server assumes false when this property is omitted.
	IsEncodingProblem bool `json:"isEncodingProblem,omitzero"`

	// Whether the range asked for ran past the end of the blob.
	//
	// The server assumes false when this property is omitted.
	IsTruncated bool `json:"isTruncated,omitzero"`

	// The size of the whole blob in octets, whatever range was asked for.
	Size UnsignedInt `json:"size,omitzero"`
}

BlobData is the content of a blob as the API returns it, rather than as a download. RFC 9404 calls it a blob; the name is qualified here because the runtime's Blob is an open download.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobDataSource added in v0.2.0

type BlobDataSource struct {
	// The octets as text, which the server encodes as UTF-8.
	DataAsText *string `json:"data:asText,omitzero"`

	// The octets as base64, for content that is not text.
	DataAsBase64 *string `json:"data:asBase64,omitzero"`

	// The id of a blob to take the octets from, so that a new blob can be
	// assembled out of ones the server already holds.
	BlobID ID `json:"blobId,omitzero"`

	// Where in that blob to start, defaulting to the beginning.
	Offset *UnsignedInt `json:"offset,omitzero"`

	// How many octets to take, defaulting to the rest of the blob.
	Length *UnsignedInt `json:"length,omitzero"`
}

BlobDataSource is one run of octets to put into a blob. Exactly one of its forms is used: text, base64, or a range of a blob that already exists. RFC 9404 calls it DataSourceObject.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobGetArguments added in v0.2.0

type BlobGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the blobs to fetch.
	IDs []ID `json:"ids,omitzero"`

	// What to return for each blob: "data:asText", "data:asBase64", "size",
	// "data" to let the server pick whichever encoding fits, or "digest:"
	// followed by an algorithm the session says it supports.
	Properties []string `json:"properties,omitzero"`

	// Where in each blob to start, so that a large blob can be read a piece at a
	// time.
	//
	// The server assumes 0 when this property is omitted.
	Offset *UnsignedInt `json:"offset,omitzero"`

	// How many octets to return, defaulting to the rest of the blob.
	Length *UnsignedInt `json:"length,omitzero"`
}

BlobGetArguments holds the arguments of the Blob/get method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobGetResponse added in v0.2.0

type BlobGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The blobs that were found.
	List []BlobData `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

BlobGetResponse holds the response to the Blob/get method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobInfo

type BlobInfo struct {
	// AccountID is the account the blob was uploaded to.
	AccountID ID `json:"accountId"`
	// BlobID is the id to refer to the blob by, such as in the blobId of an
	// EmailBodyPart.
	BlobID ID `json:"blobId"`
	// Type is the media type the server recorded for the blob, which may
	// differ from the one that was offered.
	Type string `json:"type"`
	// Size is the size of the blob in octets.
	Size UnsignedInt `json:"size"`
}

BlobInfo describes a blob the server has accepted, as returned by the upload endpoint of RFC 8620, Section 6.1.

type BlobLookupArguments added in v0.2.0

type BlobLookupArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The data types to look in, such as "Email" or "Mailbox". The session says
	// which ones the server supports.
	TypeNames []string `json:"typeNames,omitzero"`

	// The ids of the blobs to look for.
	IDs []ID `json:"ids,omitzero"`
}

BlobLookupArguments holds the arguments of the Blob/lookup method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobLookupInfo added in v0.2.0

type BlobLookupInfo struct {
	// The id of the blob.
	ID ID `json:"id,omitzero"`

	// The records that refer to the blob, keyed by data type name.
	MatchedIDs map[string][]ID `json:"matchedIds,omitzero"`
}

BlobLookupInfo says which records refer to a blob. RFC 9404 calls it BlobInfo; the name is qualified here because the runtime's BlobInfo describes an upload.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobLookupResponse added in v0.2.0

type BlobLookupResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// What was found for each blob.
	List []BlobLookupInfo `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

BlobLookupResponse holds the response to the Blob/lookup method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobRange added in v0.12.0

type BlobRange struct {
	// From and To are the first and last octet returned, counted from the
	// start of the blob and both included.
	From, To int64
	// Total is the size of the whole blob, or -1 where the server did not
	// report it.
	Total int64
}

BlobRange is the part of a blob a server returned, as its Content-Range header reported it.

type BlobUploadArguments added in v0.2.0

type BlobUploadArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The blobs to create, keyed by creation id, which the rest of the request
	// may refer to as "#" followed by that id.
	Create map[ID]BlobUploadObject `json:"create,omitzero"`
}

BlobUploadArguments holds the arguments of the Blob/upload method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobUploadObject added in v0.2.0

type BlobUploadObject struct {
	// The sources of the blob's octets, concatenated in order.
	Data []BlobDataSource `json:"data,omitzero"`

	// The media type to record for the blob. The server may disregard it.
	//
	// The server assumes null when this property is omitted.
	Type *string `json:"type,omitzero"`
}

BlobUploadObject is one blob to create, given as the sources whose octets make it up. RFC 9404 calls it UploadObject.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobUploadResponse added in v0.2.0

type BlobUploadResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The blobs that were created, keyed by creation id.
	Created map[ID]BlobUploadResult `json:"created"`

	// A map of creation id to the reason the blob could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`
}

BlobUploadResponse holds the response to the Blob/upload method.

A request using this type must declare urn:ietf:params:jmap:blob.

type BlobUploadResult added in v0.2.0

type BlobUploadResult struct {
	// The id of the blob, to refer to it by from here on.
	ID ID `json:"id"`

	// The media type the server recorded for it.
	Type *string `json:"type"`

	// The size of the blob in octets.
	Size UnsignedInt `json:"size"`
}

BlobUploadResult is what the server made of one blob it was asked to create.

A request using this type must declare urn:ietf:params:jmap:blob.

type BusyPeriod

type BusyPeriod struct {
	// When the period starts.
	UTCStart UTCDate `json:"utcStart,omitzero"`

	// When the period ends.
	UTCEnd UTCDate `json:"utcEnd,omitzero"`

	// How busy: "confirmed", "tentative", or "unavailable".
	//
	// The server assumes "unavailable" when this property is omitted.
	BusyStatus *string `json:"busyStatus,omitzero"`

	// The event that makes the principal busy, for a caller allowed to see it.
	Event *CalendarEvent `json:"event,omitzero"`
}

BusyPeriod is a stretch of time a principal is not free.

A request using this type must declare urn:ietf:params:jmap:principals:availability.

type Calendar

type Calendar struct {
	// The id of the calendar.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The user-visible name of the calendar.
	Name string `json:"name,omitzero"`

	// A longer description of what the calendar holds.
	Description *string `json:"description,omitzero"`

	// A colour to show the calendar's events in, as a CSS colour value.
	Color *string `json:"color,omitzero"`

	// A hint for where to place the calendar in a list of them.
	//
	// The server assumes 0 when this property is omitted.
	SortOrder UnsignedInt `json:"sortOrder,omitzero"`

	// Whether the user has subscribed to the calendar.
	IsSubscribed bool `json:"isSubscribed,omitzero"`

	// Whether the calendar's events should be shown in a combined view.
	//
	// The server assumes true when this property is omitted.
	IsVisible *bool `json:"isVisible,omitzero"`

	// Whether this is the calendar an event goes into when the client does not
	// say.
	//
	// The server sets this property; it may not be set by the client.
	IsDefault bool `json:"isDefault,omitzero"`

	// Whether the calendar's events count towards the user's availability:
	// "all", "attending", or "none".
	IncludeInAvailability string `json:"includeInAvailability,omitzero"`

	// The alerts to apply to events in this calendar that have a time, for
	// events that ask for the defaults.
	DefaultAlertsWithTime map[ID]EventAlert `json:"defaultAlertsWithTime,omitzero"`

	// The alerts to apply to whole-day events in this calendar, for events that
	// ask for the defaults.
	DefaultAlertsWithoutTime map[ID]EventAlert `json:"defaultAlertsWithoutTime,omitzero"`

	// The time zone to show the calendar in, or null to use the user's own.
	TimeZone *TimeZoneID `json:"timeZone,omitzero"`

	// Who else the calendar is shared with, keyed by principal id, and what each
	// may do.
	ShareWith map[ID]CalendarRights `json:"shareWith,omitzero"`

	// What the authenticated user may do with the calendar.
	//
	// The server sets this property; it may not be set by the client.
	MyRights CalendarRights `json:"myRights,omitzero"`
}

Calendar is a named collection of events.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarChangesArguments

type CalendarChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Calendar/get or Calendar/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

CalendarChangesArguments holds the arguments of the Calendar/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarChangesResponse

type CalendarChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

CalendarChangesResponse holds the response to the Calendar/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEvent

type CalendarEvent struct {
	// The id of the event.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// For an occurrence returned by an expanded query, the id of the recurring
	// event it belongs to.
	//
	// The server sets this property; it may not be set by the client.
	BaseEventID *ID `json:"baseEventId,omitzero"`

	// The calendars the event is in, as a set of ids mapped to true.
	CalendarIDs map[ID]bool `json:"calendarIds,omitzero"`

	// Whether the event is still being written. A draft is not scheduled and
	// sends no invitations. It may be set to false, but not back to true.
	//
	// The server assumes false when this property is omitted.
	IsDraft bool `json:"isDraft,omitzero"`

	// Whether this server is the one that owns the event, as opposed to holding
	// a copy of someone else's.
	//
	// The server sets this property; it may not be set by the client.
	IsOrigin bool `json:"isOrigin,omitzero"`

	// When the event starts, in UTC. It is derived from start and the time zone,
	// and setting it moves the event.
	UTCStart UTCDate `json:"utcStart,omitzero"`

	// When the event ends, in UTC. It is derived from utcStart and the duration,
	// and setting it changes the duration.
	UTCEnd UTCDate `json:"utcEnd,omitzero"`

	// Whether anyone who can see the event may add themselves as a participant.
	//
	// The server assumes false when this property is omitted.
	MayInviteSelf bool `json:"mayInviteSelf,omitzero"`

	// Whether a participant may invite others.
	//
	// The server assumes false when this property is omitted.
	MayInviteOthers bool `json:"mayInviteOthers,omitzero"`

	// Whether participants other than the owner should be hidden from each
	// other.
	//
	// The server assumes false when this property is omitted.
	HideAttendees bool `json:"hideAttendees,omitzero"`

	// The type of this object, which is "Event".
	Type string `json:"@type,omitzero"`

	// A globally unique identifier for the event, shared by every copy of it.
	UID string `json:"uid,omitzero"`

	// Other events this one relates to, keyed by their uid.
	RelatedTo map[string]EventRelation `json:"relatedTo,omitzero"`

	// The software that last modified the event.
	ProdID string `json:"prodId,omitzero"`

	// When the event was created.
	Created UTCDate `json:"created,omitzero"`

	// When the event was last modified.
	Updated UTCDate `json:"updated,omitzero"`

	// How many times the event has been revised in a way participants should be
	// told about.
	//
	// The server assumes 0 when this property is omitted.
	Sequence UnsignedInt `json:"sequence,omitzero"`

	// The scheduling method this copy of the event was delivered with, such as
	// "request" or "reply".
	Method string `json:"method,omitzero"`

	// A short summary of the event.
	//
	// The server assumes "" when this property is omitted.
	Title *string `json:"title,omitzero"`

	// A longer description of the event.
	//
	// The server assumes "" when this property is omitted.
	Description *string `json:"description,omitzero"`

	// The media type of the description.
	//
	// The server assumes "text/plain" when this property is omitted.
	DescriptionContentType *string `json:"descriptionContentType,omitzero"`

	// Whether the event should be shown as taking a whole day rather than at a
	// particular time.
	//
	// The server assumes false when this property is omitted.
	ShowWithoutTime bool `json:"showWithoutTime,omitzero"`

	// Where the event happens, keyed by an id local to the event.
	Locations map[ID]EventLocation `json:"locations,omitzero"`

	// Where the event happens online, keyed by an id local to the event.
	VirtualLocations map[ID]EventVirtualLocation `json:"virtualLocations,omitzero"`

	// Resources associated with the event, keyed by an id local to the event.
	Links map[ID]EventLink `json:"links,omitzero"`

	// The language the event's text is written in, as an RFC 5646 tag.
	Locale string `json:"locale,omitzero"`

	// Free-text keywords on the event, mapped to true.
	Keywords map[string]bool `json:"keywords,omitzero"`

	// The URIs of categories the event belongs to, mapped to true.
	Categories map[string]bool `json:"categories,omitzero"`

	// A colour to show the event in, as a CSS colour value.
	Color string `json:"color,omitzero"`

	// For one occurrence of a recurring event, the start the recurrence rules
	// gave it.
	RecurrenceID LocalDateTime `json:"recurrenceId,omitzero"`

	// The time zone the recurrenceId is in.
	//
	// The server assumes null when this property is omitted.
	RecurrenceIDTimeZone *TimeZoneID `json:"recurrenceIdTimeZone,omitzero"`

	// How the event repeats.
	RecurrenceRules []EventRecurrenceRule `json:"recurrenceRules,omitzero"`

	// Occurrences to leave out of what the recurrence rules generate.
	ExcludedRecurrenceRules []EventRecurrenceRule `json:"excludedRecurrenceRules,omitzero"`

	// Changes to particular occurrences, keyed by the start the rules gave them.
	// A patch that sets excluded to true removes the occurrence.
	RecurrenceOverrides map[LocalDateTime]PatchObject `json:"recurrenceOverrides,omitzero"`

	// Whether this occurrence has been removed from the series.
	//
	// The server assumes false when this property is omitted.
	Excluded bool `json:"excluded,omitzero"`

	// How important the event is, from 1 (highest) to 9 (lowest), with 0 meaning
	// undefined.
	//
	// The server assumes 0 when this property is omitted.
	Priority Int `json:"priority,omitzero"`

	// Whether the event makes the user unavailable: "free" or "busy".
	//
	// The server assumes "busy" when this property is omitted.
	FreeBusyStatus *string `json:"freeBusyStatus,omitzero"`

	// How much of the event others may see: "public", "private", or "secret".
	//
	// The server assumes "public" when this property is omitted.
	Privacy *string `json:"privacy,omitzero"`

	// Where to send replies, keyed by method, such as "imip" mapped to a mailto:
	// URI.
	ReplyTo map[string]string `json:"replyTo,omitzero"`

	// The address of whoever sent this copy of the event.
	SentBy string `json:"sentBy,omitzero"`

	// Who is taking part, keyed by an id local to the event.
	Participants map[ID]EventParticipant `json:"participants,omitzero"`

	// The status of the last scheduling request, as an iCalendar REQUEST-STATUS
	// value.
	RequestStatus string `json:"requestStatus,omitzero"`

	// Whether to use the calendar's default alerts instead of the ones on the
	// event.
	//
	// The server assumes false when this property is omitted.
	UseDefaultAlerts bool `json:"useDefaultAlerts,omitzero"`

	// The reminders for this event, keyed by an id local to the event.
	Alerts map[ID]EventAlert `json:"alerts,omitzero"`

	// Translations of the event's text, keyed by language tag. Each is a patch
	// to apply to the event to render it in that language.
	Localizations map[string]PatchObject `json:"localizations,omitzero"`

	// The time zone the start is in. Null means the event is floating, and
	// happens at that local time wherever the user is.
	//
	// The server assumes null when this property is omitted.
	TimeZone *TimeZoneID `json:"timeZone,omitzero"`

	// Time zones the event defines itself, for zones the IANA database does not
	// have, keyed by an id beginning with "/".
	TimeZones map[TimeZoneID]EventTimeZone `json:"timeZones,omitzero"`

	// When the event starts, in the event's own time zone.
	Start LocalDateTime `json:"start,omitzero"`

	// How long the event lasts.
	//
	// The server assumes "PT0S" when this property is omitted.
	Duration *Duration `json:"duration,omitzero"`

	// Whether the event is going ahead: "confirmed", "cancelled", or
	// "tentative".
	//
	// The server assumes "confirmed" when this property is omitted.
	Status *string `json:"status,omitzero"`
}

CalendarEvent is one event, or a recurring series of them. It is a JSCalendar JSEvent, as defined by RFC 8984, with the properties JMAP adds for storing it in an account.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventChangesArguments

type CalendarEventChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// CalendarEvent/get or CalendarEvent/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

CalendarEventChangesArguments holds the arguments of the CalendarEvent/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventChangesResponse

type CalendarEventChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

CalendarEventChangesResponse holds the response to the CalendarEvent/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventCopyArguments

type CalendarEventCopyArguments struct {
	// The id of the account to copy records from.
	FromAccountID ID `json:"fromAccountId,omitzero"`

	// The state the source account is expected to be in.
	IfFromInState *string `json:"ifFromInState,omitzero"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the destination account is expected to be in.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to copy, each of which must have an id
	// property naming the record in the source account.
	Create map[ID]CalendarEvent `json:"create,omitzero"`

	// Whether to destroy the originals once the copy succeeds.
	//
	// The server assumes false when this property is omitted.
	OnSuccessDestroyOriginal bool `json:"onSuccessDestroyOriginal,omitzero"`

	// The state the source account must be in for the originals to be destroyed.
	DestroyFromIfInState *string `json:"destroyFromIfInState,omitzero"`
}

CalendarEventCopyArguments holds the arguments of the CalendarEvent/copy method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventCopyResponse

type CalendarEventCopyResponse struct {
	// The id of the account the records were copied from.
	FromAccountID ID `json:"fromAccountId"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state of the destination account before the copy.
	OldState *string `json:"oldState"`

	// The state of the destination account after the copy.
	NewState string `json:"newState"`

	// A map of creation id to the record created in the destination account.
	Created map[ID]CalendarEvent `json:"created"`

	// A map of creation id to the reason the record could not be copied.
	NotCreated map[ID]SetError `json:"notCreated"`
}

CalendarEventCopyResponse holds the response to the CalendarEvent/copy method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventFilterCondition

type CalendarEventFilterCondition struct {
	// Matches events in this calendar.
	InCalendar *ID `json:"inCalendar,omitzero"`

	// Matches events that end at or after this time.
	After *LocalDateTime `json:"after,omitzero"`

	// Matches events that start before this time.
	Before *LocalDateTime `json:"before,omitzero"`

	// Matches events where this text appears in the title, description,
	// location, or a participant.
	Text *string `json:"text,omitzero"`

	// Matches events where this text appears in the title.
	Title *string `json:"title,omitzero"`

	// Matches events where this text appears in the description.
	Description *string `json:"description,omitzero"`

	// Matches events where this text appears in a location.
	Location *string `json:"location,omitzero"`

	// Matches events with an owner at this address.
	Owner *string `json:"owner,omitzero"`

	// Matches events with an attendee at this address.
	Attendee *string `json:"attendee,omitzero"`

	// Matches the event with this uid.
	UID string `json:"uid,omitzero"`
}

CalendarEventFilterCondition is a condition an event must satisfy to match a CalendarEvent/query.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventGetArguments

type CalendarEventGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`

	// Leave out the overrides for occurrences starting at or after this time, so
	// that a client showing one month need not fetch every exception to a long
	// series.
	RecurrenceOverridesBefore *UTCDate `json:"recurrenceOverridesBefore,omitzero"`

	// Leave out the overrides for occurrences starting before this time.
	RecurrenceOverridesAfter *UTCDate `json:"recurrenceOverridesAfter,omitzero"`

	// Return only the participants the user is likely to care about: themselves,
	// the owners, and whoever replied.
	//
	// The server assumes false when this property is omitted.
	ReduceParticipants bool `json:"reduceParticipants,omitzero"`

	// The time zone to interpret the recurrence override bounds in.
	//
	// The server assumes "Etc/UTC" when this property is omitted.
	TimeZone *TimeZoneID `json:"timeZone,omitzero"`
}

CalendarEventGetArguments holds the arguments of the CalendarEvent/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventGetResponse

type CalendarEventGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with CalendarEvent/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []CalendarEvent `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

CalendarEventGetResponse holds the response to the CalendarEvent/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotification

type CalendarEventNotification struct {
	// The id of the notification.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// When the change was made.
	//
	// The server sets this property; it may not be set by the client.
	Created UTCDate `json:"created,omitzero"`

	// Who made the change.
	//
	// The server sets this property; it may not be set by the client.
	ChangedBy CalendarPerson `json:"changedBy,omitzero"`

	// A comment they sent with the change.
	Comment *string `json:"comment,omitzero"`

	// What happened: "created", "updated", or "destroyed".
	Type string `json:"type,omitzero"`

	// The id of the event that changed.
	CalendarEventID ID `json:"calendarEventId,omitzero"`

	// Whether the event was a draft at the time, for a creation or an update.
	IsDraft bool `json:"isDraft,omitzero"`

	// The event as it was after the change, or as it was before being destroyed.
	Event CalendarEvent `json:"event,omitzero"`

	// What changed, for an update.
	EventPatch PatchObject `json:"eventPatch,omitzero"`
}

CalendarEventNotification records a change someone else made to an event the user has a stake in, so that a client can show what happened while it was away.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationChangesArguments

type CalendarEventNotificationChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// CalendarEventNotification/get or CalendarEventNotification/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

CalendarEventNotificationChangesArguments holds the arguments of the CalendarEventNotification/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationChangesResponse

type CalendarEventNotificationChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

CalendarEventNotificationChangesResponse holds the response to the CalendarEventNotification/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationFilterCondition

type CalendarEventNotificationFilterCondition struct {
	// Matches notifications created at or after this time.
	After *UTCDate `json:"after,omitzero"`

	// Matches notifications created before this time.
	Before *UTCDate `json:"before,omitzero"`

	// Matches notifications of this type.
	Type string `json:"type,omitzero"`

	// Matches notifications about one of these events.
	CalendarEventIDs []ID `json:"calendarEventIds,omitzero"`
}

CalendarEventNotificationFilterCondition is a condition a notification must satisfy to match a CalendarEventNotification/query.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationGetArguments

type CalendarEventNotificationGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

CalendarEventNotificationGetArguments holds the arguments of the CalendarEventNotification/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationGetResponse

type CalendarEventNotificationGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with CalendarEventNotification/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []CalendarEventNotification `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

CalendarEventNotificationGetResponse holds the response to the CalendarEventNotification/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationQueryArguments

type CalendarEventNotificationQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrCalendarEventNotificationFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

CalendarEventNotificationQueryArguments holds the arguments of the CalendarEventNotification/query method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationQueryChangesArguments

type CalendarEventNotificationQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrCalendarEventNotificationFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// CalendarEventNotification/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

CalendarEventNotificationQueryChangesArguments holds the arguments of the CalendarEventNotification/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationQueryChangesResponse

type CalendarEventNotificationQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

CalendarEventNotificationQueryChangesResponse holds the response to the CalendarEventNotification/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationQueryResponse

type CalendarEventNotificationQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with CalendarEventNotification/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

CalendarEventNotificationQueryResponse holds the response to the CalendarEventNotification/query method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationSetArguments

type CalendarEventNotificationSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]CalendarEventNotification `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

CalendarEventNotificationSetArguments holds the arguments of the CalendarEventNotification/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventNotificationSetResponse

type CalendarEventNotificationSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*CalendarEventNotification `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*CalendarEventNotification `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

CalendarEventNotificationSetResponse holds the response to the CalendarEventNotification/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventParseArguments

type CalendarEventParseArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the blobs to parse as iCalendar files.
	BlobIDs []ID `json:"blobIds,omitzero"`

	// The properties to include in each parsed event, or null for all of them.
	Properties []string `json:"properties,omitzero"`
}

CalendarEventParseArguments holds the arguments of the CalendarEvent/parse method.

A request using this type must declare urn:ietf:params:jmap:calendars:parse.

type CalendarEventParseResponse

type CalendarEventParseResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The events found in each blob, keyed by blob id. A file may hold more than
	// one event.
	Parsed map[ID][]CalendarEvent `json:"parsed"`

	// The ids of the blobs that do not hold an iCalendar file the server could
	// read.
	NotParsable []ID `json:"notParsable"`

	// The ids of the blobs that do not exist.
	NotFound []ID `json:"notFound"`
}

CalendarEventParseResponse holds the response to the CalendarEvent/parse method.

A request using this type must declare urn:ietf:params:jmap:calendars:parse.

type CalendarEventQueryArguments

type CalendarEventQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrCalendarEventFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to return one id per occurrence of a recurring event rather than
	// one for the series. The filter must then be limited in time, and the
	// results cannot be sorted by uid.
	//
	// The server assumes false when this property is omitted.
	ExpandRecurrences bool `json:"expandRecurrences,omitzero"`

	// The time zone to interpret a floating event's times in when expanding
	// recurrences.
	TimeZone TimeZoneID `json:"timeZone,omitzero"`
}

CalendarEventQueryArguments holds the arguments of the CalendarEvent/query method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventQueryChangesArguments

type CalendarEventQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrCalendarEventFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// CalendarEvent/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to return one id per occurrence of a recurring event rather than
	// one for the series. The filter must then be limited in time, and the
	// results cannot be sorted by uid.
	//
	// The server assumes false when this property is omitted.
	ExpandRecurrences bool `json:"expandRecurrences,omitzero"`

	// The time zone to interpret a floating event's times in when expanding
	// recurrences.
	TimeZone TimeZoneID `json:"timeZone,omitzero"`
}

CalendarEventQueryChangesArguments holds the arguments of the CalendarEvent/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventQueryChangesResponse

type CalendarEventQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

CalendarEventQueryChangesResponse holds the response to the CalendarEvent/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventQueryResponse

type CalendarEventQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with CalendarEvent/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

CalendarEventQueryResponse holds the response to the CalendarEvent/query method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventSetArguments

type CalendarEventSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]CalendarEvent `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// Whether the server should send invitations and replies for the changes
	// this call makes.
	//
	// The server assumes false when this property is omitted.
	SendSchedulingMessages bool `json:"sendSchedulingMessages,omitzero"`
}

CalendarEventSetArguments holds the arguments of the CalendarEvent/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarEventSetResponse

type CalendarEventSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*CalendarEvent `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*CalendarEvent `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

CalendarEventSetResponse holds the response to the CalendarEvent/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarGetArguments

type CalendarGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

CalendarGetArguments holds the arguments of the Calendar/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarGetResponse

type CalendarGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Calendar/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Calendar `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

CalendarGetResponse holds the response to the Calendar/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarPerson

type CalendarPerson struct {
	// The name of the person who made the change.
	Name string `json:"name,omitzero"`

	// Their email address.
	Email *string `json:"email,omitzero"`

	// Their principal id, for someone the server knows.
	PrincipalID *ID `json:"principalId,omitzero"`

	// The calendar address they acted as.
	CalendarAddress *string `json:"calendarAddress,omitzero"`
}

CalendarPerson identifies whoever made a change to an event. The specification calls it Person; the name is qualified here because it is far too general to claim on its own.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarRights

type CalendarRights struct {
	// Whether the user may see when the calendar is busy, without seeing what
	// for.
	MayReadFreeBusy bool `json:"mayReadFreeBusy,omitzero"`

	// Whether the user may read the events themselves.
	MayReadItems bool `json:"mayReadItems,omitzero"`

	// Whether the user may modify any event in the calendar.
	MayWriteAll bool `json:"mayWriteAll,omitzero"`

	// Whether the user may modify the events they own.
	MayWriteOwn bool `json:"mayWriteOwn,omitzero"`

	// Whether the user may change the properties that are private to them, such
	// as alerts and colour.
	MayUpdatePrivate bool `json:"mayUpdatePrivate,omitzero"`

	// Whether the user may reply to invitations in the calendar.
	MayRSVP bool `json:"mayRSVP,omitzero"`

	// Whether the user may change who else the calendar is shared with.
	MayShare bool `json:"mayShare,omitzero"`

	// Whether the user may delete the calendar itself.
	MayDelete bool `json:"mayDelete,omitzero"`
}

CalendarRights says what the authenticated user may do with a calendar.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarSetArguments

type CalendarSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]Calendar `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// Whether destroying a calendar may also destroy the events in it. If false,
	// destroying one that is not empty fails.
	//
	// The server assumes false when this property is omitted.
	OnDestroyRemoveEvents bool `json:"onDestroyRemoveEvents,omitzero"`

	// The id of the calendar to make the default once the other changes succeed.
	OnSuccessSetIsDefault *ID `json:"onSuccessSetIsDefault,omitzero"`
}

CalendarSetArguments holds the arguments of the Calendar/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CalendarSetResponse

type CalendarSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*Calendar `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*Calendar `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

CalendarSetResponse holds the response to the Calendar/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type CallInfo added in v0.12.0

type CallInfo struct {
	Name   string
	CallID string
}

CallInfo identifies one method call of a request: the method invoked, and the call id under which the response reports its result.

type CatchUp added in v0.6.0

type CatchUp func(ctx context.Context, sinceState string) (newState string, more bool, err error)

CatchUp fetches what changed since a state and reports the resulting state, together with whether the server has more changes to report. Watch calls it, and calls it again while more is true, because a server answers a /changes call with as many changes as it chooses rather than with all of them.

An error stops the watch and is what Watch returns.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client sends JMAP requests to one server. It is safe for concurrent use, and it caches the Session object so that repeated queries cost one round trip each.

func New

func New(sessionURL string, opts ...Option) *Client

New returns a client that discovers the server through the session resource at sessionURL. Use WellKnownURL to build that URL from a bare hostname.

func (*Client) Do

func (c *Client) Do(ctx context.Context, r *Request) (*Response, error)

Do sends one JMAP request and returns the decoded response. Method-level errors do not fail the call: the response is returned alongside a MethodErrors describing the calls the server could not execute, because the remaining calls may still have produced usable results.

func (*Client) Download

func (c *Client) Download(ctx context.Context, accountID, blobID ID, opts *DownloadOptions) (*Blob, error)

Download fetches a blob's content. The caller must close the returned blob.

A blob has no type of its own: the server serves it as whatever type the download requests, within what it considers safe. Pass the type from the body part that referred to the blob.

func (*Client) EventSource

func (c *Client) EventSource(ctx context.Context, opts *EventSourceOptions) (*EventStream, error)

EventSource opens a connection to the server's push endpoint, as described in RFC 8620, Section 7.3.

The connection stays open until it is closed or the server drops it, which it will do: a stream is a connection, not a subscription that outlives the network. Treat an error from Next as a signal to reconnect, passing LastEventID so that nothing is missed in between.

func (*Client) PrimaryAccountID

func (c *Client) PrimaryAccountID(ctx context.Context, capability string) (ID, error)

PrimaryAccountID returns the id of the account to use by default for a capability, fetching the session if it has not been fetched yet.

func (*Client) RefreshSession

func (c *Client) RefreshSession(ctx context.Context) (*Session, error)

RefreshSession re-fetches the Session object and replaces the cached copy. Call it when a response reports a sessionState different from the one the cached session carries.

func (*Client) Session

func (c *Client) Session(ctx context.Context) (*Session, error)

Session returns the server's Session object, fetching it on first use and caching it afterwards.

func (*Client) Upload

func (c *Client) Upload(ctx context.Context, accountID ID, contentType string, body io.Reader) (*BlobInfo, error)

Upload sends a blob to the account and returns the id to refer to it by. A blob is unreferenced until something points at it, such as an Email/set that names it in a body part, and a server may discard a blob nothing refers to.

The contentType is a hint. The server records the type it determines for the blob, which is what BlobInfo reports.

func (*Client) Watch added in v0.6.0

func (c *Client) Watch(ctx context.Context, accountID ID, typeName, state string, catchUp CatchUp, opts ...WatchOption) error

Watch follows one type's changes in one account, for as long as the context lasts.

A push event reports only that a type has changed, not what changed, so every client that follows changes writes the same loop: connect, request the changes since the state it holds, apply them, and wait for the next event. The parts of that loop which are easy to get wrong are implemented here rather than by the caller. A stream is a connection and not a subscription, so a dropped one is reopened, resuming from the last event it delivered, with a delay that doubles while the server is unreachable. Every connection is followed by a catch-up, because changes made while no connection was open were not pushed. And a server that returns only part of what changed is asked again until it reports no more.

state is where the loop starts: the state a previous /get or /changes reported, which the caller holds alongside the records it fetched then.

It returns the context's error when the context ends, the caller's error when catchUp fails, and a *RequestError when the server refuses the connection for a reason that retrying will not resolve.

type Comparator

type Comparator struct {
	// The property of the record to compare.
	Property string `json:"property,omitzero"`

	// Whether the comparison sorts ascending.
	//
	// The server assumes true when this property is omitted.
	IsAscending *bool `json:"isAscending,omitzero"`

	// The collation algorithm to compare strings with.
	Collation *string `json:"collation,omitzero"`
}

Comparator is one term of the sort order applied by a /query call.

type ContactAddress

type ContactAddress struct {
	// The type of this object, which is "Address".
	Type string `json:"@type,omitzero"`

	// The parts of the address.
	Components []ContactAddressComponent `json:"components,omitzero"`

	// Whether the components are already in the order they should be displayed
	// in.
	//
	// The server assumes false when this property is omitted.
	IsOrdered bool `json:"isOrdered,omitzero"`

	// The ISO 3166-1 alpha-2 code of the country.
	CountryCode string `json:"countryCode,omitzero"`

	// The location as a geo: URI, as defined by RFC 5870.
	Coordinates string `json:"coordinates,omitzero"`

	// The time zone the address is in, named as in the IANA Time Zone Database.
	TimeZone string `json:"timeZone,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// The address written out in full, for display.
	Full string `json:"full,omitzero"`

	// What to put between the components when joining them, where no separator
	// component says otherwise.
	DefaultSeparator string `json:"defaultSeparator,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// The script the phonetic members of the components are written in.
	PhoneticScript string `json:"phoneticScript,omitzero"`

	// The system the phonetic members use: "ipa", "jyut", or "piny".
	PhoneticSystem string `json:"phoneticSystem,omitzero"`
}

ContactAddress is a place associated with the entity, as an ordered set of parts rather than as one string. RFC 9553 calls it Address; it is unrelated to the Address of JMAP for Mail, which is an SMTP envelope address.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactAddressComponent

type ContactAddressComponent struct {
	// The type of this object, which is "AddressComponent".
	Type string `json:"@type,omitzero"`

	// The value of this part of the address.
	Value string `json:"value,omitzero"`

	// What part of the address this is: "room", "apartment", "floor",
	// "building", "number", "name", "block", "subdistrict", "district",
	// "locality", "region", "postcode", "country", "direction", "landmark",
	// "postOfficeBox", or "separator".
	Kind string `json:"kind,omitzero"`

	// How to pronounce this part, in the script and system the address gives.
	Phonetic string `json:"phonetic,omitzero"`
}

ContactAddressComponent is one part of an address, such as a street name or a postcode. RFC 9553 calls it AddressComponent.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactAnniversary

type ContactAnniversary struct {
	// The type of this object, which is "Anniversary".
	Type string `json:"@type,omitzero"`

	// What the date marks: "birth", "death", or "wedding".
	Kind string `json:"kind,omitzero"`

	// The date, either partially known or exact. A value with no @type is a
	// partial date.
	Date ContactPartialDateOrContactTimestamp `json:"date,omitzero"`

	// Where the anniversary took place.
	Place ContactAddress `json:"place,omitzero"`
}

ContactAnniversary is a date of significance to the entity, such as a birthday. RFC 9553 calls it Anniversary.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactAuthor

type ContactAuthor struct {
	// The type of this object, which is "Author".
	Type string `json:"@type,omitzero"`

	// The name of the author.
	Name string `json:"name,omitzero"`

	// A URI identifying the author.
	URI string `json:"uri,omitzero"`
}

ContactAuthor is who wrote a note. RFC 9553 calls it Author; at least one of its members besides @type is set.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCalendar

type ContactCalendar struct {
	// The type of this object, which is "Calendar".
	Type string `json:"@type,omitzero"`

	// What the resource is: "calendar" or "freeBusy".
	Kind string `json:"kind,omitzero"`

	// The URI where the calendar is found.
	URI string `json:"uri,omitzero"`

	// The media type of the calendar, as registered with IANA.
	MediaType string `json:"mediaType,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactCalendar is a calendar or free-busy feed belonging to the entity. RFC 9553 calls it Calendar, and it is a kind of Resource.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCard

type ContactCard struct {
	// The id of the card.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The address books the card is in, as a set of ids mapped to true.
	AddressBookIDs map[ID]bool `json:"addressBookIds,omitzero"`

	// The type of this object, which is "Card".
	Type string `json:"@type,omitzero"`

	// The version of JSContact the card is written in, which is "1.0".
	Version string `json:"version,omitzero"`

	// When the card was created.
	Created UTCDate `json:"created,omitzero"`

	// What the card describes: "individual", "group", "org", "location",
	// "device", or "application". Absent means "individual".
	Kind string `json:"kind,omitzero"`

	// The language the card's text is written in, as an RFC 5646 tag.
	Language string `json:"language,omitzero"`

	// The uids of the cards belonging to this one, mapped to true, for a card
	// whose kind is "group".
	Members map[string]bool `json:"members,omitzero"`

	// The software that last modified the card.
	ProdID string `json:"prodId,omitzero"`

	// Other entities related to this one, keyed by their uid.
	RelatedTo map[string]ContactRelation `json:"relatedTo,omitzero"`

	// A globally unique identifier for the entity, which survives being copied
	// between address books.
	UID string `json:"uid,omitzero"`

	// When the card was last modified.
	Updated UTCDate `json:"updated,omitzero"`

	// The name of the entity.
	Name ContactName `json:"name,omitzero"`

	// Other names the entity goes by, keyed by an id local to the card.
	Nicknames map[ID]ContactNickname `json:"nicknames,omitzero"`

	// The organizations the entity belongs to, keyed by an id local to the card.
	Organizations map[ID]ContactOrganization `json:"organizations,omitzero"`

	// How to address the entity.
	SpeakToAs ContactSpeakToAs `json:"speakToAs,omitzero"`

	// The positions and roles the entity holds, keyed by an id local to the
	// card.
	Titles map[ID]ContactTitle `json:"titles,omitzero"`

	// The addresses the entity receives mail at, keyed by an id local to the
	// card.
	Emails map[ID]ContactEmailAddress `json:"emails,omitzero"`

	// The entity's accounts with online services, keyed by an id local to the
	// card.
	OnlineServices map[ID]ContactOnlineService `json:"onlineServices,omitzero"`

	// The numbers the entity can be reached on, keyed by an id local to the
	// card.
	Phones map[ID]ContactPhone `json:"phones,omitzero"`

	// The languages the entity prefers to be contacted in, keyed by an id local
	// to the card.
	PreferredLanguages map[ID]ContactLanguagePref `json:"preferredLanguages,omitzero"`

	// The entity's calendars and free-busy feeds, keyed by an id local to the
	// card.
	Calendars map[ID]ContactCalendar `json:"calendars,omitzero"`

	// Where to send the entity scheduling requests, keyed by an id local to the
	// card.
	SchedulingAddresses map[ID]ContactSchedulingAddress `json:"schedulingAddresses,omitzero"`

	// The places associated with the entity, keyed by an id local to the card.
	Addresses map[ID]ContactAddress `json:"addresses,omitzero"`

	// The entity's public keys and certificates, keyed by an id local to the
	// card.
	CryptoKeys map[ID]ContactCryptoKey `json:"cryptoKeys,omitzero"`

	// The directories the entity is listed in, keyed by an id local to the card.
	Directories map[ID]ContactDirectory `json:"directories,omitzero"`

	// Other resources related to the entity, keyed by an id local to the card.
	Links map[ID]ContactLink `json:"links,omitzero"`

	// Photographs, logos, and sound clips of the entity, keyed by an id local to
	// the card.
	Media map[ID]ContactMedia `json:"media,omitzero"`

	// Translations of the card's text, keyed by language tag. Each is a patch to
	// apply to the card to render it in that language.
	Localizations map[string]PatchObject `json:"localizations,omitzero"`

	// Dates of significance to the entity, keyed by an id local to the card.
	Anniversaries map[ID]ContactAnniversary `json:"anniversaries,omitzero"`

	// Free-text keywords the user has put on the card, mapped to true.
	Keywords map[string]bool `json:"keywords,omitzero"`

	// Free text about the entity, keyed by an id local to the card.
	Notes map[ID]ContactNote `json:"notes,omitzero"`

	// What the entity is interested in or good at, keyed by an id local to the
	// card.
	PersonalInfo map[ID]ContactPersonalInfo `json:"personalInfo,omitzero"`
}

ContactCard is one entry in an address book: a person, an organization, or anything else a card can describe. It is a JSContact Card, as defined by RFC 9553, with the id and addressBookIds that JMAP adds.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardChangesArguments

type ContactCardChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// ContactCard/get or ContactCard/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

ContactCardChangesArguments holds the arguments of the ContactCard/changes method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardChangesResponse

type ContactCardChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

ContactCardChangesResponse holds the response to the ContactCard/changes method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardCopyArguments

type ContactCardCopyArguments struct {
	// The id of the account to copy records from.
	FromAccountID ID `json:"fromAccountId,omitzero"`

	// The state the source account is expected to be in.
	IfFromInState *string `json:"ifFromInState,omitzero"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the destination account is expected to be in.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to copy, each of which must have an id
	// property naming the record in the source account.
	Create map[ID]ContactCard `json:"create,omitzero"`

	// Whether to destroy the originals once the copy succeeds.
	//
	// The server assumes false when this property is omitted.
	OnSuccessDestroyOriginal bool `json:"onSuccessDestroyOriginal,omitzero"`

	// The state the source account must be in for the originals to be destroyed.
	DestroyFromIfInState *string `json:"destroyFromIfInState,omitzero"`
}

ContactCardCopyArguments holds the arguments of the ContactCard/copy method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardCopyResponse

type ContactCardCopyResponse struct {
	// The id of the account the records were copied from.
	FromAccountID ID `json:"fromAccountId"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state of the destination account before the copy.
	OldState *string `json:"oldState"`

	// The state of the destination account after the copy.
	NewState string `json:"newState"`

	// A map of creation id to the record created in the destination account.
	Created map[ID]ContactCard `json:"created"`

	// A map of creation id to the reason the record could not be copied.
	NotCreated map[ID]SetError `json:"notCreated"`
}

ContactCardCopyResponse holds the response to the ContactCard/copy method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardFilterCondition

type ContactCardFilterCondition struct {
	// Matches cards in this address book.
	InAddressBook ID `json:"inAddressBook,omitzero"`

	// Matches the card with this uid.
	UID string `json:"uid,omitzero"`

	// Matches group cards having a member with this uid.
	HasMember string `json:"hasMember,omitzero"`

	// Matches cards of this kind.
	Kind string `json:"kind,omitzero"`

	// Matches cards created before this time.
	CreatedBefore UTCDate `json:"createdBefore,omitzero"`

	// Matches cards created at or after this time.
	CreatedAfter UTCDate `json:"createdAfter,omitzero"`

	// Matches cards last modified before this time.
	UpdatedBefore UTCDate `json:"updatedBefore,omitzero"`

	// Matches cards last modified at or after this time.
	UpdatedAfter UTCDate `json:"updatedAfter,omitzero"`

	// Matches cards where this text appears in any of the properties the other
	// conditions search individually.
	Text string `json:"text,omitzero"`

	// Matches cards where this text appears in the name.
	Name string `json:"name,omitzero"`

	// Matches cards where this text appears in a given name component.
	NameGiven string `json:"name/given,omitzero"`

	// Matches cards where this text appears in a surname component.
	NameSurname string `json:"name/surname,omitzero"`

	// Matches cards where this text appears in a secondary surname component.
	NameSurname2 string `json:"name/surname2,omitzero"`

	// Matches cards where this text appears in a nickname.
	Nickname string `json:"nickname,omitzero"`

	// Matches cards where this text appears in an organization name or unit.
	Organization string `json:"organization,omitzero"`

	// Matches cards where this text appears in an email address.
	Email string `json:"email,omitzero"`

	// Matches cards where this text appears in a phone number.
	Phone string `json:"phone,omitzero"`

	// Matches cards where this text appears in an online service name, uri, or
	// user.
	OnlineService string `json:"onlineService,omitzero"`

	// Matches cards where this text appears in an address.
	Address string `json:"address,omitzero"`

	// Matches cards where this text appears in a note.
	Note string `json:"note,omitzero"`
}

ContactCardFilterCondition is a condition a card must satisfy to match a ContactCard/query. Where a condition sets more than one property, a card must satisfy all of them.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardGetArguments

type ContactCardGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

ContactCardGetArguments holds the arguments of the ContactCard/get method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardGetResponse

type ContactCardGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with ContactCard/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []ContactCard `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

ContactCardGetResponse holds the response to the ContactCard/get method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardQueryArguments

type ContactCardQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrContactCardFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

ContactCardQueryArguments holds the arguments of the ContactCard/query method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardQueryChangesArguments

type ContactCardQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrContactCardFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// ContactCard/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

ContactCardQueryChangesArguments holds the arguments of the ContactCard/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardQueryChangesResponse

type ContactCardQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

ContactCardQueryChangesResponse holds the response to the ContactCard/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardQueryResponse

type ContactCardQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with ContactCard/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

ContactCardQueryResponse holds the response to the ContactCard/query method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardSetArguments

type ContactCardSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]ContactCard `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

ContactCardSetArguments holds the arguments of the ContactCard/set method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCardSetResponse

type ContactCardSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*ContactCard `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*ContactCard `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

ContactCardSetResponse holds the response to the ContactCard/set method.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactCryptoKey

type ContactCryptoKey struct {
	// The type of this object, which is "CryptoKey".
	Type string `json:"@type,omitzero"`

	// The kind of key, if the card says.
	Kind string `json:"kind,omitzero"`

	// The URI where the resource is found.
	URI string `json:"uri,omitzero"`

	// The media type of the resource, as registered with IANA.
	MediaType string `json:"mediaType,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactCryptoKey is a public key or certificate belonging to the entity. RFC 9553 calls it CryptoKey, and it is a kind of Resource.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactDirectory

type ContactDirectory struct {
	// The type of this object, which is "Directory".
	Type string `json:"@type,omitzero"`

	// What the resource is: "directory" for a directory the entity is listed in,
	// or "entry" for the entity's own entry.
	Kind string `json:"kind,omitzero"`

	// The URI where the resource is found.
	URI string `json:"uri,omitzero"`

	// The media type of the resource, as registered with IANA.
	MediaType string `json:"mediaType,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`

	// Where the entity sorts among the entries of the directory, counting from
	// 1.
	ListAs UnsignedInt `json:"listAs,omitzero"`
}

ContactDirectory is a directory the entity is listed in, or the entry within one. RFC 9553 calls it Directory, and it is a kind of Resource.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactEmailAddress

type ContactEmailAddress struct {
	// The type of this object, which is "EmailAddress".
	Type string `json:"@type,omitzero"`

	// The address itself, as an addr-spec.
	Address string `json:"address,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactEmailAddress is an address the entity receives mail at. RFC 9553 calls it EmailAddress; it is unrelated to the EmailAddress of JMAP for Mail, which is a header field value.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactLanguagePref

type ContactLanguagePref struct {
	// The type of this object, which is "LanguagePref".
	Type string `json:"@type,omitzero"`

	// The language tag, as defined by RFC 5646.
	Language string `json:"language,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`
}

ContactLanguagePref is a language the entity prefers to be contacted in. RFC 9553 calls it LanguagePref.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactLink struct {
	// The type of this object, which is "Link".
	Type string `json:"@type,omitzero"`

	// What the resource is: "contact" for a way of contacting the entity, or
	// absent if the card does not say.
	Kind string `json:"kind,omitzero"`

	// The URI where the resource is found.
	URI string `json:"uri,omitzero"`

	// The media type of the resource, as registered with IANA.
	MediaType string `json:"mediaType,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactLink is a resource related to the entity that no other property covers. RFC 9553 calls it Link, and it is a kind of Resource.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactMedia

type ContactMedia struct {
	// The type of this object, which is "Media".
	Type string `json:"@type,omitzero"`

	// What the resource is: "photo", "sound", or "logo".
	Kind string `json:"kind,omitzero"`

	// The URI where the resource is found.
	URI string `json:"uri,omitzero"`

	// The media type of the resource, as registered with IANA.
	MediaType string `json:"mediaType,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`

	// The id of the blob holding the content, for media the server stores
	// itself.
	BlobID ID `json:"blobId,omitzero"`
}

ContactMedia is a photograph, logo, or sound clip of the entity. RFC 9553 calls it Media, and it is a kind of Resource. JMAP for Contacts adds blobId, so that the content can be fetched from the server rather than from the URI.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactName

type ContactName struct {
	// The type of this object, which is "Name".
	Type string `json:"@type,omitzero"`

	// The parts of the name.
	Components []ContactNameComponent `json:"components,omitzero"`

	// Whether the components are already in the order they should be displayed
	// in.
	//
	// The server assumes false when this property is omitted.
	IsOrdered bool `json:"isOrdered,omitzero"`

	// What to put between the components when joining them, where no separator
	// component says otherwise.
	DefaultSeparator string `json:"defaultSeparator,omitzero"`

	// The name written out in full, for display.
	Full string `json:"full,omitzero"`

	// How to sort the name, keyed by the component kind the value sorts in place
	// of.
	SortAs map[string]string `json:"sortAs,omitzero"`

	// The script the phonetic members of the components are written in.
	PhoneticScript string `json:"phoneticScript,omitzero"`

	// The system the phonetic members use: "ipa", "jyut", or "piny".
	PhoneticSystem string `json:"phoneticSystem,omitzero"`
}

ContactName is the name of the entity a card describes, as an ordered set of parts rather than as one string. RFC 9553 calls it Name.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactNameComponent

type ContactNameComponent struct {
	// The type of this object, which is "NameComponent".
	Type string `json:"@type,omitzero"`

	// The value of this part of the name.
	Value string `json:"value,omitzero"`

	// What part of the name this is: "title", "given", "given2", "surname",
	// "surname2", "credential", "generation", or "separator".
	Kind string `json:"kind,omitzero"`

	// How to pronounce this part, written in the script and system the enclosing
	// name gives.
	Phonetic string `json:"phonetic,omitzero"`
}

ContactNameComponent is one part of a name, such as a given name or a surname. RFC 9553 calls it NameComponent.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactNickname

type ContactNickname struct {
	// The type of this object, which is "Nickname".
	Type string `json:"@type,omitzero"`

	// The nickname.
	Name string `json:"name,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`
}

ContactNickname is a name the entity is also known by. RFC 9553 calls it Nickname.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactNote

type ContactNote struct {
	// The type of this object, which is "Note".
	Type string `json:"@type,omitzero"`

	// The text of the note.
	Note string `json:"note,omitzero"`

	// When the note was written.
	Created UTCDate `json:"created,omitzero"`

	// Who wrote the note.
	Author ContactAuthor `json:"author,omitzero"`
}

ContactNote is free text about the entity. RFC 9553 calls it Note.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactOnlineService

type ContactOnlineService struct {
	// The type of this object, which is "OnlineService".
	Type string `json:"@type,omitzero"`

	// The name of the service, as the service itself spells it.
	Service string `json:"service,omitzero"`

	// The URI of the entity's presence on the service.
	URI string `json:"uri,omitzero"`

	// The entity's username on the service.
	User string `json:"user,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactOnlineService is an account the entity has with an online service. RFC 9553 calls it OnlineService; at least one of uri and user is set.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactOrgUnit

type ContactOrgUnit struct {
	// The type of this object, which is "OrgUnit".
	Type string `json:"@type,omitzero"`

	// The name of the unit.
	Name string `json:"name,omitzero"`

	// The value to sort the unit by, in place of its name.
	SortAs string `json:"sortAs,omitzero"`
}

ContactOrgUnit is a unit within an organization, such as a department. RFC 9553 calls it OrgUnit.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactOrganization

type ContactOrganization struct {
	// The type of this object, which is "Organization".
	Type string `json:"@type,omitzero"`

	// The name of the organization.
	Name string `json:"name,omitzero"`

	// The units within the organization, from the largest to the smallest.
	Units []ContactOrgUnit `json:"units,omitzero"`

	// The value to sort the organization by, in place of its name.
	SortAs string `json:"sortAs,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`
}

ContactOrganization is a company or other body the entity is associated with. RFC 9553 calls it Organization; at least one of name and units is set.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactPartialDate

type ContactPartialDate struct {
	// The type of this object, which is "PartialDate".
	Type string `json:"@type,omitzero"`

	// The year, if it is known.
	Year UnsignedInt `json:"year,omitzero"`

	// The month, from 1 to 12, if it is known.
	Month UnsignedInt `json:"month,omitzero"`

	// The day of the month, from 1 to 31, if it is known.
	Day UnsignedInt `json:"day,omitzero"`

	// The calendar system the date is given in, named as in CLDR. Absent means
	// Gregorian.
	CalendarScale string `json:"calendarScale,omitzero"`
}

ContactPartialDate is a date some of whose parts are unknown, such as a birthday with no year. RFC 9553 calls it PartialDate.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactPartialDateOrContactTimestamp added in v0.12.0

type ContactPartialDateOrContactTimestamp struct {
	// ContactPartialDate holds the value where it is a ContactPartialDate.
	ContactPartialDate *ContactPartialDate

	// ContactTimestamp holds the value where it is a ContactTimestamp.
	ContactTimestamp *ContactTimestamp
}

ContactPartialDateOrContactTimestamp is a value that is a ContactPartialDate or a ContactTimestamp.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (ContactPartialDateOrContactTimestamp) MarshalJSON added in v0.12.0

func (u ContactPartialDateOrContactTimestamp) MarshalJSON() ([]byte, error)

MarshalJSON writes whichever shape the value holds.

func (*ContactPartialDateOrContactTimestamp) UnmarshalJSON added in v0.12.0

func (u *ContactPartialDateOrContactTimestamp) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type ContactPersonalInfo

type ContactPersonalInfo struct {
	// The type of this object, which is "PersonalInfo".
	Type string `json:"@type,omitzero"`

	// What sort of information this is: "expertise", "hobby", or "interest".
	Kind string `json:"kind,omitzero"`

	// The interest or field of expertise itself.
	Value string `json:"value,omitzero"`

	// How much: "high", "medium", or "low".
	Level string `json:"level,omitzero"`

	// Where this sorts among the entity's other information of the same kind,
	// counting from 1.
	ListAs UnsignedInt `json:"listAs,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactPersonalInfo is something the entity is interested in or good at. RFC 9553 calls it PersonalInfo.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactPhone

type ContactPhone struct {
	// The type of this object, which is "Phone".
	Type string `json:"@type,omitzero"`

	// The number, either as a URI or as free text.
	Number string `json:"number,omitzero"`

	// What the number can be used for, mapped to true: "mobile", "voice",
	// "text", "video", "main-number", "textphone", "fax", or "pager".
	Features map[string]bool `json:"features,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactPhone is a number the entity can be reached on. RFC 9553 calls it Phone.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactPronouns

type ContactPronouns struct {
	// The type of this object, which is "Pronouns".
	Type string `json:"@type,omitzero"`

	// The pronouns, written as the entity would have them written.
	Pronouns string `json:"pronouns,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`
}

ContactPronouns is a set of pronouns to use for the entity. RFC 9553 calls it Pronouns.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactRelation

type ContactRelation struct {
	// The type of this object, which is "Relation".
	Type string `json:"@type,omitzero"`

	// The kinds of relation, mapped to true, such as "friend", "colleague", or
	// "spouse". An empty object means the entities are related in a way the card
	// does not name.
	//
	// The server assumes an empty object when this property is omitted.
	Relation map[string]bool `json:"relation,omitzero"`
}

ContactRelation says how another entity is related to this one. RFC 9553 calls it Relation.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactSchedulingAddress

type ContactSchedulingAddress struct {
	// The type of this object, which is "SchedulingAddress".
	Type string `json:"@type,omitzero"`

	// The address to send scheduling requests to, such as a mailto: URI.
	URI string `json:"uri,omitzero"`

	// The contexts this applies in, mapped to true: "private", "work", or a
	// context the object's own type defines.
	Contexts map[string]bool `json:"contexts,omitzero"`

	// How preferred this is among the alternatives, from 1 (most) to 100
	// (least).
	Pref UnsignedInt `json:"pref,omitzero"`

	// A human-readable label for this entry.
	Label string `json:"label,omitzero"`
}

ContactSchedulingAddress is where to send scheduling requests for the entity. RFC 9553 calls it SchedulingAddress.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactSpeakToAs

type ContactSpeakToAs struct {
	// The type of this object, which is "SpeakToAs".
	Type string `json:"@type,omitzero"`

	// The grammatical gender to use in salutations: "animate", "common",
	// "feminine", "inanimate", "masculine", or "neuter".
	GrammaticalGender string `json:"grammaticalGender,omitzero"`

	// The pronouns to use, keyed by an id local to the card.
	Pronouns map[ID]ContactPronouns `json:"pronouns,omitzero"`
}

ContactSpeakToAs says how to address the entity in speech and writing. RFC 9553 calls it SpeakToAs; at least one of its members is set.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactTimestamp

type ContactTimestamp struct {
	// The type of this object, which is "Timestamp".
	Type string `json:"@type,omitzero"`

	// The point in time, in UTC.
	UTC UTCDate `json:"utc,omitzero"`
}

ContactTimestamp is a date and time known exactly, which an anniversary may carry instead of a partial date. RFC 9553 calls it Timestamp.

A request using this type must declare urn:ietf:params:jmap:contacts.

type ContactTitle

type ContactTitle struct {
	// The type of this object, which is "Title".
	Type string `json:"@type,omitzero"`

	// The title or role.
	Name string `json:"name,omitzero"`

	// Whether this is a "title" or a "role".
	//
	// The server assumes "title" when this property is omitted.
	Kind *string `json:"kind,omitzero"`

	// The id, within this card's organizations, of the organization the title is
	// held in.
	OrganizationID ID `json:"organizationId,omitzero"`
}

ContactTitle is a position or role the entity holds. RFC 9553 calls it Title.

A request using this type must declare urn:ietf:params:jmap:contacts.

type CoreCapability

type CoreCapability struct {
	MaxSizeUpload         UnsignedInt `json:"maxSizeUpload"`
	MaxConcurrentUpload   UnsignedInt `json:"maxConcurrentUpload"`
	MaxSizeRequest        UnsignedInt `json:"maxSizeRequest"`
	MaxConcurrentRequests UnsignedInt `json:"maxConcurrentRequests"`
	MaxCallsInRequest     UnsignedInt `json:"maxCallsInRequest"`
	MaxObjectsInGet       UnsignedInt `json:"maxObjectsInGet"`
	MaxObjectsInSet       UnsignedInt `json:"maxObjectsInSet"`
	CollationAlgorithms   []string    `json:"collationAlgorithms"`
}

CoreCapability holds the server limits advertised under the core capability URI, as defined in RFC 8620, Section 2.

type CoreEchoArguments

type CoreEchoArguments struct {
}

CoreEchoArguments holds the arguments of the Core/echo method, which may be anything at all.

type CoreEchoResponse

type CoreEchoResponse struct {
}

CoreEchoResponse holds the response to the Core/echo method, which is the arguments it was given.

type Date

type Date struct {
	time.Time
}

Date is the JMAP Date data type: a date-time that carries its own UTC offset.

func NewDate

func NewDate(t time.Time) Date

NewDate returns t as a JMAP Date, preserving its location.

func (Date) MarshalJSON

func (d Date) MarshalJSON() ([]byte, error)

func (Date) String added in v0.10.0

func (d Date) String() string

String returns the date in the form it takes on the wire, offset included, for the same reason UTCDate has one.

func (*Date) UnmarshalJSON

func (d *Date) UnmarshalJSON(b []byte) error

type DeliveryStatus

type DeliveryStatus struct {
	// The SMTP reply the recipient's server gave, kept verbatim.
	SMTPReply string `json:"smtpReply,omitzero"`

	// How far the message got: "queued", "yes", "no", or "unknown".
	Delivered string `json:"delivered,omitzero"`

	// Whether the message was displayed to the recipient: "unknown" or "yes".
	Displayed string `json:"displayed,omitzero"`
}

DeliveryStatus is what became of a message for one of its recipients.

A request using this type must declare urn:ietf:params:jmap:submission.

type DownloadOptions

type DownloadOptions struct {
	// Name is the filename to request the blob be offered under. Servers use
	// it in the Content-Disposition header.
	Name string
	// Type is the media type to request the blob be served as. Servers use it
	// in the Content-Type header, and may refuse a type they consider
	// unsafe.
	Type string
	// From is the first octet to fetch, counted from the start of the blob.
	// Zero starts at the beginning.
	//
	// From and Length are sent as an HTTP Range header. JMAP does not define
	// one for the download endpoint, so a server is free to ignore it and
	// return the whole blob; where that happens the download fails rather than
	// returning content the caller would write at the wrong offset.
	From int64
	// Length is how many octets to fetch, and zero fetches to the end of the
	// blob.
	Length int64
}

DownloadOptions are the parameters a download may send beyond the blob id.

type Duration

type Duration string

Duration is the JSCalendar Duration of RFC 8984, Section 1.4.6: a length of time in the ISO 8601 form, such as "PT1H30M" for an hour and a half, or "P1D" for a day.

A day is not always 24 hours, so this is not a time.Duration: "P1D" across a daylight saving change is 23 or 25 hours. ToTimeDuration converts the part that can be converted.

func (Duration) String

func (d Duration) String() string

func (Duration) ToTimeDuration

func (d Duration) ToTimeDuration() (time.Duration, error)

ToTimeDuration converts the duration to a time.Duration, counting a week as seven days and a day as 24 hours. That is exact for a duration expressed in hours or less, and an approximation for one in days or weeks, which is why the calendar itself works in the original units.

func (Duration) Valid

func (d Duration) Valid() bool

Valid reports whether the value has the form the specification requires.

type Email

type Email struct {
	// The id of the email.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The id of the blob holding the raw message.
	//
	// The server sets this property; it may not be set by the client.
	BlobID ID `json:"blobId,omitzero"`

	// The id of the thread the email belongs to.
	//
	// The server sets this property; it may not be set by the client.
	ThreadID ID `json:"threadId,omitzero"`

	// The mailboxes the email is in, as a set of ids mapped to true.
	MailboxIDs map[ID]bool `json:"mailboxIds,omitzero"`

	// The keywords set on the email, such as "$seen" or "$flagged", mapped to
	// true.
	Keywords map[string]bool `json:"keywords,omitzero"`

	// The size of the raw message in octets.
	//
	// The server sets this property; it may not be set by the client.
	Size UnsignedInt `json:"size,omitzero"`

	// When the email was received, which is what the mailbox sorts on by
	// default.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	ReceivedAt UTCDate `json:"receivedAt,omitzero"`

	// The Message-ID header field values, without the enclosing angle brackets.
	MessageID []string `json:"messageId,omitzero"`

	// The In-Reply-To header field values.
	InReplyTo []string `json:"inReplyTo,omitzero"`

	// The References header field values.
	References []string `json:"references,omitzero"`

	// The Sender header field value.
	Sender []EmailAddress `json:"sender,omitzero"`

	// The From header field value.
	From []EmailAddress `json:"from,omitzero"`

	// The To header field value.
	To []EmailAddress `json:"to,omitzero"`

	// The Cc header field value.
	Cc []EmailAddress `json:"cc,omitzero"`

	// The Bcc header field value.
	Bcc []EmailAddress `json:"bcc,omitzero"`

	// The Reply-To header field value.
	ReplyTo []EmailAddress `json:"replyTo,omitzero"`

	// The Subject header field value.
	Subject *string `json:"subject,omitzero"`

	// The Date header field value.
	SentAt *Date `json:"sentAt,omitzero"`

	// Every header field of the message, in the order they appeared.
	Headers []EmailHeader `json:"headers,omitzero"`

	// The full MIME structure of the message body.
	BodyStructure EmailBodyPart `json:"bodyStructure,omitzero"`

	// The decoded content of the body parts that were fetched, keyed by partId.
	BodyValues map[string]EmailBodyValue `json:"bodyValues,omitzero"`

	// The parts to display as the plain-text body of the message.
	TextBody []EmailBodyPart `json:"textBody,omitzero"`

	// The parts to display as the HTML body of the message.
	HTMLBody []EmailBodyPart `json:"htmlBody,omitzero"`

	// The parts to present as attachments rather than as body content.
	Attachments []EmailBodyPart `json:"attachments,omitzero"`

	// Whether the message has at least one part the server considers an
	// attachment.
	//
	// The server sets this property; it may not be set by the client.
	HasAttachment bool `json:"hasAttachment,omitzero"`

	// A short plain-text excerpt of the message body.
	//
	// The server sets this property; it may not be set by the client.
	Preview string `json:"preview,omitzero"`

	// What the server made of the message's signature when it last looked:
	// "unknown", "signed", "signed/verified", "signed/failed",
	// "encrypted+signed/verified", or "encrypted+signed/failed". Null for a
	// message with no signature.
	//
	// The server sets this property; it may not be set by the client.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	SMIMEStatus *string `json:"smimeStatus,omitzero"`

	// What the server made of the signature when the message arrived, taking the
	// same values as smimeStatus: "unknown", "signed", "signed/verified",
	// "signed/failed", "encrypted+signed/verified", or
	// "encrypted+signed/failed". It can differ from smimeStatus: a certificate
	// valid on delivery may have expired since, and it is the state at delivery
	// that says whether the message was trustworthy when it was sent.
	//
	// The server sets this property; it may not be set by the client.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	SMIMEStatusAtDelivery *string `json:"smimeStatusAtDelivery,omitzero"`

	// What went wrong with the verification, in terms meant for a person to
	// read.
	//
	// The server sets this property; it may not be set by the client.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	SMIMEErrors []string `json:"smimeErrors,omitzero"`

	// When the server last checked the signature.
	//
	// The server sets this property; it may not be set by the client.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	SMIMEVerifiedAt *UTCDate `json:"smimeVerifiedAt,omitzero"`
}

Email is a single message, presented as structured data rather than as raw RFC 5322 text.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailAddress

type EmailAddress struct {
	// The display name of the addressee, or null if the header gave none.
	Name *string `json:"name,omitzero"`

	// The addr-spec of the address.
	Email string `json:"email,omitzero"`
}

EmailAddress is one address from a header field such as From or To.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailAddressGroup

type EmailAddressGroup struct {
	// The name of the group, or null for addresses outside any group.
	Name *string `json:"name,omitzero"`

	// The addresses in the group.
	Addresses []EmailAddress `json:"addresses,omitzero"`
}

EmailAddressGroup is a named group of addresses from an address header field.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailBodyPart

type EmailBodyPart struct {
	// Identifies the part's content within the bodyValues map, or null if the
	// part has no body of its own.
	PartID *string `json:"partId,omitzero"`

	// The id of the blob holding the raw content, or null for a multipart part.
	BlobID *ID `json:"blobId,omitzero"`

	// The size of the decoded content in octets.
	Size UnsignedInt `json:"size,omitzero"`

	// The header fields of this part.
	Headers []EmailHeader `json:"headers,omitzero"`

	// The filename the part should be saved as, if it names one.
	Name *string `json:"name,omitzero"`

	// The media type of the part.
	Type string `json:"type,omitzero"`

	// The character set of the part, for textual media types.
	Charset *string `json:"charset,omitzero"`

	// The Content-Disposition of the part, such as "inline" or "attachment".
	Disposition *string `json:"disposition,omitzero"`

	// The Content-ID of the part, which inline images are referenced by.
	Cid *string `json:"cid,omitzero"`

	// The languages of the part's content.
	Language []string `json:"language,omitzero"`

	// The Content-Location of the part.
	Location *string `json:"location,omitzero"`

	// The parts of a multipart part, or null if this part is not multipart.
	SubParts []EmailBodyPart `json:"subParts,omitzero"`
}

EmailBodyPart is one part of an email's MIME structure.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailBodyValue

type EmailBodyValue struct {
	// The decoded content of the body part.
	Value string `json:"value,omitzero"`

	// Whether the part could not be decoded cleanly, so that the value contains
	// replacement characters.
	IsEncodingProblem bool `json:"isEncodingProblem,omitzero"`

	// Whether the value was cut short to satisfy maxBodyValueBytes.
	IsTruncated bool `json:"isTruncated,omitzero"`
}

EmailBodyValue is the decoded content of one body part.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailChangesArguments

type EmailChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Email/get or Email/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

EmailChangesArguments holds the arguments of the Email/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailChangesResponse

type EmailChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

EmailChangesResponse holds the response to the Email/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailCopyArguments

type EmailCopyArguments struct {
	// The id of the account to copy records from.
	FromAccountID ID `json:"fromAccountId,omitzero"`

	// The state the source account is expected to be in.
	IfFromInState *string `json:"ifFromInState,omitzero"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the destination account is expected to be in.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to copy, each of which must have an id
	// property naming the record in the source account.
	Create map[ID]Email `json:"create,omitzero"`

	// Whether to destroy the originals once the copy succeeds.
	//
	// The server assumes false when this property is omitted.
	OnSuccessDestroyOriginal bool `json:"onSuccessDestroyOriginal,omitzero"`

	// The state the source account must be in for the originals to be destroyed.
	DestroyFromIfInState *string `json:"destroyFromIfInState,omitzero"`
}

EmailCopyArguments holds the arguments of the Email/copy method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailCopyResponse

type EmailCopyResponse struct {
	// The id of the account the records were copied from.
	FromAccountID ID `json:"fromAccountId"`

	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state of the destination account before the copy.
	OldState *string `json:"oldState"`

	// The state of the destination account after the copy.
	NewState string `json:"newState"`

	// A map of creation id to the record created in the destination account.
	Created map[ID]Email `json:"created"`

	// A map of creation id to the reason the record could not be copied.
	NotCreated map[ID]SetError `json:"notCreated"`
}

EmailCopyResponse holds the response to the Email/copy method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailFilterCondition

type EmailFilterCondition struct {
	// Matches emails in this mailbox.
	InMailbox ID `json:"inMailbox,omitzero"`

	// Matches emails that are in at least one mailbox outside this set.
	InMailboxOtherThan []ID `json:"inMailboxOtherThan,omitzero"`

	// Matches emails received before this time.
	Before UTCDate `json:"before,omitzero"`

	// Matches emails received at or after this time.
	After UTCDate `json:"after,omitzero"`

	// Matches emails of at least this size in octets.
	MinSize UnsignedInt `json:"minSize,omitzero"`

	// Matches emails smaller than this size in octets.
	MaxSize UnsignedInt `json:"maxSize,omitzero"`

	// Matches emails whose thread has this keyword on every email.
	AllInThreadHaveKeyword string `json:"allInThreadHaveKeyword,omitzero"`

	// Matches emails whose thread has this keyword on at least one email.
	SomeInThreadHaveKeyword string `json:"someInThreadHaveKeyword,omitzero"`

	// Matches emails whose thread has this keyword on no email.
	NoneInThreadHaveKeyword string `json:"noneInThreadHaveKeyword,omitzero"`

	// Matches emails with this keyword set.
	HasKeyword string `json:"hasKeyword,omitzero"`

	// Matches emails without this keyword set.
	NotKeyword string `json:"notKeyword,omitzero"`

	// Matches emails according to whether they have an attachment.
	HasAttachment bool `json:"hasAttachment,omitzero"`

	// Matches emails where this text appears in the body, subject, or any
	// address header field.
	Text string `json:"text,omitzero"`

	// Matches emails where this text appears in the From header field.
	From string `json:"from,omitzero"`

	// Matches emails where this text appears in the To header field.
	To string `json:"to,omitzero"`

	// Matches emails where this text appears in the Cc header field.
	Cc string `json:"cc,omitzero"`

	// Matches emails where this text appears in the Bcc header field.
	Bcc string `json:"bcc,omitzero"`

	// Matches emails where this text appears in the Subject header field.
	Subject string `json:"subject,omitzero"`

	// Matches emails where this text appears in the message body.
	Body string `json:"body,omitzero"`

	// Matches emails carrying the named header field, optionally with the given
	// value: [name] or [name, value].
	Header []string `json:"header,omitzero"`

	// Matches emails according to whether they carry an S/MIME signature at all.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	HasSMIME bool `json:"hasSmime,omitzero"`

	// Matches emails according to whether their signature verifies now.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	HasVerifiedSMIME bool `json:"hasVerifiedSmime,omitzero"`

	// Matches emails according to whether their signature verified when the
	// message arrived.
	//
	// A request using this property must declare
	// urn:ietf:params:jmap:smimeverify.
	HasVerifiedSMIMEAtDelivery bool `json:"hasVerifiedSmimeAtDelivery,omitzero"`
}

EmailFilterCondition is a condition an email must satisfy to match an Email/query.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailGetArguments

type EmailGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`

	// The properties to include for each EmailBodyPart returned.
	BodyProperties []string `json:"bodyProperties,omitzero"`

	// Whether to populate bodyValues for the parts listed in textBody.
	//
	// The server assumes false when this property is omitted.
	FetchTextBodyValues bool `json:"fetchTextBodyValues,omitzero"`

	// Whether to populate bodyValues for the parts listed in htmlBody.
	//
	// The server assumes false when this property is omitted.
	FetchHTMLBodyValues bool `json:"fetchHTMLBodyValues,omitzero"`

	// Whether to populate bodyValues for every textual body part.
	//
	// The server assumes false when this property is omitted.
	FetchAllBodyValues bool `json:"fetchAllBodyValues,omitzero"`

	// The maximum number of octets to return for each body value, truncating
	// longer ones.
	MaxBodyValueBytes UnsignedInt `json:"maxBodyValueBytes,omitzero"`
}

EmailGetArguments holds the arguments of the Email/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailGetResponse

type EmailGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Email/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Email `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

EmailGetResponse holds the response to the Email/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailHeader

type EmailHeader struct {
	// The header field name, as written in the message.
	Name string `json:"name,omitzero"`

	// The header field value, still in its raw form apart from unfolding.
	Value string `json:"value,omitzero"`
}

EmailHeader is one header field of an email or body part, as it appeared in the message.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailImport

type EmailImport struct {
	// The id of the blob holding the raw RFC 5322 message.
	BlobID ID `json:"blobId,omitzero"`

	// The mailboxes to file the imported email in.
	MailboxIDs map[ID]bool `json:"mailboxIds,omitzero"`

	// The keywords to set on the imported email.
	Keywords map[string]bool `json:"keywords,omitzero"`

	// The time to record as the email's receivedAt, defaulting to when the
	// import happens.
	ReceivedAt UTCDate `json:"receivedAt,omitzero"`
}

EmailImport is one message to import, naming the blob holding it and where it should land.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailImportArguments

type EmailImportArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the emails are expected to be in. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// The messages to import, keyed by creation id.
	Emails map[ID]EmailImport `json:"emails,omitzero"`
}

EmailImportArguments holds the arguments of the Email/import method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailImportResponse

type EmailImportResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before the import.
	OldState *string `json:"oldState"`

	// The state after the import.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each
	// imported email.
	Created map[ID]Email `json:"created"`

	// A map of creation id to the reason the message could not be imported.
	NotCreated map[ID]SetError `json:"notCreated"`
}

EmailImportResponse holds the response to the Email/import method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailParseArguments

type EmailParseArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the blobs to parse as messages.
	BlobIDs []ID `json:"blobIds,omitzero"`

	// The properties to include in each parsed email, or null for the default
	// set.
	Properties []string `json:"properties,omitzero"`

	// The properties to include for each EmailBodyPart returned.
	BodyProperties []string `json:"bodyProperties,omitzero"`

	// Whether to populate bodyValues for the parts listed in textBody.
	//
	// The server assumes false when this property is omitted.
	FetchTextBodyValues bool `json:"fetchTextBodyValues,omitzero"`

	// Whether to populate bodyValues for the parts listed in htmlBody.
	//
	// The server assumes false when this property is omitted.
	FetchHTMLBodyValues bool `json:"fetchHTMLBodyValues,omitzero"`

	// Whether to populate bodyValues for every textual body part.
	//
	// The server assumes false when this property is omitted.
	FetchAllBodyValues bool `json:"fetchAllBodyValues,omitzero"`

	// The maximum number of octets to return for each body value, truncating
	// longer ones.
	MaxBodyValueBytes UnsignedInt `json:"maxBodyValueBytes,omitzero"`
}

EmailParseArguments holds the arguments of the Email/parse method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailParseResponse

type EmailParseResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A map of blob id to the email parsed from it. The email has no id,
	// mailboxIds, keywords, or receivedAt, because it is not a record in the
	// account.
	Parsed map[ID]Email `json:"parsed"`

	// The ids of the blobs that exist but do not hold a message the server could
	// parse.
	NotParsable []ID `json:"notParsable"`

	// The ids of the blobs that do not exist.
	NotFound []ID `json:"notFound"`
}

EmailParseResponse holds the response to the Email/parse method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailQueryArguments

type EmailQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrEmailFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to return only one email per thread, the one that sorts highest
	// among those matching the filter.
	//
	// The server assumes false when this property is omitted.
	CollapseThreads bool `json:"collapseThreads,omitzero"`
}

EmailQueryArguments holds the arguments of the Email/query method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailQueryChangesArguments

type EmailQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrEmailFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// Email/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to return only one email per thread, the one that sorts highest
	// among those matching the filter.
	//
	// The server assumes false when this property is omitted.
	CollapseThreads bool `json:"collapseThreads,omitzero"`
}

EmailQueryChangesArguments holds the arguments of the Email/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailQueryChangesResponse

type EmailQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

EmailQueryChangesResponse holds the response to the Email/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailQueryResponse

type EmailQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with Email/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

EmailQueryResponse holds the response to the Email/query method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailSetArguments

type EmailSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]Email `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

EmailSetArguments holds the arguments of the Email/set method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailSetResponse

type EmailSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*Email `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*Email `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

EmailSetResponse holds the response to the Email/set method.

A request using this type must declare urn:ietf:params:jmap:mail.

type EmailSubmission

type EmailSubmission struct {
	// The id of the submission.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The id of the identity to send from.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	IdentityID ID `json:"identityId,omitzero"`

	// The id of the email to send.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	EmailID ID `json:"emailId,omitzero"`

	// The id of the thread the sent email belongs to.
	//
	// The server sets this property; it may not be set by the client.
	ThreadID ID `json:"threadId,omitzero"`

	// The SMTP envelope to send with, or null to have the server derive one from
	// the message's header fields.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	Envelope *Envelope `json:"envelope,omitzero"`

	// When the message was, or will be, released to the SMTP server.
	//
	// The server sets this property; it may not be set by the client.
	SendAt UTCDate `json:"sendAt,omitzero"`

	// Whether the submission can still be stopped: "pending", "final", or
	// "canceled". Setting it to "canceled" is how a send is undone while it is
	// still pending.
	UndoStatus string `json:"undoStatus,omitzero"`

	// What became of the message for each recipient, keyed by address, or null
	// if the server does not track it.
	//
	// The server sets this property; it may not be set by the client.
	DeliveryStatus map[string]DeliveryStatus `json:"deliveryStatus,omitzero"`

	// The blob ids of the delivery status notifications received for this
	// submission.
	//
	// The server sets this property; it may not be set by the client.
	DsnBlobIDs []ID `json:"dsnBlobIds,omitzero"`

	// The blob ids of the message disposition notifications received for this
	// submission.
	//
	// The server sets this property; it may not be set by the client.
	MDNBlobIDs []ID `json:"mdnBlobIds,omitzero"`
}

EmailSubmission is one attempt to send an email, and the record of what happened to it.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionChangesArguments

type EmailSubmissionChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// EmailSubmission/get or EmailSubmission/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

EmailSubmissionChangesArguments holds the arguments of the EmailSubmission/changes method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionChangesResponse

type EmailSubmissionChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

EmailSubmissionChangesResponse holds the response to the EmailSubmission/changes method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionFilterCondition

type EmailSubmissionFilterCondition struct {
	// Matches submissions sent from one of these identities.
	IdentityIDs []ID `json:"identityIds,omitzero"`

	// Matches submissions of one of these emails.
	EmailIDs []ID `json:"emailIds,omitzero"`

	// Matches submissions of an email in one of these threads.
	ThreadIDs []ID `json:"threadIds,omitzero"`

	// Matches submissions with this undo status.
	UndoStatus string `json:"undoStatus,omitzero"`

	// Matches submissions whose sendAt is before this time.
	Before UTCDate `json:"before,omitzero"`

	// Matches submissions whose sendAt is at or after this time.
	After UTCDate `json:"after,omitzero"`
}

EmailSubmissionFilterCondition is a condition a submission must satisfy to match an EmailSubmission/query.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionGetArguments

type EmailSubmissionGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

EmailSubmissionGetArguments holds the arguments of the EmailSubmission/get method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionGetResponse

type EmailSubmissionGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with EmailSubmission/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []EmailSubmission `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

EmailSubmissionGetResponse holds the response to the EmailSubmission/get method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionQueryArguments

type EmailSubmissionQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrEmailSubmissionFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

EmailSubmissionQueryArguments holds the arguments of the EmailSubmission/query method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionQueryChangesArguments

type EmailSubmissionQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrEmailSubmissionFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// EmailSubmission/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

EmailSubmissionQueryChangesArguments holds the arguments of the EmailSubmission/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionQueryChangesResponse

type EmailSubmissionQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

EmailSubmissionQueryChangesResponse holds the response to the EmailSubmission/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionQueryResponse

type EmailSubmissionQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with EmailSubmission/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

EmailSubmissionQueryResponse holds the response to the EmailSubmission/query method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionSetArguments

type EmailSubmissionSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]EmailSubmission `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// Patches to apply to the emails of the submissions that succeed, keyed by
	// the submission's id or creation id.
	OnSuccessUpdateEmail map[ID]PatchObject `json:"onSuccessUpdateEmail,omitzero"`

	// The ids or creation ids of the submissions whose emails should be
	// destroyed once the submission succeeds.
	OnSuccessDestroyEmail []ID `json:"onSuccessDestroyEmail,omitzero"`
}

EmailSubmissionSetArguments holds the arguments of the EmailSubmission/set method.

A request using this type must declare urn:ietf:params:jmap:submission.

type EmailSubmissionSetResponse

type EmailSubmissionSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*EmailSubmission `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*EmailSubmission `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

EmailSubmissionSetResponse holds the response to the EmailSubmission/set method.

A request using this type must declare urn:ietf:params:jmap:submission.

type Envelope

type Envelope struct {
	// The address to send the MAIL FROM command with, which is where bounces go.
	MailFrom Address `json:"mailFrom,omitzero"`

	// The addresses to send the message to, one RCPT TO command each.
	RcptTo []Address `json:"rcptTo,omitzero"`
}

Envelope is the SMTP envelope of a submission: who the message is from and who it goes to, which need not match the message's own header fields.

A request using this type must declare urn:ietf:params:jmap:submission.

type EventAbsoluteTrigger

type EventAbsoluteTrigger struct {
	// The type of this object, which is "AbsoluteTrigger".
	Type string `json:"@type,omitzero"`

	// When to fire the alert.
	When UTCDate `json:"when,omitzero"`
}

EventAbsoluteTrigger fires an alert at a fixed time, whatever the event does. RFC 8984 calls it AbsoluteTrigger.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventAlert

type EventAlert struct {
	// The type of this object, which is "Alert".
	Type string `json:"@type,omitzero"`

	// When to fire the alert, either relative to the event or at a fixed time. A
	// trigger of a kind this catalogue does not know is left as it was written.
	Trigger EventOffsetTriggerOrEventAbsoluteTrigger `json:"trigger,omitzero"`

	// When the user dismissed the alert.
	Acknowledged UTCDate `json:"acknowledged,omitzero"`

	// Other alerts this one relates to, keyed by their uid.
	RelatedTo map[string]EventRelation `json:"relatedTo,omitzero"`

	// What to do when the alert fires: "display" or "email".
	//
	// The server assumes "display" when this property is omitted.
	Action *string `json:"action,omitzero"`
}

EventAlert is a reminder attached to an event. RFC 8984 calls it Alert.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventLink struct {
	// The type of this object, which is "Link".
	Type string `json:"@type,omitzero"`

	// The URI of the resource.
	Href string `json:"href,omitzero"`

	// The Content-ID of the resource, for one carried alongside the event.
	Cid string `json:"cid,omitzero"`

	// The media type of the resource.
	ContentType string `json:"contentType,omitzero"`

	// The size of the resource in octets.
	Size UnsignedInt `json:"size,omitzero"`

	// How the resource relates to the event, as an IANA-registered link relation
	// such as "describedby" or "enclosure".
	Rel string `json:"rel,omitzero"`

	// How to display the resource, for one that is an image: "badge", "graphic",
	// "fullsize", or "thumbnail".
	Display string `json:"display,omitzero"`

	// A human-readable description of the resource.
	Title string `json:"title,omitzero"`
}

EventLink is an external resource associated with an event, such as an agenda or a conference recording. RFC 8984 calls it Link.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventLocation

type EventLocation struct {
	// The type of this object, which is "Location".
	Type string `json:"@type,omitzero"`

	// The name of the location.
	Name string `json:"name,omitzero"`

	// Directions or other detail about the location.
	Description string `json:"description,omitzero"`

	// What sort of place this is, mapped to true, using the values registered
	// for RFC 4589.
	LocationTypes map[string]bool `json:"locationTypes,omitzero"`

	// What part of the event happens here: "start" or "end".
	RelativeTo string `json:"relativeTo,omitzero"`

	// The time zone of the location, where it differs from the event's own.
	TimeZone TimeZoneID `json:"timeZone,omitzero"`

	// The location as a geo: URI, as defined by RFC 5870.
	Coordinates string `json:"coordinates,omitzero"`

	// Resources about the location, keyed by an id local to the event.
	Links map[ID]EventLink `json:"links,omitzero"`
}

EventLocation is a physical place an event happens at. RFC 8984 calls it Location.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventNDay

type EventNDay struct {
	// The type of this object, which is "NDay".
	Type string `json:"@type,omitzero"`

	// The day of the week: "mo", "tu", "we", "th", "fr", "sa", or "su".
	Day string `json:"day,omitzero"`

	// Which occurrence of that day within the period, counting back from the end
	// when negative. Absent means every one.
	NthOfPeriod Int `json:"nthOfPeriod,omitzero"`
}

EventNDay names a day of the week within a recurrence, optionally counting from the start or end of the period. RFC 8984 calls it NDay.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventOffsetTrigger

type EventOffsetTrigger struct {
	// The type of this object, which is "OffsetTrigger".
	Type string `json:"@type,omitzero"`

	// How long before or after the reference point to fire, negative for before.
	Offset SignedDuration `json:"offset,omitzero"`

	// What the offset is measured from: "start" or "end".
	//
	// The server assumes "start" when this property is omitted.
	RelativeTo *string `json:"relativeTo,omitzero"`
}

EventOffsetTrigger fires an alert a set time before or after the event. RFC 8984 calls it OffsetTrigger.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventOffsetTriggerOrEventAbsoluteTrigger added in v0.12.0

type EventOffsetTriggerOrEventAbsoluteTrigger struct {
	// EventOffsetTrigger holds the value where it is an EventOffsetTrigger.
	EventOffsetTrigger *EventOffsetTrigger

	// EventAbsoluteTrigger holds the value where it is an EventAbsoluteTrigger.
	EventAbsoluteTrigger *EventAbsoluteTrigger
}

EventOffsetTriggerOrEventAbsoluteTrigger is a value that is an EventOffsetTrigger or an EventAbsoluteTrigger.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (EventOffsetTriggerOrEventAbsoluteTrigger) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*EventOffsetTriggerOrEventAbsoluteTrigger) UnmarshalJSON added in v0.12.0

func (u *EventOffsetTriggerOrEventAbsoluteTrigger) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type EventParticipant

type EventParticipant struct {
	// The type of this object, which is "Participant".
	Type string `json:"@type,omitzero"`

	// The participant's name.
	Name string `json:"name,omitzero"`

	// The participant's email address.
	Email string `json:"email,omitzero"`

	// A note about the participant.
	Description string `json:"description,omitzero"`

	// Where to send scheduling messages, keyed by method, such as "imip" mapped
	// to a mailto: URI.
	SendTo map[string]string `json:"sendTo,omitzero"`

	// What the participant is: "individual", "group", "location", or "resource".
	Kind string `json:"kind,omitzero"`

	// What the participant is there for, mapped to true: "owner", "attendee",
	// "optional", "informational", "chair", or "contact".
	Roles map[string]bool `json:"roles,omitzero"`

	// The id, within the event's locations, of where the participant will be.
	LocationID ID `json:"locationId,omitzero"`

	// The language to send scheduling messages in, as an RFC 5646 tag.
	Language string `json:"language,omitzero"`

	// Whether the participant is coming: "needs-action", "accepted", "declined",
	// "tentative", or "delegated".
	//
	// The server assumes "needs-action" when this property is omitted.
	ParticipationStatus *string `json:"participationStatus,omitzero"`

	// A note the participant sent with their reply.
	ParticipationComment string `json:"participationComment,omitzero"`

	// Whether the participant is expected to reply.
	//
	// The server assumes false when this property is omitted.
	ExpectReply bool `json:"expectReply,omitzero"`

	// Who sends the scheduling messages: "server", "client", or "none".
	//
	// The server assumes "server" when this property is omitted.
	ScheduleAgent *string `json:"scheduleAgent,omitzero"`

	// Whether to send a scheduling message even though nothing the participant
	// cares about has changed.
	//
	// The server assumes false when this property is omitted.
	ScheduleForceSend bool `json:"scheduleForceSend,omitzero"`

	// The sequence number of the last scheduling message sent to this
	// participant.
	//
	// The server assumes 0 when this property is omitted.
	ScheduleSequence UnsignedInt `json:"scheduleSequence,omitzero"`

	// The status codes returned by the last scheduling attempt.
	ScheduleStatus []string `json:"scheduleStatus,omitzero"`

	// When the participant's own copy of the event was last updated.
	ScheduleUpdated UTCDate `json:"scheduleUpdated,omitzero"`

	// The address of whoever acted on the participant's behalf.
	SentBy string `json:"sentBy,omitzero"`

	// The id, within the event's participants, of whoever invited this one.
	InvitedBy ID `json:"invitedBy,omitzero"`

	// The participants this one has delegated to, mapped to true.
	DelegatedTo map[ID]bool `json:"delegatedTo,omitzero"`

	// The participants who delegated to this one, mapped to true.
	DelegatedFrom map[ID]bool `json:"delegatedFrom,omitzero"`

	// The group participants this one belongs to, mapped to true.
	MemberOf map[ID]bool `json:"memberOf,omitzero"`

	// Resources about the participant, keyed by an id local to the event.
	Links map[ID]EventLink `json:"links,omitzero"`
}

EventParticipant is someone or something taking part in an event. RFC 8984 calls it Participant.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventRecurrenceRule

type EventRecurrenceRule struct {
	// The type of this object, which is "RecurrenceRule".
	Type string `json:"@type,omitzero"`

	// How often the event repeats: "yearly", "monthly", "weekly", "daily",
	// "hourly", "minutely", or "secondly".
	Frequency string `json:"frequency,omitzero"`

	// How many periods to skip between occurrences, so 2 with a weekly frequency
	// means every other week.
	//
	// The server assumes 1 when this property is omitted.
	Interval *UnsignedInt `json:"interval,omitzero"`

	// The calendar system the rule is expressed in, named as in CLDR.
	//
	// The server assumes "gregorian" when this property is omitted.
	Rscale *string `json:"rscale,omitzero"`

	// What to do when a rule lands on a date that does not exist, such as the
	// 31st of a short month: "omit", "backward", or "forward".
	//
	// The server assumes "omit" when this property is omitted.
	Skip *string `json:"skip,omitzero"`

	// Which day a week starts on, which decides where weekly intervals fall:
	// "mo", "tu", "we", "th", "fr", "sa", or "su".
	//
	// The server assumes "mo" when this property is omitted.
	FirstDayOfWeek *string `json:"firstDayOfWeek,omitzero"`

	// The days of the week the event falls on.
	ByDay []EventNDay `json:"byDay,omitzero"`

	// The days of the month, counting back from the end when negative.
	ByMonthDay []Int `json:"byMonthDay,omitzero"`

	// The months, as "1" through "12", with an "L" suffix for a leap month.
	ByMonth []string `json:"byMonth,omitzero"`

	// The days of the year, counting back from the end when negative.
	ByYearDay []Int `json:"byYearDay,omitzero"`

	// The weeks of the year, counting back from the end when negative.
	ByWeekNo []Int `json:"byWeekNo,omitzero"`

	// The hours of the day.
	ByHour []UnsignedInt `json:"byHour,omitzero"`

	// The minutes of the hour.
	ByMinute []UnsignedInt `json:"byMinute,omitzero"`

	// The seconds of the minute.
	BySecond []UnsignedInt `json:"bySecond,omitzero"`

	// Which of the occurrences the rest of the rule generates to keep, counting
	// back from the end when negative.
	BySetPosition []Int `json:"bySetPosition,omitzero"`

	// How many occurrences to generate. It cannot be given together with until.
	Count UnsignedInt `json:"count,omitzero"`

	// The last date-time an occurrence may start at. It cannot be given together
	// with count.
	Until LocalDateTime `json:"until,omitzero"`
}

EventRecurrenceRule says how an event repeats. RFC 8984 calls it RecurrenceRule.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventRelation

type EventRelation struct {
	// The type of this object, which is "Relation".
	Type string `json:"@type,omitzero"`

	// The kinds of relation, mapped to true: "first", "next", "child", or
	// "parent". An empty object means the objects are related in a way this does
	// not name.
	//
	// The server assumes an empty object when this property is omitted.
	Relation map[string]bool `json:"relation,omitzero"`
}

EventRelation says how another object is related to this one. RFC 8984 calls it Relation.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventSourceOptions

type EventSourceOptions struct {
	// Types are the object types to be notified about, such as "Email". Leave
	// it empty to receive events for every type.
	Types []string
	// Ping requests a comment from the server at that interval, so that a
	// connection dropped by an intermediary is detected rather than left
	// hanging. Servers clamp it to a range of their own. Zero requests no
	// pings.
	Ping time.Duration
	// CloseAfterState asks the server to close the connection after the first
	// event, which suits a client that only needs to know that the state it
	// holds is out of date.
	CloseAfterState bool
	// LastEventID resumes from a known point: the server sends the events
	// since that one, so that a reconnection does not miss anything. Pass the
	// LastEventID of the stream that dropped.
	LastEventID string
}

EventSourceOptions are the parameters of a request to the push endpoint.

type EventStream

type EventStream struct {
	// contains filtered or unexported fields
}

EventStream is an open connection to a server's push endpoint. It is not safe for concurrent use, and the caller must close it.

func (*EventStream) Close

func (s *EventStream) Close() error

Close ends the connection.

func (*EventStream) LastEventID

func (s *EventStream) LastEventID() string

LastEventID returns the id of the most recent event, to resume from after the stream drops.

func (*EventStream) Next

func (s *EventStream) Next() (*StateChange, error)

Next blocks until the server pushes the next state change and returns it. Pings and any other event types the server sends are consumed and skipped.

It returns io.EOF when the server closes the stream, which it does after the first event when CloseAfterState was set, and may do at any time otherwise.

type EventTimeZone

type EventTimeZone struct {
	// The type of this object, which is "TimeZone".
	Type string `json:"@type,omitzero"`

	// The identifier of the zone within the event, which begins with "/".
	TzID string `json:"tzId,omitzero"`

	// When the definition was last updated.
	Updated UTCDate `json:"updated,omitzero"`

	// Where the authoritative definition of the zone is published.
	URL string `json:"url,omitzero"`

	// The point beyond which the rules given here are not known to hold.
	ValidUntil UTCDate `json:"validUntil,omitzero"`

	// Other names for this zone, mapped to true.
	Aliases map[string]bool `json:"aliases,omitzero"`

	// The rules for standard time.
	Standard []EventTimeZoneRule `json:"standard,omitzero"`

	// The rules for daylight saving time.
	Daylight []EventTimeZoneRule `json:"daylight,omitzero"`
}

EventTimeZone is a time zone the event defines itself, for a zone the IANA database does not have. RFC 8984 calls it TimeZone.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventTimeZoneRule

type EventTimeZoneRule struct {
	// The type of this object, which is "TimeZoneRule".
	Type string `json:"@type,omitzero"`

	// When this rule first applies, in local time.
	Start LocalDateTime `json:"start,omitzero"`

	// The UTC offset before the rule applies, such as "+0100".
	OffsetFrom string `json:"offsetFrom,omitzero"`

	// The UTC offset once the rule applies.
	OffsetTo string `json:"offsetTo,omitzero"`

	// How the rule repeats.
	RecurrenceRules []EventRecurrenceRule `json:"recurrenceRules,omitzero"`

	// Changes to particular occurrences of the rule, keyed by the start of the
	// occurrence.
	RecurrenceOverrides map[LocalDateTime]PatchObject `json:"recurrenceOverrides,omitzero"`

	// The names of the zone while this rule applies, such as "GMT", mapped to
	// true.
	Names map[string]bool `json:"names,omitzero"`

	// Comments about the rule.
	Comments []string `json:"comments,omitzero"`
}

EventTimeZoneRule is one rule of a custom time zone: when an offset starts to apply, and what it is. RFC 8984 calls it TimeZoneRule.

A request using this type must declare urn:ietf:params:jmap:calendars.

type EventVirtualLocation

type EventVirtualLocation struct {
	// The type of this object, which is "VirtualLocation".
	Type string `json:"@type,omitzero"`

	// The name of the virtual location.
	//
	// The server assumes "" when this property is omitted.
	Name *string `json:"name,omitzero"`

	// Instructions for joining, or other detail.
	Description string `json:"description,omitzero"`

	// The URI to join at, such as a tel: or https: address.
	URI string `json:"uri,omitzero"`

	// What the location supports, mapped to true: "audio", "chat", "feed",
	// "moderator", "phone", "screen", or "video".
	Features map[string]bool `json:"features,omitzero"`
}

EventVirtualLocation is somewhere online an event happens, such as a video call. RFC 8984 calls it VirtualLocation.

A request using this type must declare urn:ietf:params:jmap:calendars.

type FilterOperator

type FilterOperator struct {
	// How to combine the conditions: "AND", "OR", or "NOT".
	Operator string `json:"operator,omitzero"`

	// The conditions to combine, each either a FilterOperator or a filter
	// condition for the type being queried.
	Conditions []any `json:"conditions,omitzero"`
}

FilterOperator is a boolean node combining the conditions of a /query filter.

type FilterOperatorOrCalendarEventFilterCondition added in v0.12.0

type FilterOperatorOrCalendarEventFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// CalendarEventFilterCondition holds the value where it is a
	// CalendarEventFilterCondition.
	CalendarEventFilterCondition *CalendarEventFilterCondition
}

FilterOperatorOrCalendarEventFilterCondition is a value that is a FilterOperator or a CalendarEventFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrCalendarEventFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrCalendarEventFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrCalendarEventFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrCalendarEventNotificationFilterCondition added in v0.12.0

type FilterOperatorOrCalendarEventNotificationFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// CalendarEventNotificationFilterCondition holds the value where it is a
	// CalendarEventNotificationFilterCondition.
	CalendarEventNotificationFilterCondition *CalendarEventNotificationFilterCondition
}

FilterOperatorOrCalendarEventNotificationFilterCondition is a value that is a FilterOperator or a CalendarEventNotificationFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrCalendarEventNotificationFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrCalendarEventNotificationFilterCondition) UnmarshalJSON added in v0.12.0

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrContactCardFilterCondition added in v0.12.0

type FilterOperatorOrContactCardFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// ContactCardFilterCondition holds the value where it is a
	// ContactCardFilterCondition.
	ContactCardFilterCondition *ContactCardFilterCondition
}

FilterOperatorOrContactCardFilterCondition is a value that is a FilterOperator or a ContactCardFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrContactCardFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrContactCardFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrContactCardFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrEmailFilterCondition added in v0.12.0

type FilterOperatorOrEmailFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// EmailFilterCondition holds the value where it is an EmailFilterCondition.
	EmailFilterCondition *EmailFilterCondition
}

FilterOperatorOrEmailFilterCondition is a value that is a FilterOperator or an EmailFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrEmailFilterCondition) MarshalJSON added in v0.12.0

func (u FilterOperatorOrEmailFilterCondition) MarshalJSON() ([]byte, error)

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrEmailFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrEmailFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrEmailSubmissionFilterCondition added in v0.12.0

type FilterOperatorOrEmailSubmissionFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// EmailSubmissionFilterCondition holds the value where it is an
	// EmailSubmissionFilterCondition.
	EmailSubmissionFilterCondition *EmailSubmissionFilterCondition
}

FilterOperatorOrEmailSubmissionFilterCondition is a value that is a FilterOperator or an EmailSubmissionFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrEmailSubmissionFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrEmailSubmissionFilterCondition) UnmarshalJSON added in v0.12.0

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrMailboxFilterCondition added in v0.12.0

type FilterOperatorOrMailboxFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// MailboxFilterCondition holds the value where it is a
	// MailboxFilterCondition.
	MailboxFilterCondition *MailboxFilterCondition
}

FilterOperatorOrMailboxFilterCondition is a value that is a FilterOperator or a MailboxFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrMailboxFilterCondition) MarshalJSON added in v0.12.0

func (u FilterOperatorOrMailboxFilterCondition) MarshalJSON() ([]byte, error)

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrMailboxFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrMailboxFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrPrincipalFilterCondition added in v0.12.0

type FilterOperatorOrPrincipalFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// PrincipalFilterCondition holds the value where it is a
	// PrincipalFilterCondition.
	PrincipalFilterCondition *PrincipalFilterCondition
}

FilterOperatorOrPrincipalFilterCondition is a value that is a FilterOperator or a PrincipalFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrPrincipalFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrPrincipalFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrPrincipalFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrQuotaFilterCondition added in v0.12.0

type FilterOperatorOrQuotaFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// QuotaFilterCondition holds the value where it is a QuotaFilterCondition.
	QuotaFilterCondition *QuotaFilterCondition
}

FilterOperatorOrQuotaFilterCondition is a value that is a FilterOperator or a QuotaFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrQuotaFilterCondition) MarshalJSON added in v0.12.0

func (u FilterOperatorOrQuotaFilterCondition) MarshalJSON() ([]byte, error)

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrQuotaFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrQuotaFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrShareNotificationFilterCondition added in v0.12.0

type FilterOperatorOrShareNotificationFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// ShareNotificationFilterCondition holds the value where it is a
	// ShareNotificationFilterCondition.
	ShareNotificationFilterCondition *ShareNotificationFilterCondition
}

FilterOperatorOrShareNotificationFilterCondition is a value that is a FilterOperator or a ShareNotificationFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrShareNotificationFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrShareNotificationFilterCondition) UnmarshalJSON added in v0.12.0

UnmarshalJSON fills the first shape the value fits.

type FilterOperatorOrSieveScriptFilterCondition added in v0.12.0

type FilterOperatorOrSieveScriptFilterCondition struct {
	// FilterOperator holds the value where it is a FilterOperator.
	FilterOperator *FilterOperator

	// SieveScriptFilterCondition holds the value where it is a
	// SieveScriptFilterCondition.
	SieveScriptFilterCondition *SieveScriptFilterCondition
}

FilterOperatorOrSieveScriptFilterCondition is a value that is a FilterOperator or a SieveScriptFilterCondition.

Exactly one field is set. Setting none, or more than one, is an error when the value is encoded.

func (FilterOperatorOrSieveScriptFilterCondition) MarshalJSON added in v0.12.0

MarshalJSON writes whichever shape the value holds.

func (*FilterOperatorOrSieveScriptFilterCondition) UnmarshalJSON added in v0.12.0

func (u *FilterOperatorOrSieveScriptFilterCondition) UnmarshalJSON(data []byte) error

UnmarshalJSON fills the first shape the value fits.

type ID

type ID string

ID is the JMAP Id data type defined in RFC 8620, Section 1.2. It is a string of at least 1 and at most 255 octets drawn from the URL and filename safe base64 alphabet, and it must not begin with a "-" or "#".

func (ID) String

func (i ID) String() string

func (ID) Valid

func (i ID) Valid() bool

Valid reports whether the id satisfies the syntactic restrictions the specification places on the Id type. Servers are free to assign any id that matches, so this only rejects values that no conformant server could produce.

type Identity

type Identity struct {
	// The id of the identity.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The display name to put in the From header field alongside the address.
	//
	// The server assumes "" when this property is omitted.
	Name *string `json:"name,omitzero"`

	// The address to send from. It may end in "@domain" to stand for any address
	// at that domain.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	Email string `json:"email,omitzero"`

	// The Reply-To header field to set by default.
	ReplyTo []EmailAddress `json:"replyTo,omitzero"`

	// The Bcc header field to set by default.
	Bcc []EmailAddress `json:"bcc,omitzero"`

	// The signature to append to the plain-text body of a message sent from this
	// identity.
	//
	// The server assumes "" when this property is omitted.
	TextSignature *string `json:"textSignature,omitzero"`

	// The signature to append to the HTML body of a message sent from this
	// identity.
	//
	// The server assumes "" when this property is omitted.
	HTMLSignature *string `json:"htmlSignature,omitzero"`

	// Whether the user may delete the identity, which is false for one the
	// server maintains itself.
	//
	// The server sets this property; it may not be set by the client.
	MayDelete bool `json:"mayDelete,omitzero"`
}

Identity is an address the user may send mail from, together with the defaults to apply when they do.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentityChangesArguments

type IdentityChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Identity/get or Identity/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

IdentityChangesArguments holds the arguments of the Identity/changes method.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentityChangesResponse

type IdentityChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

IdentityChangesResponse holds the response to the Identity/changes method.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentityGetArguments

type IdentityGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

IdentityGetArguments holds the arguments of the Identity/get method.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentityGetResponse

type IdentityGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Identity/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Identity `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

IdentityGetResponse holds the response to the Identity/get method.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentitySetArguments

type IdentitySetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]Identity `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

IdentitySetArguments holds the arguments of the Identity/set method.

A request using this type must declare urn:ietf:params:jmap:submission.

type IdentitySetResponse

type IdentitySetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*Identity `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*Identity `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

IdentitySetResponse holds the response to the Identity/set method.

A request using this type must declare urn:ietf:params:jmap:submission.

type Int

type Int int64

Int is the JMAP Int data type: a signed integer in the range that survives a round trip through an IEEE 754 double.

const (
	// MaxInt is the largest value the JMAP Int type may hold, 2^53-1.
	MaxInt Int = 1<<53 - 1
	// MinInt is the smallest value the JMAP Int type may hold, -(2^53-1).
	MinInt Int = -(1<<53 - 1)
)

type Invocation

type Invocation struct {
	// Name is the method name, such as "Email/get", or "error" for a
	// method-level error in a response.
	Name string
	// Args holds the arguments to marshal in a request, and a json.RawMessage
	// holding the unparsed arguments in a response.
	Args any
	// CallID is the client-assigned identifier that back references and
	// responses use to refer to this call.
	CallID string
}

Invocation is a single method call or method response. On the wire it is the three-element array [name, arguments, callId] described in RFC 8620, Section 3.2.

func (Invocation) MarshalJSON

func (in Invocation) MarshalJSON() ([]byte, error)

func (Invocation) RawArgs

func (in Invocation) RawArgs() (json.RawMessage, bool)

RawArgs returns the undecoded arguments of an invocation that came from a response.

func (*Invocation) UnmarshalJSON

func (in *Invocation) UnmarshalJSON(b []byte) error

type LocalDateTime

type LocalDateTime string

LocalDateTime is the JSCalendar LocalDateTime of RFC 8984, Section 1.4.4: a date and time with no time zone and no offset, such as "2024-05-01T09:00:00". What it means depends on the time zone the enclosing object gives, and for a recurring event that time zone is what matters: an alarm set for 09:00 stays at 09:00 when the clocks change.

It is a string rather than a time.Time because it is used as a map key, in the recurrenceOverrides of an event, and because a time.Time can carry a location that this type cannot represent.

func NewLocalDateTime

func NewLocalDateTime(t time.Time) LocalDateTime

NewLocalDateTime returns t as a local date-time, discarding its location.

func (LocalDateTime) In

func (d LocalDateTime) In(loc *time.Location) (time.Time, error)

In returns the point in time this date-time denotes in the given location. The location comes from elsewhere in the event, which is why it cannot be resolved here.

func (LocalDateTime) String

func (d LocalDateTime) String() string

func (LocalDateTime) Valid

func (d LocalDateTime) Valid() bool

Valid reports whether the value has the form the specification requires.

type MDN added in v0.2.0

type MDN struct {
	// The id of the email this is about. It is required when sending, and may be
	// null in one that was parsed, where the message it refers to may not be in
	// the account.
	ForEmailID *ID `json:"forEmailId,omitzero"`

	// The Subject header field for the notification itself.
	Subject *string `json:"subject,omitzero"`

	// A human-readable explanation, which the notification carries alongside the
	// machine-readable part.
	TextBody *string `json:"textBody,omitzero"`

	// Whether to send the original message back with the notification.
	//
	// The server assumes false when this property is omitted.
	IncludeOriginalMessage bool `json:"includeOriginalMessage,omitzero"`

	// The name of the software that produced the notification.
	ReportingUA *string `json:"reportingUA,omitzero"`

	// What became of the message.
	Disposition MDNDisposition `json:"disposition,omitzero"`

	// The gateway that translated the notification, for one that crossed from
	// another mail system.
	//
	// The server sets this property; it may not be set by the client.
	MDNGateway *string `json:"mdnGateway,omitzero"`

	// The address the original message was addressed to, which may differ from
	// where it ended up.
	//
	// The server sets this property; it may not be set by the client.
	OriginalRecipient *string `json:"originalRecipient,omitzero"`

	// The address the notification is sent on behalf of. The server fills it in
	// from the identity when it is not given.
	FinalRecipient *string `json:"finalRecipient,omitzero"`

	// The Message-ID of the message this is about.
	//
	// The server sets this property; it may not be set by the client.
	OriginalMessageID *string `json:"originalMessageId,omitzero"`

	// What went wrong, for a notification whose disposition reports a failure.
	//
	// The server sets this property; it may not be set by the client.
	Error []string `json:"error,omitzero"`

	// Fields beyond those the specification defines, keyed by field name.
	ExtensionFields map[string]string `json:"extensionFields,omitzero"`
}

MDN is a message disposition notification: a receipt saying what became of a message the user received. Sending one is a courtesy the recipient decides on, not something the sender can require.

A request using this type must declare urn:ietf:params:jmap:mdn.

type MDNDisposition added in v0.2.0

type MDNDisposition struct {
	// Whether the user did this themselves or the client did it for them:
	// "manual-action" or "automatic-action".
	ActionMode string `json:"actionMode,omitzero"`

	// Whether the user chose to send the notification: "mdn-sent-manually" if
	// they were asked, "mdn-sent-automatically" if the client sent it without
	// asking.
	SendingMode string `json:"sendingMode,omitzero"`

	// What happened to the message: "deleted" without being read, "dispatched"
	// onwards, "displayed" to the user, or "processed" in some way the other
	// three do not cover.
	Type string `json:"type,omitzero"`
}

MDNDisposition says what became of the message and how much of that the user chose. RFC 9007 calls it Disposition; the name is qualified here because it is too general to claim on its own.

A request using this type must declare urn:ietf:params:jmap:mdn.

type MDNParseArguments added in v0.2.0

type MDNParseArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the blobs to read as notifications.
	BlobIDs []ID `json:"blobIds,omitzero"`
}

MDNParseArguments holds the arguments of the MDN/parse method.

A request using this type must declare urn:ietf:params:jmap:mdn.

type MDNParseResponse added in v0.2.0

type MDNParseResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The notification found in each blob, keyed by blob id.
	Parsed map[ID]MDN `json:"parsed"`

	// The ids of the blobs that do not hold a notification the server could
	// read.
	NotParsable []ID `json:"notParsable"`

	// The ids of the blobs that do not exist.
	NotFound []ID `json:"notFound"`
}

MDNParseResponse holds the response to the MDN/parse method.

A request using this type must declare urn:ietf:params:jmap:mdn.

type MDNSendArguments added in v0.2.0

type MDNSendArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The identity to send from, which decides both the sender and the address
	// the notification is issued for.
	IdentityID ID `json:"identityId,omitzero"`

	// The notifications to send, keyed by creation id.
	Send map[ID]MDN `json:"send,omitzero"`

	// Patches to apply to the emails of the notifications that were sent, keyed
	// by creation id. This is where the $mdnsent keyword is set, so that a
	// receipt is not sent for the same message twice.
	OnSuccessUpdateEmail map[ID]PatchObject `json:"onSuccessUpdateEmail,omitzero"`
}

MDNSendArguments holds the arguments of the MDN/send method.

A request using this type must declare urn:ietf:params:jmap:mdn.

type MDNSendResponse added in v0.2.0

type MDNSendResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The notifications that were sent, with the properties the server filled
	// in, keyed by creation id.
	Sent map[ID]MDN `json:"sent"`

	// A map of creation id to the reason the notification could not be sent.
	NotSent map[ID]SetError `json:"notSent"`
}

MDNSendResponse holds the response to the MDN/send method.

A request using this type must declare urn:ietf:params:jmap:mdn.

type Mailbox

type Mailbox struct {
	// The id of the mailbox.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The user-visible name of the mailbox, unique among its siblings.
	Name string `json:"name,omitzero"`

	// The id of the parent mailbox, or null if it is at the top level.
	ParentID *ID `json:"parentId,omitzero"`

	// The IANA-registered role of the mailbox, such as "inbox" or "trash", or
	// null if it has none.
	Role *string `json:"role,omitzero"`

	// A hint for where to place the mailbox in a list of its siblings.
	//
	// The server assumes 0 when this property is omitted.
	SortOrder UnsignedInt `json:"sortOrder,omitzero"`

	// The number of emails in the mailbox.
	//
	// The server sets this property; it may not be set by the client.
	TotalEmails UnsignedInt `json:"totalEmails,omitzero"`

	// The number of emails in the mailbox without the $seen keyword.
	//
	// The server sets this property; it may not be set by the client.
	UnreadEmails UnsignedInt `json:"unreadEmails,omitzero"`

	// The number of threads with at least one email in the mailbox.
	//
	// The server sets this property; it may not be set by the client.
	TotalThreads UnsignedInt `json:"totalThreads,omitzero"`

	// The number of threads with at least one unread email in the mailbox.
	//
	// The server sets this property; it may not be set by the client.
	UnreadThreads UnsignedInt `json:"unreadThreads,omitzero"`

	// What the authenticated user may do with the mailbox.
	//
	// The server sets this property; it may not be set by the client.
	MyRights MailboxRights `json:"myRights,omitzero"`

	// Whether the user has subscribed to the mailbox.
	IsSubscribed bool `json:"isSubscribed,omitzero"`
}

Mailbox is a named set of emails, which is how JMAP models both folders and labels.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxChangesArguments

type MailboxChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Mailbox/get or Mailbox/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

MailboxChangesArguments holds the arguments of the Mailbox/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxChangesResponse

type MailboxChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

MailboxChangesResponse holds the response to the Mailbox/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxFilterCondition

type MailboxFilterCondition struct {
	// Matches mailboxes with this parent, or top-level mailboxes if null.
	ParentID *ID `json:"parentId,omitzero"`

	// Matches mailboxes whose name contains this string.
	Name string `json:"name,omitzero"`

	// Matches mailboxes with this role, or with no role if null.
	Role *string `json:"role,omitzero"`

	// Matches mailboxes according to whether they have any role at all.
	HasAnyRole bool `json:"hasAnyRole,omitzero"`

	// Matches mailboxes according to the user's subscription.
	IsSubscribed bool `json:"isSubscribed,omitzero"`
}

MailboxFilterCondition is a condition a mailbox must satisfy to match a Mailbox/query.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxGetArguments

type MailboxGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

MailboxGetArguments holds the arguments of the Mailbox/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxGetResponse

type MailboxGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Mailbox/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Mailbox `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

MailboxGetResponse holds the response to the Mailbox/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxQueryArguments

type MailboxQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrMailboxFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to order the results so that each mailbox follows its parent.
	//
	// The server assumes false when this property is omitted.
	SortAsTree bool `json:"sortAsTree,omitzero"`

	// Whether a mailbox matches only if all of its ancestors match too.
	//
	// The server assumes false when this property is omitted.
	FilterAsTree bool `json:"filterAsTree,omitzero"`
}

MailboxQueryArguments holds the arguments of the Mailbox/query method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxQueryChangesArguments

type MailboxQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrMailboxFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// Mailbox/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`

	// Whether to order the results so that each mailbox follows its parent.
	//
	// The server assumes false when this property is omitted.
	SortAsTree bool `json:"sortAsTree,omitzero"`

	// Whether a mailbox matches only if all of its ancestors match too.
	//
	// The server assumes false when this property is omitted.
	FilterAsTree bool `json:"filterAsTree,omitzero"`
}

MailboxQueryChangesArguments holds the arguments of the Mailbox/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxQueryChangesResponse

type MailboxQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

MailboxQueryChangesResponse holds the response to the Mailbox/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxQueryResponse

type MailboxQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with Mailbox/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

MailboxQueryResponse holds the response to the Mailbox/query method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxRights

type MailboxRights struct {
	// Whether the user may read the mailbox's emails.
	MayReadItems bool `json:"mayReadItems,omitzero"`

	// Whether the user may add emails to the mailbox.
	MayAddItems bool `json:"mayAddItems,omitzero"`

	// Whether the user may remove emails from the mailbox.
	MayRemoveItems bool `json:"mayRemoveItems,omitzero"`

	// Whether the user may change the $seen keyword on the mailbox's emails.
	MaySetSeen bool `json:"maySetSeen,omitzero"`

	// Whether the user may change keywords other than $seen.
	MaySetKeywords bool `json:"maySetKeywords,omitzero"`

	// Whether the user may create a child of this mailbox.
	MayCreateChild bool `json:"mayCreateChild,omitzero"`

	// Whether the user may rename or move the mailbox.
	MayRename bool `json:"mayRename,omitzero"`

	// Whether the user may delete the mailbox.
	MayDelete bool `json:"mayDelete,omitzero"`

	// Whether the user may submit the mailbox's emails for delivery.
	MaySubmit bool `json:"maySubmit,omitzero"`
}

MailboxRights says what the authenticated user may do with a mailbox.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxSetArguments

type MailboxSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]Mailbox `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// Whether destroying a mailbox may also remove the emails it holds. If
	// false, destroying a non-empty mailbox fails.
	//
	// The server assumes false when this property is omitted.
	OnDestroyRemoveEmails bool `json:"onDestroyRemoveEmails,omitzero"`
}

MailboxSetArguments holds the arguments of the Mailbox/set method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MailboxSetResponse

type MailboxSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*Mailbox `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*Mailbox `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

MailboxSetResponse holds the response to the Mailbox/set method.

A request using this type must declare urn:ietf:params:jmap:mail.

type MethodError

type MethodError struct {
	// CallID is the client-assigned identifier of the failed method call.
	CallID string `json:"-"`
	// MethodName is the name of the method that was invoked.
	MethodName string `json:"-"`
	// Type is the error type, such as "invalidArguments".
	Type string `json:"type"`
	// Description is an optional human-readable explanation.
	Description string `json:"description,omitempty"`
	// Arguments names the invalid arguments when Type is "invalidArguments".
	Arguments []string `json:"arguments,omitempty"`
	// Raw holds every member of the error object, so that error types carrying
	// members beyond those above remain inspectable.
	Raw map[string]json.RawMessage `json:"-"`
}

MethodError is a method-level error as defined in RFC 8620, Section 3.6.2. The server returns it in place of the response to a single method call; the other calls in the same request may still have succeeded.

func (*MethodError) Error

func (e *MethodError) Error() string

type MethodErrors

type MethodErrors []*MethodError

MethodErrors collects every method-level error in one response. A request whose calls partly succeeded returns both the decoded results and a MethodErrors describing the calls that did not.

func (MethodErrors) Error

func (e MethodErrors) Error() string

func (MethodErrors) Unwrap

func (e MethodErrors) Unwrap() []error

Unwrap lets errors.As reach the individual method errors.

type Observer added in v0.12.0

type Observer struct {
	// Request is called before a JMAP request is sent, ahead of the first
	// attempt. The function it returns is called once the response has been
	// decoded, or once the request has failed.
	Request func(ctx context.Context, info RequestInfo) (context.Context, func(ResponseInfo))

	// Attempt is called before each HTTP request the client sends. This
	// includes the requests that carry no JMAP calls — the session, an upload,
	// a download, the event stream — and each retry of any of them.
	Attempt func(ctx context.Context, info AttemptInfo) (context.Context, func(AttemptInfo, Answer))

	// Wait is called when the client delays a request instead of sending it:
	// either for one of the slots the server's maxConcurrentRequests allows,
	// or for the delay that follows a 429 or a 503. The function it returns is
	// called when the delay has elapsed.
	Wait func(ctx context.Context, info WaitInfo) func()
}

An Observer receives a report of what the client does. It is the attachment point for logging, metrics and tracing, and it affects neither the request sent nor the response received. A nil field is not called.

Each hook returns the function to call when the operation it covers has finished, which is where a duration is measured and where a span ends. A hook that returns a nil function receives no such call.

Request and Attempt also return the context used for the operation, so a span started in one becomes the parent of the spans started under it. Returning the incoming context, or nil, leaves the context unchanged.

The three hooks nest. A JMAP request has one attempt, or more if it is retried, and a wait may precede any attempt:

Request   Email/query, Email/get
  Wait    for a slot, where the server accepts two requests at once
  Attempt POST /jmap/api  429
  Wait    for the two seconds of the server's Retry-After
  Attempt POST /jmap/api  200

func SlogObserver added in v0.12.0

func SlogObserver(l *slog.Logger) *Observer

SlogObserver returns an Observer that writes to l at debug level, one record for each request, attempt and wait.

It logs no failure at a higher level, because an error returned to the caller is logged by the caller. What it adds is the information the caller cannot obtain: which methods were sent in one request, how long the round trip took, and how much of that was spent waiting.

type Option

type Option func(*Client)

Option configures a Client.

func WithAPIURL

func WithAPIURL(apiURL string) Option

WithAPIURL posts requests straight to apiURL instead of the apiUrl the session advertises. The session is still fetched when something needs it, such as resolving a primary account id.

func WithBasicAuth

func WithBasicAuth(username, password string) Option

WithBasicAuth authenticates with HTTP Basic credentials.

func WithBearerToken

func WithBearerToken(token string) Option

WithBearerToken authenticates with an OAuth 2.0 bearer token or an equivalent API token. Use WithTokenSource for a token that expires.

func WithHTTPClient

func WithHTTPClient(hc *http.Client) Option

WithHTTPClient makes the client issue its requests through hc, which is where timeouts, proxies, and transport-level instrumentation belong.

func WithHeader

func WithHeader(key, value string) Option

WithHeader sets a header on every request the client makes.

func WithObserver added in v0.12.0

func WithObserver(o *Observer) Option

WithObserver makes the client report what it does to o.

func WithRequestEditor

func WithRequestEditor(f func(*http.Request) error) Option

WithRequestEditor runs f on every outgoing HTTP request before it is sent, which covers authentication schemes the options above do not.

func WithRetry added in v0.6.0

func WithRetry(attempts int) Option

WithRetry makes the client send a request again where the server answered 429 or 503, up to the given number of attempts counting the first. Two or fewer than two disables it.

Those are the two responses that report the request was not carried out, and the delay is the server's Retry-After where it sent one. A request that failed in transit is not retried, since it may have been carried out; WithRetryPolicy overrides that for a client whose requests are safe to repeat.

func WithRetryPolicy added in v0.6.0

func WithRetryPolicy(p RetryPolicy) Option

WithRetryPolicy replaces the whole policy: which responses are worth another attempt, and how long to wait before each.

func WithSplitGets added in v0.12.0

func WithSplitGets() Option

WithSplitGets sends a /get holding more ids than the server's maxObjectsInGet in several requests rather than letting the server refuse it, and joins what comes back into the one response the caller asked for.

It is off by default because one call to Do then costs several round trips, and because the records no longer arrive as one snapshot: each request is answered separately, and the account may change between them. Where the state a /get reports differs between requests, the joined response is returned together with a *StateChanged, which errors.As reaches.

Only the ids written into the query are counted. A call whose ids come from a back reference is sent as it is, since their number is known to the server alone, and so is a call another call refers to, since a reference resolves within one request and splitting the call it names would leave nothing to resolve against.

func WithTokenSource added in v0.12.0

func WithTokenSource(src TokenSource) Option

WithTokenSource authenticates with a bearer token fetched when one is needed, which is what an OAuth 2.0 access token requires: it expires, and a client built around a fixed string has to be rebuilt to replace it, losing the cached session and the count of the requests in flight with it.

The token is held until it expires. A source that reports an expiry is called again shortly before it, and one that reports none is called again only when a server answers 401. Whichever it is, requests arriving together share one call: a source that exchanges a refresh token is not asked to do so several times at once.

A 401 also causes the one request that received it to be sent again, once, with a newly fetched token, since a token that has just been refused is worth replacing before the caller is told the request failed. That is separate from WithRetry, which retries what a server said it did not carry out.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent overrides the User-Agent header.

func WithoutPreflightChecks

func WithoutPreflightChecks() Option

WithoutPreflightChecks stops the client from validating a request against the session's advertised capabilities and limits before sending it. The checks turn a wasted round trip into a local error, so leave them on unless a server under-reports what it supports.

type ParticipantIdentity

type ParticipantIdentity struct {
	// The id of the identity.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The name to send with scheduling messages.
	//
	// The server assumes "" when this property is omitted.
	Name *string `json:"name,omitzero"`

	// The address that identifies the user in an event's participants.
	CalendarAddress string `json:"calendarAddress,omitzero"`

	// Where the user receives scheduling messages, keyed by method.
	SendTo map[string]string `json:"sendTo,omitzero"`

	// Whether this is the identity used when the client does not say.
	//
	// The server sets this property; it may not be set by the client.
	IsDefault bool `json:"isDefault,omitzero"`
}

ParticipantIdentity is an address the user takes part in events as, which is how the server knows which participant in an event is them.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentityChangesArguments

type ParticipantIdentityChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// ParticipantIdentity/get or ParticipantIdentity/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

ParticipantIdentityChangesArguments holds the arguments of the ParticipantIdentity/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentityChangesResponse

type ParticipantIdentityChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

ParticipantIdentityChangesResponse holds the response to the ParticipantIdentity/changes method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentityGetArguments

type ParticipantIdentityGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

ParticipantIdentityGetArguments holds the arguments of the ParticipantIdentity/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentityGetResponse

type ParticipantIdentityGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with ParticipantIdentity/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []ParticipantIdentity `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

ParticipantIdentityGetResponse holds the response to the ParticipantIdentity/get method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentitySetArguments

type ParticipantIdentitySetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]ParticipantIdentity `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

ParticipantIdentitySetArguments holds the arguments of the ParticipantIdentity/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type ParticipantIdentitySetResponse

type ParticipantIdentitySetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*ParticipantIdentity `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*ParticipantIdentity `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

ParticipantIdentitySetResponse holds the response to the ParticipantIdentity/set method.

A request using this type must declare urn:ietf:params:jmap:calendars.

type PatchObject

type PatchObject map[string]any

PatchObject is the JMAP PatchObject data type used by the update argument of a /set call. Each key is a JSON pointer into the object being patched and each value is the replacement, or nil to remove the pointed-at member.

The leading "/" of the pointer is implicit, as RFC 8620, Section 5.3 has it: a keyword is set at "keywords/$seen" rather than at "/keywords/$seen", and writing the slash refers to a property with no name.

func (PatchObject) Remove

func (p PatchObject) Remove(pointer string) PatchObject

Remove records that the member at the given JSON pointer should be deleted. The pointer is written without its leading "/", as "keywords/$seen".

func (PatchObject) Set

func (p PatchObject) Set(pointer string, value any) PatchObject

Set records that the value at the given JSON pointer should be replaced. The pointer is written without its leading "/", as "keywords/$seen".

type Principal added in v0.2.0

type Principal struct {
	// The id of the principal.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// What the principal is: "individual", "group", "resource", "location", or
	// "other".
	//
	// The server sets this property; it may not be set by the client.
	Type string `json:"type,omitzero"`

	// The user-visible name of the principal.
	Name string `json:"name,omitzero"`

	// A longer description of the principal.
	Description *string `json:"description,omitzero"`

	// An email address for the principal, or null for one that has none.
	Email *string `json:"email,omitzero"`

	// The time zone the principal is normally in, named as in the IANA Time Zone
	// Database.
	TimeZone *string `json:"timeZone,omitzero"`

	// What the principal supports, keyed by capability URI, with the details
	// each capability defines.
	//
	// The server sets this property; it may not be set by the client.
	Capabilities map[string]any `json:"capabilities,omitzero"`

	// The accounts the principal shares with the authenticated user, keyed by
	// account id, or null if none are visible.
	//
	// The server sets this property; it may not be set by the client.
	Accounts map[ID]Account `json:"accounts,omitzero"`
}

Principal is an entity that data can be shared with and that may own accounts: a person, a group, or something bookable such as a room or a projector.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalChangesArguments added in v0.2.0

type PrincipalChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Principal/get or Principal/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

PrincipalChangesArguments holds the arguments of the Principal/changes method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalChangesResponse added in v0.2.0

type PrincipalChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

PrincipalChangesResponse holds the response to the Principal/changes method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalFilterCondition added in v0.2.0

type PrincipalFilterCondition struct {
	// Matches principals that share one of these accounts with the user.
	AccountIDs []string `json:"accountIds,omitzero"`

	// Matches principals whose email address contains this text.
	Email string `json:"email,omitzero"`

	// Matches principals whose name contains this text.
	Name string `json:"name,omitzero"`

	// Matches principals where this text appears in the name, email, or
	// description.
	Text string `json:"text,omitzero"`

	// Matches principals of this type: "individual", "group", "resource",
	// "location", or "other".
	Type string `json:"type,omitzero"`

	// Matches principals in this time zone.
	TimeZone string `json:"timeZone,omitzero"`
}

PrincipalFilterCondition is a condition a principal must satisfy to match a Principal/query.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalGetArguments added in v0.2.0

type PrincipalGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

PrincipalGetArguments holds the arguments of the Principal/get method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalGetAvailabilityArguments

type PrincipalGetAvailabilityArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The id of the principal whose availability is wanted.
	ID ID `json:"id,omitzero"`

	// The start of the period to report on.
	UTCStart UTCDate `json:"utcStart,omitzero"`

	// The end of the period to report on.
	UTCEnd UTCDate `json:"utcEnd,omitzero"`

	// Whether to include the events themselves, for a caller allowed to see
	// them.
	//
	// The server assumes false when this property is omitted.
	ShowDetails bool `json:"showDetails,omitzero"`

	// The properties to include in each event returned, or null for all of them.
	EventProperties []string `json:"eventProperties,omitzero"`
}

PrincipalGetAvailabilityArguments holds the arguments of the Principal/getAvailability method.

A request using this type must declare urn:ietf:params:jmap:principals:availability.

type PrincipalGetAvailabilityResponse

type PrincipalGetAvailabilityResponse struct {
	// The periods the principal is busy in, merged and in no particular order.
	List []BusyPeriod `json:"list"`
}

PrincipalGetAvailabilityResponse holds the response to the Principal/getAvailability method.

A request using this type must declare urn:ietf:params:jmap:principals:availability.

type PrincipalGetResponse added in v0.2.0

type PrincipalGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Principal/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Principal `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

PrincipalGetResponse holds the response to the Principal/get method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalQueryArguments added in v0.2.0

type PrincipalQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrPrincipalFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

PrincipalQueryArguments holds the arguments of the Principal/query method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalQueryChangesArguments added in v0.2.0

type PrincipalQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrPrincipalFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// Principal/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

PrincipalQueryChangesArguments holds the arguments of the Principal/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalQueryChangesResponse added in v0.2.0

type PrincipalQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

PrincipalQueryChangesResponse holds the response to the Principal/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalQueryResponse added in v0.2.0

type PrincipalQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with Principal/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

PrincipalQueryResponse holds the response to the Principal/query method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalSetArguments added in v0.2.0

type PrincipalSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]Principal `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

PrincipalSetArguments holds the arguments of the Principal/set method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PrincipalSetResponse added in v0.2.0

type PrincipalSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*Principal `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*Principal `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

PrincipalSetResponse holds the response to the Principal/set method.

A request using this type must declare urn:ietf:params:jmap:principals.

type PushSubscription added in v0.2.0

type PushSubscription struct {
	// The id of the subscription.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// An id identifying the client and the device it runs on, so that a client
	// which has lost its local state can still find the subscriptions it made.
	// It must not carry an unobfuscated device id: the recommendation is a hash
	// of the device's identifier together with the vendor's own.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	DeviceClientID string `json:"deviceClientId,omitzero"`

	// The absolute URL the server posts to, which must begin with "https://". A
	// /get never returns it, since it may be private to one device.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	URL string `json:"url,omitzero"`

	// The keys to encrypt pushed data with. A /get never returns them, for the
	// same reason it withholds the url.
	//
	// This property may be set when the record is created, but not changed
	// afterwards.
	Keys *PushSubscriptionKeys `json:"keys,omitzero"`

	// The code proving the client controls the URL. It must be null when the
	// subscription is created; the server then pushes a code to the URL, and the
	// client writes it back here. Until that happens the server makes no further
	// requests to the URL, which is what stops a subscription being used to
	// attack a third party.
	VerificationCode *string `json:"verificationCode,omitzero"`

	// When the subscription lapses. The server may impose one where the client
	// gives none, or shorten the one it gives, and a client extends the lifetime
	// by writing a later time here.
	Expires *UTCDate `json:"expires,omitzero"`

	// The data types worth being told about, named as the TypeState object names
	// them. Null means every type.
	Types []string `json:"types,omitzero"`
}

PushSubscription is a URL the server posts to when something changes. It is tied to the credentials that created it rather than to an account, and the server destroys it when those credentials expire.

type PushSubscriptionGetArguments added in v0.2.0

type PushSubscriptionGetArguments struct {
	// The ids of the subscriptions to fetch, or null for all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to return. Asking for url or keys is refused with a
	// forbidden error, and leaving this out returns everything except those two.
	Properties []string `json:"properties,omitzero"`
}

PushSubscriptionGetArguments holds the arguments of the PushSubscription/get method.

type PushSubscriptionGetResponse added in v0.2.0

type PushSubscriptionGetResponse struct {
	// The subscriptions that were found, which are only those the current
	// credentials created.
	List []PushSubscription `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

PushSubscriptionGetResponse holds the response to the PushSubscription/get method.

type PushSubscriptionKeys added in v0.2.0

type PushSubscriptionKeys struct {
	// The P-256 ECDH public key, in URL-safe base64.
	P256dh string `json:"p256dh,omitzero"`

	// The authentication secret, in URL-safe base64.
	Auth string `json:"auth,omitzero"`
}

PushSubscriptionKeys are the client's encryption keys, which the server uses to encrypt everything it pushes, as RFC 8291 describes. RFC 8620 leaves this object unnamed.

type PushSubscriptionSetArguments added in v0.2.0

type PushSubscriptionSetArguments struct {
	// The subscriptions to create, keyed by creation id.
	Create map[ID]PushSubscription `json:"create,omitzero"`

	// Patches to apply, keyed by subscription id. This is how the verification
	// code is written back and how the expiry is extended; the url and keys
	// cannot be changed, only replaced by destroying the subscription and
	// creating another.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the subscriptions to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

PushSubscriptionSetArguments holds the arguments of the PushSubscription/set method.

type PushSubscriptionSetResponse added in v0.2.0

type PushSubscriptionSetResponse struct {
	// A map of creation id to the properties the server assigned to each
	// subscription it created.
	Created map[ID]*PushSubscription `json:"created"`

	// A map of subscription id to any properties the server changed beyond those
	// the patch set.
	Updated map[ID]*PushSubscription `json:"updated"`

	// The ids of the subscriptions that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the subscription could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of subscription id to the reason it could not be updated. A wrong
	// verification code is refused here, as an invalidProperties error.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of subscription id to the reason it could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

PushSubscriptionSetResponse holds the response to the PushSubscription/set method.

type PushVerification added in v0.2.0

type PushVerification struct {
	// Type is the object type, always "PushVerification".
	Type string `json:"@type"`
	// PushSubscriptionID is the id of the subscription that was created.
	PushSubscriptionID ID `json:"pushSubscriptionId"`
	// VerificationCode is the code to write back to that subscription.
	VerificationCode string `json:"verificationCode"`
}

PushVerification is what the server posts to a push subscription's URL as soon as it is created, before it will send anything else. The client writes the code back with a PushSubscription/set, which proves that the client controls the URL. Without that step a subscription could be pointed at a third party and used to flood it.

It arrives at the URL the client registered, not through the API, which is why it is here rather than in the generated types.

type Quota added in v0.2.0

type Quota struct {
	// The id of the quota.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// What is being counted: "count" for a number of objects, or "octets" for
	// their size.
	ResourceType string `json:"resourceType,omitzero"`

	// How much of the resource is in use, in whatever the resourceType counts.
	//
	// The server sets this property; it may not be set by the client.
	Used UnsignedInt `json:"used,omitzero"`

	// The point beyond which the server refuses to store more.
	HardLimit UnsignedInt `json:"hardLimit,omitzero"`

	// Who the limit applies to: "account" for this account alone, "domain" for
	// everyone in the domain, or "global" for the whole server.
	Scope string `json:"scope,omitzero"`

	// The name of the quota, which is unique within its scope and resourceType.
	Name string `json:"name,omitzero"`

	// The data types the quota applies to, such as "Mail" or "Calendar". The
	// names are those of the capabilities, not of individual record types.
	Types []string `json:"types,omitzero"`

	// The point at which the server would like the client to warn the user,
	// which it sets below the hard limit so that there is time to do something
	// about it.
	//
	// The server assumes null when this property is omitted.
	WarnLimit *UnsignedInt `json:"warnLimit,omitzero"`

	// The point beyond which the server starts refusing some operations while
	// still allowing others, such as accepting mail but not letting the user
	// send any.
	//
	// The server assumes null when this property is omitted.
	SoftLimit *UnsignedInt `json:"softLimit,omitzero"`

	// A description of the quota, meant to be shown to the user.
	//
	// The server assumes null when this property is omitted.
	Description *string `json:"description,omitzero"`
}

Quota is one limit on what an account may hold, and how much of that limit is used. An account may be under several at once: a count of messages, a number of octets, one imposed on the account and another on the whole domain.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaChangesArguments added in v0.2.0

type QuotaChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Quota/get or Quota/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

QuotaChangesArguments holds the arguments of the Quota/changes method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaChangesResponse added in v0.2.0

type QuotaChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`

	// The properties that changed on every quota in the updated list, or null if
	// the client should assume anything may have. A server that tracks this can
	// say "used" alone, which is usually all that moved.
	UpdatedProperties []string `json:"updatedProperties"`
}

QuotaChangesResponse holds the response to the Quota/changes method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaFilterCondition added in v0.2.0

type QuotaFilterCondition struct {
	// Matches quotas whose name contains this string.
	Name string `json:"name,omitzero"`

	// Matches quotas of this scope: "account", "domain", or "global".
	Scope string `json:"scope,omitzero"`

	// Matches quotas counting this resource: "count" or "octets".
	ResourceType string `json:"resourceType,omitzero"`

	// Matches quotas that apply to this data type.
	Type string `json:"type,omitzero"`
}

QuotaFilterCondition is a condition a quota must satisfy to match a Quota/query.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaGetArguments added in v0.2.0

type QuotaGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

QuotaGetArguments holds the arguments of the Quota/get method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaGetResponse added in v0.2.0

type QuotaGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Quota/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Quota `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

QuotaGetResponse holds the response to the Quota/get method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaQueryArguments added in v0.2.0

type QuotaQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrQuotaFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

QuotaQueryArguments holds the arguments of the Quota/query method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaQueryChangesArguments added in v0.2.0

type QuotaQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrQuotaFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// Quota/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

QuotaQueryChangesArguments holds the arguments of the Quota/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaQueryChangesResponse added in v0.2.0

type QuotaQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

QuotaQueryChangesResponse holds the response to the Quota/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:quota.

type QuotaQueryResponse added in v0.2.0

type QuotaQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with Quota/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

QuotaQueryResponse holds the response to the Quota/query method.

A request using this type must declare urn:ietf:params:jmap:quota.

type Request

type Request struct {
	// Using lists the capability URIs the request depends on.
	Using []string `json:"using"`
	// MethodCalls are executed by the server in order.
	MethodCalls []Invocation `json:"methodCalls"`
	// CreatedIDs maps creation ids to record ids carried over from an earlier
	// request, and is optional.
	CreatedIDs map[ID]ID `json:"createdIds,omitempty"`
}

Request is the JMAP Request object of RFC 8620, Section 3.3.

type RequestError

type RequestError struct {
	// Status is the HTTP status code the server responded with.
	Status int `json:"status"`
	// Type is the problem type URI, such as
	// "urn:ietf:params:jmap:error:unknownCapability".
	Type string `json:"type"`
	// Title is a short human-readable summary, if the server supplied one.
	Title string `json:"title,omitempty"`
	// Detail is a human-readable explanation specific to this occurrence.
	Detail string `json:"detail,omitempty"`
	// Limit names the exceeded limit when Type is
	// "urn:ietf:params:jmap:error:limit".
	Limit string `json:"limit,omitempty"`
}

RequestError is a request-level error as defined in RFC 8620, Section 3.6.1. The server reports these as an RFC 7807 problem details document with a non-2xx status, and none of the method calls in the request were executed.

func (*RequestError) Error

func (e *RequestError) Error() string

type RequestInfo added in v0.12.0

type RequestInfo struct {
	// Calls lists the method calls of the request, in the order the request
	// holds them.
	Calls []CallInfo
	// Using holds the capability URIs the request declares.
	Using []string
}

RequestInfo describes a JMAP request the client is about to send.

type RequestKind added in v0.12.0

type RequestKind string

RequestKind identifies the purpose of a request the client sends.

const (
	// KindAPI is a JMAP request posted to the API URL.
	KindAPI RequestKind = "api"
	// KindSession is a request for the session object.
	KindSession RequestKind = "session"
	// KindUpload is a blob upload to the upload URL.
	KindUpload RequestKind = "upload"
	// KindDownload is a blob download from the download URL.
	KindDownload RequestKind = "download"
	// KindEvents is a connection to the event source URL.
	KindEvents RequestKind = "events"
)

type Response

type Response struct {
	// MethodResponses holds one entry per executed method call, in the order
	// the server executed them.
	MethodResponses []Invocation `json:"methodResponses"`
	// CreatedIDs maps creation ids to the ids the server assigned.
	CreatedIDs map[ID]ID `json:"createdIds,omitempty"`
	// SessionState is the state string of the Session object at the time the
	// request was handled. A change means the session should be re-fetched.
	SessionState string `json:"sessionState"`
	// contains filtered or unexported fields
}

Response is the JMAP Response object of RFC 8620, Section 3.4.

func (*Response) Decode

func (r *Response) Decode(callID string, dest any) error

Decode unmarshals the response to the method call with the given call id into dest. It returns a *MethodError if the server reported an error for that call. Generated code uses this to turn one entry of methodResponses into a typed value.

func (*Response) Errors

func (r *Response) Errors() MethodErrors

Errors returns every method-level error in the response, or nil if there are none. A response may hold both errors and successful results, because the server executes the calls it can.

type ResponseInfo added in v0.12.0

type ResponseInfo struct {
	// Duration is the time the request took, including waits and retries.
	Duration time.Duration
	// Err is the error returned to the caller, and nil where the request was
	// answered. Method-level errors are not reported here; Errors holds
	// those.
	Err error
	// Errors holds the method-level errors of an answered request. The other
	// calls of the request may still have succeeded.
	Errors MethodErrors
}

ResponseInfo describes the outcome of a JMAP request.

type ResultReference

type ResultReference struct {
	// ResultOf is the call id of the earlier method call.
	ResultOf string `json:"resultOf"`
	// Name is the method name of that call, which the server checks against
	// the call it finds.
	Name string `json:"name"`
	// Path is a JMAP JSON pointer into that call's response.
	Path string `json:"path"`
}

ResultReference refers to a value in the response to an earlier method call in the same request, as defined in RFC 8620, Section 3.7. It is what allows a single JMAP request to carry a chain of dependent calls.

type RetryPolicy added in v0.6.0

type RetryPolicy struct {
	// Attempts is how many times a request is sent in all, counting the first.
	// Zero or one sends it once.
	Attempts int
	// Worth reports whether a response is worth another attempt. A nil Worth
	// selects the two responses that report the server did nothing: 429 and
	// 503.
	//
	// It is called with the response, or with the error where no response was
	// received. Retrying an error means retrying a request that may have been
	// carried out, so the default does not.
	Worth func(*http.Response, error) bool
	// Wait returns how long to wait before the nth attempt, counting from two.
	// The server's Retry-After is passed as it was received, or zero where the
	// server sent none. A nil Wait uses that value, and falls back to a delay
	// that doubles from 0.2 seconds to 30 seconds where the server sent none.
	//
	// A Retry-After longer than a minute is not waited out. The client stops
	// and reports the refusal instead, because holding a request in memory for
	// that long is of no use to the caller, which should retry later.
	Wait func(attempt int, retryAfter time.Duration) time.Duration
}

RetryPolicy determines when a client sends a request again, and how long it waits first.

The default is to retry only where the server reported that it did nothing — a 429 or a 503 — because a request that may have been carried out is not safe to repeat. A JMAP request creates records, and a /set sent twice creates twice.

type SearchSnippet

type SearchSnippet struct {
	// The id of the email the snippet is from.
	EmailID ID `json:"emailId,omitzero"`

	// The email's subject with the matching words wrapped in <mark> tags, or
	// null if nothing in it matched.
	Subject *string `json:"subject,omitzero"`

	// An extract of the email's body with the matching words wrapped in <mark>
	// tags, or null if nothing in it matched.
	Preview *string `json:"preview,omitzero"`
}

SearchSnippet is the part of an email that matched a search, with the matching words marked up for display.

A request using this type must declare urn:ietf:params:jmap:mail.

type SearchSnippetGetArguments

type SearchSnippetGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the search used, which is what the snippets are cut around.
	Filter *FilterOperatorOrEmailFilterCondition `json:"filter,omitzero"`

	// The ids of the emails to return snippets for.
	EmailIDs []ID `json:"emailIds,omitzero"`
}

SearchSnippetGetArguments holds the arguments of the SearchSnippet/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type SearchSnippetGetResponse

type SearchSnippetGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The snippets that were generated, one per email that was found.
	List []SearchSnippet `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

SearchSnippetGetResponse holds the response to the SearchSnippet/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type Session

type Session struct {
	// Capabilities lists the capabilities the server supports, keyed by URI.
	Capabilities map[string]json.RawMessage `json:"capabilities"`
	// Accounts lists the accounts the authenticated user has access to.
	Accounts map[ID]*Account `json:"accounts"`
	// PrimaryAccounts maps a capability URI to the id of the account that
	// should be used for it by default.
	PrimaryAccounts map[string]ID `json:"primaryAccounts"`
	// Username identifies the authenticated user.
	Username string `json:"username"`
	// APIURL is the endpoint that JMAP requests are POSTed to.
	APIURL string `json:"apiUrl"`
	// DownloadURL is a URI template for downloading blobs.
	DownloadURL string `json:"downloadUrl"`
	// UploadURL is a URI template for uploading blobs.
	UploadURL string `json:"uploadUrl"`
	// EventSourceURL is a URI template for the push event source.
	EventSourceURL string `json:"eventSourceUrl"`
	// State changes whenever any other member of the Session object changes.
	State string `json:"state"`
}

Session is the Session object described in RFC 8620, Section 2. It states where to send requests and what the server supports.

func (*Session) Capability added in v0.2.0

func (s *Session) Capability(uri string, dest any) error

Capability decodes the session's entry for a capability into dest.

Not every capability defines types and methods. Some carry only a value for the client — a limit, a key, an identifier — and this is how that value is read, including for a capability jmapc does not know.

func (*Session) Core

func (s *Session) Core() (*CoreCapability, error)

Core returns the server's core capability limits.

func (*Session) HasCapability

func (s *Session) HasCapability(uri string) bool

HasCapability reports whether the server advertises the given capability URI.

func (*Session) PrimaryAccountID

func (s *Session) PrimaryAccountID(capability string) (ID, error)

PrimaryAccountID returns the id of the account to use by default for the given capability. Generated code calls this when a query leaves accountId unset.

func (*Session) WebPushVAPID added in v0.2.0

func (s *Session) WebPushVAPID() (*WebPushVAPIDCapability, error)

WebPushVAPID returns the key the server authenticates itself to a push service with. It changes when the server rotates its keys, which appears as a new sessionState.

type SetError

type SetError struct {
	// Type is the error type, such as "invalidProperties" or "notFound".
	Type string `json:"type"`
	// Description is an optional human-readable explanation.
	Description string `json:"description,omitempty"`
	// Properties names the offending properties when Type is
	// "invalidProperties".
	Properties []string `json:"properties,omitempty"`
	// ExistingID is set when Type is "alreadyExists".
	ExistingID ID `json:"existingId,omitempty"`
}

SetError is the error object reported per-record in the notCreated, notUpdated, and notDestroyed maps of a /set response. It is not returned as a Go error, because the surrounding method call itself succeeded.

func (*SetError) Error

func (e *SetError) Error() string

type SetErrors added in v0.4.0

type SetErrors struct {
	Failures []SetFailure
}

SetErrors reports the records a request could not act on. A /set answers 200 and lists what it refused, so a caller that reads only the transport error sees success where there was none; generated code collects those refusals and returns them here, alongside the part of the response that did succeed.

Use errors.As to reach it, and Failures to see which records failed and why.

func (*SetErrors) Collect added in v0.4.0

func (e *SetErrors) Collect(method, callID string, groups map[string]map[ID]SetError)

Collect records the failures a method call reported, keyed by the response property they arrived in. It is called by generated code.

func (*SetErrors) Err added in v0.4.0

func (e *SetErrors) Err() error

Err returns e where anything failed and nil where nothing did, so that generated code can collect first and decide afterwards.

func (*SetErrors) Error added in v0.4.0

func (e *SetErrors) Error() string

func (*SetErrors) Unwrap added in v0.4.0

func (e *SetErrors) Unwrap() []error

Unwrap reports the failures as errors, so that errors.Is and errors.As reach each of them.

type SetFailure added in v0.4.0

type SetFailure struct {
	// Method is the method call that refused the record, such as "Email/set".
	Method string
	// CallID is the id of that call within the request.
	CallID string
	// Kind is the response property the failure was reported in, such as
	// "notCreated".
	Kind string
	// Key is the creation id or record id the failure is filed under.
	Key ID
	// Err is the error the server reported.
	Err SetError
}

SetFailure is one record a /set would not act on, and what the server said about it.

func (SetFailure) Error added in v0.4.0

func (f SetFailure) Error() string

func (SetFailure) Unwrap added in v0.6.0

func (f SetFailure) Unwrap() error

Unwrap exposes the SetError this failure carries, so that errors.As(err, &setError) with a *SetError target can reach it without the caller knowing SetFailure exists.

type ShareNotification added in v0.2.0

type ShareNotification struct {
	// The id of the notification.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// When the change was made.
	//
	// The server sets this property; it may not be set by the client.
	Created UTCDate `json:"created,omitzero"`

	// Who made the change.
	//
	// The server sets this property; it may not be set by the client.
	ChangedBy ShareNotificationEntity `json:"changedBy,omitzero"`

	// The type of the object whose sharing changed, such as "Mailbox" or
	// "Calendar".
	//
	// The server sets this property; it may not be set by the client.
	ObjectType string `json:"objectType,omitzero"`

	// The id of the account the object belongs to.
	//
	// The server sets this property; it may not be set by the client.
	ObjectAccountID ID `json:"objectAccountId,omitzero"`

	// The id of the object itself.
	//
	// The server sets this property; it may not be set by the client.
	ObjectID ID `json:"objectId,omitzero"`

	// What the user could do with the object before the change, or null if they
	// could not see it at all.
	//
	// The server sets this property; it may not be set by the client.
	OldRights map[string]bool `json:"oldRights,omitzero"`

	// What the user can do with the object now, or null if it is no longer
	// shared with them.
	//
	// The server sets this property; it may not be set by the client.
	NewRights map[string]bool `json:"newRights,omitzero"`

	// The name the object had when the change was made, so that a notification
	// about something since renamed still reads sensibly.
	//
	// The server sets this property; it may not be set by the client.
	Name string `json:"name,omitzero"`
}

ShareNotification records that someone changed what is shared with the user. Nothing else tells them: the object simply appears in, or disappears from, an account they can see.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationChangesArguments added in v0.2.0

type ShareNotificationChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// ShareNotification/get or ShareNotification/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

ShareNotificationChangesArguments holds the arguments of the ShareNotification/changes method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationChangesResponse added in v0.2.0

type ShareNotificationChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

ShareNotificationChangesResponse holds the response to the ShareNotification/changes method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationEntity added in v0.2.0

type ShareNotificationEntity struct {
	// The name of whoever made the change.
	Name string `json:"name,omitzero"`

	// Their email address.
	Email *string `json:"email,omitzero"`

	// Their principal id, for someone the server knows as a principal.
	PrincipalID *ID `json:"principalId,omitzero"`
}

ShareNotificationEntity identifies whoever changed what was shared. RFC 9670 calls it Entity.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationFilterCondition added in v0.2.0

type ShareNotificationFilterCondition struct {
	// Matches notifications created at or after this time.
	After *UTCDate `json:"after,omitzero"`

	// Matches notifications created before this time.
	Before *UTCDate `json:"before,omitzero"`

	// Matches notifications about objects of this type.
	ObjectType string `json:"objectType,omitzero"`

	// Matches notifications about objects in this account.
	ObjectAccountID ID `json:"objectAccountId,omitzero"`
}

ShareNotificationFilterCondition is a condition a notification must satisfy to match a ShareNotification/query.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationGetArguments added in v0.2.0

type ShareNotificationGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

ShareNotificationGetArguments holds the arguments of the ShareNotification/get method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationGetResponse added in v0.2.0

type ShareNotificationGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with ShareNotification/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []ShareNotification `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

ShareNotificationGetResponse holds the response to the ShareNotification/get method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationQueryArguments added in v0.2.0

type ShareNotificationQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrShareNotificationFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

ShareNotificationQueryArguments holds the arguments of the ShareNotification/query method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationQueryChangesArguments added in v0.2.0

type ShareNotificationQueryChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The filter the original query used.
	Filter *FilterOperatorOrShareNotificationFilterCondition `json:"filter,omitzero"`

	// The sort the original query used.
	Sort []Comparator `json:"sort,omitzero"`

	// The queryState the client already has, as returned by an earlier
	// ShareNotification/query.
	SinceQueryState string `json:"sinceQueryState,omitzero"`

	// The maximum number of changes to return.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`

	// The id of the last record in the client's cached window, beyond which
	// changes may be omitted.
	UpToID *ID `json:"upToId,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

ShareNotificationQueryChangesArguments holds the arguments of the ShareNotification/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationQueryChangesResponse added in v0.2.0

type ShareNotificationQueryChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The query state the changes are calculated from.
	OldQueryState string `json:"oldQueryState"`

	// The query state the client reaches by applying these changes.
	NewQueryState string `json:"newQueryState"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The ids to remove from the cached result list.
	Removed []ID `json:"removed"`

	// The ids to add to the cached result list, each with the index to insert it
	// at.
	Added []AddedItem `json:"added"`
}

ShareNotificationQueryChangesResponse holds the response to the ShareNotification/queryChanges method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationQueryResponse added in v0.2.0

type ShareNotificationQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with ShareNotification/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

ShareNotificationQueryResponse holds the response to the ShareNotification/query method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationSetArguments added in v0.2.0

type ShareNotificationSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]ShareNotification `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

ShareNotificationSetArguments holds the arguments of the ShareNotification/set method.

A request using this type must declare urn:ietf:params:jmap:principals.

type ShareNotificationSetResponse added in v0.2.0

type ShareNotificationSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*ShareNotification `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*ShareNotification `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

ShareNotificationSetResponse holds the response to the ShareNotification/set method.

A request using this type must declare urn:ietf:params:jmap:principals.

type SieveScript added in v0.2.0

type SieveScript struct {
	// The id of the script.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The user-visible name of the script, which is unique within the account.
	// Null asks the server to choose one.
	Name *string `json:"name,omitzero"`

	// The id of the blob holding the script's text, which is uploaded before the
	// script refers to it.
	BlobID ID `json:"blobId,omitzero"`

	// Whether this is the script the server runs. At most one script in an
	// account is active, and it is activated through the arguments of
	// SieveScript/set rather than by setting this.
	//
	// The server sets this property; it may not be set by the client.
	//
	// The server assumes false when this property is omitted.
	IsActive bool `json:"isActive,omitzero"`
}

SieveScript is one stored filtering script. An account may have several, of which at most one is running.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptFilterCondition added in v0.2.0

type SieveScriptFilterCondition struct {
	// Matches scripts whose name contains this string.
	Name string `json:"name,omitzero"`

	// Matches scripts according to whether they are the one running.
	IsActive bool `json:"isActive,omitzero"`
}

SieveScriptFilterCondition is a condition a script must satisfy to match a SieveScript/query.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptGetArguments added in v0.2.0

type SieveScriptGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

SieveScriptGetArguments holds the arguments of the SieveScript/get method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptGetResponse added in v0.2.0

type SieveScriptGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with SieveScript/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []SieveScript `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

SieveScriptGetResponse holds the response to the SieveScript/get method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptQueryArguments added in v0.2.0

type SieveScriptQueryArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The condition records must match to be included in the results.
	Filter *FilterOperatorOrSieveScriptFilterCondition `json:"filter,omitzero"`

	// The comparators to sort the results by, in order of precedence.
	Sort []Comparator `json:"sort,omitzero"`

	// The zero-based index of the first result to return. A negative value
	// counts back from the end.
	//
	// The server assumes 0 when this property is omitted.
	Position Int `json:"position,omitzero"`

	// The id of a record to position the returned window relative to, instead of
	// using position.
	Anchor *ID `json:"anchor,omitzero"`

	// The offset from the anchor at which the returned window starts.
	//
	// The server assumes 0 when this property is omitted.
	AnchorOffset Int `json:"anchorOffset,omitzero"`

	// The maximum number of ids to return.
	Limit *UnsignedInt `json:"limit,omitzero"`

	// Whether the server should compute the total number of matching records.
	//
	// The server assumes false when this property is omitted.
	CalculateTotal bool `json:"calculateTotal,omitzero"`
}

SieveScriptQueryArguments holds the arguments of the SieveScript/query method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptQueryResponse added in v0.2.0

type SieveScriptQueryResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the query on the server, for use
	// with SieveScript/queryChanges.
	QueryState string `json:"queryState"`

	// Whether the server can calculate changes for this query.
	CanCalculateChanges bool `json:"canCalculateChanges"`

	// The zero-based index of the first returned id in the full result list.
	Position UnsignedInt `json:"position"`

	// The ids of the matching records, in sorted order.
	IDs []ID `json:"ids"`

	// The total number of matching records, present only if calculateTotal was
	// true.
	Total UnsignedInt `json:"total"`

	// The limit the server applied, present only if it is lower than the one
	// requested.
	Limit UnsignedInt `json:"limit"`
}

SieveScriptQueryResponse holds the response to the SieveScript/query method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptSetArguments added in v0.2.0

type SieveScriptSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]SieveScript `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`

	// The id of the script to activate once the other changes succeed, which may
	// be a creation id written as "#" followed by the name it was created under.
	OnSuccessActivateScript *ID `json:"onSuccessActivateScript,omitzero"`

	// Whether to stop running whichever script is active. Where both this and
	// onSuccessActivateScript are given, the deactivation happens first.
	//
	// The server assumes false when this property is omitted.
	OnSuccessDeactivateScript bool `json:"onSuccessDeactivateScript,omitzero"`
}

SieveScriptSetArguments holds the arguments of the SieveScript/set method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptSetResponse added in v0.2.0

type SieveScriptSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*SieveScript `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*SieveScript `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

SieveScriptSetResponse holds the response to the SieveScript/set method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptValidateArguments added in v0.2.0

type SieveScriptValidateArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The id of the blob holding the script to check.
	BlobID ID `json:"blobId,omitzero"`
}

SieveScriptValidateArguments holds the arguments of the SieveScript/validate method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SieveScriptValidateResponse added in v0.2.0

type SieveScriptValidateResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// What is wrong with the script, as an invalidSieve error, or null if it is
	// valid.
	Error *SetError `json:"error"`
}

SieveScriptValidateResponse holds the response to the SieveScript/validate method.

A request using this type must declare urn:ietf:params:jmap:sieve.

type SignedDuration

type SignedDuration string

SignedDuration is the JSCalendar SignedDuration of RFC 8984, Section 1.4.7: a Duration that may be negative, which is how an alert specifies that it fires before the event it belongs to.

func (SignedDuration) String

func (d SignedDuration) String() string

func (SignedDuration) ToTimeDuration

func (d SignedDuration) ToTimeDuration() (time.Duration, error)

ToTimeDuration converts the duration as Duration.ToTimeDuration does, carrying the sign.

func (SignedDuration) Valid

func (d SignedDuration) Valid() bool

Valid reports whether the value has the form the specification requires.

type StateChange

type StateChange struct {
	// Type is the object type, always "StateChange".
	Type string `json:"@type"`
	// Changed maps an account id to the new state string of each type that
	// has changed within it, keyed by type name such as "Email".
	Changed map[ID]map[string]string `json:"changed"`
}

StateChange is the event a JMAP server pushes when something in an account changes, as defined in RFC 8620, Section 7.1. It reports only that a type has changed, not what changed; the client follows up with a /changes call.

func (*StateChange) StateOf

func (s *StateChange) StateOf(accountID ID, typeName string) (string, bool)

StateOf returns the new state of a type in an account, and whether the event mentioned it at all.

type StateChanged added in v0.12.0

type StateChanged struct {
	// Method is the method that was split, such as "Email/get".
	Method string
	// CallID is the id the request gave that call.
	CallID string
	// From is the state the first request reported, and To the state of the
	// request that differed from it.
	From, To string
}

StateChanged reports that a /get answered in several requests reported more than one state, so the records it returned are not one snapshot of the account. The response is returned with it, since the records are the ones the server held at the time each request reached it.

func (*StateChanged) Error added in v0.12.0

func (e *StateChanged) Error() string

type Thread

type Thread struct {
	// The id of the thread.
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// The ids of the emails in the thread, sorted by receivedAt and then by id.
	//
	// The server sets this property; it may not be set by the client.
	EmailIDs []ID `json:"emailIds,omitzero"`
}

Thread is a set of emails the server considers to be one conversation.

A request using this type must declare urn:ietf:params:jmap:mail.

type ThreadChangesArguments

type ThreadChangesArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state string the client already has, as returned by an earlier
	// Thread/get or Thread/changes.
	SinceState string `json:"sinceState,omitzero"`

	// The maximum number of ids to return across the three change lists.
	MaxChanges *UnsignedInt `json:"maxChanges,omitzero"`
}

ThreadChangesArguments holds the arguments of the Thread/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type ThreadChangesResponse

type ThreadChangesResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state the changes are calculated from.
	OldState string `json:"oldState"`

	// The state the client reaches by applying these changes.
	NewState string `json:"newState"`

	// Whether further changes remain, in which case the call should be repeated
	// from newState.
	HasMoreChanges bool `json:"hasMoreChanges"`

	// The ids of records created since oldState.
	Created []ID `json:"created"`

	// The ids of records updated since oldState.
	Updated []ID `json:"updated"`

	// The ids of records destroyed since oldState.
	Destroyed []ID `json:"destroyed"`
}

ThreadChangesResponse holds the response to the Thread/changes method.

A request using this type must declare urn:ietf:params:jmap:mail.

type ThreadGetArguments

type ThreadGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

ThreadGetArguments holds the arguments of the Thread/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type ThreadGetResponse

type ThreadGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with Thread/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []Thread `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

ThreadGetResponse holds the response to the Thread/get method.

A request using this type must declare urn:ietf:params:jmap:mail.

type TimeZoneID

type TimeZoneID string

TimeZoneID is the JSCalendar TimeZoneId of RFC 8984, Section 1.4.9: the name of a time zone in the IANA database, such as "Europe/London", or a name beginning with "/" that refers to a custom zone the event itself defines.

func (TimeZoneID) IsCustom

func (z TimeZoneID) IsCustom() bool

IsCustom reports whether the id refers to a zone defined in the event's own timeZones property rather than to one in the IANA database.

func (TimeZoneID) Location

func (z TimeZoneID) Location() (*time.Location, error)

Location returns the time zone the id names, looking it up in the IANA database. A custom zone is not there, so it fails; resolve those from the event's timeZones instead.

func (TimeZoneID) String

func (z TimeZoneID) String() string

type Token added in v0.12.0

type Token struct {
	// Value is the token itself, sent as "Authorization: Bearer <value>".
	Value string
	// Expiry is when the token stops being accepted, or the zero time where
	// that is not known.
	Expiry time.Time
}

Token is a bearer token, and the time it stops being accepted where the source knows it. A zero Expiry means the source does not know, and the token is then used until a server refuses it.

type TokenSource added in v0.12.0

type TokenSource func(ctx context.Context) (Token, error)

TokenSource returns the token to authenticate with. The client calls it when it has no token, when the one it holds has expired, and when a server has refused the one it holds.

type UTCDate

type UTCDate struct {
	time.Time
}

UTCDate is the JMAP UTCDate data type: a date-time in UTC, always serialised with a "Z" suffix and no fractional seconds.

func NewUTCDate

func NewUTCDate(t time.Time) UTCDate

NewUTCDate returns t converted to UTC and truncated to the second, which is the precision the wire format carries.

func (UTCDate) MarshalJSON

func (d UTCDate) MarshalJSON() ([]byte, error)

func (UTCDate) String added in v0.10.0

func (d UTCDate) String() string

String returns the date in the form it takes on the wire. A client that keeps a JMAP date as the text it arrived as — for a response of its own, or for a column — would otherwise have to reproduce the layout, and a second copy of it can diverge from this one unnoticed. It also determines what fmt prints, which the embedded time.Time would otherwise render in a form no JMAP server produces.

func (*UTCDate) UnmarshalJSON

func (d *UTCDate) UnmarshalJSON(b []byte) error

type UnsignedInt

type UnsignedInt uint64

UnsignedInt is the JMAP UnsignedInt data type: an Int that is never negative.

type VacationResponse

type VacationResponse struct {
	// The id of the vacation response, which is always "singleton".
	//
	// The server sets this property; it may not be set by the client.
	ID ID `json:"id,omitzero"`

	// Whether the server is sending the response.
	IsEnabled bool `json:"isEnabled,omitzero"`

	// When to start sending the response, or null to start as soon as it is
	// enabled.
	FromDate *UTCDate `json:"fromDate,omitzero"`

	// When to stop sending the response, or null to keep sending it until it is
	// disabled.
	ToDate *UTCDate `json:"toDate,omitzero"`

	// The Subject header field of the response, or null to let the server choose
	// one.
	Subject *string `json:"subject,omitzero"`

	// The plain-text body of the response.
	TextBody *string `json:"textBody,omitzero"`

	// The HTML body of the response.
	HTMLBody *string `json:"htmlBody,omitzero"`
}

VacationResponse is the automatic reply the server sends on the user's behalf while they are away. An account has exactly one, whose id is always "singleton".

A request using this type must declare urn:ietf:params:jmap:vacationresponse.

type VacationResponseGetArguments

type VacationResponseGetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The ids of the records to fetch, or null to fetch all of them.
	IDs []ID `json:"ids,omitzero"`

	// The properties to include in each returned record, or null for all of
	// them. The id property is always returned.
	Properties []string `json:"properties,omitzero"`
}

VacationResponseGetArguments holds the arguments of the VacationResponse/get method.

A request using this type must declare urn:ietf:params:jmap:vacationresponse.

type VacationResponseGetResponse

type VacationResponseGetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// A string encoding the current state of the type on the server, for use
	// with VacationResponse/changes.
	State string `json:"state"`

	// The records that were found, in an undefined order.
	List []VacationResponse `json:"list"`

	// The ids that were requested but do not exist.
	NotFound []ID `json:"notFound"`
}

VacationResponseGetResponse holds the response to the VacationResponse/get method.

A request using this type must declare urn:ietf:params:jmap:vacationresponse.

type VacationResponseSetArguments

type VacationResponseSetArguments struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId,omitzero"`

	// The state the changes are expected to apply to. The call fails with a
	// stateMismatch error if the server has moved on.
	IfInState *string `json:"ifInState,omitzero"`

	// A map of creation id to the record to create. A creation id may be
	// referenced elsewhere in the same request as "#" followed by the id.
	Create map[ID]VacationResponse `json:"create,omitzero"`

	// A map of record id to the patch to apply to it.
	Update map[ID]PatchObject `json:"update,omitzero"`

	// The ids of the records to destroy.
	Destroy []ID `json:"destroy,omitzero"`
}

VacationResponseSetArguments holds the arguments of the VacationResponse/set method.

A request using this type must declare urn:ietf:params:jmap:vacationresponse.

type VacationResponseSetResponse

type VacationResponseSetResponse struct {
	// The id of the account to operate on.
	AccountID ID `json:"accountId"`

	// The state before these changes were applied, if the server tracks it.
	OldState *string `json:"oldState"`

	// The state after these changes were applied.
	NewState string `json:"newState"`

	// A map of creation id to the properties the server assigned to each created
	// record.
	Created map[ID]*VacationResponse `json:"created"`

	// A map of record id to any properties the server changed beyond those the
	// patch set.
	Updated map[ID]*VacationResponse `json:"updated"`

	// The ids of the records that were destroyed.
	Destroyed []ID `json:"destroyed"`

	// A map of creation id to the reason the record could not be created.
	NotCreated map[ID]SetError `json:"notCreated"`

	// A map of record id to the reason the record could not be updated.
	NotUpdated map[ID]SetError `json:"notUpdated"`

	// A map of record id to the reason the record could not be destroyed.
	NotDestroyed map[ID]SetError `json:"notDestroyed"`
}

VacationResponseSetResponse holds the response to the VacationResponse/set method.

A request using this type must declare urn:ietf:params:jmap:vacationresponse.

type WaitInfo added in v0.12.0

type WaitInfo struct {
	// Reason identifies why the request is delayed.
	Reason WaitReason
	// Kind identifies the purpose of the delayed request.
	Kind RequestKind
	// Delay is the length of the delay where it is known in advance, which is
	// the case for WaitAfterRefusal and not for WaitForSlot.
	Delay time.Duration
}

WaitInfo describes a delay the client is about to apply.

type WaitReason added in v0.12.0

type WaitReason string

WaitReason identifies why a request is delayed.

const (
	// WaitForSlot is a delay until one of the concurrent requests the server
	// allows has finished.
	WaitForSlot WaitReason = "slot"
	// WaitAfterRefusal is a delay before a retry, after a 429 or a 503.
	WaitAfterRefusal WaitReason = "refusal"
)

type WatchOption added in v0.6.0

type WatchOption func(*watchConfig)

WatchOption tunes a watch.

func WithPing added in v0.6.0

func WithPing(d time.Duration) WatchOption

WithPing requests a comment from the server at that interval, so that a connection dropped by an intermediary is detected rather than left hanging. Servers clamp it to a range of their own.

func WithReconnect added in v0.6.0

func WithReconnect(f func(attempt int) time.Duration) WatchOption

WithReconnect sets how long to wait before the nth attempt to reconnect, counting from one. It replaces the doubling delay Watch uses otherwise, and is where to add jitter for a group of clients that would otherwise reconnect at the same time.

type WebPushVAPIDCapability added in v0.2.0

type WebPushVAPIDCapability struct {
	// ApplicationServerKey is the ECDSA public key the push service will use
	// to check that a notification really came from this server, in
	// uncompressed form and base64url-encoded. A client passes it to the push
	// service when it subscribes there.
	ApplicationServerKey string `json:"applicationServerKey"`
}

WebPushVAPIDCapability holds what a server says about VAPID, as defined by RFC 9749.

Directories

Path Synopsis
cmd
jmapc command
Command jmapc generates a typed client from the JMAP queries in a directory, in Go, Rust or TypeScript.
Command jmapc generates a typed client from the JMAP queries in a directory, in Go, Rust or TypeScript.
Package example holds a worked example: a few JMAP queries and the client jmapc generates from them.
Package example holds a worked example: a few JMAP queries and the client jmapc generates from them.
internal
cmd/gentypes command
Command gentypes writes the Go declarations for the JMAP data types into the jmapc runtime package.
Command gentypes writes the Go declarations for the JMAP data types into the jmapc runtime package.
gen
Package gen turns the JMAP data model, and the queries written against it, into Go source.
Package gen turns the JMAP data model, and the queries written against it, into Go source.
gen/rust
Package rust writes Rust from the JMAP data model and the queries checked against it.
Package rust writes Rust from the JMAP data model and the queries checked against it.
gen/shared
Package shared holds the parts of query generation that do not depend on the language being generated: how a comment is wrapped, the prose the generated documentation is written in, which properties a record type holds, and how a name is kept unique.
Package shared holds the parts of query generation that do not depend on the language being generated: how a comment is wrapped, the prose the generated documentation is written in, which properties a record type holds, and how a name is kept unique.
gen/ts
Package ts writes TypeScript from the JMAP data model and the queries checked against it.
Package ts writes TypeScript from the JMAP data model and the queries checked against it.
jsonschema
Package jsonschema describes the query files themselves.
Package jsonschema describes the query files themselves.
limits
Package limits checks a query against what a server says it will accept.
Package limits checks a query against what a server says it will accept.
query
Package query parses the JMAP queries a user writes and checks them against the JMAP data model, so that a mistake in a query is reported where it was written rather than by the server at run time.
Package query parses the JMAP queries a user writes and checks them against the JMAP data model, so that a mistake in a query is reported where it was written rather than by the server at run time.
request
Package request turns a checked query into the JMAP request it stands for, with the parameters filled in.
Package request turns a checked query into the JMAP request it stands for, with the parameters filled in.
spec
Package spec holds the JMAP data model that jmapc generates code against: the object types, their properties, and the methods that operate on them.
Package spec holds the JMAP data model that jmapc generates code against: the object types, their properties, and the methods that operate on them.
Package jmaptest is a JMAP server for a test to run a generated client against.
Package jmaptest is a JMAP server for a test to run a generated client against.

Jump to

Keyboard shortcuts

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