clarion-shared-types 1.0.97 → 1.0.99

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 (62) hide show
  1. package/README.md +47 -0
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js +97 -0
  5. package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
  6. package/dist/cjs/modules/alert-intake/index.js +23 -0
  7. package/dist/cjs/modules/alert-intake/index.js.map +1 -0
  8. package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js +3 -0
  9. package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
  10. package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js +48 -0
  11. package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
  12. package/dist/cjs/modules/notification/enums/notification-settings.enums.js +84 -0
  13. package/dist/cjs/modules/notification/enums/notification-settings.enums.js.map +1 -0
  14. package/dist/cjs/modules/notification/enums/sms-provider-name.enum.js +5 -0
  15. package/dist/cjs/modules/notification/enums/sms-provider-name.enum.js.map +1 -1
  16. package/dist/cjs/modules/notification/index.js +5 -0
  17. package/dist/cjs/modules/notification/index.js.map +1 -1
  18. package/dist/cjs/modules/notification/interfaces/organization-notification-settings.dto.js +3 -0
  19. package/dist/cjs/modules/notification/interfaces/organization-notification-settings.dto.js.map +1 -0
  20. package/dist/cjs/modules/notification/utils/notification-sender.util.js +96 -0
  21. package/dist/cjs/modules/notification/utils/notification-sender.util.js.map +1 -0
  22. package/dist/cjs/modules/permission/enums/permission-actions.enum.js +17 -0
  23. package/dist/cjs/modules/permission/enums/permission-actions.enum.js.map +1 -1
  24. package/dist/cjs/modules/permission/enums/permissions-moudule.enum.js +2 -0
  25. package/dist/cjs/modules/permission/enums/permissions-moudule.enum.js.map +1 -1
  26. package/dist/esm/index.js +1 -0
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js +94 -0
  29. package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
  30. package/dist/esm/modules/alert-intake/index.js +7 -0
  31. package/dist/esm/modules/alert-intake/index.js.map +1 -0
  32. package/dist/esm/modules/alert-intake/interfaces/alert-intake.js +2 -0
  33. package/dist/esm/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
  34. package/dist/esm/modules/alert-intake/utils/alert-intake.util.js +42 -0
  35. package/dist/esm/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
  36. package/dist/esm/modules/notification/enums/notification-settings.enums.js +81 -0
  37. package/dist/esm/modules/notification/enums/notification-settings.enums.js.map +1 -0
  38. package/dist/esm/modules/notification/enums/sms-provider-name.enum.js +5 -0
  39. package/dist/esm/modules/notification/enums/sms-provider-name.enum.js.map +1 -1
  40. package/dist/esm/modules/notification/index.js +5 -0
  41. package/dist/esm/modules/notification/index.js.map +1 -1
  42. package/dist/esm/modules/notification/interfaces/organization-notification-settings.dto.js +2 -0
  43. package/dist/esm/modules/notification/interfaces/organization-notification-settings.dto.js.map +1 -0
  44. package/dist/esm/modules/notification/utils/notification-sender.util.js +89 -0
  45. package/dist/esm/modules/notification/utils/notification-sender.util.js.map +1 -0
  46. package/dist/esm/modules/permission/enums/permission-actions.enum.js +17 -0
  47. package/dist/esm/modules/permission/enums/permission-actions.enum.js.map +1 -1
  48. package/dist/esm/modules/permission/enums/permissions-moudule.enum.js +2 -0
  49. package/dist/esm/modules/permission/enums/permissions-moudule.enum.js.map +1 -1
  50. package/dist/types/index.d.ts +1 -0
  51. package/dist/types/modules/alert-intake/enums/alert-intake.enum.d.ts +83 -0
  52. package/dist/types/modules/alert-intake/index.d.ts +3 -0
  53. package/dist/types/modules/alert-intake/interfaces/alert-intake.d.ts +202 -0
  54. package/dist/types/modules/alert-intake/utils/alert-intake.util.d.ts +24 -0
  55. package/dist/types/modules/notification/enums/notification-settings.enums.d.ts +74 -0
  56. package/dist/types/modules/notification/enums/sms-provider-name.enum.d.ts +6 -1
  57. package/dist/types/modules/notification/index.d.ts +3 -0
  58. package/dist/types/modules/notification/interfaces/organization-notification-settings.dto.d.ts +213 -0
  59. package/dist/types/modules/notification/utils/notification-sender.util.d.ts +44 -0
  60. package/dist/types/modules/permission/enums/permission-actions.enum.d.ts +7 -1
  61. package/dist/types/modules/permission/enums/permissions-moudule.enum.d.ts +3 -1
  62. package/package.json +1 -1
@@ -0,0 +1,202 @@
1
+ import { CountryCode } from '../../country/enums/country-code.enum';
2
+ import { AlertIntakeChannel, AlertIntakeEmergencyPolicy, AlertIntakeProvider, AlertIntakeRouteMatch, AlertIntakeSecretSource, AlertIntakeWebhookVerification } from '../enums/alert-intake.enum';
3
+ /**
4
+ * Alert intake settings.
5
+ *
6
+ * `organizationId` is the single source of truth. A CONNECTION is one
7
+ * organization's link to one provider on one channel (its short code, its WhatsApp
8
+ * number, its mailbox). A message that arrives on a connection belongs to the
9
+ * connection's organization, and everything the incident needs - app id, incident
10
+ * class, workflow queue, country - is read from that organization's record in
11
+ * clarion-organization rather than from a table in code.
12
+ *
13
+ * The fallback is a PLATFORM connection (no organization): a shared short code or a
14
+ * shared mailbox whose messages are routed to an organization by keyword, or to a
15
+ * default organization.
16
+ *
17
+ * Owned by clarion-alerts, proxied by the gateway, rendered by the admin. No shape
18
+ * here ever carries a credential: secrets are write-only.
19
+ *
20
+ * MIRRORS grm-shared-library (`modules/alert-intake/interfaces` and `dtos`). The
21
+ * response shapes are interfaces on both sides; the request shapes are class-validator
22
+ * DTOs on the backend and plain interfaces here (see the end of this file).
23
+ */
24
+ export type AlertIntakeFieldType = 'text' | 'number' | 'boolean' | 'select';
25
+ /** One value a provider needs from the operator. */
26
+ export interface AlertIntakeProviderFieldDescriptor {
27
+ key: string;
28
+ label: string;
29
+ type: AlertIntakeFieldType;
30
+ required: boolean;
31
+ /** Secret fields are write-only, and are stored encrypted or as a reference. */
32
+ secret: boolean;
33
+ placeholder?: string;
34
+ description?: string;
35
+ defaultValue?: string | number | boolean;
36
+ options?: Array<{
37
+ value: string;
38
+ label: string;
39
+ }>;
40
+ /** `text` fields only. */
41
+ maxLength?: number;
42
+ /** `number` fields only; inclusive. */
43
+ min?: number;
44
+ max?: number;
45
+ /** Only a platform operator may set this (e.g. switching off TLS verification). */
46
+ operatorOnly?: boolean;
47
+ }
48
+ /**
49
+ * Self-description of an intake provider, published by clarion-alerts. Same idea as
50
+ * the tracking and SMS provider descriptors: the service that owns the adapter is
51
+ * the source of truth for what it needs, so adding a provider changes no client code.
52
+ * Static metadata - never a credential, never anything tenant-specific.
53
+ */
54
+ export interface AlertIntakeProviderDescriptor {
55
+ provider: AlertIntakeProvider;
56
+ channel: AlertIntakeChannel;
57
+ displayName: string;
58
+ description: string;
59
+ /** What identifies the connection to the provider: the number people text, the mailbox. */
60
+ address: {
61
+ label: string;
62
+ placeholder?: string;
63
+ description?: string;
64
+ };
65
+ fields: AlertIntakeProviderFieldDescriptor[];
66
+ /** Null for a provider that is polled rather than called (IMAP). */
67
+ webhook: {
68
+ verification: AlertIntakeWebhookVerification;
69
+ /** Steps the operator performs in the PROVIDER's console, in order. */
70
+ setup: string[];
71
+ } | null;
72
+ /** Whether `POST .../test` does something for this provider. */
73
+ testable: boolean;
74
+ documentationUrl?: string;
75
+ }
76
+ export interface AlertIntakeConnection {
77
+ id: string;
78
+ /** Null = a platform connection, shared between organizations through routes. */
79
+ organizationId: number | null;
80
+ channel: AlertIntakeChannel;
81
+ provider: AlertIntakeProvider;
82
+ name: string;
83
+ /** The short code / number / WhatsApp phone-number id / mailbox messages are sent TO. */
84
+ address: string;
85
+ enabled: boolean;
86
+ /** Non-secret provider settings, as described by the provider's descriptor. */
87
+ config: Record<string, string | number | boolean>;
88
+ secretSource: AlertIntakeSecretSource;
89
+ /** Which secret fields have a value. The values themselves are never returned. */
90
+ secretsConfigured: Record<string, boolean>;
91
+ emergencyPolicy: AlertIntakeEmergencyPolicy;
92
+ /**
93
+ * The URL to paste into the provider's console. Null for a polled provider.
94
+ * It embeds an unguessable key: treat it as a credential.
95
+ */
96
+ webhookUrl: string | null;
97
+ /** When the provider last completed its verification handshake (WhatsApp). */
98
+ webhookVerifiedAt: string | null;
99
+ lastReceivedAt: string | null;
100
+ lastError: string | null;
101
+ lastErrorAt: string | null;
102
+ /** Set on the connections created from the pre-organization, per-tenant setup. */
103
+ legacyKey: string | null;
104
+ createdAt: string;
105
+ updatedAt: string;
106
+ }
107
+ /** Sends the messages of a PLATFORM connection to an organization. */
108
+ export interface AlertIntakeRoute {
109
+ id: string;
110
+ connectionId: string;
111
+ match: AlertIntakeRouteMatch;
112
+ /** Upper-cased. Null for the DEFAULT route. */
113
+ keyword: string | null;
114
+ organizationId: number;
115
+ enabled: boolean;
116
+ createdAt: string;
117
+ }
118
+ /** What the incident will be created with, derived from the organization record. */
119
+ export interface AlertIntakeOrganizationContext {
120
+ organizationId: number;
121
+ name: string;
122
+ appId: string;
123
+ incidentClass: string;
124
+ workflowTaskQueueName: string;
125
+ countryCode: CountryCode;
126
+ /** False when the organization is not ACTIVE: its messages are held, not raised. */
127
+ active: boolean;
128
+ }
129
+ /** What an organization without a connection of its own falls back to, per channel. */
130
+ export interface AlertIntakePlatformFallback {
131
+ channel: AlertIntakeChannel;
132
+ /** The shared address to publish, e.g. the platform short code. */
133
+ address: string;
134
+ provider: AlertIntakeProvider;
135
+ /** The keyword that routes to this organization, when it has one. */
136
+ keyword: string | null;
137
+ /** True when this organization is the connection's DEFAULT route. */
138
+ isDefault: boolean;
139
+ }
140
+ /** Everything the settings page needs, in one read. */
141
+ export interface OrganizationAlertIntakeSettings {
142
+ organizationId: number;
143
+ /** Null when clarion-organization could not be reached or the id is unknown. */
144
+ organization: AlertIntakeOrganizationContext | null;
145
+ connections: AlertIntakeConnection[];
146
+ platformFallbacks: AlertIntakePlatformFallback[];
147
+ /** False when the service has no key to encrypt credentials with: only secret references can be used. */
148
+ encryptedSecretsAvailable: boolean;
149
+ }
150
+ export interface AlertIntakeConnectionTestResult {
151
+ success: boolean;
152
+ /** Operator-facing. Never contains a credential. */
153
+ message: string;
154
+ latencyMs?: number;
155
+ }
156
+ export interface CreateAlertIntakeConnection {
157
+ channel: AlertIntakeChannel;
158
+ provider: AlertIntakeProvider;
159
+ /** 2-100 characters, single line. */
160
+ name: string;
161
+ /** What people send to: the short code or number, the WhatsApp phone-number id, the mailbox address. */
162
+ address: string;
163
+ enabled?: boolean;
164
+ /** Non-secret provider settings, as the provider descriptor declares them. */
165
+ config?: Record<string, string | number | boolean>;
166
+ /** Credentials. WRITE-ONLY: encrypted at rest and never returned. Keys are the descriptor's secret fields. */
167
+ secrets?: Record<string, string>;
168
+ /** Platform operators only. NAMES of provisioned secrets, used instead of `secrets` - never both. */
169
+ secretReferences?: Record<string, string>;
170
+ emergencyPolicy?: AlertIntakeEmergencyPolicy;
171
+ }
172
+ /**
173
+ * Channel and provider cannot change: a connection IS its provider link. `config`
174
+ * is merged over the stored settings and only the `secrets` sent are replaced; a key
175
+ * sent as "" is removed.
176
+ */
177
+ export interface UpdateAlertIntakeConnection {
178
+ name?: string;
179
+ address?: string;
180
+ enabled?: boolean;
181
+ config?: Record<string, string | number | boolean>;
182
+ secrets?: Record<string, string>;
183
+ /** Platform operators only. */
184
+ secretReferences?: Record<string, string>;
185
+ emergencyPolicy?: AlertIntakeEmergencyPolicy;
186
+ }
187
+ /** Platform operators only: sends a PLATFORM connection's messages to an organization. */
188
+ export interface CreateAlertIntakeRoute {
189
+ match: AlertIntakeRouteMatch;
190
+ /** Required for KEYWORD; must be absent for DEFAULT. */
191
+ keyword?: string;
192
+ organizationId: number;
193
+ enabled?: boolean;
194
+ }
195
+ export interface UpdateAlertIntakeRoute {
196
+ organizationId?: number;
197
+ enabled?: boolean;
198
+ }
199
+ /** A platform connection as the operator list returns it: the connection plus its routes. */
200
+ export type AlertIntakePlatformConnection = AlertIntakeConnection & {
201
+ routes: AlertIntakeRoute[];
202
+ };
@@ -0,0 +1,24 @@
1
+ /** A routing keyword: 2-20 letters or digits, stored upper-cased. */
2
+ export declare const ALERT_INTAKE_KEYWORD_PATTERN: RegExp;
3
+ /** Upper bounds that keep one organization's settings a form rather than a list to page through. */
4
+ export declare const MAX_ALERT_INTAKE_CONNECTIONS_PER_ORGANIZATION = 20;
5
+ export declare const MAX_ALERT_INTAKE_ROUTES_PER_CONNECTION = 200;
6
+ /** One settings value (config or secret). An access token is the longest thing that goes here. */
7
+ export declare const MAX_ALERT_INTAKE_SETTING_LENGTH = 4096;
8
+ /** Normalises what an operator typed into the stored form. Null when it is not a valid keyword. */
9
+ export declare function normaliseAlertIntakeKeyword(value: string | null | undefined): string | null;
10
+ /**
11
+ * The routing keyword of a message: its first word, upper-cased, punctuation
12
+ * stripped - `g4s, fire at the gate` and `G4S: fire` both give `G4S`.
13
+ * Null when the first word could not be a keyword.
14
+ *
15
+ * Deliberately only the FIRST word. Matching a keyword anywhere in the text would
16
+ * route "I was robbed near the G4S office" to G4S.
17
+ */
18
+ export declare function extractAlertIntakeKeyword(text: string | null | undefined): string | null;
19
+ /**
20
+ * The message with its routing keyword removed, so "G4S fire at the gate" is
21
+ * analysed as "fire at the gate". Returns the text unchanged when it does not start
22
+ * with that keyword.
23
+ */
24
+ export declare function stripAlertIntakeKeyword(text: string, keyword: string): string;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Organization notification settings enums.
3
+ *
4
+ * MIRRORS grm-shared-library (`modules/notification/enums`), values included. The
5
+ * admin renders and submits these strings and clarion-notification validates the
6
+ * same ones, so any drift is a form the API refuses. `notification-settings.spec.ts`
7
+ * pins the values.
8
+ */
9
+ /** What kind of identity an SMS is sent from. Decides how the value is validated. */
10
+ export declare enum SmsSenderType {
11
+ /** A registered alphanumeric sender name, e.g. `G4S`. At most 11 characters. */
12
+ ALPHANUMERIC = "ALPHANUMERIC",
13
+ /** An E.164 long number, e.g. `+254711000000`. */
14
+ PHONE_NUMBER = "PHONE_NUMBER",
15
+ /** A telco short code, e.g. `22384`. */
16
+ SHORT_CODE = "SHORT_CODE",
17
+ /** A provider-side sender pool (Twilio Messaging Service SID, `MG...`). */
18
+ MESSAGING_SERVICE = "MESSAGING_SERVICE"
19
+ }
20
+ /**
21
+ * Lifecycle of an organization-owned SMS sender. An organization REQUESTS a sender
22
+ * (PENDING) and a platform operator ACTIVATES it once the provider and the telco
23
+ * have registered it. Only ACTIVE senders are ever used to send.
24
+ */
25
+ export declare enum NotificationSenderStatus {
26
+ PENDING = "PENDING",
27
+ ACTIVE = "ACTIVE",
28
+ SUSPENDED = "SUSPENDED",
29
+ REJECTED = "REJECTED"
30
+ }
31
+ /**
32
+ * Whether an email provider will accept mail FROM an organization's address.
33
+ * Tracked per provider: an address can be verified in Twilio SendGrid while its
34
+ * domain is unknown to Mailgun. A provider only sends from an address it has
35
+ * VERIFIED; otherwise it falls back to the platform sender.
36
+ */
37
+ export declare enum EmailSenderVerificationStatus {
38
+ /** The provider does not know this address or its domain. */
39
+ UNVERIFIED = "UNVERIFIED",
40
+ /** Verification was started and is waiting on the owner (inbox click or DNS records). */
41
+ PENDING = "PENDING",
42
+ /** The provider accepts mail from this address. */
43
+ VERIFIED = "VERIFIED",
44
+ /** The last check could not be completed (provider error). */
45
+ FAILED = "FAILED"
46
+ }
47
+ /** How the provider recognises the address. */
48
+ export declare enum EmailSenderVerificationMethod {
49
+ /** The exact address was verified on its own (SendGrid Single Sender Verification). */
50
+ SINGLE_SENDER = "SINGLE_SENDER",
51
+ /** The whole domain is authenticated (SendGrid domain authentication, Mailgun domain). */
52
+ DOMAIN = "DOMAIN"
53
+ }
54
+ /** Whose identity a message actually went out under. */
55
+ export declare enum NotificationSenderSource {
56
+ /** The organization's own verified email address / active SMS sender. */
57
+ ORGANIZATION = "ORGANIZATION",
58
+ /** The platform's default (country-aware) sender. */
59
+ PLATFORM_DEFAULT = "PLATFORM_DEFAULT"
60
+ }
61
+ /**
62
+ * Where one resolved branding value came from. Branding resolves field by field,
63
+ * highest precedence first, so a half-filled profile still produces a complete email.
64
+ */
65
+ export declare enum NotificationBrandingSource {
66
+ /** The organization's notification settings. */
67
+ PROFILE = "PROFILE",
68
+ /** The organization record (clarion-organization). */
69
+ ORGANIZATION = "ORGANIZATION",
70
+ /** The legacy per-app defaults (deprecated). */
71
+ APP_DEFAULT = "APP_DEFAULT",
72
+ /** The platform's own branding. */
73
+ PLATFORM_DEFAULT = "PLATFORM_DEFAULT"
74
+ }
@@ -1,9 +1,14 @@
1
1
  /**
2
2
  * Identifiers for the SMS providers the notification service can dispatch through.
3
3
  * Provider order/fallback is configuration-driven; new providers can be appended.
4
+ *
5
+ * A code here only RESERVES the name. Whether a provider can actually be used is
6
+ * answered by the notification service's provider catalogue
7
+ * (`SmsProviderDescriptor`), which lists only providers with a registered adapter.
4
8
  */
5
9
  export declare enum SmsProviderName {
6
10
  TWILIO = "twilio",
7
11
  UWAZII = "uwazii",
8
- AFRICASTALKING = "africastalking"
12
+ AFRICASTALKING = "africastalking",
13
+ CELCOM = "celcom"
9
14
  }
@@ -3,8 +3,11 @@ export * from './enums/sms-provider-name.enum';
3
3
  export * from './enums/email-provider-name.enum';
4
4
  export * from './enums/notification-overall-status.enum';
5
5
  export * from './enums/provider-failure-reason.enum';
6
+ export * from './enums/notification-settings.enums';
6
7
  export * from './interfaces/provider-attempt';
7
8
  export * from './interfaces/per-channel-result';
8
9
  export * from './interfaces/sms-send-result';
9
10
  export * from './interfaces/email-send-result';
10
11
  export * from './interfaces/notification-dispatch-result';
12
+ export * from './interfaces/organization-notification-settings.dto';
13
+ export * from './utils/notification-sender.util';
@@ -0,0 +1,213 @@
1
+ import { CountryCode } from '../../country/enums/country-code.enum';
2
+ import { IncidentAppId } from '../../incident/enums/incident-app-id.enum';
3
+ import { EmailProviderName } from '../enums/email-provider-name.enum';
4
+ import { EmailSenderVerificationMethod, EmailSenderVerificationStatus, NotificationBrandingSource, NotificationSenderSource, NotificationSenderStatus, SmsSenderType } from '../enums/notification-settings.enums';
5
+ import { SmsProviderName } from '../enums/sms-provider-name.enum';
6
+ /**
7
+ * Organization notification settings: what a customer sees in a notification - the
8
+ * logo and colours of an email, the address it came from, the name an SMS arrives
9
+ * under. `organizationId` is the single key; the legacy `appId` survives only as an
10
+ * alias for events that still carry nothing but an app id.
11
+ *
12
+ * MIRRORS grm-shared-library (`modules/notification/interfaces` and `dtos`). The
13
+ * response shapes are interfaces on both sides; the request shapes are class-validator
14
+ * DTOs on the backend and plain interfaces here. Owned by clarion-notification,
15
+ * proxied by the gateway, rendered by the admin. Nothing here is a secret.
16
+ */
17
+ export interface NotificationSocialLinks {
18
+ facebook?: string | null;
19
+ x?: string | null;
20
+ instagram?: string | null;
21
+ linkedin?: string | null;
22
+ }
23
+ /** The values a notification template can brand itself with. */
24
+ export interface NotificationBrandingFields {
25
+ /** Legal/trading name shown in the footer, e.g. `G4S Kenya Ltd`. */
26
+ companyName: string;
27
+ /** Product name the customer knows, e.g. `G4S Kenya`. Used in subjects and sign-offs. */
28
+ appName: string;
29
+ /** HTTPS URL of the logo. Email clients will not load anything else. */
30
+ logoUrl: string;
31
+ /** `#RRGGBB`. Buttons, links and accents. */
32
+ primaryColour: string;
33
+ /** `#RRGGBB`. Hover/pressed shade; derived from the primary when not chosen. */
34
+ primaryColourDark: string;
35
+ /** `#RRGGBB`. Header banner and footer background. */
36
+ accentColour: string;
37
+ physicalAddress: string;
38
+ phoneNumber: string;
39
+ /** General contact address printed in the footer. Not the address mail is sent FROM. */
40
+ contactEmail: string;
41
+ supportEmail: string;
42
+ websiteUrl: string;
43
+ /** Base URL that links in a notification point at (the organization's web client). */
44
+ clientBaseUrl: string;
45
+ social: NotificationSocialLinks;
46
+ }
47
+ /** What an organization has chosen to override. Every field is optional: gaps are resolved, not rejected. */
48
+ export interface OrganizationNotificationBranding extends Partial<NotificationBrandingFields> {
49
+ organizationId: number;
50
+ /** Legacy alias: an appId-only event resolves to the organization that claims it. */
51
+ appId?: string | null;
52
+ createdAt?: string;
53
+ updatedAt?: string;
54
+ updatedBy?: number | null;
55
+ }
56
+ /** Branding after resolution: complete, and honest about where each value came from. */
57
+ export interface ResolvedNotificationBranding extends NotificationBrandingFields {
58
+ organizationId: number | null;
59
+ sources: Record<keyof NotificationBrandingFields, NotificationBrandingSource>;
60
+ }
61
+ /** One provider's answer to "will you send mail from this address?". */
62
+ export interface EmailSenderProviderVerification {
63
+ provider: EmailProviderName;
64
+ status: EmailSenderVerificationStatus;
65
+ method?: EmailSenderVerificationMethod | null;
66
+ /** Operator-facing explanation, e.g. "Domain ke.g4s.com is not added to Mailgun". */
67
+ detail?: string | null;
68
+ checkedAt?: string | null;
69
+ }
70
+ export interface OrganizationEmailSender {
71
+ id: string;
72
+ organizationId: number;
73
+ /** The address mail is sent FROM, e.g. `notifications@ke.g4s.com`. */
74
+ fromEmail: string;
75
+ /** Display name. Falls back to the resolved company name. */
76
+ fromName?: string | null;
77
+ /** Falls back to `fromEmail`. */
78
+ replyTo?: string | null;
79
+ /** The sender used when a notification does not ask for a specific one. One per organization. */
80
+ isDefault: boolean;
81
+ active: boolean;
82
+ verifications: EmailSenderProviderVerification[];
83
+ /** True when at least one configured provider has VERIFIED the address. */
84
+ usable: boolean;
85
+ createdAt?: string;
86
+ updatedAt?: string;
87
+ }
88
+ export interface OrganizationSmsSender {
89
+ id: string;
90
+ organizationId: number;
91
+ /** The provider account this sender is registered with. */
92
+ provider: SmsProviderName;
93
+ /** The destination country it is registered for. Null = every country the provider serves. */
94
+ countryCode?: CountryCode | null;
95
+ senderType: SmsSenderType;
96
+ senderId: string;
97
+ status: NotificationSenderStatus;
98
+ /** Registration reference, telco ticket, anything the operator needs later. */
99
+ notes?: string | null;
100
+ reviewedBy?: number | null;
101
+ reviewedAt?: string | null;
102
+ createdAt?: string;
103
+ updatedAt?: string;
104
+ }
105
+ /** A sender type a provider accepts, with everything a form needs to collect it. */
106
+ export interface SmsProviderSenderTypeDescriptor {
107
+ type: SmsSenderType;
108
+ label: string;
109
+ placeholder?: string;
110
+ description?: string;
111
+ }
112
+ /**
113
+ * Self-description of an SMS provider, published by clarion-notification. Adding a
114
+ * provider (Celcom, Africa's Talking, ...) changes no client code. Only providers
115
+ * with a registered adapter are described.
116
+ */
117
+ export interface SmsProviderDescriptor {
118
+ provider: SmsProviderName;
119
+ displayName: string;
120
+ description: string;
121
+ /** Countries the adapter can deliver to. */
122
+ supportedCountries: CountryCode[];
123
+ senderTypes: SmsProviderSenderTypeDescriptor[];
124
+ /** Whether the platform's account for this provider is configured and enabled right now. */
125
+ configured: boolean;
126
+ documentationUrl?: string;
127
+ }
128
+ /** The platform senders an organization falls back to. Display-only. */
129
+ export interface PlatformNotificationDefaults {
130
+ email: {
131
+ fromEmail: string | null;
132
+ fromName: string | null;
133
+ };
134
+ /** Per-country default SMS provider chain, e.g. `{ KE: ['twilio', 'uwazii'] }`. */
135
+ smsProviderChains: Partial<Record<CountryCode, SmsProviderName[]>>;
136
+ /** Email providers currently able to send, in order. */
137
+ emailProviders: EmailProviderName[];
138
+ }
139
+ /** Everything the settings page needs, in one read. */
140
+ export interface OrganizationNotificationSettings {
141
+ organizationId: number;
142
+ /** Null until the organization saves a profile. */
143
+ branding: OrganizationNotificationBranding | null;
144
+ effectiveBranding: ResolvedNotificationBranding;
145
+ emailSenders: OrganizationEmailSender[];
146
+ smsSenders: OrganizationSmsSender[];
147
+ platformDefaults: PlatformNotificationDefaults;
148
+ }
149
+ /**
150
+ * Saves an organization's branding. A field sent as null (or "") stops overriding
151
+ * and inherits again; a field left out is untouched.
152
+ */
153
+ export interface UpsertOrganizationNotificationBranding {
154
+ /** Super-admin only. */
155
+ appId?: IncidentAppId | null;
156
+ companyName?: string | null;
157
+ appName?: string | null;
158
+ /** HTTPS only. */
159
+ logoUrl?: string | null;
160
+ primaryColour?: string | null;
161
+ primaryColourDark?: string | null;
162
+ accentColour?: string | null;
163
+ physicalAddress?: string | null;
164
+ phoneNumber?: string | null;
165
+ contactEmail?: string | null;
166
+ supportEmail?: string | null;
167
+ websiteUrl?: string | null;
168
+ clientBaseUrl?: string | null;
169
+ social?: NotificationSocialLinks | null;
170
+ }
171
+ export interface CreateOrganizationEmailSender {
172
+ fromEmail: string;
173
+ fromName?: string | null;
174
+ replyTo?: string | null;
175
+ isDefault?: boolean;
176
+ }
177
+ export interface UpdateOrganizationEmailSender {
178
+ fromName?: string | null;
179
+ replyTo?: string | null;
180
+ isDefault?: boolean;
181
+ active?: boolean;
182
+ }
183
+ export interface CreateOrganizationSmsSender {
184
+ provider: SmsProviderName;
185
+ countryCode?: CountryCode | null;
186
+ senderType: SmsSenderType;
187
+ senderId: string;
188
+ notes?: string | null;
189
+ }
190
+ export interface UpdateOrganizationSmsSender {
191
+ countryCode?: CountryCode | null;
192
+ senderType?: SmsSenderType;
193
+ /** Changing the value sends the sender back to PENDING. */
194
+ senderId?: string;
195
+ notes?: string | null;
196
+ }
197
+ /** Platform operators only. */
198
+ export interface ReviewOrganizationSmsSender {
199
+ status: NotificationSenderStatus;
200
+ notes?: string | null;
201
+ }
202
+ export interface SendTestNotificationEmail {
203
+ to: string;
204
+ }
205
+ /** What the test-email endpoint answers with. */
206
+ export interface TestNotificationEmailResult {
207
+ success: boolean;
208
+ provider: string | null;
209
+ /** The address the email actually went out from. */
210
+ sender: string | null;
211
+ senderSource: NotificationSenderSource | null;
212
+ errorMessage: string | null;
213
+ }
@@ -0,0 +1,44 @@
1
+ import { SmsSenderType } from '../enums/notification-settings.enums';
2
+ /**
3
+ * MIRRORS grm-shared-library (`modules/notification/constants` and `utils`),
4
+ * patterns and thresholds included. The settings form validates with these and
5
+ * clarion-notification validates with the originals, so they must agree to the
6
+ * character: a form that accepts what the API refuses is worse than no check.
7
+ */
8
+ /** `#RRGGBB`. The only colour format accepted, because it is inlined into email CSS. */
9
+ export declare const BRAND_COLOUR_PATTERN: RegExp;
10
+ /**
11
+ * What a sender value must look like, per type. ALPHANUMERIC follows the GSM rule
12
+ * every supported provider enforces: 3-11 characters, at least one letter (an
13
+ * all-digit "name" is a number, and telcos reject it as spoofing).
14
+ */
15
+ export declare const SMS_SENDER_ID_PATTERNS: Readonly<Record<SmsSenderType, RegExp>>;
16
+ /** Human-readable form of {@link SMS_SENDER_ID_PATTERNS}, for validation messages and form hints. */
17
+ export declare const SMS_SENDER_ID_HINTS: Readonly<Record<SmsSenderType, string>>;
18
+ /** Upper bounds that keep one organization from turning its settings into a list to page through. */
19
+ export declare const MAX_EMAIL_SENDERS_PER_ORGANIZATION = 10;
20
+ export declare const MAX_SMS_SENDERS_PER_ORGANIZATION = 30;
21
+ /** Large text and UI components (WCAG 1.4.11): buttons and links in the primary colour. */
22
+ export declare const MIN_PRIMARY_COLOUR_CONTRAST = 3;
23
+ /** Body-size white text sits on the accent colour (WCAG 1.4.3). */
24
+ export declare const MIN_ACCENT_COLOUR_CONTRAST = 4.5;
25
+ /**
26
+ * Validates an SMS sender value against its declared type.
27
+ * Returns null when valid, otherwise a message fit to show an operator.
28
+ */
29
+ export declare function validateSmsSenderId(senderType: SmsSenderType, senderId: string): string | null;
30
+ /** The domain part of an email address, lower-cased. Null when there is none. */
31
+ export declare function emailDomainOf(address: string | null | undefined): string | null;
32
+ /**
33
+ * WCAG contrast ratio of a `#RRGGBB` colour against white, from 1 (white) to 21
34
+ * (black). The email templates put WHITE text on the primary colour (buttons) and
35
+ * on the accent colour (header banner, footer), so a pale brand colour produces
36
+ * an email nobody can read. Returns 0 for anything that is not a hex colour.
37
+ */
38
+ export declare function contrastRatioWithWhite(hex: string): number;
39
+ /**
40
+ * Darkens a `#RRGGBB` colour by a fraction (0-1). Used to derive the hover/pressed
41
+ * shade of a brand colour so an organization only has to choose one.
42
+ * Returns the input unchanged when it is not a valid hex colour.
43
+ */
44
+ export declare function darkenHexColour(hex: string, fraction?: number): string;
@@ -81,5 +81,11 @@ export declare enum PermissionActions {
81
81
  MANAGE_SUPPORT_CONFIGURATION = "manage:support-configuration",
82
82
  READ_SUPPORT_REPORT = "read:support-report",
83
83
  READ_SUPPORT_SYNC = "read:support-sync",
84
- MANAGE_SUPPORT_SYNC = "manage:support-sync"
84
+ MANAGE_SUPPORT_SYNC = "manage:support-sync",
85
+ READ_NOTIFICATION_SETTINGS = "read:notification-settings",
86
+ MANAGE_NOTIFICATION_SETTINGS = "manage:notification-settings",
87
+ APPROVE_NOTIFICATION_SENDER = "approve:notification-sender",
88
+ READ_ALERT_INTAKE = "read:alert-intake",
89
+ MANAGE_ALERT_INTAKE = "manage:alert-intake",
90
+ MANAGE_ALERT_INTAKE_PLATFORM = "manage:alert-intake-platform"
85
91
  }
@@ -8,5 +8,7 @@ export declare enum PermissionsModule {
8
8
  INCIDENT = "Grievance",
9
9
  RESPONSE_UNIT = "Response Unit",
10
10
  TRACKING = "Tracking",
11
- SUPPORT = "Support"
11
+ SUPPORT = "Support",
12
+ NOTIFICATION = "Notification",
13
+ ALERT_INTAKE = "Alert Intake"
12
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarion-shared-types",
3
- "version": "1.0.97",
3
+ "version": "1.0.99",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",