clarion-shared-types 1.0.98 → 1.0.100
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 +47 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js +116 -0
- package/dist/cjs/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
- package/dist/cjs/modules/alert-intake/index.js +23 -0
- package/dist/cjs/modules/alert-intake/index.js.map +1 -0
- package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js +3 -0
- package/dist/cjs/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
- package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js +48 -0
- package/dist/cjs/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
- package/dist/cjs/modules/permission/enums/permission-actions.enum.js +8 -0
- package/dist/cjs/modules/permission/enums/permission-actions.enum.js.map +1 -1
- package/dist/cjs/modules/permission/enums/permissions-moudule.enum.js +1 -0
- package/dist/cjs/modules/permission/enums/permissions-moudule.enum.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js +113 -0
- package/dist/esm/modules/alert-intake/enums/alert-intake.enum.js.map +1 -0
- package/dist/esm/modules/alert-intake/index.js +7 -0
- package/dist/esm/modules/alert-intake/index.js.map +1 -0
- package/dist/esm/modules/alert-intake/interfaces/alert-intake.js +2 -0
- package/dist/esm/modules/alert-intake/interfaces/alert-intake.js.map +1 -0
- package/dist/esm/modules/alert-intake/utils/alert-intake.util.js +42 -0
- package/dist/esm/modules/alert-intake/utils/alert-intake.util.js.map +1 -0
- package/dist/esm/modules/permission/enums/permission-actions.enum.js +8 -0
- package/dist/esm/modules/permission/enums/permission-actions.enum.js.map +1 -1
- package/dist/esm/modules/permission/enums/permissions-moudule.enum.js +1 -0
- package/dist/esm/modules/permission/enums/permissions-moudule.enum.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/modules/alert-intake/enums/alert-intake.enum.d.ts +101 -0
- package/dist/types/modules/alert-intake/index.d.ts +3 -0
- package/dist/types/modules/alert-intake/interfaces/alert-intake.d.ts +300 -0
- package/dist/types/modules/alert-intake/utils/alert-intake.util.d.ts +24 -0
- package/dist/types/modules/permission/enums/permission-actions.enum.d.ts +4 -1
- package/dist/types/modules/permission/enums/permissions-moudule.enum.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,3 +70,50 @@ detection are delivered in later phases and should build on these types.
|
|
|
70
70
|
```bash
|
|
71
71
|
npm test # compiles src/modules/country and runs the country/currency suite
|
|
72
72
|
```
|
|
73
|
+
|
|
74
|
+
## Organization notification settings
|
|
75
|
+
|
|
76
|
+
`src/modules/notification` mirrors the backend contract for an organization's
|
|
77
|
+
notification settings (branding, email senders, SMS senders) that clarion-admin's
|
|
78
|
+
**Notification Settings** page renders. The backend source of truth is
|
|
79
|
+
`grm-shared-library/src/modules/notification`; clarion-notification owns the data.
|
|
80
|
+
|
|
81
|
+
- Enums: `SmsSenderType`, `NotificationSenderStatus`, `EmailSenderVerificationStatus` /
|
|
82
|
+
`Method`, `NotificationSenderSource`, `NotificationBrandingSource`.
|
|
83
|
+
- Shapes: `OrganizationNotificationSettings`, `ResolvedNotificationBranding` (with the
|
|
84
|
+
per-field `sources` the page uses to say "inherited from…"), `OrganizationEmailSender`,
|
|
85
|
+
`OrganizationSmsSender`, `SmsProviderDescriptor`, and plain request interfaces in
|
|
86
|
+
place of the backend's class-validator DTOs.
|
|
87
|
+
- Rules: `validateSmsSenderId`, `SMS_SENDER_ID_PATTERNS` / `_HINTS`,
|
|
88
|
+
`BRAND_COLOUR_PATTERN`, `contrastRatioWithWhite` with `MIN_PRIMARY_COLOUR_CONTRAST`
|
|
89
|
+
and `MIN_ACCENT_COLOUR_CONTRAST`.
|
|
90
|
+
|
|
91
|
+
**The rules must stay byte-identical to the backend's.** The form validates with
|
|
92
|
+
these so the user is told before they submit; the API validates with its own copy and
|
|
93
|
+
is the one that counts. `notification-settings.spec.ts` pins the regex sources and
|
|
94
|
+
thresholds so a drift fails here rather than as a form that accepts what the API
|
|
95
|
+
rejects.
|
|
96
|
+
|
|
97
|
+
## Alert intake (SMS / WhatsApp / email channels)
|
|
98
|
+
|
|
99
|
+
`src/modules/alert-intake` mirrors the backend contract for how the public reaches an
|
|
100
|
+
organization without the app, which clarion-admin's **Alert Channels** page renders.
|
|
101
|
+
The backend source of truth is `grm-shared-library/src/modules/alert-intake`;
|
|
102
|
+
clarion-alerts owns the data.
|
|
103
|
+
|
|
104
|
+
- Enums: `AlertIntakeChannel`, `AlertIntakeProvider`, `AlertIntakeSecretSource`,
|
|
105
|
+
`AlertIntakeEmergencyPolicy`, `AlertIntakeRouteMatch`, `AlertIntakeWebhookVerification`,
|
|
106
|
+
`AlertIntakeRejectionReason`.
|
|
107
|
+
- Shapes: `OrganizationAlertIntakeSettings`, `AlertIntakeConnection` (never carries a
|
|
108
|
+
credential - `secretsConfigured` says which secrets exist), `AlertIntakeRoute`,
|
|
109
|
+
`AlertIntakePlatformFallback`, `AlertIntakeProviderDescriptor` (the server-driven
|
|
110
|
+
form), `AlertIntakePlatformConnection`, and plain request interfaces
|
|
111
|
+
(`CreateAlertIntakeConnection`, `UpdateAlertIntakeConnection`, `CreateAlertIntakeRoute`,
|
|
112
|
+
`UpdateAlertIntakeRoute`) in place of the backend's class-validator DTOs.
|
|
113
|
+
- Rules: `ALERT_INTAKE_KEYWORD_PATTERN`, `normaliseAlertIntakeKeyword`,
|
|
114
|
+
`extractAlertIntakeKeyword`, `stripAlertIntakeKeyword` and the `MAX_ALERT_INTAKE_*` limits.
|
|
115
|
+
|
|
116
|
+
The enum file and the util file are byte-identical copies of the backend's;
|
|
117
|
+
`alert-intake.spec.ts` pins the values so a drift fails here rather than as a form the
|
|
118
|
+
API refuses. Permission actions `read:alert-intake`, `manage:alert-intake` and
|
|
119
|
+
`manage:alert-intake-platform` (Super-Admin only) are mirrored in `PermissionActions`.
|
package/dist/cjs/index.js
CHANGED
|
@@ -36,6 +36,7 @@ __exportStar(require("./modules/country/index"), exports);
|
|
|
36
36
|
__exportStar(require("./modules/tracking/index"), exports);
|
|
37
37
|
__exportStar(require("./modules/entitlement/index"), exports);
|
|
38
38
|
__exportStar(require("./modules/alert-dispatch/index"), exports);
|
|
39
|
+
__exportStar(require("./modules/alert-intake/index"), exports);
|
|
39
40
|
__exportStar(require("./modules/partner/index"), exports);
|
|
40
41
|
__exportStar(require("./modules/support/index"), exports);
|
|
41
42
|
// Interfaces
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,UAAU;AACV,uDAAqC;AACrC,+DAA6C;AAC7C,yDAAuC;AACvC,6DAA2C;AAC3C,uDAAqC;AACrC,uDAAqC;AACrC,iEAA+C;AAC/C,gEAA8C;AAC9C,2DAAyC;AACzC,2DAAyC;AACzC,sDAAoC;AACpC,sDAAoC;AACpC,sDAAoC;AACpC,yDAAuC;AACvC,mEAAiD;AACjD,+DAA6C;AAC7C,uDAAqC;AACrC,0DAAwC;AACxC,2DAAyC;AACzC,8DAA4C;AAC5C,iEAA+C;AAC/C,0DAAwC;AACxC,0DAAwC;AAExC,aAAa;AACb,6EAA2D;AAC3D,yEAAuD"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,UAAU;AACV,uDAAqC;AACrC,+DAA6C;AAC7C,yDAAuC;AACvC,6DAA2C;AAC3C,uDAAqC;AACrC,uDAAqC;AACrC,iEAA+C;AAC/C,gEAA8C;AAC9C,2DAAyC;AACzC,2DAAyC;AACzC,sDAAoC;AACpC,sDAAoC;AACpC,sDAAoC;AACpC,yDAAuC;AACvC,mEAAiD;AACjD,+DAA6C;AAC7C,uDAAqC;AACrC,0DAAwC;AACxC,2DAAyC;AACzC,8DAA4C;AAC5C,iEAA+C;AAC/C,+DAA6C;AAC7C,0DAAwC;AACxC,0DAAwC;AAExC,aAAa;AACb,6EAA2D;AAC3D,yEAAuD"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Alert intake: how a member of the public reaches an organization WITHOUT the app -
|
|
4
|
+
* an SMS, a WhatsApp message or an email that clarion-alerts turns into an incident.
|
|
5
|
+
*
|
|
6
|
+
* Not to be confused with `alert-dispatch`, which is about who an SOS raised IN the
|
|
7
|
+
* app is sent to.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AlertIntakeMessageState = exports.AlertIntakeRejectionReason = exports.AlertIntakeWebhookVerification = exports.AlertIntakeRouteMatch = exports.AlertIntakeEmergencyPolicy = exports.AlertIntakeSecretSource = exports.AlertIntakeProvider = exports.AlertIntakeChannel = void 0;
|
|
11
|
+
/** The channel a message arrived on. */
|
|
12
|
+
var AlertIntakeChannel;
|
|
13
|
+
(function (AlertIntakeChannel) {
|
|
14
|
+
AlertIntakeChannel["SMS"] = "SMS";
|
|
15
|
+
AlertIntakeChannel["WHATSAPP"] = "WHATSAPP";
|
|
16
|
+
AlertIntakeChannel["EMAIL"] = "EMAIL";
|
|
17
|
+
})(AlertIntakeChannel || (exports.AlertIntakeChannel = AlertIntakeChannel = {}));
|
|
18
|
+
/**
|
|
19
|
+
* The provider a connection talks to.
|
|
20
|
+
*
|
|
21
|
+
* A code here only RESERVES the name. Whether a provider can be connected is
|
|
22
|
+
* answered by clarion-alerts' provider catalogue (`AlertIntakeProviderDescriptor`),
|
|
23
|
+
* which lists only providers with a registered adapter. UWAZII and CELCOM are
|
|
24
|
+
* reserved without an adapter on purpose: their inbound callback formats have not
|
|
25
|
+
* been confirmed, and until they are, GENERIC_SMS connects them by configuration.
|
|
26
|
+
*/
|
|
27
|
+
var AlertIntakeProvider;
|
|
28
|
+
(function (AlertIntakeProvider) {
|
|
29
|
+
// SMS
|
|
30
|
+
AlertIntakeProvider["AFRICASTALKING"] = "africastalking";
|
|
31
|
+
AlertIntakeProvider["UWAZII"] = "uwazii";
|
|
32
|
+
AlertIntakeProvider["CELCOM"] = "celcom";
|
|
33
|
+
/** Any gateway that POSTs flat JSON or form fields; the field names are configured. */
|
|
34
|
+
AlertIntakeProvider["GENERIC_SMS"] = "generic_sms";
|
|
35
|
+
// WhatsApp
|
|
36
|
+
AlertIntakeProvider["WHATSAPP_CLOUD"] = "whatsapp_cloud";
|
|
37
|
+
// Email
|
|
38
|
+
AlertIntakeProvider["IMAP"] = "imap";
|
|
39
|
+
/** An inbound-parse webhook (Mailgun routes, SendGrid Inbound Parse, or a generic JSON post). */
|
|
40
|
+
AlertIntakeProvider["EMAIL_WEBHOOK"] = "email_webhook";
|
|
41
|
+
})(AlertIntakeProvider || (exports.AlertIntakeProvider = AlertIntakeProvider = {}));
|
|
42
|
+
/**
|
|
43
|
+
* Where a connection's credentials live. Never in a plaintext column.
|
|
44
|
+
*
|
|
45
|
+
* ENCRYPTED entered by the organization, encrypted at rest by clarion-alerts
|
|
46
|
+
* (AES-256-GCM, bound to the connection and the field). Write-only:
|
|
47
|
+
* the API never returns them.
|
|
48
|
+
* SECRET_REFERENCE the NAME of a secret the platform operator provisioned (Secret
|
|
49
|
+
* Manager / environment). How the legacy per-tenant credentials
|
|
50
|
+
* keep working, and the option for an operator who does not want
|
|
51
|
+
* a credential in the database at all.
|
|
52
|
+
*/
|
|
53
|
+
var AlertIntakeSecretSource;
|
|
54
|
+
(function (AlertIntakeSecretSource) {
|
|
55
|
+
AlertIntakeSecretSource["ENCRYPTED"] = "ENCRYPTED";
|
|
56
|
+
AlertIntakeSecretSource["SECRET_REFERENCE"] = "SECRET_REFERENCE";
|
|
57
|
+
})(AlertIntakeSecretSource || (exports.AlertIntakeSecretSource = AlertIntakeSecretSource = {}));
|
|
58
|
+
/**
|
|
59
|
+
* How the emergency type of an incident raised from a message is decided.
|
|
60
|
+
* AUTO derives it from the organization: a grievance desk never raises an
|
|
61
|
+
* emergency; an incident desk decides from the message's category and priority.
|
|
62
|
+
*/
|
|
63
|
+
var AlertIntakeEmergencyPolicy;
|
|
64
|
+
(function (AlertIntakeEmergencyPolicy) {
|
|
65
|
+
AlertIntakeEmergencyPolicy["AUTO"] = "AUTO";
|
|
66
|
+
AlertIntakeEmergencyPolicy["ALWAYS_EMERGENCY"] = "ALWAYS_EMERGENCY";
|
|
67
|
+
AlertIntakeEmergencyPolicy["ALWAYS_NON_EMERGENCY"] = "ALWAYS_NON_EMERGENCY";
|
|
68
|
+
})(AlertIntakeEmergencyPolicy || (exports.AlertIntakeEmergencyPolicy = AlertIntakeEmergencyPolicy = {}));
|
|
69
|
+
/** How a message on a PLATFORM connection finds its organization. */
|
|
70
|
+
var AlertIntakeRouteMatch;
|
|
71
|
+
(function (AlertIntakeRouteMatch) {
|
|
72
|
+
/** The first word of the message, e.g. `G4S fire at ...` on a shared short code. */
|
|
73
|
+
AlertIntakeRouteMatch["KEYWORD"] = "KEYWORD";
|
|
74
|
+
/** Everything no other route claimed. At most one per connection. */
|
|
75
|
+
AlertIntakeRouteMatch["DEFAULT"] = "DEFAULT";
|
|
76
|
+
})(AlertIntakeRouteMatch || (exports.AlertIntakeRouteMatch = AlertIntakeRouteMatch = {}));
|
|
77
|
+
/** How a provider proves a webhook call really came from it. */
|
|
78
|
+
var AlertIntakeWebhookVerification;
|
|
79
|
+
(function (AlertIntakeWebhookVerification) {
|
|
80
|
+
/** The unguessable URL is the only proof (Africa's Talking signs nothing). */
|
|
81
|
+
AlertIntakeWebhookVerification["SECRET_URL"] = "SECRET_URL";
|
|
82
|
+
/** A shared secret the gateway sends in a header, compared in constant time. */
|
|
83
|
+
AlertIntakeWebhookVerification["SHARED_SECRET_HEADER"] = "SHARED_SECRET_HEADER";
|
|
84
|
+
/** `X-Hub-Signature-256`: HMAC-SHA256 of the raw body with the Meta app secret. */
|
|
85
|
+
AlertIntakeWebhookVerification["META_SIGNATURE"] = "META_SIGNATURE";
|
|
86
|
+
})(AlertIntakeWebhookVerification || (exports.AlertIntakeWebhookVerification = AlertIntakeWebhookVerification = {}));
|
|
87
|
+
/** Why a message that arrived did not become an incident. Stored; shown to operators. */
|
|
88
|
+
var AlertIntakeRejectionReason;
|
|
89
|
+
(function (AlertIntakeRejectionReason) {
|
|
90
|
+
AlertIntakeRejectionReason["UNKNOWN_CONNECTION"] = "UNKNOWN_CONNECTION";
|
|
91
|
+
AlertIntakeRejectionReason["CONNECTION_DISABLED"] = "CONNECTION_DISABLED";
|
|
92
|
+
AlertIntakeRejectionReason["VERIFICATION_FAILED"] = "VERIFICATION_FAILED";
|
|
93
|
+
AlertIntakeRejectionReason["NO_ORGANIZATION"] = "NO_ORGANIZATION";
|
|
94
|
+
AlertIntakeRejectionReason["ORGANIZATION_INACTIVE"] = "ORGANIZATION_INACTIVE";
|
|
95
|
+
AlertIntakeRejectionReason["RATE_LIMITED"] = "RATE_LIMITED";
|
|
96
|
+
})(AlertIntakeRejectionReason || (exports.AlertIntakeRejectionReason = AlertIntakeRejectionReason = {}));
|
|
97
|
+
/**
|
|
98
|
+
* Where a stored message stands, as an operator reads it. Derived from the pipeline's
|
|
99
|
+
* processing status, retry schedule and rejection reason - not stored.
|
|
100
|
+
*
|
|
101
|
+
* QUEUED waiting for, or being worked on by, the pipeline
|
|
102
|
+
* RAISED became an incident
|
|
103
|
+
* RETRYING failed; another attempt is scheduled
|
|
104
|
+
* PARKED failed and will not be retried on its own: it ran out of attempts, or it
|
|
105
|
+
* has a `rejectionReason` (no organization, organization inactive)
|
|
106
|
+
* DUPLICATE the same sender repeating themselves; not raised
|
|
107
|
+
*/
|
|
108
|
+
var AlertIntakeMessageState;
|
|
109
|
+
(function (AlertIntakeMessageState) {
|
|
110
|
+
AlertIntakeMessageState["QUEUED"] = "QUEUED";
|
|
111
|
+
AlertIntakeMessageState["RAISED"] = "RAISED";
|
|
112
|
+
AlertIntakeMessageState["RETRYING"] = "RETRYING";
|
|
113
|
+
AlertIntakeMessageState["PARKED"] = "PARKED";
|
|
114
|
+
AlertIntakeMessageState["DUPLICATE"] = "DUPLICATE";
|
|
115
|
+
})(AlertIntakeMessageState || (exports.AlertIntakeMessageState = AlertIntakeMessageState = {}));
|
|
116
|
+
//# sourceMappingURL=alert-intake.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.enum.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/enums/alert-intake.enum.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,wCAAwC;AACxC,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC1B,iCAAW,CAAA;IACX,2CAAqB,CAAA;IACrB,qCAAe,CAAA;AACnB,CAAC,EAJW,kBAAkB,kCAAlB,kBAAkB,QAI7B;AAED;;;;;;;;GAQG;AACH,IAAY,mBAaX;AAbD,WAAY,mBAAmB;IAC3B,MAAM;IACN,wDAAiC,CAAA;IACjC,wCAAiB,CAAA;IACjB,wCAAiB,CAAA;IACjB,uFAAuF;IACvF,kDAA2B,CAAA;IAC3B,WAAW;IACX,wDAAiC,CAAA;IACjC,QAAQ;IACR,oCAAa,CAAA;IACb,iGAAiG;IACjG,sDAA+B,CAAA;AACnC,CAAC,EAbW,mBAAmB,mCAAnB,mBAAmB,QAa9B;AAED;;;;;;;;;;GAUG;AACH,IAAY,uBAGX;AAHD,WAAY,uBAAuB;IAC/B,kDAAuB,CAAA;IACvB,gEAAqC,CAAA;AACzC,CAAC,EAHW,uBAAuB,uCAAvB,uBAAuB,QAGlC;AAED;;;;GAIG;AACH,IAAY,0BAIX;AAJD,WAAY,0BAA0B;IAClC,2CAAa,CAAA;IACb,mEAAqC,CAAA;IACrC,2EAA6C,CAAA;AACjD,CAAC,EAJW,0BAA0B,0CAA1B,0BAA0B,QAIrC;AAED,qEAAqE;AACrE,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC7B,oFAAoF;IACpF,4CAAmB,CAAA;IACnB,qEAAqE;IACrE,4CAAmB,CAAA;AACvB,CAAC,EALW,qBAAqB,qCAArB,qBAAqB,QAKhC;AAED,gEAAgE;AAChE,IAAY,8BAOX;AAPD,WAAY,8BAA8B;IACtC,8EAA8E;IAC9E,2DAAyB,CAAA;IACzB,gFAAgF;IAChF,+EAA6C,CAAA;IAC7C,mFAAmF;IACnF,mEAAiC,CAAA;AACrC,CAAC,EAPW,8BAA8B,8CAA9B,8BAA8B,QAOzC;AAED,yFAAyF;AACzF,IAAY,0BAOX;AAPD,WAAY,0BAA0B;IAClC,uEAAyC,CAAA;IACzC,yEAA2C,CAAA;IAC3C,yEAA2C,CAAA;IAC3C,iEAAmC,CAAA;IACnC,6EAA+C,CAAA;IAC/C,2DAA6B,CAAA;AACjC,CAAC,EAPW,0BAA0B,0CAA1B,0BAA0B,QAOrC;AAED;;;;;;;;;;GAUG;AACH,IAAY,uBAMX;AAND,WAAY,uBAAuB;IAC/B,4CAAiB,CAAA;IACjB,4CAAiB,CAAA;IACjB,gDAAqB,CAAA;IACrB,4CAAiB,CAAA;IACjB,kDAAuB,CAAA;AAC3B,CAAC,EANW,uBAAuB,uCAAvB,uBAAuB,QAMlC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Enums
|
|
18
|
+
__exportStar(require("./enums/alert-intake.enum"), exports);
|
|
19
|
+
// Response shapes + plain request interfaces
|
|
20
|
+
__exportStar(require("./interfaces/alert-intake"), exports);
|
|
21
|
+
// Utilities
|
|
22
|
+
__exportStar(require("./utils/alert-intake.util"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/alert-intake/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,QAAQ;AACR,4DAA0C;AAE1C,6CAA6C;AAC7C,4DAA0C;AAE1C,YAAY;AACZ,4DAA0C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/interfaces/alert-intake.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_ALERT_INTAKE_SETTING_LENGTH = exports.MAX_ALERT_INTAKE_ROUTES_PER_CONNECTION = exports.MAX_ALERT_INTAKE_CONNECTIONS_PER_ORGANIZATION = exports.ALERT_INTAKE_KEYWORD_PATTERN = void 0;
|
|
4
|
+
exports.normaliseAlertIntakeKeyword = normaliseAlertIntakeKeyword;
|
|
5
|
+
exports.extractAlertIntakeKeyword = extractAlertIntakeKeyword;
|
|
6
|
+
exports.stripAlertIntakeKeyword = stripAlertIntakeKeyword;
|
|
7
|
+
/** A routing keyword: 2-20 letters or digits, stored upper-cased. */
|
|
8
|
+
exports.ALERT_INTAKE_KEYWORD_PATTERN = /^[A-Z0-9]{2,20}$/;
|
|
9
|
+
/** Upper bounds that keep one organization's settings a form rather than a list to page through. */
|
|
10
|
+
exports.MAX_ALERT_INTAKE_CONNECTIONS_PER_ORGANIZATION = 20;
|
|
11
|
+
exports.MAX_ALERT_INTAKE_ROUTES_PER_CONNECTION = 200;
|
|
12
|
+
/** One settings value (config or secret). An access token is the longest thing that goes here. */
|
|
13
|
+
exports.MAX_ALERT_INTAKE_SETTING_LENGTH = 4096;
|
|
14
|
+
/** Normalises what an operator typed into the stored form. Null when it is not a valid keyword. */
|
|
15
|
+
function normaliseAlertIntakeKeyword(value) {
|
|
16
|
+
const keyword = (value !== null && value !== void 0 ? value : '').trim().toUpperCase();
|
|
17
|
+
return exports.ALERT_INTAKE_KEYWORD_PATTERN.test(keyword) ? keyword : null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The routing keyword of a message: its first word, upper-cased, punctuation
|
|
21
|
+
* stripped - `g4s, fire at the gate` and `G4S: fire` both give `G4S`.
|
|
22
|
+
* Null when the first word could not be a keyword.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately only the FIRST word. Matching a keyword anywhere in the text would
|
|
25
|
+
* route "I was robbed near the G4S office" to G4S.
|
|
26
|
+
*/
|
|
27
|
+
function extractAlertIntakeKeyword(text) {
|
|
28
|
+
var _a;
|
|
29
|
+
const first = (_a = (text !== null && text !== void 0 ? text : '').trim().split(/\s+/)[0]) !== null && _a !== void 0 ? _a : '';
|
|
30
|
+
return normaliseAlertIntakeKeyword(first.replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, ''));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The message with its routing keyword removed, so "G4S fire at the gate" is
|
|
34
|
+
* analysed as "fire at the gate". Returns the text unchanged when it does not start
|
|
35
|
+
* with that keyword.
|
|
36
|
+
*/
|
|
37
|
+
function stripAlertIntakeKeyword(text, keyword) {
|
|
38
|
+
const trimmed = (text !== null && text !== void 0 ? text : '').trim();
|
|
39
|
+
// Keywords are [A-Z0-9] by construction; escaping keeps this safe for a caller that skipped normalising.
|
|
40
|
+
const literal = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
41
|
+
const match = new RegExp(`^[^A-Za-z0-9]*${literal}(?![A-Za-z0-9])[^A-Za-z0-9]*`, 'i').exec(trimmed);
|
|
42
|
+
if (!match)
|
|
43
|
+
return text;
|
|
44
|
+
const rest = trimmed.slice(match[0].length).trim();
|
|
45
|
+
// A message that was ONLY the keyword is still a message; do not turn it into nothing.
|
|
46
|
+
return rest.length > 0 ? rest : trimmed;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=alert-intake.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.util.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/utils/alert-intake.util.ts"],"names":[],"mappings":";;;AAUA,kEAGC;AAUD,8DAGC;AAOD,0DASC;AA1CD,qEAAqE;AACxD,QAAA,4BAA4B,GAAG,kBAAkB,CAAC;AAE/D,oGAAoG;AACvF,QAAA,6CAA6C,GAAG,EAAE,CAAC;AACnD,QAAA,sCAAsC,GAAG,GAAG,CAAC;AAC1D,kGAAkG;AACrF,QAAA,+BAA+B,GAAG,IAAI,CAAC;AAEpD,mGAAmG;AACnG,SAAgB,2BAA2B,CAAC,KAAgC;IACxE,MAAM,OAAO,GAAG,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,OAAO,oCAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,yBAAyB,CAAC,IAA+B;;IACrE,MAAM,KAAK,GAAG,MAAA,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;IACxD,OAAO,2BAA2B,CAAC,KAAK,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CAAC,IAAY,EAAE,OAAe;IACjE,MAAM,OAAO,GAAG,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,yGAAyG;IACzG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,iBAAiB,OAAO,8BAA8B,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpG,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,uFAAuF;IACvF,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC"}
|
|
@@ -118,5 +118,13 @@ var PermissionActions;
|
|
|
118
118
|
// Confirming that an SMS sender ID really is registered with the provider.
|
|
119
119
|
// Granted to NO role on the backend: only Super-Admin ('*') passes it.
|
|
120
120
|
PermissionActions["APPROVE_NOTIFICATION_SENDER"] = "approve:notification-sender";
|
|
121
|
+
// Module: Alert Intake
|
|
122
|
+
// The channels the PUBLIC reaches an organization on without the app - its SMS
|
|
123
|
+
// short code, WhatsApp number and mailbox (clarion-alerts). Mirrors grm-shared-library.
|
|
124
|
+
PermissionActions["READ_ALERT_INTAKE"] = "read:alert-intake";
|
|
125
|
+
PermissionActions["MANAGE_ALERT_INTAKE"] = "manage:alert-intake";
|
|
126
|
+
// PLATFORM connections and their routes (which keyword sends a message to which
|
|
127
|
+
// organization). Granted to NO role on the backend: only Super-Admin ('*') passes it.
|
|
128
|
+
PermissionActions["MANAGE_ALERT_INTAKE_PLATFORM"] = "manage:alert-intake-platform";
|
|
121
129
|
})(PermissionActions || (exports.PermissionActions = PermissionActions = {}));
|
|
122
130
|
//# sourceMappingURL=permission-actions.enum.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission-actions.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permission-actions.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"permission-actions.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permission-actions.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,iBAsIX;AAtID,WAAY,iBAAiB;IACzB,uBAAuB;IACvB,gEAA2C,CAAA;IAC3C,4DAAuC,CAAA;IACvC,gEAA2C,CAAA;IAC3C,gEAA2C,CAAA;IAE3C,kBAAkB;IAClB,sDAAiC,CAAA;IACjC,kDAA6B,CAAA;IAC7B,sDAAiC,CAAA;IACjC,sDAAiC,CAAA;IACjC,wEAAwE;IACxE,mEAAmE;IACnE,oEAA+C,CAAA;IAC/C,0EAAqD,CAAA;IACrD,wEAAmD,CAAA;IACnD,wEAAmD,CAAA;IACnD,wEAAmD,CAAA;IACnD,2EAA2E;IAC3E,4EAA4E;IAC5E,qEAAqE;IACrE,uDAAuD;IACvD,wEAAmD,CAAA;IACnD,4EAAuD,CAAA;IAEvD,wBAAwB;IACxB,oEAA+C,CAAA;IAC/C,gEAA2C,CAAA;IAC3C,oEAA+C,CAAA;IAC/C,oEAA+C,CAAA;IAE/C,eAAe;IACf,gDAA2B,CAAA;IAC3B,4CAAuB,CAAA;IACvB,gDAA2B,CAAA;IAC3B,gDAA2B,CAAA;IAE3B,eAAe;IACf,gDAA2B,CAAA;IAC3B,4CAAuB,CAAA;IACvB,gDAA2B,CAAA;IAC3B,gDAA2B,CAAA;IAE3B,mBAAmB;IACnB,wDAAmC,CAAA;IACnC,oDAA+B,CAAA;IAC/B,wDAAmC,CAAA;IACnC,wDAAmC,CAAA;IACnC,oFAA+D,CAAA;IAC/D,gFAA2D,CAAA;IAC3D,oFAA+D,CAAA;IAC/D,oFAA+D,CAAA;IAE/D,uBAAuB;IACvB,kEAA6C,CAAA;IAC7C,8DAAyC,CAAA;IACzC,kEAA6C,CAAA;IAC7C,kEAA6C,CAAA;IAE7C,4EAA4E;IAC5E,wEAAwE;IACxE,6EAA6E;IAC7E,qDAAqD;IACrD,gGAA2E,CAAA;IAC3E,4FAAuE,CAAA;IACvE,gGAA2E,CAAA;IAC3E,gGAA2E,CAAA;IAC3E,sFAAiE,CAAA;IACjE,kFAA6D,CAAA;IAC7D,sFAAiE,CAAA;IACjE,sFAAiE,CAAA;IACjE,sEAAiD,CAAA;IACjD,oEAA+C,CAAA;IAC/C,0EAAqD,CAAA;IACrD,8EAAyD,CAAA;IAEzD,kBAAkB;IAClB,EAAE;IACF,2EAA2E;IAC3E,0EAA0E;IAC1E,uEAAuE;IACvE,+BAA+B;IAC/B,oEAA+C,CAAA;IAC/C,gEAA2C,CAAA;IAC3C,oEAA+C,CAAA;IAC/C,oEAA+C,CAAA;IAC/C,kEAA6C,CAAA;IAC7C,gEAA2C,CAAA;IAC3C,kFAA6D,CAAA;IAC7D,sFAAiE,CAAA;IACjE,kEAA6C,CAAA;IAC7C,oEAA+C,CAAA;IAC/C,yEAAyE;IACzE,gEAA2C,CAAA;IAC3C;;;OAGG;IACH,8DAAyC,CAAA;IACzC,mFAAmF;IACnF,wEAAmD,CAAA;IACnD,oEAA+C,CAAA;IAC/C,gFAAgF;IAChF,sEAAiD,CAAA;IACjD,wEAAmD,CAAA;IACnD,0EAAqD,CAAA;IACrD,0EAAqD,CAAA;IACrD,kEAA6C,CAAA;IAC7C,gEAA2C,CAAA;IAC3C,8DAAyC,CAAA;IACzC,kFAA6D,CAAA;IAC7D,gEAA2C,CAAA;IAC3C,4DAAuC,CAAA;IACvC,gEAA2C,CAAA;IAE3C,uBAAuB;IACvB,0EAA0E;IAC1E,4EAA4E;IAC5E,gDAAgD;IAChD,8EAAyD,CAAA;IACzD,kFAA6D,CAAA;IAC7D,2EAA2E;IAC3E,uEAAuE;IACvE,gFAA2D,CAAA;IAE3D,uBAAuB;IACvB,+EAA+E;IAC/E,wFAAwF;IACxF,4DAAuC,CAAA;IACvC,gEAA2C,CAAA;IAC3C,gFAAgF;IAChF,sFAAsF;IACtF,kFAA6D,CAAA;AACjE,CAAC,EAtIW,iBAAiB,iCAAjB,iBAAiB,QAsI5B"}
|
|
@@ -14,5 +14,6 @@ var PermissionsModule;
|
|
|
14
14
|
PermissionsModule["TRACKING"] = "Tracking";
|
|
15
15
|
PermissionsModule["SUPPORT"] = "Support";
|
|
16
16
|
PermissionsModule["NOTIFICATION"] = "Notification";
|
|
17
|
+
PermissionsModule["ALERT_INTAKE"] = "Alert Intake";
|
|
17
18
|
})(PermissionsModule || (exports.PermissionsModule = PermissionsModule = {}));
|
|
18
19
|
//# sourceMappingURL=permissions-moudule.enum.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-moudule.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permissions-moudule.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,
|
|
1
|
+
{"version":3,"file":"permissions-moudule.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permissions-moudule.enum.ts"],"names":[],"mappings":";;;AAAA,IAAY,iBAaX;AAbD,WAAY,iBAAiB;IACzB,kDAA6B,CAAA;IAC7B,wCAAmB,CAAA;IACnB,sDAAiC,CAAA;IACjC,kCAAa,CAAA;IACb,kCAAa,CAAA;IACb,kCAAa,CAAA;IACb,2CAAsB,CAAA;IACtB,oDAA+B,CAAA;IAC/B,0CAAqB,CAAA;IACrB,wCAAmB,CAAA;IACnB,kDAA6B,CAAA;IAC7B,kDAA6B,CAAA;AACjC,CAAC,EAbW,iBAAiB,iCAAjB,iBAAiB,QAa5B"}
|
package/dist/esm/index.js
CHANGED
|
@@ -20,6 +20,7 @@ export * from './modules/country/index';
|
|
|
20
20
|
export * from './modules/tracking/index';
|
|
21
21
|
export * from './modules/entitlement/index';
|
|
22
22
|
export * from './modules/alert-dispatch/index';
|
|
23
|
+
export * from './modules/alert-intake/index';
|
|
23
24
|
export * from './modules/partner/index';
|
|
24
25
|
export * from './modules/support/index';
|
|
25
26
|
// Interfaces
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AAExC,aAAa;AACb,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,cAAc,sBAAsB,CAAC;AACrC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AAExC,aAAa;AACb,cAAc,4CAA4C,CAAC;AAC3D,cAAc,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert intake: how a member of the public reaches an organization WITHOUT the app -
|
|
3
|
+
* an SMS, a WhatsApp message or an email that clarion-alerts turns into an incident.
|
|
4
|
+
*
|
|
5
|
+
* Not to be confused with `alert-dispatch`, which is about who an SOS raised IN the
|
|
6
|
+
* app is sent to.
|
|
7
|
+
*/
|
|
8
|
+
/** The channel a message arrived on. */
|
|
9
|
+
export var AlertIntakeChannel;
|
|
10
|
+
(function (AlertIntakeChannel) {
|
|
11
|
+
AlertIntakeChannel["SMS"] = "SMS";
|
|
12
|
+
AlertIntakeChannel["WHATSAPP"] = "WHATSAPP";
|
|
13
|
+
AlertIntakeChannel["EMAIL"] = "EMAIL";
|
|
14
|
+
})(AlertIntakeChannel || (AlertIntakeChannel = {}));
|
|
15
|
+
/**
|
|
16
|
+
* The provider a connection talks to.
|
|
17
|
+
*
|
|
18
|
+
* A code here only RESERVES the name. Whether a provider can be connected is
|
|
19
|
+
* answered by clarion-alerts' provider catalogue (`AlertIntakeProviderDescriptor`),
|
|
20
|
+
* which lists only providers with a registered adapter. UWAZII and CELCOM are
|
|
21
|
+
* reserved without an adapter on purpose: their inbound callback formats have not
|
|
22
|
+
* been confirmed, and until they are, GENERIC_SMS connects them by configuration.
|
|
23
|
+
*/
|
|
24
|
+
export var AlertIntakeProvider;
|
|
25
|
+
(function (AlertIntakeProvider) {
|
|
26
|
+
// SMS
|
|
27
|
+
AlertIntakeProvider["AFRICASTALKING"] = "africastalking";
|
|
28
|
+
AlertIntakeProvider["UWAZII"] = "uwazii";
|
|
29
|
+
AlertIntakeProvider["CELCOM"] = "celcom";
|
|
30
|
+
/** Any gateway that POSTs flat JSON or form fields; the field names are configured. */
|
|
31
|
+
AlertIntakeProvider["GENERIC_SMS"] = "generic_sms";
|
|
32
|
+
// WhatsApp
|
|
33
|
+
AlertIntakeProvider["WHATSAPP_CLOUD"] = "whatsapp_cloud";
|
|
34
|
+
// Email
|
|
35
|
+
AlertIntakeProvider["IMAP"] = "imap";
|
|
36
|
+
/** An inbound-parse webhook (Mailgun routes, SendGrid Inbound Parse, or a generic JSON post). */
|
|
37
|
+
AlertIntakeProvider["EMAIL_WEBHOOK"] = "email_webhook";
|
|
38
|
+
})(AlertIntakeProvider || (AlertIntakeProvider = {}));
|
|
39
|
+
/**
|
|
40
|
+
* Where a connection's credentials live. Never in a plaintext column.
|
|
41
|
+
*
|
|
42
|
+
* ENCRYPTED entered by the organization, encrypted at rest by clarion-alerts
|
|
43
|
+
* (AES-256-GCM, bound to the connection and the field). Write-only:
|
|
44
|
+
* the API never returns them.
|
|
45
|
+
* SECRET_REFERENCE the NAME of a secret the platform operator provisioned (Secret
|
|
46
|
+
* Manager / environment). How the legacy per-tenant credentials
|
|
47
|
+
* keep working, and the option for an operator who does not want
|
|
48
|
+
* a credential in the database at all.
|
|
49
|
+
*/
|
|
50
|
+
export var AlertIntakeSecretSource;
|
|
51
|
+
(function (AlertIntakeSecretSource) {
|
|
52
|
+
AlertIntakeSecretSource["ENCRYPTED"] = "ENCRYPTED";
|
|
53
|
+
AlertIntakeSecretSource["SECRET_REFERENCE"] = "SECRET_REFERENCE";
|
|
54
|
+
})(AlertIntakeSecretSource || (AlertIntakeSecretSource = {}));
|
|
55
|
+
/**
|
|
56
|
+
* How the emergency type of an incident raised from a message is decided.
|
|
57
|
+
* AUTO derives it from the organization: a grievance desk never raises an
|
|
58
|
+
* emergency; an incident desk decides from the message's category and priority.
|
|
59
|
+
*/
|
|
60
|
+
export var AlertIntakeEmergencyPolicy;
|
|
61
|
+
(function (AlertIntakeEmergencyPolicy) {
|
|
62
|
+
AlertIntakeEmergencyPolicy["AUTO"] = "AUTO";
|
|
63
|
+
AlertIntakeEmergencyPolicy["ALWAYS_EMERGENCY"] = "ALWAYS_EMERGENCY";
|
|
64
|
+
AlertIntakeEmergencyPolicy["ALWAYS_NON_EMERGENCY"] = "ALWAYS_NON_EMERGENCY";
|
|
65
|
+
})(AlertIntakeEmergencyPolicy || (AlertIntakeEmergencyPolicy = {}));
|
|
66
|
+
/** How a message on a PLATFORM connection finds its organization. */
|
|
67
|
+
export var AlertIntakeRouteMatch;
|
|
68
|
+
(function (AlertIntakeRouteMatch) {
|
|
69
|
+
/** The first word of the message, e.g. `G4S fire at ...` on a shared short code. */
|
|
70
|
+
AlertIntakeRouteMatch["KEYWORD"] = "KEYWORD";
|
|
71
|
+
/** Everything no other route claimed. At most one per connection. */
|
|
72
|
+
AlertIntakeRouteMatch["DEFAULT"] = "DEFAULT";
|
|
73
|
+
})(AlertIntakeRouteMatch || (AlertIntakeRouteMatch = {}));
|
|
74
|
+
/** How a provider proves a webhook call really came from it. */
|
|
75
|
+
export var AlertIntakeWebhookVerification;
|
|
76
|
+
(function (AlertIntakeWebhookVerification) {
|
|
77
|
+
/** The unguessable URL is the only proof (Africa's Talking signs nothing). */
|
|
78
|
+
AlertIntakeWebhookVerification["SECRET_URL"] = "SECRET_URL";
|
|
79
|
+
/** A shared secret the gateway sends in a header, compared in constant time. */
|
|
80
|
+
AlertIntakeWebhookVerification["SHARED_SECRET_HEADER"] = "SHARED_SECRET_HEADER";
|
|
81
|
+
/** `X-Hub-Signature-256`: HMAC-SHA256 of the raw body with the Meta app secret. */
|
|
82
|
+
AlertIntakeWebhookVerification["META_SIGNATURE"] = "META_SIGNATURE";
|
|
83
|
+
})(AlertIntakeWebhookVerification || (AlertIntakeWebhookVerification = {}));
|
|
84
|
+
/** Why a message that arrived did not become an incident. Stored; shown to operators. */
|
|
85
|
+
export var AlertIntakeRejectionReason;
|
|
86
|
+
(function (AlertIntakeRejectionReason) {
|
|
87
|
+
AlertIntakeRejectionReason["UNKNOWN_CONNECTION"] = "UNKNOWN_CONNECTION";
|
|
88
|
+
AlertIntakeRejectionReason["CONNECTION_DISABLED"] = "CONNECTION_DISABLED";
|
|
89
|
+
AlertIntakeRejectionReason["VERIFICATION_FAILED"] = "VERIFICATION_FAILED";
|
|
90
|
+
AlertIntakeRejectionReason["NO_ORGANIZATION"] = "NO_ORGANIZATION";
|
|
91
|
+
AlertIntakeRejectionReason["ORGANIZATION_INACTIVE"] = "ORGANIZATION_INACTIVE";
|
|
92
|
+
AlertIntakeRejectionReason["RATE_LIMITED"] = "RATE_LIMITED";
|
|
93
|
+
})(AlertIntakeRejectionReason || (AlertIntakeRejectionReason = {}));
|
|
94
|
+
/**
|
|
95
|
+
* Where a stored message stands, as an operator reads it. Derived from the pipeline's
|
|
96
|
+
* processing status, retry schedule and rejection reason - not stored.
|
|
97
|
+
*
|
|
98
|
+
* QUEUED waiting for, or being worked on by, the pipeline
|
|
99
|
+
* RAISED became an incident
|
|
100
|
+
* RETRYING failed; another attempt is scheduled
|
|
101
|
+
* PARKED failed and will not be retried on its own: it ran out of attempts, or it
|
|
102
|
+
* has a `rejectionReason` (no organization, organization inactive)
|
|
103
|
+
* DUPLICATE the same sender repeating themselves; not raised
|
|
104
|
+
*/
|
|
105
|
+
export var AlertIntakeMessageState;
|
|
106
|
+
(function (AlertIntakeMessageState) {
|
|
107
|
+
AlertIntakeMessageState["QUEUED"] = "QUEUED";
|
|
108
|
+
AlertIntakeMessageState["RAISED"] = "RAISED";
|
|
109
|
+
AlertIntakeMessageState["RETRYING"] = "RETRYING";
|
|
110
|
+
AlertIntakeMessageState["PARKED"] = "PARKED";
|
|
111
|
+
AlertIntakeMessageState["DUPLICATE"] = "DUPLICATE";
|
|
112
|
+
})(AlertIntakeMessageState || (AlertIntakeMessageState = {}));
|
|
113
|
+
//# sourceMappingURL=alert-intake.enum.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.enum.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/enums/alert-intake.enum.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wCAAwC;AACxC,MAAM,CAAN,IAAY,kBAIX;AAJD,WAAY,kBAAkB;IAC1B,iCAAW,CAAA;IACX,2CAAqB,CAAA;IACrB,qCAAe,CAAA;AACnB,CAAC,EAJW,kBAAkB,KAAlB,kBAAkB,QAI7B;AAED;;;;;;;;GAQG;AACH,MAAM,CAAN,IAAY,mBAaX;AAbD,WAAY,mBAAmB;IAC3B,MAAM;IACN,wDAAiC,CAAA;IACjC,wCAAiB,CAAA;IACjB,wCAAiB,CAAA;IACjB,uFAAuF;IACvF,kDAA2B,CAAA;IAC3B,WAAW;IACX,wDAAiC,CAAA;IACjC,QAAQ;IACR,oCAAa,CAAA;IACb,iGAAiG;IACjG,sDAA+B,CAAA;AACnC,CAAC,EAbW,mBAAmB,KAAnB,mBAAmB,QAa9B;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAN,IAAY,uBAGX;AAHD,WAAY,uBAAuB;IAC/B,kDAAuB,CAAA;IACvB,gEAAqC,CAAA;AACzC,CAAC,EAHW,uBAAuB,KAAvB,uBAAuB,QAGlC;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,0BAIX;AAJD,WAAY,0BAA0B;IAClC,2CAAa,CAAA;IACb,mEAAqC,CAAA;IACrC,2EAA6C,CAAA;AACjD,CAAC,EAJW,0BAA0B,KAA1B,0BAA0B,QAIrC;AAED,qEAAqE;AACrE,MAAM,CAAN,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC7B,oFAAoF;IACpF,4CAAmB,CAAA;IACnB,qEAAqE;IACrE,4CAAmB,CAAA;AACvB,CAAC,EALW,qBAAqB,KAArB,qBAAqB,QAKhC;AAED,gEAAgE;AAChE,MAAM,CAAN,IAAY,8BAOX;AAPD,WAAY,8BAA8B;IACtC,8EAA8E;IAC9E,2DAAyB,CAAA;IACzB,gFAAgF;IAChF,+EAA6C,CAAA;IAC7C,mFAAmF;IACnF,mEAAiC,CAAA;AACrC,CAAC,EAPW,8BAA8B,KAA9B,8BAA8B,QAOzC;AAED,yFAAyF;AACzF,MAAM,CAAN,IAAY,0BAOX;AAPD,WAAY,0BAA0B;IAClC,uEAAyC,CAAA;IACzC,yEAA2C,CAAA;IAC3C,yEAA2C,CAAA;IAC3C,iEAAmC,CAAA;IACnC,6EAA+C,CAAA;IAC/C,2DAA6B,CAAA;AACjC,CAAC,EAPW,0BAA0B,KAA1B,0BAA0B,QAOrC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAN,IAAY,uBAMX;AAND,WAAY,uBAAuB;IAC/B,4CAAiB,CAAA;IACjB,4CAAiB,CAAA;IACjB,gDAAqB,CAAA;IACrB,4CAAiB,CAAA;IACjB,kDAAuB,CAAA;AAC3B,CAAC,EANW,uBAAuB,KAAvB,uBAAuB,QAMlC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/alert-intake/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,2BAA2B,CAAC;AAE1C,6CAA6C;AAC7C,cAAc,2BAA2B,CAAC;AAE1C,YAAY;AACZ,cAAc,2BAA2B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/interfaces/alert-intake.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** A routing keyword: 2-20 letters or digits, stored upper-cased. */
|
|
2
|
+
export const ALERT_INTAKE_KEYWORD_PATTERN = /^[A-Z0-9]{2,20}$/;
|
|
3
|
+
/** Upper bounds that keep one organization's settings a form rather than a list to page through. */
|
|
4
|
+
export const MAX_ALERT_INTAKE_CONNECTIONS_PER_ORGANIZATION = 20;
|
|
5
|
+
export 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 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 function normaliseAlertIntakeKeyword(value) {
|
|
10
|
+
const keyword = (value !== null && value !== void 0 ? value : '').trim().toUpperCase();
|
|
11
|
+
return ALERT_INTAKE_KEYWORD_PATTERN.test(keyword) ? keyword : null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The routing keyword of a message: its first word, upper-cased, punctuation
|
|
15
|
+
* stripped - `g4s, fire at the gate` and `G4S: fire` both give `G4S`.
|
|
16
|
+
* Null when the first word could not be a keyword.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately only the FIRST word. Matching a keyword anywhere in the text would
|
|
19
|
+
* route "I was robbed near the G4S office" to G4S.
|
|
20
|
+
*/
|
|
21
|
+
export function extractAlertIntakeKeyword(text) {
|
|
22
|
+
var _a;
|
|
23
|
+
const first = (_a = (text !== null && text !== void 0 ? text : '').trim().split(/\s+/)[0]) !== null && _a !== void 0 ? _a : '';
|
|
24
|
+
return normaliseAlertIntakeKeyword(first.replace(/^[^A-Za-z0-9]+|[^A-Za-z0-9]+$/g, ''));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The message with its routing keyword removed, so "G4S fire at the gate" is
|
|
28
|
+
* analysed as "fire at the gate". Returns the text unchanged when it does not start
|
|
29
|
+
* with that keyword.
|
|
30
|
+
*/
|
|
31
|
+
export function stripAlertIntakeKeyword(text, keyword) {
|
|
32
|
+
const trimmed = (text !== null && text !== void 0 ? text : '').trim();
|
|
33
|
+
// Keywords are [A-Z0-9] by construction; escaping keeps this safe for a caller that skipped normalising.
|
|
34
|
+
const literal = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
35
|
+
const match = new RegExp(`^[^A-Za-z0-9]*${literal}(?![A-Za-z0-9])[^A-Za-z0-9]*`, 'i').exec(trimmed);
|
|
36
|
+
if (!match)
|
|
37
|
+
return text;
|
|
38
|
+
const rest = trimmed.slice(match[0].length).trim();
|
|
39
|
+
// A message that was ONLY the keyword is still a message; do not turn it into nothing.
|
|
40
|
+
return rest.length > 0 ? rest : trimmed;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=alert-intake.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alert-intake.util.js","sourceRoot":"","sources":["../../../../../src/modules/alert-intake/utils/alert-intake.util.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,MAAM,CAAC,MAAM,4BAA4B,GAAG,kBAAkB,CAAC;AAE/D,oGAAoG;AACpG,MAAM,CAAC,MAAM,6CAA6C,GAAG,EAAE,CAAC;AAChE,MAAM,CAAC,MAAM,sCAAsC,GAAG,GAAG,CAAC;AAC1D,kGAAkG;AAClG,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,CAAC;AAEpD,mGAAmG;AACnG,MAAM,UAAU,2BAA2B,CAAC,KAAgC;IACxE,MAAM,OAAO,GAAG,CAAC,KAAK,aAAL,KAAK,cAAL,KAAK,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnD,OAAO,4BAA4B,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAA+B;;IACrE,MAAM,KAAK,GAAG,MAAA,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,mCAAI,EAAE,CAAC;IACxD,OAAO,2BAA2B,CAAC,KAAK,CAAC,OAAO,CAAC,gCAAgC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,OAAe;IACjE,MAAM,OAAO,GAAG,CAAC,IAAI,aAAJ,IAAI,cAAJ,IAAI,GAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpC,yGAAyG;IACzG,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,iBAAiB,OAAO,8BAA8B,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpG,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,uFAAuF;IACvF,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;AAC5C,CAAC"}
|
|
@@ -115,5 +115,13 @@ export var PermissionActions;
|
|
|
115
115
|
// Confirming that an SMS sender ID really is registered with the provider.
|
|
116
116
|
// Granted to NO role on the backend: only Super-Admin ('*') passes it.
|
|
117
117
|
PermissionActions["APPROVE_NOTIFICATION_SENDER"] = "approve:notification-sender";
|
|
118
|
+
// Module: Alert Intake
|
|
119
|
+
// The channels the PUBLIC reaches an organization on without the app - its SMS
|
|
120
|
+
// short code, WhatsApp number and mailbox (clarion-alerts). Mirrors grm-shared-library.
|
|
121
|
+
PermissionActions["READ_ALERT_INTAKE"] = "read:alert-intake";
|
|
122
|
+
PermissionActions["MANAGE_ALERT_INTAKE"] = "manage:alert-intake";
|
|
123
|
+
// PLATFORM connections and their routes (which keyword sends a message to which
|
|
124
|
+
// organization). Granted to NO role on the backend: only Super-Admin ('*') passes it.
|
|
125
|
+
PermissionActions["MANAGE_ALERT_INTAKE_PLATFORM"] = "manage:alert-intake-platform";
|
|
118
126
|
})(PermissionActions || (PermissionActions = {}));
|
|
119
127
|
//# sourceMappingURL=permission-actions.enum.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission-actions.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permission-actions.enum.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"permission-actions.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permission-actions.enum.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,5 +11,6 @@ export var PermissionsModule;
|
|
|
11
11
|
PermissionsModule["TRACKING"] = "Tracking";
|
|
12
12
|
PermissionsModule["SUPPORT"] = "Support";
|
|
13
13
|
PermissionsModule["NOTIFICATION"] = "Notification";
|
|
14
|
+
PermissionsModule["ALERT_INTAKE"] = "Alert Intake";
|
|
14
15
|
})(PermissionsModule || (PermissionsModule = {}));
|
|
15
16
|
//# sourceMappingURL=permissions-moudule.enum.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-moudule.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permissions-moudule.enum.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"permissions-moudule.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permissions-moudule.enum.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,iBAaX;AAbD,WAAY,iBAAiB;IACzB,kDAA6B,CAAA;IAC7B,wCAAmB,CAAA;IACnB,sDAAiC,CAAA;IACjC,kCAAa,CAAA;IACb,kCAAa,CAAA;IACb,kCAAa,CAAA;IACb,2CAAsB,CAAA;IACtB,oDAA+B,CAAA;IAC/B,0CAAqB,CAAA;IACrB,wCAAmB,CAAA;IACnB,kDAA6B,CAAA;IAC7B,kDAA6B,CAAA;AACjC,CAAC,EAbW,iBAAiB,KAAjB,iBAAiB,QAa5B"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * from './modules/country/index';
|
|
|
19
19
|
export * from './modules/tracking/index';
|
|
20
20
|
export * from './modules/entitlement/index';
|
|
21
21
|
export * from './modules/alert-dispatch/index';
|
|
22
|
+
export * from './modules/alert-intake/index';
|
|
22
23
|
export * from './modules/partner/index';
|
|
23
24
|
export * from './modules/support/index';
|
|
24
25
|
export * from './modules/common/interfaces/server-message';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert intake: how a member of the public reaches an organization WITHOUT the app -
|
|
3
|
+
* an SMS, a WhatsApp message or an email that clarion-alerts turns into an incident.
|
|
4
|
+
*
|
|
5
|
+
* Not to be confused with `alert-dispatch`, which is about who an SOS raised IN the
|
|
6
|
+
* app is sent to.
|
|
7
|
+
*/
|
|
8
|
+
/** The channel a message arrived on. */
|
|
9
|
+
export declare enum AlertIntakeChannel {
|
|
10
|
+
SMS = "SMS",
|
|
11
|
+
WHATSAPP = "WHATSAPP",
|
|
12
|
+
EMAIL = "EMAIL"
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The provider a connection talks to.
|
|
16
|
+
*
|
|
17
|
+
* A code here only RESERVES the name. Whether a provider can be connected is
|
|
18
|
+
* answered by clarion-alerts' provider catalogue (`AlertIntakeProviderDescriptor`),
|
|
19
|
+
* which lists only providers with a registered adapter. UWAZII and CELCOM are
|
|
20
|
+
* reserved without an adapter on purpose: their inbound callback formats have not
|
|
21
|
+
* been confirmed, and until they are, GENERIC_SMS connects them by configuration.
|
|
22
|
+
*/
|
|
23
|
+
export declare enum AlertIntakeProvider {
|
|
24
|
+
AFRICASTALKING = "africastalking",
|
|
25
|
+
UWAZII = "uwazii",
|
|
26
|
+
CELCOM = "celcom",
|
|
27
|
+
/** Any gateway that POSTs flat JSON or form fields; the field names are configured. */
|
|
28
|
+
GENERIC_SMS = "generic_sms",
|
|
29
|
+
WHATSAPP_CLOUD = "whatsapp_cloud",
|
|
30
|
+
IMAP = "imap",
|
|
31
|
+
/** An inbound-parse webhook (Mailgun routes, SendGrid Inbound Parse, or a generic JSON post). */
|
|
32
|
+
EMAIL_WEBHOOK = "email_webhook"
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Where a connection's credentials live. Never in a plaintext column.
|
|
36
|
+
*
|
|
37
|
+
* ENCRYPTED entered by the organization, encrypted at rest by clarion-alerts
|
|
38
|
+
* (AES-256-GCM, bound to the connection and the field). Write-only:
|
|
39
|
+
* the API never returns them.
|
|
40
|
+
* SECRET_REFERENCE the NAME of a secret the platform operator provisioned (Secret
|
|
41
|
+
* Manager / environment). How the legacy per-tenant credentials
|
|
42
|
+
* keep working, and the option for an operator who does not want
|
|
43
|
+
* a credential in the database at all.
|
|
44
|
+
*/
|
|
45
|
+
export declare enum AlertIntakeSecretSource {
|
|
46
|
+
ENCRYPTED = "ENCRYPTED",
|
|
47
|
+
SECRET_REFERENCE = "SECRET_REFERENCE"
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* How the emergency type of an incident raised from a message is decided.
|
|
51
|
+
* AUTO derives it from the organization: a grievance desk never raises an
|
|
52
|
+
* emergency; an incident desk decides from the message's category and priority.
|
|
53
|
+
*/
|
|
54
|
+
export declare enum AlertIntakeEmergencyPolicy {
|
|
55
|
+
AUTO = "AUTO",
|
|
56
|
+
ALWAYS_EMERGENCY = "ALWAYS_EMERGENCY",
|
|
57
|
+
ALWAYS_NON_EMERGENCY = "ALWAYS_NON_EMERGENCY"
|
|
58
|
+
}
|
|
59
|
+
/** How a message on a PLATFORM connection finds its organization. */
|
|
60
|
+
export declare enum AlertIntakeRouteMatch {
|
|
61
|
+
/** The first word of the message, e.g. `G4S fire at ...` on a shared short code. */
|
|
62
|
+
KEYWORD = "KEYWORD",
|
|
63
|
+
/** Everything no other route claimed. At most one per connection. */
|
|
64
|
+
DEFAULT = "DEFAULT"
|
|
65
|
+
}
|
|
66
|
+
/** How a provider proves a webhook call really came from it. */
|
|
67
|
+
export declare enum AlertIntakeWebhookVerification {
|
|
68
|
+
/** The unguessable URL is the only proof (Africa's Talking signs nothing). */
|
|
69
|
+
SECRET_URL = "SECRET_URL",
|
|
70
|
+
/** A shared secret the gateway sends in a header, compared in constant time. */
|
|
71
|
+
SHARED_SECRET_HEADER = "SHARED_SECRET_HEADER",
|
|
72
|
+
/** `X-Hub-Signature-256`: HMAC-SHA256 of the raw body with the Meta app secret. */
|
|
73
|
+
META_SIGNATURE = "META_SIGNATURE"
|
|
74
|
+
}
|
|
75
|
+
/** Why a message that arrived did not become an incident. Stored; shown to operators. */
|
|
76
|
+
export declare enum AlertIntakeRejectionReason {
|
|
77
|
+
UNKNOWN_CONNECTION = "UNKNOWN_CONNECTION",
|
|
78
|
+
CONNECTION_DISABLED = "CONNECTION_DISABLED",
|
|
79
|
+
VERIFICATION_FAILED = "VERIFICATION_FAILED",
|
|
80
|
+
NO_ORGANIZATION = "NO_ORGANIZATION",
|
|
81
|
+
ORGANIZATION_INACTIVE = "ORGANIZATION_INACTIVE",
|
|
82
|
+
RATE_LIMITED = "RATE_LIMITED"
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Where a stored message stands, as an operator reads it. Derived from the pipeline's
|
|
86
|
+
* processing status, retry schedule and rejection reason - not stored.
|
|
87
|
+
*
|
|
88
|
+
* QUEUED waiting for, or being worked on by, the pipeline
|
|
89
|
+
* RAISED became an incident
|
|
90
|
+
* RETRYING failed; another attempt is scheduled
|
|
91
|
+
* PARKED failed and will not be retried on its own: it ran out of attempts, or it
|
|
92
|
+
* has a `rejectionReason` (no organization, organization inactive)
|
|
93
|
+
* DUPLICATE the same sender repeating themselves; not raised
|
|
94
|
+
*/
|
|
95
|
+
export declare enum AlertIntakeMessageState {
|
|
96
|
+
QUEUED = "QUEUED",
|
|
97
|
+
RAISED = "RAISED",
|
|
98
|
+
RETRYING = "RETRYING",
|
|
99
|
+
PARKED = "PARKED",
|
|
100
|
+
DUPLICATE = "DUPLICATE"
|
|
101
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
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
|
+
* 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
|
+
/** What arrived for this organization recently, and what needs someone's attention. */
|
|
150
|
+
activity?: AlertIntakeActivitySummary;
|
|
151
|
+
}
|
|
152
|
+
/** Counts over the last `windowHours` - except `parked` and `failingConnections`, which are as of now. */
|
|
153
|
+
export interface AlertIntakeActivitySummary {
|
|
154
|
+
windowHours: number;
|
|
155
|
+
received: number;
|
|
156
|
+
raised: number;
|
|
157
|
+
duplicates: number;
|
|
158
|
+
retrying: number;
|
|
159
|
+
/** Waiting for an operator: out of attempts, or held for a reason (no organization, organization inactive). */
|
|
160
|
+
parked: number;
|
|
161
|
+
/** Enabled connections whose last attempt failed (a rejected call, a mailbox that could not be read). */
|
|
162
|
+
failingConnections: number;
|
|
163
|
+
}
|
|
164
|
+
/** What is kept of a file that came with a message. Never its contents. */
|
|
165
|
+
export interface AlertIntakeMessageAttachment {
|
|
166
|
+
fileName: string;
|
|
167
|
+
mimeType: string;
|
|
168
|
+
size: number;
|
|
169
|
+
/** True once the file is stored in DMS and linked to the incident. */
|
|
170
|
+
attached: boolean;
|
|
171
|
+
/** Why it was not attached, when it was not. */
|
|
172
|
+
error: string | null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* A stored message, as an operator sees it in a list. `preview` is the start of the
|
|
176
|
+
* text; the whole of it is only in the detail.
|
|
177
|
+
*/
|
|
178
|
+
export interface AlertIntakeMessage {
|
|
179
|
+
id: string;
|
|
180
|
+
/** Null while no organization has been found for it. */
|
|
181
|
+
organizationId: number | null;
|
|
182
|
+
connectionId: string | null;
|
|
183
|
+
connectionName: string | null;
|
|
184
|
+
channel: AlertIntakeChannel;
|
|
185
|
+
/** Phone number, WhatsApp number or email address, as stored. */
|
|
186
|
+
sender: string | null;
|
|
187
|
+
senderName: string | null;
|
|
188
|
+
subject: string | null;
|
|
189
|
+
preview: string;
|
|
190
|
+
/** The keyword that routed it, on a platform connection. */
|
|
191
|
+
routeKeyword: string | null;
|
|
192
|
+
state: AlertIntakeMessageState;
|
|
193
|
+
rejectionReason: AlertIntakeRejectionReason | null;
|
|
194
|
+
/** The last error, for RETRYING and PARKED. */
|
|
195
|
+
error: string | null;
|
|
196
|
+
attempts: number;
|
|
197
|
+
nextAttemptAt: string | null;
|
|
198
|
+
/** The incident it raised. */
|
|
199
|
+
incidentId: number | null;
|
|
200
|
+
attachmentCount: number;
|
|
201
|
+
/** When the sender was told their message was received, if they were. */
|
|
202
|
+
acknowledgedAt: string | null;
|
|
203
|
+
receivedAt: string;
|
|
204
|
+
updatedAt: string;
|
|
205
|
+
/** What the CALLER may do with it now. */
|
|
206
|
+
actions: {
|
|
207
|
+
/** Try again: a PARKED message that ran out of attempts, or whose organization is active again. */
|
|
208
|
+
retry: boolean;
|
|
209
|
+
/** Raise a message that was taken for a duplicate. */
|
|
210
|
+
raiseAnyway: boolean;
|
|
211
|
+
/** Give a message no route claimed to an organization (platform operators). */
|
|
212
|
+
assign: boolean;
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
export interface AlertIntakeMessageDetail extends AlertIntakeMessage {
|
|
216
|
+
/** What the incident is raised from (a routing keyword removed). */
|
|
217
|
+
content: string;
|
|
218
|
+
/** Exactly as received. */
|
|
219
|
+
originalContent: string;
|
|
220
|
+
attachments: AlertIntakeMessageAttachment[];
|
|
221
|
+
acknowledgementError: string | null;
|
|
222
|
+
}
|
|
223
|
+
export interface AlertIntakeMessagePage {
|
|
224
|
+
items: AlertIntakeMessage[];
|
|
225
|
+
total: number;
|
|
226
|
+
page: number;
|
|
227
|
+
limit: number;
|
|
228
|
+
}
|
|
229
|
+
export interface AlertIntakeConnectionTestResult {
|
|
230
|
+
success: boolean;
|
|
231
|
+
/** Operator-facing. Never contains a credential. */
|
|
232
|
+
message: string;
|
|
233
|
+
latencyMs?: number;
|
|
234
|
+
}
|
|
235
|
+
export interface CreateAlertIntakeConnection {
|
|
236
|
+
channel: AlertIntakeChannel;
|
|
237
|
+
provider: AlertIntakeProvider;
|
|
238
|
+
/** 2-100 characters, single line. */
|
|
239
|
+
name: string;
|
|
240
|
+
/** What people send to: the short code or number, the WhatsApp phone-number id, the mailbox address. */
|
|
241
|
+
address: string;
|
|
242
|
+
enabled?: boolean;
|
|
243
|
+
/** Non-secret provider settings, as the provider descriptor declares them. */
|
|
244
|
+
config?: Record<string, string | number | boolean>;
|
|
245
|
+
/** Credentials. WRITE-ONLY: encrypted at rest and never returned. Keys are the descriptor's secret fields. */
|
|
246
|
+
secrets?: Record<string, string>;
|
|
247
|
+
/** Platform operators only. NAMES of provisioned secrets, used instead of `secrets` - never both. */
|
|
248
|
+
secretReferences?: Record<string, string>;
|
|
249
|
+
emergencyPolicy?: AlertIntakeEmergencyPolicy;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Channel and provider cannot change: a connection IS its provider link. `config`
|
|
253
|
+
* is merged over the stored settings and only the `secrets` sent are replaced; a key
|
|
254
|
+
* sent as "" is removed.
|
|
255
|
+
*/
|
|
256
|
+
export interface UpdateAlertIntakeConnection {
|
|
257
|
+
name?: string;
|
|
258
|
+
address?: string;
|
|
259
|
+
enabled?: boolean;
|
|
260
|
+
config?: Record<string, string | number | boolean>;
|
|
261
|
+
secrets?: Record<string, string>;
|
|
262
|
+
/** Platform operators only. */
|
|
263
|
+
secretReferences?: Record<string, string>;
|
|
264
|
+
emergencyPolicy?: AlertIntakeEmergencyPolicy;
|
|
265
|
+
}
|
|
266
|
+
/** Platform operators only: sends a PLATFORM connection's messages to an organization. */
|
|
267
|
+
export interface CreateAlertIntakeRoute {
|
|
268
|
+
match: AlertIntakeRouteMatch;
|
|
269
|
+
/** Required for KEYWORD; must be absent for DEFAULT. */
|
|
270
|
+
keyword?: string;
|
|
271
|
+
organizationId: number;
|
|
272
|
+
enabled?: boolean;
|
|
273
|
+
}
|
|
274
|
+
export interface UpdateAlertIntakeRoute {
|
|
275
|
+
organizationId?: number;
|
|
276
|
+
enabled?: boolean;
|
|
277
|
+
}
|
|
278
|
+
/** A platform connection as the operator list returns it: the connection plus its routes. */
|
|
279
|
+
export type AlertIntakePlatformConnection = AlertIntakeConnection & {
|
|
280
|
+
routes: AlertIntakeRoute[];
|
|
281
|
+
};
|
|
282
|
+
/** Filters for an organization's stored messages (query string). `limit` is at most 100. */
|
|
283
|
+
export interface ListAlertIntakeMessagesQuery {
|
|
284
|
+
state?: AlertIntakeMessageState;
|
|
285
|
+
channel?: AlertIntakeChannel;
|
|
286
|
+
connectionId?: string;
|
|
287
|
+
reason?: AlertIntakeRejectionReason;
|
|
288
|
+
page?: number;
|
|
289
|
+
limit?: number;
|
|
290
|
+
}
|
|
291
|
+
/** Platform operators: every organization's messages, and those no organization has yet. */
|
|
292
|
+
export interface ListPlatformAlertIntakeMessagesQuery extends ListAlertIntakeMessagesQuery {
|
|
293
|
+
organizationId?: number;
|
|
294
|
+
/** Only messages no organization has been found for. */
|
|
295
|
+
unrouted?: boolean;
|
|
296
|
+
}
|
|
297
|
+
/** Platform operators: give a message no route claimed to an organization, and raise it. */
|
|
298
|
+
export interface AssignAlertIntakeMessage {
|
|
299
|
+
organizationId: number;
|
|
300
|
+
}
|
|
@@ -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;
|
|
@@ -84,5 +84,8 @@ export declare enum PermissionActions {
|
|
|
84
84
|
MANAGE_SUPPORT_SYNC = "manage:support-sync",
|
|
85
85
|
READ_NOTIFICATION_SETTINGS = "read:notification-settings",
|
|
86
86
|
MANAGE_NOTIFICATION_SETTINGS = "manage:notification-settings",
|
|
87
|
-
APPROVE_NOTIFICATION_SENDER = "approve:notification-sender"
|
|
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"
|
|
88
91
|
}
|