Documentation ¶
Index ¶
- Constants
- func GetJSONFieldStr(t ct.TestLike, body []byte, wantKey string) string
- func GetJSONFieldStringArray(t ct.TestLike, body []byte, wantKey string) []string
- func GjsonEscape(in string) string
- func NewLoggedClient(t ct.TestLike, hsName string, cli *http.Client) *http.Client
- func ParseJSON(t ct.TestLike, res *http.Response) []byte
- func SplitMxc(mxcUri string) (string, string)
- type CSAPI
- func (c *CSAPI) ConsumeRefreshToken(t ct.TestLike, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64)
- func (c *CSAPI) CreateMedia(t ct.TestLike) string
- func (c *CSAPI) CreateRoom(t ct.TestLike, body map[string]interface{}) *http.Response
- func (c *CSAPI) Do(t ct.TestLike, method string, paths []string, opts ...RequestOpt) *http.Response
- func (c *CSAPI) DownloadContent(t ct.TestLike, mxcUri string) ([]byte, string)
- func (c *CSAPI) DownloadContentAuthenticated(t ct.TestLike, mxcUri string) ([]byte, string)
- func (c *CSAPI) GetAllPushRules(t ct.TestLike) gjson.Result
- func (c *CSAPI) GetCapabilities(t ct.TestLike) []byte
- func (c *CSAPI) GetDefaultRoomVersion(t ct.TestLike) gomatrixserverlib.RoomVersion
- func (c *CSAPI) GetGlobalAccountData(t ct.TestLike, eventType string) *http.Response
- func (c *CSAPI) GetPushRule(t ct.TestLike, scope string, kind string, ruleID string) gjson.Result
- func (c *CSAPI) GetRoomAccountData(t ct.TestLike, roomID string, eventType string) *http.Response
- func (c *CSAPI) InviteRoom(t ct.TestLike, roomID string, userID string) *http.Response
- func (c *CSAPI) JoinRoom(t ct.TestLike, roomIDOrAlias string, serverNames []string) *http.Response
- func (c *CSAPI) LeaveRoom(t ct.TestLike, roomID string) *http.Response
- func (c *CSAPI) LoginUser(t ct.TestLike, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string)
- func (c *CSAPI) LoginUserWithRefreshToken(t ct.TestLike, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64)
- func (c *CSAPI) MustCreateRoom(t ct.TestLike, reqBody map[string]interface{}) string
- func (c *CSAPI) MustDo(t ct.TestLike, method string, paths []string, opts ...RequestOpt) *http.Response
- func (c *CSAPI) MustGenerateOneTimeKeys(t ct.TestLike, otkCount uint) (deviceKeys map[string]interface{}, oneTimeKeys map[string]interface{})
- func (c *CSAPI) MustGetGlobalAccountData(t ct.TestLike, eventType string) *http.Response
- func (c *CSAPI) MustGetRoomAccountData(t ct.TestLike, roomID string, eventType string) *http.Response
- func (c *CSAPI) MustInviteRoom(t ct.TestLike, roomID string, userID string)
- func (c *CSAPI) MustJoinRoom(t ct.TestLike, roomIDOrAlias string, serverNames []string) string
- func (c *CSAPI) MustLeaveRoom(t ct.TestLike, roomID string)
- func (c *CSAPI) MustSendRedaction(t ct.TestLike, roomID string, content map[string]interface{}, eventID string) string
- func (c *CSAPI) MustSendToDeviceMessages(t ct.TestLike, evType string, ...)
- func (c *CSAPI) MustSendTyping(t ct.TestLike, roomID string, isTyping bool, timeoutMillis int)
- func (c *CSAPI) MustSetGlobalAccountData(t ct.TestLike, eventType string, content map[string]interface{}) *http.Response
- func (c *CSAPI) MustSetRoomAccountData(t ct.TestLike, roomID string, eventType string, content map[string]interface{}) *http.Response
- func (c *CSAPI) MustSync(t ct.TestLike, syncReq SyncReq) (gjson.Result, string)
- func (c *CSAPI) MustSyncUntil(t ct.TestLike, syncReq SyncReq, checks ...SyncCheckOpt) string
- func (c *CSAPI) MustUploadKeys(t ct.TestLike, deviceKeys map[string]interface{}, ...) (otkCounts map[string]int)
- func (c *CSAPI) RegisterSharedSecret(t ct.TestLike, user, pass string, isAdmin bool) (userID, accessToken, deviceID string)
- func (c *CSAPI) RegisterUser(t ct.TestLike, localpart, password string) (userID, accessToken, deviceID string)
- func (c *CSAPI) SendEventSynced(t ct.TestLike, roomID string, e b.Event) string
- func (c *CSAPI) SendRedaction(t ct.TestLike, roomID string, content map[string]interface{}, eventID string) *http.Response
- func (c *CSAPI) SendToDeviceMessages(t ct.TestLike, evType string, ...) (errRes *http.Response)
- func (c *CSAPI) SendTyping(t ct.TestLike, roomID string, isTyping bool, timeoutMillis int) *http.Response
- func (c *CSAPI) SetPushRule(t ct.TestLike, scope string, kind string, ruleID string, ...) *http.Response
- func (c *CSAPI) Sync(t ct.TestLike, syncReq SyncReq) (gjson.Result, *http.Response)
- func (c *CSAPI) Unsafe_SendEventUnsynced(t ct.TestLike, roomID string, e b.Event) string
- func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t ct.TestLike, roomID string, e b.Event, txnID string) string
- func (c *CSAPI) UploadContent(t ct.TestLike, fileBody []byte, fileName string, contentType string) string
- func (c *CSAPI) UploadMediaAsync(t ct.TestLike, serverName, mediaID string, fileBody []byte, fileName string, ...)
- type LoginOpt
- type RequestOpt
- type SyncCheckOpt
- func SyncEphemeralHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
- func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt
- func SyncInvitedTo(userID, roomID string) SyncCheckOpt
- func SyncJoinedTo(userID, roomID string, checks ...func(gjson.Result) bool) SyncCheckOpt
- func SyncLeftFrom(userID, roomID string) SyncCheckOpt
- func SyncPresenceHas(fromUser string, expectedPresence *string, checks ...func(gjson.Result) bool) SyncCheckOpt
- func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
- func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
- func SyncTimelineHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
- func SyncTimelineHasEventID(roomID string, eventID string) SyncCheckOpt
- func SyncToDeviceHas(fromUser string, check func(gjson.Result) bool) SyncCheckOpt
- func SyncUsersTyping(roomID string, userIDs []string) SyncCheckOpt
- type SyncReq
Constants ¶
const (
CtxKeyWithRetryUntil ctxKey = "complement_retry_until" // contains *retryUntilParams
)
const (
)Variables ¶
This section is empty.
Functions ¶
func GetJSONFieldStr ¶
GetJSONFieldStr extracts a value from a byte-encoded JSON body given a search key
func GetJSONFieldStringArray ¶
func GjsonEscape ¶
GjsonEscape escapes . and * from the input so it can be used with gjson.Get
func NewLoggedClient ¶
NewLoggedClient returns an http.Client which logs requests/responses
Types ¶
type CSAPI ¶
type CSAPI struct { UserID string AccessToken string DeviceID string Password string // if provided BaseURL string Client *http.Client // how long are we willing to wait for MustSyncUntil.... calls SyncUntilTimeout time.Duration // True to enable verbose logging Debug bool // contains filtered or unexported fields }
func (*CSAPI) ConsumeRefreshToken ¶
func (c *CSAPI) ConsumeRefreshToken(t ct.TestLike, refreshToken string) (newAccessToken, newRefreshToken string, expiresInMs int64)
RefreshToken will consume a refresh token and return a new access token and refresh token.
func (*CSAPI) CreateMedia ¶
CreateMedia creates an MXC URI for asynchronous media uploads.
func (*CSAPI) CreateRoom ¶
CreateRoom creates a room with an optional HTTP request body.
func (*CSAPI) Do ¶
Do performs an arbitrary HTTP request to the server. This function supports RequestOpts to set extra information on the request such as an HTTP request body, query parameters and content-type. See all functions in this package starting with `With...`.
Fails the test if an HTTP request could not be made or if there was a network error talking to the server. To do assertions on the HTTP response, see the `must` package. For example:
must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 400, JSON: []match.JSON{ match.JSONKeyEqual("errcode", "M_INVALID_USERNAME"), }, })
func (*CSAPI) DownloadContent ¶
DownloadContent downloads media from the server, returning the raw bytes and the Content-Type. Fails the test on error.
func (*CSAPI) DownloadContentAuthenticated ¶
DownloadContentAuthenticated downloads media from _matrix/client/v1/media resource, returning the raw bytes and the Content-Type. Fails the test on error.
func (*CSAPI) GetAllPushRules ¶
GetAllPushRules fetches all configured push rules for a user from the homeserver. Push rules are returned as a parsed gjson result
Example of printing the IDs of all underride rules of the current user:
allPushRules := c.GetAllPushRules(t) globalUnderridePushRules := allPushRules.Get("global").Get("underride").Array() for index, rule := range globalUnderridePushRules { fmt.Printf("This rule's ID is: %s\n", rule.Get("rule_id").Str) }
Push rules are returned in the same order received from the homeserver.
func (*CSAPI) GetCapabilities ¶
GetCapbabilities queries the server's capabilities
func (*CSAPI) GetDefaultRoomVersion ¶
func (c *CSAPI) GetDefaultRoomVersion(t ct.TestLike) gomatrixserverlib.RoomVersion
GetDefaultRoomVersion returns the server's default room version
func (*CSAPI) GetGlobalAccountData ¶
func (*CSAPI) GetPushRule ¶
GetPushRule queries the contents of a client's push rule by scope, kind and rule ID. A parsed gjson result is returned. Fails the test if the query to server returns a non-2xx status code.
Example of checking that a global underride rule contains the expected actions:
containsDisplayNameRule := c.GetPushRule(t, "global", "underride", ".m.rule.contains_display_name") must.MatchGJSON( t, containsDisplayNameRule, match.JSONKeyEqual("actions", []interface{}{ "notify", map[string]interface{}{"set_tweak": "sound", "value": "default"}, map[string]interface{}{"set_tweak": "highlight"}, }), )
func (*CSAPI) GetRoomAccountData ¶
func (*CSAPI) InviteRoom ¶
InviteRoom invites userID to the room ID, else fails the test.
func (*CSAPI) LoginUser ¶
func (c *CSAPI) LoginUser(t ct.TestLike, localpart, password string, opts ...LoginOpt) (userID, accessToken, deviceID string)
LoginUser will log in to a homeserver and create a new device on an existing user.
func (*CSAPI) LoginUserWithRefreshToken ¶
func (c *CSAPI) LoginUserWithRefreshToken(t ct.TestLike, localpart, password string) (userID, accessToken, refreshToken, deviceID string, expiresInMs int64)
LoginUserWithRefreshToken will log in to a homeserver, with refresh token enabled, and create a new device on an existing user.
func (*CSAPI) MustCreateRoom ¶
MustCreateRoom creates a room with an optional HTTP request body. Fails the test on error. Returns the room ID.
func (*CSAPI) MustDo ¶
func (c *CSAPI) MustDo(t ct.TestLike, method string, paths []string, opts ...RequestOpt) *http.Response
MustDo is the same as Do but fails the test if the returned HTTP response code is not 2xx.
func (*CSAPI) MustGenerateOneTimeKeys ¶
func (c *CSAPI) MustGenerateOneTimeKeys(t ct.TestLike, otkCount uint) (deviceKeys map[string]interface{}, oneTimeKeys map[string]interface{})
Generate realistic looking device keys and OTKs. They are not guaranteed to be 100% valid, but should pass most server-side checks. Critically, these keys are generated using a Pseudo-Random Number Generator (PRNG) for determinism and hence ARE NOT SECURE. DO NOT USE THIS OUTSIDE OF TESTS.
func (*CSAPI) MustGetGlobalAccountData ¶
func (*CSAPI) MustGetRoomAccountData ¶
func (*CSAPI) MustInviteRoom ¶
InviteRoom invites userID to the room ID, else fails the test.
func (*CSAPI) MustJoinRoom ¶
MustJoinRoom joins the room ID or alias given, else fails the test. Returns the room ID.
func (*CSAPI) MustLeaveRoom ¶
MustLeaveRoom leaves the room ID, else fails the test.
func (*CSAPI) MustSendRedaction ¶
func (c *CSAPI) MustSendRedaction(t ct.TestLike, roomID string, content map[string]interface{}, eventID string) string
SendRedaction sends a redaction request. Will fail if the returned HTTP request code is not 200. Returns the event ID of the redaction event.
func (*CSAPI) MustSendToDeviceMessages ¶
func (c *CSAPI) MustSendToDeviceMessages(t ct.TestLike, evType string, messages map[string]map[string]map[string]interface{})
SendToDeviceMessages sends to-device messages over /sendToDevice/.
The messages parameter is nested as follows: user_id -> device_id -> content (map[string]interface{})
func (*CSAPI) MustSendTyping ¶
MustSendTyping marks this user as typing until the timeout is reached. If isTyping is false, timeout is ignored.
func (*CSAPI) MustSetGlobalAccountData ¶
func (*CSAPI) MustSetRoomAccountData ¶
func (*CSAPI) MustSync ¶
Perform a single /sync request with the given request options. To sync until something happens, see `MustSyncUntil`.
Fails the test if the /sync request does not return 200 OK. Returns the top-level parsed /sync response JSON as well as the next_batch token from the response.
func (*CSAPI) MustSyncUntil ¶
MustSyncUntil blocks and continually calls /sync (advancing the since token) until all the check functions return no error. Returns the final/latest since token.
Initial /sync example: (no since token)
bob.InviteRoom(t, roomID, alice.UserID) alice.JoinRoom(t, roomID, nil) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID))
Incremental /sync example: (test controls since token)
since := alice.MustSyncUntil(t, client.SyncReq{TimeoutMillis: "0"}) // get a since token bob.InviteRoom(t, roomID, alice.UserID) since = alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncInvitedTo(alice.UserID, roomID)) alice.JoinRoom(t, roomID, nil) alice.MustSyncUntil(t, client.SyncReq{Since: since}, client.SyncJoinedTo(alice.UserID, roomID))
Checking multiple parts of /sync:
alice.MustSyncUntil( t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID), client.SyncJoinedTo(alice.UserID, roomID2), client.SyncJoinedTo(alice.UserID, roomID3), )
Check functions are unordered and independent. Once a check function returns true it is removed from the list of checks and won't be called again.
In the unlikely event that you want all the checkers to pass *explicitly* in a single /sync response (e.g to assert some form of atomic update which updates multiple parts of the /sync response at once) then make your own checker function which does this.
In the unlikely event that you need ordering on your checks, call MustSyncUntil multiple times with a single checker, and reuse the returned since token, as in the "Incremental sync" example.
Will time out after CSAPI.SyncUntilTimeout. Returns the `next_batch` token from the final response.
func (*CSAPI) MustUploadKeys ¶
func (*CSAPI) RegisterSharedSecret ¶
func (c *CSAPI) RegisterSharedSecret(t ct.TestLike, user, pass string, isAdmin bool) (userID, accessToken, deviceID string)
RegisterSharedSecret registers a new account with a shared secret via HMAC See https://github.com/matrix-org/synapse/blob/e550ab17adc8dd3c48daf7fedcd09418a73f524b/synapse/_scripts/register_new_matrix_user.py#L40
func (*CSAPI) RegisterUser ¶
func (c *CSAPI) RegisterUser(t ct.TestLike, localpart, password string) (userID, accessToken, deviceID string)
RegisterUser will register the user with given parameters and return user ID, access token and device ID. It fails the test on network error.
func (*CSAPI) SendEventSynced ¶
SendEventSynced sends `e` into the room and waits for its event ID to come down /sync. Returns the event ID of the sent event.
func (*CSAPI) SendRedaction ¶
func (c *CSAPI) SendRedaction(t ct.TestLike, roomID string, content map[string]interface{}, eventID string) *http.Response
SendRedaction sends a redaction request.
func (*CSAPI) SendToDeviceMessages ¶
func (c *CSAPI) SendToDeviceMessages(t ct.TestLike, evType string, messages map[string]map[string]map[string]interface{}) (errRes *http.Response)
SendToDeviceMessages sends to-device messages over /sendToDevice/.
The messages parameter is nested as follows: user_id -> device_id -> content (map[string]interface{})
func (*CSAPI) SendTyping ¶
func (c *CSAPI) SendTyping(t ct.TestLike, roomID string, isTyping bool, timeoutMillis int) *http.Response
SendTyping marks this user as typing until the timeout is reached. If isTyping is false, timeout is ignored.
func (*CSAPI) SetPushRule ¶
func (c *CSAPI) SetPushRule(t ct.TestLike, scope string, kind string, ruleID string, body map[string]interface{}, before string, after string) *http.Response
SetPushRule creates a new push rule on the user, or modifies an existing one. If `before` or `after` parameters are not set to an empty string, their values will be set as the `before` and `after` query parameters respectively on the "set push rules" client endpoint: https://spec.matrix.org/v1.5/client-server-api/#put_matrixclientv3pushrulesscopekindruleid
Example of setting a push rule with ID 'com.example.rule2' that must come after 'com.example.rule1':
c.SetPushRule(t, "global", "underride", "com.example.rule2", map[string]interface{}{ "actions": []string{"dont_notify"}, }, nil, "com.example.rule1")
func (*CSAPI) Sync ¶
Perform a single /sync request with the given request options. To sync until something happens, see `MustSyncUntil`.
Always returns the HTTP response, even on non-2xx. Returns the top-level parsed /sync response JSON on 2xx.
func (*CSAPI) Unsafe_SendEventUnsynced ¶
Unsafe_SendEventUnsynced sends `e` into the room. This function is UNSAFE as it does not wait for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`. Returns the event ID of the sent event.
func (*CSAPI) Unsafe_SendEventUnsyncedWithTxnID ¶
func (c *CSAPI) Unsafe_SendEventUnsyncedWithTxnID(t ct.TestLike, roomID string, e b.Event, txnID string) string
SendEventUnsyncedWithTxnID sends `e` into the room with a prescribed transaction ID. This is useful for writing tests that interrogate transaction semantics. This function is UNSAFE as it does not wait for the event to be fully processed. This can cause flakey tests. Prefer `SendEventSynced`. Returns the event ID of the sent event.
type RequestOpt ¶
RequestOpt is a functional option which will modify an outgoing HTTP request. See functions starting with `With...` in this package for more info.
func WithContentType ¶
func WithContentType(cType string) RequestOpt
WithContentType sets the HTTP request Content-Type header to `cType`
func WithJSONBody ¶
func WithJSONBody(t ct.TestLike, obj interface{}) RequestOpt
WithJSONBody sets the HTTP request body to the JSON serialised form of `obj`
func WithQueries ¶
func WithQueries(q url.Values) RequestOpt
WithQueries sets the query parameters on the request. This function should not be used to set an "access_token" parameter for Matrix authentication. Instead, set CSAPI.AccessToken.
func WithRawBody ¶
func WithRawBody(body []byte) RequestOpt
WithRawBody sets the HTTP request body to `body`
func WithRetryUntil ¶
WithRetryUntil will retry the request until the provided function returns true. Times out after `timeout`, which will then fail the test.
type SyncCheckOpt ¶
SyncCheckOpt is a functional option for use with MustSyncUntil which should return <nil> if the response satisfies the check, else return a human friendly error. The result object is the entire /sync response from this request.
func SyncEphemeralHas ¶
func SyncEphemeralHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
func SyncGlobalAccountDataHas ¶
func SyncGlobalAccountDataHas(check func(gjson.Result) bool) SyncCheckOpt
Calls the `check` function for each global account data event, and returns with success if the `check` function returns true for at least one event.
func SyncInvitedTo ¶
func SyncInvitedTo(userID, roomID string) SyncCheckOpt
Checks that `userID` gets invited to `roomID`.
This checks different parts of the /sync response depending on the client making the request. If the client is also the person being invited to the room then the 'invite' block will be inspected. If the client is different to the person being invited then the 'join' block will be inspected.
func SyncJoinedTo ¶
func SyncJoinedTo(userID, roomID string, checks ...func(gjson.Result) bool) SyncCheckOpt
Check that `userID` gets joined to `roomID` by inspecting the join timeline for a membership event.
Additional checks can be passed to narrow down the check, all must pass.
func SyncLeftFrom ¶
func SyncLeftFrom(userID, roomID string) SyncCheckOpt
Check that `userID` is leaving `roomID` by inspecting the timeline for a membership event, or witnessing `roomID` in `rooms.leave` Note: This will not work properly with initial syncs, see https://github.com/matrix-org/matrix-doc/issues/3537
func SyncPresenceHas ¶
func SyncPresenceHas(fromUser string, expectedPresence *string, checks ...func(gjson.Result) bool) SyncCheckOpt
Check that the sync contains presence from a user, optionally with an expected presence (set to nil to not check), and optionally with extra checks.
func SyncRoomAccountDataHas ¶
func SyncRoomAccountDataHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
Calls the `check` function for each account data event for the given room, and returns with success if the `check` function returns true for at least one event.
func SyncStateHas ¶
func SyncStateHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
Check that the state section for `roomID` has an event which passes the check function. Note that the state section of a sync response only contains the change in state up to the start of the timeline and will not contain the entire state of the room for incremental or `lazy_load_members` syncs.
func SyncTimelineHas ¶
func SyncTimelineHas(roomID string, check func(gjson.Result) bool) SyncCheckOpt
Check that the timeline for `roomID` has an event which passes the check function.
func SyncTimelineHasEventID ¶
func SyncTimelineHasEventID(roomID string, eventID string) SyncCheckOpt
Check that the timeline for `roomID` has an event which matches the event ID.
func SyncToDeviceHas ¶
func SyncToDeviceHas(fromUser string, check func(gjson.Result) bool) SyncCheckOpt
Check that sync has received a to-device message, with optional user filtering.
If fromUser == "", all messages will be passed through to the check function. `check` will be called for all messages that have passed the filter.
`check` gets passed the full event, including sender and type.
func SyncUsersTyping ¶
func SyncUsersTyping(roomID string, userIDs []string) SyncCheckOpt
SyncUsersTyping passes when all users in `userIDs` are typing in the same typing EDU. It must see a typing EDU first before returning, even if the list of user IDs is empty.
type SyncReq ¶
type SyncReq struct { // A point in time to continue a sync from. This should be the next_batch token returned by an // earlier call to this endpoint. Since string // The ID of a filter created using the filter API or a filter JSON object encoded as a string. // The server will detect whether it is an ID or a JSON object by whether the first character is // a "{" open brace. Passing the JSON inline is best suited to one off requests. Creating a // filter using the filter API is recommended for clients that reuse the same filter multiple // times, for example in long poll requests. Filter string // Controls whether to include the full state for all rooms the user is a member of. // If this is set to true, then all state events will be returned, even if since is non-empty. // The timeline will still be limited by the since parameter. In this case, the timeout parameter // will be ignored and the query will return immediately, possibly with an empty timeline. // If false, and since is non-empty, only state which has changed since the point indicated by // since will be returned. // By default, this is false. FullState bool // Controls whether the client is automatically marked as online by polling this API. If this // parameter is omitted then the client is automatically marked as online when it uses this API. // Otherwise if the parameter is set to “offline” then the client is not marked as being online // when it uses this API. When set to “unavailable”, the client is marked as being idle. // One of: [offline online unavailable]. SetPresence string // The maximum time to wait, in milliseconds, before returning this request. If no events // (or other data) become available before this time elapses, the server will return a response // with empty fields. // By default, this is 1000 for Complement testing. TimeoutMillis string // string for easier conversion to query params }
SyncReq contains all the /sync request configuration options. The empty struct `SyncReq{}` is valid which will do a full /sync due to lack of a since token.