@myronsi/messenger-api 2.0.0-alpha.6.next.48 → 2.0.0-alpha.8.next.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  Contract changes only. The backend changelog is `CHANGELOG.md` in the repository root. Rules: `docs/api-compatibility.md`.
4
4
 
5
+ ## 2.0.0-alpha.8
6
+
7
+ Found by validating every response of the backend's HTTP tests against this contract:
8
+
9
+ - `GET /attachments/{attachment_id}/content` and `GET /users/{user_id}/avatar` list `206` (byte ranges), `304`
10
+ (`ETag`) and `416`; the attachment download also its `302` to a signed URL.
11
+ - `POST /ws/ticket` answers `201`, as listed (the server sent `200`).
12
+ - The conventions name the statuses any operation may answer: `413`, `415`, `500`, `503`.
13
+
14
+ ## 2.0.0-alpha.7
15
+
16
+ Search:
17
+
18
+ - New `GET /search/messages`: full-text search across all chats of the caller, with filters (`chat_id`, `sender_id`,
19
+ `type`, `from`, `to`) and `search_after` paging.
20
+ - `SearchHit.highlight` wraps the matched words in U+E000 and U+E001.
21
+ - `GET /chats/{chat_id}/messages/search` can answer `429` (searches are rate limited).
22
+
5
23
  ## 2.0.0-alpha.6
6
24
 
7
25
  Groups, found while implementing them:
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /* Generated from api/openapi.yaml 2.0.0-alpha.6. Do not edit. */
2
- export declare const API_VERSION: "2.0.0-alpha.6";
1
+ /* Generated from api/openapi.yaml 2.0.0-alpha.8. Do not edit. */
2
+ export declare const API_VERSION: "2.0.0-alpha.8";
3
3
  export type { paths, components, operations } from "./schema.js";
4
4
  export * from "./ws-events.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export const API_VERSION = "2.0.0-alpha.6";
1
+ export const API_VERSION = "2.0.0-alpha.8";
package/dist/openapi.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  openapi: 3.1.0
2
2
  info:
3
3
  title: Messenger API
4
- version: 2.0.0-alpha.6
4
+ version: 2.0.0-alpha.8
5
5
  summary: REST contract of the Messenger backend (v2).
6
6
  description: |
7
7
  Contract for the Go backend. The WebSocket protocol is described in `websocket/` and
@@ -25,6 +25,10 @@ info:
25
25
  `min_client_api_version` gets `426` with `code: client_outdated`.
26
26
  - Files are never referenced by a client-supplied URL: upload with `POST /attachments`,
27
27
  then refer to the returned `attachment_id`.
28
+ - Statuses any operation may answer, not repeated per operation: `413` (body over the size
29
+ limit, `payload_too_large`) and `415` (a body that is not `application/json`,
30
+ `unsupported_media_type`) for operations with a body; `500` (a bug) and `503` (a store is
31
+ away; retry after `Retry-After`) for all.
28
32
  license:
29
33
  name: MIT
30
34
  identifier: MIT
@@ -744,6 +748,15 @@ paths:
744
748
  content:
745
749
  image/*:
746
750
  schema: { type: string, format: binary }
751
+ "206":
752
+ description: The requested byte range (`Range` header)
753
+ content:
754
+ image/*:
755
+ schema: { type: string, format: binary }
756
+ "304":
757
+ description: Not modified (`If-None-Match` with the `ETag` of an earlier answer)
758
+ "416":
759
+ description: The requested range is outside the file
747
760
  "401": { $ref: "#/components/responses/Unauthorized" }
748
761
  "404": { $ref: "#/components/responses/NotFound" }
749
762
  /users/{user_id}/avatars:
@@ -872,6 +885,17 @@ paths:
872
885
  content:
873
886
  application/octet-stream:
874
887
  schema: { type: string, format: binary }
888
+ "206":
889
+ description: The requested byte range (`Range` header); players use it to seek
890
+ content:
891
+ application/octet-stream:
892
+ schema: { type: string, format: binary }
893
+ "304":
894
+ description: Not modified (`If-None-Match` with the `ETag` of an earlier answer)
895
+ "416":
896
+ description: The requested range is outside the file
897
+ "302":
898
+ description: Redirect to a short-lived signed URL of object storage (`MEDIA_SIGNED_URLS`); not cached
875
899
  "401": { $ref: "#/components/responses/Unauthorized" }
876
900
  "403": { $ref: "#/components/responses/Forbidden" }
877
901
  "404": { $ref: "#/components/responses/NotFound" }
@@ -1127,6 +1151,7 @@ paths:
1127
1151
  "401": { $ref: "#/components/responses/Unauthorized" }
1128
1152
  "404": { $ref: "#/components/responses/NotFound" }
1129
1153
  "422": { $ref: "#/components/responses/ValidationFailed" }
1154
+ "429": { $ref: "#/components/responses/TooManyRequests" }
1130
1155
  /chats/{chat_id}/media:
1131
1156
  parameters:
1132
1157
  - $ref: "#/components/parameters/ClientVersion"
@@ -1240,6 +1265,62 @@ paths:
1240
1265
  "422": { $ref: "#/components/responses/ValidationFailed" }
1241
1266
  "429": { $ref: "#/components/responses/TooManyRequests" }
1242
1267
 
1268
+ # -------------------------------------------------------------- search
1269
+ /search/messages:
1270
+ parameters:
1271
+ - $ref: "#/components/parameters/ClientVersion"
1272
+ - $ref: "#/components/parameters/ClientApiVersion"
1273
+ get:
1274
+ tags: [messages]
1275
+ operationId: searchAllMessages
1276
+ summary: Search messages in all my chats
1277
+ description: |
1278
+ Full-text search across every chat the caller is in, newest first. Only chats the caller
1279
+ is a member of are searched, messages they deleted for themselves are left out, and every
1280
+ hit is checked against the message store before it is returned (a deleted message never
1281
+ shows, even when the index lags behind). Edits and deletions reach the results within a
1282
+ few seconds.
1283
+ parameters:
1284
+ - name: q
1285
+ in: query
1286
+ required: true
1287
+ schema: { type: string, minLength: 2, maxLength: 128 }
1288
+ - name: chat_id
1289
+ in: query
1290
+ description: Only this chat
1291
+ schema: { $ref: "#/components/schemas/Id" }
1292
+ - name: sender_id
1293
+ in: query
1294
+ description: Only messages of this user
1295
+ schema: { $ref: "#/components/schemas/Id" }
1296
+ - name: type
1297
+ in: query
1298
+ schema:
1299
+ type: string
1300
+ enum: [text, file, voice]
1301
+ - name: from
1302
+ in: query
1303
+ description: Messages created at or after this time
1304
+ schema: { $ref: "#/components/schemas/Timestamp" }
1305
+ - name: to
1306
+ in: query
1307
+ description: Messages created before this time
1308
+ schema: { $ref: "#/components/schemas/Timestamp" }
1309
+ - $ref: "#/components/parameters/Limit"
1310
+ - $ref: "#/components/parameters/After"
1311
+ responses:
1312
+ "426": { $ref: "#/components/responses/ClientOutdated" }
1313
+ "400": { $ref: "#/components/responses/BadRequest" }
1314
+ "200":
1315
+ description: Matches, newest first
1316
+ content:
1317
+ application/json:
1318
+ schema: { $ref: "#/components/schemas/MessageSearchPage" }
1319
+ "401": { $ref: "#/components/responses/Unauthorized" }
1320
+ "404": { $ref: "#/components/responses/NotFound" }
1321
+ "422": { $ref: "#/components/responses/ValidationFailed" }
1322
+ "429": { $ref: "#/components/responses/TooManyRequests" }
1323
+
1243
1324
  # ------------------------------------------------------------ requests
1244
1325
  /requests:
1245
1326
  parameters:
@@ -2196,7 +2277,11 @@ components:
2196
2277
  message: { $ref: "#/components/schemas/Message" }
2197
2278
  highlight:
2198
2279
  type: [string, "null"]
2199
- description: Plain-text excerpt; never HTML.
2280
+ description: |
2281
+ Plain-text excerpt of the matching text or file name; never HTML. The matched words are
2282
+ wrapped in U+E000 (start) and U+E001 (end), characters of the Unicode private use area,
2283
+ so a client can mark them without parsing markup. `null` when the message matched without
2284
+ an excerpt.
2200
2285
  MessageSearchPage:
2201
2286
  type: object
2202
2287
  required: [items, next_cursor]
package/dist/schema.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /* Generated from api/openapi.yaml 2.0.0-alpha.6. Do not edit. */
1
+ /* Generated from api/openapi.yaml 2.0.0-alpha.8. Do not edit. */
2
2
  export interface paths {
3
3
  "/meta": {
4
4
  parameters: {
@@ -990,6 +990,35 @@ export interface paths {
990
990
  patch?: never;
991
991
  trace?: never;
992
992
  };
993
+ "/search/messages": {
994
+ parameters: {
995
+ query?: never;
996
+ header?: {
997
+ /** @description Version of the client app, for logs and the per-client metric. */
998
+ "X-Client-Version"?: components["parameters"]["ClientVersion"];
999
+ /** @description Contract version the client was built with (`API_VERSION` of `@myronsi/messenger-api`). A different MAJOR or a version below `min_client_api_version` is answered with `426`; a malformed value with `400` (`invalid_client_version`). */
1000
+ "X-Client-Api-Version"?: components["parameters"]["ClientApiVersion"];
1001
+ };
1002
+ path?: never;
1003
+ cookie?: never;
1004
+ };
1005
+ /**
1006
+ * Search messages in all my chats
1007
+ * @description Full-text search across every chat the caller is in, newest first. Only chats the caller
1008
+ * is a member of are searched, messages they deleted for themselves are left out, and every
1009
+ * hit is checked against the message store before it is returned (a deleted message never
1010
+ * shows, even when the index lags behind). Edits and deletions reach the results within a
1011
+ * few seconds.
1012
+ */
1013
+ get: operations["searchAllMessages"];
1014
+ put?: never;
1015
+ post?: never;
1016
+ delete?: never;
1017
+ options?: never;
1018
+ head?: never;
1019
+ patch?: never;
1020
+ trace?: never;
1021
+ };
993
1022
  "/requests": {
994
1023
  parameters: {
995
1024
  query?: never;
@@ -1550,7 +1579,12 @@ export interface components {
1550
1579
  };
1551
1580
  SearchHit: {
1552
1581
  message: components["schemas"]["Message"];
1553
- /** @description Plain-text excerpt; never HTML. */
1582
+ /**
1583
+ * @description Plain-text excerpt of the matching text or file name; never HTML. The matched words are
1584
+ * wrapped in U+E000 (start) and U+E001 (end), characters of the Unicode private use area,
1585
+ * so a client can mark them without parsing markup. `null` when the message matched without
1586
+ * an excerpt.
1587
+ */
1554
1588
  highlight?: string | null;
1555
1589
  };
1556
1590
  MessageSearchPage: {
@@ -2769,9 +2803,32 @@ export interface operations {
2769
2803
  "image/*": string;
2770
2804
  };
2771
2805
  };
2806
+ /** @description The requested byte range (`Range` header) */
2807
+ 206: {
2808
+ headers: {
2809
+ [name: string]: unknown;
2810
+ };
2811
+ content: {
2812
+ "image/*": string;
2813
+ };
2814
+ };
2815
+ /** @description Not modified (`If-None-Match` with the `ETag` of an earlier answer) */
2816
+ 304: {
2817
+ headers: {
2818
+ [name: string]: unknown;
2819
+ };
2820
+ content?: never;
2821
+ };
2772
2822
  400: components["responses"]["BadRequest"];
2773
2823
  401: components["responses"]["Unauthorized"];
2774
2824
  404: components["responses"]["NotFound"];
2825
+ /** @description The requested range is outside the file */
2826
+ 416: {
2827
+ headers: {
2828
+ [name: string]: unknown;
2829
+ };
2830
+ content?: never;
2831
+ };
2775
2832
  426: components["responses"]["ClientOutdated"];
2776
2833
  };
2777
2834
  };
@@ -2942,10 +2999,40 @@ export interface operations {
2942
2999
  "application/octet-stream": string;
2943
3000
  };
2944
3001
  };
3002
+ /** @description The requested byte range (`Range` header); players use it to seek */
3003
+ 206: {
3004
+ headers: {
3005
+ [name: string]: unknown;
3006
+ };
3007
+ content: {
3008
+ "application/octet-stream": string;
3009
+ };
3010
+ };
3011
+ /** @description Redirect to a short-lived signed URL of object storage (`MEDIA_SIGNED_URLS`); not cached */
3012
+ 302: {
3013
+ headers: {
3014
+ [name: string]: unknown;
3015
+ };
3016
+ content?: never;
3017
+ };
3018
+ /** @description Not modified (`If-None-Match` with the `ETag` of an earlier answer) */
3019
+ 304: {
3020
+ headers: {
3021
+ [name: string]: unknown;
3022
+ };
3023
+ content?: never;
3024
+ };
2945
3025
  400: components["responses"]["BadRequest"];
2946
3026
  401: components["responses"]["Unauthorized"];
2947
3027
  403: components["responses"]["Forbidden"];
2948
3028
  404: components["responses"]["NotFound"];
3029
+ /** @description The requested range is outside the file */
3030
+ 416: {
3031
+ headers: {
3032
+ [name: string]: unknown;
3033
+ };
3034
+ content?: never;
3035
+ };
2949
3036
  426: components["responses"]["ClientOutdated"];
2950
3037
  };
2951
3038
  };
@@ -3317,6 +3404,7 @@ export interface operations {
3317
3404
  404: components["responses"]["NotFound"];
3318
3405
  422: components["responses"]["ValidationFailed"];
3319
3406
  426: components["responses"]["ClientOutdated"];
3407
+ 429: components["responses"]["TooManyRequests"];
3320
3408
  };
3321
3409
  };
3322
3410
  listChatMedia: {
@@ -3467,6 +3555,52 @@ export interface operations {
3467
3555
  429: components["responses"]["TooManyRequests"];
3468
3556
  };
3469
3557
  };
3558
+ searchAllMessages: {
3559
+ parameters: {
3560
+ query: {
3561
+ q: string;
3562
+ /** @description Only this chat */
3563
+ chat_id?: components["schemas"]["Id"];
3564
+ /** @description Only messages of this user */
3565
+ sender_id?: components["schemas"]["Id"];
3566
+ type?: "text" | "file" | "voice";
3567
+ /** @description Messages created at or after this time */
3568
+ from?: components["schemas"]["Timestamp"];
3569
+ /** @description Messages created before this time */
3570
+ to?: components["schemas"]["Timestamp"];
3571
+ /** @description Page size */
3572
+ limit?: components["parameters"]["Limit"];
3573
+ /** @description Opaque `next_cursor` of the previous page */
3574
+ after?: components["parameters"]["After"];
3575
+ };
3576
+ header?: {
3577
+ /** @description Version of the client app, for logs and the per-client metric. */
3578
+ "X-Client-Version"?: components["parameters"]["ClientVersion"];
3579
+ /** @description Contract version the client was built with (`API_VERSION` of `@myronsi/messenger-api`). A different MAJOR or a version below `min_client_api_version` is answered with `426`; a malformed value with `400` (`invalid_client_version`). */
3580
+ "X-Client-Api-Version"?: components["parameters"]["ClientApiVersion"];
3581
+ };
3582
+ path?: never;
3583
+ cookie?: never;
3584
+ };
3585
+ requestBody?: never;
3586
+ responses: {
3587
+ /** @description Matches, newest first */
3588
+ 200: {
3589
+ headers: {
3590
+ [name: string]: unknown;
3591
+ };
3592
+ content: {
3593
+ "application/json": components["schemas"]["MessageSearchPage"];
3594
+ };
3595
+ };
3596
+ 400: components["responses"]["BadRequest"];
3597
+ 401: components["responses"]["Unauthorized"];
3598
+ 404: components["responses"]["NotFound"];
3599
+ 422: components["responses"]["ValidationFailed"];
3600
+ 426: components["responses"]["ClientOutdated"];
3601
+ 429: components["responses"]["TooManyRequests"];
3602
+ };
3603
+ };
3470
3604
  listApprovalRequests: {
3471
3605
  parameters: {
3472
3606
  query?: {
@@ -1,4 +1,4 @@
1
- /* Generated from api/openapi.yaml 2.0.0-alpha.6. Do not edit. */
1
+ /* Generated from api/openapi.yaml 2.0.0-alpha.8. Do not edit. */
2
2
 
3
3
  /**
4
4
  * Any WebSocket event, in either direction.
@@ -1178,7 +1178,7 @@
1178
1178
  "string",
1179
1179
  "null"
1180
1180
  ],
1181
- "description": "Plain-text excerpt; never HTML."
1181
+ "description": "Plain-text excerpt of the matching text or file name; never HTML. The matched words are\nwrapped in U+E000 (start) and U+E001 (end), characters of the Unicode private use area,\nso a client can mark them without parsing markup. `null` when the message matched without\nan excerpt.\n"
1182
1182
  }
1183
1183
  }
1184
1184
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myronsi/messenger-api",
3
- "version": "2.0.0-alpha.6.next.48",
3
+ "version": "2.0.0-alpha.8.next.50",
4
4
  "description": "API contract of the Messenger backend: OpenAPI document, WebSocket event schemas and generated TypeScript types",
5
5
  "license": "MIT",
6
6
  "repository": {