Skip to content

@shutter-network/concorde/http-channel

The HTTP routes this component serves: 2 on the Public server.

Every path is relative. Each one is printed as the plugin declares it, under whatever prefix the component's constructor registers that plugin at. This page states no mount point, because the constructor is where the mount point is decided.

Generated from what the route plugins in src/http-channel/routes.ts declare, which is what a running Gateway serves at GET /openapi.json. Never edited by hand.

Public server

The Public server is what a User's client calls. Which credential each route wants, and which wants none, is in that route's own description below.

GET /

Read your own Message log

The presented User's own Messages, both directions, in the single numbered sequence that is their log. There is no user parameter and nothing to omit. The log read is the one the Token names. No User can read another's by any spelling of the request. ?user= is refused as the unknown parameter it is. Three cursor cases, one order. No cursor answers the newest page, which is what a client opening a conversation wants. before=N answers the newest page strictly below N, which is scrolling back. after=N walks forwards from N, which is polling, and after=0 is how a log is read from its beginning, since nothing is numbered 0 and no cursor at all means the newest page instead. All three answer ascending by seq, so a client concatenates pages without reversing anything. Passing after and before together is a 400, because it describes two windows rather than one. The envelope carries no more-results flag, because a full page is one. messages.length === limit means there may be more. The next request is this one with the cursor moved on. after takes the largest seq received, to walk forwards. before takes the smallest, to walk back. A short page is the end of that direction for now. There is no read state of any kind (no stored position, no unread count and no receipts). So the cursor a client needs is one it already holds, because it is holding the Messages. limit defaults to 50 and is capped at 200. A larger value is refused with a 400 rather than quietly reduced. The Messages past the cap are reachable by paging rather than lost. This is the one list in the framework with a cursor. A Message log is read by cursor and cannot be searched or filtered. The parameters are a window over one User's seq, and there is no full-text or field matching. Requires a bearer Token, presented as Authorization: Bearer <token> and obtained from POST /auth/tokens. The User acted on is the one the Gateway authenticated, and no parameter anywhere names another. An unknown query parameter is a 400, not a filter that did nothing and a request answered with everything.

Tagged Messages.

Query parameters

  • after integer, optional, 0 to 2147483647

    Walk forwards from this seq, exclusive: the poll. after=0 reads the log from its beginning, oldest first, which no other spelling expresses.

  • before integer, optional, 0 to 2147483647

    The newest page strictly below this seq: scrolling back. Answers ascending like every other case, so the page before the one in hand arrives the same way up.

  • limit integer, optional, 1 to 200, default 50

Responses

200 application/json

The window that matched, ascending by seq, with both directions interleaved as the one log they are.

  • messages array of object, required
    • id string, required

    • userId string, required

    • direction string, required, one of "inbound", "outbound"

      Which way it travelled. inbound is the User to the agent and outbound is the agent to the User, and only a User can cause an inbound one. Decided by the server the request arrived on rather than by any field, so there is nothing anywhere for a caller to set.

    • seq integer, required

      This Message's number in one User's log, from 1, counting both directions. It is the cursor: the largest one held is what after takes to read whatever has arrived since. It is not global and no other User's activity moves it, so two Users' Messages are not orderable against each other by it.

    • text string, required

    • createdAt string, required

400 application/json

A cursor or limit is not an integer or is out of range, both cursors were passed, or a parameter this route does not take was written, user among them, since this route has none.

  • statusCode integer, required
  • error string, required
  • message string, required

401 application/json

Authentication failed, which is the whole of what is said: a wrong password, an id nobody holds, a User with no password, and a Token that is missing, malformed, unknown or expired are one status and one message, so nothing here answers who exists. This part authenticates nobody: the refusal is publicServer.requireUser, taken as one option on the route, so it is the same 401 every protected route on this server answers, whichever scheme the deployment accepts.

  • statusCode integer, required
  • error string, required
  • message string, required

POST /

Submit a Message

An inbound Message from the User the presented Token names. There is no field for the submitting User and nowhere for one to arrive. The id comes from the Token and from nothing a client can write, which is what makes the attribution trustworthy. A userId written into the body is stripped before the handler and reaches nothing. The Message and the Signal that wakes the agent for it are one transaction. A Message that was stored always has one. What the agent makes of it is not this response. An answer arrives on the log as an outbound Message whenever it arrives, which is what after=<seq> is for. Requires a bearer Token, presented as Authorization: Bearer <token> and obtained from POST /auth/tokens. The User acted on is the one the Gateway authenticated, and no parameter anywhere names another. An unknown query parameter is a 400, not a filter that did nothing and a request answered with everything.

Tagged Messages.

Request body

application/json, required.

  • text string, required, at least 1 character

Responses

201 application/json

The Message as it was stored, including the seq it was given. That number is the cursor to poll from for the answer.

  • id string, required

  • userId string, required

  • direction string, required, one of "inbound", "outbound"

    Which way it travelled. inbound is the User to the agent and outbound is the agent to the User, and only a User can cause an inbound one. Decided by the server the request arrived on rather than by any field, so there is nothing anywhere for a caller to set.

  • seq integer, required

    This Message's number in one User's log, from 1, counting both directions. It is the cursor: the largest one held is what after takes to read whatever has arrived since. It is not global and no other User's activity moves it, so two Users' Messages are not orderable against each other by it.

  • text string, required

  • createdAt string, required

400 application/json

text is missing or empty, or a query parameter was written.

  • statusCode integer, required
  • error string, required
  • message string, required

401 application/json

Authentication failed, which is the whole of what is said: a wrong password, an id nobody holds, a User with no password, and a Token that is missing, malformed, unknown or expired are one status and one message, so nothing here answers who exists. This part authenticates nobody: the refusal is publicServer.requireUser, taken as one option on the route, so it is the same 401 every protected route on this server answers, whichever scheme the deployment accepts.

  • statusCode integer, required
  • error string, required
  • message string, required

503 application/json

The Message was not recorded, and sending it again is the right thing to do. Nothing is wrong with the request and the log is intact: seq is computed per User inside the insert and a unique constraint makes a lost race visible, so this is one User's own concurrent writers outrunning a bounded retry. A 503 and not a 500 for that reason.

  • statusCode integer, required
  • error string, required
  • message string, required