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,94 @@
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
+ //# 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"}
@@ -0,0 +1,7 @@
1
+ // Enums
2
+ export * from './enums/alert-intake.enum';
3
+ // Response shapes + plain request interfaces
4
+ export * from './interfaces/alert-intake';
5
+ // Utilities
6
+ export * from './utils/alert-intake.util';
7
+ //# 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,cAAc,2BAA2B,CAAC;AAE1C,6CAA6C;AAC7C,cAAc,2BAA2B,CAAC;AAE1C,YAAY;AACZ,cAAc,2BAA2B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=alert-intake.js.map
@@ -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"}
@@ -0,0 +1,81 @@
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 var SmsSenderType;
11
+ (function (SmsSenderType) {
12
+ /** A registered alphanumeric sender name, e.g. `G4S`. At most 11 characters. */
13
+ SmsSenderType["ALPHANUMERIC"] = "ALPHANUMERIC";
14
+ /** An E.164 long number, e.g. `+254711000000`. */
15
+ SmsSenderType["PHONE_NUMBER"] = "PHONE_NUMBER";
16
+ /** A telco short code, e.g. `22384`. */
17
+ SmsSenderType["SHORT_CODE"] = "SHORT_CODE";
18
+ /** A provider-side sender pool (Twilio Messaging Service SID, `MG...`). */
19
+ SmsSenderType["MESSAGING_SERVICE"] = "MESSAGING_SERVICE";
20
+ })(SmsSenderType || (SmsSenderType = {}));
21
+ /**
22
+ * Lifecycle of an organization-owned SMS sender. An organization REQUESTS a sender
23
+ * (PENDING) and a platform operator ACTIVATES it once the provider and the telco
24
+ * have registered it. Only ACTIVE senders are ever used to send.
25
+ */
26
+ export var NotificationSenderStatus;
27
+ (function (NotificationSenderStatus) {
28
+ NotificationSenderStatus["PENDING"] = "PENDING";
29
+ NotificationSenderStatus["ACTIVE"] = "ACTIVE";
30
+ NotificationSenderStatus["SUSPENDED"] = "SUSPENDED";
31
+ NotificationSenderStatus["REJECTED"] = "REJECTED";
32
+ })(NotificationSenderStatus || (NotificationSenderStatus = {}));
33
+ /**
34
+ * Whether an email provider will accept mail FROM an organization's address.
35
+ * Tracked per provider: an address can be verified in Twilio SendGrid while its
36
+ * domain is unknown to Mailgun. A provider only sends from an address it has
37
+ * VERIFIED; otherwise it falls back to the platform sender.
38
+ */
39
+ export var EmailSenderVerificationStatus;
40
+ (function (EmailSenderVerificationStatus) {
41
+ /** The provider does not know this address or its domain. */
42
+ EmailSenderVerificationStatus["UNVERIFIED"] = "UNVERIFIED";
43
+ /** Verification was started and is waiting on the owner (inbox click or DNS records). */
44
+ EmailSenderVerificationStatus["PENDING"] = "PENDING";
45
+ /** The provider accepts mail from this address. */
46
+ EmailSenderVerificationStatus["VERIFIED"] = "VERIFIED";
47
+ /** The last check could not be completed (provider error). */
48
+ EmailSenderVerificationStatus["FAILED"] = "FAILED";
49
+ })(EmailSenderVerificationStatus || (EmailSenderVerificationStatus = {}));
50
+ /** How the provider recognises the address. */
51
+ export var EmailSenderVerificationMethod;
52
+ (function (EmailSenderVerificationMethod) {
53
+ /** The exact address was verified on its own (SendGrid Single Sender Verification). */
54
+ EmailSenderVerificationMethod["SINGLE_SENDER"] = "SINGLE_SENDER";
55
+ /** The whole domain is authenticated (SendGrid domain authentication, Mailgun domain). */
56
+ EmailSenderVerificationMethod["DOMAIN"] = "DOMAIN";
57
+ })(EmailSenderVerificationMethod || (EmailSenderVerificationMethod = {}));
58
+ /** Whose identity a message actually went out under. */
59
+ export var NotificationSenderSource;
60
+ (function (NotificationSenderSource) {
61
+ /** The organization's own verified email address / active SMS sender. */
62
+ NotificationSenderSource["ORGANIZATION"] = "ORGANIZATION";
63
+ /** The platform's default (country-aware) sender. */
64
+ NotificationSenderSource["PLATFORM_DEFAULT"] = "PLATFORM_DEFAULT";
65
+ })(NotificationSenderSource || (NotificationSenderSource = {}));
66
+ /**
67
+ * Where one resolved branding value came from. Branding resolves field by field,
68
+ * highest precedence first, so a half-filled profile still produces a complete email.
69
+ */
70
+ export var NotificationBrandingSource;
71
+ (function (NotificationBrandingSource) {
72
+ /** The organization's notification settings. */
73
+ NotificationBrandingSource["PROFILE"] = "PROFILE";
74
+ /** The organization record (clarion-organization). */
75
+ NotificationBrandingSource["ORGANIZATION"] = "ORGANIZATION";
76
+ /** The legacy per-app defaults (deprecated). */
77
+ NotificationBrandingSource["APP_DEFAULT"] = "APP_DEFAULT";
78
+ /** The platform's own branding. */
79
+ NotificationBrandingSource["PLATFORM_DEFAULT"] = "PLATFORM_DEFAULT";
80
+ })(NotificationBrandingSource || (NotificationBrandingSource = {}));
81
+ //# sourceMappingURL=notification-settings.enums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-settings.enums.js","sourceRoot":"","sources":["../../../../../src/modules/notification/enums/notification-settings.enums.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qFAAqF;AACrF,MAAM,CAAN,IAAY,aASX;AATD,WAAY,aAAa;IACrB,gFAAgF;IAChF,8CAA6B,CAAA;IAC7B,kDAAkD;IAClD,8CAA6B,CAAA;IAC7B,wCAAwC;IACxC,0CAAyB,CAAA;IACzB,2EAA2E;IAC3E,wDAAuC,CAAA;AAC3C,CAAC,EATW,aAAa,KAAb,aAAa,QASxB;AAED;;;;GAIG;AACH,MAAM,CAAN,IAAY,wBAKX;AALD,WAAY,wBAAwB;IAChC,+CAAmB,CAAA;IACnB,6CAAiB,CAAA;IACjB,mDAAuB,CAAA;IACvB,iDAAqB,CAAA;AACzB,CAAC,EALW,wBAAwB,KAAxB,wBAAwB,QAKnC;AAED;;;;;GAKG;AACH,MAAM,CAAN,IAAY,6BASX;AATD,WAAY,6BAA6B;IACrC,6DAA6D;IAC7D,0DAAyB,CAAA;IACzB,yFAAyF;IACzF,oDAAmB,CAAA;IACnB,mDAAmD;IACnD,sDAAqB,CAAA;IACrB,8DAA8D;IAC9D,kDAAiB,CAAA;AACrB,CAAC,EATW,6BAA6B,KAA7B,6BAA6B,QASxC;AAED,+CAA+C;AAC/C,MAAM,CAAN,IAAY,6BAKX;AALD,WAAY,6BAA6B;IACrC,uFAAuF;IACvF,gEAA+B,CAAA;IAC/B,0FAA0F;IAC1F,kDAAiB,CAAA;AACrB,CAAC,EALW,6BAA6B,KAA7B,6BAA6B,QAKxC;AAED,wDAAwD;AACxD,MAAM,CAAN,IAAY,wBAKX;AALD,WAAY,wBAAwB;IAChC,yEAAyE;IACzE,yDAA6B,CAAA;IAC7B,qDAAqD;IACrD,iEAAqC,CAAA;AACzC,CAAC,EALW,wBAAwB,KAAxB,wBAAwB,QAKnC;AAED;;;GAGG;AACH,MAAM,CAAN,IAAY,0BASX;AATD,WAAY,0BAA0B;IAClC,gDAAgD;IAChD,iDAAmB,CAAA;IACnB,sDAAsD;IACtD,2DAA6B,CAAA;IAC7B,gDAAgD;IAChD,yDAA2B,CAAA;IAC3B,mCAAmC;IACnC,mEAAqC,CAAA;AACzC,CAAC,EATW,0BAA0B,KAA1B,0BAA0B,QASrC"}
@@ -1,11 +1,16 @@
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 var SmsProviderName;
6
10
  (function (SmsProviderName) {
7
11
  SmsProviderName["TWILIO"] = "twilio";
8
12
  SmsProviderName["UWAZII"] = "uwazii";
9
13
  SmsProviderName["AFRICASTALKING"] = "africastalking";
14
+ SmsProviderName["CELCOM"] = "celcom";
10
15
  })(SmsProviderName || (SmsProviderName = {}));
11
16
  //# sourceMappingURL=sms-provider-name.enum.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sms-provider-name.enum.js","sourceRoot":"","sources":["../../../../../src/modules/notification/enums/sms-provider-name.enum.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAN,IAAY,eAIX;AAJD,WAAY,eAAe;IACvB,oCAAiB,CAAA;IACjB,oCAAiB,CAAA;IACjB,oDAAiC,CAAA;AACrC,CAAC,EAJW,eAAe,KAAf,eAAe,QAI1B"}
1
+ {"version":3,"file":"sms-provider-name.enum.js","sourceRoot":"","sources":["../../../../../src/modules/notification/enums/sms-provider-name.enum.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACvB,oCAAiB,CAAA;IACjB,oCAAiB,CAAA;IACjB,oDAAiC,CAAA;IACjC,oCAAiB,CAAA;AACrB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B"}
@@ -4,10 +4,15 @@ export * from './enums/sms-provider-name.enum';
4
4
  export * from './enums/email-provider-name.enum';
5
5
  export * from './enums/notification-overall-status.enum';
6
6
  export * from './enums/provider-failure-reason.enum';
7
+ export * from './enums/notification-settings.enums';
7
8
  // Result/interface contracts (display-safe)
8
9
  export * from './interfaces/provider-attempt';
9
10
  export * from './interfaces/per-channel-result';
10
11
  export * from './interfaces/sms-send-result';
11
12
  export * from './interfaces/email-send-result';
12
13
  export * from './interfaces/notification-dispatch-result';
14
+ // Organization notification settings (branding + sender identity)
15
+ export * from './interfaces/organization-notification-settings.dto';
16
+ // Utilities
17
+ export * from './utils/notification-sender.util';
13
18
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/notification/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AAErD,4CAA4C;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2CAA2C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/notification/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,mCAAmC,CAAC;AAClD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,0CAA0C,CAAC;AACzD,cAAc,sCAAsC,CAAC;AACrD,cAAc,qCAAqC,CAAC;AAEpD,4CAA4C;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,iCAAiC,CAAC;AAChD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2CAA2C,CAAC;AAE1D,kEAAkE;AAClE,cAAc,qDAAqD,CAAC;AAEpE,YAAY;AACZ,cAAc,kCAAkC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=organization-notification-settings.dto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"organization-notification-settings.dto.js","sourceRoot":"","sources":["../../../../../src/modules/notification/interfaces/organization-notification-settings.dto.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
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 const BRAND_COLOUR_PATTERN = /^#[0-9a-fA-F]{6}$/;
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 const SMS_SENDER_ID_PATTERNS = Object.freeze({
16
+ [SmsSenderType.ALPHANUMERIC]: /^(?=.*[A-Za-z])[A-Za-z0-9 _.&-]{3,11}$/,
17
+ [SmsSenderType.PHONE_NUMBER]: /^\+[1-9]\d{6,14}$/,
18
+ [SmsSenderType.SHORT_CODE]: /^\d{3,8}$/,
19
+ [SmsSenderType.MESSAGING_SERVICE]: /^MG[0-9a-fA-F]{32}$/,
20
+ });
21
+ /** Human-readable form of {@link SMS_SENDER_ID_PATTERNS}, for validation messages and form hints. */
22
+ export const SMS_SENDER_ID_HINTS = Object.freeze({
23
+ [SmsSenderType.ALPHANUMERIC]: '3-11 characters (letters, digits, space, _ . & -) with at least one letter, e.g. G4S',
24
+ [SmsSenderType.PHONE_NUMBER]: 'an E.164 number, e.g. +254711000000',
25
+ [SmsSenderType.SHORT_CODE]: '3-8 digits, e.g. 22384',
26
+ [SmsSenderType.MESSAGING_SERVICE]: 'a Twilio Messaging Service SID (MG followed by 32 hex characters)',
27
+ });
28
+ /** Upper bounds that keep one organization from turning its settings into a list to page through. */
29
+ export const MAX_EMAIL_SENDERS_PER_ORGANIZATION = 10;
30
+ export const MAX_SMS_SENDERS_PER_ORGANIZATION = 30;
31
+ /** Large text and UI components (WCAG 1.4.11): buttons and links in the primary colour. */
32
+ export const MIN_PRIMARY_COLOUR_CONTRAST = 3;
33
+ /** Body-size white text sits on the accent colour (WCAG 1.4.3). */
34
+ export const MIN_ACCENT_COLOUR_CONTRAST = 4.5;
35
+ /**
36
+ * Validates an SMS sender value against its declared type.
37
+ * Returns null when valid, otherwise a message fit to show an operator.
38
+ */
39
+ export function validateSmsSenderId(senderType, senderId) {
40
+ const pattern = SMS_SENDER_ID_PATTERNS[senderType];
41
+ if (!pattern)
42
+ return `Unsupported sender type: ${senderType}`;
43
+ const value = (senderId !== null && senderId !== void 0 ? senderId : '').trim();
44
+ if (!value)
45
+ return 'Sender ID is required';
46
+ return pattern.test(value) ? null : `A ${senderType} sender must be ${SMS_SENDER_ID_HINTS[senderType]}`;
47
+ }
48
+ /** The domain part of an email address, lower-cased. Null when there is none. */
49
+ export function emailDomainOf(address) {
50
+ const value = (address !== null && address !== void 0 ? address : '').trim().toLowerCase();
51
+ const at = value.lastIndexOf('@');
52
+ if (at <= 0 || at === value.length - 1)
53
+ return null;
54
+ return value.slice(at + 1);
55
+ }
56
+ /**
57
+ * WCAG contrast ratio of a `#RRGGBB` colour against white, from 1 (white) to 21
58
+ * (black). The email templates put WHITE text on the primary colour (buttons) and
59
+ * on the accent colour (header banner, footer), so a pale brand colour produces
60
+ * an email nobody can read. Returns 0 for anything that is not a hex colour.
61
+ */
62
+ export function contrastRatioWithWhite(hex) {
63
+ const match = /^#([0-9a-fA-F]{6})$/.exec((hex !== null && hex !== void 0 ? hex : '').trim());
64
+ if (!match)
65
+ return 0;
66
+ const [r, g, b] = [0, 2, 4].map(offset => {
67
+ const channel = parseInt(match[1].slice(offset, offset + 2), 16) / 255;
68
+ return channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
69
+ });
70
+ const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
71
+ return Math.round((1.05 / (luminance + 0.05)) * 100) / 100;
72
+ }
73
+ /**
74
+ * Darkens a `#RRGGBB` colour by a fraction (0-1). Used to derive the hover/pressed
75
+ * shade of a brand colour so an organization only has to choose one.
76
+ * Returns the input unchanged when it is not a valid hex colour.
77
+ */
78
+ export function darkenHexColour(hex, fraction = 0.15) {
79
+ const match = /^#([0-9a-fA-F]{6})$/.exec((hex !== null && hex !== void 0 ? hex : '').trim());
80
+ if (!match)
81
+ return hex;
82
+ const clamped = Math.min(Math.max(fraction, 0), 1);
83
+ const channels = [0, 2, 4].map(offset => {
84
+ const channel = parseInt(match[1].slice(offset, offset + 2), 16);
85
+ return Math.round(channel * (1 - clamped)).toString(16).padStart(2, '0');
86
+ });
87
+ return `#${channels.join('')}`;
88
+ }
89
+ //# sourceMappingURL=notification-sender.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-sender.util.js","sourceRoot":"","sources":["../../../../../src/modules/notification/utils/notification-sender.util.ts"],"names":[],"mappings":"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"}
@@ -106,5 +106,22 @@ export var PermissionActions;
106
106
  PermissionActions["READ_SUPPORT_REPORT"] = "read:support-report";
107
107
  PermissionActions["READ_SUPPORT_SYNC"] = "read:support-sync";
108
108
  PermissionActions["MANAGE_SUPPORT_SYNC"] = "manage:support-sync";
109
+ // Module: Notification
110
+ // An organization's notification settings (clarion-notification): how its
111
+ // emails are branded, the address they are sent from, and the sender ID its
112
+ // SMS arrive under. Mirrors grm-shared-library.
113
+ PermissionActions["READ_NOTIFICATION_SETTINGS"] = "read:notification-settings";
114
+ PermissionActions["MANAGE_NOTIFICATION_SETTINGS"] = "manage:notification-settings";
115
+ // Confirming that an SMS sender ID really is registered with the provider.
116
+ // Granted to NO role on the backend: only Super-Admin ('*') passes it.
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";
109
126
  })(PermissionActions || (PermissionActions = {}));
110
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,iBAmHX;AAnHD,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;AAC/C,CAAC,EAnHW,iBAAiB,KAAjB,iBAAiB,QAmH5B"}
1
+ {"version":3,"file":"permission-actions.enum.js","sourceRoot":"","sources":["../../../../../src/modules/permission/enums/permission-actions.enum.ts"],"names":[],"mappings":"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"}
@@ -10,5 +10,7 @@ export var PermissionsModule;
10
10
  PermissionsModule["RESPONSE_UNIT"] = "Response Unit";
11
11
  PermissionsModule["TRACKING"] = "Tracking";
12
12
  PermissionsModule["SUPPORT"] = "Support";
13
+ PermissionsModule["NOTIFICATION"] = "Notification";
14
+ PermissionsModule["ALERT_INTAKE"] = "Alert Intake";
13
15
  })(PermissionsModule || (PermissionsModule = {}));
14
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,iBAWX;AAXD,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;AACvB,CAAC,EAXW,iBAAiB,KAAjB,iBAAiB,QAW5B"}
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"}
@@ -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,83 @@
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
+ }
@@ -0,0 +1,3 @@
1
+ export * from './enums/alert-intake.enum';
2
+ export * from './interfaces/alert-intake';
3
+ export * from './utils/alert-intake.util';