@dalmore/api-contracts 0.0.0-dev.4eac826 → 0.0.0-dev.56068a6

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 (201) hide show
  1. package/README.md +23 -19
  2. package/common/types/account-contact.types.ts +2 -1
  3. package/common/types/account-manager.types.ts +3 -7
  4. package/common/types/account-setting.types.ts +65 -0
  5. package/common/types/account.types.ts +1 -0
  6. package/common/types/auth.types.ts +7 -18
  7. package/common/types/bonus-tier.types.ts +33 -0
  8. package/common/types/cart.types.ts +4 -1
  9. package/common/types/common.types.ts +38 -6
  10. package/common/types/comply-advantage-api.types.ts +3 -3
  11. package/common/types/contact-us.types.ts +6 -2
  12. package/common/types/covered-person.types.ts +2 -1
  13. package/common/types/dashboard.types.ts +2 -9
  14. package/common/types/disbursements.types.ts +97 -3
  15. package/common/types/escrow-account.types.ts +3 -3
  16. package/common/types/individuals.types.ts +5 -17
  17. package/common/types/investor-account.types.ts +2 -1
  18. package/common/types/invite.types.ts +27 -1
  19. package/common/types/issuer-offering.types.ts +13 -17
  20. package/common/types/legal-entity.types.ts +3 -2
  21. package/common/types/mail-template.types.ts +34 -0
  22. package/common/types/note.types.ts +1 -1
  23. package/common/types/notification.types.ts +525 -29
  24. package/common/types/offering.types.ts +4 -9
  25. package/common/types/site-settings.types.ts +2 -1
  26. package/common/types/site.types.ts +2 -9
  27. package/common/types/{trade-line-item.type.ts → trade-line-item.types.ts} +2 -9
  28. package/common/types/trade.types.ts +48 -2
  29. package/common/types/transaction.types.ts +12 -1
  30. package/common/types/trusted-contact.types.ts +7 -7
  31. package/common/types/user.types.ts +17 -33
  32. package/common/types/webhook.types.ts +142 -0
  33. package/contracts/clients/cart/index.ts +21 -1
  34. package/contracts/clients/index.ts +2 -0
  35. package/contracts/clients/trade-line-items/index.ts +1 -1
  36. package/contracts/clients/trades/index.ts +1 -1
  37. package/contracts/{investors → clients}/transactions/index.ts +3 -3
  38. package/index.ts +10 -0
  39. package/package.json +23 -32
  40. package/contracts/compliance/account-contacts/index.ts +0 -82
  41. package/contracts/compliance/account-managers/index.ts +0 -142
  42. package/contracts/compliance/accounts/index.ts +0 -187
  43. package/contracts/compliance/activities/index.ts +0 -55
  44. package/contracts/compliance/aic/index.ts +0 -60
  45. package/contracts/compliance/api-keys/index.ts +0 -91
  46. package/contracts/compliance/assets/index.ts +0 -122
  47. package/contracts/compliance/auth/index.ts +0 -134
  48. package/contracts/compliance/batch-jobs/index.ts +0 -62
  49. package/contracts/compliance/bonus-tiers/index.ts +0 -55
  50. package/contracts/compliance/checklist/index.ts +0 -87
  51. package/contracts/compliance/checklist-items/index.ts +0 -86
  52. package/contracts/compliance/covered-persons/index.ts +0 -97
  53. package/contracts/compliance/dashboard/index.ts +0 -111
  54. package/contracts/compliance/data-records/index.ts +0 -116
  55. package/contracts/compliance/data-rooms/index.ts +0 -113
  56. package/contracts/compliance/default-theme-configs/index.ts +0 -95
  57. package/contracts/compliance/disbursement/index.ts +0 -165
  58. package/contracts/compliance/disbursement-approval-users/index.ts +0 -84
  59. package/contracts/compliance/disbursement-transactions/index.ts +0 -37
  60. package/contracts/compliance/domain-filters/index.ts +0 -117
  61. package/contracts/compliance/email-themes/index.ts +0 -284
  62. package/contracts/compliance/escrow-accounts/index.ts +0 -85
  63. package/contracts/compliance/exchange-api-keys/index.ts +0 -129
  64. package/contracts/compliance/exchange-imports/index.ts +0 -137
  65. package/contracts/compliance/files/index.ts +0 -267
  66. package/contracts/compliance/files-public/index.ts +0 -188
  67. package/contracts/compliance/health/index.ts +0 -26
  68. package/contracts/compliance/index.ts +0 -147
  69. package/contracts/compliance/individuals/index.ts +0 -57
  70. package/contracts/compliance/investor-accounts/index.ts +0 -141
  71. package/contracts/compliance/invites/index.ts +0 -137
  72. package/contracts/compliance/issuer-bank-accounts/index.ts +0 -81
  73. package/contracts/compliance/issuer-payment-methods/index.ts +0 -81
  74. package/contracts/compliance/issuers/index.ts +0 -97
  75. package/contracts/compliance/job-items/index.ts +0 -58
  76. package/contracts/compliance/jobs/index.ts +0 -59
  77. package/contracts/compliance/kyb/index.ts +0 -54
  78. package/contracts/compliance/kyc/index.ts +0 -77
  79. package/contracts/compliance/legal-entities/index.ts +0 -57
  80. package/contracts/compliance/login-histories/index.ts +0 -37
  81. package/contracts/compliance/notes/index.ts +0 -69
  82. package/contracts/compliance/notion-databases/index.ts +0 -107
  83. package/contracts/compliance/notion-pages/index.ts +0 -105
  84. package/contracts/compliance/offering-reports/index.ts +0 -149
  85. package/contracts/compliance/offerings/index.ts +0 -233
  86. package/contracts/compliance/pages/index.ts +0 -178
  87. package/contracts/compliance/payment-methods/index.ts +0 -57
  88. package/contracts/compliance/rejection-reasons/index.ts +0 -32
  89. package/contracts/compliance/review/index.ts +0 -169
  90. package/contracts/compliance/roles/index.ts +0 -34
  91. package/contracts/compliance/secondary-customers/index.ts +0 -77
  92. package/contracts/compliance/secondary-orders/index.ts +0 -60
  93. package/contracts/compliance/secondary-trades/index.ts +0 -100
  94. package/contracts/compliance/secure-requests/index.ts +0 -54
  95. package/contracts/compliance/signer/index.ts +0 -369
  96. package/contracts/compliance/site-links/index.ts +0 -128
  97. package/contracts/compliance/site-settings/index.ts +0 -669
  98. package/contracts/compliance/sites/index.ts +0 -56
  99. package/contracts/compliance/state-machine/index.ts +0 -94
  100. package/contracts/compliance/tasks/index.ts +0 -91
  101. package/contracts/compliance/third-parties/index.ts +0 -52
  102. package/contracts/compliance/trade-line-items/index.ts +0 -59
  103. package/contracts/compliance/trades/index.ts +0 -230
  104. package/contracts/compliance/transactions/index.ts +0 -161
  105. package/contracts/compliance/user-manuals/index.ts +0 -271
  106. package/contracts/compliance/user-settings/index.ts +0 -189
  107. package/contracts/compliance/users/index.ts +0 -200
  108. package/contracts/compliance/webhooks/index.ts +0 -41
  109. package/contracts/compliance-apikey/accounts/index.ts +0 -58
  110. package/contracts/compliance-apikey/index.ts +0 -14
  111. package/contracts/index.ts +0 -6
  112. package/contracts/investors/account-contacts/index.ts +0 -58
  113. package/contracts/investors/aic/index.ts +0 -59
  114. package/contracts/investors/assets/index.ts +0 -61
  115. package/contracts/investors/auth/index.ts +0 -116
  116. package/contracts/investors/bonus-tiers/index.ts +0 -37
  117. package/contracts/investors/cart/index.ts +0 -75
  118. package/contracts/investors/contact-us/index.ts +0 -48
  119. package/contracts/investors/data-records/index.ts +0 -113
  120. package/contracts/investors/data-rooms/index.ts +0 -96
  121. package/contracts/investors/files/index.ts +0 -167
  122. package/contracts/investors/files-public/index.ts +0 -185
  123. package/contracts/investors/index.ts +0 -72
  124. package/contracts/investors/individuals/index.ts +0 -121
  125. package/contracts/investors/investor-accounts/index.ts +0 -110
  126. package/contracts/investors/issuer-payment-methods/index.ts +0 -36
  127. package/contracts/investors/issuers/index.ts +0 -30
  128. package/contracts/investors/legal-entities/index.ts +0 -93
  129. package/contracts/investors/notes/index.ts +0 -69
  130. package/contracts/investors/offerings/index.ts +0 -93
  131. package/contracts/investors/pages/index.ts +0 -88
  132. package/contracts/investors/payment-methods/index.ts +0 -149
  133. package/contracts/investors/portfolios/index.ts +0 -53
  134. package/contracts/investors/sites/index.ts +0 -96
  135. package/contracts/investors/tasks/index.ts +0 -111
  136. package/contracts/investors/trade-line-items/index.ts +0 -75
  137. package/contracts/investors/trades/index.ts +0 -114
  138. package/contracts/investors/trusted-contacts/index.ts +0 -93
  139. package/contracts/investors/user-manuals/index.ts +0 -62
  140. package/contracts/investors/user-settings/index.ts +0 -170
  141. package/contracts/investors/users/index.ts +0 -45
  142. package/contracts/investors/webhooks/index.ts +0 -30
  143. package/contracts/issuers/account-contacts/index.ts +0 -76
  144. package/contracts/issuers/account-integrations/index.ts +0 -97
  145. package/contracts/issuers/accounts/index.ts +0 -97
  146. package/contracts/issuers/activities/index.ts +0 -54
  147. package/contracts/issuers/aic/index.ts +0 -39
  148. package/contracts/issuers/api-key-logs/index.ts +0 -53
  149. package/contracts/issuers/api-keys/index.ts +0 -93
  150. package/contracts/issuers/assets/index.ts +0 -122
  151. package/contracts/issuers/auth/index.ts +0 -152
  152. package/contracts/issuers/bonus-tiers/index.ts +0 -55
  153. package/contracts/issuers/contact-us/index.ts +0 -48
  154. package/contracts/issuers/covered-persons/index.ts +0 -136
  155. package/contracts/issuers/dashboard/index.ts +0 -72
  156. package/contracts/issuers/data-records/index.ts +0 -257
  157. package/contracts/issuers/data-rooms/index.ts +0 -134
  158. package/contracts/issuers/disbursement-approval-users/index.ts +0 -82
  159. package/contracts/issuers/disbursement-transactions/index.ts +0 -53
  160. package/contracts/issuers/disbursements/index.ts +0 -171
  161. package/contracts/issuers/email-themes/index.ts +0 -242
  162. package/contracts/issuers/escrow-accounts/index.ts +0 -81
  163. package/contracts/issuers/exchange-api-keys/index.ts +0 -144
  164. package/contracts/issuers/files/index.ts +0 -166
  165. package/contracts/issuers/files-public/index.ts +0 -166
  166. package/contracts/issuers/health/index.ts +0 -24
  167. package/contracts/issuers/index.ts +0 -112
  168. package/contracts/issuers/investor-accounts/index.ts +0 -148
  169. package/contracts/issuers/invites/index.ts +0 -129
  170. package/contracts/issuers/issuer/index.ts +0 -94
  171. package/contracts/issuers/issuer-bank-accounts/index.ts +0 -81
  172. package/contracts/issuers/issuer-payment-methods/index.ts +0 -136
  173. package/contracts/issuers/kyc/index.ts +0 -38
  174. package/contracts/issuers/login-histories/index.ts +0 -51
  175. package/contracts/issuers/notes/index.ts +0 -69
  176. package/contracts/issuers/offerings/index.ts +0 -206
  177. package/contracts/issuers/pages/index.ts +0 -138
  178. package/contracts/issuers/payment-methods/index.ts +0 -61
  179. package/contracts/issuers/portfolios/index.ts +0 -36
  180. package/contracts/issuers/rejection-reasons/index.ts +0 -32
  181. package/contracts/issuers/review/index.ts +0 -63
  182. package/contracts/issuers/secondary-customers/index.ts +0 -55
  183. package/contracts/issuers/secondary-orders/index.ts +0 -57
  184. package/contracts/issuers/secondary-trades/index.ts +0 -57
  185. package/contracts/issuers/secure-requests/index.ts +0 -34
  186. package/contracts/issuers/site-links/index.ts +0 -116
  187. package/contracts/issuers/site-settings/index.ts +0 -585
  188. package/contracts/issuers/sites/index.ts +0 -32
  189. package/contracts/issuers/tasks/index.ts +0 -111
  190. package/contracts/issuers/trades/index.ts +0 -132
  191. package/contracts/issuers/transactions/index.ts +0 -158
  192. package/contracts/issuers/user-manuals/index.ts +0 -62
  193. package/contracts/issuers/user-settings/index.ts +0 -170
  194. package/contracts/issuers/users/index.ts +0 -126
  195. package/contracts/secondaries/accounts/index.ts +0 -58
  196. package/contracts/secondaries/index.ts +0 -23
  197. package/contracts/secondaries/secondary-customers/index.ts +0 -55
  198. package/contracts/secondaries/secondary-issuers/index.ts +0 -94
  199. package/contracts/secondaries/secondary-orders/index.ts +0 -56
  200. package/contracts/secondaries/secondary-securities/index.ts +0 -95
  201. package/contracts/secondaries/secondary-trades/index.ts +0 -56
package/README.md CHANGED
@@ -14,32 +14,33 @@ npm install @dalmore/api-contracts@dev
14
14
 
15
15
  ## Usage
16
16
 
17
- ### Import specific contracts (recommended for tree-shaking)
17
+ ### Import from main entry
18
18
 
19
19
  ```typescript
20
- import { complianceContract } from '@dalmore/api-contracts/compliance';
21
- import { investorsContract } from '@dalmore/api-contracts/investors';
22
- import { issuersContract } from '@dalmore/api-contracts/issuers';
23
- import { clientsContract } from '@dalmore/api-contracts/clients';
20
+ import { clientsContract } from '@dalmore/api-contracts';
21
+ import type { IInvestorAccount } from '@dalmore/api-contracts';
24
22
  ```
25
23
 
26
- ### Import types
24
+ ### Import specific subpaths (recommended for tree-shaking)
27
25
 
28
26
  ```typescript
29
- import type { IInvestorAccount } from '@dalmore/api-contracts/types/investor-account.types';
30
- import type { ITrade } from '@dalmore/api-contracts/types/trade.types';
27
+ // Import clients contract
28
+ import { clientsContract } from '@dalmore/api-contracts/clients';
29
+
30
+ // Import types
31
+ import type { IInvestorAccount, ITrade } from '@dalmore/api-contracts/types';
31
32
  ```
32
33
 
33
34
  ### Create a typed client
34
35
 
35
36
  ```typescript
36
- import { complianceContract } from '@dalmore/api-contracts/compliance';
37
+ import { clientsContract } from '@dalmore/api-contracts/clients';
37
38
  import { initClient } from '@ts-rest/core';
38
39
 
39
- const client = initClient(complianceContract, {
40
+ const client = initClient(clientsContract, {
40
41
  baseUrl: 'https://platform.dalmoregroup.com',
41
42
  baseHeaders: {
42
- Authorization: `Bearer ${token}`,
43
+ 'X-API-Key': `${apiKey}`,
43
44
  },
44
45
  });
45
46
 
@@ -53,17 +54,20 @@ const { status, body } = await client.accounts.getAccounts({
53
54
 
54
55
  This package requires the following peer dependencies:
55
56
 
56
- - `@ts-rest/core` ^3.0.0
57
- - `zod` ^3.0.0
57
+ - `@anatine/zod-openapi` ^1.14.2
58
+ - `@ts-rest/core` ^3.52.1
59
+ - `typeid-js` ^1.2.0
60
+ - `zod` ^3.24.4
58
61
 
59
- ## Available Contracts
62
+ ## Available Exports
60
63
 
61
- - `complianceContract` - Compliance portal API
62
- - `investorsContract` - Investor portal API
63
- - `issuersContract` - Issuer portal API
64
64
  - `clientsContract` - Client API (API key auth)
65
- - `secondariesContract` - Secondaries API
66
- - `complianceApiKeyContract` - Compliance API (API key auth)
65
+
66
+ ## Available Subpath Exports
67
+
68
+ - `@dalmore/api-contracts` - Main entry (clients contract and types)
69
+ - `@dalmore/api-contracts/clients` - Clients contract
70
+ - `@dalmore/api-contracts/types` - All common types
67
71
 
68
72
  ## TypeScript Configuration
69
73
 
@@ -6,6 +6,7 @@ import { PhoneZodSchema } from './phone.type';
6
6
  import {
7
7
  AccountContactType,
8
8
  AccountZod,
9
+ EmailSchema,
9
10
  IPaginationMeta,
10
11
  } from './common.types';
11
12
  import { IBaseEntity } from './entity.types';
@@ -60,7 +61,7 @@ export const PatchAccountContactZod = z.object({
60
61
  .openapi({ example: 'Mr' }),
61
62
  firstName: z.string().min(1).max(150).openapi({ example: 'John' }),
62
63
  lastName: z.string().min(1).max(150).openapi({ example: 'Doe' }),
63
- email: z.string().email().openapi({ example: 'john.doe@example.com' }),
64
+ email: EmailSchema.openapi({ example: 'john.doe@example.com' }),
64
65
  phone: PhoneZodSchema.nullable()
65
66
  .optional()
66
67
  .openapi({ example: '+12124567890' }),
@@ -4,7 +4,7 @@ import { TypeID } from 'typeid-js';
4
4
  import { IBaseEntity } from './entity.types';
5
5
  import { PhoneNumberData } from './sms.types';
6
6
  import { userIdSchema, UserZod } from './user.types';
7
- import { IPaginationMeta } from './common.types';
7
+ import { EmailSchema, IPaginationMeta } from './common.types';
8
8
  import { PhoneZodSchema } from './phone.type';
9
9
 
10
10
  extendZodWithOpenApi(z);
@@ -68,7 +68,7 @@ export type IAccountManagerZod = z.infer<typeof IAccountManagerZod>;
68
68
  export const PostAccountManagerZod = z.object({
69
69
  firstName: z.string().min(1).max(255).openapi({ example: 'John' }),
70
70
  lastName: z.string().min(1).max(255).openapi({ example: 'Doe' }),
71
- email: z.string().email().openapi({ example: 'john.doe@example.com' }),
71
+ email: EmailSchema,
72
72
  phone: PhoneZodSchema.nullable()
73
73
  .optional()
74
74
  .openapi({ example: '+12124567890' }),
@@ -80,11 +80,7 @@ export type PostAccountManagerZod = z.infer<typeof PostAccountManagerZod>;
80
80
  export const PatchAccountManagerZod = z.object({
81
81
  firstName: z.string().min(1).max(255).optional().openapi({ example: 'John' }),
82
82
  lastName: z.string().min(1).max(255).optional().openapi({ example: 'Doe' }),
83
- email: z
84
- .string()
85
- .email()
86
- .optional()
87
- .openapi({ example: 'john.doe@example.com' }),
83
+ email: EmailSchema.optional(),
88
84
  phone: PhoneZodSchema.nullable()
89
85
  .optional()
90
86
  .openapi({ example: '+12124567890' }),
@@ -0,0 +1,65 @@
1
+ import { extendZodWithOpenApi } from '@anatine/zod-openapi';
2
+ import { z } from 'zod';
3
+ import { TypeID } from 'typeid-js';
4
+ import { IBaseEntity } from './entity.types';
5
+ import { IPaginationMeta } from './common.types';
6
+ import { accountIdSchema } from './account.types';
7
+
8
+ extendZodWithOpenApi(z);
9
+
10
+ export const accountSettingIdSchema = z.string().refine(
11
+ (value) => {
12
+ try {
13
+ const tid = TypeID.fromString(value);
14
+ return tid.getType() === 'account_setting';
15
+ } catch {
16
+ return false;
17
+ }
18
+ },
19
+ {
20
+ message:
21
+ 'Invalid account setting ID format. Must be a valid TypeID with "account_setting" prefix.',
22
+ },
23
+ );
24
+
25
+ export const IAccountSettingZod = IBaseEntity.extend({
26
+ id: accountSettingIdSchema.openapi({
27
+ example: 'account_setting_01j5y5ghx8fvc83dmx3pznq7hv',
28
+ }),
29
+ accountId: z.string().openapi({
30
+ example: 'account_01j5y5ghx8fvc83dmx3pznq7hv',
31
+ }),
32
+ });
33
+ export type IAccountSettingZod = z.infer<typeof IAccountSettingZod>;
34
+
35
+ export const IPaginatedAccountSetting = z.object({
36
+ items: z.array(IAccountSettingZod),
37
+ meta: IPaginationMeta,
38
+ });
39
+ export type IPaginatedAccountSetting = z.infer<typeof IPaginatedAccountSetting>;
40
+
41
+ export const AccountSettingsFilters = z.object({
42
+ accountId: accountIdSchema.optional(),
43
+ });
44
+ export type AccountSettingsFilters = z.infer<typeof AccountSettingsFilters>;
45
+
46
+ export const accountSettingsInclude = z.enum(['notificationChannels']);
47
+
48
+ export const AccountSettingsIncludeQuery = z.object({
49
+ include: z
50
+ .string()
51
+ .optional()
52
+ .transform((str) => (str ? str.split(',') : []))
53
+ .refine(
54
+ (includes) =>
55
+ includes.every((include) =>
56
+ accountSettingsInclude.options.includes(include as any),
57
+ ),
58
+ {
59
+ message: `Invalid include value. Valid values are: ${accountSettingsInclude.options.join(', ')}`,
60
+ },
61
+ ),
62
+ });
63
+ export type AccountSettingsIncludeQuery = z.infer<
64
+ typeof AccountSettingsIncludeQuery
65
+ >;
@@ -91,6 +91,7 @@ export const AccountFiltersZod = z.object({
91
91
  const accountsInclude = z.enum([
92
92
  'accountManager',
93
93
  'accountIntegrations',
94
+ 'accountSettings',
94
95
  'apiKeys',
95
96
  'assets',
96
97
  'dataRooms',
@@ -8,6 +8,7 @@ import {
8
8
  ManagedByType,
9
9
  UserRole,
10
10
  createUrlSchema,
11
+ EmailSchema,
11
12
  } from './common.types';
12
13
  import { TypeID } from 'typeid-js';
13
14
  import { TwoFactorMethod } from './sms.types';
@@ -60,13 +61,7 @@ const BaseAuthBody = z.object({
60
61
  .openapi({
61
62
  example: 'Armstrong',
62
63
  }),
63
- email: z
64
- .string()
65
- .email()
66
- .transform((val) => val.toLowerCase())
67
- .openapi({
68
- example: 'neil@dalmoregroup.com',
69
- }),
64
+ email: EmailSchema,
70
65
  password: PasswordSchema,
71
66
  });
72
67
 
@@ -99,13 +94,7 @@ export const IChangePasswordBodyZod = z
99
94
  });
100
95
 
101
96
  export const LoginBody = z.object({
102
- email: z
103
- .string()
104
- .email()
105
- .transform((val) => val.toLowerCase())
106
- .openapi({
107
- example: 'neil@dalmoregroup.com',
108
- }),
97
+ email: EmailSchema,
109
98
  password: z.string().openapi({
110
99
  example: 'Secretpassword6#',
111
100
  }),
@@ -297,7 +286,7 @@ export const RegisterBodyInvestors = BaseAuthBody.extend({
297
286
  });
298
287
 
299
288
  export const ResetPasswordVerifyBody = z.object({
300
- email: z.string().email(),
289
+ email: EmailSchema,
301
290
  code: z.string().length(6, 'code is not 6 characters').openapi({
302
291
  example: '123456',
303
292
  }),
@@ -315,7 +304,7 @@ export type ResetPasswordVerifyResponseType = z.infer<
315
304
  >;
316
305
 
317
306
  export const ResetPasswordBody = z.object({
318
- email: z.string().email(),
307
+ email: EmailSchema,
319
308
  code: z.string().length(6, 'code is not 6 characters').openapi({
320
309
  example: '123456',
321
310
  }),
@@ -337,7 +326,7 @@ export type ClientAuthSuccessResponse = z.infer<
337
326
  >;
338
327
 
339
328
  export const AdminForgotPasswordRequestZod = z.object({
340
- email: z.string().email(),
329
+ email: EmailSchema,
341
330
  portal: z.nativeEnum(PortalType),
342
331
  });
343
332
  export type AdminForgotPasswordRequestZod = z.infer<
@@ -345,7 +334,7 @@ export type AdminForgotPasswordRequestZod = z.infer<
345
334
  >;
346
335
 
347
336
  export const InvestorForgotPasswordRequestZod = z.object({
348
- email: z.string().email(),
337
+ email: EmailSchema,
349
338
  url: createUrlSchema({ strict: true }),
350
339
  });
351
340
  export type InvestorForgotPasswordRequestZod = z.infer<
@@ -98,6 +98,15 @@ export type EstimateBonusTierCalculationZod = z.infer<
98
98
  typeof EstimateBonusTierCalculationZod
99
99
  >;
100
100
 
101
+ export const ComplianceEstimateBonusTierCalculationZod =
102
+ EstimateBonusTierCalculationZod.and(
103
+ z.object({
104
+ accountId: accountIdSchema,
105
+ }),
106
+ );
107
+ export type ComplianceEstimateBonusTierCalculationZod = z.infer<
108
+ typeof ComplianceEstimateBonusTierCalculationZod
109
+ >;
101
110
  export const EstimateBonusTierCalculationResponseZod = z.object({
102
111
  bonusTierId: bonusTierIdSchema
103
112
  .nullable()
@@ -145,3 +154,27 @@ export const CompliancePostBonusTierZod = PostBonusTierZod.extend({
145
154
  export type CompliancePostBonusTierZod = z.infer<
146
155
  typeof CompliancePostBonusTierZod
147
156
  >;
157
+ export const PurchaseCalculationZod = z.object({
158
+ assetId: assetIdSchema,
159
+ totalAmount: z.number().positive().openapi({ example: 1000 }),
160
+ purchasedShares: z.number().positive().int().openapi({ example: 100 }),
161
+ });
162
+ export type PurchaseCalculationZod = z.infer<typeof PurchaseCalculationZod>;
163
+
164
+ export const PurchaseCalculationResponseZod = z.object({
165
+ bonusTierId: bonusTierIdSchema
166
+ .nullable()
167
+ .openapi({ example: 'bonus_tier_01j5y5ghx5fg68d663j1fvy2x7' }),
168
+ assetId: assetIdSchema.openapi({
169
+ example: 'asset_00041061050r3gg28a1c60t3gf',
170
+ }),
171
+ type: z
172
+ .nativeEnum(BonusType)
173
+ .nullable()
174
+ .openapi({ example: BonusType.PERCENTAGE }),
175
+ bonusShares: z.number().int().openapi({ example: 100 }),
176
+ });
177
+
178
+ export type PurchaseCalculationResponseZod = z.infer<
179
+ typeof PurchaseCalculationResponseZod
180
+ >;
@@ -3,6 +3,7 @@ import { extendZodWithOpenApi } from '@anatine/zod-openapi';
3
3
  import { TradeStatus } from './common.types';
4
4
  import { investorAccountIdSchema } from './investor-account.types';
5
5
  import { paymentMethodIdSchema } from './payment-methods.types';
6
+ import { userIdSchema } from './user.types';
6
7
 
7
8
  extendZodWithOpenApi(z);
8
9
 
@@ -10,7 +11,9 @@ export const PlaceTradeResponse = z.object({
10
11
  tradeStatus: z.nativeEnum(TradeStatus).optional(),
11
12
  });
12
13
  export const PlaceTradeBody = z.object({});
13
-
14
+ export const ClientPlacetradeBody = z.object({
15
+ userId: userIdSchema,
16
+ });
14
17
  export const PatchCartBody = z.object({
15
18
  investorAccountId: investorAccountIdSchema.optional(),
16
19
  paymentMethodId: paymentMethodIdSchema.optional(),
@@ -69,6 +69,10 @@ export enum BaseStatus {
69
69
  VOIDED = 'VOIDED',
70
70
  JOIN = 'JOIN',
71
71
  RESTORE = 'RESTORE',
72
+ ACTIVE = 'ACTIVE',
73
+ LOCKED = 'LOCKED',
74
+ ENABLED = 'ENABLED',
75
+ DISABLED = 'DISABLED',
72
76
  }
73
77
 
74
78
  export const UserWithoutPasswordAccountZod = IBaseEntity.extend({
@@ -111,6 +115,10 @@ export enum HttpMethod {
111
115
  OPTIONS = 'OPTIONS',
112
116
  }
113
117
 
118
+ export enum UserStatus {
119
+ ACTIVE = 'ACTIVE',
120
+ LOCKED = 'LOCKED',
121
+ }
114
122
  export const SENSITIVE_PATTERNS = [
115
123
  /password/i,
116
124
  /credit.*card/i,
@@ -200,11 +208,6 @@ export enum UserType {
200
208
  DEMO = 'DEMO',
201
209
  }
202
210
 
203
- export enum UserStatus {
204
- ACTIVE = 'ACTIVE',
205
- LOCKED = 'LOCKED',
206
- }
207
-
208
211
  export enum UserRole {
209
212
  API_KEY = 'API_KEY',
210
213
  IMPORT = 'IMPORT',
@@ -306,7 +309,7 @@ export const AuthUserReq = BaseAuthReq.extend({
306
309
  lastName: z.string(),
307
310
  email: z.string().email(),
308
311
  provider: z.string(),
309
- status: z.lazy(() => z.nativeEnum(UserStatus)),
312
+ locked: z.boolean(),
310
313
  lastLoginAt: z.date().nullable(),
311
314
  loginCount: z.number(),
312
315
  requiresTwoFactorSetup: z.boolean().optional(),
@@ -809,6 +812,8 @@ export enum EventField {
809
812
  SA_STATUS = 'saStatus',
810
813
  ONBOARDING_STATUS = 'onboardingStatus',
811
814
  TRANSACTION_STATUS = 'transactionStatus',
815
+ ACTIVE = 'active',
816
+ LOCKED = 'locked',
812
817
  }
813
818
 
814
819
  export enum EventName {
@@ -1518,3 +1523,30 @@ export const SUBJECT_TYPE_MAP: Record<BulkExportType, string> = {
1518
1523
  [BulkExportType.SECONDARY_CUSTOMERS]: 'Secondary Customers',
1519
1524
  [BulkExportType.SECONDARY_TRADES]: 'Secondary Trades',
1520
1525
  };
1526
+
1527
+ export const StringToBooleanSchema = z.preprocess(
1528
+ (val) =>
1529
+ val === 'true' || val === '1'
1530
+ ? true
1531
+ : val === 'false' || val === '0'
1532
+ ? false
1533
+ : val,
1534
+ z.boolean(),
1535
+ );
1536
+ export type StringToBooleanSchema = z.infer<typeof StringToBooleanSchema>;
1537
+
1538
+ /**
1539
+ * Reusable email schema that validates email format, transforms to lowercase,
1540
+ * and includes OpenAPI metadata.
1541
+ *
1542
+ * @example
1543
+ * EmailSchema.parse('John.Doe@EXAMPLE.COM'); // returns 'john.doe@example.com'
1544
+ * EmailSchema.optional().parse(undefined); // returns undefined
1545
+ */
1546
+ export const EmailSchema = z
1547
+ .string()
1548
+ .email()
1549
+ .transform((val) => val.toLowerCase())
1550
+ .openapi({
1551
+ example: 'neil@dalmoregroup.com',
1552
+ });
@@ -30,7 +30,7 @@ export const CreateSearchRequestSchema = z.object({
30
30
  .optional(),
31
31
  })
32
32
  .optional(),
33
- tags: z.record(z.string()).optional(),
33
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
34
34
  share_url: z.union([z.literal(0), z.literal(1)]).optional(),
35
35
  exact_match: z.boolean().optional(),
36
36
  });
@@ -268,7 +268,7 @@ export const GetSearchDetailsResponseSchema = z.object({
268
268
  total_matches: z.number(),
269
269
  updated_at: z.string(),
270
270
  created_at: z.string(),
271
- tags: z.record(z.string()).optional(),
271
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
272
272
  labels: z
273
273
  .array(
274
274
  z.object({
@@ -310,7 +310,7 @@ export const UpdateSearchRequestSchema = z.object({
310
310
  risk_level: z.enum(['low', 'medium', 'high', 'unknown']).optional(),
311
311
  assignee_id: z.number().optional(),
312
312
  limit: z.number().int().max(100).optional(),
313
- tags: z.record(z.string()).optional(),
313
+ tags: z.union([z.record(z.string()), z.array(z.any())]).optional(),
314
314
  });
315
315
 
316
316
  export type UpdateSearchRequest = z.infer<typeof UpdateSearchRequestSchema>;
@@ -1,7 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
3
3
  import { TypeID } from 'typeid-js';
4
- import { BaseContactUsOptions, createUrlSchema } from './common.types';
4
+ import {
5
+ BaseContactUsOptions,
6
+ createUrlSchema,
7
+ EmailSchema,
8
+ } from './common.types';
5
9
  extendZodWithOpenApi(z);
6
10
 
7
11
  export const contactUsIdSchema = z.string().refine(
@@ -55,7 +59,7 @@ export const InvestorPostContactUsZod = PostContactUsZod.extend({
55
59
  export type InvestorPostContactUsZod = z.infer<typeof InvestorPostContactUsZod>;
56
60
 
57
61
  export const PublicInvestorContactUsZod = PostContactUsZod.extend({
58
- email: z.string().email().openapi({ example: 'email@example.com' }),
62
+ email: EmailSchema,
59
63
  firstName: z.string().min(1).max(100).openapi({ example: 'John' }),
60
64
  lastName: z.string().min(1).max(100).openapi({ example: 'Doe' }),
61
65
  contactOption: z.nativeEnum(InvestorContactOptions).openapi({
@@ -6,6 +6,7 @@ import {
6
6
  ComplianceReview,
7
7
  CoveredPersonsRoleType,
8
8
  CoveredPersonsStatus,
9
+ EmailSchema,
9
10
  IDType,
10
11
  IPaginationMeta,
11
12
  } from './common.types';
@@ -137,7 +138,7 @@ export const PatchCoveredPersonsZod = z
137
138
  .openapi({ example: CoveredPersonsRoleType.ACCOUNTING }),
138
139
 
139
140
  ownership: z.number().min(0).max(100).openapi({ example: 15 }).optional(),
140
- email: z.string().nullable().optional(),
141
+ email: EmailSchema.nullable().optional(),
141
142
  idType: z
142
143
  .nativeEnum(IDType)
143
144
  .optional()
@@ -7,6 +7,7 @@ import {
7
7
  FileLabels,
8
8
  IPaginationMeta,
9
9
  OfferingType,
10
+ StringToBooleanSchema,
10
11
  } from './common.types';
11
12
  import { accountIdSchema } from './account.types';
12
13
 
@@ -330,15 +331,7 @@ export const GetInvestmentDashboardQueryZod = z.object({
330
331
  offerings: OfferingsArrayQueryZod.optional(),
331
332
  offeringTypes: OfferingTypesQueryZod.optional(),
332
333
  timeFilteringType: z.nativeEnum(DashboardTimeFilteringType),
333
- debug: z.preprocess(
334
- (val) =>
335
- val === 'true' || val === '1'
336
- ? true
337
- : val === 'false' || val === '0'
338
- ? false
339
- : val,
340
- z.boolean().optional(),
341
- ),
334
+ debug: StringToBooleanSchema.optional(),
342
335
  });
343
336
  export type GetInvestmentDashboardQueryZod = z.infer<
344
337
  typeof GetInvestmentDashboardQueryZod
@@ -11,14 +11,17 @@ import {
11
11
  import { tradeIdSchema } from './trade.types';
12
12
  import { accountIdSchema } from './account.types';
13
13
  import { TypeID } from 'typeid-js';
14
- import { issuerIdSchema } from './issuer.types';
15
- import { issuerBankAccountIdSchema } from './issuer-bank-account.types';
14
+ import { IIssuer, issuerIdSchema } from './issuer.types';
15
+ import {
16
+ IIssuerBankAccount,
17
+ issuerBankAccountIdSchema,
18
+ } from './issuer-bank-account.types';
16
19
  import { userIdSchema, UserZod } from './user.types';
17
20
  import {
18
21
  PostDisbursementAdjustmentZod,
19
22
  DisbursementAdjustmentType,
20
23
  } from './disbursement-adjustment.types';
21
- import { escrowAccountIdSchema } from './escrow-account.types';
24
+ import { IEscrowAccount, escrowAccountIdSchema } from './escrow-account.types';
22
25
 
23
26
  export const disbursementIdSchema = z.string().refine(
24
27
  (value) => {
@@ -309,6 +312,97 @@ export const DisbursementSummaryZod = z.object({
309
312
  });
310
313
  export type DisbursementSummaryZod = z.infer<typeof DisbursementSummaryZod>;
311
314
 
315
+ // GET /disbursements/preview query parameters
316
+ export const GetDisbursementPreviewQueryZod = z.object({
317
+ offeringId: offeringIdSchema,
318
+ selectedTrades: z
319
+ .string()
320
+ .optional()
321
+ .transform((str) => (str ? str.split(',') : []))
322
+ .refine(
323
+ (ids) =>
324
+ ids.every((id) => {
325
+ try {
326
+ const tid = TypeID.fromString(id);
327
+ return tid.getType() === 'trade';
328
+ } catch {
329
+ return false;
330
+ }
331
+ }),
332
+ {
333
+ message: 'All selected trades must be valid trade IDs',
334
+ },
335
+ )
336
+ .openapi({
337
+ example: 'trade_01abc123,trade_01def456',
338
+ }),
339
+ });
340
+ export type GetDisbursementPreviewQueryZod = z.infer<
341
+ typeof GetDisbursementPreviewQueryZod
342
+ >;
343
+
344
+ // Context fields for disbursement preview
345
+ export const DisbursementPreviewContextZod = z.object({
346
+ issuer: z.lazy(() => IIssuer).nullable(),
347
+ offering: z.lazy(() => IOffering).nullable(),
348
+ escrowAccount: z.lazy(() => IEscrowAccount).nullable(),
349
+ destinationBank: z.lazy(() => IIssuerBankAccount).nullable(),
350
+ });
351
+ export type DisbursementPreviewContextZod = z.infer<
352
+ typeof DisbursementPreviewContextZod
353
+ >;
354
+
355
+ // Balance values for disbursement preview
356
+ export const DisbursementPreviewBalanceZod = z.object({
357
+ totalRaised: z.number(),
358
+ totalDisbursed: z.number(),
359
+ pending: z.number(),
360
+ refundPool: z.number(),
361
+ availableForDisbursement: z.number(),
362
+ });
363
+ export type DisbursementPreviewBalanceZod = z.infer<
364
+ typeof DisbursementPreviewBalanceZod
365
+ >;
366
+
367
+ // Trade summary for disbursement preview
368
+ export const DisbursementPreviewTradeSummaryZod = z.object({
369
+ selectedTradesCount: z.number(),
370
+ selectedTradesTotalAmount: z.number(),
371
+ });
372
+ export type DisbursementPreviewTradeSummaryZod = z.infer<
373
+ typeof DisbursementPreviewTradeSummaryZod
374
+ >;
375
+
376
+ // Contingency validation result
377
+ export const DisbursementPreviewContingencyZod = z.object({
378
+ contingencyPassed: z.boolean(),
379
+ contingencyMessage: z.string().nullable(),
380
+ contingencyAmount: z.number(),
381
+ });
382
+ export type DisbursementPreviewContingencyZod = z.infer<
383
+ typeof DisbursementPreviewContingencyZod
384
+ >;
385
+
386
+ // Amount defaults and constraints
387
+ export const DisbursementPreviewAmountZod = z.object({
388
+ defaultAmount: z.number(),
389
+ minAmount: z.number(),
390
+ maxAmount: z.number(),
391
+ });
392
+ export type DisbursementPreviewAmountZod = z.infer<
393
+ typeof DisbursementPreviewAmountZod
394
+ >;
395
+
396
+ // Complete response for GET /disbursements/preview
397
+ export const DisbursementPreviewZod = z.object({
398
+ context: DisbursementPreviewContextZod,
399
+ balance: DisbursementPreviewBalanceZod,
400
+ tradeSummary: DisbursementPreviewTradeSummaryZod,
401
+ contingency: DisbursementPreviewContingencyZod,
402
+ amount: DisbursementPreviewAmountZod,
403
+ });
404
+ export type DisbursementPreviewZod = z.infer<typeof DisbursementPreviewZod>;
405
+
312
406
  export const EligibleOfferingZod = z.object({
313
407
  offeringId: offeringIdSchema,
314
408
  offeringName: z.string(),
@@ -1,6 +1,6 @@
1
1
  import { extendZodWithOpenApi } from '@anatine/zod-openapi';
2
2
  import { z } from 'zod';
3
- import { AccountZod, IPaginationMeta } from './common.types';
3
+ import { AccountZod, EmailSchema, IPaginationMeta } from './common.types';
4
4
  import { IBaseEntity } from './entity.types';
5
5
  import { TypeID } from 'typeid-js';
6
6
  import { accountIdSchema } from './account.types';
@@ -43,7 +43,7 @@ export const PostEscrowAccount = z.object({
43
43
  accountNumber: z.string().optional().nullable(),
44
44
  routingNumber: z.string().min(9).max(9).optional().nullable(),
45
45
  agentName: z.string().min(2).max(50),
46
- agentEmail: z.string().email(),
46
+ agentEmail: EmailSchema,
47
47
  });
48
48
 
49
49
  export type PostEscrowAccount = z.infer<typeof PostEscrowAccount>;
@@ -65,7 +65,7 @@ export const PatchEscrowAccount = z.object({
65
65
  accountNumber: z.string().min(10).max(18).optional().nullable().optional(),
66
66
  routingNumber: z.string().min(9).max(9).optional().nullable().optional(),
67
67
  agentName: z.string().min(2).max(50).optional(),
68
- agentEmail: z.string().email().optional(),
68
+ agentEmail: EmailSchema.optional(),
69
69
  });
70
70
 
71
71
  export type PatchEscrowAccount = z.infer<typeof PatchEscrowAccount>;