idnits 2.17.1 draft-ietf-jmap-core-04.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- ** The document seems to lack an IANA Considerations section. (See Section 2.2 of https://www.ietf.org/id-info/checklist for how to handle the case when there are no actions for IANA.) ** There are 2 instances of too long lines in the document, the longest one being 34 characters in excess of 72. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (March 5, 2018) is 2237 days in the past. Is this intentional? -- Found something which looks like a code comment -- if you have code sections in the document, please surround them with '' and '' lines. Checking references for intended status: Proposed Standard ---------------------------------------------------------------------------- (See RFCs 3967 and 4897 for information about using normative references to lower-maturity documents in RFCs) -- Looks like a reference, but probably isn't: '1' on line 2190 == Unused Reference: 'RFC2047' is defined on line 2090, but no explicit reference was found in the text == Unused Reference: 'RFC2231' is defined on line 2100, but no explicit reference was found in the text ** Obsolete normative reference: RFC 5246 (Obsoleted by RFC 8446) ** Obsolete normative reference: RFC 5785 (Obsoleted by RFC 8615) ** Obsolete normative reference: RFC 7159 (Obsoleted by RFC 8259) ** Obsolete normative reference: RFC 7230 (Obsoleted by RFC 9110, RFC 9112) ** Obsolete normative reference: RFC 7235 (Obsoleted by RFC 9110) Summary: 7 errors (**), 0 flaws (~~), 3 warnings (==), 3 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 JMAP N. Jenkins 3 Internet-Draft FastMail 4 Intended status: Standards Track March 5, 2018 5 Expires: September 6, 2018 7 JSON Meta Application Protocol 8 draft-ietf-jmap-core-04 10 Abstract 12 This document specifies a protocol for synchronising JSON-based data 13 objects efficiently, with support for push and out-of-band binary 14 data upload/download. 16 Status of This Memo 18 This Internet-Draft is submitted in full conformance with the 19 provisions of BCP 78 and BCP 79. 21 Internet-Drafts are working documents of the Internet Engineering 22 Task Force (IETF). Note that other groups may also distribute 23 working documents as Internet-Drafts. The list of current Internet- 24 Drafts is at https://datatracker.ietf.org/drafts/current/. 26 Internet-Drafts are draft documents valid for a maximum of six months 27 and may be updated, replaced, or obsoleted by other documents at any 28 time. It is inappropriate to use Internet-Drafts as reference 29 material or to cite them other than as "work in progress." 31 This Internet-Draft will expire on September 6, 2018. 33 Copyright Notice 35 Copyright (c) 2018 IETF Trust and the persons identified as the 36 document authors. All rights reserved. 38 This document is subject to BCP 78 and the IETF Trust's Legal 39 Provisions Relating to IETF Documents 40 (https://trustee.ietf.org/license-info) in effect on the date of 41 publication of this document. Please review these documents 42 carefully, as they describe your rights and restrictions with respect 43 to this document. Code Components extracted from this document must 44 include Simplified BSD License text as described in Section 4.e of 45 the Trust Legal Provisions and are provided without warranty as 46 described in the Simplified BSD License. 48 Table of Contents 50 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 51 1.1. Notational conventions . . . . . . . . . . . . . . . . . 3 52 1.2. The Number datatype . . . . . . . . . . . . . . . . . . . 4 53 1.3. The Date datatypes . . . . . . . . . . . . . . . . . . . 4 54 1.4. JSON as the data encoding format . . . . . . . . . . . . 4 55 1.5. Terminology . . . . . . . . . . . . . . . . . . . . . . . 5 56 1.5.1. User . . . . . . . . . . . . . . . . . . . . . . . . 5 57 1.5.2. Accounts . . . . . . . . . . . . . . . . . . . . . . 5 58 1.5.3. Data types and records . . . . . . . . . . . . . . . 5 59 1.6. Ids . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 60 1.7. The JMAP API model . . . . . . . . . . . . . . . . . . . 6 61 2. The JMAP Session resource . . . . . . . . . . . . . . . . . . 6 62 2.1. Service Autodiscovery . . . . . . . . . . . . . . . . . . 9 63 3. Structured data exchange . . . . . . . . . . . . . . . . . . 9 64 3.1. Making an API request . . . . . . . . . . . . . . . . . . 10 65 3.2. The Request object . . . . . . . . . . . . . . . . . . . 10 66 3.2.1. Example request . . . . . . . . . . . . . . . . . . . 10 67 3.3. Vendor-specific extensions . . . . . . . . . . . . . . . 11 68 3.4. The Response object . . . . . . . . . . . . . . . . . . . 11 69 3.4.1. Example response: . . . . . . . . . . . . . . . . . . 11 70 3.5. Omitting arguments . . . . . . . . . . . . . . . . . . . 12 71 3.6. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 12 72 3.6.1. Request-level errors . . . . . . . . . . . . . . . . 12 73 3.6.2. Method-level errors . . . . . . . . . . . . . . . . . 12 74 3.7. References to previous method results . . . . . . . . . . 14 75 3.8. Security . . . . . . . . . . . . . . . . . . . . . . . . 18 76 3.9. Concurrency . . . . . . . . . . . . . . . . . . . . . . . 18 77 4. Standard methods and naming convention . . . . . . . . . . . 18 78 4.1. /get . . . . . . . . . . . . . . . . . . . . . . . . . . 19 79 4.2. /changes . . . . . . . . . . . . . . . . . . . . . . . . 20 80 4.3. /set . . . . . . . . . . . . . . . . . . . . . . . . . . 21 81 4.4. /query . . . . . . . . . . . . . . . . . . . . . . . . . 26 82 4.5. /queryChanges . . . . . . . . . . . . . . . . . . . . . . 30 83 4.6. Examples . . . . . . . . . . . . . . . . . . . . . . . . 33 84 5. Binary data . . . . . . . . . . . . . . . . . . . . . . . . . 36 85 5.1. Uploading binary data . . . . . . . . . . . . . . . . . . 37 86 5.2. Downloading binary data . . . . . . . . . . . . . . . . . 38 87 5.3. Blob/copy . . . . . . . . . . . . . . . . . . . . . . . . 39 88 6. Push . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 89 6.1. The StateChange object . . . . . . . . . . . . . . . . . 40 90 6.2. PushSubscription . . . . . . . . . . . . . . . . . . . . 41 91 6.2.1. PushSubscription/set . . . . . . . . . . . . . . . . 42 92 6.2.2. PushSubscription/get . . . . . . . . . . . . . . . . 42 93 6.3. Event Source . . . . . . . . . . . . . . . . . . . . . . 42 94 7. Security considerations . . . . . . . . . . . . . . . . . . . 44 95 7.1. Transport confidentiality . . . . . . . . . . . . . . . . 44 96 7.2. Authentication scheme . . . . . . . . . . . . . . . . . . 44 97 7.3. Service autodiscovery . . . . . . . . . . . . . . . . . . 44 98 7.4. JSON parsing . . . . . . . . . . . . . . . . . . . . . . 44 99 7.5. Denial of service . . . . . . . . . . . . . . . . . . . . 45 100 7.6. Push encryption . . . . . . . . . . . . . . . . . . . . . 45 101 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 45 102 8.1. Normative References . . . . . . . . . . . . . . . . . . 45 103 8.2. URIs . . . . . . . . . . . . . . . . . . . . . . . . . . 47 104 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 47 106 1. Introduction 108 JMAP is a generic protocol for synchronising data, such as mail, 109 calendars or contacts, between a client and a server. It is 110 optimised for mobile and web environments, and aims to provide a 111 consistent interface to different data types. 113 This specification is for the generic mechanism of data 114 synchronisation. Further specifications define the data models for 115 different data types that may be synchronised via JMAP. 117 JMAP is designed to make efficient use of limited network resources. 118 Multiple API calls may be batched in a single request to the server, 119 reducing round trips and improving battery life on mobile devices. 120 Push connections remove the need for polling, and an efficient delta 121 update mechanism ensures a minimum of data is transferred. 123 JMAP is designed to be horizontally scalable to a very large number 124 of users. This is facilitated by the separate end points for users 125 after login, the separation of binary and structured data, and a 126 shared data model that does not allow data dependencies between 127 accounts. 129 1.1. Notational conventions 131 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 132 "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 133 document are to be interpreted as described in [RFC2119]. 135 The underlying format used for this specification is JSON. 136 Consequently, the terms "object" and "array" as well as the four 137 primitive types (strings, numbers, booleans, and null) are to be 138 interpreted as described in Section 1 of [RFC7159]. Unless otherwise 139 noted, all the property names and values are case sensitive. 141 Some examples in this document contain "partial" JSON documents used 142 for illustrative purposes. In these examples, three periods "..." 143 are used to indicate a portion of the document that has been removed 144 for compactness. 146 Types signatures are given for all JSON objects in this document. 147 The following conventions are used: 149 o "Boolean|String" - The value is either a JSON "Boolean" value, or 150 a JSON "String" value. 152 o "Foo" - Any name that is not a native JSON type means an object 153 for which the properties (and their types) are defined elsewhere 154 within this document. 156 o "Foo[]" - An array of objects of type "Foo". 158 o "String[Foo]" - A JSON "Object" being used as a map (associative 159 array), where all the values are of type "Foo". 161 1.2. The Number datatype 163 The JSON datatypes are limited to those found in JavaScript. A 164 "Number" in JavaScript is represented as a signed double (64-bit 165 floating point). However, except where explicitly specified, all 166 numbers used in this API are unsigned integers <= 2^53 (the maximum 167 integer that may be reliably stored in a double). 169 1.3. The Date datatypes 171 Where "Date" is given as a type, it means a string in [RFC3339] 172 _date-time_ format. To ensure a normalised form, the _time-secfrac_ 173 MUST always be omitted and any letters in the string (e.g. "T" and 174 "Z") MUST be upper-case. For example, ""2014-10-30T14:12:00+08:00"". 176 Where "UTCDate" is given as a type, it means a "Date" where the 177 _time-offset_ component MUST be "Z" (i.e. it must be in UTC time). 178 For example, ""2014-10-30T06:12:00Z"". 180 1.4. JSON as the data encoding format 182 JSON is a text-based data interchange format as specified in 183 [RFC7159]. The I-JSON format defined in [RFC7493] is a strict subset 184 of this, adding restrictions to avoid potentially confusing scenarios 185 (for example, it mandates that an object MUST NOT have two properties 186 with the same key). 188 All data sent from the client to the server or from the server to the 189 client (except binary file upload/download) MUST be valid I-JSON 190 according to the RFC, and is therefore case-sensitive and encoded in 191 UTF-8 ([RFC3629]). 193 1.5. Terminology 195 1.5.1. User 197 A user represents a set of permissions relating to what data can be 198 seen. 200 1.5.2. Accounts 202 An account is a collection of data. A single account may contain an 203 arbitrary set of data types, for example a collection of mail, 204 contacts and calendars. Most operations in JMAP are isolated to a 205 single account; there are a few explicit operations to copy data 206 between them. Certain properties are guaranteed for data within the 207 same account, for example uniqueness of ids within a type in that 208 account. 210 An account is not the same as a user, although it is common for the 211 primary account to directly belong to the user. For example, you may 212 have an account that contains data for a group or business, to which 213 multiple users have access. Users may also have access to accounts 214 belonging to another user if that user is sharing some of their data. 215 A single set of credentials may provide access to data in multiple 216 accounts. 218 1.5.3. Data types and records 220 JMAP provides a uniform interface for creating, retrieving, updating 221 and deleting various types of objects. A *data type* is a collection 222 of named, typed properties, just like the schema for a database 223 table. Each instance of a data type is called a *record*. 225 1.6. Ids 227 All record ids are assigned by the server, and are immutable. They 228 MUST be unique among all records of the *same type* within the *same 229 account*. Ids may clash across accounts, or for two records of 230 different types within the same account. 232 Ids are always "String"s. An id MUST be a valid UTF-8 string of at 233 least 1 character in length and maximum 256 octets in size, but MUST 234 NOT start with the "#" character, as this is reserved for doing back 235 references during object creation (see the _/set_ description). 237 1.7. The JMAP API model 239 JMAP uses HTTP [RFC7230] to expose API, Push, Upload and Download 240 resources. Implementations MUST support HTTP/1.1, and MAY support 241 later versions. Support for common HTTP mechanisms such as 242 redirection and caching are assumed. 244 All HTTP requests MUST be authenticated. Servers MUST conform with 245 the [RFC7235] HTTP Authentication framework to reject requests that 246 fail authentication and inform the client of available authentication 247 schemes. 249 Clients SHOULD understand and be able to handle standard HTTP status 250 codes appropriately. 252 An authenticated client can fetch the JMAP Session object with 253 details about the data and capabilities the server can provide as 254 shown in section 2. The client may then exchange data with the 255 server in the following ways: 257 1. The client may make an API request to the server to get or set 258 structured data. This request consists of an ordered series of 259 method calls. These are processed by the server, which then 260 returns an ordered series of responses. This is described in 261 sections 3 and 4. 263 2. The client may download or upload binary files from/to the 264 server. This is detailed in section 5. 266 3. The client may connect to a push channel on the server, to be 267 notified when data has changed. This is explained in section 6. 269 2. The JMAP Session resource 271 To communicate with a JMAP server you need two things to start: 273 1. The URL for the JMAP Session resource. This may be requested 274 directly from the user, or discovered automatically based on a 275 username domain (see Service Autodiscovery section below). 277 2. Credentials to authenticate with. How to obtain credentials is 278 out of scope for this specification. 280 An authenticated GET request to the JMAP Session resource MUST return 281 the details about the data and capabilities the server can provide to 282 the client given those credentials. 284 The response to a successful request is a JSON-encoded *JMAP Session* 285 object. It has the following properties: 287 o *username*: "String" The username associated with the given 288 credentials. 290 o *accounts*: "String[Account]" A map of *account id* to Account 291 object for each account the user has access to. A single set of 292 credentials may provide access to multiple accounts, for example 293 if another user is sharing their mail with the logged in user, or 294 if there is an account that contains data for a group or business. 295 All data belongs to a single account. With the exception of a few 296 explicit operations to copy data between accounts, all JMAP 297 methods take an _accountId_ argument that specifies on which 298 account the operations are to take place. This argument is always 299 optional; if not specified, the primary account is used. All ids 300 (other than account ids of course) are only unique within their 301 account. In the event of a severe internal error, a server may 302 have to reallocate ids or do something else that violates standard 303 JMAP data constraints. In this situation, the data on the server 304 is no longer compatible with cached data the client may have from 305 before. The server MUST treat this as though the account has been 306 deleted and then recreated with a new account id. Clients will 307 then be forced to throw away any data with the old account id and 308 refetch all data from scratch. An *Account* object has the 309 following properties: 311 * *name*: "String" A user-friendly string to show when presenting 312 content from this account, e.g. the email address representing 313 the owner of the account. 315 * *isPrimary*: "Boolean" This MUST be true for *at most* one of 316 the accounts returned. This is to be considered the user's 317 main or default account by the client. If no account being 318 returned belongs to the user, or in any other way there is no 319 appropriate way to determine a default account, then this MAY 320 be "false" for all accounts. 322 * *isReadOnly*: "Boolean" This is "true" if the entire account is 323 read-only. 325 * *hasDataFor*: "String[]" A list of the data profiles available 326 in this account. Each future JMAP data types specification 327 will define a profile name to encompass that set of types. 329 o *capabilities*: "String[Object]" An object specifying the 330 capabilities of this server. Each key is a URI for a 331 specification supported by the server. The value for each of 332 these keys is an object with further information about the 333 server's capabilities in relation to that specification. The 334 client MUST ignore any properties it does not understand. The 335 capabilities object MUST include a property called "ietf:jmap". 336 The value of this property is an object which MUST contain the 337 following information on server capabilities: 339 * *maxSizeUpload*: "Number" The maximum file size, in octets, 340 that the server will accept for a single file upload (for any 341 purpose). 343 * *maxConcurrentUpload*: "Number" The maximum number of 344 concurrent requests the server will accept to the upload 345 endpoint. 347 * *maxSizeRequest*: "Number" The maximum size, in octets, that 348 the server will accept for a single request to the API 349 endpoint. 351 * *maxConcurrentRequests*: "Number" The maximum number of 352 concurrent requests the server will accept to the API endpoint. 354 * *maxCallsInRequest*: "Number" The maximum number of method 355 calls the server will accept in a single request to the API 356 endpoint. This MUST be greater than or equal to "32" to ensure 357 clients can rely on the ability to make efficient network use. 359 * *maxObjectsInGet*: "Number" The maximum number of objects that 360 the client may request in a single "/get" type method call. 362 * *maxObjectsInSet*: "Number" The maximum number of objects the 363 client may send to create, update or destroy in a single "/set" 364 type method call. 366 * *collationAlgorithms*: "String[]" A list of identifiers for 367 algorithms registered in the collation registry defined in 368 [RFC4790] that the server supports for sorting when querying 369 records. 371 Future specifications will define their own properties on the 372 capabilities object. Servers MAY advertise vendor-specific JMAP 373 extensions. To avoid conflict, the identifiers for these MUST be 374 a URI beginning with a domain owned by the vendor. Clients MUST 375 opt in to any specifications it wishes to use (see "Making an API 376 request"). 378 o *apiUrl*: "String" The URL to use for JMAP API requests. 380 o *downloadUrl*: "String" The URL endpoint to use when downloading 381 files (see the Download section of this spec), in [RFC6570] URI 382 Template (level 1) format. The URL MUST contain variables called 383 "blobId", MAY contain a variables called "accountId" and SHOULD 384 contain a variable called "name". 386 o *uploadUrl*: "String" The URL endpoint to use when uploading files 387 (see the Upload section of this spec), in [RFC6570] URI Template 388 (level 1) format. The URL MAY contain a variable called 389 "accountId". 391 o *eventSourceUrl*: "String" The URL to connect to for push events 392 (see the Push section of this spec). 394 To ensure future compatibility, other properties MAY be included on 395 the JMAP Session object. Clients MUST ignore any properties they are 396 not expecting. 398 2.1. Service Autodiscovery 400 There are two standardised autodiscovery methods in use for internet 401 protocols: 403 o *DNS srv* ([RFC6186] and [RFC6764]) 405 o *.well-known/servicename* ([RFC5785]) 407 A JMAP-supporting host for the domain "example.com" SHOULD publish a 408 SRV record "_jmaps._tcp.example.com" which gives a _hostname_ and 409 _port_ (usually port "443"). The JMAP Session resource is then 410 "https://${hostname}[:${port}]/.well-known/jmap" (following any 411 redirects). 413 If the client has a username in the form of an email address, it MAY 414 use the domain portion of this to attempt autodiscovery of the JMAP 415 server. 417 3. Structured data exchange 419 The client may make an API request to the server to get or set 420 structured data. This request consists of an ordered series of 421 method calls. These are processed by the server, which then returns 422 an ordered series of responses. 424 3.1. Making an API request 426 To make an API request, the client makes an authenticated POST 427 request to the API resource, the location of which may be found on 428 the JMAP Session object. 430 The request MUST consist of a single JSON *Request* object. If 431 successful, the response MUST also be of type "application/json" and 432 consist of a single *Response* object. 434 3.2. The Request object 436 A *Request* object has the following properties: 438 o *using*: "String[]" The set of capabilities the client wishes to 439 use. The client MAY include capability identifiers even if the 440 method calls it makes do not utilise those capabilities. The 441 server advertises the set of specifications it supports in the 442 JMAP Session object, as keys on the _capabilities_ property. 444 o *methodCalls*: "Array[]" An array of method calls to process on 445 the server. The method calls MUST be processed sequentially, in 446 order. A *method call* is represented by an array containing 447 three elements: 449 1. A "String" *name* of the method to call. 451 2. An "Object" containing _named_ *arguments* for that method. 453 3. A *client id*: an arbitrary "String" to be echoed back with 454 the responses emitted by that method call (a method may return 455 1 or more responses, as it may make implicit calls to other 456 methods; all responses initiated by this method call get the 457 same client id in the response). 459 Future specifications MAY add further properties to the Request 460 object to extend the semantics. To ensure forwards compatability, a 461 server MUST ignore any other properties it does not understand on the 462 JMAP request object. 464 3.2.1. Example request 465 { 466 "using": [ "ietf.org/rfc/jmap-core", "ietf.org/rfc/jmap-mail" ], 467 "methodCalls": [ 468 ["method1", {"arg1": "arg1data", "arg2": "arg2data"}, "#1"], 469 ["method2", {"arg1": "arg1data"}, "#2"], 470 ["method3", {}, "#3"] 471 ] 472 } 474 3.3. Vendor-specific extensions 476 Individual services will have custom features they wish to expose 477 over JMAP. This may take the form of extra datatypes and/or methods 478 not in the spec, or extra arguments to JMAP methods, or extra 479 properties on existing data types (which may also appear in arguments 480 to methods that take property names). 482 The server can advertise custom extensions it supports by including 483 the identifiers in the capabilities object. Identifiers for vendor 484 extensions MUST be a URL belonging to a domain owned by the vendor, 485 to avoid conflict. The URL SHOULD resolve to documentation for the 486 changes the extension makes. 488 To ensure compatibility with clients that don't know about a specific 489 custom extension, and for compatibility with future versions of JMAP, 490 to use an extension the client MUST opt in by passing the appropriate 491 capability identifier in the _using_ array of the Request object. 492 The server MUST only follow the specifications that are opted-into 493 and behave as though it does not implement anything else when 494 processing a request. 496 3.4. The Response object 498 A *Response* object has the following properties: 500 o *methodResponses*: "Array[]" An array of responses, in the same 501 format as the _methodCalls_ on the request object. The output of 502 the methods MUST be added to the _methodResponses_ array in the 503 same order as the methods are processed. 505 Unless otherwise specified, if the method call completed successfully 506 its response name is the same as the method name in the request. 508 3.4.1. Example response: 510 { 511 "methodResponses": [ 512 ["method1", {"arg1": 3, "arg2": "foo"}, "#1"], 513 ["method2", {"isBlah": true}, "#2"], 514 ["anotherResponseFromMethod2", { 515 "data": 10, 516 "yetmoredata": "Hello" 517 }, "#2"], 518 ["error", {"type":"unknownMethod"}, "#3"] 519 ] 520 } 522 3.5. Omitting arguments 524 An argument to a method may be specified to have a default value. If 525 omitted by the client, the server MUST treat the method call the same 526 as if the default value had been specified. Similarly, the server 527 MAY omit any argument in a response which has the default value. 529 Unless otherwise specified in a method description, "null" is the 530 default value for any argument in a request or response where this is 531 allowed by the type signature. Other arguments may only be omitted 532 if an explicit default value is defined in the method description. 534 3.6. Errors 536 3.6.1. Request-level errors 538 If the data sent as an API request is not valid JSON or does not 539 match the structure above, or includes a capability that the server 540 does not support in the "using" property of the request, a "400 Bad 541 Request" error will be returned at the HTTP level. The body of the 542 response SHOULD include a short description of the problem to help 543 client developers debug the issue. 545 3.6.2. Method-level errors 547 If a method encounters an error, the appropriate "error" response 548 MUST be inserted at the current point in the _methodResponses_ array 549 and, unless otherwise specified, further processing MUST NOT happen 550 within that method call. 552 Any further method calls in the request MUST then be processed as 553 normal. 555 An "error" response looks like this: 557 ["error", { 558 type: "unknownMethod" 559 }, "client-id"] 561 The response name is "error", and it MUST have a type property. 562 Other properties may be present with further information; these are 563 detailed in the error type descriptions where appropriate. 565 With the exception of "serverError", the externally-visible state of 566 the server MUST NOT have changed if an error is returned at the 567 method level. 569 The following error types are defined which may be returned for any 570 method call where appropriate: 572 "serverError": An unexpected or unknown error occured during the 573 processing of the call. The state of the server after such an error 574 is undefined. 576 "unknownMethod": The server does not recognise this method name. 578 "invalidArguments": One of the arguments is of the wrong type or 579 otherwise invalid, or a required argument is missing. A 580 "description" property MAY be present to help debug with an 581 explanation of what the problem was. This is a non-localised string, 582 and is not intended to be shown directly to end users. 584 "forbidden": The method and arguments are valid, but executing the 585 method would violate an ACL or other permissions policy. 587 "timedOut": The method failed to execute because it timed out waiting 588 for a lock, or was taking too much compute time. 590 "accountNotFound": An _accountId_ was included with the method call 591 that does not correspond to a valid account. 593 "accountNotSupportedByMethod": An _accountId_ given corresponds to a 594 valid account, but the account does not support this data type. 596 "accountReadOnly": This method call would modify state in an account 597 that has "isReadOnly == true". 599 Further possible errors for a particular method are specified in the 600 method descriptions. 602 Further general errors MAY be defined in future RFCs. Should a 603 client receive an error type it does not understand, it MUST treat it 604 the same as the "serverError" type. 606 3.7. References to previous method results 608 To allow clients to make more efficient use of the network and avoid 609 round trips, an argument to one method can be taken from the result 610 of a previous method call. 612 To do this, the client prefixes the argument name with "#". The 613 value is a _ResultReference_ object as described below. When 614 processing a method call, the server MUST first check the arguments 615 object for any names beginning with "#". If found, the back 616 reference should be resolved and the value used as the "real" 617 argument. The method is then processed as normal. If any back 618 reference fails to resolve, the whole method MUST be rejected with a 619 "resultReference" error. If an argument object contains the same 620 argument name in normal and referenced form (e.g. "foo" and "#foo"), 621 the method MUST return an "invalidArguments" error. 623 A *ResultReference* object has the following properties: 625 o *resultOf*: "String" The client id of the method call to get the 626 result from (the string given as the third item in the array for a 627 method call). 629 o *name*: "String" The expected name of the response. 631 o *path*: "String" A pointer into the arguments. This is an RFC6901 632 JSON Pointer, except it also allows the use of "*" to map through 633 an array (see description below). 635 To resolve: 637 1. Find the first response with a client id identical to the 638 _resultOf_ property of the _ResultReference_ in the 639 _methodResponses_ array from previously processed method calls in 640 the same request. If none, evaluation fails. 642 2. If the response name is not identical to the _name_ property of 643 the _ResultReference_, evaluation fails. 645 3. Apply the _path_ to the arguments object of the response (the 646 second item in the response array) following the [RFC6901] JSON 647 pointer algorithm, except with the following addition in 648 Section 4 (Evaluation): 650 If the currently referenced value is a JSON array, the reference 651 token may be exactly the single character "*", making the new 652 referenced value the result of applying the rest of the JSON pointer 653 tokens to every item in the array and returning the results in the 654 same order in a new array. If the result of applying the rest of the 655 pointer tokens to a value was itself an array, its items should be 656 included individually in the output rather than including the array 657 itself (i.e. the result is flattened from an array of arrays to a 658 single array). 660 As a simple example, suppose we have the following API request 661 _methodCalls_: 663 [[ "Foo/changes", { 664 "sinceState": "abcdef" 665 }, "t0" ], 666 [ "Foo/get", { 667 "#ids": { 668 "resultOf": "t0", 669 "name": "Foo/changes", 670 "path": "/changed" 671 } 672 }, "t1" ]] 674 After executing the first method call the _methodResponses_ array is: 676 [[ "Foo/changes", { 677 "accountId": "1", 678 "oldState": "abcdef", 679 "newState": "123456", 680 "hasMoreChanges": false, 681 "changed": [ "f1", "f4" ], 682 "destroyed": [] 683 }, "t0" ]] 685 So to execute the Foo/get call, we look through the arguments and 686 find there is one with a "#" prefix. To resolve this, we apply the 687 algorithm above: 689 1. Find the first response with client id "t0". The Foo/changes 690 response fulfils this criterion. 692 2. Check the response name is the same as in the result reference. 693 It is, so this is fine. 695 3. Apply the _path_ as a JSON pointer to the arguments object. This 696 simply selects the "changed" property, so the result of 697 evaluating is: "[ "f1", "f4" ]" 699 The JMAP server now continues to process the Foo/get call as though 700 the arguments were: 702 { 703 "ids": [ "f1", "f4" ] 704 } 706 Now a more complicated example using the JMAP Mail data model: fetch 707 the "from"/"date"/"subject" for every email in the first 10 threads 708 in the Inbox (sorted newest first): 710 [[ "Email/query", { 711 "filter": { inMailbox: "id_of_inbox" }, 712 "sort": [{ property: "receivedAt", isAscending: false }], 713 "collapseThreads": true, 714 "position": 0, 715 "limit": 10 716 }, "t0" ], 717 [ "Email/get", { 718 "#ids": { 719 "resultOf": "t0", 720 "name": "Email/query", 721 "path": "/ids" 722 }, 723 "properties": [ "threadId" ] 724 }, "t1" ], 725 [ "Thread/get", { 726 "#ids": { 727 "resultOf": "t1", 728 "name": "Email/get", 729 "path": "/list/*/threadId" 730 } 731 }, "t2" ], 732 [ "Email/get", { 733 "#ids": { 734 "resultOf": "t2", 735 "name": "Thread/get", 736 "path": "/list/*/emailIds" 737 }, 738 "properties": [ "from", "receivedAt", "subject" ] 739 }, "t3" ]] 741 After executing the first 3 method calls the _methodResponses_ array 742 might be: 744 [[ "Email/query", { 745 "accountId": "1", 746 "filter": { inMailbox: "id_of_inbox" }, 747 "sort": [{ property: "receivedAt", isAscending: false }], 748 "collapseThreads": true, 749 "state": "abcdefg", 750 "canCalculateChanges": true, 751 "position": 0, 752 "total": 101, 753 "ids": [ "msg1023", "msg223", "msg110", "msg93", "msg91", "msg38", "msg36", "msg33", "msg11", "msg1" ] 754 }, "t0" ], 755 [ "Email/get", { 756 "accountId": "1", 757 "state": "123456", 758 "list": [{ 759 "id": "msg1023", 760 "threadId": "trd194", 761 }, { 762 "id": "msg223", 763 "threadId": "trd114" 764 }, 765 ... 766 ], 767 "notFound": null 768 }, "t1" ], 769 [ "Thread/get", { 770 "accountId": "1", 771 "state": "123456", 772 "list": [{ 773 "id: "trd194", 774 "emailIds": [ "msg1020", "msg1021", "msg1023" ] 775 }, { 776 "id: "trd114", 777 "emailIds": [ "msg201", "msg223" ] 778 }, 779 ... 780 ], 781 "notFound": null 782 }, "t2" ]] 784 So to execute the final Email/get call, we look through the arguments 785 and find there is one with a "#" prefix. To resolve this, we apply 786 the algorithm: 788 1. Find the first response with client id "t2". The "Thread/get" 789 response fulfils this criterion. 791 2. "Thread/get" is the name specified in the result reference, so 792 this is fine. 794 3. Apply the _path_ as a JSON pointer to the arguments object. 795 Token-by-token: a) "list": get the array of thread objects b) 796 "*": for each of the items in the array: 798 i) `emailIds`: get the array of email ids 799 ii) Concatenate these into a single array of all the ids in the result. 801 The JMAP server now continues to process the Email/get call as though 802 the arguments were: 804 { 805 "ids": [ "msg1020", "msg1021", "msg1023", "msg201", "msg223", etc... ], 806 "properties": [ "from", "receivedAt", "subject" ] 807 } 809 3.8. Security 811 As always, the server must be strict about data received from the 812 client. Arguments need to be checked for validity; a malicious user 813 could attempt to find an exploit through the API. In case of invalid 814 arguments (unknown/insufficient/wrong type for data etc.) the method 815 MUST return an "invalidArguments" error and terminate. 817 3.9. Concurrency 819 Each individual method call within a request MUST be serializable; 820 concurrent execution of methods MUST produce the same effect as 821 running them one at a time in some order. 823 This means that the observable ordering may interleave method calls 824 from different concurrent API requests, such that the data on the 825 server may change between two method calls within a single API 826 request. 828 4. Standard methods and naming convention 830 JMAP provides a uniform interface for creating, retrieving, updating 831 and deleting objects of a particular type. For a "Foo" data type, 832 records of that type would be fetched via a Foo/get call and modified 833 via a Foo/set call. Delta updates may be fetched via a Foo/changes 834 call. These methods all follow a standard format as described below. 836 4.1. /get 838 Objects of type *Foo* are fetched via a call to _Foo/get_. 840 It takes the following arguments: 842 o *accountId*: "String|null" The id of the Account to use. If 843 "null", the primary account is used. 845 o *ids*: "String[]|null" The ids of the Foo objects to return. If 846 "null" then *all* records of the data type are returned, if this 847 is supported for that data type. 849 o *properties*: "String[]|null" If supplied, only the properties 850 listed in the array are returned for each Foo object. If "null", 851 all properties of the object are returned. The id of the object 852 is *always* returned, even if not explicitly requested. If an 853 invalid property is requested, the call MUST be rejected with an 854 "invalidArguments" error. 856 The response has the following arguments: 858 o *accountId*: "String" The id of the account used for the call. 860 o *state*: "String" A string representing the state on the server 861 for *all* the data of this type in the account (not just the 862 objects returned in this call). If the data changes, this string 863 MUST change. If the Foo data is unchanged, servers SHOULD return 864 the same state string on subsequent requests for this data type. 865 When a client receives a response with a different state string to 866 a previous call, it MUST either throw away all currently cached 867 objects for the type, or call _Foo/changes_ to get the exact 868 changes. 870 o *list*: "Foo[]" An array of the Foo objects requested. This is 871 the *empty array* if no objects were found, or if the _ids_ 872 argument passed in was also the empty array. The results MAY be 873 in a different order to the _ids_ in the request arguments. If an 874 identical id is included more than once in the request, the server 875 MUST only include it once in either the _list_ or _notFound_ 876 argument of the response. 878 o *notFound*: "String[]|null" This array contains the ids passed to 879 the method for records that do not exist. This property is "null" 880 if all requested ids were found, or if the _ids_ argument passed 881 in was either "null" or the empty array. 883 The following additional error may be returned instead of the _Foo/ 884 get_ response: 886 "requestTooLarge": The number of _ids_ requested by the client 887 exceeds the maximum number the server is willing to process in a 888 single method call. 890 4.2. /changes 892 When the state of the set of Foo records changes on the server 893 (whether due to creation, updates or deletion), the _state_ property 894 of the _Foo/get_ response will change. The _Foo/changes_ method 895 allows a client to efficiently update the state of its Foo cache to 896 match the new state on the server. It takes the following arguments: 898 o *accountId*: "String|null" The id of the Account to use. If 899 "null", the primary account is used. 901 o *sinceState*: "String" The current state of the client. This is 902 the string that was returned as the _state_ argument in the _Foo/ 903 get_ response. The server will return the changes that have 904 occurred since this state. 906 o *maxChanges*: "Number|null" The maximum number of ids to return in 907 the response. The server MAY choose to return fewer than this 908 value, but MUST NOT return more. If not given by the client, the 909 server may choose how many to return. If supplied by the client, 910 the value MUST be a positive integer greater than 0. If a value 911 outside of this range is given, the server MUST reject the call 912 with an "invalidArguments" error. 914 The response has the following arguments: 916 o *accountId*: "String" The id of the account used for the call. 918 o *oldState*: "String" This is the _sinceState_ argument echoed 919 back; the state from which the server is returning changes. 921 o *newState*: "String" This is the state the client will be in after 922 applying the set of changes to the old state. 924 o *hasMoreChanges*: "Boolean" If "true", the client may call _Foo/ 925 changes_ again with the _newState_ returned to get further 926 updates. If "false", _newState_ is the current server state. 928 o *changed*: "String[]|null" An array of ids for records which have 929 been created or modified but not destroyed since the oldState, or 930 "null" if none. 932 o *destroyed*: "String[]|null" An array of ids for records which 933 have been destroyed since the old state, or "null" if none. 935 If a _maxChanges_ is supplied, or set automatically by the server, 936 the server MUST ensure the number of ids returned across _changed_ 937 and _destroyed_ does not exceed this limit. If there are more 938 changes than this between the client's state and the current server 939 state, the update returned SHOULD generate an update to take the 940 client to an intermediate state, from which the client can continue 941 to call _Foo/changes_ until it is fully up to date. If it is unable 942 to calculate an intermediate state, it MUST return a 943 "cannotCalculateChanges" error response instead. 945 If a Foo record has been modified AND destroyed since the oldState, 946 the server SHOULD just return the id in the _destroyed_ list, but MAY 947 return it in the _changed_ list as well. If a Foo record has been 948 created AND destroyed since the oldState, the server SHOULD remove 949 the id from the response entirely, but MAY include it in the 950 _destroyed_ list. 952 The following additional errors may be returned instead of the _Foo/ 953 changes_ response: 955 "cannotCalculateChanges": The server cannot calculate the changes 956 from the state string given by the client. Usually due to the 957 client's state being too old, or the server being unable to produce 958 an update to an intermediate state when there are too many updates. 959 The client MUST invalidate its Foo cache. 961 Maintaining state to allow calculation of _Foo/changes_ can be 962 expensive for the server, but always returning 963 _cannotCalculateChanges_ severely increases network traffic and 964 resource usage for the client. To allow efficient sync, servers 965 SHOULD be able to calculate changes from any state string that was 966 given to a client within the last 30 days (but of course may support 967 calculating updates from states older than this). 969 4.3. /set 971 Modifying the state of Foo objects on the server is done via the 972 _Foo/set_ method. This encompasses creating, updating and destroying 973 Foo records. This allows the server to sort out ordering and 974 dependencies that may exist if doing multiple operations at once (for 975 example to ensure there is always a minimum number of a certain 976 record type). 978 The _Foo/set_ method takes the following arguments: 980 o *accountId*: "String|null" The id of the Account to use. If 981 "null", the primary account is used. 983 o *ifInState*: "String|null" This is a state string as returned by 984 the _Foo/get_ method. If supplied, the string must match the 985 current state, otherwise the method will be aborted and a 986 "stateMismatch" error returned. If "null", any changes will be 987 applied to the current state. 989 o *create*: "String[Foo]|null" A map of _creation id_ (an arbitrary 990 string set by the client) to Foo objects, or "null" if no objects 991 are to be created. The Foo object type definition MAY define 992 default values for properties. Any such property MAY be omitted 993 by the client. The client MUST omit any properties that may only 994 be set by the server (for example, the _id_ property on most 995 object types). 997 o *update*: "String[PatchObject]|null" A map of id to a Patch object 998 to apply to the current Foo object with that id, or "null" if no 999 objects are to be updated. A _PatchObject_ is of type 1000 "String[*]", and represents an unordered set of patches. The keys 1001 are a path in [RFC6901] JSON pointer format, with an implicit 1002 leading "/" (i.e. prefix each key with "/" before applying the 1003 JSON pointer evaluation algorithm). All paths MUST also conform 1004 to the following restrictions; if there is any violation, the 1005 update MUST be rejected with an "invalidPatch" error: 1007 * The pointer MUST NOT reference inside an array (i.e. you MUST 1008 NOT insert/delete from an array; the array MUST be replaced in 1009 its entirety instead). 1011 * All parts prior to the last (i.e. the value after the final 1012 slash) MUST already exist on the object being patched. 1014 * There MUST NOT be two patches in the PatchObject where the 1015 pointer of one is the prefix of the pointer of the other, e.g. 1016 "alerts/1/offset" and "alerts". 1018 The value associated with each pointer determines how to apply 1019 that patch: 1021 * If "null", set to the default value if specified for this 1022 property, otherwise remove the property from the patched 1023 object. If the key is not present in the parent, this a no-op. 1025 * Anything else: The value to set for this property (this may be 1026 a replacement or addition to the object being patched). 1028 Any server-set properties MAY be included in the patch if their 1029 value is identical to the current server value (before applying 1030 the patches to the object). Otherwise, the update MUST be 1031 rejected with an _invalidProperties_ SetError. This patch 1032 definition is designed such that an entire Foo object is also a 1033 valid PatchObject. The client MAY choose to optimise network 1034 usage by just sending the diff, or MAY just send the whole object; 1035 the server processes it the same either way. 1037 o *destroy*: "String[]|null" A list of ids for Foo objects to 1038 permanently delete, or "null" if no objects are to be destroyed. 1040 Each creation, modification or destruction of an object is considered 1041 an atomic unit. It is permissible for the server to commit changes 1042 to some objects but not others, however it is not permissible to only 1043 commit part of an update to a single record (e.g. update a _name_ 1044 property but not a _count_ property, if both are supplied in the 1045 update object). 1047 The final state MUST be valid after the Foo/set is finished, however 1048 the server may have to transition through invalid intermediate states 1049 (not exposed to the client) while processing the individual 1050 create/update/destroy requests. For example, suppose there is a 1051 "name" property that must be unique. A single method call could 1052 rename an object A => B, and simultaneously rename another object B 1053 => A. If the final state is valid, this is allowed. Otherwise, each 1054 creation, modification or destruction of an object should be 1055 processed sequentially and accepted/rejected based on the current 1056 server state. 1058 If a create, update or destroy is rejected, the appropriate error 1059 MUST be added to the notCreated/notUpdated/notDestroyed property of 1060 the response and the server MUST continue to the next create/update/ 1061 destroy. It does not terminate the method. 1063 If an id given cannot be found, the update or destroy MUST be 1064 rejected with a "notFound" set error. 1066 The server MAY skip an update (rejecting it with a "willDestroy" 1067 SetError) if that object is destroyed in the same /set request. 1069 Some record objects may hold references to others (foreign keys). 1070 When records are created or modified, they may reference other 1071 records being created _in the same API request_ by using the creation 1072 id prefixed with a "#". The order of the method calls in the request 1073 by the client MUST be such that the record being referenced is 1074 created in the same or an earlier call. The server thus never has to 1075 look ahead. Instead, while processing a request (a series of method 1076 calls), the server MUST keep a simple map for the duration of the 1077 request of creation id to record id for each newly created record, so 1078 it can substitute in the correct value if necessary in later method 1079 calls. 1081 Creation ids are scoped by type; a separate "creation id -> id" map 1082 MUST be kept for each type for the duration of the request. Foreign 1083 key references are always for a particular record type, so use of the 1084 same creation key in two different types cannot cause any ambiguity. 1085 Creation ids sent by the client SHOULD be unique within the single 1086 API request for a particular data type. If a creation id is reused 1087 for the same type, the server MUST map the creation id to the most 1088 recently created item with that id. 1090 The response has the following arguments: 1092 o *accountId*: "String" The id of the account used for the call. 1094 o *oldState*: "String|null" The state string that would have been 1095 returned by _Foo/get_ before making the requested changes, or 1096 "null" if the server doesn't know what the previous state string 1097 was. 1099 o *newState*: "String" The state string that will now be returned by 1100 _Foo/get_. 1102 o *created*: "String[Foo]|null" A map of the creation id to an 1103 object containing any properties of the created Foo object that 1104 were not sent by the client. This includes all server-set 1105 properties (such as the _id_ in most object types) and any 1106 properties that were omitted by the client and so set to a default 1107 by the server. This argument is "null" if no Foo objects were 1108 successfully created. 1110 o *updated*: "String[Foo|null]|null" The _keys_ in this map are the 1111 ids of all Foos that were successfully updated, or "null" if none 1112 successful. The _value_ for each id is a Foo object containing 1113 any property that changed in a way _not_ explicitly requested by 1114 the _PatchObject_ sent to the server, or "null" if none. This 1115 lets the client know of any changes to server-set or computed 1116 properties. 1118 o *destroyed*: "String[]|null" A list of Foo ids for records that 1119 were successfully destroyed, or "null" if none successful. 1121 o *notCreated*: "String[SetError]|null" A map of creation id to a 1122 SetError object for each record that failed to be created, or 1123 "null" if all successful. 1125 o *notUpdated*: "String[SetError]|null" A map of Foo id to a 1126 SetError object for each record that failed to be updated, or 1127 "null" if all successful. 1129 o *notDestroyed*: "String[SetError]|null" A map of Foo id to a 1130 SetError object for each record that failed to be destroyed, or 1131 "null" if all successful. 1133 A *SetError* object has the following properties: 1135 o *type*: "String" The type of error. 1137 o *description*: "String|null" A description of the error to display 1138 to the user. 1140 The following SetError types are defined and may be returned for set 1141 operations on any record type where appropriate: 1143 o "forbidden": (create; update; destroy) The create/update/destroy 1144 would violate an ACL or other permissions policy. 1146 o "overQuota": (create) The create would exceed a server-defined 1147 limit on the number or total size of objects of this type. 1149 o "rateLimit": (create) Too many objects of this type have been 1150 created recently, and a server-defined rate limit has been 1151 reached. It may work if tried again later. 1153 o "notFound": (update; destroy) The id given cannot be found. 1155 o "invalidPatch": (update) The PatchObject given to update the 1156 record was not a valid patch (see the patch description). 1158 o "willDestroy" (update) The client requested an object be both 1159 updated and destroyed in the same /set request, and the server has 1160 decided to therefore ignore the update. 1162 o "invalidProperties": (create; update) The record given is invalid 1163 in some way. For example: 1165 * It contains properties which are invalid according to the type 1166 specification of this record type. 1168 * It contains a property that may only be set by the server (e.g. 1169 "id") and are different to the current value. Note, to allow 1170 clients to pass whole objects back, it is not an error to 1171 include a server-set property so long as the value is identical 1172 to the current value on the server (or the value that will be 1173 set by the server if a create). 1175 * There is a reference to another record (foreign key) and the 1176 given id does not correspond to a valid record. 1178 The SetError object SHOULD also have a property called 1179 _properties_ of type "String[]" that lists *all* the properties 1180 that were invalid. Individual methods MAY specify more specific 1181 errors for certain conditions that would otherwise result in an 1182 invalidProperties error. If the condition of one of these is met, 1183 it MUST be returned instead of the invalidProperties error. 1185 o "singleton": (create; destroy) This is a singleton type, so you 1186 cannot create another one or destroy the existing one. 1188 Other possible SetError types MAY be given in specific method 1189 descriptions. Other properties MAY also be present on the _SetError_ 1190 object, as described in the relevant methods. 1192 The following additional errors may be returned instead of the _Foo/ 1193 set_ response: 1195 "requestTooLarge": The total number of objects to create, update or 1196 destroy exceeds the maximum number the server is willing to process 1197 in a single method call. 1199 "stateMismatch": An "ifInState" argument was supplied and it does not 1200 match the current state. 1202 4.4. /query 1204 For data sets where the total amount of data is expected to be very 1205 small, clients can just fetch the complete set of data and then do 1206 any sorting/filtering locally. However, for large data sets (e.g. 1207 multi-gigabyte mailboxes), the client needs to be able to 1208 search/sort/window the data type on the server. 1210 A query on the set of Foos in an account is made by calling _Foo/ 1211 query_. This takes a number of arguments to determine which records 1212 to include, how they should be sorted, and which part of the result 1213 should be returned (the full list may be _very_ long). The result is 1214 returned as a list of Foo ids. 1216 A call to _Foo/query_ takes the following arguments: 1218 o *accountId*: "String|null" The id of the Account to use. If 1219 "null", the primary account is used. 1221 o *filter*: "FilterOperator|FilterCondition|null" Determines the set 1222 of Foos returned in the results. If "null", all objects in the 1223 account of this type are included in the results. A 1224 *FilterOperator* object has the following properties: 1226 * *operator*: "String" This MUST be one of the following strings: 1227 "AND"/"OR"/"NOT": 1229 + *AND*: all of the conditions must match for the filter to 1230 match. 1232 + *OR*: at least one of the conditions must match for the 1233 filter to match. 1235 + *NOT*: none of the conditions must match for the filter to 1236 match. 1238 * *conditions*: "(FilterOperator|FilterCondition)[]" The 1239 conditions to evaluate against each email. 1241 A *FilterCondition* is an "object", whose allowed properties and 1242 semantics depend on the data type and is defined in the _/query_ 1243 method specification for that type. 1245 o *sort*: "Comparator[]|null" Lists the names of properties to 1246 compare between two Foo records, and how to compare them, to 1247 determine which comes first in the sort. If two Foo records have 1248 an identical value for the first comparator, the next comparator 1249 will be considered and so on. If all comparators are the same 1250 (this includes the case where an empty array or "null" is given as 1251 the _sort_ argument), the sort order is server-dependent, but MUST 1252 be stable between calls to Foo/query. A *Comparator* has the 1253 following properties: 1255 * *property*: "String" The name of the property on the Foo 1256 objects to compare. 1258 * *isAscending*: "Boolean" (optional; default: "true") If true, 1259 sort in ascending order. If false, reverse the comparator's 1260 results to sort in descending order. 1262 * *collation*: "String" (optional; default is server-dependent) 1263 The identifier, as registered in the collation registry defined 1264 in [RFC4790], for the algorithm to use when comparing the order 1265 of strings. The algorithms the server supports are advertised 1266 in the capabilities object returned with the JMAP Session 1267 object. If omitted, the default algorithm is server-dependent, 1268 but: 1270 1. It MUST be unicode-aware. 1272 2. It SHOULD have reasonable default behavior for many 1273 languages when the user's language is unknown. 1275 3. It MAY be selected based on out-of-band information about 1276 the user's language/locale. 1278 4. It SHOULD be case-insensitive where such a concept makes 1279 sense for a language/locale. 1281 The "i;unicode-casemap" collation ([RFC5051]) and the Unicode 1282 Collation Algorithm () 1283 are two examples that fulfil these criterion. When the 1284 property being compared is not a string, the _collation_ 1285 property is ignored and the following comparison rules apply 1286 based on the type. In ascending order: 1288 + "Boolean": "false" comes before "true". 1290 + "Number": A lower number comes before a higher number. 1292 + "Date"/"UTCDate": The earlier date comes first. 1294 o *position*: "Number" (default: "0") The 0-based index of the first 1295 id in the full list of results to return. If a negative value is 1296 given, it is an offset from the end of the list. Specifically, 1297 the negative value MUST be added to the total number of results 1298 given the filter, and if still negative clamped to "0". This is 1299 now the 0-based index of the first id to return. If the index is 1300 greater than or equal to the total number of objects in the 1301 results list then the _ids_ array in the response will be empty, 1302 but this is not an error. 1304 o *anchor*: "String|null" A Foo id. If supplied the _position_ 1305 argument is ignored. The index of this id in the results will be 1306 used in combination with the "anchorOffset" argument to determine 1307 the index of the first result to return (see below for more 1308 details). 1310 o *anchorOffset*: "Number|null" The index of the anchor object 1311 relative to the index of the first result to return. This MAY be 1312 negative. For example, "-1" means the first Foo after the anchor 1313 Foo should be the first result in the results returned (see below 1314 for more details). 1316 o *limit*: "Number|null" The maximum number of results to return. 1317 If "null", no limit presumed. The server MAY choose to enforce a 1318 maximum "limit" argument. In this case, if a greater value is 1319 given (or if it is "null"), the limit should be clamped to the 1320 maximum; since the total number of results in the search is 1321 returned, the client can determine if it has received all the 1322 results. If a negative value is given, the call MUST be rejected 1323 with an "invalidArguments" error. 1325 If an *anchor* argument is given, then after filtering and sorting 1326 the anchor is looked for in the results. If found, the *anchor 1327 offset* is then subtracted from its index. If the resulting index is 1328 now negative, it is clamped to 0. This index is now used exactly as 1329 though it were supplied as the "position" argument. If the anchor is 1330 not found, the call is rejected with an "anchorNotFound" error. 1332 If an _anchor_ is specified, any position argument supplied by the 1333 client MUST be ignored. If _anchorOffset_ is "null", it defaults to 1334 "0". If no _anchor_ is supplied, any anchor offset argument MUST be 1335 ignored. 1337 A client can use _anchor_ instead of _position_ to find the index of 1338 an id within a large set of results. 1340 The response has the following arguments: 1342 o *accountId*: "String" The id of the account used for the call. 1344 o *filter*: "FilterOperator|FilterCondition|null" The filter to 1345 apply to the search. Echoed back from the call. 1347 o *sort*: "Comparator[]|null" The sort options used. Echoed back 1348 from the call. 1350 o *state*: "String" A string encoding the current state on the 1351 server. This string MUST change if the results of the search 1352 _may_ have changed (for example, there has been a change to the 1353 state of the set of Foos; it does not _guarantee_ that anything in 1354 the search has changed). It may be passed to _Foo/queryChanges_ 1355 to efficiently get the set of changes from the client's current 1356 state. Should a client receive back a response with a different 1357 state string to a previous call, it MUST either throw away the 1358 currently cached search and fetch it again (note, this does not 1359 require fetching the records again, just the list of ids) or, call 1360 _Foo/queryChanges_ to get the delta difference. 1362 o *canCalculateChanges*: "Boolean" This is "true" if the server 1363 supports calling _Foo/queryChanges_ with these "filter"/"sort" 1364 parameters. Note, this does not guarantee that the _Foo/ 1365 queryChanges_ call will succeed, as it may only be possible for a 1366 limited time afterwards due to server internal implementation 1367 details. 1369 o *position*: "Number" The 0-based index of the first result in the 1370 "ids" array within the complete list of search results. 1372 o *total*: "Number" The total number of foos in the results (given 1373 the _filter_). 1375 o *ids*: "String[]" The list of ids for each foo in the search 1376 results, starting at the index given by the _position_ argument of 1377 this response, and continuing until it hits the end of the results 1378 or reaches the "limit" number of ids. If _position_ is >= 1379 _total_, this MUST be the empty list. 1381 The following additional errors may be returned instead of the _Foo/ 1382 query_ response: 1384 "anchorNotFound": An anchor argument was supplied, but it cannot be 1385 found in the results of the search. 1387 "unsupportedSort": The _sort_ is syntactically valid, but includes a 1388 property the server does not support sorting on, or a collation 1389 method it does not recognise. 1391 "unsupportedFilter": The _filter_ is syntactically valid, but the 1392 server cannot process it. 1394 4.5. /queryChanges 1396 The "Foo/queryChanges" call allows a client to efficiently update the 1397 state of any cached foo search to match the new state on the server. 1398 It takes the following arguments: 1400 o *accountId*: "String|null" The id of the account to use for this 1401 call. If "null", the primary account will be used. 1403 o *filter*: "FilterOperator|FilterCondition|null" The filter 1404 argument that was used with _Foo/query_. 1406 o *sort*: "Comparator[]|null" The sort argument that was used with 1407 _Foo/query_. 1409 o *sinceState*: "String" The current state of the client. This is 1410 the string that was returned as the _state_ argument in the _Foo/ 1411 query_ response. The server will return the changes made since 1412 this state. 1414 o *maxChanges*: "Number|null" The maximum number of changes to 1415 return in the response. See error descriptions below for more 1416 details. 1418 o *uptoId*: "String|null" The last (highest-index) id the client 1419 currently has cached from the search results. When there are a 1420 large number of results, in a common case the client may have only 1421 downloaded and cached a small subset from the beginning of the 1422 results. If the sort and filter are both only on immutable 1423 properties, this allows the server to omit changes after this 1424 point in the results, which can significantly increase efficiency. 1425 If they are not immutable, this argument is ignored. 1427 The response has the following arguments: 1429 o *accountId*: "String" The id of the account used for the call. 1431 o *filter*: "FilterOperator|FilterCondition|null" The filter to 1432 apply to the search. Echoed back from the call. 1434 o *sort*: "Comparator[]|null" The sort options used. Echoed back 1435 from the call. 1437 o *oldState*: "String" This is the "sinceState" argument echoed 1438 back; the state from which the server is returning changes. 1440 o *newState*: "String" This is the state the client will be in after 1441 applying the set of changes to the old state. 1443 o *uptoId*: "String|null" Echoed back from the call. 1445 o *total*: "Number" The total number of foos in the results (given 1446 the _filter_). 1448 o *removed*: "String[]" The _id_ for every foo that was in the 1449 results in the old state and is not in the results in the new 1450 state. If the sort and filter are both only on immutable 1451 properties and an _uptoId_ is supplied and exists in the results, 1452 any ids that were removed but have a higher index than _uptoId_ 1453 SHOULD be omitted. If the server cannot calculate this exactly, 1454 the server MAY return extra foos in addition that may have been in 1455 the old results but are not in the new results. If the _filter_ 1456 or _sort_ includes a mutable property, the server MUST include all 1457 foos in the current results for which this property MAY have 1458 changed. 1460 o *added*: "AddedItem[]" The id and index in the search results (in 1461 the new state) for every foo that has been added to the results 1462 since the old state AND every foo in the current results that was 1463 included in the _removed_ array (due to a filter or sort based 1464 upon a mutable property). If the sort and filter are both only on 1465 immutable properties and an _uptoId_ is supplied and exists in the 1466 results, any ids that were added but have a higher index than 1467 _uptoId_ SHOULD be omitted. The array MUST be sorted in order of 1468 index, lowest index first. An *AddedItem* object has the 1469 following properties: 1471 * *id*: "String" 1473 * *index*: "Number" 1475 The result of this is that if the client has a cached sparse array of 1476 foo ids in the results in the old state: 1478 fooIds = [ "id1", "id2", null, null, "id3", "id4", null, null, null ] 1480 then if it *splices out* all foos in the removed array: 1482 removed = [ "id2", ... ]; 1483 fooIds => [ "id1", null, null, "id3", "id4", null, null, null ] 1485 and *splices in* (in order) all of the foos in the added array: 1487 added = [{ id: "id5", index: 0, ... }]; 1488 fooIds => [ "id5", "id1", null, null, "id3", "id4", null, null, null ] 1490 and *truncates* or *extends* to the new total length, then the 1491 results will now be in the new state. 1493 The following additional errors may be returned instead of the _Foo/ 1494 queryChanges_ response: 1496 "tooManyChanges": There are more changes the the client's 1497 _maxChanges_ argument. Each item in the removed or added array is 1498 considered as one change. The client may retry with a higher max 1499 changes or invalidate its cache of the search results. 1501 "cannotCalculateChanges": The server cannot calculate the changes 1502 from the state string given by the client. Usually due to the 1503 client's state being too old. The client MUST invalidate its cache 1504 of the search results. 1506 4.6. Examples 1508 Suppose we have a type _Todo_ with the following properties: 1510 o *id*: "String" (immutable; server-set) The id of the object. 1512 o *title*: "String" A brief summary of what is to be done. 1514 o *keywords*: "String[Boolean]" (mutable; default: "{}") A set of 1515 keywords that apply to the todo. The set is represented as an 1516 object, with the keys being the _keywords_. The value for each key 1517 in the object MUST be "true". 1519 o *neuralNetworkTimeEstimation*: "Number" (server-set) The title and 1520 keywords are fed into the server's state-of-the-art neural network 1521 to get an estimation of how long this todo will take, in seconds. 1523 and the server supports querying by keyword using the syntax "{ 1524 hasKeyword: "foo" }" in the _filter_ argument to _/query_. 1526 Now, a client might want to display the list of todos with a 1527 particular query, so it makes the following method call: 1529 [["Todo/query", { 1530 "filter": { "hasKeyword": "music" }, 1531 "sort": [{ "property": "title" }], 1532 "position": 0, 1533 "limit": 10 1534 }, "0"], 1535 ["Todo/get", { 1536 "#ids": { 1537 "resultOf": "0", 1538 "name": "Todo/query", 1539 "path": "/ids" 1540 }, 1541 }, "1"]] 1543 This would query the server for the set of todos with a keyword of 1544 "music", sorted by title, and limited to the first 10 results. It 1545 fetches the full object for each of these Todos using backreferences 1546 to reference the result of the query. The response might look 1547 something like: 1549 [["Todo/query", { 1550 "accountId": "x", 1551 "filter": { "hasKeyword": "music" }, 1552 "sort": [{ "property": "title" }], 1553 "state": "y13213", 1554 "canCalculateChanges": true, 1555 "position": 0, 1556 "total": 26, 1557 "ids": [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j" ] 1558 }, "0"], 1559 ["Todo/get", { 1560 "accountId": "x", 1561 "state": "10324", 1562 "list": [{ 1563 "id": "a", 1564 "title": "Practise Piano", 1565 "keywords": { 1566 "music": true, 1567 "beethoven": true, 1568 "mozart": true, 1569 "liszt": true, 1570 "rachmaninov": true 1571 }, 1572 "neuralNetworkTimeEstimation": 3600 1573 }, { 1574 "id": "b", 1575 "title": "Listen to Daft Punk", 1576 "keywords": { 1577 "music": true, 1578 "trance": true 1579 }, 1580 "neuralNetworkTimeEstimation": 18000 1581 }, 1582 ... 1583 ] 1584 }, "1"]] 1586 Now suppose the user adds a keyword "chopin" and removes the keyword 1587 "mozart" from the "Practise Piano" task. The client may send the 1588 whole object to the server, as this is a valid PatchObject: 1590 [["Todo/set", { 1591 "ifInState": "10324", 1592 "update": { 1593 "a": { 1594 "id": "a", 1595 "title": "Practise Piano", 1596 "keywords": { 1597 "music": true, 1598 "beethoven": true, 1599 "chopin": true, 1600 "liszt": true, 1601 "rachmaninov": true, 1602 } 1603 "neuralNetworkTimeEstimation": 360 1604 } 1605 } 1606 }, "0"]] 1608 or it may send a minimal patch: 1610 [["Todo/set", { 1611 "ifInState": "10324", 1612 "update": { 1613 "a": { 1614 "keywords/chopin": true, 1615 "keywords/mozart": null 1616 } 1617 } 1618 }, "0"]] 1620 The effect is exactly the same on the server in either case, and 1621 presuming the server is still in state "10324" it will probably 1622 return success: 1624 [["Todo/set", { 1625 "accountId": "x", 1626 "oldState": "10324", 1627 "newState": "10329", 1628 "updated": { 1629 "a": { 1630 "neuralNetworkTimeEstimation": 5400 1631 } 1632 } 1633 }, "0"]] 1635 The server changed the "neuralNetworkTimeEstimation" property on the 1636 object as part of this change; as this changed in a way _not_ 1637 explicitly requested by the PatchObject sent to the server, it is 1638 returned with the "updated" confirmation. 1640 Now, suppose another user deleted the "Listen to Daft Punk" todo. 1641 The first user will receive a push notification (see later in the 1642 spec) with the changed state string for the "Todo" type. Since the 1643 new string does not match its current state, it knows it needs to 1644 check for updates. It may make a request like: 1646 [["Todo/changes", { 1647 "accountId": "x", 1648 "sinceState": "10324", 1649 "maxChanges": 50, 1650 }, "0"], 1651 ["Todo/queryChanges", { 1652 "filter": { "hasKeyword": "music" }, 1653 "sort": [{ "property": "title" }], 1654 "sinceState": "y13213" 1655 "maxChanges": 50, 1656 }, "1"]] 1658 and receive in response: 1660 [["Todo/changes", { 1661 "accountId": "x", 1662 "oldState": "10324", 1663 "newState": "871903", 1664 "hasMoreChanges": false, 1665 "changed": null, 1666 "destroyed": ["b"] 1667 }, "0"], 1668 ["Todo/queryChanges", { 1669 "filter": { "hasKeyword": "music" }, 1670 "sort": [{ "property": "title" }], 1671 "oldState": "y13213" 1672 "newState": "y13218" 1673 "total": 25, 1674 "removed": ["b"], 1675 "added": null 1676 }, "1"]] 1678 5. Binary data 1680 Binary data is referenced by a _blobId_ in JMAP, and uploaded/ 1681 downloaded separately to the core API. A blobId does not have a name 1682 inherent to it, but this is normally given in the same object that 1683 contains the blobId. The data represented by a blobId is immutable. 1685 Any blobId that exists within an account may be used when creating/ 1686 updating another object in that account. For example, an Email type 1687 may have a blobId that represents the RFC5322 representation of the 1688 message. A client could create a new Email object with an attachment 1689 and use this blobId, in effect attaching the old message to the new 1690 one. Similarly it could attach any existing existing attachment of 1691 an old message without having to download and upload it again. 1693 When the client uses a blobId in a create/update, the server MAY 1694 assign a new blobId to refer to the same binary data from the new/ 1695 updated object. If it does so, it MUST return any properties that 1696 contain a changed blobId in the created/updated response so the 1697 client gets the new ids. 1699 A blob that is not referenced by a JMAP object (e.g. as a message 1700 attachment), MAY be deleted by the server to free up resources. 1701 Uploads (see below) are initially unreferenced blobs. To ensure 1702 interoperability: 1704 o The server SHOULD use a separate quota for unreferenced blobs to 1705 the user's usual quota. 1707 o This quota SHOULD be at least the maximum total size that a single 1708 object can reference on this server. For example, if supporting 1709 JMAP Mail, this should be at least the maximum total attachments 1710 size for a message. 1712 o When an upload would take the user over quota, the server MUST 1713 delete unreferenced blobs in date order, oldest first, until there 1714 is room for the new blob. 1716 o Except where quota restrictions force early deletion, an 1717 unreferenced blob SHOULD NOT be deleted for at least 24h from the 1718 time of upload; if reuploaded, the same blobId MAY be returned, 1719 but this SHOULD reset the expiry time. 1721 o A blob MUST NOT be deleted during the method call which removed 1722 the last reference, so that a client can issue a create and a 1723 destroy that both reference the blob within the same method call. 1725 5.1. Uploading binary data 1727 There is a single endpoint which handles all file uploads for an 1728 account, regardless of what they are to be used for. The JMAP 1729 Session object has an _uploadUrl_ property in [RFC6570] URI Template 1730 (level 1) format, which MAY contain a variable called "accountId". 1731 The client may use this template in combination with an _accountId_ 1732 (if required in the template) to get the URL of the file upload 1733 resource. 1735 To upload a file, the client submits an authenticated POST request to 1736 the file upload resource. 1738 A successful request MUST return a single JSON object with the 1739 following properties as the response: 1741 o *accountId*: "String" The id of the account used for the call. 1743 o *blobId*: "String", The id representing the binary data uploaded. 1744 The data for this id is immutable. The id _only_ refers to the 1745 binary data, not any metadata. 1747 o *type*: "String" The media type of the file (as specified in 1748 [RFC6838], section 4.2) as set in the Content-Type header of the 1749 upload HTTP request, with CFWS collapsed to SP and 1750 [RFC2231]/[RFC2047] encoding removed. 1752 o *size*: "Number" The size of the file in octets. 1754 If identical binary content to an existing blob in the account is 1755 uploaded, the existing blobId MAY be returned. 1757 5.2. Downloading binary data 1759 The JMAP Session object has a _downloadUrl_ property, which is in 1760 [RFC6570] URI Template (level 1) format. The URL MUST contain a 1761 variable called "blobId", MAY contain a variable called "accountId", 1762 and SHOULD contain a variable called "name". 1764 The client may use this template in combination with an _accountId_ 1765 (if required in the URL template) and _blobId_ to download any binary 1766 data (files) referenced by other objects. Since a blob is not 1767 associated with a particular name, the template SHOULD allow a name 1768 to be substituted in as well; the server will return this as the 1769 filename if it sets a "Content-Disposition" header. 1771 To download the data the client makes an authenticated GET request to 1772 the download URL with the appropriate variables substituted in. The 1773 client SHOULD send an "Accept" header with the content type they 1774 would like the server to return for the file. The "Content-Type" 1775 header of a successful response SHOULD be set to the type as 1776 requested in the "Accept" header by the client, or "application/ 1777 octet-stream" if unknown and no "Accept" header given. 1779 5.3. Blob/copy 1781 Binary data may be copied *between* two different accounts using the 1782 _Blob/copy_ method, rather than having to download then reupload on 1783 the client. 1785 The _Blob/copy_ method takes the following arguments: 1787 o *fromAccountId*: "String|null" The id of the account to copy blobs 1788 from. If "null", defaults to the primary account. 1790 o *toAccountId*: "String|null" The id of the account to copy blobs 1791 to. If "null", defaults to the primary account. 1793 o *blobIds*: "String[]" A list of ids of blobs to copy to the other 1794 account. 1796 The response has the following arguments: 1798 o *fromAccountId*: "String" The id of the account emails were copied 1799 from. 1801 o *toAccountId*: "String" The id of the account emails were copied 1802 to. 1804 o *copied*: "String[String]|null" A map of the blob id in the 1805 _fromAccount_ to the id for the blob in the _toAccount_, or "null" 1806 if none were successfully copied. 1808 o *notCopied*: "String[SetError]|null" A map of blob id to a 1809 SetError object for each blob that failed to be copied, "null" if 1810 none. 1812 The *SetError* may be any of the standard set errors that may be 1813 returned for a _create_. 1815 The following additional errors may be returned instead of the _Blob/ 1816 copy_ response: 1818 "fromAccountNotFound": A _fromAccountId_ was explicitly included with 1819 the request, but it does not correspond to a valid account. 1821 "toAccountNotFound": A _toAccountId_ was explicitly included with the 1822 request, but it does not correspond to a valid account. 1824 6. Push 1826 Push notifications allow clients to efficiently update (almost) 1827 instantly to stay in sync with data changes on the server. In JMAP, 1828 push notifications occur out-of-band (i.e. not over the same 1829 connection as API exchanges), so that they can make use of efficient 1830 native push mechanisms on different platforms. 1832 The general model for push is simple and sends minimal data over the 1833 push channel. The format allows multiple changes to be coalesced 1834 into a single push update, and the frequency of pushes to be rate 1835 limited by the server. It doesn't matter if some push events are 1836 dropped before they reach the client; it will still get all changes 1837 next time it syncs. 1839 6.1. The StateChange object 1841 When something changes on the server, the server pushes a 1842 *StateChange* object to the client. A *StateChange* object has the 1843 following properties: 1845 o *changed*: "String[TypeState]" A map of _account id_ to an object 1846 encoding the state of data types that have changed for that 1847 account since the last push event, for each of the accounts to 1848 which the user has access and for which something has changed. A 1849 *TypeState* object is a map. The keys are the type name "Foo" 1850 (e.g. "Mailbox" or "Email"), and the value is the _state_ 1851 property that would currently be returned by a call to _Foo/get_. 1852 The client can compare the new state strings with its current 1853 values to see whether it has the current data for these types. If 1854 not, the changes can then be efficiently fetched in a single 1855 standard API request (using the _/changes_ type methods). 1857 o *trigger*: "String" What caused this change. The following causes 1858 are defined: 1860 * "delivery": The arrival of a new message caused the change. 1862 * "user": An action by the user caused the change. 1864 * "unknown": The cause of the change is unknown. 1866 Future specifications may define further values. Clients MUST 1867 treat an unrecognised value the same as "unknown". Clients in 1868 battery constrained environments may use this information to 1869 decide whether to immediately fetch the changes. 1871 6.2. PushSubscription 1873 A push subscription is a message delivery context established between 1874 the client and a push service. A *PushSubscription* object has the 1875 following properties: 1877 o *url*: "String" An absolute URL where the JMAP server will POST 1878 the data for the push message. This MUST begin with "https://". 1880 o *expires*: "UTCDate|null" The time this push subscription expires. 1881 If specified, the JMAP server MUST NOT make further requests to 1882 this resource after this time. It MAY automatically remove the 1883 push subscription at or after this time. 1885 o *keys*: "Object|null" Client-generated encryption keys. If 1886 supplied the server MUST use them as specified in [RFC8291] to 1887 encrypt all data sent to the push subscription. The object MUST 1888 have the following properties: 1890 * *p256dh*: the P-256 ECDH Diffie-Hellman public key as described 1891 in [RFC8291], encoded in URL-safe base64 representation as 1892 defined in [RFC4648]. 1894 * *auth*: the authentication secret as described in [RFC8291], 1895 encoded in URL-safe base64 representation as defined in 1896 [RFC4648]. 1898 Clients may register the push subscription with the JMAP server, 1899 which will then make a POST request to the associated push endpoint 1900 whenever an event occurs. 1902 The POST request MUST have a content type of "application/json" and 1903 contain the utf-8 JSON encoded _StateChange_ object as the body. The 1904 request MUST have a "TTL" header, and MAY have "Urgency" and/or 1905 "Topic" headers, as specified in section 5 of [RFC8030]. 1907 If the response code is "503" (Service Unavailable), the JMAP server 1908 MAY try again later, but may also just drop the event. If the 1909 response code is "429" (Too Many Requests) the JMAP server SHOULD 1910 attempt to reduce the frequency of pushes to that URL. Any other 1911 "4xx" or "5xx" response code MUST be considered a *permanent failure* 1912 and the push subscription should be deregistered (not tried again 1913 even for future events unless explicitly re-registered by the 1914 client). 1916 The use of this push endpoint conforms with the use of a push 1917 endpoint by an Application Server as defined in [RFC8030]. A client 1918 MAY use the rest of [RFC8030] in combination with its own Push Server 1919 to form a complete end-to-end solution, or MAY rely on alternative 1920 mechanisms to ensure the delivery of the pushed data after it leaves 1921 the JMAP server. 1923 6.2.1. PushSubscription/set 1925 Each session may only have a single push subscription registered. 1926 The push subscription is tied to the access token used to create it. 1927 Should the access token expire or be revoked, the push subscription 1928 MUST be removed by the JMAP server. The client MUST re-register the 1929 push subscription after reauthenticating to resume callbacks. 1931 To set the push subscription, make a call to _PushSubscription/set_. 1932 It takes the following argument: 1934 o *pushSubscription*: "PushSubscription|null" The PushSubscription 1935 object representing the endpoint the JMAP server will POST events 1936 to. This will replace any previously set subscription. Set to 1937 "null" to remove any previously registered subscription. 1939 The response has no arguments. 1941 The following additional errors may be returned instead of the 1942 _PushSubscription/set_ response: 1944 "invalidUrl": Returned if the URL does not begin with "https://", or 1945 is otherwise syntactically invalid or does not resolve. 1947 "forbidden": Returned if the URL is valid, but for policy reasons the 1948 server is not willing to connect to it. 1950 6.2.2. PushSubscription/get 1952 To check the currently set push subscription (if any), make a call to 1953 _PushSubscription/set_. It does not take any arguments. The response 1954 has a single argument: 1956 o *pushSubscription*: "PushSubscription|null" The PushSubscription 1957 object the JMAP server is currently posting push events to, or 1958 "null" if none. 1960 6.3. Event Source 1962 Clients that can hold open TCP connections can connect directly to 1963 the JMAP server to receive push notifications via a "text/event- 1964 stream" resource, as described in . This is a long running HTTP request down which the 1966 server can push data. 1968 When a change occurs in the data on the server, it pushes an event 1969 called *state* to any connected clients, with the _StateChange_ 1970 object as the data. 1972 The server SHOULD also send a new event id that encodes the entire 1973 server state visible to the user immediately after sending a _state_ 1974 event. When a new connection is made to the event-source endpoint, a 1975 client following the server-sent events specification [1] will send a 1976 Last-Event-ID HTTP header with the last id it saw, which the server 1977 can use to work out whether the client has missed some changes. If 1978 so, it SHOULD send these changes immediately on connection. 1980 The client MAY add a query parameter called "closeafter" with value 1981 "state" to the event-source resource URL when requesting the event- 1982 source resource. If set, the server MUST end the HTTP response after 1983 pushing a _state_ event. This can be used by clients in environments 1984 where buffering proxies prevent the pushed data from arriving 1985 immediately, or indeed at all, when operating in the usual mode. 1987 The client MAY add a query parameter called "ping", with a positive 1988 integer value representing a length of time in seconds, e.g. 1989 "ping=300". If set, the server MUST send an event called *ping* 1990 whenever this time elapses since the previous event was sent. This 1991 MUST NOT set a new event id. 1993 The server MAY modify the interval given as a query parameter to be 1994 subject to a minimum and/or maximum value. For interoperability, 1995 servers MUST NOT have a minimum allowed value higher than 30 or a 1996 maximum allowed value less than 300. 1998 The data for the ping event MUST be a JSON object containing an 1999 _interval_ property, the value (type "Number") being the interval in 2000 seconds the server is using to send pings (this may be different to 2001 the requested value if the server clamped it to be within a min/max 2002 value). 2004 Clients can monitor for the _ping_ event to help determine when the 2005 closeafter mode may be required. 2007 Refer to the JMAP Session resource section of this spec for details 2008 on how to get the URL for the event-source resource. Requests to the 2009 resource MUST be authenticated. 2011 A client MAY hold open multiple connections to the event-source 2012 resource, although it SHOULD try to use a single connection for 2013 efficiency. 2015 7. Security considerations 2017 7.1. Transport confidentiality 2019 All HTTP requests MUST use [RFC5246] TLS (https) transport to ensure 2020 the confidentiality of data sent and received via JMAP. Clients MUST 2021 validate TLS certificate chains to protect against man-in-the-middle 2022 attacks. 2024 7.2. Authentication scheme 2026 A number of HTTP authentication schemes have been standardised 2027 (). Servers should take care to assess the security 2029 characteristics of different schemes in relation to their needs when 2030 deciding what to implement. 2032 If offering the Basic authentication scheme, services are strongly 2033 recommended to not allow a user's regular password but require 2034 generation of a unique "app password" via some external mechanism for 2035 each client they wish to connect. This allows connections from 2036 different devices to be differentiated by the server, and access to 2037 be individually revoked. 2039 7.3. Service autodiscovery 2041 Unless secured by something like DNSSEC, autodiscovery of server 2042 details is vulnerable to a DNS poisoning attack leading to the client 2043 talking to an attacker's server instead of the real JMAP server. The 2044 attacker may then man-in-the-middle requests and depending on the 2045 authentication scheme, steal credentials to generate its own 2046 requests. 2048 Clients that do not support SRV lookups are likely to try just using 2049 the "/.well-known/jmap" path directly against the domain of the 2050 username over HTTPS. Servers SHOULD ensure this path resolves or 2051 redirects to the correct JMAP Session resource to allow this to work. 2052 If this is not feasible, servers MUST ensure this path cannot be 2053 controlled by an attacker, as again it may be used to steal 2054 credentials. 2056 7.4. JSON parsing 2058 The security considerations of [RFC7159] apply to the use of JSON as 2059 the data interchange format. 2061 7.5. Denial of service 2063 A small request may result in a very large response, and require 2064 considerable work on the server if resource limits are not enforced. 2065 JMAP provides mechanisms for advertising and enforcing a wide variety 2066 of limits for mitigating this threat, including limits on number of 2067 objects fetched in a single method call, number of methods in a 2068 single request, number of concurrent requests, etc. 2070 JMAP servers MUST implement sensible limits to mitigate against 2071 resource exhaustion attacks. 2073 7.6. Push encryption 2075 When data changes, a small object is pushed with the new state 2076 strings for the types that have changed. While the data here is 2077 minimal, a passive man-in-the-middle attacker may be able to gain 2078 useful information. To ensure confidentiality, if the push is sent 2079 via a third party outside of the control of the client and JMAP 2080 server the client MUST specify encryption keys when establishing the 2081 PushSubscription. 2083 The privacy and security considerations of [RFC8030] and [RFC8291] 2084 also all apply to the use of the PushSubscription mechanism. 2086 8. References 2088 8.1. Normative References 2090 [RFC2047] Moore, K., "MIME (Multipurpose Internet Mail Extensions) 2091 Part Three: Message Header Extensions for Non-ASCII Text", 2092 RFC 2047, DOI 10.17487/RFC2047, November 1996, 2093 . 2095 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 2096 Requirement Levels", BCP 14, RFC 2119, 2097 DOI 10.17487/RFC2119, March 1997, 2098 . 2100 [RFC2231] Freed, N. and K. Moore, "MIME Parameter Value and Encoded 2101 Word Extensions: Character Sets, Languages, and 2102 Continuations", RFC 2231, DOI 10.17487/RFC2231, November 2103 1997, . 2105 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 2106 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 2107 . 2109 [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO 2110 10646", STD 63, RFC 3629, DOI 10.17487/RFC3629, November 2111 2003, . 2113 [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data 2114 Encodings", RFC 4648, DOI 10.17487/RFC4648, October 2006, 2115 . 2117 [RFC4790] Newman, C., Duerst, M., and A. Gulbrandsen, "Internet 2118 Application Protocol Collation Registry", RFC 4790, 2119 DOI 10.17487/RFC4790, March 2007, 2120 . 2122 [RFC5051] Crispin, M., "i;unicode-casemap - Simple Unicode Collation 2123 Algorithm", RFC 5051, DOI 10.17487/RFC5051, October 2007, 2124 . 2126 [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security 2127 (TLS) Protocol Version 1.2", RFC 5246, 2128 DOI 10.17487/RFC5246, August 2008, 2129 . 2131 [RFC5785] Nottingham, M. and E. Hammer-Lahav, "Defining Well-Known 2132 Uniform Resource Identifiers (URIs)", RFC 5785, 2133 DOI 10.17487/RFC5785, April 2010, 2134 . 2136 [RFC6186] Daboo, C., "Use of SRV Records for Locating Email 2137 Submission/Access Services", RFC 6186, 2138 DOI 10.17487/RFC6186, March 2011, 2139 . 2141 [RFC6570] Gregorio, J., Fielding, R., Hadley, M., Nottingham, M., 2142 and D. Orchard, "URI Template", RFC 6570, 2143 DOI 10.17487/RFC6570, March 2012, 2144 . 2146 [RFC6764] Daboo, C., "Locating Services for Calendaring Extensions 2147 to WebDAV (CalDAV) and vCard Extensions to WebDAV 2148 (CardDAV)", RFC 6764, DOI 10.17487/RFC6764, February 2013, 2149 . 2151 [RFC6838] Freed, N., Klensin, J., and T. Hansen, "Media Type 2152 Specifications and Registration Procedures", BCP 13, 2153 RFC 6838, DOI 10.17487/RFC6838, January 2013, 2154 . 2156 [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 2157 "JavaScript Object Notation (JSON) Pointer", RFC 6901, 2158 DOI 10.17487/RFC6901, April 2013, 2159 . 2161 [RFC7159] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 2162 Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March 2163 2014, . 2165 [RFC7230] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 2166 Protocol (HTTP/1.1): Message Syntax and Routing", 2167 RFC 7230, DOI 10.17487/RFC7230, June 2014, 2168 . 2170 [RFC7235] Fielding, R., Ed. and J. Reschke, Ed., "Hypertext Transfer 2171 Protocol (HTTP/1.1): Authentication", RFC 7235, 2172 DOI 10.17487/RFC7235, June 2014, 2173 . 2175 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 2176 DOI 10.17487/RFC7493, March 2015, 2177 . 2179 [RFC8030] Thomson, M., Damaggio, E., and B. Raymor, Ed., "Generic 2180 Event Delivery Using HTTP Push", RFC 8030, 2181 DOI 10.17487/RFC8030, December 2016, 2182 . 2184 [RFC8291] Thomson, M., "Message Encryption for Web Push", RFC 8291, 2185 DOI 10.17487/RFC8291, November 2017, 2186 . 2188 8.2. URIs 2190 [1] https://html.spec.whatwg.org/multipage/server-sent-events.html 2192 Author's Address 2194 Neil Jenkins 2195 FastMail 2196 Level 2, 114 William St 2197 Melbourne VIC 3000 2198 Australia 2200 Email: neilj@fastmailteam.com 2201 URI: https://www.fastmail.com