Can't use result reference for accountId

Issue Description

Trying to pass accountId as

"#accountId": {
  "resultOf": "c0",
  "name": "Principal/query",
  "path": "/ids/0"
}

does not work

Expected Behavior

result reference is resolved correctly

Actual Behavior

{
  "type": "invalidArguments",
  "description": "The \"accountId\" property is required."
}

Stalwart Version

v0.16.x

You are correct that accountId is an argument like any other: RFC 8620 section 5.1 lists it under “It takes the following arguments”, alongside ids and properties. And section 3.7 defines back-references generically over arguments rather than over a fixed list of names, with the explicit requirement that “the server MUST first check the arguments object for any names beginning with ‘#’”. Stalwart does not do that today. It recognises a fixed set of back-reference keys (#ids, #properties, #mailboxIds, #emailIds and #destroy) and silently ignores anything else, which is why #accountId never reaches the method and you see “The accountId property is required” rather than a resolution error.

That said, the specific reference you are building would not give you the value you are after, even with generic # handling in place. Principal ids and Account ids are not the same thing. RFC 9670 section 2 defines a Principal’s id as “The id of the Principal”, and exposes the accounts it relates to through a separate accounts property, described as “A map of Account id to Account object for each JMAP Account containing data for this Principal that the user has access to”. Section 1.3 states that a Principal “may be associated with zero or more Accounts”, and section 1.5.2 defines accountIdForPrincipal and principalId as two distinct properties of the same object. So /ids/0 on a Principal/query response yields a principal id, and passing that as accountId is not what the specification intends.

There is also no way to reach an account id from a Principal response using a JSON Pointer. The only place a Principal exposes account ids is the accounts property, and there the ids are the keys of the map, not the values. A JSON Pointer can select a map value only by a key you already know, and the * extension defined in RFC 8620 section 3.7 applies only when “the currently referenced value is a JSON array”, so there is no token that enumerates object keys. The account ids you want are simply not addressable by any path expression over a Principal/query or Principal/get response, which is why no result reference operation exists that could produce an accountId from a Principal lookup.

In practice the account id has to come from somewhere the client already knows: the accounts object in the Session resource, the accountId echoed back in an earlier method response, or objectAccountId on a ShareNotification if you are reacting to a sharing change. For the flow you describe, the portable approach is to call Principal/get for the principal you found, read the keys of its accounts property, and use the one you want in a follow-up request.

To summarise, the particular chain from Principal/query into accountId is not something that can be made to work, because the value at /ids/0 is a principal id rather than an account id.

Also, there is the enhanced result references JMAP extension draft which would allow you to run the query you need. Please post to the IETF JMAP mailing list if you would like to see this draft published.

Stalwart does not do that today. It recognises a fixed set of back-reference keys

Will the full standard-conformant behavior be implemented at some point?

You’re right about the request being incorrect with its use of the principal ID. But a reference like the following work, assuming there is only one account for the given principal?

{
  "resultOf": "c1",
  "name": "Principal/get",
  "path": "/list/0/accounts/0/urn:ietf:params:jmap:principals:owner/accountIdForPrincipal"
}

If I remember correctly, Vandelay did something similar to get the account ID for a given email address.

Only if there is a result reference that could use fetch account ids, at the moment there are none. Feel free to post to the IETF WG mailing list if you would like the protocol to be extended for your use case.

That is not valid unfortunately, accounts are maps, not arrays, so they can’t be accessed by index.

Right, my bad.

Hm that feels weird, I mean sure maybe the hardcoded fields cover most use cases right now, but it’s still a divergence from the spec and I’m certain one could come up with various requests that use result references for other fields.

And considering that you yourself wrote the previously mentioned enhanced result references draft, I assume you are also interested in and planning to expand the possibilities here.