@tbs-fitness/contract 0.0.0-stage → 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.
Files changed (59) hide show
  1. package/README.md +133 -2
  2. package/dist/cjs/audit/audit-log.dto.d.ts +26 -0
  3. package/dist/cjs/audit/audit-log.dto.js +24 -0
  4. package/dist/cjs/audit/index.d.ts +1 -0
  5. package/dist/cjs/audit/index.js +17 -0
  6. package/dist/cjs/auth/auth.dto.d.ts +142 -0
  7. package/dist/cjs/auth/auth.dto.js +104 -0
  8. package/dist/cjs/auth/index.d.ts +1 -0
  9. package/dist/cjs/auth/index.js +17 -0
  10. package/dist/cjs/coach/coach-auth.dto.d.ts +102 -0
  11. package/dist/cjs/coach/coach-auth.dto.js +65 -0
  12. package/dist/cjs/coach/index.d.ts +1 -0
  13. package/dist/cjs/coach/index.js +17 -0
  14. package/dist/cjs/common/api-response.schema.d.ts +37 -0
  15. package/dist/cjs/common/api-response.schema.js +26 -0
  16. package/dist/cjs/common/contact.schema.d.ts +5 -0
  17. package/dist/cjs/common/contact.schema.js +20 -0
  18. package/dist/cjs/common/index.d.ts +4 -0
  19. package/dist/cjs/common/index.js +20 -0
  20. package/dist/cjs/common/pagination.schema.d.ts +14 -0
  21. package/dist/cjs/common/pagination.schema.js +15 -0
  22. package/dist/cjs/common/safe-text.schema.d.ts +7 -0
  23. package/dist/cjs/common/safe-text.schema.js +21 -0
  24. package/dist/cjs/enums/index.d.ts +20 -0
  25. package/dist/cjs/enums/index.js +31 -0
  26. package/dist/cjs/feature-flags/feature-flag.dto.d.ts +142 -0
  27. package/dist/cjs/feature-flags/feature-flag.dto.js +135 -0
  28. package/dist/cjs/feature-flags/index.d.ts +1 -0
  29. package/dist/cjs/feature-flags/index.js +17 -0
  30. package/dist/cjs/package.json +1 -0
  31. package/dist/esm/audit/audit-log.dto.d.ts +26 -0
  32. package/dist/esm/audit/audit-log.dto.js +21 -0
  33. package/dist/esm/audit/index.d.ts +1 -0
  34. package/dist/esm/audit/index.js +1 -0
  35. package/dist/esm/auth/auth.dto.d.ts +142 -0
  36. package/dist/esm/auth/auth.dto.js +101 -0
  37. package/dist/esm/auth/index.d.ts +1 -0
  38. package/dist/esm/auth/index.js +1 -0
  39. package/dist/esm/coach/coach-auth.dto.d.ts +102 -0
  40. package/dist/esm/coach/coach-auth.dto.js +62 -0
  41. package/dist/esm/coach/index.d.ts +1 -0
  42. package/dist/esm/coach/index.js +1 -0
  43. package/dist/esm/common/api-response.schema.d.ts +37 -0
  44. package/dist/esm/common/api-response.schema.js +21 -0
  45. package/dist/esm/common/contact.schema.d.ts +5 -0
  46. package/dist/esm/common/contact.schema.js +17 -0
  47. package/dist/esm/common/index.d.ts +4 -0
  48. package/dist/esm/common/index.js +4 -0
  49. package/dist/esm/common/pagination.schema.d.ts +14 -0
  50. package/dist/esm/common/pagination.schema.js +12 -0
  51. package/dist/esm/common/safe-text.schema.d.ts +7 -0
  52. package/dist/esm/common/safe-text.schema.js +17 -0
  53. package/dist/esm/enums/index.d.ts +20 -0
  54. package/dist/esm/enums/index.js +28 -0
  55. package/dist/esm/feature-flags/feature-flag.dto.d.ts +142 -0
  56. package/dist/esm/feature-flags/feature-flag.dto.js +132 -0
  57. package/dist/esm/feature-flags/index.d.ts +1 -0
  58. package/dist/esm/feature-flags/index.js +1 -0
  59. package/package.json +118 -4
package/README.md CHANGED
@@ -1,3 +1,134 @@
1
- # Temporary Holding Version
1
+ # TBS_contract
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The contract between the TBS platforms. The backend, web and mobile apps all import their API schemas, DTO types and enums from this package, so a request or response has one definition and a breaking change shows up as a compile error.
4
+
5
+ It is published as `@tbs-fitness/contract`. The package holds definitions only: no database code, no framework code and no secrets, because it ends up in client bundles.
6
+
7
+ ## What is in it
8
+
9
+ | Import | Contents |
10
+ | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
11
+ | `@tbs-fitness/contract/enums` | `ROLES`, `ACCOUNT_STATUSES`, `TOKEN_TRANSPORTS`, `AUDIT_OUTCOMES`, `APP_ENVIRONMENTS`, `FEATURE_FLAG_RULE_TYPES` and their types |
12
+ | `@tbs-fitness/contract/common` | Pagination, response envelopes (`{ data }`, `{ data, meta }`, `{ error }`), `emailSchema`, `phoneSchema`, `safeTextSchema` |
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 |
15
+ | `@tbs-fitness/contract/audit` | The audit log query and response |
16
+ | `@tbs-fitness/contract/feature-flags` | Feature flag requests and responses |
17
+
18
+ Each domain has its own entry point, so names only need to be unique within a domain. `auditLogResponseSchema`, for example, exists in both `/audit` and `/feature-flags`.
19
+
20
+ ## Using it
21
+
22
+ The package needs `zod` 4 from the app, so that every app has a single copy of it.
23
+
24
+ ```ts
25
+ import type { PaginatedResponse } from '@tbs-fitness/contract/common';
26
+ import {
27
+ type CreateFlagInput,
28
+ createFlagSchema,
29
+ type FlagResponse,
30
+ flagResponseSchema,
31
+ } from '@tbs-fitness/contract/feature-flags';
32
+
33
+ const input: CreateFlagInput = {
34
+ key: 'new-checkout',
35
+ name: 'New checkout',
36
+ environment: 'staging',
37
+ };
38
+
39
+ const result = createFlagSchema.safeParse(input); // The same rules as the API.
40
+ ```
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>`.
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
+
53
+ ## Installing it
54
+
55
+ The package is public on npm, so installing it needs no token:
56
+
57
+ ```bash
58
+ npm install @tbs-fitness/contract
59
+ ```
60
+
61
+ ## Adding to it
62
+
63
+ 1. Put a domain's schemas in a `.dto.ts` file in `src/<domain>`, and export its types with `z.input` and `z.output`.
64
+ 2. Put values shared by several domains in `src/enums` or `src/common`.
65
+ 3. For a new domain, add `src/<domain>/index.ts` and an entry to `exports` in `package.json`.
66
+ 4. Add tests next to the schema.
67
+
68
+ Keep validation that needs a server, such as a uniqueness check, in the backend.
69
+
70
+ The package is public, so anyone can read everything in it, permanently. Add only what clients can already see in API traffic: never secrets, internal hostnames or customer data.
71
+
72
+ ## Development
73
+
74
+ You need Node 24.
75
+
76
+ ```bash
77
+ nvm install
78
+ ```
79
+
80
+ ```bash
81
+ npm install
82
+ ```
83
+
84
+ | Command | What it does |
85
+ | ---------------- | --------------------------------------------- |
86
+ | `npm run build` | Builds ESM and CommonJS into `dist` |
87
+ | `npm test` | Runs the unit tests |
88
+ | `npm run check` | Runs the typecheck, lint, format check, tests |
89
+ | `npm run format` | Formats the code |
90
+
91
+ ### Trying a change in the backend
92
+
93
+ The backend installs this package from a sibling checkout until the first version is published. After changing it, run this in `TBS_backend`, which rebuilds the package and installs it as a published copy would be. `npm install ../TBS_contract` alone keeps the old copy while the version is unchanged.
94
+
95
+ ```bash
96
+ rm -rf node_modules/@tbs-fitness/contract && npm install
97
+ ```
98
+
99
+ ## Versioning
100
+
101
+ Versions follow semver, and every app pins the version it was tested with.
102
+
103
+ | Change | Version |
104
+ | ------------------------------------------------------------------- | ------- |
105
+ | Removing or renaming anything exported, or a field in a response | Major |
106
+ | A stricter rule, a new required request field, a removed enum value | Major |
107
+ | A new schema, a new optional request field, a new response field | Minor |
108
+ | A fix that accepts and returns the same data | Patch |
109
+
110
+ A new enum value can break a client with an exhaustive `switch`, so treat it as a major version unless the clients are known to handle it.
111
+
112
+ ## Publishing
113
+
114
+ Log in to npm as a user who can publish to the `tbs-fitness` organisation:
115
+
116
+ ```bash
117
+ npm login
118
+ ```
119
+
120
+ Then, from an up-to-date `main`, set the new version and publish it. The first release is already `0.1.0`, so skip `npm version` for that one.
121
+
122
+ ```bash
123
+ npm version minor
124
+ ```
125
+
126
+ ```bash
127
+ npm publish
128
+ ```
129
+
130
+ ```bash
131
+ git push --follow-tags
132
+ ```
133
+
134
+ `npm publish` runs all the checks and a fresh build first. `publishConfig` in `package.json` sets `access` to `public`, because npm otherwise treats a scoped package as private, which needs a paid plan.
@@ -0,0 +1,26 @@
1
+ import { z } from 'zod';
2
+ export declare const auditLogQuerySchema: z.ZodObject<{
3
+ page: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
4
+ pageSize: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
5
+ actorId: z.ZodOptional<z.ZodUUID>;
6
+ action: z.ZodOptional<z.ZodString>;
7
+ resourceType: z.ZodOptional<z.ZodString>;
8
+ resourceId: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>;
10
+ export type AuditLogQuery = z.output<typeof auditLogQuerySchema>;
11
+ export declare const auditLogResponseSchema: z.ZodObject<{
12
+ id: z.ZodUUID;
13
+ actorId: z.ZodNullable<z.ZodUUID>;
14
+ action: z.ZodString;
15
+ outcome: z.ZodEnum<{
16
+ success: "success";
17
+ failure: "failure";
18
+ }>;
19
+ resourceType: z.ZodString;
20
+ resourceId: z.ZodNullable<z.ZodString>;
21
+ requestId: z.ZodNullable<z.ZodString>;
22
+ correlationId: z.ZodNullable<z.ZodString>;
23
+ metadata: z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
24
+ createdAt: z.ZodISODateTime;
25
+ }, z.core.$strip>;
26
+ export type AuditLogResponse = z.output<typeof auditLogResponseSchema>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.auditLogResponseSchema = exports.auditLogQuerySchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const pagination_schema_js_1 = require("../common/pagination.schema.js");
6
+ const index_js_1 = require("../enums/index.js");
7
+ exports.auditLogQuerySchema = pagination_schema_js_1.paginationQuerySchema.extend({
8
+ actorId: zod_1.z.uuid().optional(),
9
+ action: zod_1.z.string().max(100).optional(),
10
+ resourceType: zod_1.z.string().max(100).optional(),
11
+ resourceId: zod_1.z.string().max(100).optional(),
12
+ });
13
+ exports.auditLogResponseSchema = zod_1.z.object({
14
+ id: zod_1.z.uuid(),
15
+ actorId: zod_1.z.uuid().nullable(),
16
+ action: zod_1.z.string(),
17
+ outcome: zod_1.z.enum(index_js_1.AUDIT_OUTCOMES),
18
+ resourceType: zod_1.z.string(),
19
+ resourceId: zod_1.z.string().nullable(),
20
+ requestId: zod_1.z.string().nullable(),
21
+ correlationId: zod_1.z.string().nullable(),
22
+ metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable(),
23
+ createdAt: zod_1.z.iso.datetime(),
24
+ });
@@ -0,0 +1 @@
1
+ export * from './audit-log.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("./audit-log.dto.js"), exports);
@@ -0,0 +1,142 @@
1
+ import { z } from 'zod';
2
+ export declare const MIN_PASSWORD_LENGTH = 12;
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;
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;
11
+ export declare const loginSchema: z.ZodObject<{
12
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
13
+ password: z.ZodString;
14
+ deviceName: z.ZodOptional<z.ZodString>;
15
+ tokenTransport: z.ZodDefault<z.ZodEnum<{
16
+ body: "body";
17
+ cookie: "cookie";
18
+ }>>;
19
+ }, z.core.$strict>;
20
+ export type LoginInput = z.input<typeof loginSchema>;
21
+ export type LoginBody = z.output<typeof loginSchema>;
22
+ export declare const refreshSchema: z.ZodDefault<z.ZodObject<{
23
+ refreshToken: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strict>>;
25
+ export type RefreshInput = z.input<typeof refreshSchema>;
26
+ export type RefreshBody = z.output<typeof refreshSchema>;
27
+ export declare const changePasswordSchema: z.ZodObject<{
28
+ currentPassword: z.ZodString;
29
+ newPassword: z.ZodString;
30
+ }, z.core.$strict>;
31
+ export type ChangePasswordInput = z.input<typeof changePasswordSchema>;
32
+ export type ChangePasswordBody = z.output<typeof changePasswordSchema>;
33
+ export declare const passwordResetRequestSchema: z.ZodObject<{
34
+ email: z.ZodPipe<z.ZodString, z.ZodEmail>;
35
+ }, z.core.$strict>;
36
+ export type PasswordResetRequestInput = z.input<typeof passwordResetRequestSchema>;
37
+ export type PasswordResetRequestBody = z.output<typeof passwordResetRequestSchema>;
38
+ export declare const passwordResetConfirmSchema: z.ZodObject<{
39
+ token: z.ZodString;
40
+ newPassword: z.ZodString;
41
+ }, z.core.$strict>;
42
+ export type PasswordResetConfirmInput = z.input<typeof passwordResetConfirmSchema>;
43
+ export type PasswordResetConfirmBody = z.output<typeof passwordResetConfirmSchema>;
44
+ export declare const setRoleSchema: z.ZodObject<{
45
+ role: z.ZodEnum<{
46
+ ADMIN: "ADMIN";
47
+ COACH: "COACH";
48
+ CUSTOMER: "CUSTOMER";
49
+ }>;
50
+ }, z.core.$strict>;
51
+ export type SetRoleInput = z.input<typeof setRoleSchema>;
52
+ export type SetRoleBody = z.output<typeof setRoleSchema>;
53
+ export declare const setStatusSchema: z.ZodObject<{
54
+ status: z.ZodEnum<{
55
+ active: "active";
56
+ disabled: "disabled";
57
+ }>;
58
+ }, z.core.$strict>;
59
+ export type SetStatusInput = z.input<typeof setStatusSchema>;
60
+ export type SetStatusBody = z.output<typeof setStatusSchema>;
61
+ export declare const idParamSchema: z.ZodUUID;
62
+ export declare const tokenResponseSchema: z.ZodObject<{
63
+ accessToken: z.ZodString;
64
+ tokenType: z.ZodLiteral<"Bearer">;
65
+ expiresInSeconds: z.ZodNumber;
66
+ refreshToken: z.ZodOptional<z.ZodString>;
67
+ csrfToken: z.ZodOptional<z.ZodString>;
68
+ sessionId: z.ZodUUID;
69
+ }, z.core.$strip>;
70
+ export type TokenResponse = z.output<typeof tokenResponseSchema>;
71
+ export declare const accountResponseSchema: z.ZodObject<{
72
+ id: z.ZodUUID;
73
+ email: z.ZodString;
74
+ role: z.ZodEnum<{
75
+ ADMIN: "ADMIN";
76
+ COACH: "COACH";
77
+ CUSTOMER: "CUSTOMER";
78
+ }>;
79
+ roles: z.ZodArray<z.ZodString>;
80
+ permissions: z.ZodArray<z.ZodString>;
81
+ lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
82
+ }, z.core.$strip>;
83
+ export type AccountResponse = z.output<typeof accountResponseSchema>;
84
+ export declare const loginResponseSchema: z.ZodObject<{
85
+ accessToken: z.ZodString;
86
+ tokenType: z.ZodLiteral<"Bearer">;
87
+ expiresInSeconds: z.ZodNumber;
88
+ refreshToken: z.ZodOptional<z.ZodString>;
89
+ csrfToken: z.ZodOptional<z.ZodString>;
90
+ sessionId: z.ZodUUID;
91
+ account: z.ZodObject<{
92
+ id: z.ZodUUID;
93
+ email: z.ZodString;
94
+ role: z.ZodEnum<{
95
+ ADMIN: "ADMIN";
96
+ COACH: "COACH";
97
+ CUSTOMER: "CUSTOMER";
98
+ }>;
99
+ roles: z.ZodArray<z.ZodString>;
100
+ permissions: z.ZodArray<z.ZodString>;
101
+ lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
102
+ }, z.core.$strip>;
103
+ }, z.core.$strip>;
104
+ export type LoginResponse = z.output<typeof loginResponseSchema>;
105
+ export declare const sessionResponseSchema: z.ZodObject<{
106
+ id: z.ZodUUID;
107
+ deviceName: z.ZodNullable<z.ZodString>;
108
+ userAgent: z.ZodNullable<z.ZodString>;
109
+ createdAt: z.ZodISODateTime;
110
+ lastUsedAt: z.ZodISODateTime;
111
+ expiresAt: z.ZodISODateTime;
112
+ current: z.ZodBoolean;
113
+ }, z.core.$strip>;
114
+ export type SessionResponse = z.output<typeof sessionResponseSchema>;
115
+ export declare const logoutAllResponseSchema: z.ZodObject<{
116
+ revokedSessions: z.ZodNumber;
117
+ }, z.core.$strip>;
118
+ export type LogoutAllResponse = z.output<typeof logoutAllResponseSchema>;
119
+ export declare const passwordResetRequestedResponseSchema: z.ZodObject<{
120
+ message: z.ZodString;
121
+ }, z.core.$strip>;
122
+ export type PasswordResetRequestedResponse = z.output<typeof passwordResetRequestedResponseSchema>;
123
+ export declare const adminAccountResponseSchema: z.ZodObject<{
124
+ id: z.ZodUUID;
125
+ email: z.ZodString;
126
+ role: z.ZodEnum<{
127
+ ADMIN: "ADMIN";
128
+ COACH: "COACH";
129
+ CUSTOMER: "CUSTOMER";
130
+ }>;
131
+ status: z.ZodEnum<{
132
+ pending_verification: "pending_verification";
133
+ active: "active";
134
+ disabled: "disabled";
135
+ }>;
136
+ lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
137
+ }, z.core.$strip>;
138
+ export type AdminAccountResponse = z.output<typeof adminAccountResponseSchema>;
139
+ export declare const revokedSessionsResponseSchema: z.ZodObject<{
140
+ revokedSessions: z.ZodNumber;
141
+ }, z.core.$strip>;
142
+ export type RevokedSessionsResponse = z.output<typeof revokedSessionsResponseSchema>;
@@ -0,0 +1,104 @@
1
+ "use strict";
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.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
+ const zod_1 = require("zod");
5
+ const contact_schema_js_1 = require("../common/contact.schema.js");
6
+ const safe_text_schema_js_1 = require("../common/safe-text.schema.js");
7
+ const index_js_1 = require("../enums/index.js");
8
+ // Per OWASP: length is what matters, with no composition rules. The upper limit
9
+ // stops very long inputs from being used to exhaust the hashing function.
10
+ exports.MIN_PASSWORD_LENGTH = 12;
11
+ exports.MAX_PASSWORD_LENGTH = 128;
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
+ });
21
+ exports.newPasswordSchema = zod_1.z
22
+ .string()
23
+ .min(exports.MIN_PASSWORD_LENGTH)
24
+ .max(exports.MAX_PASSWORD_LENGTH);
25
+ /** No minimum at login, so an old short password fails like any wrong password. */
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);
31
+ // Strict objects reject unknown fields, so an attempt to send `roles` or
32
+ // `status` fails loudly rather than being silently ignored.
33
+ exports.loginSchema = zod_1.z.strictObject({
34
+ email: contact_schema_js_1.emailSchema,
35
+ password: exports.submittedPasswordSchema,
36
+ deviceName: (0, safe_text_schema_js_1.safeTextSchema)(100).optional(),
37
+ tokenTransport: zod_1.z.enum(index_js_1.TOKEN_TRANSPORTS).default('body'),
38
+ });
39
+ exports.refreshSchema = zod_1.z
40
+ .strictObject({ refreshToken: exports.opaqueTokenSchema.optional() })
41
+ .default({});
42
+ exports.changePasswordSchema = zod_1.z.strictObject({
43
+ currentPassword: exports.submittedPasswordSchema,
44
+ newPassword: exports.newPasswordSchema,
45
+ });
46
+ exports.passwordResetRequestSchema = zod_1.z.strictObject({
47
+ email: contact_schema_js_1.emailSchema,
48
+ });
49
+ exports.passwordResetConfirmSchema = zod_1.z.strictObject({
50
+ token: exports.opaqueTokenSchema,
51
+ newPassword: exports.newPasswordSchema,
52
+ });
53
+ exports.setRoleSchema = zod_1.z.strictObject({
54
+ role: zod_1.z.enum(index_js_1.ROLES),
55
+ });
56
+ exports.setStatusSchema = zod_1.z.strictObject({
57
+ status: zod_1.z.enum(index_js_1.ADMIN_SETTABLE_ACCOUNT_STATUSES),
58
+ });
59
+ exports.idParamSchema = zod_1.z.uuid();
60
+ exports.tokenResponseSchema = zod_1.z.object({
61
+ accessToken: zod_1.z.string(),
62
+ tokenType: zod_1.z.literal('Bearer'),
63
+ expiresInSeconds: zod_1.z.number().int(),
64
+ refreshToken: zod_1.z.string().optional(),
65
+ csrfToken: zod_1.z.string().optional(),
66
+ sessionId: zod_1.z.uuid(),
67
+ });
68
+ exports.accountResponseSchema = zod_1.z.object({
69
+ id: zod_1.z.uuid(),
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`. */
73
+ roles: zod_1.z.array(zod_1.z.string()),
74
+ permissions: zod_1.z.array(zod_1.z.string()),
75
+ lastLoginAt: zod_1.z.iso.datetime().nullable(),
76
+ });
77
+ exports.loginResponseSchema = exports.tokenResponseSchema.extend({
78
+ account: exports.accountResponseSchema,
79
+ });
80
+ exports.sessionResponseSchema = zod_1.z.object({
81
+ id: zod_1.z.uuid(),
82
+ deviceName: zod_1.z.string().nullable(),
83
+ userAgent: zod_1.z.string().nullable(),
84
+ createdAt: zod_1.z.iso.datetime(),
85
+ lastUsedAt: zod_1.z.iso.datetime(),
86
+ expiresAt: zod_1.z.iso.datetime(),
87
+ current: zod_1.z.boolean(),
88
+ });
89
+ exports.logoutAllResponseSchema = zod_1.z.object({
90
+ revokedSessions: zod_1.z.number().int(),
91
+ });
92
+ exports.passwordResetRequestedResponseSchema = zod_1.z.object({
93
+ message: zod_1.z.string(),
94
+ });
95
+ exports.adminAccountResponseSchema = zod_1.z.object({
96
+ id: zod_1.z.uuid(),
97
+ email: zod_1.z.string(),
98
+ role: zod_1.z.enum(index_js_1.ROLES),
99
+ status: zod_1.z.enum(index_js_1.ACCOUNT_STATUSES),
100
+ lastLoginAt: zod_1.z.iso.datetime().nullable(),
101
+ });
102
+ exports.revokedSessionsResponseSchema = zod_1.z.object({
103
+ revokedSessions: zod_1.z.number().int(),
104
+ });
@@ -0,0 +1 @@
1
+ export * from './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("./auth.dto.js"), exports);
@@ -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);