@fleetless/contracts 5.2.0 → 6.0.0-next.1

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/artifacts/openapi.json +1975 -415
  3. package/artifacts/routes.json +1697 -251
  4. package/artifacts/schema/accept-team-invite-request.schema.json +13 -7
  5. package/artifacts/schema/app-auth-config.schema.json +108 -4
  6. package/artifacts/schema/app-hosted-pages.schema.json +33 -0
  7. package/artifacts/schema/app-invitation.schema.json +2 -2
  8. package/artifacts/schema/app-mail-template-list-response.schema.json +4 -3
  9. package/artifacts/schema/app-mail-template.schema.json +3 -2
  10. package/artifacts/schema/app-sign-in-methods.schema.json +19 -0
  11. package/artifacts/schema/app-user-list-response.schema.json +36 -0
  12. package/artifacts/schema/app-user.schema.json +36 -0
  13. package/artifacts/schema/auth-me-response.schema.json +27 -0
  14. package/artifacts/schema/auth-ok.schema.json +13 -1
  15. package/artifacts/schema/client-accept-invitation-request.schema.json +3 -4
  16. package/artifacts/schema/client-identity.schema.json +13 -1
  17. package/artifacts/schema/client-login-code-request.schema.json +24 -0
  18. package/artifacts/schema/client-login-code-verify-request.schema.json +30 -0
  19. package/artifacts/schema/client-provider-list-response.schema.json +22 -2
  20. package/artifacts/schema/client-register-request.schema.json +3 -4
  21. package/artifacts/schema/client-sign-in-result.schema.json +55 -0
  22. package/artifacts/schema/client-two-factor-disable-request.schema.json +15 -0
  23. package/artifacts/schema/client-two-factor-setup-confirm-request.schema.json +20 -0
  24. package/artifacts/schema/client-two-factor-setup-confirm-response.schema.json +49 -0
  25. package/artifacts/schema/client-two-factor-setup-request.schema.json +12 -0
  26. package/artifacts/schema/client-two-factor-verify-request.schema.json +25 -0
  27. package/artifacts/schema/create-app-invitation-request.schema.json +1 -1
  28. package/artifacts/schema/create-passkey-request.schema.json +25 -0
  29. package/artifacts/schema/create-passkey-response.schema.json +84 -0
  30. package/artifacts/schema/developer-passkey.schema.json +56 -0
  31. package/artifacts/schema/developer-two-factor.schema.json +105 -0
  32. package/artifacts/schema/fleetless-user-list-response.schema.json +22 -0
  33. package/artifacts/schema/fleetless-user.schema.json +22 -0
  34. package/artifacts/schema/invalid-code-details.schema.json +16 -0
  35. package/artifacts/schema/org.schema.json +5 -0
  36. package/artifacts/schema/patch-org-request.schema.json +5 -3
  37. package/artifacts/schema/patch-org-response.schema.json +5 -0
  38. package/artifacts/schema/put-app-auth-look-request.schema.json +22 -0
  39. package/artifacts/schema/put-app-auth-mcp-request.schema.json +1 -14
  40. package/artifacts/schema/put-app-auth-sign-in-request.schema.json +39 -0
  41. package/artifacts/schema/put-app-auth-urls-request.schema.json +31 -4
  42. package/artifacts/schema/recovery-codes-response.schema.json +20 -0
  43. package/artifacts/schema/rename-passkey-request.schema.json +16 -0
  44. package/artifacts/schema/totp-confirm-request.schema.json +15 -0
  45. package/artifacts/schema/totp-confirm-response.schema.json +27 -0
  46. package/artifacts/schema/two-factor-challenge.schema.json +24 -0
  47. package/artifacts/schema/two-factor-setup-response.schema.json +21 -0
  48. package/artifacts/schema/webauthn-options-response.schema.json +18 -0
  49. package/dist/app-users.d.ts +154 -34
  50. package/dist/app-users.js +177 -45
  51. package/dist/client-auth.d.ts +133 -24
  52. package/dist/client-auth.js +139 -28
  53. package/dist/config.d.ts +2 -2
  54. package/dist/errors.d.ts +10 -1
  55. package/dist/errors.js +34 -5
  56. package/dist/identity.d.ts +172 -123
  57. package/dist/identity.js +189 -101
  58. package/dist/index.d.ts +9 -9
  59. package/dist/index.js +11 -7
  60. package/dist/protocol.d.ts +1 -1
  61. package/dist/realtime.d.ts +1 -0
  62. package/dist/rest.d.ts +2 -2
  63. package/dist/rest.js +17 -28
  64. package/dist/routes.d.ts +19 -0
  65. package/dist/routes.js +497 -183
  66. package/package.json +1 -1
  67. package/artifacts/schema/developer-login-request.schema.json +0 -19
  68. package/artifacts/schema/password-reset-confirm.schema.json +0 -19
  69. package/artifacts/schema/password-reset-request.schema.json +0 -14
  70. package/artifacts/schema/sign-up-request.schema.json +0 -26
  71. package/artifacts/schema/sign-up-response.schema.json +0 -127
@@ -0,0 +1,55 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "anyOf": [
4
+ {
5
+ "type": "object",
6
+ "properties": {
7
+ "access_token": {
8
+ "type": "string",
9
+ "minLength": 1,
10
+ "description": "The token to send as `Authorization: Bearer <token>` on every call. Short-lived: read `expires_in` rather than assuming a lifetime."
11
+ },
12
+ "refresh_token": {
13
+ "type": "string",
14
+ "minLength": 1,
15
+ "description": "The token that buys the next access token. It rotates on every use, so a value presented twice is detectable theft and ends the whole family."
16
+ },
17
+ "expires_in": {
18
+ "type": "integer",
19
+ "exclusiveMinimum": 0,
20
+ "maximum": 9007199254740991,
21
+ "description": "How long the access token stays valid, in **seconds** from now. Not a timestamp, and not milliseconds."
22
+ }
23
+ },
24
+ "required": [
25
+ "access_token",
26
+ "refresh_token",
27
+ "expires_in"
28
+ ],
29
+ "additionalProperties": false
30
+ },
31
+ {
32
+ "type": "object",
33
+ "properties": {
34
+ "status": {
35
+ "type": "string",
36
+ "enum": [
37
+ "two_factor_required",
38
+ "two_factor_setup_required"
39
+ ],
40
+ "description": "`two_factor_required`: ask for the authenticator code. `two_factor_setup_required`: the app requires two-factor and the person has none yet, so set one up before any session exists."
41
+ },
42
+ "challenge": {
43
+ "type": "string",
44
+ "minLength": 1,
45
+ "description": "The handle the next step spends. Valid five minutes; afterwards it answers `410 token_spent` and the sign-in starts over."
46
+ }
47
+ },
48
+ "required": [
49
+ "status",
50
+ "challenge"
51
+ ],
52
+ "additionalProperties": false
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "code": {
6
+ "type": "string",
7
+ "pattern": "^\\d{6}$",
8
+ "description": "A code the authenticator shows now."
9
+ }
10
+ },
11
+ "required": [
12
+ "code"
13
+ ],
14
+ "additionalProperties": false
15
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "challenge": {
6
+ "description": "The same challenge as at `setup`, during sign-in; absent with a bearer.",
7
+ "type": "string",
8
+ "minLength": 1
9
+ },
10
+ "code": {
11
+ "type": "string",
12
+ "pattern": "^\\d{6}$",
13
+ "description": "A code the new authenticator shows now. It proves the secret was copied correctly before anything depends on it."
14
+ }
15
+ },
16
+ "required": [
17
+ "code"
18
+ ],
19
+ "additionalProperties": false
20
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "recovery_codes": {
6
+ "minItems": 10,
7
+ "maxItems": 10,
8
+ "type": "array",
9
+ "items": {
10
+ "type": "string",
11
+ "pattern": "^[a-z2-7]{5}-[a-z2-7]{5}$"
12
+ },
13
+ "description": "The ten single-use recovery codes, lowercase, shown once. Any earlier set is void."
14
+ },
15
+ "session": {
16
+ "type": "object",
17
+ "properties": {
18
+ "access_token": {
19
+ "type": "string",
20
+ "minLength": 1,
21
+ "description": "The token to send as `Authorization: Bearer <token>` on every call. Short-lived: read `expires_in` rather than assuming a lifetime."
22
+ },
23
+ "refresh_token": {
24
+ "type": "string",
25
+ "minLength": 1,
26
+ "description": "The token that buys the next access token. It rotates on every use, so a value presented twice is detectable theft and ends the whole family."
27
+ },
28
+ "expires_in": {
29
+ "type": "integer",
30
+ "exclusiveMinimum": 0,
31
+ "maximum": 9007199254740991,
32
+ "description": "How long the access token stays valid, in **seconds** from now. Not a timestamp, and not milliseconds."
33
+ }
34
+ },
35
+ "required": [
36
+ "access_token",
37
+ "refresh_token",
38
+ "expires_in"
39
+ ],
40
+ "additionalProperties": false,
41
+ "description": "The session the sign-in was waiting for, or a fresh one for the account settings."
42
+ }
43
+ },
44
+ "required": [
45
+ "recovery_codes",
46
+ "session"
47
+ ],
48
+ "additionalProperties": false
49
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "challenge": {
6
+ "description": "The `two_factor_setup_required` challenge, during sign-in. Absent when the call carries the app user's bearer instead.",
7
+ "type": "string",
8
+ "minLength": 1
9
+ }
10
+ },
11
+ "additionalProperties": false
12
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "challenge": {
6
+ "type": "string",
7
+ "minLength": 1,
8
+ "description": "The challenge the sign-in step answered."
9
+ },
10
+ "code": {
11
+ "description": "The six-digit code the authenticator shows now. A code already accepted once is refused, so a replay of a seen code does not sign anybody in.",
12
+ "type": "string",
13
+ "pattern": "^\\d{6}$"
14
+ },
15
+ "recovery_code": {
16
+ "description": "One of the ten recovery codes, `xxxxx-xxxxx`, in either case. Spent by its use.",
17
+ "type": "string",
18
+ "pattern": "^[a-zA-Z2-7]{5}-[a-zA-Z2-7]{5}$"
19
+ }
20
+ },
21
+ "required": [
22
+ "challenge"
23
+ ],
24
+ "additionalProperties": false
25
+ }
@@ -29,7 +29,7 @@
29
29
  },
30
30
  "send_mail": {
31
31
  "type": "boolean",
32
- "description": "Whether Fleetless mails the invitation. **Refused with `409 target_state_conflict` naming `invite_url` when the app has configured none** — there would be nowhere for the link to point, and a mail carrying a Fleetless-hosted page is a surface this product does not have."
32
+ "description": "Whether Fleetless mails the invitation. The link points at the app's `invite_url`, or at the Fleetless-hosted invitation page when the app has configured none — so the mail always leads somewhere, and nothing is refused for a missing URL."
33
33
  }
34
34
  },
35
35
  "required": [
@@ -0,0 +1,25 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "name": {
6
+ "type": "string",
7
+ "minLength": 1,
8
+ "maxLength": 80,
9
+ "description": "What to call the passkey, such as the device it lives on."
10
+ },
11
+ "credential": {
12
+ "type": "object",
13
+ "propertyNames": {
14
+ "type": "string"
15
+ },
16
+ "additionalProperties": {},
17
+ "description": "The browser's `RegistrationResponseJSON` for the options `POST /api/auth/passkeys/options` answered."
18
+ }
19
+ },
20
+ "required": [
21
+ "name",
22
+ "credential"
23
+ ],
24
+ "additionalProperties": false
25
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "passkey": {
6
+ "type": "object",
7
+ "properties": {
8
+ "id": {
9
+ "type": "string",
10
+ "format": "uuid",
11
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
12
+ "description": "The passkey in the API, as renamed and removed through `/api/auth/passkeys/:id`."
13
+ },
14
+ "name": {
15
+ "type": "string",
16
+ "minLength": 1,
17
+ "maxLength": 80,
18
+ "description": "What the person called it, such as the device it lives on."
19
+ },
20
+ "created_at": {
21
+ "type": "string",
22
+ "format": "date-time",
23
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
24
+ "description": "When it was registered."
25
+ },
26
+ "last_used_at": {
27
+ "anyOf": [
28
+ {
29
+ "type": "string",
30
+ "format": "date-time",
31
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
32
+ },
33
+ {
34
+ "type": "null"
35
+ }
36
+ ],
37
+ "description": "When it last signed the person in or confirmed a sign-in, or `null` if never."
38
+ },
39
+ "synced": {
40
+ "anyOf": [
41
+ {
42
+ "type": "boolean"
43
+ },
44
+ {
45
+ "type": "null"
46
+ }
47
+ ],
48
+ "description": "Whether the authenticator reported the passkey as syncable across the person's devices (the backup-eligible flag), or `null` when it said nothing."
49
+ }
50
+ },
51
+ "required": [
52
+ "id",
53
+ "name",
54
+ "created_at",
55
+ "last_used_at",
56
+ "synced"
57
+ ],
58
+ "additionalProperties": false,
59
+ "description": "The passkey as it is now stored."
60
+ },
61
+ "recovery_codes": {
62
+ "anyOf": [
63
+ {
64
+ "minItems": 10,
65
+ "maxItems": 10,
66
+ "type": "array",
67
+ "items": {
68
+ "type": "string",
69
+ "pattern": "^[a-z2-7]{5}-[a-z2-7]{5}$"
70
+ }
71
+ },
72
+ {
73
+ "type": "null"
74
+ }
75
+ ],
76
+ "description": "The ten recovery codes, shown once, when this passkey is the account's first second factor; `null` when the account already had one and its codes stay valid."
77
+ }
78
+ },
79
+ "required": [
80
+ "passkey",
81
+ "recovery_codes"
82
+ ],
83
+ "additionalProperties": false
84
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "id": {
6
+ "type": "string",
7
+ "format": "uuid",
8
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
9
+ "description": "The passkey in the API, as renamed and removed through `/api/auth/passkeys/:id`."
10
+ },
11
+ "name": {
12
+ "type": "string",
13
+ "minLength": 1,
14
+ "maxLength": 80,
15
+ "description": "What the person called it, such as the device it lives on."
16
+ },
17
+ "created_at": {
18
+ "type": "string",
19
+ "format": "date-time",
20
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
21
+ "description": "When it was registered."
22
+ },
23
+ "last_used_at": {
24
+ "anyOf": [
25
+ {
26
+ "type": "string",
27
+ "format": "date-time",
28
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
29
+ },
30
+ {
31
+ "type": "null"
32
+ }
33
+ ],
34
+ "description": "When it last signed the person in or confirmed a sign-in, or `null` if never."
35
+ },
36
+ "synced": {
37
+ "anyOf": [
38
+ {
39
+ "type": "boolean"
40
+ },
41
+ {
42
+ "type": "null"
43
+ }
44
+ ],
45
+ "description": "Whether the authenticator reported the passkey as syncable across the person's devices (the backup-eligible flag), or `null` when it said nothing."
46
+ }
47
+ },
48
+ "required": [
49
+ "id",
50
+ "name",
51
+ "created_at",
52
+ "last_used_at",
53
+ "synced"
54
+ ],
55
+ "additionalProperties": false
56
+ }
@@ -0,0 +1,105 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "passkeys": {
6
+ "type": "array",
7
+ "items": {
8
+ "type": "object",
9
+ "properties": {
10
+ "id": {
11
+ "type": "string",
12
+ "format": "uuid",
13
+ "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
14
+ "description": "The passkey in the API, as renamed and removed through `/api/auth/passkeys/:id`."
15
+ },
16
+ "name": {
17
+ "type": "string",
18
+ "minLength": 1,
19
+ "maxLength": 80,
20
+ "description": "What the person called it, such as the device it lives on."
21
+ },
22
+ "created_at": {
23
+ "type": "string",
24
+ "format": "date-time",
25
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
26
+ "description": "When it was registered."
27
+ },
28
+ "last_used_at": {
29
+ "anyOf": [
30
+ {
31
+ "type": "string",
32
+ "format": "date-time",
33
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
34
+ },
35
+ {
36
+ "type": "null"
37
+ }
38
+ ],
39
+ "description": "When it last signed the person in or confirmed a sign-in, or `null` if never."
40
+ },
41
+ "synced": {
42
+ "anyOf": [
43
+ {
44
+ "type": "boolean"
45
+ },
46
+ {
47
+ "type": "null"
48
+ }
49
+ ],
50
+ "description": "Whether the authenticator reported the passkey as syncable across the person's devices (the backup-eligible flag), or `null` when it said nothing."
51
+ }
52
+ },
53
+ "required": [
54
+ "id",
55
+ "name",
56
+ "created_at",
57
+ "last_used_at",
58
+ "synced"
59
+ ],
60
+ "additionalProperties": false
61
+ },
62
+ "description": "Every passkey the caller has registered, oldest first. Empty when none."
63
+ },
64
+ "authenticator": {
65
+ "anyOf": [
66
+ {
67
+ "type": "object",
68
+ "properties": {
69
+ "created_at": {
70
+ "type": "string",
71
+ "format": "date-time",
72
+ "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
73
+ "description": "When the authenticator was confirmed."
74
+ }
75
+ },
76
+ "required": [
77
+ "created_at"
78
+ ],
79
+ "additionalProperties": false
80
+ },
81
+ {
82
+ "type": "null"
83
+ }
84
+ ],
85
+ "description": "The confirmed authenticator app, or `null` when there is none. At most one."
86
+ },
87
+ "recovery_codes_left": {
88
+ "type": "integer",
89
+ "minimum": 0,
90
+ "maximum": 10,
91
+ "description": "How many of the ten recovery codes are unspent. `0` while the caller has no second factor."
92
+ },
93
+ "required_by_org": {
94
+ "type": "boolean",
95
+ "description": "Whether the organisation requires a second factor. While it does, the last one cannot be removed."
96
+ }
97
+ },
98
+ "required": [
99
+ "passkeys",
100
+ "authenticator",
101
+ "recovery_codes_left",
102
+ "required_by_org"
103
+ ],
104
+ "additionalProperties": false
105
+ }
@@ -46,6 +46,27 @@
46
46
  ],
47
47
  "description": "The console powers this person holds. **Required** — every Fleetless user has a tier; it was optional only while the org also held people with no console powers to grade, and that pool is gone."
48
48
  },
49
+ "two_factor": {
50
+ "type": "object",
51
+ "properties": {
52
+ "passkeys": {
53
+ "type": "integer",
54
+ "minimum": 0,
55
+ "maximum": 9007199254740991,
56
+ "description": "How many passkeys the person has registered."
57
+ },
58
+ "authenticator": {
59
+ "type": "boolean",
60
+ "description": "Whether the person has a confirmed authenticator app."
61
+ }
62
+ },
63
+ "required": [
64
+ "passkeys",
65
+ "authenticator"
66
+ ],
67
+ "additionalProperties": false,
68
+ "description": "The person's second factors, as the team list shows them: none, passkeys, an authenticator, or both. No credential travels here. An owner resets them through `DELETE /api/org/users/:id/two-factor`."
69
+ },
49
70
  "created_at": {
50
71
  "type": "string",
51
72
  "format": "date-time",
@@ -59,6 +80,7 @@
59
80
  "email",
60
81
  "display_name",
61
82
  "tier",
83
+ "two_factor",
62
84
  "created_at"
63
85
  ],
64
86
  "additionalProperties": false
@@ -41,6 +41,27 @@
41
41
  ],
42
42
  "description": "The console powers this person holds. **Required** — every Fleetless user has a tier; it was optional only while the org also held people with no console powers to grade, and that pool is gone."
43
43
  },
44
+ "two_factor": {
45
+ "type": "object",
46
+ "properties": {
47
+ "passkeys": {
48
+ "type": "integer",
49
+ "minimum": 0,
50
+ "maximum": 9007199254740991,
51
+ "description": "How many passkeys the person has registered."
52
+ },
53
+ "authenticator": {
54
+ "type": "boolean",
55
+ "description": "Whether the person has a confirmed authenticator app."
56
+ }
57
+ },
58
+ "required": [
59
+ "passkeys",
60
+ "authenticator"
61
+ ],
62
+ "additionalProperties": false,
63
+ "description": "The person's second factors, as the team list shows them: none, passkeys, an authenticator, or both. No credential travels here. An owner resets them through `DELETE /api/org/users/:id/two-factor`."
64
+ },
44
65
  "created_at": {
45
66
  "type": "string",
46
67
  "format": "date-time",
@@ -54,6 +75,7 @@
54
75
  "email",
55
76
  "display_name",
56
77
  "tier",
78
+ "two_factor",
57
79
  "created_at"
58
80
  ],
59
81
  "additionalProperties": false
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "attempts_left": {
6
+ "type": "integer",
7
+ "minimum": 0,
8
+ "maximum": 9007199254740991,
9
+ "description": "How many more wrong codes this code or challenge takes before it is spent. `0` means the next attempt answers `410 token_spent`."
10
+ }
11
+ },
12
+ "required": [
13
+ "attempts_left"
14
+ ],
15
+ "additionalProperties": false
16
+ }
@@ -14,6 +14,10 @@
14
14
  "maxLength": 120,
15
15
  "description": "The organisation's display name. Free text, changed through `PATCH /api/org`."
16
16
  },
17
+ "require_two_factor": {
18
+ "type": "boolean",
19
+ "description": "Whether every member must have a second factor — a passkey or an authenticator app. A member without one sets it up at their next sign-in, before any session exists; nobody is signed out when it is switched on. It covers the console and the central MCP endpoint; server keys and robot bridges are not people and are not affected. Owners change it through `PATCH /api/org`."
20
+ },
17
21
  "created_at": {
18
22
  "type": "string",
19
23
  "format": "date-time",
@@ -24,6 +28,7 @@
24
28
  "required": [
25
29
  "id",
26
30
  "name",
31
+ "require_two_factor",
27
32
  "created_at"
28
33
  ],
29
34
  "additionalProperties": false
@@ -3,13 +3,15 @@
3
3
  "type": "object",
4
4
  "properties": {
5
5
  "name": {
6
+ "description": "The organisation's new display name. Absent leaves it alone.",
6
7
  "type": "string",
7
8
  "minLength": 1,
8
9
  "maxLength": 120
10
+ },
11
+ "require_two_factor": {
12
+ "description": "Whether every member must have a second factor. Turning it on signs nobody out: each member without one sets it up at their next sign-in. Absent leaves it alone.",
13
+ "type": "boolean"
9
14
  }
10
15
  },
11
- "required": [
12
- "name"
13
- ],
14
16
  "additionalProperties": false
15
17
  }
@@ -17,6 +17,10 @@
17
17
  "maxLength": 120,
18
18
  "description": "The organisation's display name. Free text, changed through `PATCH /api/org`."
19
19
  },
20
+ "require_two_factor": {
21
+ "type": "boolean",
22
+ "description": "Whether every member must have a second factor — a passkey or an authenticator app. A member without one sets it up at their next sign-in, before any session exists; nobody is signed out when it is switched on. It covers the console and the central MCP endpoint; server keys and robot bridges are not people and are not affected. Owners change it through `PATCH /api/org`."
23
+ },
20
24
  "created_at": {
21
25
  "type": "string",
22
26
  "format": "date-time",
@@ -27,6 +31,7 @@
27
31
  "required": [
28
32
  "id",
29
33
  "name",
34
+ "require_two_factor",
30
35
  "created_at"
31
36
  ],
32
37
  "additionalProperties": false,
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "type": "object",
4
+ "properties": {
5
+ "hosted_accent": {
6
+ "anyOf": [
7
+ {
8
+ "type": "string",
9
+ "pattern": "^#[0-9a-f]{6}$"
10
+ },
11
+ {
12
+ "type": "null"
13
+ }
14
+ ],
15
+ "description": "The accent colour of the hosted pages, `#rrggbb` in lowercase, or `null` for the neutral shell's own."
16
+ }
17
+ },
18
+ "required": [
19
+ "hosted_accent"
20
+ ],
21
+ "additionalProperties": false
22
+ }
@@ -5,23 +5,10 @@
5
5
  "mcp_enabled": {
6
6
  "type": "boolean",
7
7
  "description": "Whether this app serves an MCP endpoint at `/mcp/<identifier>`. Off refuses the whole OAuth surface for the app, not merely the tool calls, and is re-read on every request rather than cached off a token."
8
- },
9
- "mcp_login_url": {
10
- "anyOf": [
11
- {
12
- "type": "string",
13
- "maxLength": 500
14
- },
15
- {
16
- "type": "null"
17
- }
18
- ],
19
- "description": "The page an MCP authorization redirects to, with `{interaction}` where the interaction id goes. Not a token: the id names a pending request the server already holds, and the app authenticates the user itself before approving it."
20
8
  }
21
9
  },
22
10
  "required": [
23
- "mcp_enabled",
24
- "mcp_login_url"
11
+ "mcp_enabled"
25
12
  ],
26
13
  "additionalProperties": false
27
14
  }