Updating objects
The update command changes an existing configuration object, or a singleton, the single instance of an object type such as the system settings. It is the everyday command for adjusting a setting from the shell or a script, without re-creating the object.
An update is sent as a JMAP patch. A patch lists only the fields to change, and every field it does not mention keeps its current value, so an update never has to repeat the whole object. The patch has the shape of the update argument of a JMAP Foo/set call.
Synopsis
Section titled “Synopsis”stalwart-cli update <object> [<id>] ( --field key=value... | --json '<json>' | --file <path> | --stdin )The <object> argument is the object type name, with or without the x: prefix. The slash form is rejected, because selecting a variant is a create feature.
The <id> argument is required for a regular object. For a singleton it is optional: it defaults to singleton, and any other id is rejected. The four input forms are mutually exclusive, so exactly one of them supplies the patch.
Field paths and JSON pointers
Section titled “Field paths and JSON pointers”A --field key decides how much of a property the update replaces, and it takes one of two forms:
- Top-level property name:
--field name=fooreplaces the entire property. - JSON pointer path:
--field 'aliases/2/name=foo'patches a sub-element. A JSON pointer is a/-separated path that addresses one element inside a JSON document, here thenameof the alias at index2. The first segment is matched against the schema case-insensitively and rewritten to its canonical case. Deeper segments, such as map keys, list indices and nested object properties, are passed through verbatim.
A path changes one element without sending the whole field, which matters for collections: replacing a whole set to add one entry would require knowing, and repeating, every existing entry. The following command adds one entry to a set:
stalwart-cli update domain b --field 'aliases/extra.example.com=true'Setting the same path to null removes the entry from a set or map:
stalwart-cli update domain b --field 'aliases/extra.example.com=null'The paths follow the patch model that JMAP itself uses. In that model, every kind of collection is encoded as a JSON object, so each element can be addressed by a key:
- A set is encoded as a map of
value -> true. Setting a value totrueadds it, and setting it tonullremoves it. - An object list is encoded as a map from stringified positional indices to objects. A new index adds an object, and setting an index to
nullremoves it. - A map is a plain JSON object. Setting a key’s value updates it, and setting it to
nulldeletes it.
Quoted keys
Section titled “Quoted keys”The parser splits each --field argument on its first =. In a path that contains a literal =, for example in a map key, that split would land inside the path. Quoting the entire key avoids this: everything between the matching quote characters becomes the key, and the first = after the closing quote separates the key from the value:
stalwart-cli update systemsettings --field '"proxyTrustedNetworks/127.0.0.1"=true'A / inside a key segment raises a different problem, because / separates the segments of the path. A segment that contains one, such as a network in CIDR notation, is written with the escapes of RFC 6901, the JSON pointer specification: ~1 for / and ~0 for ~. The CLI passes the path unchanged, and the server decodes the escapes. The following command adds 10.0.0.0/8 to the trusted proxy networks:
stalwart-cli update systemsettings --field 'proxyTrustedNetworks/10.0.0.0~18=true'Updating singletons
Section titled “Updating singletons”Because a singleton has only one instance, it needs no real id. It is addressed by the literal id singleton, which is also used when the id is omitted, so the following commands are equivalent:
stalwart-cli update systemsettings --field defaultHostname=mail.example.comstalwart-cli update systemsettings singleton --field defaultHostname=mail.example.comAny other id is refused for a singleton.
Input sources
Section titled “Input sources”The input sources are the same as for create, and each suits a different situation:
| Source | When to use |
|---|---|
--field key=value | Quick targeted edits from the shell |
--json '<json>' | A small structured patch composed inline |
--file <path> | A patch generated by another tool or template |
--stdin | A patch piped from another command |
With the JSON forms, the document is the patch object sent to JMAP, not the full object. Its keys are therefore property names or JSON pointer paths, exactly as with --field, and a sub-key is set with a key that contains /:
stalwart-cli update domain b --json '{"description": "Renamed", "aliases/extra.example.com": true}'Repeating the same key with --field is an error. So is supplying more than one input source.
Examples
Section titled “Examples”The following commands cover the common kinds of change. A scalar field, such as a description, is changed by setting it:
stalwart-cli update domain b --field description='Primary domain'A flag of a singleton is changed without an id:
stalwart-cli update imap --field allowPlainTextAuth=falseA structured field is replaced by passing its full JSON value:
stalwart-cli update domain b \ --field 'certificateManagement={"@type":"Automatic","acmeProviderId":"a"}'An object list is addressed by index, so a new alias is added at the next available index:
stalwart-cli update Account c --field 'aliases/3={"name":"hello","domainId":"b"}'An id is added to a set of ids by setting it to true:
stalwart-cli update Account c --field 'memberGroupIds/g1=true'Setting the same id to null removes it again:
stalwart-cli update Account c --field 'memberGroupIds/g1=null'A patch generated by another tool is read from standard input:
generate-domain-patch.sh | stalwart-cli update domain b --stdinVariant changes
Section titled “Variant changes”A multi-variant field holds one of several shapes, called variants, and its @type names the one in use. certificateManagement on a domain is an example, with a Manual and an Automatic variant. Changing the variant requires replacing the entire sub-object in one patch, because JMAP cannot mix @type/... JSON pointer keys with changes to sibling properties when the type itself changes. The new variant’s full body is therefore sent at once:
stalwart-cli update domain b \ --field 'certificateManagement={"@type":"Automatic","acmeProviderId":"a"}'The CLI does not validate variant changes, so errors surface only when the server checks the patch. A complex variant transition is therefore easier to get right in a JSON file built by a configuration tool.
Output
Section titled “Output”On success, the CLI prints a confirmation line:
Updated Domain bSome fields are set by the server rather than by the caller, and the server may return them after an update, mostly when it recomputes them. The CLI prints such fields below the confirmation as key: <value> lines.
See also
Section titled “See also”- Fetching a single object to verify changes.
- Creating objects for the corresponding create flow.
- Declarative bulk operations for atomic multi-object updates with cross-references.