@dalmore/api-contracts 0.0.0-dev.2dc8e92 → 0.0.0-dev.3af7603

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 (39) hide show
  1. package/common/types/account-setting.types.ts +31 -0
  2. package/common/types/activity.types.ts +1 -1
  3. package/common/types/api-key-logs.types.ts +1 -1
  4. package/common/types/asset.types.ts +14 -14
  5. package/common/types/bonus-tier.types.ts +33 -0
  6. package/common/types/cart.types.ts +4 -1
  7. package/common/types/common.types.ts +16 -6
  8. package/common/types/dashboard.types.ts +2 -9
  9. package/common/types/disbursements.types.ts +119 -3
  10. package/common/types/file.types.ts +20 -4
  11. package/common/types/i-will-do-it-later.types.ts +68 -0
  12. package/common/types/index.ts +2 -0
  13. package/common/types/individuals.types.ts +2 -15
  14. package/common/types/issuer-offering.types.ts +113 -30
  15. package/common/types/issuer-payment-method.types.ts +41 -0
  16. package/common/types/issuer.types.ts +9 -0
  17. package/common/types/notification.types.ts +239 -29
  18. package/common/types/offering.types.ts +106 -20
  19. package/common/types/site.types.ts +2 -9
  20. package/common/types/{trade-line-item.type.ts → trade-line-item.types.ts} +2 -9
  21. package/common/types/trade.types.ts +71 -1
  22. package/common/types/transaction.types.ts +12 -1
  23. package/common/types/user.types.ts +15 -28
  24. package/contracts/clients/cart/index.ts +80 -0
  25. package/contracts/clients/index.ts +10 -0
  26. package/contracts/clients/issuer-payment-methods/index.ts +39 -0
  27. package/contracts/clients/payment-methods/index.ts +85 -0
  28. package/contracts/clients/trade-line-items/index.ts +66 -0
  29. package/contracts/clients/trades/index.ts +65 -1
  30. package/contracts/clients/transactions/index.ts +37 -0
  31. package/contracts/compliance/bonus-tiers/index.ts +21 -2
  32. package/contracts/compliance/trade-line-items/index.ts +1 -1
  33. package/contracts/compliance/users/index.ts +21 -0
  34. package/contracts/investors/bonus-tiers/index.ts +18 -0
  35. package/contracts/investors/individuals/index.ts +22 -0
  36. package/contracts/investors/trade-line-items/index.ts +1 -1
  37. package/contracts/issuers/bonus-tiers/index.ts +18 -0
  38. package/contracts/issuers/disbursements/index.ts +36 -0
  39. package/package.json +1 -1
@@ -8,10 +8,13 @@ import {
8
8
  ManagedByType,
9
9
  OfferingVersioningType,
10
10
  ComplianceReview,
11
+ DurationType,
12
+ AssetType,
13
+ StringToBooleanSchema,
11
14
  } from './common.types';
12
15
  import { IBaseEntity } from './entity.types';
13
16
  import { IIssuer, issuerIdSchema } from './issuer.types';
14
- import { IAsset } from './asset.types';
17
+ import { IAsset, postAssetRefinement, AssetTemplateType } from './asset.types';
15
18
  import { fileIdSchema, FileZod } from './file.types';
16
19
  import { accountIdSchema } from './account.types';
17
20
 
@@ -128,20 +131,60 @@ export const PostIssuerOffering = z
128
131
  .nullable()
129
132
  .openapi({ example: 'This is a description of the offering.' }),
130
133
  managedBy: z.nativeEnum(ManagedByType).optional(),
134
+ assetName: z.string().min(2).max(50).openapi({ example: 'Asset name' }),
135
+ assetType: z.nativeEnum(AssetType).openapi({ example: AssetType.STOCK }),
136
+ pricePerUnit: z
137
+ .number()
138
+ .min(0.01)
139
+ .max(10000000000)
140
+ .nullable()
141
+ .openapi({ example: 2000 }),
142
+ totalUnits: z
143
+ .number()
144
+ .min(1)
145
+ .max(10000000000)
146
+ .nullable()
147
+ .openapi({ example: 5200 }),
148
+ yield: z
149
+ .number()
150
+ .min(0.01)
151
+ .max(10000000000)
152
+ .nullable()
153
+ .optional()
154
+ .openapi({ example: 1200 }),
155
+ duration: z
156
+ .number()
157
+ .min(1)
158
+ .max(1000)
159
+ .nullable()
160
+ .optional()
161
+ .openapi({ example: 1 }),
162
+ durationType: z
163
+ .nativeEnum(DurationType)
164
+ .nullable()
165
+ .optional()
166
+ .openapi({ example: DurationType.DAY }),
167
+ template: z
168
+ .nativeEnum(AssetTemplateType)
169
+ .default(AssetTemplateType.STANDARD)
170
+ .openapi({ example: AssetTemplateType.STANDARD }),
171
+ tiers: z.array(z.number().positive()).nullable().optional(),
172
+ enableBonus: z.boolean().default(false).optional(),
131
173
  })
132
- .refine(
133
- (data) => {
134
- // Check if both values are present, and if so, ensure minInvestment is less than maxInvestment
135
- if (data.minInvestment && data.maxInvestment) {
136
- return data.minInvestment < data.maxInvestment;
174
+ .superRefine((data, ctx) => {
175
+ // Check if both values are present, and if so, ensure minInvestment is less than maxInvestment
176
+ if (data.minInvestment && data.maxInvestment) {
177
+ if (data.minInvestment >= data.maxInvestment) {
178
+ ctx.addIssue({
179
+ path: ['minInvestment'],
180
+ message: 'Minimum investment must be less than maximum investment.',
181
+ code: z.ZodIssueCode.custom,
182
+ });
137
183
  }
138
- return true; // If one or both values are undefined, skip this check
139
- },
140
- {
141
- message: 'Minimum investment must be less than maximum investment.',
142
- path: ['minInvestment'],
143
- },
144
- );
184
+ }
185
+ // Apply asset-specific refinements
186
+ postAssetRefinement(data, ctx);
187
+ });
145
188
 
146
189
  export type PostIssuerOffering = z.infer<typeof PostIssuerOffering>;
147
190
  export const PatchIssuerOffering = z.object({
@@ -151,38 +194,39 @@ export const PatchIssuerOffering = z.object({
151
194
  .max(100)
152
195
  .optional()
153
196
  .openapi({ example: 'Airbnb IPO' }),
197
+ type: z
198
+ .nativeEnum(OfferingType)
199
+ .optional()
200
+ .openapi({ example: OfferingType.REG_D }),
154
201
  targetAmount: z
155
202
  .number()
156
203
  .min(0)
157
204
  .max(10000000000)
158
205
  .optional()
159
206
  .openapi({ example: 120000 }),
160
- raiseAmount: z
161
- .number()
162
- .min(0)
163
- .max(10000000000)
164
- .optional()
165
- .openapi({ example: 200000 }),
166
207
  minInvestment: z
167
208
  .number()
168
209
  .min(0)
169
210
  .max(10000000000)
211
+ .nullable()
170
212
  .optional()
171
213
  .openapi({ example: 1000 }),
172
214
  maxInvestment: z
173
215
  .number()
174
216
  .min(0)
175
217
  .max(10000000000)
218
+ .nullable()
176
219
  .optional()
177
220
  .openapi({ example: 20000 }),
178
221
  contingencyAmount: z
179
222
  .number()
180
223
  .min(0)
181
224
  .max(10000000000)
225
+ .nullable()
182
226
  .optional()
183
227
  .openapi({ example: 5000 }),
184
- startAt: dateSchema.optional().openapi({ example: '10/20/2024' }),
185
- endAt: dateSchema.optional().openapi({ example: '10/27/2024' }),
228
+ startAt: dateSchema.nullable().optional().openapi({ example: '10/20/2024' }),
229
+ endAt: dateSchema.nullable().optional().openapi({ example: '10/27/2024' }),
186
230
  cancellationPeriod: z
187
231
  .number()
188
232
  .min(1)
@@ -212,6 +256,53 @@ export const PatchIssuerOffering = z.object({
212
256
  managedBy: z.nativeEnum(ManagedByType).optional(),
213
257
  showTotalRaised: z.boolean().optional(),
214
258
  issuerId: issuerIdSchema.optional(),
259
+ assetName: z.string().min(2).max(50).optional().openapi({ example: 'Z' }),
260
+ assetType: z
261
+ .nativeEnum(AssetType)
262
+ .optional()
263
+ .openapi({ example: AssetType.STOCK }),
264
+ pricePerUnit: z
265
+ .number()
266
+ .min(0.01)
267
+ .max(10000000000)
268
+ .nullable()
269
+ .optional()
270
+ .openapi({ example: 2000 }),
271
+ totalUnits: z
272
+ .number()
273
+ .min(1)
274
+ .max(10000000000)
275
+ .nullable()
276
+ .optional()
277
+ .openapi({ example: 5200 }),
278
+ yield: z
279
+ .number()
280
+ .min(0.01)
281
+ .max(10000000000)
282
+ .nullable()
283
+ .optional()
284
+ .openapi({ example: 1200 }),
285
+ duration: z
286
+ .number()
287
+ .min(1)
288
+ .max(1000)
289
+ .nullable()
290
+ .optional()
291
+ .openapi({ example: 1 }),
292
+ durationType: z
293
+ .nativeEnum(DurationType)
294
+ .nullable()
295
+ .optional()
296
+ .openapi({ example: DurationType.DAY }),
297
+ template: z
298
+ .nativeEnum(AssetTemplateType)
299
+ .default(AssetTemplateType.STANDARD)
300
+ .openapi({ example: AssetTemplateType.STANDARD })
301
+ .nullable()
302
+ .optional(),
303
+ tiers: z.array(z.number().positive()).nullable().optional(),
304
+ enabled: z.boolean().optional(),
305
+ enableBonus: z.boolean().optional(),
215
306
  });
216
307
  export type PatchIssuerOffering = z.infer<typeof PatchIssuerOffering>;
217
308
 
@@ -281,15 +372,7 @@ export const IssuerOfferingsFilterZod = z.object({
281
372
  issuerId: z.lazy(() => issuerIdSchema).optional(),
282
373
  type: z.nativeEnum(OfferingType).optional(),
283
374
  status: z.nativeEnum(ComplianceReview).optional(),
284
- enabled: z.preprocess(
285
- (val) =>
286
- val === 'true' || val === '1'
287
- ? true
288
- : val === 'false' || val === '0'
289
- ? false
290
- : val,
291
- z.boolean().optional(),
292
- ),
375
+ enabled: StringToBooleanSchema.optional(),
293
376
  managedBy: z.nativeEnum(ManagedByType).optional(),
294
377
  versioningType: z.nativeEnum(OfferingVersioningType).optional(),
295
378
  combinedStatus: z.nativeEnum(OfferingStatus).optional(),
@@ -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 }),
@@ -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 { accountIdSchema } from './account.types';
4
+ import { IBaseEntity } from './entity.types';
5
5
 
6
6
  extendZodWithOpenApi(z);
7
- export enum NotificationChannel {
7
+
8
+ export enum NotificationChannelType {
8
9
  EMAIL = 'EMAIL',
9
10
  SLACK = 'SLACK',
11
+ WEBHOOK = 'WEBHOOK',
10
12
  }
11
- export enum NotificationType {
12
- COMPLIANCE_TRADE_ALERT = 'COMPLIANCE_TRADE_ALERT',
13
- TRADE_ALERT = 'TRADE_ALERT',
13
+
14
+ export enum NotificationRecordStatus {
15
+ PENDING = 'PENDING',
16
+ SENT = 'SENT',
17
+ FAILED = 'FAILED',
14
18
  }
15
19
 
16
- export const notificationIdSchema = z.string().refine(
20
+ export const notificationChannelIdSchema = z.string().refine(
17
21
  (value) => {
18
22
  try {
19
23
  const tid = TypeID.fromString(value);
20
- return tid.getType() === 'notification';
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 "notification" prefix.',
31
+ 'Invalid notification channel ID format. Must be a valid TypeID with "notification_channel" prefix.',
28
32
  },
29
33
  );
30
34
 
31
- export const SendNotificationZod = z.object({
32
- message: z.string(),
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
- buttonText: z.string(),
35
- link: z.string(),
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 SendNotificationZod = z.infer<typeof SendNotificationZod>;
116
+ export type EmailNotificationPayload = z.infer<
117
+ typeof EmailNotificationPayloadSchema
118
+ >;
43
119
 
44
- const SlackSettingsSchema = z.object({
45
- channelName: z.string().min(1).max(50),
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 PostNotificationZod = z.object({
50
- accountId: accountIdSchema,
51
- notificationChannel: z.literal(NotificationChannel.SLACK), // Only Slack for now
52
- notificationType: z.nativeEnum(NotificationType),
53
- enabled: z.boolean().default(true),
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 type PostNotificationZod = z.infer<typeof PostNotificationZod>;
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>;