@dalmore/api-contracts 0.0.0-dev.785b227 → 0.0.0-dev.b5e5f0c

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.
@@ -199,7 +199,7 @@ export const ActivityZod = IBaseEntity.extend({
199
199
  userId: z.string().nullable(),
200
200
  activityTypeId: z.string(),
201
201
  accountId: z.string().nullable(),
202
- user: UserForActivityZod,
202
+ user: UserForActivityZod.nullable(),
203
203
  activityType: ActivityTypeZod,
204
204
  targetObject: z.string().nullable().optional(),
205
205
  __entity: z.string().optional(),
@@ -308,3 +308,25 @@ export const DisbursementSummaryZod = z.object({
308
308
  amountToBeTransferred: z.number(),
309
309
  });
310
310
  export type DisbursementSummaryZod = z.infer<typeof DisbursementSummaryZod>;
311
+
312
+ export const EligibleOfferingZod = z.object({
313
+ offeringId: offeringIdSchema,
314
+ offeringName: z.string(),
315
+ availableAmount: z.number(),
316
+ });
317
+ export type EligibleOfferingZod = z.infer<typeof EligibleOfferingZod>;
318
+
319
+ export const IPaginatedEligibleOffering = z.object({
320
+ items: z.array(EligibleOfferingZod),
321
+ meta: IPaginationMeta,
322
+ });
323
+ export type IPaginatedEligibleOffering = z.infer<
324
+ typeof IPaginatedEligibleOffering
325
+ >;
326
+
327
+ export const EligibleOfferingsFiltersZod = z.object({
328
+ search: z.string().optional(),
329
+ });
330
+ export type EligibleOfferingsFiltersZod = z.infer<
331
+ typeof EligibleOfferingsFiltersZod
332
+ >;
@@ -17,7 +17,7 @@ import { KybZod } from './kyb.types';
17
17
  import { IIndividualZod, individualIdSchema } from './individuals.types';
18
18
  import { LegalEntityZod } from './legal-entity.types';
19
19
  import { IInvestorAccount } from './investor-account.types';
20
- import { TradeZod } from './trade.types';
20
+ import { tradeIdSchema, TradeZod } from './trade.types';
21
21
 
22
22
  extendZodWithOpenApi(z);
23
23
 
@@ -168,13 +168,13 @@ export type PostFileQueryParams = z.infer<typeof PostFileQueryParams>;
168
168
 
169
169
  /**
170
170
  * CLIENT portal specific schema for file uploads
171
- * Only allows INDIVIDUALS as target for file uploads
171
+ * Only allows INDIVIDUALS and TRADES as target for file uploads
172
172
  */
173
173
  export const ClientPostFileQueryParams = z.object({
174
174
  name: z.string().min(1).max(100).openapi({ example: 'file_name' }),
175
175
  category: z.string().max(50).openapi({ example: 'application' }),
176
176
  label: FileLabelsEnum.openapi({ example: FileLabels.OTHER }),
177
- targetId: individualIdSchema.openapi({
177
+ targetId: z.union([individualIdSchema, tradeIdSchema]).openapi({
178
178
  example: 'individual_01kcrsny60fb9rjc8bbqc3b80c',
179
179
  }),
180
180
  metadata: metadataSchema.nullable().optional(),
@@ -314,8 +314,23 @@ export const reviewFiles = z.object({
314
314
  });
315
315
  export type reviewFiles = z.infer<typeof reviewFiles>;
316
316
 
317
+ /**
318
+ * Zod preprocessor that trims strings and converts empty/whitespace-only strings to null
319
+ */
320
+ const trimAndNullifyString = z.preprocess((val) => {
321
+ if (typeof val === 'string') {
322
+ const trimmed = val.trim();
323
+ return trimmed === '' ? null : trimmed;
324
+ }
325
+ return val;
326
+ }, z.unknown());
327
+
317
328
  export const PatchFileMetadata = z.object({
318
- corrected: z.record(z.string(), z.unknown()),
329
+ corrected: z.record(z.string(), trimAndNullifyString),
330
+ expectedCorrected: z
331
+ .record(z.string(), trimAndNullifyString)
332
+ .nullable()
333
+ .optional(),
319
334
  });
320
335
  export type PatchFileMetadata = z.infer<typeof PatchFileMetadata>;
321
336
 
@@ -343,6 +358,7 @@ export const FileMetadataSchema = z.object({
343
358
  },
344
359
  ),
345
360
  corrected: z.record(z.any()).optional(),
361
+ expectedCorrected: z.record(z.any()).optional(),
346
362
  });
347
363
  export type FileMetadata = z.infer<typeof FileMetadataSchema>;
348
364
 
@@ -42,6 +42,7 @@ export * from './domain-filter.types';
42
42
  export * from './aic.types';
43
43
  export * from './default-theme-config.types';
44
44
  export * from './offering-reports.types';
45
+ export * from './payment-methods.types';
45
46
 
46
47
  export enum Versions {
47
48
  V1 = 'v1',
@@ -222,10 +222,51 @@ export type IPaginatedIssuerPaymentMethod = z.infer<
222
222
  typeof IPaginatedIssuerPaymentMethod
223
223
  >;
224
224
 
225
+ const issuerPaymentMethodsInclude = z.enum(['issuer', 'integration']);
226
+
227
+ /**
228
+ * @description Query parameters for including related entities
229
+ * @example in contract use as -> query: PaginationOptionsZod.merge(GetIssuerPaymentMethodZod).merge(IssuerPaymentMethodsIncludeQuery)
230
+ */
231
+ export const IssuerPaymentMethodsIncludeQuery = z.object({
232
+ include: z
233
+ .string()
234
+ .optional()
235
+ .transform((str) => (str ? str.split(',') : []))
236
+ .refine(
237
+ (includes) =>
238
+ includes.every((include) =>
239
+ issuerPaymentMethodsInclude.options.includes(include as any),
240
+ ),
241
+ {
242
+ message: `Invalid include option provided. Valid options are: ${issuerPaymentMethodsInclude.options.join(',')}`,
243
+ },
244
+ )
245
+ .openapi({
246
+ example: `${issuerPaymentMethodsInclude.options.join(',')}`,
247
+ }),
248
+ });
249
+ export type IssuerPaymentMethodsIncludeQuery = z.infer<
250
+ typeof IssuerPaymentMethodsIncludeQuery
251
+ >;
252
+
225
253
  export const GetIssuerPaymentMethodZod = z.object({
226
254
  issuerId: issuerIdSchema.openapi({
227
255
  example: 'issuer_01jdq2crwke8xskjd840cj79pw',
228
256
  }),
257
+ enabled: z
258
+ .string()
259
+ .optional()
260
+ .refine((v) => !v || v === 'true' || v === 'false', {
261
+ message: 'enabled must be a boolean string',
262
+ })
263
+ .transform((v) => {
264
+ if (!v) return undefined;
265
+ return v === 'true';
266
+ })
267
+ .openapi({
268
+ example: 'true',
269
+ }),
229
270
  });
230
271
  export type GetIssuerPaymentMethodZod = z.infer<
231
272
  typeof GetIssuerPaymentMethodZod
@@ -152,6 +152,10 @@ export const PutIssuerZod = z
152
152
  .lazy(() => fileIdSchema)
153
153
  .optional()
154
154
  .nullable(),
155
+ formationDocumentFileId: z
156
+ .lazy(() => fileIdSchema)
157
+ .optional()
158
+ .nullable(),
155
159
  coverArtId: z
156
160
  .lazy(() => fileIdSchema)
157
161
  .optional()
@@ -188,6 +192,11 @@ export const IIssuer = IBaseEntity.extend({
188
192
  accountId: z.string(),
189
193
  account: AccountZod.optional().nullable(),
190
194
  ss4LetterFileId: z.string().nullable(),
195
+ formationDocumentFileId: z.string().nullable(),
196
+ formationDocument: z
197
+ .lazy(() => FileZod)
198
+ .nullable()
199
+ .optional(),
191
200
  status: z
192
201
  .nativeEnum(IssuerStatus)
193
202
  .openapi({ example: IssuerStatus.SUBMITTED }),
@@ -16,6 +16,8 @@ import { secureRequestContract } from './secure-requests';
16
16
  import { aicContract } from './aic';
17
17
  import { authContract } from './auth';
18
18
  import { sitesContract } from './sites';
19
+ import { paymentMethodsContract } from './payment-methods';
20
+ import { issuerPaymentMethodsContract } from './issuer-payment-methods';
19
21
  import { tradeLineItemsContract } from './trade-line-items';
20
22
 
21
23
  const c = initContract();
@@ -34,9 +36,11 @@ export const clientsContract = c.router(
34
36
  filesPublic: filesPublicContract,
35
37
  individuals: individualsContract,
36
38
  investorAccounts: investorAccountsContract,
39
+ issuerPaymentMethods: issuerPaymentMethodsContract,
37
40
  issuers: issuersContract,
38
41
  legalEntities: legalEntityContract,
39
42
  offerings: offeringsContract,
43
+ paymentMethods: paymentMethodsContract,
40
44
  secureRequests: secureRequestContract,
41
45
  sites: sitesContract,
42
46
  tradeLineItems: tradeLineItemsContract,
@@ -0,0 +1,39 @@
1
+ import { initContract } from '@ts-rest/core';
2
+ import {
3
+ ForbiddenError,
4
+ InternalError,
5
+ NotFoundError,
6
+ UnauthorizedError,
7
+ GetIssuerPaymentMethodZod,
8
+ IPaginatedIssuerPaymentMethod,
9
+ IssuerPaymentMethodsIncludeQuery,
10
+ PaginationOptionsZod,
11
+ } from '../../../common/types';
12
+
13
+ const c = initContract();
14
+
15
+ export const issuerPaymentMethodsContract = c.router(
16
+ {
17
+ getIssuerPaymentMethods: {
18
+ summary: 'Get issuer payment methods',
19
+ method: 'GET',
20
+ path: '',
21
+ metadata: {
22
+ auth: true,
23
+ },
24
+ query: PaginationOptionsZod.merge(GetIssuerPaymentMethodZod).merge(
25
+ IssuerPaymentMethodsIncludeQuery,
26
+ ),
27
+ responses: {
28
+ 200: IPaginatedIssuerPaymentMethod,
29
+ 401: UnauthorizedError,
30
+ 403: ForbiddenError,
31
+ 404: NotFoundError,
32
+ 500: InternalError,
33
+ },
34
+ },
35
+ },
36
+ {
37
+ pathPrefix: 'issuer-payment-methods',
38
+ },
39
+ );
@@ -0,0 +1,85 @@
1
+ import { initContract } from '@ts-rest/core';
2
+ import { z } from 'zod';
3
+ import {
4
+ UnauthorizedError,
5
+ ForbiddenError,
6
+ NotFoundError,
7
+ userIdSchema,
8
+ BadRequestError,
9
+ InternalError,
10
+ } from '../../../common/types';
11
+ import {
12
+ PaymentMethodResponseArray,
13
+ PaymentMethodResponse,
14
+ PostPaymentMethod,
15
+ PostSetupIntentBody,
16
+ SetupIntentResponse,
17
+ } from '../../../common/types/payment-methods.types';
18
+
19
+ const c = initContract();
20
+
21
+ export const paymentMethodsContract = c.router(
22
+ {
23
+ getPaymentMethods: {
24
+ summary: 'Get payment methods for a user',
25
+ method: 'GET',
26
+ path: '',
27
+ metadata: {
28
+ auth: true,
29
+ },
30
+ query: z.object({
31
+ userId: userIdSchema,
32
+ }),
33
+ responses: {
34
+ 200: PaymentMethodResponseArray,
35
+ 401: UnauthorizedError,
36
+ 403: ForbiddenError,
37
+ 404: NotFoundError,
38
+ 500: InternalError,
39
+ },
40
+ },
41
+ createPaymentMethod: {
42
+ summary: 'Create payment method for a user',
43
+ method: 'POST',
44
+ path: '',
45
+ metadata: {
46
+ auth: true,
47
+ },
48
+ query: z.object({
49
+ userId: userIdSchema,
50
+ }),
51
+ body: PostPaymentMethod,
52
+ responses: {
53
+ 201: PaymentMethodResponse,
54
+ 400: BadRequestError,
55
+ 401: UnauthorizedError,
56
+ 403: ForbiddenError,
57
+ 404: NotFoundError,
58
+ 500: InternalError,
59
+ },
60
+ },
61
+ createSetupIntent: {
62
+ summary: 'Create payment method setup intent for a user',
63
+ method: 'POST',
64
+ path: '/intent',
65
+ metadata: {
66
+ auth: true,
67
+ },
68
+ query: z.object({
69
+ userId: userIdSchema,
70
+ }),
71
+ body: PostSetupIntentBody,
72
+ responses: {
73
+ 201: SetupIntentResponse,
74
+ 400: BadRequestError,
75
+ 401: UnauthorizedError,
76
+ 403: ForbiddenError,
77
+ 404: NotFoundError,
78
+ 500: InternalError,
79
+ },
80
+ },
81
+ },
82
+ {
83
+ pathPrefix: 'payment-methods',
84
+ },
85
+ );
@@ -19,7 +19,9 @@ import {
19
19
  DisbursementsMissingConfigQuery,
20
20
  DisbursementSummaryZod,
21
21
  DisbursementZod,
22
+ EligibleOfferingsFiltersZod,
22
23
  IPaginatedDisbursement,
24
+ IPaginatedEligibleOffering,
23
25
  PostDisbursementBalanceZod,
24
26
  PostDisbursementSummaryZod,
25
27
  PostDisbursementZod,
@@ -146,6 +148,22 @@ export const disbursementsContract = c.router(
146
148
  500: InternalError,
147
149
  },
148
150
  },
151
+ getEligibleOfferings: {
152
+ summary: 'Get eligible offerings for disbursement',
153
+ method: 'GET',
154
+ path: '/eligible-offerings',
155
+ metadata: {
156
+ auth: true,
157
+ },
158
+ query: PaginationOptionsZod.merge(EligibleOfferingsFiltersZod),
159
+ responses: {
160
+ 200: IPaginatedEligibleOffering,
161
+ 401: UnauthorizedError,
162
+ 403: ForbiddenError,
163
+ 404: NotFoundError,
164
+ 500: InternalError,
165
+ },
166
+ },
149
167
  },
150
168
  {
151
169
  pathPrefix: 'disbursements',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dalmore/api-contracts",
3
- "version": "0.0.0-dev.785b227",
3
+ "version": "0.0.0-dev.b5e5f0c",
4
4
  "description": "Type-safe API contracts for Dalmore Client Portal",
5
5
  "main": "./contracts/index.ts",
6
6
  "types": "./contracts/index.ts",