@dalmore/api-contracts 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -39
- package/common/helpers/index.ts +59 -0
- package/{src/common → common}/types/account-contact.types.ts +2 -1
- package/{src/common → common}/types/account-manager.types.ts +3 -7
- package/common/types/account-setting.types.ts +65 -0
- package/{src/common → common}/types/account.types.ts +1 -0
- package/{src/common → common}/types/activity.types.ts +1 -1
- package/{src/common → common}/types/api-key-logs.types.ts +1 -1
- package/{src/common → common}/types/asset.types.ts +14 -14
- package/{src/common → common}/types/auth.types.ts +7 -18
- package/{src/common → common}/types/bonus-tier.types.ts +33 -0
- package/{src/common → common}/types/cart.types.ts +4 -1
- package/{src/common → common}/types/common.types.ts +39 -7
- package/{src/common → common}/types/contact-us.types.ts +6 -2
- package/{src/common → common}/types/covered-person.types.ts +2 -1
- package/{src/common → common}/types/dashboard.types.ts +2 -9
- package/{src/common → common}/types/data-record.types.ts +1 -1
- package/{src/common → common}/types/disbursements.types.ts +119 -3
- package/{src/common → common}/types/escrow-account.types.ts +3 -3
- package/{src/common → common}/types/file.types.ts +20 -4
- package/common/types/i-will-do-it-later.types.ts +68 -0
- package/{src/common → common}/types/index.ts +2 -0
- package/{src/common → common}/types/individuals.types.ts +5 -17
- package/{src/common → common}/types/investor-account.types.ts +2 -1
- package/{src/common → common}/types/invite.types.ts +27 -1
- package/{src/common → common}/types/issuer-offering.types.ts +113 -30
- package/{src/common → common}/types/issuer-payment-method.types.ts +41 -0
- package/{src/common → common}/types/issuer.types.ts +9 -0
- package/{src/common → common}/types/legal-entity.types.ts +3 -2
- package/{src/common → common}/types/note.types.ts +1 -1
- package/common/types/notification.types.ts +544 -0
- package/{src/common → common}/types/offering.types.ts +106 -20
- package/{src/common → common}/types/page.types.ts +1 -1
- package/{src/common → common}/types/phone.type.ts +1 -1
- package/{src/common → common}/types/site-settings.types.ts +2 -1
- package/{src/common → common}/types/site.types.ts +2 -9
- package/{src/common/types/trade-line-item.type.ts → common/types/trade-line-item.types.ts} +2 -9
- package/{src/common → common}/types/trade.types.ts +137 -4
- package/{src/common → common}/types/transaction.types.ts +12 -1
- package/{src/common → common}/types/trusted-contact.types.ts +7 -7
- package/{src/common → common}/types/user.types.ts +17 -33
- package/{src/common → common}/types/zip.type.ts +1 -1
- package/contracts/clients/cart/index.ts +80 -0
- package/{src/contracts → contracts}/clients/index.ts +10 -0
- package/contracts/clients/issuer-payment-methods/index.ts +39 -0
- package/contracts/clients/payment-methods/index.ts +85 -0
- package/contracts/clients/trade-line-items/index.ts +66 -0
- package/{src/contracts → contracts}/clients/trades/index.ts +65 -1
- package/contracts/clients/transactions/index.ts +37 -0
- package/index.ts +10 -0
- package/package.json +32 -11
- package/index.mjs +0 -10970
- package/src/common/types/address.spec.ts +0 -203
- package/src/common/types/common.types.spec.ts +0 -336
- package/src/common/types/contract-helpers.ts +0 -205
- package/src/common/types/files.types.spec.ts +0 -154
- package/src/common/types/issuer-payment-method.types.spec.ts +0 -612
- package/src/common/types/notification.types.ts +0 -58
- package/src/common/types/offering.types.spec.ts +0 -91
- package/src/common/types/phone.spec.ts +0 -76
- package/src/common/types/site-link.types.spec.ts +0 -134
- /package/{src/common → common}/types/account-detail.types.ts +0 -0
- /package/{src/common → common}/types/account-integration.types.ts +0 -0
- /package/{src/common → common}/types/address.types.ts +0 -0
- /package/{src/common → common}/types/aic.types.ts +0 -0
- /package/{src/common → common}/types/aml.types.ts +0 -0
- /package/{src/common → common}/types/api-keys.types.ts +0 -0
- /package/{src/common → common}/types/batch-jobs.types.ts +0 -0
- /package/{src/common → common}/types/checklist-items.types.ts +0 -0
- /package/{src/common → common}/types/checklist.types.ts +0 -0
- /package/{src/common → common}/types/comply-advantage-api.types.ts +0 -0
- /package/{src/common → common}/types/comply-advantage.types.ts +0 -0
- /package/{src/common → common}/types/countries.types.ts +0 -0
- /package/{src/common → common}/types/data-room.types.ts +0 -0
- /package/{src/common → common}/types/default-theme-config.types.ts +0 -0
- /package/{src/common → common}/types/disbursement-adjustment.types.ts +0 -0
- /package/{src/common → common}/types/disbursement-approval-user.types.ts +0 -0
- /package/{src/common → common}/types/disbursement-review.types.ts +0 -0
- /package/{src/common → common}/types/disbursement-transaction.types.ts +0 -0
- /package/{src/common → common}/types/domain-filter.types.ts +0 -0
- /package/{src/common → common}/types/email-theme.types.ts +0 -0
- /package/{src/common → common}/types/entity.types.ts +0 -0
- /package/{src/common → common}/types/error-responses.types.ts +0 -0
- /package/{src/common → common}/types/exchange-api-key.types.ts +0 -0
- /package/{src/common → common}/types/exchange-import.types.ts +0 -0
- /package/{src/common → common}/types/exchange-provider.types.ts +0 -0
- /package/{src/common → common}/types/health.types.ts +0 -0
- /package/{src/common → common}/types/investorAccountIdSchema.type.ts +0 -0
- /package/{src/common → common}/types/investors-offering.types.ts +0 -0
- /package/{src/common → common}/types/issuer-bank-account.types.ts +0 -0
- /package/{src/common → common}/types/job-item.types.ts +0 -0
- /package/{src/common → common}/types/jobs.types.ts +0 -0
- /package/{src/common → common}/types/kyb.types.ts +0 -0
- /package/{src/common → common}/types/kyc.types.ts +0 -0
- /package/{src/common → common}/types/login-history.types.ts +0 -0
- /package/{src/common → common}/types/mail-template.types.ts +0 -0
- /package/{src/common → common}/types/north-cap-integration.types.ts +0 -0
- /package/{src/common → common}/types/notion-api.types.ts +0 -0
- /package/{src/common → common}/types/notion-database.types.ts +0 -0
- /package/{src/common → common}/types/notion-page.types.ts +0 -0
- /package/{src/common → common}/types/offering-reports.types.ts +0 -0
- /package/{src/common → common}/types/offering-submission.types.ts +0 -0
- /package/{src/common → common}/types/page-revision.types.ts +0 -0
- /package/{src/common → common}/types/password.type.ts +0 -0
- /package/{src/common → common}/types/payment-methods.types.ts +0 -0
- /package/{src/common → common}/types/portfolio.types.ts +0 -0
- /package/{src/common → common}/types/privacy-policy-and-tos.types.ts +0 -0
- /package/{src/common → common}/types/queue.types.ts +0 -0
- /package/{src/common → common}/types/registered-reps.types.ts +0 -0
- /package/{src/common → common}/types/rejection-reasons.types.ts +0 -0
- /package/{src/common → common}/types/reminder-config.types.ts +0 -0
- /package/{src/common → common}/types/review.types.ts +0 -0
- /package/{src/common → common}/types/role.types.ts +0 -0
- /package/{src/common → common}/types/secondary-customer.types.ts +0 -0
- /package/{src/common → common}/types/secondary-issuer.types.ts +0 -0
- /package/{src/common → common}/types/secondary-order.types.ts +0 -0
- /package/{src/common → common}/types/secondary-security.types.ts +0 -0
- /package/{src/common → common}/types/secondary-trade.entity.ts +0 -0
- /package/{src/common → common}/types/secondary-trade.types.ts +0 -0
- /package/{src/common → common}/types/secure-request.types.ts +0 -0
- /package/{src/common → common}/types/signer.types.ts +0 -0
- /package/{src/common → common}/types/site-link.types.ts +0 -0
- /package/{src/common → common}/types/sms.types.ts +0 -0
- /package/{src/common → common}/types/state-machine.types.ts +0 -0
- /package/{src/common → common}/types/states.types.ts +0 -0
- /package/{src/common → common}/types/subdoc-preview.types.ts +0 -0
- /package/{src/common → common}/types/task.types.ts +0 -0
- /package/{src/common → common}/types/trade-adjustment.type.ts +0 -0
- /package/{src/common → common}/types/typography.types.ts +0 -0
- /package/{src/common → common}/types/user-manual.types.ts +0 -0
- /package/{src/common → common}/types/user-setting.types.ts +0 -0
- /package/{src/common → common}/types/webhook.types.ts +0 -0
- /package/{src/contracts → contracts}/clients/accounts/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/aic/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/api-key-logs/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/api-keys/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/assets/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/auth/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/files/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/files-public/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/individuals/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/investor-accounts/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/issuers/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/legal-entities/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/offerings/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/secure-requests/index.ts +0 -0
- /package/{src/contracts → contracts}/clients/sites/index.ts +0 -0
|
@@ -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 }),
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { IBaseEntity } from './entity.types';
|
|
3
3
|
import {
|
|
4
4
|
dateSchema,
|
|
5
|
+
EmailSchema,
|
|
5
6
|
IPaginationMeta,
|
|
6
7
|
KYBStatus,
|
|
7
8
|
SanctionsStatus,
|
|
@@ -138,7 +139,7 @@ export const PostLegalEntitySchema = z
|
|
|
138
139
|
investorAccountId: investorAccountIdSchema,
|
|
139
140
|
name: CompanyNameSchema,
|
|
140
141
|
ein: EINSchema,
|
|
141
|
-
email:
|
|
142
|
+
email: EmailSchema.optional(),
|
|
142
143
|
companyType: CompanyTypeSchema.optional(),
|
|
143
144
|
phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
|
|
144
145
|
dateOfIncorporation: z.lazy(() => dateSchema).optional(),
|
|
@@ -153,7 +154,7 @@ export const UpdateLegalEntitySchema = z
|
|
|
153
154
|
id: legalEntityIdSchema.optional(),
|
|
154
155
|
name: CompanyNameSchema.optional(),
|
|
155
156
|
ein: EINSchema,
|
|
156
|
-
email:
|
|
157
|
+
email: EmailSchema.optional(),
|
|
157
158
|
companyType: CompanyTypeSchema.optional(),
|
|
158
159
|
phone: PhoneZodSchema.openapi({ example: '+12124567890' }).optional(),
|
|
159
160
|
dateOfIncorporation: z.lazy(() => dateSchema).optional(),
|
|
@@ -79,7 +79,7 @@ export const PostNoteBody = z.object({
|
|
|
79
79
|
export type PostNoteBody = z.infer<typeof PostNoteBody>;
|
|
80
80
|
|
|
81
81
|
export const CompliancePostNoteBody = PostNoteBody.extend({
|
|
82
|
-
accountId: accountIdSchema,
|
|
82
|
+
accountId: accountIdSchema.nullable().default(null),
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
export type CompliancePostNoteBody = z.infer<typeof CompliancePostNoteBody>;
|
|
@@ -0,0 +1,544 @@
|
|
|
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, StringToBooleanSchema } from './common.types';
|
|
6
|
+
import {
|
|
7
|
+
ActivityTypeAction,
|
|
8
|
+
ActivityTypeCategory,
|
|
9
|
+
ActivityTypeResource,
|
|
10
|
+
} from './activity.types';
|
|
11
|
+
|
|
12
|
+
extendZodWithOpenApi(z);
|
|
13
|
+
|
|
14
|
+
export enum NotificationChannelType {
|
|
15
|
+
EMAIL = 'EMAIL',
|
|
16
|
+
SLACK = 'SLACK',
|
|
17
|
+
WEBHOOK = 'WEBHOOK',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export enum NotificationRecordStatus {
|
|
21
|
+
PENDING = 'PENDING',
|
|
22
|
+
SENT = 'SENT',
|
|
23
|
+
FAILED = 'FAILED',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type TriggerExclusion = {
|
|
27
|
+
category?: ActivityTypeCategory;
|
|
28
|
+
resource?: ActivityTypeResource;
|
|
29
|
+
action?: ActivityTypeAction;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Excluded notifications
|
|
33
|
+
export const EXCLUDED_NOTIFICATION_TRIGGERS: TriggerExclusion[] = [
|
|
34
|
+
// { action: ActivityTypeAction.RE_SIGN },
|
|
35
|
+
// { action: ActivityTypeAction.RESET_2FA },
|
|
36
|
+
// { action: ActivityTypeAction.LOGIN },
|
|
37
|
+
// { action: ActivityTypeAction.RESET_PASSWORD },
|
|
38
|
+
// { action: ActivityTypeAction.TWO_FACTOR_LOGIN },
|
|
39
|
+
// { action: ActivityTypeAction.FORGOT_PASSWORD },
|
|
40
|
+
// { resource: ActivityTypeResource.USERS },
|
|
41
|
+
// { resource: ActivityTypeResource.THEME_SETTINGS },
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
export const ISSUER_ALLOWED_CATEGORIES: ActivityTypeCategory[] = [
|
|
45
|
+
ActivityTypeCategory.ISSUER,
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks if an activity type should be excluded from notifications.
|
|
50
|
+
*
|
|
51
|
+
* Each exclusion pattern can specify any combination of category, resource, and action.
|
|
52
|
+
* Omitted fields act as wildcards (match any value).
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // Excludes ALL activities with action RE_SIGN (any category, any resource)
|
|
56
|
+
* { action: ActivityTypeAction.RE_SIGN }
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* // Excludes ALL USERS activities (any category, any action)
|
|
60
|
+
* { resource: ActivityTypeResource.USERS }
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* // Excludes only COMPLIANCE + TRADES + CREATE (all three must match)
|
|
64
|
+
* { category: ActivityTypeCategory.COMPLIANCE, resource: ActivityTypeResource.TRADES, action: ActivityTypeAction.CREATE }
|
|
65
|
+
*
|
|
66
|
+
* @param category - The activity type category to check
|
|
67
|
+
* @param resource - The activity type resource to check
|
|
68
|
+
* @param action - The activity type action to check
|
|
69
|
+
* @param exclusions - Array of exclusion patterns (defaults to EXCLUDED_NOTIFICATION_TRIGGERS)
|
|
70
|
+
* @returns true if the activity type matches any exclusion pattern
|
|
71
|
+
*/
|
|
72
|
+
export function isTriggerExcluded(
|
|
73
|
+
category: string,
|
|
74
|
+
resource: string,
|
|
75
|
+
action: string,
|
|
76
|
+
exclusions: TriggerExclusion[] = EXCLUDED_NOTIFICATION_TRIGGERS,
|
|
77
|
+
): boolean {
|
|
78
|
+
return exclusions.some((exclusion) => {
|
|
79
|
+
const categoryMatch =
|
|
80
|
+
!exclusion.category || exclusion.category === category;
|
|
81
|
+
const resourceMatch =
|
|
82
|
+
!exclusion.resource || exclusion.resource === resource;
|
|
83
|
+
const actionMatch = !exclusion.action || exclusion.action === action;
|
|
84
|
+
return categoryMatch && resourceMatch && actionMatch;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Checks if a category is allowed for notification triggers.
|
|
90
|
+
*
|
|
91
|
+
* Used to restrict which activity type categories a user can subscribe to.
|
|
92
|
+
* For example, issuers can only subscribe to ISSUER category triggers.
|
|
93
|
+
*
|
|
94
|
+
* @param category - The activity type category to check
|
|
95
|
+
* @param allowedCategories - Optional array of allowed categories. If empty or undefined, all categories are allowed.
|
|
96
|
+
* @returns true if the category is allowed (or if no restrictions are set)
|
|
97
|
+
*/
|
|
98
|
+
export function isCategoryAllowed(
|
|
99
|
+
category: string,
|
|
100
|
+
allowedCategories?: ActivityTypeCategory[],
|
|
101
|
+
): boolean {
|
|
102
|
+
if (!allowedCategories || allowedCategories.length === 0) {
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return allowedCategories.includes(category as ActivityTypeCategory);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const notificationChannelIdSchema = z.string().refine(
|
|
109
|
+
(value) => {
|
|
110
|
+
try {
|
|
111
|
+
const tid = TypeID.fromString(value);
|
|
112
|
+
return tid.getType() === 'notification_channel';
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
message:
|
|
119
|
+
'Invalid notification channel ID format. Must be a valid TypeID with "notification_channel" prefix.',
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
export const notificationChannelTriggerIdSchema = z.string().refine(
|
|
124
|
+
(value) => {
|
|
125
|
+
try {
|
|
126
|
+
const tid = TypeID.fromString(value);
|
|
127
|
+
return tid.getType() === 'notification_channel_trigger';
|
|
128
|
+
} catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
message:
|
|
134
|
+
'Invalid notification channel trigger ID format. Must be a valid TypeID with "notification_channel_trigger" prefix.',
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
export const notificationRecordIdSchema = z.string().refine(
|
|
139
|
+
(value) => {
|
|
140
|
+
try {
|
|
141
|
+
const tid = TypeID.fromString(value);
|
|
142
|
+
return tid.getType() === 'notification_record';
|
|
143
|
+
} catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
message:
|
|
149
|
+
'Invalid notification record ID format. Must be a valid TypeID with "notification_record" prefix.',
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
export const EmailChannelSettingsSchema = z.object({
|
|
154
|
+
recipients: z
|
|
155
|
+
.array(z.string().email())
|
|
156
|
+
.min(1)
|
|
157
|
+
.max(100, 'At most 100 recipients are allowed'),
|
|
158
|
+
subjectTemplate: z.string().optional(),
|
|
159
|
+
});
|
|
160
|
+
export type EmailChannelSettings = z.infer<typeof EmailChannelSettingsSchema>;
|
|
161
|
+
|
|
162
|
+
export const SlackChannelSettingsSchema = z
|
|
163
|
+
.object({
|
|
164
|
+
webhookUrl: z.string().url().optional(),
|
|
165
|
+
channelEmail: z.string().email().optional(),
|
|
166
|
+
})
|
|
167
|
+
.refine((data) => data.webhookUrl || data.channelEmail, {
|
|
168
|
+
message: 'Either webhookUrl or channelEmail is required',
|
|
169
|
+
});
|
|
170
|
+
export type SlackChannelSettings = z.infer<typeof SlackChannelSettingsSchema>;
|
|
171
|
+
|
|
172
|
+
export const WebhookChannelSettingsSchema = z.object({
|
|
173
|
+
url: z.string().url(),
|
|
174
|
+
method: z.enum(['POST', 'PUT']),
|
|
175
|
+
headers: z.record(z.string()).optional(),
|
|
176
|
+
authType: z.enum(['none', 'bearer', 'basic', 'api_key']).default('none'),
|
|
177
|
+
authValue: z.string().optional(),
|
|
178
|
+
});
|
|
179
|
+
export type WebhookChannelSettings = z.infer<
|
|
180
|
+
typeof WebhookChannelSettingsSchema
|
|
181
|
+
>;
|
|
182
|
+
|
|
183
|
+
export const NotificationChannelSettingsSchema = z.discriminatedUnion('type', [
|
|
184
|
+
z.object({
|
|
185
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
186
|
+
config: EmailChannelSettingsSchema,
|
|
187
|
+
}),
|
|
188
|
+
z.object({
|
|
189
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
190
|
+
config: SlackChannelSettingsSchema,
|
|
191
|
+
}),
|
|
192
|
+
z.object({
|
|
193
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
194
|
+
config: WebhookChannelSettingsSchema,
|
|
195
|
+
}),
|
|
196
|
+
]);
|
|
197
|
+
export type NotificationChannelSettings = z.infer<
|
|
198
|
+
typeof NotificationChannelSettingsSchema
|
|
199
|
+
>;
|
|
200
|
+
|
|
201
|
+
export const EmailNotificationPayloadSchema = z.object({
|
|
202
|
+
to: z.array(z.string().email()),
|
|
203
|
+
subject: z.string(),
|
|
204
|
+
body: z.string(),
|
|
205
|
+
html: z.string().optional(),
|
|
206
|
+
});
|
|
207
|
+
export type EmailNotificationPayload = z.infer<
|
|
208
|
+
typeof EmailNotificationPayloadSchema
|
|
209
|
+
>;
|
|
210
|
+
|
|
211
|
+
export const SlackNotificationPayloadSchema = z.object({
|
|
212
|
+
webhookUrl: z.string().url().optional(),
|
|
213
|
+
channelEmail: z.string().email().optional(),
|
|
214
|
+
message: z.string(),
|
|
215
|
+
blocks: z.array(z.record(z.unknown())).optional(),
|
|
216
|
+
});
|
|
217
|
+
export type SlackNotificationPayload = z.infer<
|
|
218
|
+
typeof SlackNotificationPayloadSchema
|
|
219
|
+
>;
|
|
220
|
+
|
|
221
|
+
export const WebhookNotificationPayloadSchema = z.object({
|
|
222
|
+
url: z.string().url(),
|
|
223
|
+
method: z.enum(['POST', 'PUT']),
|
|
224
|
+
headers: z.record(z.string()),
|
|
225
|
+
body: z.record(z.unknown()),
|
|
226
|
+
});
|
|
227
|
+
export type WebhookNotificationPayload = z.infer<
|
|
228
|
+
typeof WebhookNotificationPayloadSchema
|
|
229
|
+
>;
|
|
230
|
+
|
|
231
|
+
export const NotificationPayloadSchema = z.discriminatedUnion('type', [
|
|
232
|
+
z.object({
|
|
233
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
234
|
+
data: EmailNotificationPayloadSchema,
|
|
235
|
+
}),
|
|
236
|
+
z.object({
|
|
237
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
238
|
+
data: SlackNotificationPayloadSchema,
|
|
239
|
+
}),
|
|
240
|
+
z.object({
|
|
241
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
242
|
+
data: WebhookNotificationPayloadSchema,
|
|
243
|
+
}),
|
|
244
|
+
]);
|
|
245
|
+
export type NotificationPayload = z.infer<typeof NotificationPayloadSchema>;
|
|
246
|
+
|
|
247
|
+
export const EmailNotificationResponseSchema = z.object({
|
|
248
|
+
messageId: z.string().optional(),
|
|
249
|
+
accepted: z.array(z.string()).optional(),
|
|
250
|
+
rejected: z.array(z.string()).optional(),
|
|
251
|
+
});
|
|
252
|
+
export type EmailNotificationResponse = z.infer<
|
|
253
|
+
typeof EmailNotificationResponseSchema
|
|
254
|
+
>;
|
|
255
|
+
|
|
256
|
+
export const SlackNotificationResponseSchema = z.object({
|
|
257
|
+
ok: z.boolean().optional(),
|
|
258
|
+
error: z.string().optional(),
|
|
259
|
+
responseBody: z.string().optional(),
|
|
260
|
+
});
|
|
261
|
+
export type SlackNotificationResponse = z.infer<
|
|
262
|
+
typeof SlackNotificationResponseSchema
|
|
263
|
+
>;
|
|
264
|
+
|
|
265
|
+
export const WebhookNotificationResponseSchema = z.object({
|
|
266
|
+
statusCode: z.number(),
|
|
267
|
+
headers: z.record(z.string()).optional(),
|
|
268
|
+
body: z.unknown().optional(),
|
|
269
|
+
});
|
|
270
|
+
export type WebhookNotificationResponse = z.infer<
|
|
271
|
+
typeof WebhookNotificationResponseSchema
|
|
272
|
+
>;
|
|
273
|
+
|
|
274
|
+
export const NotificationResponseSchema = z.discriminatedUnion('type', [
|
|
275
|
+
z.object({
|
|
276
|
+
type: z.literal(NotificationChannelType.EMAIL),
|
|
277
|
+
data: EmailNotificationResponseSchema,
|
|
278
|
+
}),
|
|
279
|
+
z.object({
|
|
280
|
+
type: z.literal(NotificationChannelType.SLACK),
|
|
281
|
+
data: SlackNotificationResponseSchema,
|
|
282
|
+
}),
|
|
283
|
+
z.object({
|
|
284
|
+
type: z.literal(NotificationChannelType.WEBHOOK),
|
|
285
|
+
data: WebhookNotificationResponseSchema,
|
|
286
|
+
}),
|
|
287
|
+
]);
|
|
288
|
+
export type NotificationResponse = z.infer<typeof NotificationResponseSchema>;
|
|
289
|
+
|
|
290
|
+
export const INotificationChannelZod = IBaseEntity.extend({
|
|
291
|
+
id: notificationChannelIdSchema.openapi({
|
|
292
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
293
|
+
}),
|
|
294
|
+
accountSettingsId: z.string().openapi({
|
|
295
|
+
example: 'account_setting_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
296
|
+
}),
|
|
297
|
+
channelType: z.nativeEnum(NotificationChannelType).openapi({
|
|
298
|
+
example: NotificationChannelType.SLACK,
|
|
299
|
+
}),
|
|
300
|
+
name: z.string().openapi({
|
|
301
|
+
example: 'Compliance Alerts',
|
|
302
|
+
}),
|
|
303
|
+
enabled: z.boolean().openapi({
|
|
304
|
+
example: true,
|
|
305
|
+
}),
|
|
306
|
+
settings: NotificationChannelSettingsSchema.openapi({
|
|
307
|
+
example: {
|
|
308
|
+
type: NotificationChannelType.SLACK,
|
|
309
|
+
config: {
|
|
310
|
+
webhookUrl: 'https://hooks.slack.com/test',
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
}),
|
|
314
|
+
});
|
|
315
|
+
export type INotificationChannelZod = z.infer<typeof INotificationChannelZod>;
|
|
316
|
+
|
|
317
|
+
export const INotificationChannelTriggerZod = IBaseEntity.extend({
|
|
318
|
+
id: notificationChannelTriggerIdSchema.openapi({
|
|
319
|
+
example: 'notification_channel_trigger_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
320
|
+
}),
|
|
321
|
+
notificationChannelId: notificationChannelIdSchema.openapi({
|
|
322
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
323
|
+
}),
|
|
324
|
+
activityTypeId: z.string().openapi({
|
|
325
|
+
example: 'activity_type_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
326
|
+
}),
|
|
327
|
+
enabled: z.boolean().openapi({
|
|
328
|
+
example: true,
|
|
329
|
+
}),
|
|
330
|
+
});
|
|
331
|
+
export type INotificationChannelTriggerZod = z.infer<
|
|
332
|
+
typeof INotificationChannelTriggerZod
|
|
333
|
+
>;
|
|
334
|
+
|
|
335
|
+
export const IAvailableTriggerZod = z.object({
|
|
336
|
+
activityTypeId: z.string().openapi({
|
|
337
|
+
example: 'activity_type_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
338
|
+
}),
|
|
339
|
+
category: z.string().openapi({
|
|
340
|
+
example: 'COMPLIANCE',
|
|
341
|
+
}),
|
|
342
|
+
resource: z.string().openapi({
|
|
343
|
+
example: 'TRADES',
|
|
344
|
+
}),
|
|
345
|
+
action: z.string().openapi({
|
|
346
|
+
example: 'CREATE',
|
|
347
|
+
}),
|
|
348
|
+
enabled: z.boolean().openapi({
|
|
349
|
+
description: 'Whether the trigger is enabled for this activity type',
|
|
350
|
+
example: false,
|
|
351
|
+
}),
|
|
352
|
+
trigger: INotificationChannelTriggerZod.nullable().openapi({
|
|
353
|
+
description: 'The configured trigger, or null if not configured',
|
|
354
|
+
}),
|
|
355
|
+
});
|
|
356
|
+
export type IAvailableTriggerZod = z.infer<typeof IAvailableTriggerZod>;
|
|
357
|
+
|
|
358
|
+
export const IAvailableTriggersResponse = z.object({
|
|
359
|
+
items: z.array(IAvailableTriggerZod),
|
|
360
|
+
});
|
|
361
|
+
export type IAvailableTriggersResponse = z.infer<
|
|
362
|
+
typeof IAvailableTriggersResponse
|
|
363
|
+
>;
|
|
364
|
+
|
|
365
|
+
export const INotificationRecordZod = IBaseEntity.extend({
|
|
366
|
+
id: notificationRecordIdSchema.openapi({
|
|
367
|
+
example: 'notification_record_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
368
|
+
}),
|
|
369
|
+
notificationChannelId: notificationChannelIdSchema.openapi({
|
|
370
|
+
example: 'notification_channel_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
371
|
+
}),
|
|
372
|
+
activityId: z.string().nullable().openapi({
|
|
373
|
+
example: 'activity_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
374
|
+
}),
|
|
375
|
+
targetTable: z.string().openapi({
|
|
376
|
+
example: 'trades',
|
|
377
|
+
}),
|
|
378
|
+
targetId: z.string().openapi({
|
|
379
|
+
example: 'trade_01j5y5ghx8fvc83dmx3pznq7hv',
|
|
380
|
+
}),
|
|
381
|
+
status: z.nativeEnum(NotificationRecordStatus).openapi({
|
|
382
|
+
example: NotificationRecordStatus.SENT,
|
|
383
|
+
}),
|
|
384
|
+
payload: NotificationPayloadSchema,
|
|
385
|
+
response: NotificationResponseSchema.nullable(),
|
|
386
|
+
errorMessage: z.string().nullable().openapi({
|
|
387
|
+
example: null,
|
|
388
|
+
}),
|
|
389
|
+
retryCount: z.number().openapi({
|
|
390
|
+
example: 0,
|
|
391
|
+
}),
|
|
392
|
+
sentAt: z.date().nullable().openapi({
|
|
393
|
+
example: new Date(),
|
|
394
|
+
}),
|
|
395
|
+
});
|
|
396
|
+
export type INotificationRecordZod = z.infer<typeof INotificationRecordZod>;
|
|
397
|
+
|
|
398
|
+
export const CreateChannelInputSchema = z
|
|
399
|
+
.object({
|
|
400
|
+
accountSettingsId: z.string(),
|
|
401
|
+
channelType: z.nativeEnum(NotificationChannelType),
|
|
402
|
+
name: z
|
|
403
|
+
.string()
|
|
404
|
+
.min(1, 'Name is required')
|
|
405
|
+
.max(255, 'Name must be less than 255 characters'),
|
|
406
|
+
enabled: z.boolean().optional(),
|
|
407
|
+
settings: NotificationChannelSettingsSchema,
|
|
408
|
+
})
|
|
409
|
+
.refine((data) => data.channelType === data.settings.type, {
|
|
410
|
+
message: 'Channel type must match settings type',
|
|
411
|
+
path: ['settings', 'type'],
|
|
412
|
+
});
|
|
413
|
+
export type CreateChannelInput = z.infer<typeof CreateChannelInputSchema>;
|
|
414
|
+
|
|
415
|
+
export const IssuerCreateChannelInputSchema = z
|
|
416
|
+
.object({
|
|
417
|
+
channelType: z.nativeEnum(NotificationChannelType),
|
|
418
|
+
name: z
|
|
419
|
+
.string()
|
|
420
|
+
.min(1, 'Name is required')
|
|
421
|
+
.max(255, 'Name must be less than 255 characters'),
|
|
422
|
+
enabled: z.boolean().optional(),
|
|
423
|
+
settings: NotificationChannelSettingsSchema,
|
|
424
|
+
})
|
|
425
|
+
.refine((data) => data.channelType === data.settings.type, {
|
|
426
|
+
message: 'Channel type must match settings type',
|
|
427
|
+
path: ['settings', 'type'],
|
|
428
|
+
});
|
|
429
|
+
export type IssuerCreateChannelInput = z.infer<
|
|
430
|
+
typeof IssuerCreateChannelInputSchema
|
|
431
|
+
>;
|
|
432
|
+
|
|
433
|
+
export const UpdateChannelInputSchema = z.object({
|
|
434
|
+
name: z.string().optional(),
|
|
435
|
+
enabled: z.boolean().optional(),
|
|
436
|
+
settings: NotificationChannelSettingsSchema.optional(),
|
|
437
|
+
});
|
|
438
|
+
export type UpdateChannelInput = z.infer<typeof UpdateChannelInputSchema>;
|
|
439
|
+
|
|
440
|
+
export const CreateTriggerInputSchema = z.object({
|
|
441
|
+
notificationChannelId: notificationChannelIdSchema,
|
|
442
|
+
activityTypeId: z.string(),
|
|
443
|
+
enabled: z.boolean().optional(),
|
|
444
|
+
});
|
|
445
|
+
export type CreateTriggerInput = z.infer<typeof CreateTriggerInputSchema>;
|
|
446
|
+
|
|
447
|
+
export const IPaginatedNotificationChannel = z.object({
|
|
448
|
+
items: z.array(INotificationChannelZod),
|
|
449
|
+
meta: IPaginationMeta,
|
|
450
|
+
});
|
|
451
|
+
export type IPaginatedNotificationChannel = z.infer<
|
|
452
|
+
typeof IPaginatedNotificationChannel
|
|
453
|
+
>;
|
|
454
|
+
|
|
455
|
+
export const IPaginatedNotificationChannelTrigger = z.object({
|
|
456
|
+
items: z.array(INotificationChannelTriggerZod),
|
|
457
|
+
meta: IPaginationMeta,
|
|
458
|
+
});
|
|
459
|
+
export type IPaginatedNotificationChannelTrigger = z.infer<
|
|
460
|
+
typeof IPaginatedNotificationChannelTrigger
|
|
461
|
+
>;
|
|
462
|
+
|
|
463
|
+
export const IPaginatedNotificationRecord = z.object({
|
|
464
|
+
items: z.array(INotificationRecordZod),
|
|
465
|
+
meta: IPaginationMeta,
|
|
466
|
+
});
|
|
467
|
+
export type IPaginatedNotificationRecord = z.infer<
|
|
468
|
+
typeof IPaginatedNotificationRecord
|
|
469
|
+
>;
|
|
470
|
+
|
|
471
|
+
export const NotificationChannelFilters = z.object({
|
|
472
|
+
accountSettingsId: z.string().optional(),
|
|
473
|
+
channelType: z.nativeEnum(NotificationChannelType).optional(),
|
|
474
|
+
enabled: StringToBooleanSchema.optional(),
|
|
475
|
+
});
|
|
476
|
+
export type NotificationChannelFilters = z.infer<
|
|
477
|
+
typeof NotificationChannelFilters
|
|
478
|
+
>;
|
|
479
|
+
|
|
480
|
+
export const NotificationChannelTriggerFilters = z.object({
|
|
481
|
+
notificationChannelId: notificationChannelIdSchema.optional(),
|
|
482
|
+
activityTypeId: z.string().optional(),
|
|
483
|
+
enabled: StringToBooleanSchema.optional(),
|
|
484
|
+
});
|
|
485
|
+
export type NotificationChannelTriggerFilters = z.infer<
|
|
486
|
+
typeof NotificationChannelTriggerFilters
|
|
487
|
+
>;
|
|
488
|
+
|
|
489
|
+
export const NotificationRecordFilters = z.object({
|
|
490
|
+
notificationChannelId: notificationChannelIdSchema.optional(),
|
|
491
|
+
status: z.nativeEnum(NotificationRecordStatus).optional(),
|
|
492
|
+
});
|
|
493
|
+
export type NotificationRecordFilters = z.infer<
|
|
494
|
+
typeof NotificationRecordFilters
|
|
495
|
+
>;
|
|
496
|
+
|
|
497
|
+
export const notificationChannelsInclude = z.enum([
|
|
498
|
+
'triggers',
|
|
499
|
+
'accountSettings',
|
|
500
|
+
'notificationRecords',
|
|
501
|
+
]);
|
|
502
|
+
|
|
503
|
+
export const NotificationChannelsIncludeQuery = z.object({
|
|
504
|
+
include: z
|
|
505
|
+
.string()
|
|
506
|
+
.optional()
|
|
507
|
+
.transform((str) => (str ? str.split(',') : []))
|
|
508
|
+
.refine(
|
|
509
|
+
(includes) =>
|
|
510
|
+
includes.every((include) =>
|
|
511
|
+
notificationChannelsInclude.options.includes(include as any),
|
|
512
|
+
),
|
|
513
|
+
{
|
|
514
|
+
message: `Invalid include value. Valid values are: ${notificationChannelsInclude.options.join(', ')}`,
|
|
515
|
+
},
|
|
516
|
+
),
|
|
517
|
+
});
|
|
518
|
+
export type NotificationChannelsIncludeQuery = z.infer<
|
|
519
|
+
typeof NotificationChannelsIncludeQuery
|
|
520
|
+
>;
|
|
521
|
+
|
|
522
|
+
export const notificationRecordsInclude = z.enum([
|
|
523
|
+
'notificationChannel',
|
|
524
|
+
'activity',
|
|
525
|
+
]);
|
|
526
|
+
|
|
527
|
+
export const NotificationRecordsIncludeQuery = z.object({
|
|
528
|
+
include: z
|
|
529
|
+
.string()
|
|
530
|
+
.optional()
|
|
531
|
+
.transform((str) => (str ? str.split(',') : []))
|
|
532
|
+
.refine(
|
|
533
|
+
(includes) =>
|
|
534
|
+
includes.every((include) =>
|
|
535
|
+
notificationRecordsInclude.options.includes(include as any),
|
|
536
|
+
),
|
|
537
|
+
{
|
|
538
|
+
message: `Invalid include value. Valid values are: ${notificationRecordsInclude.options.join(', ')}`,
|
|
539
|
+
},
|
|
540
|
+
),
|
|
541
|
+
});
|
|
542
|
+
export type NotificationRecordsIncludeQuery = z.infer<
|
|
543
|
+
typeof NotificationRecordsIncludeQuery
|
|
544
|
+
>;
|