@dalmore/api-contracts 0.0.0-dev.4c056b7 → 0.0.0-dev.4ec8ae0
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/common/types/account-setting.types.ts +31 -0
- package/common/types/activity.types.ts +1 -1
- package/common/types/bonus-tier.types.ts +24 -0
- package/common/types/cart.types.ts +4 -1
- package/common/types/common.types.ts +16 -6
- package/common/types/dashboard.types.ts +2 -9
- package/common/types/disbursements.types.ts +97 -3
- package/common/types/file.types.ts +17 -1
- package/common/types/i-will-do-it-later.types.ts +68 -0
- package/common/types/index.ts +1 -0
- package/common/types/individuals.types.ts +2 -15
- package/common/types/issuer-offering.types.ts +8 -9
- package/common/types/notification.types.ts +239 -29
- package/common/types/offering.types.ts +4 -9
- package/common/types/site.types.ts +2 -9
- package/common/types/{trade-line-item.type.ts → trade-line-item.types.ts} +2 -9
- package/common/types/trade.types.ts +1 -1
- package/common/types/transaction.types.ts +12 -1
- package/common/types/user.types.ts +15 -28
- package/contracts/clients/cart/index.ts +21 -1
- package/contracts/clients/index.ts +2 -0
- package/contracts/clients/trade-line-items/index.ts +1 -1
- package/contracts/clients/trades/index.ts +1 -1
- package/contracts/clients/transactions/index.ts +37 -0
- package/contracts/compliance/bonus-tiers/index.ts +19 -0
- package/contracts/compliance/trade-line-items/index.ts +1 -1
- package/contracts/compliance/users/index.ts +21 -0
- package/contracts/investors/bonus-tiers/index.ts +18 -0
- package/contracts/investors/individuals/index.ts +22 -0
- package/contracts/investors/trade-line-items/index.ts +1 -1
- package/contracts/issuers/bonus-tiers/index.ts +18 -0
- package/contracts/issuers/disbursements/index.ts +18 -0
- package/package.json +1 -1
|
@@ -1,58 +1,268 @@
|
|
|
1
1
|
import { extendZodWithOpenApi } from '@anatine/zod-openapi';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { TypeID } from 'typeid-js';
|
|
4
|
-
import {
|
|
4
|
+
import { IBaseEntity } from './entity.types';
|
|
5
5
|
|
|
6
6
|
extendZodWithOpenApi(z);
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
export enum NotificationChannelType {
|
|
8
9
|
EMAIL = 'EMAIL',
|
|
9
10
|
SLACK = 'SLACK',
|
|
11
|
+
WEBHOOK = 'WEBHOOK',
|
|
10
12
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
export enum NotificationRecordStatus {
|
|
15
|
+
PENDING = 'PENDING',
|
|
16
|
+
SENT = 'SENT',
|
|
17
|
+
FAILED = 'FAILED',
|
|
14
18
|
}
|
|
15
19
|
|
|
16
|
-
export const
|
|
20
|
+
export const notificationChannelIdSchema = z.string().refine(
|
|
17
21
|
(value) => {
|
|
18
22
|
try {
|
|
19
23
|
const tid = TypeID.fromString(value);
|
|
20
|
-
return tid.getType() === '
|
|
24
|
+
return tid.getType() === 'notification_channel';
|
|
21
25
|
} catch {
|
|
22
26
|
return false;
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
{
|
|
26
30
|
message:
|
|
27
|
-
'Invalid notification ID format. Must be a valid TypeID with "
|
|
31
|
+
'Invalid notification channel ID format. Must be a valid TypeID with "notification_channel" prefix.',
|
|
28
32
|
},
|
|
29
33
|
);
|
|
30
34
|
|
|
31
|
-
export const
|
|
32
|
-
|
|
35
|
+
export const notificationChannelTriggerIdSchema = z.string().refine(
|
|
36
|
+
(value) => {
|
|
37
|
+
try {
|
|
38
|
+
const tid = TypeID.fromString(value);
|
|
39
|
+
return tid.getType() === 'notification_channel_trigger';
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
message:
|
|
46
|
+
'Invalid notification channel trigger ID format. Must be a valid TypeID with "notification_channel_trigger" prefix.',
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
export const notificationRecordIdSchema = z.string().refine(
|
|
51
|
+
(value) => {
|
|
52
|
+
try {
|
|
53
|
+
const tid = TypeID.fromString(value);
|
|
54
|
+
return tid.getType() === 'notification_record';
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
message:
|
|
61
|
+
'Invalid notification record ID format. Must be a valid TypeID with "notification_record" prefix.',
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
export const EmailChannelSettingsSchema = z.object({
|
|
66
|
+
recipients: z.array(z.string().email()).min(1),
|
|
67
|
+
subjectTemplate: z.string().optional(),
|
|
68
|
+
});
|
|
69
|
+
export type EmailChannelSettings = z.infer<typeof EmailChannelSettingsSchema>;
|
|
70
|
+
|
|
71
|
+
export const SlackChannelSettingsSchema = z
|
|
72
|
+
.object({
|
|
73
|
+
webhookUrl: z.string().url().optional(),
|
|
74
|
+
channelEmail: z.string().email().optional(),
|
|
75
|
+
})
|
|
76
|
+
.refine((data) => data.webhookUrl || data.channelEmail, {
|
|
77
|
+
message: 'Either webhookUrl or channelEmail is required',
|
|
78
|
+
});
|
|
79
|
+
export type SlackChannelSettings = z.infer<typeof SlackChannelSettingsSchema>;
|
|
80
|
+
|
|
81
|
+
export const WebhookChannelSettingsSchema = z.object({
|
|
82
|
+
url: z.string().url(),
|
|
83
|
+
method: z.enum(['POST', 'PUT']),
|
|
84
|
+
headers: z.record(z.string()).optional(),
|
|
85
|
+
authType: z.enum(['none', 'bearer', 'basic', 'api_key']).default('none'),
|
|
86
|
+
authValue: z.string().optional(),
|
|
87
|
+
});
|
|
88
|
+
export type WebhookChannelSettings = z.infer<
|
|
89
|
+
typeof WebhookChannelSettingsSchema
|
|
90
|
+
>;
|
|
91
|
+
|
|
92
|
+
export const NotificationChannelSettingsSchema = z.discriminatedUnion('type', [
|
|
93
|
+
z.object({
|
|
94
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
95
|
+
config: EmailChannelSettingsSchema,
|
|
96
|
+
}),
|
|
97
|
+
z.object({
|
|
98
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
99
|
+
config: SlackChannelSettingsSchema,
|
|
100
|
+
}),
|
|
101
|
+
z.object({
|
|
102
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
103
|
+
config: WebhookChannelSettingsSchema,
|
|
104
|
+
}),
|
|
105
|
+
]);
|
|
106
|
+
export type NotificationChannelSettings = z.infer<
|
|
107
|
+
typeof NotificationChannelSettingsSchema
|
|
108
|
+
>;
|
|
109
|
+
|
|
110
|
+
export const EmailNotificationPayloadSchema = z.object({
|
|
111
|
+
to: z.array(z.string().email()),
|
|
33
112
|
subject: z.string(),
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
debug: z.boolean().default(false),
|
|
37
|
-
notificationChannel: z.nativeEnum(NotificationChannel),
|
|
38
|
-
channelName: z.string(),
|
|
39
|
-
channelEmail: z.string().email(),
|
|
40
|
-
notificationType: z.nativeEnum(NotificationType),
|
|
113
|
+
body: z.string(),
|
|
114
|
+
html: z.string().optional(),
|
|
41
115
|
});
|
|
42
|
-
export type
|
|
116
|
+
export type EmailNotificationPayload = z.infer<
|
|
117
|
+
typeof EmailNotificationPayloadSchema
|
|
118
|
+
>;
|
|
43
119
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
channelEmail: z.string().email(),
|
|
120
|
+
export const SlackNotificationPayloadSchema = z.object({
|
|
121
|
+
webhookUrl: z.string().url().optional(),
|
|
122
|
+
channelEmail: z.string().email().optional(),
|
|
123
|
+
message: z.string(),
|
|
124
|
+
blocks: z.array(z.record(z.unknown())).optional(),
|
|
47
125
|
});
|
|
126
|
+
export type SlackNotificationPayload = z.infer<
|
|
127
|
+
typeof SlackNotificationPayloadSchema
|
|
128
|
+
>;
|
|
48
129
|
|
|
49
|
-
export const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
debug: z.boolean().default(false),
|
|
55
|
-
settings: SlackSettingsSchema,
|
|
130
|
+
export const WebhookNotificationPayloadSchema = z.object({
|
|
131
|
+
url: z.string().url(),
|
|
132
|
+
method: z.enum(['POST', 'PUT']),
|
|
133
|
+
headers: z.record(z.string()),
|
|
134
|
+
body: z.record(z.unknown()),
|
|
56
135
|
});
|
|
136
|
+
export type WebhookNotificationPayload = z.infer<
|
|
137
|
+
typeof WebhookNotificationPayloadSchema
|
|
138
|
+
>;
|
|
139
|
+
|
|
140
|
+
export const NotificationPayloadSchema = z.discriminatedUnion('type', [
|
|
141
|
+
z.object({
|
|
142
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
143
|
+
data: EmailNotificationPayloadSchema,
|
|
144
|
+
}),
|
|
145
|
+
z.object({
|
|
146
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
147
|
+
data: SlackNotificationPayloadSchema,
|
|
148
|
+
}),
|
|
149
|
+
z.object({
|
|
150
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
151
|
+
data: WebhookNotificationPayloadSchema,
|
|
152
|
+
}),
|
|
153
|
+
]);
|
|
154
|
+
export type NotificationPayload = z.infer<typeof NotificationPayloadSchema>;
|
|
57
155
|
|
|
58
|
-
export
|
|
156
|
+
export const EmailNotificationResponseSchema = z.object({
|
|
157
|
+
messageId: z.string().optional(),
|
|
158
|
+
accepted: z.array(z.string()).optional(),
|
|
159
|
+
rejected: z.array(z.string()).optional(),
|
|
160
|
+
});
|
|
161
|
+
export type EmailNotificationResponse = z.infer<
|
|
162
|
+
typeof EmailNotificationResponseSchema
|
|
163
|
+
>;
|
|
164
|
+
|
|
165
|
+
export const SlackNotificationResponseSchema = z.object({
|
|
166
|
+
ok: z.boolean().optional(),
|
|
167
|
+
error: z.string().optional(),
|
|
168
|
+
responseBody: z.string().optional(),
|
|
169
|
+
});
|
|
170
|
+
export type SlackNotificationResponse = z.infer<
|
|
171
|
+
typeof SlackNotificationResponseSchema
|
|
172
|
+
>;
|
|
173
|
+
|
|
174
|
+
export const WebhookNotificationResponseSchema = z.object({
|
|
175
|
+
statusCode: z.number(),
|
|
176
|
+
headers: z.record(z.string()).optional(),
|
|
177
|
+
body: z.unknown().optional(),
|
|
178
|
+
});
|
|
179
|
+
export type WebhookNotificationResponse = z.infer<
|
|
180
|
+
typeof WebhookNotificationResponseSchema
|
|
181
|
+
>;
|
|
182
|
+
|
|
183
|
+
export const NotificationResponseSchema = z.discriminatedUnion('type', [
|
|
184
|
+
z.object({
|
|
185
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
186
|
+
data: EmailNotificationResponseSchema,
|
|
187
|
+
}),
|
|
188
|
+
z.object({
|
|
189
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
190
|
+
data: SlackNotificationResponseSchema,
|
|
191
|
+
}),
|
|
192
|
+
z.object({
|
|
193
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
194
|
+
data: WebhookNotificationResponseSchema,
|
|
195
|
+
}),
|
|
196
|
+
]);
|
|
197
|
+
export type NotificationResponse = z.infer<typeof NotificationResponseSchema>;
|
|
198
|
+
|
|
199
|
+
export const INotificationChannelZod = IBaseEntity.extend({
|
|
200
|
+
id: notificationChannelIdSchema.openapi({
|
|
201
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
202
|
+
}),
|
|
203
|
+
accountSettingsId: z.string().openapi({
|
|
204
|
+
example: 'account_setting_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
205
|
+
}),
|
|
206
|
+
channelType: z.nativeEnum(NotificationChannelType).openapi({
|
|
207
|
+
example: NotificationChannelType.SLACK,
|
|
208
|
+
}),
|
|
209
|
+
name: z.string().openapi({
|
|
210
|
+
example: 'Compliance Alerts',
|
|
211
|
+
}),
|
|
212
|
+
enabled: z.boolean().openapi({
|
|
213
|
+
example: true,
|
|
214
|
+
}),
|
|
215
|
+
settings: NotificationChannelSettingsSchema,
|
|
216
|
+
});
|
|
217
|
+
export type INotificationChannelZod = z.infer<typeof INotificationChannelZod>;
|
|
218
|
+
|
|
219
|
+
export const INotificationChannelTriggerZod = IBaseEntity.extend({
|
|
220
|
+
id: notificationChannelTriggerIdSchema.openapi({
|
|
221
|
+
example: 'notification_channel_trigger_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
222
|
+
}),
|
|
223
|
+
notificationChannelId: notificationChannelIdSchema.openapi({
|
|
224
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
225
|
+
}),
|
|
226
|
+
activityTypeId: z.string().openapi({
|
|
227
|
+
example: 'activity_type_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
228
|
+
}),
|
|
229
|
+
enabled: z.boolean().openapi({
|
|
230
|
+
example: true,
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
233
|
+
export type INotificationChannelTriggerZod = z.infer<
|
|
234
|
+
typeof INotificationChannelTriggerZod
|
|
235
|
+
>;
|
|
236
|
+
|
|
237
|
+
export const INotificationRecordZod = IBaseEntity.extend({
|
|
238
|
+
id: notificationRecordIdSchema.openapi({
|
|
239
|
+
example: 'notification_record_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
240
|
+
}),
|
|
241
|
+
notificationChannelId: notificationChannelIdSchema.openapi({
|
|
242
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
243
|
+
}),
|
|
244
|
+
activityId: z.string().nullable().openapi({
|
|
245
|
+
example: 'activity_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
246
|
+
}),
|
|
247
|
+
targetTable: z.string().openapi({
|
|
248
|
+
example: 'trades',
|
|
249
|
+
}),
|
|
250
|
+
targetId: z.string().openapi({
|
|
251
|
+
example: 'trade_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
252
|
+
}),
|
|
253
|
+
status: z.nativeEnum(NotificationRecordStatus).openapi({
|
|
254
|
+
example: NotificationRecordStatus.SENT,
|
|
255
|
+
}),
|
|
256
|
+
payload: NotificationPayloadSchema,
|
|
257
|
+
response: NotificationResponseSchema.nullable(),
|
|
258
|
+
errorMessage: z.string().nullable().openapi({
|
|
259
|
+
example: null,
|
|
260
|
+
}),
|
|
261
|
+
retryCount: z.number().openapi({
|
|
262
|
+
example: 0,
|
|
263
|
+
}),
|
|
264
|
+
sentAt: z.date().nullable().openapi({
|
|
265
|
+
example: new Date(),
|
|
266
|
+
}),
|
|
267
|
+
});
|
|
268
|
+
export type INotificationRecordZod = z.infer<typeof INotificationRecordZod>;
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
OfferingOnboardingStatus,
|
|
18
18
|
AssetType,
|
|
19
19
|
DurationType,
|
|
20
|
+
StringToBooleanSchema,
|
|
20
21
|
} from './common.types';
|
|
21
22
|
import { IBaseEntity } from './entity.types';
|
|
22
23
|
import { fileIdSchema, FileZod } from './file.types';
|
|
@@ -230,6 +231,7 @@ export const PatchOffering = PatchOfferingBase.merge(
|
|
|
230
231
|
.nullable()
|
|
231
232
|
.optional(),
|
|
232
233
|
tiers: z.array(z.number().positive()).nullable().optional(),
|
|
234
|
+
enableBonus: z.boolean().optional(),
|
|
233
235
|
}),
|
|
234
236
|
);
|
|
235
237
|
export type PatchOffering = z.infer<typeof PatchOffering>;
|
|
@@ -276,6 +278,7 @@ export const PostComplianceOffering = PatchOfferingBase.merge(
|
|
|
276
278
|
.default(AssetTemplateType.STANDARD)
|
|
277
279
|
.openapi({ example: AssetTemplateType.STANDARD }),
|
|
278
280
|
tiers: z.array(z.number().positive()).nullable().optional(),
|
|
281
|
+
enableBonus: z.boolean().default(false).optional(),
|
|
279
282
|
}),
|
|
280
283
|
).superRefine(postAssetRefinement);
|
|
281
284
|
export type PostComplianceOffering = z.infer<typeof PostComplianceOffering>;
|
|
@@ -344,15 +347,7 @@ export const OfferingFiltersZod = z.object({
|
|
|
344
347
|
issuerId: z.lazy(() => issuerIdSchema).optional(),
|
|
345
348
|
type: z.nativeEnum(OfferingType).optional(),
|
|
346
349
|
status: z.nativeEnum(ComplianceReview).optional(),
|
|
347
|
-
enabled:
|
|
348
|
-
(val) =>
|
|
349
|
-
val === 'true' || val === '1'
|
|
350
|
-
? true
|
|
351
|
-
: val === 'false' || val === '0'
|
|
352
|
-
? false
|
|
353
|
-
: val,
|
|
354
|
-
z.boolean().optional(),
|
|
355
|
-
),
|
|
350
|
+
enabled: StringToBooleanSchema.optional(),
|
|
356
351
|
managedBy: z.nativeEnum(ManagedByType).optional(),
|
|
357
352
|
versioningType: z.nativeEnum(OfferingVersioningType).optional(),
|
|
358
353
|
combinedStatus: z.nativeEnum(OfferingStatus).optional(),
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
AccountStatus,
|
|
6
6
|
AccountZod,
|
|
7
7
|
IPaginationMeta,
|
|
8
|
+
StringToBooleanSchema,
|
|
8
9
|
UrlSchema,
|
|
9
10
|
} from './common.types';
|
|
10
11
|
import { accountIdSchema } from './account.types';
|
|
@@ -73,15 +74,7 @@ export const SitesParamSchema = z.object({
|
|
|
73
74
|
export const SitesFiltersZod = z.object({
|
|
74
75
|
url: z.string().optional(),
|
|
75
76
|
accountId: accountIdSchema.optional(),
|
|
76
|
-
enabled:
|
|
77
|
-
(val) =>
|
|
78
|
-
val === 'true' || val === '1'
|
|
79
|
-
? true
|
|
80
|
-
: val === 'false' || val === '0'
|
|
81
|
-
? false
|
|
82
|
-
: val,
|
|
83
|
-
z.boolean().optional(),
|
|
84
|
-
),
|
|
77
|
+
enabled: StringToBooleanSchema.optional(),
|
|
85
78
|
});
|
|
86
79
|
|
|
87
80
|
const sitesInclude = z.enum(['account']);
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
IPaginationMeta,
|
|
9
9
|
OfferingType,
|
|
10
10
|
SignatureStatus,
|
|
11
|
+
StringToBooleanSchema,
|
|
11
12
|
} from './common.types';
|
|
12
13
|
import { fileIdSchema } from './file.types';
|
|
13
14
|
import { accountIdSchema } from './account.types';
|
|
@@ -107,15 +108,7 @@ export type TradeLineItemQuery = z.infer<typeof TradeLineItemQuery>;
|
|
|
107
108
|
|
|
108
109
|
export const TradeLineItemFiltersQuery = z.object({
|
|
109
110
|
accountId: accountIdSchema.optional(),
|
|
110
|
-
hasSubdoc:
|
|
111
|
-
(val) =>
|
|
112
|
-
val === 'true' || val === '1'
|
|
113
|
-
? true
|
|
114
|
-
: val === 'false' || val === '0'
|
|
115
|
-
? false
|
|
116
|
-
: val,
|
|
117
|
-
z.boolean().optional(),
|
|
118
|
-
),
|
|
111
|
+
hasSubdoc: StringToBooleanSchema.optional(),
|
|
119
112
|
saStatus: z.nativeEnum(SignatureStatus).optional(),
|
|
120
113
|
offeringId: z.lazy(() => offeringIdSchema).optional(),
|
|
121
114
|
search: z.string().max(50).optional(),
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
import {
|
|
40
40
|
tradeLineItemIdSchema,
|
|
41
41
|
TradeLineItemZod,
|
|
42
|
-
} from './trade-line-item.
|
|
42
|
+
} from './trade-line-item.types';
|
|
43
43
|
import { TradeAdjustmentZod } from './trade-adjustment.type';
|
|
44
44
|
import { TransactionZod } from './transaction.types';
|
|
45
45
|
import { accountIdSchema } from './account.types';
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { extendZodWithOpenApi } from '@anatine/zod-openapi';
|
|
1
3
|
import { TypeID } from 'typeid-js';
|
|
2
4
|
import {
|
|
3
5
|
dateSchema,
|
|
4
6
|
InvestorAccountType,
|
|
5
7
|
numberPrecisionSchema,
|
|
6
8
|
} from './common.types';
|
|
7
|
-
import { z } from 'zod';
|
|
8
9
|
import { IBaseEntity } from './entity.types';
|
|
9
10
|
import { accountIdSchema } from './account.types';
|
|
10
11
|
import {
|
|
@@ -18,7 +19,9 @@ import {
|
|
|
18
19
|
investorAccountIdSchema,
|
|
19
20
|
} from './investor-account.types';
|
|
20
21
|
import { TransactionStatus, TransactionType } from './common.types';
|
|
22
|
+
import { userIdSchema } from './user.types';
|
|
21
23
|
export { TransactionStatus, TransactionType };
|
|
24
|
+
extendZodWithOpenApi(z);
|
|
22
25
|
|
|
23
26
|
export enum RefundPaymentMethod {
|
|
24
27
|
CHECK = 'CHECK',
|
|
@@ -115,6 +118,14 @@ export type InvestorPostTransactionZod = z.infer<
|
|
|
115
118
|
typeof InvestorPostTransactionZod
|
|
116
119
|
>;
|
|
117
120
|
|
|
121
|
+
export const ClientPostTransactionZod = InvestorPostTransactionZod.extend({
|
|
122
|
+
userId: z
|
|
123
|
+
.lazy(() => userIdSchema)
|
|
124
|
+
.openapi({ example: 'user_01j5y5ghx5fg68d663j1fvy2x7' }),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export type ClientPostTransactionZod = z.infer<typeof ClientPostTransactionZod>;
|
|
128
|
+
|
|
118
129
|
export const refundTransactionIdSchema = z.string().refine(
|
|
119
130
|
(value) => {
|
|
120
131
|
try {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { extendZodWithOpenApi } from '@anatine/zod-openapi';
|
|
2
3
|
import {
|
|
3
4
|
AccountStatus,
|
|
4
5
|
AccountWithoutUsersZod,
|
|
@@ -7,12 +8,11 @@ import {
|
|
|
7
8
|
ManagedByType,
|
|
8
9
|
OfferingType,
|
|
9
10
|
PortalType,
|
|
11
|
+
StringToBooleanSchema,
|
|
10
12
|
UserRole,
|
|
11
|
-
UserStatus,
|
|
12
13
|
UserType,
|
|
13
14
|
} from './common.types';
|
|
14
15
|
import { dateOrString, IBaseEntity } from './entity.types';
|
|
15
|
-
import { extendZodWithOpenApi } from '@anatine/zod-openapi';
|
|
16
16
|
import { PhoneZodSchema } from './phone.type';
|
|
17
17
|
import { IInvestorAccount } from './investor-account.types';
|
|
18
18
|
import { TradeZod } from './trade.types';
|
|
@@ -51,6 +51,11 @@ export const UserDeleteResponse = z.object({
|
|
|
51
51
|
});
|
|
52
52
|
export type UserDeleteResponse = z.infer<typeof UserDeleteResponse>;
|
|
53
53
|
|
|
54
|
+
export const UserRestoreResponse = z.object({
|
|
55
|
+
message: z.string(),
|
|
56
|
+
});
|
|
57
|
+
export type UserRestoreResponse = z.infer<typeof UserRestoreResponse>;
|
|
58
|
+
|
|
54
59
|
export const GetMeResponse = IBaseEntity.extend({
|
|
55
60
|
accountId: z.string().nullable(),
|
|
56
61
|
accountName: z.string().nullable(),
|
|
@@ -59,7 +64,7 @@ export const GetMeResponse = IBaseEntity.extend({
|
|
|
59
64
|
email: z.string().email(),
|
|
60
65
|
provider: z.string(),
|
|
61
66
|
active: z.boolean(),
|
|
62
|
-
|
|
67
|
+
locked: z.boolean(),
|
|
63
68
|
lastLoginAt: dateOrString.nullable(),
|
|
64
69
|
loginCount: z.number(),
|
|
65
70
|
role: z.string(),
|
|
@@ -157,7 +162,7 @@ export const UserZod = IBaseEntity.extend({
|
|
|
157
162
|
onboarding: z.string().nullable(),
|
|
158
163
|
account: AccountWithoutUsersZod.optional(),
|
|
159
164
|
active: z.boolean(),
|
|
160
|
-
|
|
165
|
+
locked: z.boolean(),
|
|
161
166
|
userLogin: IBaseEntity.extend({
|
|
162
167
|
firstName: z.string(),
|
|
163
168
|
lastName: z.string(),
|
|
@@ -179,27 +184,9 @@ export const UserFiltersZod = z.object({
|
|
|
179
184
|
search: z.string().max(50).optional(),
|
|
180
185
|
role: z.nativeEnum(UserRole).optional(),
|
|
181
186
|
portal: z.string().optional(),
|
|
182
|
-
|
|
183
|
-
active:
|
|
184
|
-
|
|
185
|
-
.optional()
|
|
186
|
-
.refine((v) => !v || v === 'true' || v === 'false', {
|
|
187
|
-
message: 'active must be a boolean string',
|
|
188
|
-
})
|
|
189
|
-
.transform((v) => {
|
|
190
|
-
if (!v) return undefined;
|
|
191
|
-
return v === 'true';
|
|
192
|
-
}),
|
|
193
|
-
twoFactorEnabled: z
|
|
194
|
-
.string()
|
|
195
|
-
.optional()
|
|
196
|
-
.refine((v) => !v || v === 'true' || v === 'false', {
|
|
197
|
-
message: 'twoFactorEnabled must be a boolean string',
|
|
198
|
-
})
|
|
199
|
-
.transform((v) => {
|
|
200
|
-
if (!v) return undefined;
|
|
201
|
-
return v === 'true';
|
|
202
|
-
}),
|
|
187
|
+
locked: StringToBooleanSchema.optional(),
|
|
188
|
+
active: StringToBooleanSchema.optional(),
|
|
189
|
+
twoFactorEnabled: StringToBooleanSchema.optional(),
|
|
203
190
|
});
|
|
204
191
|
|
|
205
192
|
const usersInclude = z.enum(['account', 'role']);
|
|
@@ -274,7 +261,7 @@ export type IssuerUsersStatusUpdateResponse = z.infer<
|
|
|
274
261
|
>;
|
|
275
262
|
|
|
276
263
|
export const UpdateLockedStatus = z.object({
|
|
277
|
-
|
|
264
|
+
locked: z.boolean(),
|
|
278
265
|
});
|
|
279
266
|
|
|
280
267
|
export type UpdateLockedStatus = z.infer<typeof UpdateLockedStatus>;
|
|
@@ -285,7 +272,7 @@ export const UsersSummaryFilterZod = z.object({
|
|
|
285
272
|
portalType: z.nativeEnum(PortalType).optional(),
|
|
286
273
|
search: z.string().trim().max(50).optional(),
|
|
287
274
|
selectRole: z.nativeEnum(UserRole).optional(),
|
|
288
|
-
|
|
275
|
+
locked: StringToBooleanSchema.optional(),
|
|
289
276
|
});
|
|
290
277
|
export type UsersSummaryFilterZod = z.infer<typeof UsersSummaryFilterZod>;
|
|
291
278
|
|
|
@@ -299,7 +286,7 @@ export const UsersSummaryZod = z.object({
|
|
|
299
286
|
portalType: z.string(),
|
|
300
287
|
loginCount: z.number().int(),
|
|
301
288
|
lastLogin: z.date(),
|
|
302
|
-
|
|
289
|
+
locked: z.boolean(),
|
|
303
290
|
});
|
|
304
291
|
export type UsersSummaryZod = z.infer<typeof UsersSummaryZod>;
|
|
305
292
|
|
|
@@ -10,7 +10,11 @@ import {
|
|
|
10
10
|
userIdSchema,
|
|
11
11
|
tradeIdSchema,
|
|
12
12
|
} from '../../../common/types';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
PatchCartBody,
|
|
15
|
+
ClientPlacetradeBody,
|
|
16
|
+
PlaceTradeResponse,
|
|
17
|
+
} from '../../../common/types/cart.types';
|
|
14
18
|
|
|
15
19
|
const c = initContract();
|
|
16
20
|
|
|
@@ -34,6 +38,22 @@ export const cartContract = c.router(
|
|
|
34
38
|
500: InternalError,
|
|
35
39
|
},
|
|
36
40
|
},
|
|
41
|
+
postCheckout: {
|
|
42
|
+
summary: 'Place a trade (checkout button)',
|
|
43
|
+
method: 'POST',
|
|
44
|
+
path: '/checkout',
|
|
45
|
+
metadata: {
|
|
46
|
+
auth: true,
|
|
47
|
+
},
|
|
48
|
+
body: ClientPlacetradeBody,
|
|
49
|
+
responses: {
|
|
50
|
+
200: PlaceTradeResponse,
|
|
51
|
+
400: BadRequestError,
|
|
52
|
+
401: UnauthorizedError,
|
|
53
|
+
403: ForbiddenError,
|
|
54
|
+
500: InternalError,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
37
57
|
patchCart: {
|
|
38
58
|
summary: 'Patch a cart',
|
|
39
59
|
method: 'PATCH',
|
|
@@ -19,6 +19,7 @@ import { sitesContract } from './sites';
|
|
|
19
19
|
import { paymentMethodsContract } from './payment-methods';
|
|
20
20
|
import { issuerPaymentMethodsContract } from './issuer-payment-methods';
|
|
21
21
|
import { tradeLineItemsContract } from './trade-line-items';
|
|
22
|
+
import { clientsTransactionsContract } from './transactions';
|
|
22
23
|
|
|
23
24
|
const c = initContract();
|
|
24
25
|
|
|
@@ -45,6 +46,7 @@ export const clientsContract = c.router(
|
|
|
45
46
|
sites: sitesContract,
|
|
46
47
|
tradeLineItems: tradeLineItemsContract,
|
|
47
48
|
trades: tradesContract,
|
|
49
|
+
transactions: clientsTransactionsContract,
|
|
48
50
|
},
|
|
49
51
|
{
|
|
50
52
|
pathPrefix: '/clients/api/v1/',
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { initContract } from '@ts-rest/core';
|
|
2
|
+
import {
|
|
3
|
+
BadRequestError,
|
|
4
|
+
InternalError,
|
|
5
|
+
NotFoundError,
|
|
6
|
+
UnauthorizedError,
|
|
7
|
+
} from '../../../common/types';
|
|
8
|
+
import {
|
|
9
|
+
ClientPostTransactionZod,
|
|
10
|
+
TransactionZod,
|
|
11
|
+
} from '../../../common/types/transaction.types';
|
|
12
|
+
|
|
13
|
+
const c = initContract();
|
|
14
|
+
|
|
15
|
+
export const clientsTransactionsContract = c.router(
|
|
16
|
+
{
|
|
17
|
+
postTransaction: {
|
|
18
|
+
summary: 'Create a transaction',
|
|
19
|
+
method: 'POST',
|
|
20
|
+
path: '',
|
|
21
|
+
metadata: {
|
|
22
|
+
auth: true,
|
|
23
|
+
},
|
|
24
|
+
body: ClientPostTransactionZod,
|
|
25
|
+
responses: {
|
|
26
|
+
201: TransactionZod,
|
|
27
|
+
400: BadRequestError,
|
|
28
|
+
401: UnauthorizedError,
|
|
29
|
+
404: NotFoundError,
|
|
30
|
+
500: InternalError,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
pathPrefix: 'transactions',
|
|
36
|
+
},
|
|
37
|
+
);
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
EstimateBonusTierCalculationResponseZod,
|
|
11
11
|
EstimateBonusTierCalculationZod,
|
|
12
12
|
IBonusTierList,
|
|
13
|
+
PurchaseCalculationResponseZod,
|
|
14
|
+
PurchaseCalculationZod,
|
|
13
15
|
} from '../../../common/types/bonus-tier.types';
|
|
14
16
|
|
|
15
17
|
const c = initContract();
|
|
@@ -32,6 +34,23 @@ export const bonusTiersContract = c.router(
|
|
|
32
34
|
500: InternalError,
|
|
33
35
|
},
|
|
34
36
|
},
|
|
37
|
+
purchaseCalculation: {
|
|
38
|
+
summary:
|
|
39
|
+
'[ADMIN] Calculate the bonus shares that would be awarded for a trade',
|
|
40
|
+
method: 'POST',
|
|
41
|
+
path: '/purchase-calculation',
|
|
42
|
+
metadata: {
|
|
43
|
+
auth: true,
|
|
44
|
+
},
|
|
45
|
+
body: PurchaseCalculationZod,
|
|
46
|
+
responses: {
|
|
47
|
+
200: PurchaseCalculationResponseZod,
|
|
48
|
+
400: BadRequestError,
|
|
49
|
+
401: UnauthorizedError,
|
|
50
|
+
403: ForbiddenError,
|
|
51
|
+
500: InternalError,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
35
54
|
postBonusTier: {
|
|
36
55
|
summary: 'Create a new bonus tier',
|
|
37
56
|
method: 'POST',
|