grm-shared-library 1.1.213 → 1.1.215

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 (60) hide show
  1. package/README.md +16 -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/dtos/alert-intake.dto.js +306 -0
  5. package/dist/cjs/modules/alert-intake/dtos/alert-intake.dto.js.map +1 -0
  6. package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js +116 -0
  7. package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
  8. package/dist/cjs/modules/alert-intake/index.js +25 -0
  9. package/dist/cjs/modules/alert-intake/index.js.map +1 -0
  10. package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js +3 -0
  11. package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
  12. package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js +48 -0
  13. package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
  14. package/dist/cjs/modules/notification/dtos/alert-acknowledgement.dto.js +55 -0
  15. package/dist/cjs/modules/notification/dtos/alert-acknowledgement.dto.js.map +1 -0
  16. package/dist/cjs/modules/notification/index.js +2 -0
  17. package/dist/cjs/modules/notification/index.js.map +1 -1
  18. package/dist/cjs/modules/permission/data/permissions.data.js +8 -0
  19. package/dist/cjs/modules/permission/data/permissions.data.js.map +1 -1
  20. package/dist/cjs/modules/permission/enums/permission-actions.enum.js +16 -0
  21. package/dist/cjs/modules/permission/enums/permission-actions.enum.js.map +1 -1
  22. package/dist/cjs/modules/permission/enums/permissions-module.enum.js +1 -0
  23. package/dist/cjs/modules/permission/enums/permissions-module.enum.js.map +1 -1
  24. package/dist/cjs/modules/role/data/roles.data.js +8 -0
  25. package/dist/cjs/modules/role/data/roles.data.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/dtos/alert-intake.dto.js +296 -0
  29. package/dist/esm/modules/alert-intake/dtos/alert-intake.dto.js.map +1 -0
  30. package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js +113 -0
  31. package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
  32. package/dist/esm/modules/alert-intake/index.js +9 -0
  33. package/dist/esm/modules/alert-intake/index.js.map +1 -0
  34. package/dist/esm/modules/alert-intake/interfaces/alert-intake.js +2 -0
  35. package/dist/esm/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
  36. package/dist/esm/modules/alert-intake/utils/alert-intake.util.js +42 -0
  37. package/dist/esm/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
  38. package/dist/esm/modules/notification/dtos/alert-acknowledgement.dto.js +51 -0
  39. package/dist/esm/modules/notification/dtos/alert-acknowledgement.dto.js.map +1 -0
  40. package/dist/esm/modules/notification/index.js +2 -0
  41. package/dist/esm/modules/notification/index.js.map +1 -1
  42. package/dist/esm/modules/permission/data/permissions.data.js +8 -0
  43. package/dist/esm/modules/permission/data/permissions.data.js.map +1 -1
  44. package/dist/esm/modules/permission/enums/permission-actions.enum.js +16 -0
  45. package/dist/esm/modules/permission/enums/permission-actions.enum.js.map +1 -1
  46. package/dist/esm/modules/permission/enums/permissions-module.enum.js +1 -0
  47. package/dist/esm/modules/permission/enums/permissions-module.enum.js.map +1 -1
  48. package/dist/esm/modules/role/data/roles.data.js +8 -0
  49. package/dist/esm/modules/role/data/roles.data.js.map +1 -1
  50. package/dist/types/index.d.ts +1 -0
  51. package/dist/types/modules/alert-intake/dtos/alert-intake.dto.d.ts +55 -0
  52. package/dist/types/modules/alert-intake/enums/alert-intake.enum.d.ts +101 -0
  53. package/dist/types/modules/alert-intake/index.d.ts +4 -0
  54. package/dist/types/modules/alert-intake/interfaces/alert-intake.d.ts +230 -0
  55. package/dist/types/modules/alert-intake/utils/alert-intake.util.d.ts +24 -0
  56. package/dist/types/modules/notification/dtos/alert-acknowledgement.dto.d.ts +17 -0
  57. package/dist/types/modules/notification/index.d.ts +1 -0
  58. package/dist/types/modules/permission/enums/permission-actions.enum.d.ts +4 -1
  59. package/dist/types/modules/permission/enums/permissions-module.enum.d.ts +2 -1
  60. package/package.json +1 -1
@@ -0,0 +1,230 @@
1
+ import { CountryCode } from '../../country/enums/country-code.enum';
2
+ import { AlertIntakeChannel, AlertIntakeEmergencyPolicy, AlertIntakeMessageState, AlertIntakeProvider, AlertIntakeRejectionReason, 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
+ export type AlertIntakeFieldType = 'text' | 'number' | 'boolean' | 'select';
21
+ /** One value a provider needs from the operator. */
22
+ export interface AlertIntakeProviderFieldDescriptor {
23
+ key: string;
24
+ label: string;
25
+ type: AlertIntakeFieldType;
26
+ required: boolean;
27
+ /** Secret fields are write-only, and are stored encrypted or as a reference. */
28
+ secret: boolean;
29
+ placeholder?: string;
30
+ description?: string;
31
+ defaultValue?: string | number | boolean;
32
+ options?: Array<{
33
+ value: string;
34
+ label: string;
35
+ }>;
36
+ /** `text` fields only. */
37
+ maxLength?: number;
38
+ /** `number` fields only; inclusive. */
39
+ min?: number;
40
+ max?: number;
41
+ /** Only a platform operator may set this (e.g. switching off TLS verification). */
42
+ operatorOnly?: boolean;
43
+ }
44
+ /**
45
+ * Self-description of an intake provider, published by clarion-alerts. Same idea as
46
+ * the tracking and SMS provider descriptors: the service that owns the adapter is
47
+ * the source of truth for what it needs, so adding a provider changes no client code.
48
+ * Static metadata - never a credential, never anything tenant-specific.
49
+ */
50
+ export interface AlertIntakeProviderDescriptor {
51
+ provider: AlertIntakeProvider;
52
+ channel: AlertIntakeChannel;
53
+ displayName: string;
54
+ description: string;
55
+ /** What identifies the connection to the provider: the number people text, the mailbox. */
56
+ address: {
57
+ label: string;
58
+ placeholder?: string;
59
+ description?: string;
60
+ };
61
+ fields: AlertIntakeProviderFieldDescriptor[];
62
+ /** Null for a provider that is polled rather than called (IMAP). */
63
+ webhook: {
64
+ verification: AlertIntakeWebhookVerification;
65
+ /** Steps the operator performs in the PROVIDER's console, in order. */
66
+ setup: string[];
67
+ } | null;
68
+ /** Whether `POST .../test` does something for this provider. */
69
+ testable: boolean;
70
+ documentationUrl?: string;
71
+ }
72
+ export interface AlertIntakeConnection {
73
+ id: string;
74
+ /** Null = a platform connection, shared between organizations through routes. */
75
+ organizationId: number | null;
76
+ channel: AlertIntakeChannel;
77
+ provider: AlertIntakeProvider;
78
+ name: string;
79
+ /** The short code / number / WhatsApp phone-number id / mailbox messages are sent TO. */
80
+ address: string;
81
+ enabled: boolean;
82
+ /** Non-secret provider settings, as described by the provider's descriptor. */
83
+ config: Record<string, string | number | boolean>;
84
+ secretSource: AlertIntakeSecretSource;
85
+ /** Which secret fields have a value. The values themselves are never returned. */
86
+ secretsConfigured: Record<string, boolean>;
87
+ emergencyPolicy: AlertIntakeEmergencyPolicy;
88
+ /**
89
+ * The URL to paste into the provider's console. Null for a polled provider.
90
+ * It embeds an unguessable key: treat it as a credential.
91
+ */
92
+ webhookUrl: string | null;
93
+ /** When the provider last completed its verification handshake (WhatsApp). */
94
+ webhookVerifiedAt: string | null;
95
+ lastReceivedAt: string | null;
96
+ lastError: string | null;
97
+ lastErrorAt: string | null;
98
+ /** Set on the connections created from the pre-organization, per-tenant setup. */
99
+ legacyKey: string | null;
100
+ createdAt: string;
101
+ updatedAt: string;
102
+ }
103
+ /** Sends the messages of a PLATFORM connection to an organization. */
104
+ export interface AlertIntakeRoute {
105
+ id: string;
106
+ connectionId: string;
107
+ match: AlertIntakeRouteMatch;
108
+ /** Upper-cased. Null for the DEFAULT route. */
109
+ keyword: string | null;
110
+ organizationId: number;
111
+ enabled: boolean;
112
+ createdAt: string;
113
+ }
114
+ /** What the incident will be created with, derived from the organization record. */
115
+ export interface AlertIntakeOrganizationContext {
116
+ organizationId: number;
117
+ name: string;
118
+ appId: string;
119
+ incidentClass: string;
120
+ workflowTaskQueueName: string;
121
+ countryCode: CountryCode;
122
+ /** False when the organization is not ACTIVE: its messages are held, not raised. */
123
+ active: boolean;
124
+ }
125
+ /** What an organization without a connection of its own falls back to, per channel. */
126
+ export interface AlertIntakePlatformFallback {
127
+ channel: AlertIntakeChannel;
128
+ /** The shared address to publish, e.g. the platform short code. */
129
+ address: string;
130
+ provider: AlertIntakeProvider;
131
+ /** The keyword that routes to this organization, when it has one. */
132
+ keyword: string | null;
133
+ /** True when this organization is the connection's DEFAULT route. */
134
+ isDefault: boolean;
135
+ }
136
+ /** Everything the settings page needs, in one read. */
137
+ export interface OrganizationAlertIntakeSettings {
138
+ organizationId: number;
139
+ /** Null when clarion-organization could not be reached or the id is unknown. */
140
+ organization: AlertIntakeOrganizationContext | null;
141
+ connections: AlertIntakeConnection[];
142
+ platformFallbacks: AlertIntakePlatformFallback[];
143
+ /** False when the service has no key to encrypt credentials with: only secret references can be used. */
144
+ encryptedSecretsAvailable: boolean;
145
+ /** What arrived for this organization recently, and what needs someone's attention. */
146
+ activity?: AlertIntakeActivitySummary;
147
+ }
148
+ /** Counts over the last `windowHours` - except `parked` and `failingConnections`, which are as of now. */
149
+ export interface AlertIntakeActivitySummary {
150
+ windowHours: number;
151
+ received: number;
152
+ raised: number;
153
+ duplicates: number;
154
+ retrying: number;
155
+ /** Waiting for an operator: out of attempts, or held for a reason (no organization, organization inactive). */
156
+ parked: number;
157
+ /** Enabled connections whose last attempt failed (a rejected call, a mailbox that could not be read). */
158
+ failingConnections: number;
159
+ }
160
+ /** What is kept of a file that came with a message. Never its contents. */
161
+ export interface AlertIntakeMessageAttachment {
162
+ fileName: string;
163
+ mimeType: string;
164
+ size: number;
165
+ /** True once the file is stored in DMS and linked to the incident. */
166
+ attached: boolean;
167
+ /** Why it was not attached, when it was not. */
168
+ error: string | null;
169
+ }
170
+ /**
171
+ * A stored message, as an operator sees it in a list. `preview` is the start of the
172
+ * text; the whole of it is only in the detail.
173
+ */
174
+ export interface AlertIntakeMessage {
175
+ id: string;
176
+ /** Null while no organization has been found for it. */
177
+ organizationId: number | null;
178
+ connectionId: string | null;
179
+ connectionName: string | null;
180
+ channel: AlertIntakeChannel;
181
+ /** Phone number, WhatsApp number or email address, as stored. */
182
+ sender: string | null;
183
+ senderName: string | null;
184
+ subject: string | null;
185
+ preview: string;
186
+ /** The keyword that routed it, on a platform connection. */
187
+ routeKeyword: string | null;
188
+ state: AlertIntakeMessageState;
189
+ rejectionReason: AlertIntakeRejectionReason | null;
190
+ /** The last error, for RETRYING and PARKED. */
191
+ error: string | null;
192
+ attempts: number;
193
+ nextAttemptAt: string | null;
194
+ /** The incident it raised. */
195
+ incidentId: number | null;
196
+ attachmentCount: number;
197
+ /** When the sender was told their message was received, if they were. */
198
+ acknowledgedAt: string | null;
199
+ receivedAt: string;
200
+ updatedAt: string;
201
+ /** What the CALLER may do with it now. */
202
+ actions: {
203
+ /** Try again: a PARKED message that ran out of attempts, or whose organization is active again. */
204
+ retry: boolean;
205
+ /** Raise a message that was taken for a duplicate. */
206
+ raiseAnyway: boolean;
207
+ /** Give a message no route claimed to an organization (platform operators). */
208
+ assign: boolean;
209
+ };
210
+ }
211
+ export interface AlertIntakeMessageDetail extends AlertIntakeMessage {
212
+ /** What the incident is raised from (a routing keyword removed). */
213
+ content: string;
214
+ /** Exactly as received. */
215
+ originalContent: string;
216
+ attachments: AlertIntakeMessageAttachment[];
217
+ acknowledgementError: string | null;
218
+ }
219
+ export interface AlertIntakeMessagePage {
220
+ items: AlertIntakeMessage[];
221
+ total: number;
222
+ page: number;
223
+ limit: number;
224
+ }
225
+ export interface AlertIntakeConnectionTestResult {
226
+ success: boolean;
227
+ /** Operator-facing. Never contains a credential. */
228
+ message: string;
229
+ latencyMs?: number;
230
+ }
@@ -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,17 @@
1
+ import { SmsSendResult } from '../interfaces/sms-send-result';
2
+ /**
3
+ * clarion-alerts -> clarion-notification: tell the person who texted an alert that it
4
+ * was received (POST /alert-intake/notifications/sms). Sent under the ORGANIZATION's
5
+ * SMS sender ID, so the reply comes from the organization they reached.
6
+ *
7
+ * One recipient: an acknowledgement answers one message. The caller decides whether
8
+ * one is due (opt-in per connection, throttled per sender); this route only sends.
9
+ */
10
+ export declare class AlertAcknowledgementSmsDto {
11
+ phoneNumber: string;
12
+ message: string;
13
+ organizationId: number;
14
+ reference?: string;
15
+ }
16
+ /** 200 sent · 422 can never be sent (e.g. the number) · 502 not sent, safe to retry · 503 no provider. */
17
+ export type AlertAcknowledgementSmsResult = SmsSendResult;
@@ -22,3 +22,4 @@ export * from './utils/notification-sender.util';
22
22
  export * from './enums/billing-notification.enum';
23
23
  export * from './dtos/billing-notification.dto';
24
24
  export * from './interfaces/billing-notification-result';
25
+ export * from './dtos/alert-acknowledgement.dto';
@@ -149,5 +149,8 @@ export declare enum PermissionActions {
149
149
  DELETE_NEWSFEED_POST = "delete:newsfeed-post",
150
150
  READ_NOTIFICATION_SETTINGS = "read:notification-settings",
151
151
  MANAGE_NOTIFICATION_SETTINGS = "manage:notification-settings",
152
- APPROVE_NOTIFICATION_SENDER = "approve:notification-sender"
152
+ APPROVE_NOTIFICATION_SENDER = "approve:notification-sender",
153
+ READ_ALERT_INTAKE = "read:alert-intake",
154
+ MANAGE_ALERT_INTAKE = "manage:alert-intake",
155
+ MANAGE_ALERT_INTAKE_PLATFORM = "manage:alert-intake-platform"
153
156
  }
@@ -11,5 +11,6 @@ export declare enum PermissionsModule {
11
11
  BILLING = "Billing",
12
12
  NEWSFEED = "Newsfeed",
13
13
  SUPPORT = "Support",
14
- NOTIFICATION = "Notification"
14
+ NOTIFICATION = "Notification",
15
+ ALERT_INTAKE = "Alert Intake"
15
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grm-shared-library",
3
- "version": "1.1.213",
3
+ "version": "1.1.215",
4
4
  "main": "dist/cjs/index.js",
5
5
  "module": "dist/esm/index.js",
6
6
  "types": "dist/types/index.d.ts",