@tbs-fitness/contract 0.1.0 → 0.2.0
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/README.md +10 -0
- package/dist/cjs/auth/auth.dto.d.ts +30 -9
- package/dist/cjs/auth/auth.dto.js +24 -11
- package/dist/cjs/coach/coach-auth.dto.d.ts +102 -0
- package/dist/cjs/coach/coach-auth.dto.js +65 -0
- package/dist/cjs/coach/index.d.ts +1 -0
- package/dist/cjs/coach/index.js +17 -0
- package/dist/cjs/enums/index.d.ts +10 -2
- package/dist/cjs/enums/index.js +14 -3
- package/dist/cjs/feature-flags/feature-flag.dto.d.ts +7 -7
- package/dist/esm/auth/auth.dto.d.ts +30 -9
- package/dist/esm/auth/auth.dto.js +20 -7
- package/dist/esm/coach/coach-auth.dto.d.ts +102 -0
- package/dist/esm/coach/coach-auth.dto.js +62 -0
- package/dist/esm/coach/index.d.ts +1 -0
- package/dist/esm/coach/index.js +1 -0
- package/dist/esm/enums/index.d.ts +10 -2
- package/dist/esm/enums/index.js +13 -2
- package/dist/esm/feature-flags/feature-flag.dto.d.ts +7 -7
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -11,6 +11,7 @@ It is published as `@tbs-fitness/contract`. The package holds definitions only:
|
|
|
11
11
|
| `@tbs-fitness/contract/enums` | `ROLES`, `ACCOUNT_STATUSES`, `TOKEN_TRANSPORTS`, `AUDIT_OUTCOMES`, `APP_ENVIRONMENTS`, `FEATURE_FLAG_RULE_TYPES` and their types |
|
|
12
12
|
| `@tbs-fitness/contract/common` | Pagination, response envelopes (`{ data }`, `{ data, meta }`, `{ error }`), `emailSchema`, `phoneSchema`, `safeTextSchema` |
|
|
13
13
|
| `@tbs-fitness/contract/auth` | Login, sessions, password changes and resets, account administration |
|
|
14
|
+
| `@tbs-fitness/contract/coach` | Coach sign-up, one-time code verification and resend, coach sign-in and profile, password recovery |
|
|
14
15
|
| `@tbs-fitness/contract/audit` | The audit log query and response |
|
|
15
16
|
| `@tbs-fitness/contract/feature-flags` | Feature flag requests and responses |
|
|
16
17
|
|
|
@@ -40,6 +41,15 @@ const result = createFlagSchema.safeParse(input); // The same rules as the API.
|
|
|
40
41
|
|
|
41
42
|
Requests have two types. Clients use `*Input`, where fields with a default are optional. The backend uses `*Body`, which is the result after validation. List queries come from the URL as strings, so they have no `*Input`: use `Partial<PaginationQuery>` or `Partial<AuditLogQuery>`.
|
|
42
43
|
|
|
44
|
+
## Version 0.2.0 (breaking)
|
|
45
|
+
|
|
46
|
+
- `ROLES` is now `ADMIN`, `COACH` and `CUSTOMER`. A user has exactly one role.
|
|
47
|
+
- `ACCOUNT_STATUSES` adds `pending_verification`. Administrators set only `ADMIN_SETTABLE_ACCOUNT_STATUSES`.
|
|
48
|
+
- `setRolesSchema` is replaced by `setRoleSchema` (`{ role }`), and `adminAccountResponseSchema` has `role` instead of `roles`. `accountResponseSchema` adds `role` and keeps `roles` as `[role]`.
|
|
49
|
+
- New: `@tbs-fitness/contract/coach`, and `OTP_LENGTH`, `otpCodeSchema`, `opaqueTokenSchema` and `submittedPasswordSchema` in `/auth`.
|
|
50
|
+
|
|
51
|
+
A caret range on 0.x does not cross minor versions, so consumers must install `^0.2.0` explicitly.
|
|
52
|
+
|
|
43
53
|
## Installing it
|
|
44
54
|
|
|
45
55
|
The package is public on npm, so installing it needs no token:
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const MIN_PASSWORD_LENGTH = 12;
|
|
3
3
|
export declare const MAX_PASSWORD_LENGTH = 128;
|
|
4
|
+
/** Every one-time code the API sends has this many digits. */
|
|
5
|
+
export declare const OTP_LENGTH = 6;
|
|
6
|
+
export declare const otpCodeSchema: z.ZodString;
|
|
4
7
|
export declare const newPasswordSchema: z.ZodString;
|
|
8
|
+
/** No minimum at login, so an old short password fails like any wrong password. */
|
|
9
|
+
export declare const submittedPasswordSchema: z.ZodString;
|
|
10
|
+
export declare const opaqueTokenSchema: z.ZodString;
|
|
5
11
|
export declare const loginSchema: z.ZodObject<{
|
|
6
12
|
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
7
13
|
password: z.ZodString;
|
|
@@ -35,15 +41,15 @@ export declare const passwordResetConfirmSchema: z.ZodObject<{
|
|
|
35
41
|
}, z.core.$strict>;
|
|
36
42
|
export type PasswordResetConfirmInput = z.input<typeof passwordResetConfirmSchema>;
|
|
37
43
|
export type PasswordResetConfirmBody = z.output<typeof passwordResetConfirmSchema>;
|
|
38
|
-
export declare const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
+
export declare const setRoleSchema: z.ZodObject<{
|
|
45
|
+
role: z.ZodEnum<{
|
|
46
|
+
ADMIN: "ADMIN";
|
|
47
|
+
COACH: "COACH";
|
|
48
|
+
CUSTOMER: "CUSTOMER";
|
|
49
|
+
}>;
|
|
44
50
|
}, z.core.$strict>;
|
|
45
|
-
export type
|
|
46
|
-
export type
|
|
51
|
+
export type SetRoleInput = z.input<typeof setRoleSchema>;
|
|
52
|
+
export type SetRoleBody = z.output<typeof setRoleSchema>;
|
|
47
53
|
export declare const setStatusSchema: z.ZodObject<{
|
|
48
54
|
status: z.ZodEnum<{
|
|
49
55
|
active: "active";
|
|
@@ -65,6 +71,11 @@ export type TokenResponse = z.output<typeof tokenResponseSchema>;
|
|
|
65
71
|
export declare const accountResponseSchema: z.ZodObject<{
|
|
66
72
|
id: z.ZodUUID;
|
|
67
73
|
email: z.ZodString;
|
|
74
|
+
role: z.ZodEnum<{
|
|
75
|
+
ADMIN: "ADMIN";
|
|
76
|
+
COACH: "COACH";
|
|
77
|
+
CUSTOMER: "CUSTOMER";
|
|
78
|
+
}>;
|
|
68
79
|
roles: z.ZodArray<z.ZodString>;
|
|
69
80
|
permissions: z.ZodArray<z.ZodString>;
|
|
70
81
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
@@ -80,6 +91,11 @@ export declare const loginResponseSchema: z.ZodObject<{
|
|
|
80
91
|
account: z.ZodObject<{
|
|
81
92
|
id: z.ZodUUID;
|
|
82
93
|
email: z.ZodString;
|
|
94
|
+
role: z.ZodEnum<{
|
|
95
|
+
ADMIN: "ADMIN";
|
|
96
|
+
COACH: "COACH";
|
|
97
|
+
CUSTOMER: "CUSTOMER";
|
|
98
|
+
}>;
|
|
83
99
|
roles: z.ZodArray<z.ZodString>;
|
|
84
100
|
permissions: z.ZodArray<z.ZodString>;
|
|
85
101
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
@@ -107,8 +123,13 @@ export type PasswordResetRequestedResponse = z.output<typeof passwordResetReques
|
|
|
107
123
|
export declare const adminAccountResponseSchema: z.ZodObject<{
|
|
108
124
|
id: z.ZodUUID;
|
|
109
125
|
email: z.ZodString;
|
|
110
|
-
|
|
126
|
+
role: z.ZodEnum<{
|
|
127
|
+
ADMIN: "ADMIN";
|
|
128
|
+
COACH: "COACH";
|
|
129
|
+
CUSTOMER: "CUSTOMER";
|
|
130
|
+
}>;
|
|
111
131
|
status: z.ZodEnum<{
|
|
132
|
+
pending_verification: "pending_verification";
|
|
112
133
|
active: "active";
|
|
113
134
|
disabled: "disabled";
|
|
114
135
|
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.revokedSessionsResponseSchema = exports.adminAccountResponseSchema = exports.passwordResetRequestedResponseSchema = exports.logoutAllResponseSchema = exports.sessionResponseSchema = exports.loginResponseSchema = exports.accountResponseSchema = exports.tokenResponseSchema = exports.idParamSchema = exports.setStatusSchema = exports.
|
|
3
|
+
exports.revokedSessionsResponseSchema = exports.adminAccountResponseSchema = exports.passwordResetRequestedResponseSchema = exports.logoutAllResponseSchema = exports.sessionResponseSchema = exports.loginResponseSchema = exports.accountResponseSchema = exports.tokenResponseSchema = exports.idParamSchema = exports.setStatusSchema = exports.setRoleSchema = exports.passwordResetConfirmSchema = exports.passwordResetRequestSchema = exports.changePasswordSchema = exports.refreshSchema = exports.loginSchema = exports.opaqueTokenSchema = exports.submittedPasswordSchema = exports.newPasswordSchema = exports.otpCodeSchema = exports.OTP_LENGTH = exports.MAX_PASSWORD_LENGTH = exports.MIN_PASSWORD_LENGTH = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const contact_schema_js_1 = require("../common/contact.schema.js");
|
|
6
6
|
const safe_text_schema_js_1 = require("../common/safe-text.schema.js");
|
|
@@ -10,40 +10,51 @@ const index_js_1 = require("../enums/index.js");
|
|
|
10
10
|
exports.MIN_PASSWORD_LENGTH = 12;
|
|
11
11
|
exports.MAX_PASSWORD_LENGTH = 128;
|
|
12
12
|
const MAX_OPAQUE_TOKEN_LENGTH = 512;
|
|
13
|
+
/** Every one-time code the API sends has this many digits. */
|
|
14
|
+
exports.OTP_LENGTH = 6;
|
|
15
|
+
exports.otpCodeSchema = zod_1.z
|
|
16
|
+
.string()
|
|
17
|
+
.trim()
|
|
18
|
+
.regex(new RegExp(`^\\d{${exports.OTP_LENGTH}}$`), {
|
|
19
|
+
error: `Enter the ${exports.OTP_LENGTH}-digit code`,
|
|
20
|
+
});
|
|
13
21
|
exports.newPasswordSchema = zod_1.z
|
|
14
22
|
.string()
|
|
15
23
|
.min(exports.MIN_PASSWORD_LENGTH)
|
|
16
24
|
.max(exports.MAX_PASSWORD_LENGTH);
|
|
17
25
|
/** No minimum at login, so an old short password fails like any wrong password. */
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
exports.submittedPasswordSchema = zod_1.z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(exports.MAX_PASSWORD_LENGTH);
|
|
30
|
+
exports.opaqueTokenSchema = zod_1.z.string().min(1).max(MAX_OPAQUE_TOKEN_LENGTH);
|
|
20
31
|
// Strict objects reject unknown fields, so an attempt to send `roles` or
|
|
21
32
|
// `status` fails loudly rather than being silently ignored.
|
|
22
33
|
exports.loginSchema = zod_1.z.strictObject({
|
|
23
34
|
email: contact_schema_js_1.emailSchema,
|
|
24
|
-
password: submittedPasswordSchema,
|
|
35
|
+
password: exports.submittedPasswordSchema,
|
|
25
36
|
deviceName: (0, safe_text_schema_js_1.safeTextSchema)(100).optional(),
|
|
26
37
|
tokenTransport: zod_1.z.enum(index_js_1.TOKEN_TRANSPORTS).default('body'),
|
|
27
38
|
});
|
|
28
39
|
exports.refreshSchema = zod_1.z
|
|
29
|
-
.strictObject({ refreshToken: opaqueTokenSchema.optional() })
|
|
40
|
+
.strictObject({ refreshToken: exports.opaqueTokenSchema.optional() })
|
|
30
41
|
.default({});
|
|
31
42
|
exports.changePasswordSchema = zod_1.z.strictObject({
|
|
32
|
-
currentPassword: submittedPasswordSchema,
|
|
43
|
+
currentPassword: exports.submittedPasswordSchema,
|
|
33
44
|
newPassword: exports.newPasswordSchema,
|
|
34
45
|
});
|
|
35
46
|
exports.passwordResetRequestSchema = zod_1.z.strictObject({
|
|
36
47
|
email: contact_schema_js_1.emailSchema,
|
|
37
48
|
});
|
|
38
49
|
exports.passwordResetConfirmSchema = zod_1.z.strictObject({
|
|
39
|
-
token: opaqueTokenSchema,
|
|
50
|
+
token: exports.opaqueTokenSchema,
|
|
40
51
|
newPassword: exports.newPasswordSchema,
|
|
41
52
|
});
|
|
42
|
-
exports.
|
|
43
|
-
|
|
53
|
+
exports.setRoleSchema = zod_1.z.strictObject({
|
|
54
|
+
role: zod_1.z.enum(index_js_1.ROLES),
|
|
44
55
|
});
|
|
45
56
|
exports.setStatusSchema = zod_1.z.strictObject({
|
|
46
|
-
status: zod_1.z.enum(index_js_1.
|
|
57
|
+
status: zod_1.z.enum(index_js_1.ADMIN_SETTABLE_ACCOUNT_STATUSES),
|
|
47
58
|
});
|
|
48
59
|
exports.idParamSchema = zod_1.z.uuid();
|
|
49
60
|
exports.tokenResponseSchema = zod_1.z.object({
|
|
@@ -57,6 +68,8 @@ exports.tokenResponseSchema = zod_1.z.object({
|
|
|
57
68
|
exports.accountResponseSchema = zod_1.z.object({
|
|
58
69
|
id: zod_1.z.uuid(),
|
|
59
70
|
email: zod_1.z.string(),
|
|
71
|
+
role: zod_1.z.enum(index_js_1.ROLES),
|
|
72
|
+
/** @deprecated Always `[role]`. Kept for clients written before `role`. */
|
|
60
73
|
roles: zod_1.z.array(zod_1.z.string()),
|
|
61
74
|
permissions: zod_1.z.array(zod_1.z.string()),
|
|
62
75
|
lastLoginAt: zod_1.z.iso.datetime().nullable(),
|
|
@@ -82,7 +95,7 @@ exports.passwordResetRequestedResponseSchema = zod_1.z.object({
|
|
|
82
95
|
exports.adminAccountResponseSchema = zod_1.z.object({
|
|
83
96
|
id: zod_1.z.uuid(),
|
|
84
97
|
email: zod_1.z.string(),
|
|
85
|
-
|
|
98
|
+
role: zod_1.z.enum(index_js_1.ROLES),
|
|
86
99
|
status: zod_1.z.enum(index_js_1.ACCOUNT_STATUSES),
|
|
87
100
|
lastLoginAt: zod_1.z.iso.datetime().nullable(),
|
|
88
101
|
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const coachSignupSchema: z.ZodObject<{
|
|
3
|
+
fullName: z.ZodPipe<z.ZodString, z.ZodString>;
|
|
4
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
5
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
6
|
+
password: z.ZodString;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type CoachSignupInput = z.input<typeof coachSignupSchema>;
|
|
9
|
+
export type CoachSignupBody = z.output<typeof coachSignupSchema>;
|
|
10
|
+
/** Used by both resend endpoints and by forgot-password. */
|
|
11
|
+
export declare const otpEmailSchema: z.ZodObject<{
|
|
12
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export type OtpEmailInput = z.input<typeof otpEmailSchema>;
|
|
15
|
+
export type OtpEmailBody = z.output<typeof otpEmailSchema>;
|
|
16
|
+
export declare const verifyOtpSchema: z.ZodObject<{
|
|
17
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
18
|
+
code: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type VerifyOtpInput = z.input<typeof verifyOtpSchema>;
|
|
21
|
+
export type VerifyOtpBody = z.output<typeof verifyOtpSchema>;
|
|
22
|
+
/**
|
|
23
|
+
* Coaches sign in from the browser, so the refresh token always travels in an
|
|
24
|
+
* HttpOnly cookie. `rememberMe: false` makes that cookie end with the browser
|
|
25
|
+
* session instead of persisting.
|
|
26
|
+
*/
|
|
27
|
+
export declare const coachLoginSchema: z.ZodObject<{
|
|
28
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
29
|
+
password: z.ZodString;
|
|
30
|
+
deviceName: z.ZodOptional<z.ZodString>;
|
|
31
|
+
rememberMe: z.ZodDefault<z.ZodBoolean>;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type CoachLoginInput = z.input<typeof coachLoginSchema>;
|
|
34
|
+
export type CoachLoginBody = z.output<typeof coachLoginSchema>;
|
|
35
|
+
export declare const resetPasswordSchema: z.ZodObject<{
|
|
36
|
+
resetToken: z.ZodString;
|
|
37
|
+
newPassword: z.ZodString;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
export type ResetPasswordInput = z.input<typeof resetPasswordSchema>;
|
|
40
|
+
export type ResetPasswordBody = z.output<typeof resetPasswordSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Says what the client needs to drive the code screen, and nothing about
|
|
43
|
+
* whether the email belongs to an account: the same values are returned either
|
|
44
|
+
* way.
|
|
45
|
+
*/
|
|
46
|
+
export declare const otpDispatchResponseSchema: z.ZodObject<{
|
|
47
|
+
message: z.ZodString;
|
|
48
|
+
otpLength: z.ZodNumber;
|
|
49
|
+
expiresInSeconds: z.ZodNumber;
|
|
50
|
+
resendAvailableInSeconds: z.ZodNumber;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
export type OtpDispatchResponse = z.output<typeof otpDispatchResponseSchema>;
|
|
53
|
+
export declare const signupVerifiedResponseSchema: z.ZodObject<{
|
|
54
|
+
message: z.ZodString;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type SignupVerifiedResponse = z.output<typeof signupVerifiedResponseSchema>;
|
|
57
|
+
/** Issued only after a recovery code is verified. It can reset a password once. */
|
|
58
|
+
export declare const resetTokenResponseSchema: z.ZodObject<{
|
|
59
|
+
resetToken: z.ZodString;
|
|
60
|
+
expiresInSeconds: z.ZodNumber;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export type ResetTokenResponse = z.output<typeof resetTokenResponseSchema>;
|
|
63
|
+
export declare const coachProfileSchema: z.ZodObject<{
|
|
64
|
+
id: z.ZodUUID;
|
|
65
|
+
email: z.ZodString;
|
|
66
|
+
fullName: z.ZodNullable<z.ZodString>;
|
|
67
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
68
|
+
role: z.ZodLiteral<"COACH">;
|
|
69
|
+
status: z.ZodEnum<{
|
|
70
|
+
pending_verification: "pending_verification";
|
|
71
|
+
active: "active";
|
|
72
|
+
disabled: "disabled";
|
|
73
|
+
}>;
|
|
74
|
+
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
75
|
+
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
76
|
+
createdAt: z.ZodISODateTime;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
export type CoachProfile = z.output<typeof coachProfileSchema>;
|
|
79
|
+
export declare const coachLoginResponseSchema: z.ZodObject<{
|
|
80
|
+
accessToken: z.ZodString;
|
|
81
|
+
tokenType: z.ZodLiteral<"Bearer">;
|
|
82
|
+
expiresInSeconds: z.ZodNumber;
|
|
83
|
+
refreshToken: z.ZodOptional<z.ZodString>;
|
|
84
|
+
csrfToken: z.ZodOptional<z.ZodString>;
|
|
85
|
+
sessionId: z.ZodUUID;
|
|
86
|
+
coach: z.ZodObject<{
|
|
87
|
+
id: z.ZodUUID;
|
|
88
|
+
email: z.ZodString;
|
|
89
|
+
fullName: z.ZodNullable<z.ZodString>;
|
|
90
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
91
|
+
role: z.ZodLiteral<"COACH">;
|
|
92
|
+
status: z.ZodEnum<{
|
|
93
|
+
pending_verification: "pending_verification";
|
|
94
|
+
active: "active";
|
|
95
|
+
disabled: "disabled";
|
|
96
|
+
}>;
|
|
97
|
+
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
98
|
+
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
99
|
+
createdAt: z.ZodISODateTime;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
}, z.core.$strip>;
|
|
102
|
+
export type CoachLoginResponse = z.output<typeof coachLoginResponseSchema>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.coachLoginResponseSchema = exports.coachProfileSchema = exports.resetTokenResponseSchema = exports.signupVerifiedResponseSchema = exports.otpDispatchResponseSchema = exports.resetPasswordSchema = exports.coachLoginSchema = exports.verifyOtpSchema = exports.otpEmailSchema = exports.coachSignupSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const auth_dto_js_1 = require("../auth/auth.dto.js");
|
|
6
|
+
const contact_schema_js_1 = require("../common/contact.schema.js");
|
|
7
|
+
const safe_text_schema_js_1 = require("../common/safe-text.schema.js");
|
|
8
|
+
const index_js_1 = require("../enums/index.js");
|
|
9
|
+
exports.coachSignupSchema = zod_1.z.strictObject({
|
|
10
|
+
fullName: (0, safe_text_schema_js_1.safeTextSchema)(100).pipe(zod_1.z.string().min(2, { error: 'Enter your full name' })),
|
|
11
|
+
email: contact_schema_js_1.emailSchema,
|
|
12
|
+
phone: contact_schema_js_1.phoneSchema.optional(),
|
|
13
|
+
password: auth_dto_js_1.newPasswordSchema,
|
|
14
|
+
});
|
|
15
|
+
/** Used by both resend endpoints and by forgot-password. */
|
|
16
|
+
exports.otpEmailSchema = zod_1.z.strictObject({ email: contact_schema_js_1.emailSchema });
|
|
17
|
+
exports.verifyOtpSchema = zod_1.z.strictObject({
|
|
18
|
+
email: contact_schema_js_1.emailSchema,
|
|
19
|
+
code: auth_dto_js_1.otpCodeSchema,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Coaches sign in from the browser, so the refresh token always travels in an
|
|
23
|
+
* HttpOnly cookie. `rememberMe: false` makes that cookie end with the browser
|
|
24
|
+
* session instead of persisting.
|
|
25
|
+
*/
|
|
26
|
+
exports.coachLoginSchema = auth_dto_js_1.loginSchema
|
|
27
|
+
.omit({ tokenTransport: true })
|
|
28
|
+
.extend({ rememberMe: zod_1.z.boolean().default(true) });
|
|
29
|
+
exports.resetPasswordSchema = zod_1.z.strictObject({
|
|
30
|
+
resetToken: auth_dto_js_1.opaqueTokenSchema,
|
|
31
|
+
newPassword: auth_dto_js_1.newPasswordSchema,
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Says what the client needs to drive the code screen, and nothing about
|
|
35
|
+
* whether the email belongs to an account: the same values are returned either
|
|
36
|
+
* way.
|
|
37
|
+
*/
|
|
38
|
+
exports.otpDispatchResponseSchema = zod_1.z.object({
|
|
39
|
+
message: zod_1.z.string(),
|
|
40
|
+
otpLength: zod_1.z.number().int(),
|
|
41
|
+
expiresInSeconds: zod_1.z.number().int(),
|
|
42
|
+
resendAvailableInSeconds: zod_1.z.number().int(),
|
|
43
|
+
});
|
|
44
|
+
exports.signupVerifiedResponseSchema = zod_1.z.object({
|
|
45
|
+
message: zod_1.z.string(),
|
|
46
|
+
});
|
|
47
|
+
/** Issued only after a recovery code is verified. It can reset a password once. */
|
|
48
|
+
exports.resetTokenResponseSchema = zod_1.z.object({
|
|
49
|
+
resetToken: zod_1.z.string(),
|
|
50
|
+
expiresInSeconds: zod_1.z.number().int(),
|
|
51
|
+
});
|
|
52
|
+
exports.coachProfileSchema = zod_1.z.object({
|
|
53
|
+
id: zod_1.z.uuid(),
|
|
54
|
+
email: zod_1.z.string(),
|
|
55
|
+
fullName: zod_1.z.string().nullable(),
|
|
56
|
+
phone: zod_1.z.string().nullable(),
|
|
57
|
+
role: zod_1.z.literal('COACH'),
|
|
58
|
+
status: zod_1.z.enum(index_js_1.ACCOUNT_STATUSES),
|
|
59
|
+
emailVerifiedAt: zod_1.z.iso.datetime().nullable(),
|
|
60
|
+
lastLoginAt: zod_1.z.iso.datetime().nullable(),
|
|
61
|
+
createdAt: zod_1.z.iso.datetime(),
|
|
62
|
+
});
|
|
63
|
+
exports.coachLoginResponseSchema = auth_dto_js_1.tokenResponseSchema.extend({
|
|
64
|
+
coach: exports.coachProfileSchema,
|
|
65
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './coach-auth.dto.js';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./coach-auth.dto.js"), exports);
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
export declare const APP_ENVIRONMENTS: readonly ["development", "staging", "production"];
|
|
2
2
|
export type AppEnvironment = (typeof APP_ENVIRONMENTS)[number];
|
|
3
|
-
|
|
3
|
+
/** Each user has exactly one role. A new role is added here and nowhere else. */
|
|
4
|
+
export declare const ROLES: readonly ["ADMIN", "COACH", "CUSTOMER"];
|
|
4
5
|
export type Role = (typeof ROLES)[number];
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* `pending_verification` is a self-registered user who has not yet proved they
|
|
8
|
+
* own their email address. Such a user cannot sign in.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ACCOUNT_STATUSES: readonly ["pending_verification", "active", "disabled"];
|
|
6
11
|
export type AccountStatus = (typeof ACCOUNT_STATUSES)[number];
|
|
12
|
+
/** The statuses an administrator may set. Verification is never set by hand. */
|
|
13
|
+
export declare const ADMIN_SETTABLE_ACCOUNT_STATUSES: readonly ["active", "disabled"];
|
|
14
|
+
export type AdminSettableAccountStatus = (typeof ADMIN_SETTABLE_ACCOUNT_STATUSES)[number];
|
|
7
15
|
export declare const TOKEN_TRANSPORTS: readonly ["body", "cookie"];
|
|
8
16
|
export type TokenTransport = (typeof TOKEN_TRANSPORTS)[number];
|
|
9
17
|
export declare const AUDIT_OUTCOMES: readonly ["success", "failure"];
|
package/dist/cjs/enums/index.js
CHANGED
|
@@ -2,14 +2,25 @@
|
|
|
2
2
|
// These values are stored in the database and sent over the API. Renaming or
|
|
3
3
|
// removing one is a breaking change, so it needs a major version.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.FEATURE_FLAG_RULE_TYPES = exports.AUDIT_OUTCOMES = exports.TOKEN_TRANSPORTS = exports.ACCOUNT_STATUSES = exports.ROLES = exports.APP_ENVIRONMENTS = void 0;
|
|
5
|
+
exports.FEATURE_FLAG_RULE_TYPES = exports.AUDIT_OUTCOMES = exports.TOKEN_TRANSPORTS = exports.ADMIN_SETTABLE_ACCOUNT_STATUSES = exports.ACCOUNT_STATUSES = exports.ROLES = exports.APP_ENVIRONMENTS = void 0;
|
|
6
6
|
exports.APP_ENVIRONMENTS = [
|
|
7
7
|
'development',
|
|
8
8
|
'staging',
|
|
9
9
|
'production',
|
|
10
10
|
];
|
|
11
|
-
|
|
12
|
-
exports.
|
|
11
|
+
/** Each user has exactly one role. A new role is added here and nowhere else. */
|
|
12
|
+
exports.ROLES = ['ADMIN', 'COACH', 'CUSTOMER'];
|
|
13
|
+
/**
|
|
14
|
+
* `pending_verification` is a self-registered user who has not yet proved they
|
|
15
|
+
* own their email address. Such a user cannot sign in.
|
|
16
|
+
*/
|
|
17
|
+
exports.ACCOUNT_STATUSES = [
|
|
18
|
+
'pending_verification',
|
|
19
|
+
'active',
|
|
20
|
+
'disabled',
|
|
21
|
+
];
|
|
22
|
+
/** The statuses an administrator may set. Verification is never set by hand. */
|
|
23
|
+
exports.ADMIN_SETTABLE_ACCOUNT_STATUSES = ['active', 'disabled'];
|
|
13
24
|
exports.TOKEN_TRANSPORTS = ['body', 'cookie'];
|
|
14
25
|
exports.AUDIT_OUTCOMES = ['success', 'failure'];
|
|
15
26
|
exports.FEATURE_FLAG_RULE_TYPES = [
|
|
@@ -41,9 +41,9 @@ export declare const createRuleSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
41
41
|
}, z.core.$strict>, z.ZodObject<{
|
|
42
42
|
ruleType: z.ZodLiteral<"role">;
|
|
43
43
|
ruleValue: z.ZodEnum<{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
ADMIN: "ADMIN";
|
|
45
|
+
COACH: "COACH";
|
|
46
|
+
CUSTOMER: "CUSTOMER";
|
|
47
47
|
}>;
|
|
48
48
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
49
49
|
}, z.core.$strict>], "ruleType">;
|
|
@@ -67,9 +67,9 @@ export declare const flagListQuerySchema: z.ZodObject<{
|
|
|
67
67
|
export declare const ruleResponseSchema: z.ZodObject<{
|
|
68
68
|
id: z.ZodUUID;
|
|
69
69
|
ruleType: z.ZodEnum<{
|
|
70
|
-
trainer: "trainer";
|
|
71
|
-
customer: "customer";
|
|
72
70
|
user: "user";
|
|
71
|
+
customer: "customer";
|
|
72
|
+
trainer: "trainer";
|
|
73
73
|
role: "role";
|
|
74
74
|
}>;
|
|
75
75
|
ruleValue: z.ZodString;
|
|
@@ -100,9 +100,9 @@ export declare const flagResponseSchema: z.ZodObject<{
|
|
|
100
100
|
rules: z.ZodArray<z.ZodObject<{
|
|
101
101
|
id: z.ZodUUID;
|
|
102
102
|
ruleType: z.ZodEnum<{
|
|
103
|
-
trainer: "trainer";
|
|
104
|
-
customer: "customer";
|
|
105
103
|
user: "user";
|
|
104
|
+
customer: "customer";
|
|
105
|
+
trainer: "trainer";
|
|
106
106
|
role: "role";
|
|
107
107
|
}>;
|
|
108
108
|
ruleValue: z.ZodString;
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const MIN_PASSWORD_LENGTH = 12;
|
|
3
3
|
export declare const MAX_PASSWORD_LENGTH = 128;
|
|
4
|
+
/** Every one-time code the API sends has this many digits. */
|
|
5
|
+
export declare const OTP_LENGTH = 6;
|
|
6
|
+
export declare const otpCodeSchema: z.ZodString;
|
|
4
7
|
export declare const newPasswordSchema: z.ZodString;
|
|
8
|
+
/** No minimum at login, so an old short password fails like any wrong password. */
|
|
9
|
+
export declare const submittedPasswordSchema: z.ZodString;
|
|
10
|
+
export declare const opaqueTokenSchema: z.ZodString;
|
|
5
11
|
export declare const loginSchema: z.ZodObject<{
|
|
6
12
|
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
7
13
|
password: z.ZodString;
|
|
@@ -35,15 +41,15 @@ export declare const passwordResetConfirmSchema: z.ZodObject<{
|
|
|
35
41
|
}, z.core.$strict>;
|
|
36
42
|
export type PasswordResetConfirmInput = z.input<typeof passwordResetConfirmSchema>;
|
|
37
43
|
export type PasswordResetConfirmBody = z.output<typeof passwordResetConfirmSchema>;
|
|
38
|
-
export declare const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
+
export declare const setRoleSchema: z.ZodObject<{
|
|
45
|
+
role: z.ZodEnum<{
|
|
46
|
+
ADMIN: "ADMIN";
|
|
47
|
+
COACH: "COACH";
|
|
48
|
+
CUSTOMER: "CUSTOMER";
|
|
49
|
+
}>;
|
|
44
50
|
}, z.core.$strict>;
|
|
45
|
-
export type
|
|
46
|
-
export type
|
|
51
|
+
export type SetRoleInput = z.input<typeof setRoleSchema>;
|
|
52
|
+
export type SetRoleBody = z.output<typeof setRoleSchema>;
|
|
47
53
|
export declare const setStatusSchema: z.ZodObject<{
|
|
48
54
|
status: z.ZodEnum<{
|
|
49
55
|
active: "active";
|
|
@@ -65,6 +71,11 @@ export type TokenResponse = z.output<typeof tokenResponseSchema>;
|
|
|
65
71
|
export declare const accountResponseSchema: z.ZodObject<{
|
|
66
72
|
id: z.ZodUUID;
|
|
67
73
|
email: z.ZodString;
|
|
74
|
+
role: z.ZodEnum<{
|
|
75
|
+
ADMIN: "ADMIN";
|
|
76
|
+
COACH: "COACH";
|
|
77
|
+
CUSTOMER: "CUSTOMER";
|
|
78
|
+
}>;
|
|
68
79
|
roles: z.ZodArray<z.ZodString>;
|
|
69
80
|
permissions: z.ZodArray<z.ZodString>;
|
|
70
81
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
@@ -80,6 +91,11 @@ export declare const loginResponseSchema: z.ZodObject<{
|
|
|
80
91
|
account: z.ZodObject<{
|
|
81
92
|
id: z.ZodUUID;
|
|
82
93
|
email: z.ZodString;
|
|
94
|
+
role: z.ZodEnum<{
|
|
95
|
+
ADMIN: "ADMIN";
|
|
96
|
+
COACH: "COACH";
|
|
97
|
+
CUSTOMER: "CUSTOMER";
|
|
98
|
+
}>;
|
|
83
99
|
roles: z.ZodArray<z.ZodString>;
|
|
84
100
|
permissions: z.ZodArray<z.ZodString>;
|
|
85
101
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
@@ -107,8 +123,13 @@ export type PasswordResetRequestedResponse = z.output<typeof passwordResetReques
|
|
|
107
123
|
export declare const adminAccountResponseSchema: z.ZodObject<{
|
|
108
124
|
id: z.ZodUUID;
|
|
109
125
|
email: z.ZodString;
|
|
110
|
-
|
|
126
|
+
role: z.ZodEnum<{
|
|
127
|
+
ADMIN: "ADMIN";
|
|
128
|
+
COACH: "COACH";
|
|
129
|
+
CUSTOMER: "CUSTOMER";
|
|
130
|
+
}>;
|
|
111
131
|
status: z.ZodEnum<{
|
|
132
|
+
pending_verification: "pending_verification";
|
|
112
133
|
active: "active";
|
|
113
134
|
disabled: "disabled";
|
|
114
135
|
}>;
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { emailSchema } from '../common/contact.schema.js';
|
|
3
3
|
import { safeTextSchema } from '../common/safe-text.schema.js';
|
|
4
|
-
import { ACCOUNT_STATUSES, ROLES, TOKEN_TRANSPORTS } from '../enums/index.js';
|
|
4
|
+
import { ACCOUNT_STATUSES, ADMIN_SETTABLE_ACCOUNT_STATUSES, ROLES, TOKEN_TRANSPORTS, } from '../enums/index.js';
|
|
5
5
|
// Per OWASP: length is what matters, with no composition rules. The upper limit
|
|
6
6
|
// stops very long inputs from being used to exhaust the hashing function.
|
|
7
7
|
export const MIN_PASSWORD_LENGTH = 12;
|
|
8
8
|
export const MAX_PASSWORD_LENGTH = 128;
|
|
9
9
|
const MAX_OPAQUE_TOKEN_LENGTH = 512;
|
|
10
|
+
/** Every one-time code the API sends has this many digits. */
|
|
11
|
+
export const OTP_LENGTH = 6;
|
|
12
|
+
export const otpCodeSchema = z
|
|
13
|
+
.string()
|
|
14
|
+
.trim()
|
|
15
|
+
.regex(new RegExp(`^\\d{${OTP_LENGTH}}$`), {
|
|
16
|
+
error: `Enter the ${OTP_LENGTH}-digit code`,
|
|
17
|
+
});
|
|
10
18
|
export const newPasswordSchema = z
|
|
11
19
|
.string()
|
|
12
20
|
.min(MIN_PASSWORD_LENGTH)
|
|
13
21
|
.max(MAX_PASSWORD_LENGTH);
|
|
14
22
|
/** No minimum at login, so an old short password fails like any wrong password. */
|
|
15
|
-
const submittedPasswordSchema = z
|
|
16
|
-
|
|
23
|
+
export const submittedPasswordSchema = z
|
|
24
|
+
.string()
|
|
25
|
+
.min(1)
|
|
26
|
+
.max(MAX_PASSWORD_LENGTH);
|
|
27
|
+
export const opaqueTokenSchema = z.string().min(1).max(MAX_OPAQUE_TOKEN_LENGTH);
|
|
17
28
|
// Strict objects reject unknown fields, so an attempt to send `roles` or
|
|
18
29
|
// `status` fails loudly rather than being silently ignored.
|
|
19
30
|
export const loginSchema = z.strictObject({
|
|
@@ -36,11 +47,11 @@ export const passwordResetConfirmSchema = z.strictObject({
|
|
|
36
47
|
token: opaqueTokenSchema,
|
|
37
48
|
newPassword: newPasswordSchema,
|
|
38
49
|
});
|
|
39
|
-
export const
|
|
40
|
-
|
|
50
|
+
export const setRoleSchema = z.strictObject({
|
|
51
|
+
role: z.enum(ROLES),
|
|
41
52
|
});
|
|
42
53
|
export const setStatusSchema = z.strictObject({
|
|
43
|
-
status: z.enum(
|
|
54
|
+
status: z.enum(ADMIN_SETTABLE_ACCOUNT_STATUSES),
|
|
44
55
|
});
|
|
45
56
|
export const idParamSchema = z.uuid();
|
|
46
57
|
export const tokenResponseSchema = z.object({
|
|
@@ -54,6 +65,8 @@ export const tokenResponseSchema = z.object({
|
|
|
54
65
|
export const accountResponseSchema = z.object({
|
|
55
66
|
id: z.uuid(),
|
|
56
67
|
email: z.string(),
|
|
68
|
+
role: z.enum(ROLES),
|
|
69
|
+
/** @deprecated Always `[role]`. Kept for clients written before `role`. */
|
|
57
70
|
roles: z.array(z.string()),
|
|
58
71
|
permissions: z.array(z.string()),
|
|
59
72
|
lastLoginAt: z.iso.datetime().nullable(),
|
|
@@ -79,7 +92,7 @@ export const passwordResetRequestedResponseSchema = z.object({
|
|
|
79
92
|
export const adminAccountResponseSchema = z.object({
|
|
80
93
|
id: z.uuid(),
|
|
81
94
|
email: z.string(),
|
|
82
|
-
|
|
95
|
+
role: z.enum(ROLES),
|
|
83
96
|
status: z.enum(ACCOUNT_STATUSES),
|
|
84
97
|
lastLoginAt: z.iso.datetime().nullable(),
|
|
85
98
|
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const coachSignupSchema: z.ZodObject<{
|
|
3
|
+
fullName: z.ZodPipe<z.ZodString, z.ZodString>;
|
|
4
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
5
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
6
|
+
password: z.ZodString;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type CoachSignupInput = z.input<typeof coachSignupSchema>;
|
|
9
|
+
export type CoachSignupBody = z.output<typeof coachSignupSchema>;
|
|
10
|
+
/** Used by both resend endpoints and by forgot-password. */
|
|
11
|
+
export declare const otpEmailSchema: z.ZodObject<{
|
|
12
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
13
|
+
}, z.core.$strict>;
|
|
14
|
+
export type OtpEmailInput = z.input<typeof otpEmailSchema>;
|
|
15
|
+
export type OtpEmailBody = z.output<typeof otpEmailSchema>;
|
|
16
|
+
export declare const verifyOtpSchema: z.ZodObject<{
|
|
17
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
18
|
+
code: z.ZodString;
|
|
19
|
+
}, z.core.$strict>;
|
|
20
|
+
export type VerifyOtpInput = z.input<typeof verifyOtpSchema>;
|
|
21
|
+
export type VerifyOtpBody = z.output<typeof verifyOtpSchema>;
|
|
22
|
+
/**
|
|
23
|
+
* Coaches sign in from the browser, so the refresh token always travels in an
|
|
24
|
+
* HttpOnly cookie. `rememberMe: false` makes that cookie end with the browser
|
|
25
|
+
* session instead of persisting.
|
|
26
|
+
*/
|
|
27
|
+
export declare const coachLoginSchema: z.ZodObject<{
|
|
28
|
+
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
29
|
+
password: z.ZodString;
|
|
30
|
+
deviceName: z.ZodOptional<z.ZodString>;
|
|
31
|
+
rememberMe: z.ZodDefault<z.ZodBoolean>;
|
|
32
|
+
}, z.core.$strict>;
|
|
33
|
+
export type CoachLoginInput = z.input<typeof coachLoginSchema>;
|
|
34
|
+
export type CoachLoginBody = z.output<typeof coachLoginSchema>;
|
|
35
|
+
export declare const resetPasswordSchema: z.ZodObject<{
|
|
36
|
+
resetToken: z.ZodString;
|
|
37
|
+
newPassword: z.ZodString;
|
|
38
|
+
}, z.core.$strict>;
|
|
39
|
+
export type ResetPasswordInput = z.input<typeof resetPasswordSchema>;
|
|
40
|
+
export type ResetPasswordBody = z.output<typeof resetPasswordSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Says what the client needs to drive the code screen, and nothing about
|
|
43
|
+
* whether the email belongs to an account: the same values are returned either
|
|
44
|
+
* way.
|
|
45
|
+
*/
|
|
46
|
+
export declare const otpDispatchResponseSchema: z.ZodObject<{
|
|
47
|
+
message: z.ZodString;
|
|
48
|
+
otpLength: z.ZodNumber;
|
|
49
|
+
expiresInSeconds: z.ZodNumber;
|
|
50
|
+
resendAvailableInSeconds: z.ZodNumber;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
export type OtpDispatchResponse = z.output<typeof otpDispatchResponseSchema>;
|
|
53
|
+
export declare const signupVerifiedResponseSchema: z.ZodObject<{
|
|
54
|
+
message: z.ZodString;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type SignupVerifiedResponse = z.output<typeof signupVerifiedResponseSchema>;
|
|
57
|
+
/** Issued only after a recovery code is verified. It can reset a password once. */
|
|
58
|
+
export declare const resetTokenResponseSchema: z.ZodObject<{
|
|
59
|
+
resetToken: z.ZodString;
|
|
60
|
+
expiresInSeconds: z.ZodNumber;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
export type ResetTokenResponse = z.output<typeof resetTokenResponseSchema>;
|
|
63
|
+
export declare const coachProfileSchema: z.ZodObject<{
|
|
64
|
+
id: z.ZodUUID;
|
|
65
|
+
email: z.ZodString;
|
|
66
|
+
fullName: z.ZodNullable<z.ZodString>;
|
|
67
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
68
|
+
role: z.ZodLiteral<"COACH">;
|
|
69
|
+
status: z.ZodEnum<{
|
|
70
|
+
pending_verification: "pending_verification";
|
|
71
|
+
active: "active";
|
|
72
|
+
disabled: "disabled";
|
|
73
|
+
}>;
|
|
74
|
+
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
75
|
+
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
76
|
+
createdAt: z.ZodISODateTime;
|
|
77
|
+
}, z.core.$strip>;
|
|
78
|
+
export type CoachProfile = z.output<typeof coachProfileSchema>;
|
|
79
|
+
export declare const coachLoginResponseSchema: z.ZodObject<{
|
|
80
|
+
accessToken: z.ZodString;
|
|
81
|
+
tokenType: z.ZodLiteral<"Bearer">;
|
|
82
|
+
expiresInSeconds: z.ZodNumber;
|
|
83
|
+
refreshToken: z.ZodOptional<z.ZodString>;
|
|
84
|
+
csrfToken: z.ZodOptional<z.ZodString>;
|
|
85
|
+
sessionId: z.ZodUUID;
|
|
86
|
+
coach: z.ZodObject<{
|
|
87
|
+
id: z.ZodUUID;
|
|
88
|
+
email: z.ZodString;
|
|
89
|
+
fullName: z.ZodNullable<z.ZodString>;
|
|
90
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
91
|
+
role: z.ZodLiteral<"COACH">;
|
|
92
|
+
status: z.ZodEnum<{
|
|
93
|
+
pending_verification: "pending_verification";
|
|
94
|
+
active: "active";
|
|
95
|
+
disabled: "disabled";
|
|
96
|
+
}>;
|
|
97
|
+
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
98
|
+
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
99
|
+
createdAt: z.ZodISODateTime;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
}, z.core.$strip>;
|
|
102
|
+
export type CoachLoginResponse = z.output<typeof coachLoginResponseSchema>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { loginSchema, newPasswordSchema, opaqueTokenSchema, otpCodeSchema, tokenResponseSchema, } from '../auth/auth.dto.js';
|
|
3
|
+
import { emailSchema, phoneSchema } from '../common/contact.schema.js';
|
|
4
|
+
import { safeTextSchema } from '../common/safe-text.schema.js';
|
|
5
|
+
import { ACCOUNT_STATUSES } from '../enums/index.js';
|
|
6
|
+
export const coachSignupSchema = z.strictObject({
|
|
7
|
+
fullName: safeTextSchema(100).pipe(z.string().min(2, { error: 'Enter your full name' })),
|
|
8
|
+
email: emailSchema,
|
|
9
|
+
phone: phoneSchema.optional(),
|
|
10
|
+
password: newPasswordSchema,
|
|
11
|
+
});
|
|
12
|
+
/** Used by both resend endpoints and by forgot-password. */
|
|
13
|
+
export const otpEmailSchema = z.strictObject({ email: emailSchema });
|
|
14
|
+
export const verifyOtpSchema = z.strictObject({
|
|
15
|
+
email: emailSchema,
|
|
16
|
+
code: otpCodeSchema,
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Coaches sign in from the browser, so the refresh token always travels in an
|
|
20
|
+
* HttpOnly cookie. `rememberMe: false` makes that cookie end with the browser
|
|
21
|
+
* session instead of persisting.
|
|
22
|
+
*/
|
|
23
|
+
export const coachLoginSchema = loginSchema
|
|
24
|
+
.omit({ tokenTransport: true })
|
|
25
|
+
.extend({ rememberMe: z.boolean().default(true) });
|
|
26
|
+
export const resetPasswordSchema = z.strictObject({
|
|
27
|
+
resetToken: opaqueTokenSchema,
|
|
28
|
+
newPassword: newPasswordSchema,
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Says what the client needs to drive the code screen, and nothing about
|
|
32
|
+
* whether the email belongs to an account: the same values are returned either
|
|
33
|
+
* way.
|
|
34
|
+
*/
|
|
35
|
+
export const otpDispatchResponseSchema = z.object({
|
|
36
|
+
message: z.string(),
|
|
37
|
+
otpLength: z.number().int(),
|
|
38
|
+
expiresInSeconds: z.number().int(),
|
|
39
|
+
resendAvailableInSeconds: z.number().int(),
|
|
40
|
+
});
|
|
41
|
+
export const signupVerifiedResponseSchema = z.object({
|
|
42
|
+
message: z.string(),
|
|
43
|
+
});
|
|
44
|
+
/** Issued only after a recovery code is verified. It can reset a password once. */
|
|
45
|
+
export const resetTokenResponseSchema = z.object({
|
|
46
|
+
resetToken: z.string(),
|
|
47
|
+
expiresInSeconds: z.number().int(),
|
|
48
|
+
});
|
|
49
|
+
export const coachProfileSchema = z.object({
|
|
50
|
+
id: z.uuid(),
|
|
51
|
+
email: z.string(),
|
|
52
|
+
fullName: z.string().nullable(),
|
|
53
|
+
phone: z.string().nullable(),
|
|
54
|
+
role: z.literal('COACH'),
|
|
55
|
+
status: z.enum(ACCOUNT_STATUSES),
|
|
56
|
+
emailVerifiedAt: z.iso.datetime().nullable(),
|
|
57
|
+
lastLoginAt: z.iso.datetime().nullable(),
|
|
58
|
+
createdAt: z.iso.datetime(),
|
|
59
|
+
});
|
|
60
|
+
export const coachLoginResponseSchema = tokenResponseSchema.extend({
|
|
61
|
+
coach: coachProfileSchema,
|
|
62
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './coach-auth.dto.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './coach-auth.dto.js';
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
export declare const APP_ENVIRONMENTS: readonly ["development", "staging", "production"];
|
|
2
2
|
export type AppEnvironment = (typeof APP_ENVIRONMENTS)[number];
|
|
3
|
-
|
|
3
|
+
/** Each user has exactly one role. A new role is added here and nowhere else. */
|
|
4
|
+
export declare const ROLES: readonly ["ADMIN", "COACH", "CUSTOMER"];
|
|
4
5
|
export type Role = (typeof ROLES)[number];
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* `pending_verification` is a self-registered user who has not yet proved they
|
|
8
|
+
* own their email address. Such a user cannot sign in.
|
|
9
|
+
*/
|
|
10
|
+
export declare const ACCOUNT_STATUSES: readonly ["pending_verification", "active", "disabled"];
|
|
6
11
|
export type AccountStatus = (typeof ACCOUNT_STATUSES)[number];
|
|
12
|
+
/** The statuses an administrator may set. Verification is never set by hand. */
|
|
13
|
+
export declare const ADMIN_SETTABLE_ACCOUNT_STATUSES: readonly ["active", "disabled"];
|
|
14
|
+
export type AdminSettableAccountStatus = (typeof ADMIN_SETTABLE_ACCOUNT_STATUSES)[number];
|
|
7
15
|
export declare const TOKEN_TRANSPORTS: readonly ["body", "cookie"];
|
|
8
16
|
export type TokenTransport = (typeof TOKEN_TRANSPORTS)[number];
|
|
9
17
|
export declare const AUDIT_OUTCOMES: readonly ["success", "failure"];
|
package/dist/esm/enums/index.js
CHANGED
|
@@ -5,8 +5,19 @@ export const APP_ENVIRONMENTS = [
|
|
|
5
5
|
'staging',
|
|
6
6
|
'production',
|
|
7
7
|
];
|
|
8
|
-
|
|
9
|
-
export const
|
|
8
|
+
/** Each user has exactly one role. A new role is added here and nowhere else. */
|
|
9
|
+
export const ROLES = ['ADMIN', 'COACH', 'CUSTOMER'];
|
|
10
|
+
/**
|
|
11
|
+
* `pending_verification` is a self-registered user who has not yet proved they
|
|
12
|
+
* own their email address. Such a user cannot sign in.
|
|
13
|
+
*/
|
|
14
|
+
export const ACCOUNT_STATUSES = [
|
|
15
|
+
'pending_verification',
|
|
16
|
+
'active',
|
|
17
|
+
'disabled',
|
|
18
|
+
];
|
|
19
|
+
/** The statuses an administrator may set. Verification is never set by hand. */
|
|
20
|
+
export const ADMIN_SETTABLE_ACCOUNT_STATUSES = ['active', 'disabled'];
|
|
10
21
|
export const TOKEN_TRANSPORTS = ['body', 'cookie'];
|
|
11
22
|
export const AUDIT_OUTCOMES = ['success', 'failure'];
|
|
12
23
|
export const FEATURE_FLAG_RULE_TYPES = [
|
|
@@ -41,9 +41,9 @@ export declare const createRuleSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
41
41
|
}, z.core.$strict>, z.ZodObject<{
|
|
42
42
|
ruleType: z.ZodLiteral<"role">;
|
|
43
43
|
ruleValue: z.ZodEnum<{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
ADMIN: "ADMIN";
|
|
45
|
+
COACH: "COACH";
|
|
46
|
+
CUSTOMER: "CUSTOMER";
|
|
47
47
|
}>;
|
|
48
48
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
49
49
|
}, z.core.$strict>], "ruleType">;
|
|
@@ -67,9 +67,9 @@ export declare const flagListQuerySchema: z.ZodObject<{
|
|
|
67
67
|
export declare const ruleResponseSchema: z.ZodObject<{
|
|
68
68
|
id: z.ZodUUID;
|
|
69
69
|
ruleType: z.ZodEnum<{
|
|
70
|
-
trainer: "trainer";
|
|
71
|
-
customer: "customer";
|
|
72
70
|
user: "user";
|
|
71
|
+
customer: "customer";
|
|
72
|
+
trainer: "trainer";
|
|
73
73
|
role: "role";
|
|
74
74
|
}>;
|
|
75
75
|
ruleValue: z.ZodString;
|
|
@@ -100,9 +100,9 @@ export declare const flagResponseSchema: z.ZodObject<{
|
|
|
100
100
|
rules: z.ZodArray<z.ZodObject<{
|
|
101
101
|
id: z.ZodUUID;
|
|
102
102
|
ruleType: z.ZodEnum<{
|
|
103
|
-
trainer: "trainer";
|
|
104
|
-
customer: "customer";
|
|
105
103
|
user: "user";
|
|
104
|
+
customer: "customer";
|
|
105
|
+
trainer: "trainer";
|
|
106
106
|
role: "role";
|
|
107
107
|
}>;
|
|
108
108
|
ruleValue: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbs-fitness/contract",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TBS API contract: Zod schemas, DTO types and enums shared by the backend, web and mobile apps",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -33,6 +33,16 @@
|
|
|
33
33
|
"default": "./dist/cjs/auth/index.js"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
+
"./coach": {
|
|
37
|
+
"import": {
|
|
38
|
+
"types": "./dist/esm/coach/index.d.ts",
|
|
39
|
+
"default": "./dist/esm/coach/index.js"
|
|
40
|
+
},
|
|
41
|
+
"require": {
|
|
42
|
+
"types": "./dist/cjs/coach/index.d.ts",
|
|
43
|
+
"default": "./dist/cjs/coach/index.js"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
36
46
|
"./common": {
|
|
37
47
|
"import": {
|
|
38
48
|
"types": "./dist/esm/common/index.d.ts",
|