@tbs-fitness/contract 0.2.0 → 0.4.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 +21 -0
- package/dist/cjs/app-settings/app-settings.dto.d.ts +124 -0
- package/dist/cjs/app-settings/app-settings.dto.js +94 -0
- package/dist/cjs/app-settings/index.d.ts +1 -0
- package/dist/cjs/app-settings/index.js +17 -0
- package/dist/cjs/audit/audit-log.dto.js +2 -1
- package/dist/cjs/auth/auth.dto.d.ts +36 -0
- package/dist/cjs/auth/auth.dto.js +28 -8
- package/dist/cjs/coach/coach-auth.dto.d.ts +12 -0
- package/dist/cjs/coach/coach-auth.dto.js +18 -6
- package/dist/cjs/common/api-response.schema.js +2 -1
- package/dist/cjs/common/date-time.schema.d.ts +39 -0
- package/dist/cjs/common/date-time.schema.js +112 -0
- package/dist/cjs/common/index.d.ts +1 -0
- package/dist/cjs/common/index.js +1 -0
- package/dist/cjs/communication/index.d.ts +2 -0
- package/dist/cjs/communication/index.js +18 -0
- package/dist/cjs/communication/message-catalogue.d.ts +26 -0
- package/dist/cjs/communication/message-catalogue.js +53 -0
- package/dist/cjs/communication/template.dto.d.ts +240 -0
- package/dist/cjs/communication/template.dto.js +206 -0
- package/dist/cjs/enums/index.d.ts +26 -0
- package/dist/cjs/enums/index.js +32 -1
- package/dist/cjs/feature-flags/feature-flag.dto.js +10 -9
- package/dist/esm/app-settings/app-settings.dto.d.ts +124 -0
- package/dist/esm/app-settings/app-settings.dto.js +90 -0
- package/dist/esm/app-settings/index.d.ts +1 -0
- package/dist/esm/app-settings/index.js +1 -0
- package/dist/esm/audit/audit-log.dto.js +2 -1
- package/dist/esm/auth/auth.dto.d.ts +36 -0
- package/dist/esm/auth/auth.dto.js +28 -8
- package/dist/esm/coach/coach-auth.dto.d.ts +12 -0
- package/dist/esm/coach/coach-auth.dto.js +19 -7
- package/dist/esm/common/api-response.schema.js +2 -1
- package/dist/esm/common/date-time.schema.d.ts +39 -0
- package/dist/esm/common/date-time.schema.js +107 -0
- package/dist/esm/common/index.d.ts +1 -0
- package/dist/esm/common/index.js +1 -0
- package/dist/esm/communication/index.d.ts +2 -0
- package/dist/esm/communication/index.js +2 -0
- package/dist/esm/communication/message-catalogue.d.ts +26 -0
- package/dist/esm/communication/message-catalogue.js +50 -0
- package/dist/esm/communication/template.dto.d.ts +240 -0
- package/dist/esm/communication/template.dto.js +200 -0
- package/dist/esm/enums/index.d.ts +26 -0
- package/dist/esm/enums/index.js +31 -0
- package/dist/esm/feature-flags/feature-flag.dto.js +10 -9
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -41,6 +41,27 @@ const result = createFlagSchema.safeParse(input); // The same rules as the API.
|
|
|
41
41
|
|
|
42
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
43
|
|
|
44
|
+
## Version 0.4.0
|
|
45
|
+
|
|
46
|
+
Communication and runtime settings. Additive; consumers install `^0.4.0` explicitly.
|
|
47
|
+
|
|
48
|
+
- `/enums`: `COMMUNICATION_CHANNELS` (`EMAIL`, `SMS`), `MESSAGE_TYPES`, `DELIVERY_STATUSES` and `TEMPLATE_STATUSES`.
|
|
49
|
+
- New `/communication`:
|
|
50
|
+
- `MESSAGE_CATALOGUE`: per message type, the channels that may carry it, the default switches, and the variables its sender supplies, with the required ones.
|
|
51
|
+
- `templatePlaceholders`, `hasMalformedPlaceholder` and `templateProblems`, the template rules shared by the server and the admin editor.
|
|
52
|
+
- `createTemplateSchema`, `templateResponseSchema`, `previewTemplateSchema`, `renderedMessageSchema`, `testSendResponseSchema` and `messageTypeResponseSchema`.
|
|
53
|
+
- New `/app-settings`: `APP_SETTING_KEYS`, a value schema and default per key (`communication.channels` master switches, `communication.messages` per type and channel), plus `appSettingResponseSchema`, `updateAppSettingSchema` (`{ value, version }`) and `appSettingHistoryResponseSchema`.
|
|
54
|
+
|
|
55
|
+
## Version 0.3.0
|
|
56
|
+
|
|
57
|
+
Time zones and the platform's date and time rules. Additive, but a caret range on 0.x does not cross minor versions, so consumers install `^0.3.0` explicitly.
|
|
58
|
+
|
|
59
|
+
- `/common`: `DEFAULT_TIMEZONE` (`UTC`), `isValidTimezone`, `canonicalTimezone` (the current IANA name for a renamed zone, such as `Asia/Kolkata` for `Asia/Calcutta`, which Node and some browsers still report; both schemas below apply it), `timezoneSchema` (an IANA `Area/Location` name or `UTC`; abbreviations such as `IST` and offsets such as `+05:30` are refused), `detectedTimezoneSchema` (a browser suggestion: unusable values become `undefined`), `utcTimestampSchema` (response instants, `Z` only), `instantInputSchema` (request instants, `Z` or an explicit offset, never a bare local time) and `dateOnlySchema` (`YYYY-MM-DD`, never shifted between zones).
|
|
60
|
+
- `/enums`: `TIMEZONE_SOURCES` (`AUTO`, `MANUAL`).
|
|
61
|
+
- `/auth`: `timezonePreferenceSchema`, `updateTimezoneSchema` (`{ timezone, source? }`, source defaults to `MANUAL`), and `timezone` and `timezoneSource` on `accountResponseSchema`.
|
|
62
|
+
- `/coach`: an optional `timezone` on `coachSignupSchema` and `coachLoginSchema`, and `timezone` and `timezoneSource` on `coachProfileSchema`. Both response fields are required, so deploy the backend before a client built on 0.3.0.
|
|
63
|
+
- Every response timestamp now uses `utcTimestampSchema`, which is the same rule as before. Feature-flag request timestamps use `instantInputSchema`.
|
|
64
|
+
|
|
44
65
|
## Version 0.2.0 (breaking)
|
|
45
66
|
|
|
46
67
|
- `ROLES` is now `ADMIN`, `COACH` and `CUSTOMER`. A user has exactly one role.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type MessageType } from '../enums/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Runtime settings an administrator changes without a deploy. Each key has a
|
|
5
|
+
* value schema here, which both the server and the admin screen use. A key
|
|
6
|
+
* with no saved value uses its default.
|
|
7
|
+
*/
|
|
8
|
+
export declare const APP_SETTING_KEYS: readonly ["communication.channels", "communication.messages"];
|
|
9
|
+
export type AppSettingKey = (typeof APP_SETTING_KEYS)[number];
|
|
10
|
+
/** A switch per channel. */
|
|
11
|
+
export declare const channelSwitchesSchema: z.ZodObject<{
|
|
12
|
+
EMAIL: z.ZodBoolean;
|
|
13
|
+
SMS: z.ZodBoolean;
|
|
14
|
+
}, z.core.$strict>;
|
|
15
|
+
export type ChannelSwitches = z.output<typeof channelSwitchesSchema>;
|
|
16
|
+
/**
|
|
17
|
+
* Master switches: a channel switched off here sends nothing, whatever the
|
|
18
|
+
* per-message settings say.
|
|
19
|
+
*/
|
|
20
|
+
export declare const communicationChannelsSettingSchema: z.ZodObject<{
|
|
21
|
+
EMAIL: z.ZodBoolean;
|
|
22
|
+
SMS: z.ZodBoolean;
|
|
23
|
+
}, z.core.$strict>;
|
|
24
|
+
/**
|
|
25
|
+
* Per message type and channel. A type missing from a saved value uses its
|
|
26
|
+
* catalogue defaults, so a newly added message type needs no data change.
|
|
27
|
+
*/
|
|
28
|
+
export declare const communicationMessagesSettingSchema: z.ZodRecord<z.ZodEnum<{
|
|
29
|
+
"auth.otp.signup_verification": "auth.otp.signup_verification";
|
|
30
|
+
"auth.otp.password_reset": "auth.otp.password_reset";
|
|
31
|
+
"auth.password_reset_link": "auth.password_reset_link";
|
|
32
|
+
}> & z.core.$partial, z.ZodObject<{
|
|
33
|
+
EMAIL: z.ZodBoolean;
|
|
34
|
+
SMS: z.ZodBoolean;
|
|
35
|
+
}, z.core.$strict>>;
|
|
36
|
+
export type CommunicationMessagesSetting = z.output<typeof communicationMessagesSettingSchema>;
|
|
37
|
+
export declare const APP_SETTING_VALUE_SCHEMAS: {
|
|
38
|
+
readonly 'communication.channels': z.ZodObject<{
|
|
39
|
+
EMAIL: z.ZodBoolean;
|
|
40
|
+
SMS: z.ZodBoolean;
|
|
41
|
+
}, z.core.$strict>;
|
|
42
|
+
readonly 'communication.messages': z.ZodRecord<z.ZodEnum<{
|
|
43
|
+
"auth.otp.signup_verification": "auth.otp.signup_verification";
|
|
44
|
+
"auth.otp.password_reset": "auth.otp.password_reset";
|
|
45
|
+
"auth.password_reset_link": "auth.password_reset_link";
|
|
46
|
+
}> & z.core.$partial, z.ZodObject<{
|
|
47
|
+
EMAIL: z.ZodBoolean;
|
|
48
|
+
SMS: z.ZodBoolean;
|
|
49
|
+
}, z.core.$strict>>;
|
|
50
|
+
};
|
|
51
|
+
export interface AppSettingValues {
|
|
52
|
+
'communication.channels': ChannelSwitches;
|
|
53
|
+
'communication.messages': CommunicationMessagesSetting;
|
|
54
|
+
}
|
|
55
|
+
/** Every message type, with its catalogue defaults: the effective value with nothing saved. */
|
|
56
|
+
export declare function defaultMessageSettings(): Record<MessageType, ChannelSwitches>;
|
|
57
|
+
export declare const APP_SETTING_DEFAULTS: AppSettingValues;
|
|
58
|
+
export declare const appSettingKeyParamSchema: z.ZodEnum<{
|
|
59
|
+
"communication.channels": "communication.channels";
|
|
60
|
+
"communication.messages": "communication.messages";
|
|
61
|
+
}>;
|
|
62
|
+
export declare const appSettingResponseSchema: z.ZodObject<{
|
|
63
|
+
key: z.ZodEnum<{
|
|
64
|
+
"communication.channels": "communication.channels";
|
|
65
|
+
"communication.messages": "communication.messages";
|
|
66
|
+
}>;
|
|
67
|
+
label: z.ZodString;
|
|
68
|
+
description: z.ZodString;
|
|
69
|
+
value: z.ZodUnknown;
|
|
70
|
+
defaultValue: z.ZodUnknown;
|
|
71
|
+
version: z.ZodNumber;
|
|
72
|
+
updatedBy: z.ZodNullable<z.ZodUUID>;
|
|
73
|
+
updatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
export type AppSettingResponse = z.output<typeof appSettingResponseSchema>;
|
|
76
|
+
export declare const appSettingListResponseSchema: z.ZodArray<z.ZodObject<{
|
|
77
|
+
key: z.ZodEnum<{
|
|
78
|
+
"communication.channels": "communication.channels";
|
|
79
|
+
"communication.messages": "communication.messages";
|
|
80
|
+
}>;
|
|
81
|
+
label: z.ZodString;
|
|
82
|
+
description: z.ZodString;
|
|
83
|
+
value: z.ZodUnknown;
|
|
84
|
+
defaultValue: z.ZodUnknown;
|
|
85
|
+
version: z.ZodNumber;
|
|
86
|
+
updatedBy: z.ZodNullable<z.ZodUUID>;
|
|
87
|
+
updatedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
88
|
+
}, z.core.$strip>>;
|
|
89
|
+
/**
|
|
90
|
+
* Replaces a setting's value. `version` must be the one last read, so a
|
|
91
|
+
* change made in between is not silently overwritten. The value is checked
|
|
92
|
+
* against the key's schema on the server.
|
|
93
|
+
*/
|
|
94
|
+
export declare const updateAppSettingSchema: z.ZodObject<{
|
|
95
|
+
value: z.ZodUnknown;
|
|
96
|
+
version: z.ZodNumber;
|
|
97
|
+
}, z.core.$strict>;
|
|
98
|
+
export type UpdateAppSettingInput = z.input<typeof updateAppSettingSchema>;
|
|
99
|
+
export type UpdateAppSettingBody = z.output<typeof updateAppSettingSchema>;
|
|
100
|
+
export declare const appSettingHistoryEntrySchema: z.ZodObject<{
|
|
101
|
+
id: z.ZodUUID;
|
|
102
|
+
key: z.ZodEnum<{
|
|
103
|
+
"communication.channels": "communication.channels";
|
|
104
|
+
"communication.messages": "communication.messages";
|
|
105
|
+
}>;
|
|
106
|
+
previousValue: z.ZodUnknown;
|
|
107
|
+
newValue: z.ZodUnknown;
|
|
108
|
+
version: z.ZodNumber;
|
|
109
|
+
actorUserId: z.ZodUUID;
|
|
110
|
+
createdAt: z.ZodISODateTime;
|
|
111
|
+
}, z.core.$strip>;
|
|
112
|
+
export type AppSettingHistoryEntry = z.output<typeof appSettingHistoryEntrySchema>;
|
|
113
|
+
export declare const appSettingHistoryResponseSchema: z.ZodArray<z.ZodObject<{
|
|
114
|
+
id: z.ZodUUID;
|
|
115
|
+
key: z.ZodEnum<{
|
|
116
|
+
"communication.channels": "communication.channels";
|
|
117
|
+
"communication.messages": "communication.messages";
|
|
118
|
+
}>;
|
|
119
|
+
previousValue: z.ZodUnknown;
|
|
120
|
+
newValue: z.ZodUnknown;
|
|
121
|
+
version: z.ZodNumber;
|
|
122
|
+
actorUserId: z.ZodUUID;
|
|
123
|
+
createdAt: z.ZodISODateTime;
|
|
124
|
+
}, z.core.$strip>>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appSettingHistoryResponseSchema = exports.appSettingHistoryEntrySchema = exports.updateAppSettingSchema = exports.appSettingListResponseSchema = exports.appSettingResponseSchema = exports.appSettingKeyParamSchema = exports.APP_SETTING_DEFAULTS = exports.APP_SETTING_VALUE_SCHEMAS = exports.communicationMessagesSettingSchema = exports.communicationChannelsSettingSchema = exports.channelSwitchesSchema = exports.APP_SETTING_KEYS = void 0;
|
|
4
|
+
exports.defaultMessageSettings = defaultMessageSettings;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const date_time_schema_js_1 = require("../common/date-time.schema.js");
|
|
7
|
+
const message_catalogue_js_1 = require("../communication/message-catalogue.js");
|
|
8
|
+
const index_js_1 = require("../enums/index.js");
|
|
9
|
+
/**
|
|
10
|
+
* Runtime settings an administrator changes without a deploy. Each key has a
|
|
11
|
+
* value schema here, which both the server and the admin screen use. A key
|
|
12
|
+
* with no saved value uses its default.
|
|
13
|
+
*/
|
|
14
|
+
exports.APP_SETTING_KEYS = [
|
|
15
|
+
'communication.channels',
|
|
16
|
+
'communication.messages',
|
|
17
|
+
];
|
|
18
|
+
/** A switch per channel. */
|
|
19
|
+
exports.channelSwitchesSchema = zod_1.z.strictObject({
|
|
20
|
+
EMAIL: zod_1.z.boolean(),
|
|
21
|
+
SMS: zod_1.z.boolean(),
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Master switches: a channel switched off here sends nothing, whatever the
|
|
25
|
+
* per-message settings say.
|
|
26
|
+
*/
|
|
27
|
+
exports.communicationChannelsSettingSchema = exports.channelSwitchesSchema;
|
|
28
|
+
/**
|
|
29
|
+
* Per message type and channel. A type missing from a saved value uses its
|
|
30
|
+
* catalogue defaults, so a newly added message type needs no data change.
|
|
31
|
+
*/
|
|
32
|
+
exports.communicationMessagesSettingSchema = zod_1.z
|
|
33
|
+
.partialRecord(zod_1.z.enum(index_js_1.MESSAGE_TYPES), exports.channelSwitchesSchema)
|
|
34
|
+
.superRefine((value, ctx) => {
|
|
35
|
+
for (const [type, switches] of Object.entries(value)) {
|
|
36
|
+
const allowed = message_catalogue_js_1.MESSAGE_CATALOGUE[type].channels;
|
|
37
|
+
for (const [channel, on] of Object.entries(switches ?? {})) {
|
|
38
|
+
if (on && !allowed.includes(channel)) {
|
|
39
|
+
ctx.addIssue({
|
|
40
|
+
code: 'custom',
|
|
41
|
+
path: [type, channel],
|
|
42
|
+
message: `${message_catalogue_js_1.MESSAGE_CATALOGUE[type].label} cannot be sent by ${channel}`,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
exports.APP_SETTING_VALUE_SCHEMAS = {
|
|
49
|
+
'communication.channels': exports.communicationChannelsSettingSchema,
|
|
50
|
+
'communication.messages': exports.communicationMessagesSettingSchema,
|
|
51
|
+
};
|
|
52
|
+
/** Every message type, with its catalogue defaults: the effective value with nothing saved. */
|
|
53
|
+
function defaultMessageSettings() {
|
|
54
|
+
return Object.fromEntries(index_js_1.MESSAGE_TYPES.map((type) => [
|
|
55
|
+
type,
|
|
56
|
+
{ ...message_catalogue_js_1.MESSAGE_CATALOGUE[type].defaultChannels },
|
|
57
|
+
]));
|
|
58
|
+
}
|
|
59
|
+
exports.APP_SETTING_DEFAULTS = {
|
|
60
|
+
'communication.channels': { EMAIL: true, SMS: true },
|
|
61
|
+
'communication.messages': defaultMessageSettings(),
|
|
62
|
+
};
|
|
63
|
+
exports.appSettingKeyParamSchema = zod_1.z.enum(exports.APP_SETTING_KEYS);
|
|
64
|
+
exports.appSettingResponseSchema = zod_1.z.object({
|
|
65
|
+
key: zod_1.z.enum(exports.APP_SETTING_KEYS),
|
|
66
|
+
label: zod_1.z.string(),
|
|
67
|
+
description: zod_1.z.string(),
|
|
68
|
+
value: zod_1.z.unknown(),
|
|
69
|
+
defaultValue: zod_1.z.unknown(),
|
|
70
|
+
/** 0 until the setting is first saved. Send it back to update. */
|
|
71
|
+
version: zod_1.z.number().int(),
|
|
72
|
+
updatedBy: zod_1.z.uuid().nullable(),
|
|
73
|
+
updatedAt: date_time_schema_js_1.utcTimestampSchema.nullable(),
|
|
74
|
+
});
|
|
75
|
+
exports.appSettingListResponseSchema = zod_1.z.array(exports.appSettingResponseSchema);
|
|
76
|
+
/**
|
|
77
|
+
* Replaces a setting's value. `version` must be the one last read, so a
|
|
78
|
+
* change made in between is not silently overwritten. The value is checked
|
|
79
|
+
* against the key's schema on the server.
|
|
80
|
+
*/
|
|
81
|
+
exports.updateAppSettingSchema = zod_1.z.strictObject({
|
|
82
|
+
value: zod_1.z.unknown(),
|
|
83
|
+
version: zod_1.z.number().int().min(0),
|
|
84
|
+
});
|
|
85
|
+
exports.appSettingHistoryEntrySchema = zod_1.z.object({
|
|
86
|
+
id: zod_1.z.uuid(),
|
|
87
|
+
key: zod_1.z.enum(exports.APP_SETTING_KEYS),
|
|
88
|
+
previousValue: zod_1.z.unknown(),
|
|
89
|
+
newValue: zod_1.z.unknown(),
|
|
90
|
+
version: zod_1.z.number().int(),
|
|
91
|
+
actorUserId: zod_1.z.uuid(),
|
|
92
|
+
createdAt: date_time_schema_js_1.utcTimestampSchema,
|
|
93
|
+
});
|
|
94
|
+
exports.appSettingHistoryResponseSchema = zod_1.z.array(exports.appSettingHistoryEntrySchema);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './app-settings.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("./app-settings.dto.js"), exports);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.auditLogResponseSchema = exports.auditLogQuerySchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const date_time_schema_js_1 = require("../common/date-time.schema.js");
|
|
5
6
|
const pagination_schema_js_1 = require("../common/pagination.schema.js");
|
|
6
7
|
const index_js_1 = require("../enums/index.js");
|
|
7
8
|
exports.auditLogQuerySchema = pagination_schema_js_1.paginationQuerySchema.extend({
|
|
@@ -20,5 +21,5 @@ exports.auditLogResponseSchema = zod_1.z.object({
|
|
|
20
21
|
requestId: zod_1.z.string().nullable(),
|
|
21
22
|
correlationId: zod_1.z.string().nullable(),
|
|
22
23
|
metadata: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable(),
|
|
23
|
-
createdAt:
|
|
24
|
+
createdAt: date_time_schema_js_1.utcTimestampSchema,
|
|
24
25
|
});
|
|
@@ -68,6 +68,32 @@ export declare const tokenResponseSchema: z.ZodObject<{
|
|
|
68
68
|
sessionId: z.ZodUUID;
|
|
69
69
|
}, z.core.$strip>;
|
|
70
70
|
export type TokenResponse = z.output<typeof tokenResponseSchema>;
|
|
71
|
+
/**
|
|
72
|
+
* A user's time zone preference: an IANA zone, and whether it was detected
|
|
73
|
+
* (`AUTO`) or chosen (`MANUAL`).
|
|
74
|
+
*/
|
|
75
|
+
export declare const timezonePreferenceSchema: z.ZodObject<{
|
|
76
|
+
timezone: z.ZodString;
|
|
77
|
+
timezoneSource: z.ZodEnum<{
|
|
78
|
+
AUTO: "AUTO";
|
|
79
|
+
MANUAL: "MANUAL";
|
|
80
|
+
}>;
|
|
81
|
+
}, z.core.$strip>;
|
|
82
|
+
export type TimezonePreference = z.output<typeof timezonePreferenceSchema>;
|
|
83
|
+
/**
|
|
84
|
+
* Sets the signed-in user's own time zone. `MANUAL` (the default) is a choice
|
|
85
|
+
* the user made. `AUTO` records a detected zone that a later sign-in may
|
|
86
|
+
* replace.
|
|
87
|
+
*/
|
|
88
|
+
export declare const updateTimezoneSchema: z.ZodObject<{
|
|
89
|
+
timezone: z.ZodPipe<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>, z.ZodTransform<string, string>>;
|
|
90
|
+
source: z.ZodDefault<z.ZodEnum<{
|
|
91
|
+
AUTO: "AUTO";
|
|
92
|
+
MANUAL: "MANUAL";
|
|
93
|
+
}>>;
|
|
94
|
+
}, z.core.$strict>;
|
|
95
|
+
export type UpdateTimezoneInput = z.input<typeof updateTimezoneSchema>;
|
|
96
|
+
export type UpdateTimezoneBody = z.output<typeof updateTimezoneSchema>;
|
|
71
97
|
export declare const accountResponseSchema: z.ZodObject<{
|
|
72
98
|
id: z.ZodUUID;
|
|
73
99
|
email: z.ZodString;
|
|
@@ -79,6 +105,11 @@ export declare const accountResponseSchema: z.ZodObject<{
|
|
|
79
105
|
roles: z.ZodArray<z.ZodString>;
|
|
80
106
|
permissions: z.ZodArray<z.ZodString>;
|
|
81
107
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
108
|
+
timezone: z.ZodString;
|
|
109
|
+
timezoneSource: z.ZodEnum<{
|
|
110
|
+
AUTO: "AUTO";
|
|
111
|
+
MANUAL: "MANUAL";
|
|
112
|
+
}>;
|
|
82
113
|
}, z.core.$strip>;
|
|
83
114
|
export type AccountResponse = z.output<typeof accountResponseSchema>;
|
|
84
115
|
export declare const loginResponseSchema: z.ZodObject<{
|
|
@@ -99,6 +130,11 @@ export declare const loginResponseSchema: z.ZodObject<{
|
|
|
99
130
|
roles: z.ZodArray<z.ZodString>;
|
|
100
131
|
permissions: z.ZodArray<z.ZodString>;
|
|
101
132
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
133
|
+
timezone: z.ZodString;
|
|
134
|
+
timezoneSource: z.ZodEnum<{
|
|
135
|
+
AUTO: "AUTO";
|
|
136
|
+
MANUAL: "MANUAL";
|
|
137
|
+
}>;
|
|
102
138
|
}, z.core.$strip>;
|
|
103
139
|
}, z.core.$strip>;
|
|
104
140
|
export type LoginResponse = z.output<typeof loginResponseSchema>;
|
|
@@ -1,8 +1,9 @@
|
|
|
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.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;
|
|
3
|
+
exports.revokedSessionsResponseSchema = exports.adminAccountResponseSchema = exports.passwordResetRequestedResponseSchema = exports.logoutAllResponseSchema = exports.sessionResponseSchema = exports.loginResponseSchema = exports.accountResponseSchema = exports.updateTimezoneSchema = exports.timezonePreferenceSchema = 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
|
+
const date_time_schema_js_1 = require("../common/date-time.schema.js");
|
|
6
7
|
const safe_text_schema_js_1 = require("../common/safe-text.schema.js");
|
|
7
8
|
const index_js_1 = require("../enums/index.js");
|
|
8
9
|
// Per OWASP: length is what matters, with no composition rules. The upper limit
|
|
@@ -65,15 +66,34 @@ exports.tokenResponseSchema = zod_1.z.object({
|
|
|
65
66
|
csrfToken: zod_1.z.string().optional(),
|
|
66
67
|
sessionId: zod_1.z.uuid(),
|
|
67
68
|
});
|
|
68
|
-
|
|
69
|
+
/**
|
|
70
|
+
* A user's time zone preference: an IANA zone, and whether it was detected
|
|
71
|
+
* (`AUTO`) or chosen (`MANUAL`).
|
|
72
|
+
*/
|
|
73
|
+
exports.timezonePreferenceSchema = zod_1.z.object({
|
|
74
|
+
timezone: zod_1.z.string(),
|
|
75
|
+
timezoneSource: zod_1.z.enum(index_js_1.TIMEZONE_SOURCES),
|
|
76
|
+
});
|
|
77
|
+
/**
|
|
78
|
+
* Sets the signed-in user's own time zone. `MANUAL` (the default) is a choice
|
|
79
|
+
* the user made. `AUTO` records a detected zone that a later sign-in may
|
|
80
|
+
* replace.
|
|
81
|
+
*/
|
|
82
|
+
exports.updateTimezoneSchema = zod_1.z.strictObject({
|
|
83
|
+
timezone: date_time_schema_js_1.timezoneSchema,
|
|
84
|
+
source: zod_1.z.enum(index_js_1.TIMEZONE_SOURCES).default('MANUAL'),
|
|
85
|
+
});
|
|
86
|
+
exports.accountResponseSchema = zod_1.z
|
|
87
|
+
.object({
|
|
69
88
|
id: zod_1.z.uuid(),
|
|
70
89
|
email: zod_1.z.string(),
|
|
71
90
|
role: zod_1.z.enum(index_js_1.ROLES),
|
|
72
91
|
/** @deprecated Always `[role]`. Kept for clients written before `role`. */
|
|
73
92
|
roles: zod_1.z.array(zod_1.z.string()),
|
|
74
93
|
permissions: zod_1.z.array(zod_1.z.string()),
|
|
75
|
-
lastLoginAt:
|
|
76
|
-
})
|
|
94
|
+
lastLoginAt: date_time_schema_js_1.utcTimestampSchema.nullable(),
|
|
95
|
+
})
|
|
96
|
+
.extend(exports.timezonePreferenceSchema.shape);
|
|
77
97
|
exports.loginResponseSchema = exports.tokenResponseSchema.extend({
|
|
78
98
|
account: exports.accountResponseSchema,
|
|
79
99
|
});
|
|
@@ -81,9 +101,9 @@ exports.sessionResponseSchema = zod_1.z.object({
|
|
|
81
101
|
id: zod_1.z.uuid(),
|
|
82
102
|
deviceName: zod_1.z.string().nullable(),
|
|
83
103
|
userAgent: zod_1.z.string().nullable(),
|
|
84
|
-
createdAt:
|
|
85
|
-
lastUsedAt:
|
|
86
|
-
expiresAt:
|
|
104
|
+
createdAt: date_time_schema_js_1.utcTimestampSchema,
|
|
105
|
+
lastUsedAt: date_time_schema_js_1.utcTimestampSchema,
|
|
106
|
+
expiresAt: date_time_schema_js_1.utcTimestampSchema,
|
|
87
107
|
current: zod_1.z.boolean(),
|
|
88
108
|
});
|
|
89
109
|
exports.logoutAllResponseSchema = zod_1.z.object({
|
|
@@ -97,7 +117,7 @@ exports.adminAccountResponseSchema = zod_1.z.object({
|
|
|
97
117
|
email: zod_1.z.string(),
|
|
98
118
|
role: zod_1.z.enum(index_js_1.ROLES),
|
|
99
119
|
status: zod_1.z.enum(index_js_1.ACCOUNT_STATUSES),
|
|
100
|
-
lastLoginAt:
|
|
120
|
+
lastLoginAt: date_time_schema_js_1.utcTimestampSchema.nullable(),
|
|
101
121
|
});
|
|
102
122
|
exports.revokedSessionsResponseSchema = zod_1.z.object({
|
|
103
123
|
revokedSessions: zod_1.z.number().int(),
|
|
@@ -4,6 +4,7 @@ export declare const coachSignupSchema: z.ZodObject<{
|
|
|
4
4
|
email: z.ZodPipe<z.ZodString, z.ZodEmail>;
|
|
5
5
|
phone: z.ZodOptional<z.ZodString>;
|
|
6
6
|
password: z.ZodString;
|
|
7
|
+
timezone: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodTransform<string | undefined, unknown>>>;
|
|
7
8
|
}, z.core.$strict>;
|
|
8
9
|
export type CoachSignupInput = z.input<typeof coachSignupSchema>;
|
|
9
10
|
export type CoachSignupBody = z.output<typeof coachSignupSchema>;
|
|
@@ -29,6 +30,7 @@ export declare const coachLoginSchema: z.ZodObject<{
|
|
|
29
30
|
password: z.ZodString;
|
|
30
31
|
deviceName: z.ZodOptional<z.ZodString>;
|
|
31
32
|
rememberMe: z.ZodDefault<z.ZodBoolean>;
|
|
33
|
+
timezone: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodTransform<string | undefined, unknown>>>;
|
|
32
34
|
}, z.core.$strict>;
|
|
33
35
|
export type CoachLoginInput = z.input<typeof coachLoginSchema>;
|
|
34
36
|
export type CoachLoginBody = z.output<typeof coachLoginSchema>;
|
|
@@ -74,6 +76,11 @@ export declare const coachProfileSchema: z.ZodObject<{
|
|
|
74
76
|
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
75
77
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
76
78
|
createdAt: z.ZodISODateTime;
|
|
79
|
+
timezone: z.ZodString;
|
|
80
|
+
timezoneSource: z.ZodEnum<{
|
|
81
|
+
AUTO: "AUTO";
|
|
82
|
+
MANUAL: "MANUAL";
|
|
83
|
+
}>;
|
|
77
84
|
}, z.core.$strip>;
|
|
78
85
|
export type CoachProfile = z.output<typeof coachProfileSchema>;
|
|
79
86
|
export declare const coachLoginResponseSchema: z.ZodObject<{
|
|
@@ -97,6 +104,11 @@ export declare const coachLoginResponseSchema: z.ZodObject<{
|
|
|
97
104
|
emailVerifiedAt: z.ZodNullable<z.ZodISODateTime>;
|
|
98
105
|
lastLoginAt: z.ZodNullable<z.ZodISODateTime>;
|
|
99
106
|
createdAt: z.ZodISODateTime;
|
|
107
|
+
timezone: z.ZodString;
|
|
108
|
+
timezoneSource: z.ZodEnum<{
|
|
109
|
+
AUTO: "AUTO";
|
|
110
|
+
MANUAL: "MANUAL";
|
|
111
|
+
}>;
|
|
100
112
|
}, z.core.$strip>;
|
|
101
113
|
}, z.core.$strip>;
|
|
102
114
|
export type CoachLoginResponse = z.output<typeof coachLoginResponseSchema>;
|
|
@@ -4,6 +4,7 @@ exports.coachLoginResponseSchema = exports.coachProfileSchema = exports.resetTok
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const auth_dto_js_1 = require("../auth/auth.dto.js");
|
|
6
6
|
const contact_schema_js_1 = require("../common/contact.schema.js");
|
|
7
|
+
const date_time_schema_js_1 = require("../common/date-time.schema.js");
|
|
7
8
|
const safe_text_schema_js_1 = require("../common/safe-text.schema.js");
|
|
8
9
|
const index_js_1 = require("../enums/index.js");
|
|
9
10
|
exports.coachSignupSchema = zod_1.z.strictObject({
|
|
@@ -11,6 +12,8 @@ exports.coachSignupSchema = zod_1.z.strictObject({
|
|
|
11
12
|
email: contact_schema_js_1.emailSchema,
|
|
12
13
|
phone: contact_schema_js_1.phoneSchema.optional(),
|
|
13
14
|
password: auth_dto_js_1.newPasswordSchema,
|
|
15
|
+
/** The browser's time zone. Missing or unusable becomes UTC on the server. */
|
|
16
|
+
timezone: date_time_schema_js_1.detectedTimezoneSchema,
|
|
14
17
|
});
|
|
15
18
|
/** Used by both resend endpoints and by forgot-password. */
|
|
16
19
|
exports.otpEmailSchema = zod_1.z.strictObject({ email: contact_schema_js_1.emailSchema });
|
|
@@ -25,7 +28,14 @@ exports.verifyOtpSchema = zod_1.z.strictObject({
|
|
|
25
28
|
*/
|
|
26
29
|
exports.coachLoginSchema = auth_dto_js_1.loginSchema
|
|
27
30
|
.omit({ tokenTransport: true })
|
|
28
|
-
.extend({
|
|
31
|
+
.extend({
|
|
32
|
+
rememberMe: zod_1.z.boolean().default(true),
|
|
33
|
+
/**
|
|
34
|
+
* The browser's time zone. It replaces the saved one only while the
|
|
35
|
+
* coach's preference is `AUTO`; a manual choice is never overwritten.
|
|
36
|
+
*/
|
|
37
|
+
timezone: date_time_schema_js_1.detectedTimezoneSchema,
|
|
38
|
+
});
|
|
29
39
|
exports.resetPasswordSchema = zod_1.z.strictObject({
|
|
30
40
|
resetToken: auth_dto_js_1.opaqueTokenSchema,
|
|
31
41
|
newPassword: auth_dto_js_1.newPasswordSchema,
|
|
@@ -49,17 +59,19 @@ exports.resetTokenResponseSchema = zod_1.z.object({
|
|
|
49
59
|
resetToken: zod_1.z.string(),
|
|
50
60
|
expiresInSeconds: zod_1.z.number().int(),
|
|
51
61
|
});
|
|
52
|
-
exports.coachProfileSchema = zod_1.z
|
|
62
|
+
exports.coachProfileSchema = zod_1.z
|
|
63
|
+
.object({
|
|
53
64
|
id: zod_1.z.uuid(),
|
|
54
65
|
email: zod_1.z.string(),
|
|
55
66
|
fullName: zod_1.z.string().nullable(),
|
|
56
67
|
phone: zod_1.z.string().nullable(),
|
|
57
68
|
role: zod_1.z.literal('COACH'),
|
|
58
69
|
status: zod_1.z.enum(index_js_1.ACCOUNT_STATUSES),
|
|
59
|
-
emailVerifiedAt:
|
|
60
|
-
lastLoginAt:
|
|
61
|
-
createdAt:
|
|
62
|
-
})
|
|
70
|
+
emailVerifiedAt: date_time_schema_js_1.utcTimestampSchema.nullable(),
|
|
71
|
+
lastLoginAt: date_time_schema_js_1.utcTimestampSchema.nullable(),
|
|
72
|
+
createdAt: date_time_schema_js_1.utcTimestampSchema,
|
|
73
|
+
})
|
|
74
|
+
.extend(auth_dto_js_1.timezonePreferenceSchema.shape);
|
|
63
75
|
exports.coachLoginResponseSchema = auth_dto_js_1.tokenResponseSchema.extend({
|
|
64
76
|
coach: exports.coachProfileSchema,
|
|
65
77
|
});
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.paginatedResponseSchema = exports.dataResponseSchema = exports.apiErrorResponseSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
+
const date_time_schema_js_1 = require("./date-time.schema.js");
|
|
5
6
|
const pagination_schema_js_1 = require("./pagination.schema.js");
|
|
6
7
|
exports.apiErrorResponseSchema = zod_1.z.object({
|
|
7
8
|
error: zod_1.z.object({
|
|
@@ -16,7 +17,7 @@ exports.apiErrorResponseSchema = zod_1.z.object({
|
|
|
16
17
|
}))
|
|
17
18
|
.optional(),
|
|
18
19
|
requestId: zod_1.z.string(),
|
|
19
|
-
timestamp:
|
|
20
|
+
timestamp: date_time_schema_js_1.utcTimestampSchema,
|
|
20
21
|
path: zod_1.z.string(),
|
|
21
22
|
}),
|
|
22
23
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The platform's date and time rules, shared so the backend and the apps
|
|
4
|
+
* validate them identically:
|
|
5
|
+
*
|
|
6
|
+
* - An instant (something that happened at one moment) travels as ISO 8601.
|
|
7
|
+
* Responses always use UTC with `Z`. Requests may use `Z` or an explicit
|
|
8
|
+
* offset, but never a bare local time, which would be ambiguous.
|
|
9
|
+
* - A date-only value (a birthday, an expiry date) travels as `YYYY-MM-DD` and
|
|
10
|
+
* is never converted between time zones.
|
|
11
|
+
* - A time zone is an IANA identifier such as `Asia/Kolkata`. Abbreviations
|
|
12
|
+
* (`IST`) and fixed offsets (`+05:30`) are refused, because offsets change
|
|
13
|
+
* with daylight saving.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_TIMEZONE = "UTC";
|
|
16
|
+
/**
|
|
17
|
+
* True for `UTC` and for an IANA `Area/Location` name the runtime's time zone
|
|
18
|
+
* database knows. Runs anywhere `Intl` does, so the browser and the server
|
|
19
|
+
* agree.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isValidTimezone(value: unknown): value is string;
|
|
22
|
+
/** The current IANA name for a zone, such as `Asia/Kolkata` for `Asia/Calcutta`. */
|
|
23
|
+
export declare function canonicalTimezone(value: string): string;
|
|
24
|
+
export declare const timezoneSchema: z.ZodPipe<z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>, z.ZodTransform<string, string>>;
|
|
25
|
+
/**
|
|
26
|
+
* A time zone the client detected and suggests, such as at sign-up. A missing
|
|
27
|
+
* or unusable value becomes `undefined` instead of failing the request, and the
|
|
28
|
+
* server then applies its default.
|
|
29
|
+
*/
|
|
30
|
+
export declare const detectedTimezoneSchema: z.ZodOptional<z.ZodPipe<z.ZodUnknown, z.ZodTransform<string | undefined, unknown>>>;
|
|
31
|
+
/** An instant in a response: ISO 8601 in UTC, ending in `Z`. */
|
|
32
|
+
export declare const utcTimestampSchema: z.ZodISODateTime;
|
|
33
|
+
/**
|
|
34
|
+
* An instant in a request: ISO 8601 with `Z` or an explicit offset, such as
|
|
35
|
+
* `2026-11-02T15:00:00+05:30`. A local time without either is refused.
|
|
36
|
+
*/
|
|
37
|
+
export declare const instantInputSchema: z.ZodISODateTime;
|
|
38
|
+
/** A calendar date with no time and no zone, such as `2026-11-02`. */
|
|
39
|
+
export declare const dateOnlySchema: z.ZodString;
|