@myronsi/messenger-api 2.0.0-alpha.1.next.29 → 2.0.0-alpha.2.next.34
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 +10 -0
- package/README.md +5 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/openapi.yaml +31 -9
- package/dist/schema.d.ts +28 -10
- package/dist/ws-docs.json +1 -1
- package/dist/ws-events.d.ts +1 -1
- package/dist/ws-events.schema.json +21 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
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.2
|
|
6
|
+
|
|
7
|
+
Authentication details found while implementing the Go backend:
|
|
8
|
+
|
|
9
|
+
- Session IDs (`Session.id`, `session_id` path parameter) are UUIDs (`format: uuid`) instead of decimal IDs.
|
|
10
|
+
- `code` of `POST /auth/login/2fa` and `POST /me/2fa/disable` accepts an authenticator code or a recovery code.
|
|
11
|
+
- `POST /me/2fa/confirm` answers `200` with `recovery_codes` (shown once) instead of `204`.
|
|
12
|
+
- `POST /me/password` can answer `403` (wrong current password); `POST /me/2fa/confirm` and `/me/2fa/disable` can answer `409`.
|
|
13
|
+
- The refresh cookie is scoped to `/api/v2/auth/refresh`.
|
|
14
|
+
|
|
5
15
|
## 2.0.0-alpha.1
|
|
6
16
|
|
|
7
17
|
First draft of API contract v2 for the Go backend (`/api/v2`), published as `@myronsi/messenger-api@2.0.0-alpha.1`:
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ api/
|
|
|
15
15
|
├─ ws-events.d.ts WebSocket event types (from the JSON Schemas)
|
|
16
16
|
├─ ws-events.schema.json bundled JSON Schemas (used by the breaking-change check)
|
|
17
17
|
├─ ws-docs.json websocket.md and the examples (used by the PATCH check)
|
|
18
|
-
└─ index.js export const API_VERSION = "2.0.0-alpha.
|
|
18
|
+
└─ index.js export const API_VERSION = "2.0.0-alpha.2"
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Use in the frontend
|
|
@@ -45,14 +45,13 @@ Change the contract first, in the same PR as the code that implements it. Bump `
|
|
|
45
45
|
|
|
46
46
|
## Go server
|
|
47
47
|
|
|
48
|
-
The Go server code is generated from `openapi.yaml` with [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) (strict server) in the same PR as a contract change. The configuration is `oapi-codegen.yaml
|
|
48
|
+
The Go server code is generated from `openapi.yaml` with [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen) (strict server) in the same PR as a contract change. The configuration is `oapi-codegen.yaml`, the output is `internal/httpapi/api.gen.go`, and the `go:generate` directive lives in `internal/httpapi/generate.go`:
|
|
49
49
|
|
|
50
|
-
```
|
|
51
|
-
|
|
50
|
+
```sh
|
|
51
|
+
make generate # go generate ./...
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
When an operation is added to the contract, the build fails until it is added to `internal/httpapi/unimplemented.go` (which answers 501) or to a real implementation. CI runs `go generate ./... && git diff --exit-code`, so a stale generated file fails the build.
|
|
56
55
|
## Publishing
|
|
57
56
|
|
|
58
57
|
See `docs/releasing.md`: `next` on every merge to `master` that changes `api/`, the stable version after a backend release when `info.version` is not on npm yet. Both use `npm publish` with Trusted Publishing, which also attaches provenance.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated from api/openapi.yaml 2.0.0-alpha.
|
|
2
|
-
export declare const API_VERSION: "2.0.0-alpha.
|
|
1
|
+
/* Generated from api/openapi.yaml 2.0.0-alpha.2. Do not edit. */
|
|
2
|
+
export declare const API_VERSION: "2.0.0-alpha.2";
|
|
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.
|
|
1
|
+
export const API_VERSION = "2.0.0-alpha.2";
|
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.
|
|
4
|
+
version: 2.0.0-alpha.2
|
|
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
|
|
@@ -356,7 +356,7 @@ paths:
|
|
|
356
356
|
tags: [me]
|
|
357
357
|
operationId: changePassword
|
|
358
358
|
summary: Change the password
|
|
359
|
-
description: Revokes all other sessions.
|
|
359
|
+
description: "Revokes all other sessions. A wrong current password answers `403` with `code: invalid_credentials`."
|
|
360
360
|
requestBody:
|
|
361
361
|
required: true
|
|
362
362
|
content:
|
|
@@ -368,6 +368,7 @@ paths:
|
|
|
368
368
|
description: Password changed
|
|
369
369
|
"400": { $ref: "#/components/responses/BadRequest" }
|
|
370
370
|
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
371
|
+
"403": { $ref: "#/components/responses/Forbidden" }
|
|
371
372
|
"422": { $ref: "#/components/responses/ValidationFailed" }
|
|
372
373
|
"429": { $ref: "#/components/responses/TooManyRequests" }
|
|
373
374
|
/me/security:
|
|
@@ -463,7 +464,7 @@ paths:
|
|
|
463
464
|
tags: [me]
|
|
464
465
|
operationId: setupTwoFactor
|
|
465
466
|
summary: Start two-factor setup
|
|
466
|
-
description: Returns the secret and an `otpauth://` URI; two-factor stays off until confirmed.
|
|
467
|
+
description: "Returns the secret and an `otpauth://` URI; two-factor stays off until confirmed. A wrong password answers `403` with `code: invalid_credentials`; `409` when two-factor is already on."
|
|
467
468
|
requestBody:
|
|
468
469
|
required: true
|
|
469
470
|
content:
|
|
@@ -488,6 +489,7 @@ paths:
|
|
|
488
489
|
tags: [me]
|
|
489
490
|
operationId: confirmTwoFactor
|
|
490
491
|
summary: Turn two-factor on with a code
|
|
492
|
+
description: "Returns the recovery codes. They are shown only once, so store them safely."
|
|
491
493
|
requestBody:
|
|
492
494
|
required: true
|
|
493
495
|
content:
|
|
@@ -495,10 +497,14 @@ paths:
|
|
|
495
497
|
schema: { $ref: "#/components/schemas/TwoFactorCode" }
|
|
496
498
|
responses:
|
|
497
499
|
"426": { $ref: "#/components/responses/ClientOutdated" }
|
|
498
|
-
"
|
|
500
|
+
"200":
|
|
499
501
|
description: Two-factor authentication enabled
|
|
502
|
+
content:
|
|
503
|
+
application/json:
|
|
504
|
+
schema: { $ref: "#/components/schemas/TwoFactorRecoveryCodes" }
|
|
500
505
|
"400": { $ref: "#/components/responses/BadRequest" }
|
|
501
506
|
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
507
|
+
"409": { $ref: "#/components/responses/Conflict" }
|
|
502
508
|
"429": { $ref: "#/components/responses/TooManyRequests" }
|
|
503
509
|
/me/2fa/disable:
|
|
504
510
|
parameters:
|
|
@@ -508,6 +514,7 @@ paths:
|
|
|
508
514
|
tags: [me]
|
|
509
515
|
operationId: disableTwoFactor
|
|
510
516
|
summary: Turn two-factor off
|
|
517
|
+
description: "A wrong password or code answers `403` (`invalid_credentials` or `invalid_two_factor_code`); `409` when two-factor is off."
|
|
511
518
|
requestBody:
|
|
512
519
|
required: true
|
|
513
520
|
content:
|
|
@@ -520,6 +527,7 @@ paths:
|
|
|
520
527
|
"400": { $ref: "#/components/responses/BadRequest" }
|
|
521
528
|
"401": { $ref: "#/components/responses/Unauthorized" }
|
|
522
529
|
"403": { $ref: "#/components/responses/Forbidden" }
|
|
530
|
+
"409": { $ref: "#/components/responses/Conflict" }
|
|
523
531
|
"429": { $ref: "#/components/responses/TooManyRequests" }
|
|
524
532
|
/me/privacy:
|
|
525
533
|
parameters:
|
|
@@ -1512,7 +1520,7 @@ components:
|
|
|
1512
1520
|
|
|
1513
1521
|
headers:
|
|
1514
1522
|
RefreshCookie:
|
|
1515
|
-
description: HttpOnly, Secure, SameSite refresh cookie scoped to `/api/v2/auth
|
|
1523
|
+
description: HttpOnly, Secure, SameSite refresh cookie scoped to `/api/v2/auth/refresh`, so the browser sends it only to the refresh endpoint. Login and refresh set it; logout clears it (expired cookie).
|
|
1516
1524
|
schema: { type: string }
|
|
1517
1525
|
|
|
1518
1526
|
parameters:
|
|
@@ -1555,7 +1563,7 @@ components:
|
|
|
1555
1563
|
name: session_id
|
|
1556
1564
|
in: path
|
|
1557
1565
|
required: true
|
|
1558
|
-
schema: {
|
|
1566
|
+
schema: { type: string, format: uuid }
|
|
1559
1567
|
|
|
1560
1568
|
ClientVersion:
|
|
1561
1569
|
name: X-Client-Version
|
|
@@ -1734,7 +1742,10 @@ components:
|
|
|
1734
1742
|
required: [login_challenge, code]
|
|
1735
1743
|
properties:
|
|
1736
1744
|
login_challenge: { type: string }
|
|
1737
|
-
code:
|
|
1745
|
+
code:
|
|
1746
|
+
type: string
|
|
1747
|
+
pattern: "^([0-9]{6}|[0-9A-Fa-f]{8}-[0-9A-Fa-f]{8})$"
|
|
1748
|
+
description: A code of the authenticator app, or an unused recovery code.
|
|
1738
1749
|
TokenResponse:
|
|
1739
1750
|
type: object
|
|
1740
1751
|
required: [access_token, token_type, expires_in]
|
|
@@ -1829,7 +1840,7 @@ components:
|
|
|
1829
1840
|
type: object
|
|
1830
1841
|
required: [id, created_at, last_used_at, is_current]
|
|
1831
1842
|
properties:
|
|
1832
|
-
id: {
|
|
1843
|
+
id: { type: string, format: uuid }
|
|
1833
1844
|
device:
|
|
1834
1845
|
type: [string, "null"]
|
|
1835
1846
|
description: Sanitised user agent
|
|
@@ -1848,12 +1859,23 @@ components:
|
|
|
1848
1859
|
required: [code]
|
|
1849
1860
|
properties:
|
|
1850
1861
|
code: { type: string, pattern: "^[0-9]{6}$" }
|
|
1862
|
+
TwoFactorRecoveryCodes:
|
|
1863
|
+
type: object
|
|
1864
|
+
required: [recovery_codes]
|
|
1865
|
+
properties:
|
|
1866
|
+
recovery_codes:
|
|
1867
|
+
type: array
|
|
1868
|
+
items: { type: string }
|
|
1869
|
+
description: One-time codes for signing in without the authenticator app. Shown only once.
|
|
1851
1870
|
DisableTwoFactorRequest:
|
|
1852
1871
|
type: object
|
|
1853
1872
|
required: [password, code]
|
|
1854
1873
|
properties:
|
|
1855
1874
|
password: { type: string, maxLength: 128, writeOnly: true }
|
|
1856
|
-
code:
|
|
1875
|
+
code:
|
|
1876
|
+
type: string
|
|
1877
|
+
pattern: "^([0-9]{6}|[0-9A-Fa-f]{8}-[0-9A-Fa-f]{8})$"
|
|
1878
|
+
description: A code of the authenticator app, or an unused recovery code.
|
|
1857
1879
|
Visibility:
|
|
1858
1880
|
type: string
|
|
1859
1881
|
description: Who may see the item. `*_except` scopes use the exception lists.
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated from api/openapi.yaml 2.0.0-alpha.
|
|
1
|
+
/* Generated from api/openapi.yaml 2.0.0-alpha.2. Do not edit. */
|
|
2
2
|
export interface paths {
|
|
3
3
|
"/meta": {
|
|
4
4
|
parameters: {
|
|
@@ -276,7 +276,7 @@ export interface paths {
|
|
|
276
276
|
get?: never;
|
|
277
277
|
/**
|
|
278
278
|
* Change the password
|
|
279
|
-
* @description Revokes all other sessions.
|
|
279
|
+
* @description Revokes all other sessions. A wrong current password answers `403` with `code: invalid_credentials`.
|
|
280
280
|
*/
|
|
281
281
|
put: operations["changePassword"];
|
|
282
282
|
post?: never;
|
|
@@ -372,7 +372,7 @@ export interface paths {
|
|
|
372
372
|
put?: never;
|
|
373
373
|
/**
|
|
374
374
|
* Start two-factor setup
|
|
375
|
-
* @description Returns the secret and an `otpauth://` URI; two-factor stays off until confirmed.
|
|
375
|
+
* @description Returns the secret and an `otpauth://` URI; two-factor stays off until confirmed. A wrong password answers `403` with `code: invalid_credentials`; `409` when two-factor is already on.
|
|
376
376
|
*/
|
|
377
377
|
post: operations["setupTwoFactor"];
|
|
378
378
|
delete?: never;
|
|
@@ -395,7 +395,10 @@ export interface paths {
|
|
|
395
395
|
};
|
|
396
396
|
get?: never;
|
|
397
397
|
put?: never;
|
|
398
|
-
/**
|
|
398
|
+
/**
|
|
399
|
+
* Turn two-factor on with a code
|
|
400
|
+
* @description Returns the recovery codes. They are shown only once, so store them safely.
|
|
401
|
+
*/
|
|
399
402
|
post: operations["confirmTwoFactor"];
|
|
400
403
|
delete?: never;
|
|
401
404
|
options?: never;
|
|
@@ -417,7 +420,10 @@ export interface paths {
|
|
|
417
420
|
};
|
|
418
421
|
get?: never;
|
|
419
422
|
put?: never;
|
|
420
|
-
/**
|
|
423
|
+
/**
|
|
424
|
+
* Turn two-factor off
|
|
425
|
+
* @description A wrong password or code answers `403` (`invalid_credentials` or `invalid_two_factor_code`); `409` when two-factor is off.
|
|
426
|
+
*/
|
|
421
427
|
post: operations["disableTwoFactor"];
|
|
422
428
|
delete?: never;
|
|
423
429
|
options?: never;
|
|
@@ -1286,6 +1292,7 @@ export interface components {
|
|
|
1286
1292
|
};
|
|
1287
1293
|
TwoFactorLoginRequest: {
|
|
1288
1294
|
login_challenge: string;
|
|
1295
|
+
/** @description A code of the authenticator app, or an unused recovery code. */
|
|
1289
1296
|
code: string;
|
|
1290
1297
|
};
|
|
1291
1298
|
TokenResponse: {
|
|
@@ -1344,7 +1351,8 @@ export interface components {
|
|
|
1344
1351
|
session_duration_days: number;
|
|
1345
1352
|
};
|
|
1346
1353
|
Session: {
|
|
1347
|
-
|
|
1354
|
+
/** Format: uuid */
|
|
1355
|
+
id: string;
|
|
1348
1356
|
/** @description Sanitised user agent */
|
|
1349
1357
|
device?: string | null;
|
|
1350
1358
|
created_at: components["schemas"]["Timestamp"];
|
|
@@ -1359,8 +1367,13 @@ export interface components {
|
|
|
1359
1367
|
TwoFactorCode: {
|
|
1360
1368
|
code: string;
|
|
1361
1369
|
};
|
|
1370
|
+
TwoFactorRecoveryCodes: {
|
|
1371
|
+
/** @description One-time codes for signing in without the authenticator app. Shown only once. */
|
|
1372
|
+
recovery_codes: string[];
|
|
1373
|
+
};
|
|
1362
1374
|
DisableTwoFactorRequest: {
|
|
1363
1375
|
password: string;
|
|
1376
|
+
/** @description A code of the authenticator app, or an unused recovery code. */
|
|
1364
1377
|
code: string;
|
|
1365
1378
|
};
|
|
1366
1379
|
/**
|
|
@@ -1717,7 +1730,7 @@ export interface components {
|
|
|
1717
1730
|
UserId: components["schemas"]["Id"];
|
|
1718
1731
|
RequestId: components["schemas"]["Id"];
|
|
1719
1732
|
AttachmentId: components["schemas"]["Id"];
|
|
1720
|
-
SessionId:
|
|
1733
|
+
SessionId: string;
|
|
1721
1734
|
/** @description Version of the client app, for logs and the per-client metric. */
|
|
1722
1735
|
ClientVersion: string;
|
|
1723
1736
|
/** @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`). */
|
|
@@ -1725,7 +1738,7 @@ export interface components {
|
|
|
1725
1738
|
};
|
|
1726
1739
|
requestBodies: never;
|
|
1727
1740
|
headers: {
|
|
1728
|
-
/** @description HttpOnly, Secure, SameSite refresh cookie scoped to `/api/v2/auth
|
|
1741
|
+
/** @description HttpOnly, Secure, SameSite refresh cookie scoped to `/api/v2/auth/refresh`, so the browser sends it only to the refresh endpoint. Login and refresh set it; logout clears it (expired cookie). */
|
|
1729
1742
|
RefreshCookie: string;
|
|
1730
1743
|
};
|
|
1731
1744
|
pathItems: never;
|
|
@@ -2161,6 +2174,7 @@ export interface operations {
|
|
|
2161
2174
|
};
|
|
2162
2175
|
400: components["responses"]["BadRequest"];
|
|
2163
2176
|
401: components["responses"]["Unauthorized"];
|
|
2177
|
+
403: components["responses"]["Forbidden"];
|
|
2164
2178
|
422: components["responses"]["ValidationFailed"];
|
|
2165
2179
|
426: components["responses"]["ClientOutdated"];
|
|
2166
2180
|
429: components["responses"]["TooManyRequests"];
|
|
@@ -2365,14 +2379,17 @@ export interface operations {
|
|
|
2365
2379
|
};
|
|
2366
2380
|
responses: {
|
|
2367
2381
|
/** @description Two-factor authentication enabled */
|
|
2368
|
-
|
|
2382
|
+
200: {
|
|
2369
2383
|
headers: {
|
|
2370
2384
|
[name: string]: unknown;
|
|
2371
2385
|
};
|
|
2372
|
-
content
|
|
2386
|
+
content: {
|
|
2387
|
+
"application/json": components["schemas"]["TwoFactorRecoveryCodes"];
|
|
2388
|
+
};
|
|
2373
2389
|
};
|
|
2374
2390
|
400: components["responses"]["BadRequest"];
|
|
2375
2391
|
401: components["responses"]["Unauthorized"];
|
|
2392
|
+
409: components["responses"]["Conflict"];
|
|
2376
2393
|
426: components["responses"]["ClientOutdated"];
|
|
2377
2394
|
429: components["responses"]["TooManyRequests"];
|
|
2378
2395
|
};
|
|
@@ -2405,6 +2422,7 @@ export interface operations {
|
|
|
2405
2422
|
400: components["responses"]["BadRequest"];
|
|
2406
2423
|
401: components["responses"]["Unauthorized"];
|
|
2407
2424
|
403: components["responses"]["Forbidden"];
|
|
2425
|
+
409: components["responses"]["Conflict"];
|
|
2408
2426
|
426: components["responses"]["ClientOutdated"];
|
|
2409
2427
|
429: components["responses"]["TooManyRequests"];
|
|
2410
2428
|
};
|
package/dist/ws-docs.json
CHANGED
package/dist/ws-events.d.ts
CHANGED
|
@@ -214,7 +214,8 @@
|
|
|
214
214
|
},
|
|
215
215
|
"code": {
|
|
216
216
|
"type": "string",
|
|
217
|
-
"pattern": "^[0-9]{6}$"
|
|
217
|
+
"pattern": "^([0-9]{6}|[0-9A-Fa-f]{8}-[0-9A-Fa-f]{8})$",
|
|
218
|
+
"description": "A code of the authenticator app, or an unused recovery code."
|
|
218
219
|
}
|
|
219
220
|
}
|
|
220
221
|
},
|
|
@@ -450,7 +451,8 @@
|
|
|
450
451
|
],
|
|
451
452
|
"properties": {
|
|
452
453
|
"id": {
|
|
453
|
-
"
|
|
454
|
+
"type": "string",
|
|
455
|
+
"format": "uuid"
|
|
454
456
|
},
|
|
455
457
|
"device": {
|
|
456
458
|
"type": [
|
|
@@ -500,6 +502,21 @@
|
|
|
500
502
|
}
|
|
501
503
|
}
|
|
502
504
|
},
|
|
505
|
+
"TwoFactorRecoveryCodes": {
|
|
506
|
+
"type": "object",
|
|
507
|
+
"required": [
|
|
508
|
+
"recovery_codes"
|
|
509
|
+
],
|
|
510
|
+
"properties": {
|
|
511
|
+
"recovery_codes": {
|
|
512
|
+
"type": "array",
|
|
513
|
+
"items": {
|
|
514
|
+
"type": "string"
|
|
515
|
+
},
|
|
516
|
+
"description": "One-time codes for signing in without the authenticator app. Shown only once."
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
},
|
|
503
520
|
"DisableTwoFactorRequest": {
|
|
504
521
|
"type": "object",
|
|
505
522
|
"required": [
|
|
@@ -514,7 +531,8 @@
|
|
|
514
531
|
},
|
|
515
532
|
"code": {
|
|
516
533
|
"type": "string",
|
|
517
|
-
"pattern": "^[0-9]{6}$"
|
|
534
|
+
"pattern": "^([0-9]{6}|[0-9A-Fa-f]{8}-[0-9A-Fa-f]{8})$",
|
|
535
|
+
"description": "A code of the authenticator app, or an unused recovery code."
|
|
518
536
|
}
|
|
519
537
|
}
|
|
520
538
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myronsi/messenger-api",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.2.next.34",
|
|
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": {
|