grm-shared-library 1.1.246 → 1.1.248
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/dist/cjs/kafka/dtos/user/guardians-changed-payload.dto.js +66 -0
- package/dist/cjs/kafka/dtos/user/guardians-changed-payload.dto.js.map +1 -0
- package/dist/cjs/kafka/index.js +1 -0
- package/dist/cjs/kafka/index.js.map +1 -1
- package/dist/cjs/kafka/topics.js +4 -0
- package/dist/cjs/kafka/topics.js.map +1 -1
- package/dist/cjs/modules/user/dtos/guardian-identifier.dto.js +2 -2
- package/dist/cjs/modules/user/dtos/guardian-identifier.dto.js.map +1 -1
- package/dist/cjs/modules/user/index.js +1 -0
- package/dist/cjs/modules/user/index.js.map +1 -1
- package/dist/cjs/modules/user/utils/app-account.util.js +90 -0
- package/dist/cjs/modules/user/utils/app-account.util.js.map +1 -0
- package/dist/esm/kafka/dtos/user/guardians-changed-payload.dto.js +62 -0
- package/dist/esm/kafka/dtos/user/guardians-changed-payload.dto.js.map +1 -0
- package/dist/esm/kafka/index.js +1 -0
- package/dist/esm/kafka/index.js.map +1 -1
- package/dist/esm/kafka/topics.js +4 -0
- package/dist/esm/kafka/topics.js.map +1 -1
- package/dist/esm/modules/user/dtos/guardian-identifier.dto.js +2 -2
- package/dist/esm/modules/user/dtos/guardian-identifier.dto.js.map +1 -1
- package/dist/esm/modules/user/index.js +1 -0
- package/dist/esm/modules/user/index.js.map +1 -1
- package/dist/esm/modules/user/utils/app-account.util.js +83 -0
- package/dist/esm/modules/user/utils/app-account.util.js.map +1 -0
- package/dist/types/kafka/dtos/user/guardians-changed-payload.dto.d.ts +32 -0
- package/dist/types/kafka/index.d.ts +1 -0
- package/dist/types/kafka/topics.d.ts +1 -0
- package/dist/types/modules/user/index.d.ts +1 -0
- package/dist/types/modules/user/interfaces/account-analytics.d.ts +184 -8
- package/dist/types/modules/user/interfaces/guardian.d.ts +7 -0
- package/dist/types/modules/user/utils/app-account.util.d.ts +59 -0
- package/package.json +72 -72
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GuardiansChangedPayloadDto = exports.GuardiansChangedReason = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
/** What changed about somebody's guardians - for logs and analytics; every reason means "refresh". */
|
|
15
|
+
var GuardiansChangedReason;
|
|
16
|
+
(function (GuardiansChangedReason) {
|
|
17
|
+
/** A guardian was added. */
|
|
18
|
+
GuardiansChangedReason["ADDED"] = "ADDED";
|
|
19
|
+
/** A guardian was removed by the person they guard. */
|
|
20
|
+
GuardiansChangedReason["REMOVED"] = "REMOVED";
|
|
21
|
+
/** Another guardian became the primary one. */
|
|
22
|
+
GuardiansChangedReason["PRIMARY_CHANGED"] = "PRIMARY_CHANGED";
|
|
23
|
+
/** A guardian on the list by phone number proved that number in the same organization's app, and is now an app guardian. */
|
|
24
|
+
GuardiansChangedReason["PROMOTED"] = "PROMOTED";
|
|
25
|
+
/** An app guardian's account was deleted; they stay on the list by phone number. */
|
|
26
|
+
GuardiansChangedReason["DEMOTED"] = "DEMOTED";
|
|
27
|
+
/** A guardian stopped looking after one of their dependents. */
|
|
28
|
+
GuardiansChangedReason["DEPENDENT_REMOVED"] = "DEPENDENT_REMOVED";
|
|
29
|
+
})(GuardiansChangedReason || (exports.GuardiansChangedReason = GuardiansChangedReason = {}));
|
|
30
|
+
/**
|
|
31
|
+
* Payload of `KAFKA_TOPICS.GUARDIANS_CHANGED`: somebody's guardian list changed,
|
|
32
|
+
* and these people's apps should read their guardians and dependents again.
|
|
33
|
+
*
|
|
34
|
+
* Ids only - no names, numbers or relationships. The apps read the lists through
|
|
35
|
+
* the guardian API, which applies its own access rules.
|
|
36
|
+
*/
|
|
37
|
+
class GuardiansChangedPayloadDto {
|
|
38
|
+
}
|
|
39
|
+
exports.GuardiansChangedPayloadDto = GuardiansChangedPayloadDto;
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, class_validator_1.IsInt)(),
|
|
42
|
+
(0, class_validator_1.IsPositive)(),
|
|
43
|
+
__metadata("design:type", Number)
|
|
44
|
+
], GuardiansChangedPayloadDto.prototype, "organizationId", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, class_validator_1.IsInt)(),
|
|
47
|
+
(0, class_validator_1.IsPositive)(),
|
|
48
|
+
__metadata("design:type", Number)
|
|
49
|
+
], GuardiansChangedPayloadDto.prototype, "dependentId", void 0);
|
|
50
|
+
__decorate([
|
|
51
|
+
(0, class_validator_1.IsArray)(),
|
|
52
|
+
(0, class_validator_1.ArrayMinSize)(1),
|
|
53
|
+
(0, class_validator_1.ArrayMaxSize)(100),
|
|
54
|
+
(0, class_validator_1.IsInt)({ each: true }),
|
|
55
|
+
(0, class_validator_1.IsPositive)({ each: true }),
|
|
56
|
+
__metadata("design:type", Array)
|
|
57
|
+
], GuardiansChangedPayloadDto.prototype, "userIds", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, class_validator_1.IsEnum)(GuardiansChangedReason),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], GuardiansChangedPayloadDto.prototype, "reason", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
(0, class_validator_1.IsISO8601)(),
|
|
64
|
+
__metadata("design:type", String)
|
|
65
|
+
], GuardiansChangedPayloadDto.prototype, "occurredAt", void 0);
|
|
66
|
+
//# sourceMappingURL=guardians-changed-payload.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardians-changed-payload.dto.js","sourceRoot":"","sources":["../../../../../src/kafka/dtos/user/guardians-changed-payload.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA4G;AAE5G,sGAAsG;AACtG,IAAY,sBAaX;AAbD,WAAY,sBAAsB;IAC9B,4BAA4B;IAC5B,yCAAe,CAAA;IACf,uDAAuD;IACvD,6CAAmB,CAAA;IACnB,+CAA+C;IAC/C,6DAAmC,CAAA;IACnC,4HAA4H;IAC5H,+CAAqB,CAAA;IACrB,oFAAoF;IACpF,6CAAmB,CAAA;IACnB,gEAAgE;IAChE,iEAAuC,CAAA;AAC3C,CAAC,EAbW,sBAAsB,sCAAtB,sBAAsB,QAajC;AAED;;;;;;GAMG;AACH,MAAa,0BAA0B;CAwBtC;AAxBD,gEAwBC;AApBG;IAFC,IAAA,uBAAK,GAAE;IACP,IAAA,4BAAU,GAAE;;kEACW;AAKxB;IAFC,IAAA,uBAAK,GAAE;IACP,IAAA,4BAAU,GAAE;;+DACQ;AAQrB;IALC,IAAA,yBAAO,GAAE;IACT,IAAA,8BAAY,EAAC,CAAC,CAAC;IACf,IAAA,8BAAY,EAAC,GAAG,CAAC;IACjB,IAAA,uBAAK,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACrB,IAAA,4BAAU,EAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;;2DACR;AAGnB;IADC,IAAA,wBAAM,EAAC,sBAAsB,CAAC;;0DACC;AAGhC;IADC,IAAA,2BAAS,GAAE;;8DACQ"}
|
package/dist/cjs/kafka/index.js
CHANGED
|
@@ -24,4 +24,5 @@ __exportStar(require("./dtos/otp/create-otp-payload.dto"), exports);
|
|
|
24
24
|
__exportStar(require("./dtos/otp/otp-payload.dto"), exports);
|
|
25
25
|
__exportStar(require("./dtos/password/password-reset-payload.dto"), exports);
|
|
26
26
|
__exportStar(require("./dtos/account-deletion/account-deletion-request-payload.dto"), exports);
|
|
27
|
+
__exportStar(require("./dtos/user/guardians-changed-payload.dto"), exports);
|
|
27
28
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/kafka/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,mDAAiC;AACjC,8EAA4D;AAC5D,uEAAqD;AACrD,iFAA+D;AAC/D,0EAAwD;AACxD,oEAAkD;AAClD,6DAA2C;AAC3C,6EAA2D;AAC3D,+FAA6E"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/kafka/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,mDAAiC;AACjC,8EAA4D;AAC5D,uEAAqD;AACrD,iFAA+D;AAC/D,0EAAwD;AACxD,oEAAkD;AAClD,6DAA2C;AAC3C,6EAA2D;AAC3D,+FAA6E;AAC7E,4EAA0D"}
|
package/dist/cjs/kafka/topics.js
CHANGED
|
@@ -12,6 +12,10 @@ exports.KAFKA_TOPICS = {
|
|
|
12
12
|
USER_CREATED: 'user.created',
|
|
13
13
|
USER_UPDATED: 'user.updated',
|
|
14
14
|
USER_DELETED: 'user.deleted',
|
|
15
|
+
// Somebody's guardians or dependents changed (producer: clarion-authentication;
|
|
16
|
+
// payload GuardiansChangedPayloadDto; consumer: clarion-notification, which
|
|
17
|
+
// sends each affected person a silent push so their app refreshes). Ids only.
|
|
18
|
+
GUARDIANS_CHANGED: 'user.guardians.changed.v1',
|
|
15
19
|
// Org. ORG_CREATED is published by clarion-organization after commit
|
|
16
20
|
// (payload OrganizationCreatedEvent); clarion-incident provisions the Safety
|
|
17
21
|
// Alerts category from it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../../../src/kafka/topics.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../../../src/kafka/topics.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ class GuardianIdentifierDto {
|
|
|
17
17
|
exports.GuardianIdentifierDto = GuardianIdentifierDto;
|
|
18
18
|
__decorate([
|
|
19
19
|
(0, swagger_1.ApiProperty)({
|
|
20
|
-
description: 'Phone number
|
|
20
|
+
description: 'Phone number of an external guardian (older apps). Prefer relationshipId, which names either kind.',
|
|
21
21
|
example: '+1234567890',
|
|
22
22
|
required: false,
|
|
23
23
|
type: 'string'
|
|
@@ -28,7 +28,7 @@ __decorate([
|
|
|
28
28
|
], GuardianIdentifierDto.prototype, "phoneNumber", void 0);
|
|
29
29
|
__decorate([
|
|
30
30
|
(0, swagger_1.ApiProperty)({
|
|
31
|
-
description: '
|
|
31
|
+
description: 'The guardian entry id - `id` of an app-user guardian relation or of an external guardian (since grm-shared-library 1.1.248)',
|
|
32
32
|
example: 789,
|
|
33
33
|
required: false,
|
|
34
34
|
type: 'number'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guardian-identifier.dto.js","sourceRoot":"","sources":["../../../../../src/modules/user/dtos/guardian-identifier.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA8C;AAC9C,qDAA6E;AAE7E,MAAa,qBAAqB;CAoBjC;AApBD,sDAoBC;AAXG;IARC,IAAA,qBAAW,EAAC;QACT,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"guardian-identifier.dto.js","sourceRoot":"","sources":["../../../../../src/modules/user/dtos/guardian-identifier.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA8C;AAC9C,qDAA6E;AAE7E,MAAa,qBAAqB;CAoBjC;AApBD,sDAoBC;AAXG;IARC,IAAA,qBAAW,EAAC;QACT,WAAW,EAAE,oGAAoG;QACjH,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,QAAQ;KACjB,CAAC;IACD,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;0DACQ;AAUrB;IARC,IAAA,qBAAW,EAAC;QACT,WAAW,EAAE,6HAA6H;QAC1I,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,QAAQ;KACjB,CAAC;IACD,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;6DACW"}
|
|
@@ -32,4 +32,5 @@ __exportStar(require("./interfaces/guardian"), exports);
|
|
|
32
32
|
__exportStar(require("./interfaces/guardian-relation"), exports);
|
|
33
33
|
__exportStar(require("./interfaces/guardians-response"), exports);
|
|
34
34
|
__exportStar(require("./interfaces/account-analytics"), exports);
|
|
35
|
+
__exportStar(require("./utils/app-account.util"), exports);
|
|
35
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/user/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,yDAAuC;AACvC,sDAAoC;AACpC,iEAA+C;AAC/C,sEAAoD;AACpD,6EAA2D;AAC3D,+EAA6D;AAC7D,yEAAuD;AAEvD,2DAAyC;AACzC,qEAAmD;AACnD,wEAAsD;AAEtD,oDAAkC;AAClC,4DAA0C;AAC1C,4DAA0C;AAC1C,wDAAsC;AACtC,iEAA+C;AAC/C,kEAAgD;AAChD,iEAA+C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/user/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,yDAAuC;AACvC,sDAAoC;AACpC,iEAA+C;AAC/C,sEAAoD;AACpD,6EAA2D;AAC3D,+EAA6D;AAC7D,yEAAuD;AAEvD,2DAAyC;AACzC,qEAAmD;AACnD,wEAAsD;AAEtD,oDAAkC;AAClC,4DAA0C;AAC1C,4DAA0C;AAC1C,wDAAsC;AACtC,iEAA+C;AAC/C,kEAAgD;AAChD,iEAA+C;AAE/C,2DAAyC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.APP_ACCOUNT_ERROR_CODES = exports.APP_ACCOUNT_ROLE = void 0;
|
|
4
|
+
exports.isAppAccount = isAppAccount;
|
|
5
|
+
exports.hasAppRole = hasAppRole;
|
|
6
|
+
exports.parseAppOrganizations = parseAppOrganizations;
|
|
7
|
+
exports.isAccountFromAnotherApp = isAccountFromAnotherApp;
|
|
8
|
+
const role_enum_1 = require("../../role/enums/role.enum");
|
|
9
|
+
/**
|
|
10
|
+
* App accounts and staff accounts.
|
|
11
|
+
*
|
|
12
|
+
* Each brand's mobile app (G4S Kenya, GeoSHIELD, SGA Security, ...) is its own
|
|
13
|
+
* product for one organization's customers, so an account made in one app is an
|
|
14
|
+
* account with that organization only. Signing in to another brand's app means
|
|
15
|
+
* registering with that brand. One person may therefore hold several app
|
|
16
|
+
* accounts - one per organization - with the same phone number and e-mail.
|
|
17
|
+
*
|
|
18
|
+
* Staff (Super-Admin, organization and control-centre staff, responders,
|
|
19
|
+
* corporate-client admins) keep one platform-wide account each: their e-mail and
|
|
20
|
+
* phone number stay unique across the whole platform.
|
|
21
|
+
*
|
|
22
|
+
* An APP ACCOUNT is one whose only role is Mobile-User. That is the same rule the
|
|
23
|
+
* database's unique indexes use (`roles = '{Mobile-User}'`), so code and schema
|
|
24
|
+
* can never disagree about which kind an account is. An account holding
|
|
25
|
+
* Mobile-User beside a staff role is a staff account that also uses an app.
|
|
26
|
+
*/
|
|
27
|
+
exports.APP_ACCOUNT_ROLE = role_enum_1.Roles.MOBILE_USER;
|
|
28
|
+
/** An account whose only role is Mobile-User: unique within its organization, not platform-wide. */
|
|
29
|
+
function isAppAccount(roles) {
|
|
30
|
+
return Array.isArray(roles) && roles.length === 1 && roles[0] === exports.APP_ACCOUNT_ROLE;
|
|
31
|
+
}
|
|
32
|
+
/** Holds the Mobile-User role, alone or beside staff roles: someone who can use a brand's app. */
|
|
33
|
+
function hasAppRole(roles) {
|
|
34
|
+
return Array.isArray(roles) && roles.includes(exports.APP_ACCOUNT_ROLE);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parses `APP_ORGANIZATIONS`. Blank means "none configured". A malformed entry
|
|
38
|
+
* throws: a typo here would let an app sign people in to the wrong organization,
|
|
39
|
+
* so it must stop the service at boot rather than be skipped.
|
|
40
|
+
*/
|
|
41
|
+
function parseAppOrganizations(raw) {
|
|
42
|
+
const map = new Map();
|
|
43
|
+
for (const entry of String(raw !== null && raw !== void 0 ? raw : '').split(',')) {
|
|
44
|
+
const trimmed = entry.trim();
|
|
45
|
+
if (!trimmed)
|
|
46
|
+
continue;
|
|
47
|
+
const match = /^([A-Za-z0-9_-]+)\s*:\s*(\d+)$/.exec(trimmed);
|
|
48
|
+
if (!match)
|
|
49
|
+
throw new Error(`APP_ORGANIZATIONS: "${trimmed}" is not <appId>:<organizationId>`);
|
|
50
|
+
const [, appId, id] = match;
|
|
51
|
+
const organizationId = Number(id);
|
|
52
|
+
if (!Number.isSafeInteger(organizationId) || organizationId <= 0) {
|
|
53
|
+
throw new Error(`APP_ORGANIZATIONS: "${trimmed}" names no valid organization`);
|
|
54
|
+
}
|
|
55
|
+
const existing = map.get(appId);
|
|
56
|
+
if (existing !== undefined && existing !== organizationId) {
|
|
57
|
+
throw new Error(`APP_ORGANIZATIONS: ${appId} is given two organizations (${existing} and ${organizationId})`);
|
|
58
|
+
}
|
|
59
|
+
map.set(appId, organizationId);
|
|
60
|
+
}
|
|
61
|
+
return map;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Whether a signed-in account is being used from another organization's app: the
|
|
65
|
+
* request names an app (`X-App-Id`) that belongs to organization A, and the account
|
|
66
|
+
* is an app user of organization B.
|
|
67
|
+
*
|
|
68
|
+
* Unknown here means "not a mismatch": no app named, an app with no configured
|
|
69
|
+
* organization, or an account that is staff only. Those keep working as before.
|
|
70
|
+
*/
|
|
71
|
+
function isAccountFromAnotherApp(appOrganizations, appId, account) {
|
|
72
|
+
if (!appId)
|
|
73
|
+
return false;
|
|
74
|
+
const expected = appOrganizations.get(appId);
|
|
75
|
+
if (expected === undefined)
|
|
76
|
+
return false;
|
|
77
|
+
if (!hasAppRole(account.roles))
|
|
78
|
+
return false;
|
|
79
|
+
return Number(account.organizationId) !== expected;
|
|
80
|
+
}
|
|
81
|
+
/** Error codes a client can act on, for the account rules above. */
|
|
82
|
+
exports.APP_ACCOUNT_ERROR_CODES = {
|
|
83
|
+
/** A token or session belongs to another organization's app: sign out and sign in again here. */
|
|
84
|
+
APP_ACCOUNT_MISMATCH: 'APP_ACCOUNT_MISMATCH',
|
|
85
|
+
/** A sign-in names an app and an organization that do not belong together. */
|
|
86
|
+
APP_ORGANIZATION_MISMATCH: 'APP_ORGANIZATION_MISMATCH',
|
|
87
|
+
/** An older app asked for "the" account of a number that has accounts with several organizations. */
|
|
88
|
+
ACCOUNT_AMBIGUOUS: 'ACCOUNT_AMBIGUOUS',
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=app-account.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-account.util.js","sourceRoot":"","sources":["../../../../../src/modules/user/utils/app-account.util.ts"],"names":[],"mappings":";;;AAuBA,oCAEC;AAGD,gCAEC;AAeD,sDAmBC;AAUD,0DAUC;AApFD,0DAAmD;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AACU,QAAA,gBAAgB,GAAG,iBAAK,CAAC,WAAW,CAAC;AAElD,oGAAoG;AACpG,SAAgB,YAAY,CAAC,KAA2C;IACpE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,wBAAgB,CAAC;AACvF,CAAC;AAED,kGAAkG;AAClG,SAAgB,UAAU,CAAC,KAA2C;IAClE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,wBAAgB,CAAC,CAAC;AACpE,CAAC;AAUD;;;;GAIG;AACH,SAAgB,qBAAqB,CAAC,GAA8B;IAChE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,mCAAmC,CAAC,CAAC;QAC/F,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;QAC5B,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,+BAA+B,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,gCAAgC,QAAQ,QAAQ,cAAc,GAAG,CAAC,CAAC;QAClH,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,uBAAuB,CACnC,gBAAkC,EAClC,KAAgC,EAChC,OAAsF;IAEtF,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC;AACvD,CAAC;AAED,oEAAoE;AACvD,QAAA,uBAAuB,GAAG;IACnC,iGAAiG;IACjG,oBAAoB,EAAE,sBAAsB;IAC5C,8EAA8E;IAC9E,yBAAyB,EAAE,2BAA2B;IACtD,qGAAqG;IACrG,iBAAiB,EAAE,mBAAmB;CAChC,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { ArrayMaxSize, ArrayMinSize, IsArray, IsEnum, IsInt, IsISO8601, IsPositive } from "class-validator";
|
|
11
|
+
/** What changed about somebody's guardians - for logs and analytics; every reason means "refresh". */
|
|
12
|
+
export var GuardiansChangedReason;
|
|
13
|
+
(function (GuardiansChangedReason) {
|
|
14
|
+
/** A guardian was added. */
|
|
15
|
+
GuardiansChangedReason["ADDED"] = "ADDED";
|
|
16
|
+
/** A guardian was removed by the person they guard. */
|
|
17
|
+
GuardiansChangedReason["REMOVED"] = "REMOVED";
|
|
18
|
+
/** Another guardian became the primary one. */
|
|
19
|
+
GuardiansChangedReason["PRIMARY_CHANGED"] = "PRIMARY_CHANGED";
|
|
20
|
+
/** A guardian on the list by phone number proved that number in the same organization's app, and is now an app guardian. */
|
|
21
|
+
GuardiansChangedReason["PROMOTED"] = "PROMOTED";
|
|
22
|
+
/** An app guardian's account was deleted; they stay on the list by phone number. */
|
|
23
|
+
GuardiansChangedReason["DEMOTED"] = "DEMOTED";
|
|
24
|
+
/** A guardian stopped looking after one of their dependents. */
|
|
25
|
+
GuardiansChangedReason["DEPENDENT_REMOVED"] = "DEPENDENT_REMOVED";
|
|
26
|
+
})(GuardiansChangedReason || (GuardiansChangedReason = {}));
|
|
27
|
+
/**
|
|
28
|
+
* Payload of `KAFKA_TOPICS.GUARDIANS_CHANGED`: somebody's guardian list changed,
|
|
29
|
+
* and these people's apps should read their guardians and dependents again.
|
|
30
|
+
*
|
|
31
|
+
* Ids only - no names, numbers or relationships. The apps read the lists through
|
|
32
|
+
* the guardian API, which applies its own access rules.
|
|
33
|
+
*/
|
|
34
|
+
export class GuardiansChangedPayloadDto {
|
|
35
|
+
}
|
|
36
|
+
__decorate([
|
|
37
|
+
IsInt(),
|
|
38
|
+
IsPositive(),
|
|
39
|
+
__metadata("design:type", Number)
|
|
40
|
+
], GuardiansChangedPayloadDto.prototype, "organizationId", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
IsInt(),
|
|
43
|
+
IsPositive(),
|
|
44
|
+
__metadata("design:type", Number)
|
|
45
|
+
], GuardiansChangedPayloadDto.prototype, "dependentId", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
IsArray(),
|
|
48
|
+
ArrayMinSize(1),
|
|
49
|
+
ArrayMaxSize(100),
|
|
50
|
+
IsInt({ each: true }),
|
|
51
|
+
IsPositive({ each: true }),
|
|
52
|
+
__metadata("design:type", Array)
|
|
53
|
+
], GuardiansChangedPayloadDto.prototype, "userIds", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
IsEnum(GuardiansChangedReason),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], GuardiansChangedPayloadDto.prototype, "reason", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
IsISO8601(),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], GuardiansChangedPayloadDto.prototype, "occurredAt", void 0);
|
|
62
|
+
//# sourceMappingURL=guardians-changed-payload.dto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guardians-changed-payload.dto.js","sourceRoot":"","sources":["../../../../../src/kafka/dtos/user/guardians-changed-payload.dto.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE5G,sGAAsG;AACtG,MAAM,CAAN,IAAY,sBAaX;AAbD,WAAY,sBAAsB;IAC9B,4BAA4B;IAC5B,yCAAe,CAAA;IACf,uDAAuD;IACvD,6CAAmB,CAAA;IACnB,+CAA+C;IAC/C,6DAAmC,CAAA;IACnC,4HAA4H;IAC5H,+CAAqB,CAAA;IACrB,oFAAoF;IACpF,6CAAmB,CAAA;IACnB,gEAAgE;IAChE,iEAAuC,CAAA;AAC3C,CAAC,EAbW,sBAAsB,KAAtB,sBAAsB,QAajC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,0BAA0B;CAwBtC;AApBG;IAFC,KAAK,EAAE;IACP,UAAU,EAAE;;kEACW;AAKxB;IAFC,KAAK,EAAE;IACP,UAAU,EAAE;;+DACQ;AAQrB;IALC,OAAO,EAAE;IACT,YAAY,CAAC,CAAC,CAAC;IACf,YAAY,CAAC,GAAG,CAAC;IACjB,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;;2DACR;AAGnB;IADC,MAAM,CAAC,sBAAsB,CAAC;;0DACC;AAGhC;IADC,SAAS,EAAE;;8DACQ"}
|
package/dist/esm/kafka/index.js
CHANGED
|
@@ -8,4 +8,5 @@ export * from './dtos/otp/create-otp-payload.dto';
|
|
|
8
8
|
export * from './dtos/otp/otp-payload.dto';
|
|
9
9
|
export * from './dtos/password/password-reset-payload.dto';
|
|
10
10
|
export * from './dtos/account-deletion/account-deletion-request-payload.dto';
|
|
11
|
+
export * from './dtos/user/guardians-changed-payload.dto';
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/kafka/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,sCAAsC,CAAC;AACrD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8DAA8D,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/kafka/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,kBAAkB,CAAC;AACjC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,sCAAsC,CAAC;AACrD,cAAc,gDAAgD,CAAC;AAC/D,cAAc,yCAAyC,CAAC;AACxD,cAAc,mCAAmC,CAAC;AAClD,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8DAA8D,CAAC;AAC7E,cAAc,2CAA2C,CAAC"}
|
package/dist/esm/kafka/topics.js
CHANGED
|
@@ -9,6 +9,10 @@ export const KAFKA_TOPICS = {
|
|
|
9
9
|
USER_CREATED: 'user.created',
|
|
10
10
|
USER_UPDATED: 'user.updated',
|
|
11
11
|
USER_DELETED: 'user.deleted',
|
|
12
|
+
// Somebody's guardians or dependents changed (producer: clarion-authentication;
|
|
13
|
+
// payload GuardiansChangedPayloadDto; consumer: clarion-notification, which
|
|
14
|
+
// sends each affected person a silent push so their app refreshes). Ids only.
|
|
15
|
+
GUARDIANS_CHANGED: 'user.guardians.changed.v1',
|
|
12
16
|
// Org. ORG_CREATED is published by clarion-organization after commit
|
|
13
17
|
// (payload OrganizationCreatedEvent); clarion-incident provisions the Safety
|
|
14
18
|
// Alerts category from it.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../../../src/kafka/topics.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GAAG;IACxB,OAAO;IACP,eAAe,EAAE,iBAAiB;IAClC,cAAc,EAAE,gBAAgB;IAChC,eAAe,EAAE,iBAAiB;IAClC,6BAA6B,EAAE,+BAA+B;IAC9D,6BAA6B,EAAE,+BAA+B;IAC9D,OAAO;IACP,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,YAAY,EAAE,cAAc;IAC5B,qEAAqE;IACrE,6EAA6E;IAC7E,2BAA2B;IAC3B,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,aAAa;IAC1B,WAAW,EAAE,aAAa;IAC1B,MAAM;IACN,YAAY,EAAE,eAAe;IAC7B,aAAa,EAAE,eAAe;IAC9B,WAAW;IACX,cAAc,EAAE,gBAAgB;IAChC,WAAW;IACX,gBAAgB,EAAE,kBAAkB;IACpC,gBAAgB,EAAE,kBAAkB;IACpC,uBAAuB,EAAE,yBAAyB;IAClD,sBAAsB,EAAE,wBAAwB;IAChD,yBAAyB,EAAE,2BAA2B;IACtD,wBAAwB,EAAE,0BAA0B;IACpD,0BAA0B,EAAE,4BAA4B;IACxD,sBAAsB,EAAE,wBAAwB;IAChD,iBAAiB,EAAE,mBAAmB;IACtC,2BAA2B,EAAE,6BAA6B;IAC1D,yCAAyC,EAAE,2CAA2C;IACtF,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,uCAAuC,EAAE,4CAA4C;IACrF,8CAA8C,EAAE,mDAAmD;IACnG,sDAAsD,EAClD,2DAA2D;IAC/D,qEAAqE;IACrE,+BAA+B;IAC/B,0CAA0C,EAAE,4DAA4D;IACxG,OAAO;IACP,oBAAoB,EAAE,sBAAsB;IAC5C,yBAAyB,EAAE,2BAA2B;IACtD,qBAAqB,EAAE,uBAAuB;IAC9C,OAAO;IACP,YAAY,EAAE,cAAc;IAC5B,UAAU,EAAE,YAAY;IACxB,WAAW,EAAE,aAAa;IAC1B,OAAO;IACP,iBAAiB,EAAE,mBAAmB;IACtC,oBAAoB,EAAE,sBAAsB;IAC5C,WAAW;IACX,qBAAqB,EAAE,uBAAuB;IAC9C,uBAAuB,EAAE,yBAAyB;IAClD,qBAAqB,EAAE,uBAAuB;IAC9C,sBAAsB,EAAE,wBAAwB;IAChD,qBAAqB,EAAE,uBAAuB;IAC9C,mBAAmB,EAAE,qBAAqB;IAC1C,qBAAqB,EAAE,uBAAuB;IAC9C,oBAAoB,EAAE,sBAAsB;IAC5C,wBAAwB,EAAE,0BAA0B;IACpD,wBAAwB,EAAE,0BAA0B;IACpD,wBAAwB,EAAE,0BAA0B;IACpD,iEAAiE;IACjE,iBAAiB,EAAE,oCAAoC;IACvD,eAAe,EAAE,kCAAkC;IACnD,wBAAwB,EAAE,6BAA6B;IACvD,wBAAwB,EAAE,6BAA6B;IACvD,wBAAwB,EAAE,6BAA6B;IACvD,wEAAwE;IACxE,+DAA+D;IAC/D,yBAAyB,EAAE,uCAAuC;IAClE,yBAAyB,EAAE,uCAAuC;IAClE,yBAAyB,EAAE,uCAAuC;IAClE,wCAAwC,EACpC,sDAAsD;IAC1D,gCAAgC,EAAE,8CAA8C;IAChF,iFAAiF;IACjF,wBAAwB,EAAE,6BAA6B;IACvD,+BAA+B,EAAE,oCAAoC;IACrE,iFAAiF;IACjF,2EAA2E;IAC3E,4EAA4E;IAC5E,2EAA2E;IAC3E,iEAAiE;IACjE,sBAAsB,EAAE,2BAA2B;IACnD,sBAAsB,EAAE,2BAA2B;IACnD,uBAAuB,EAAE,4BAA4B;IACrD,6BAA6B,EAAE,kCAAkC;IACjE,+BAA+B,EAAE,oCAAoC;IACrE,8BAA8B,EAAE,mCAAmC;IACnE,+BAA+B,EAAE,oCAAoC;IACrE,4BAA4B,EAAE,iCAAiC;IAC/D,uBAAuB,EAAE,4BAA4B;IACrD,qBAAqB,EAAE,0BAA0B;IACjD,uBAAuB,EAAE,4BAA4B;IACrD,0BAA0B,EAAE,+BAA+B;IAC3D,2BAA2B,EAAE,gCAAgC;IAC7D,wBAAwB,EAAE,6BAA6B;IACvD,wBAAwB,EAAE,6BAA6B;IACvD,yBAAyB,EAAE,8BAA8B;IACzD,0BAA0B,EAAE,+BAA+B;IAC3D,oCAAoC,EAAE,yCAAyC;IAC/E,iCAAiC,EAAE,sCAAsC;IACzE,4BAA4B,EAAE,iCAAiC;IAC/D,+BAA+B,EAAE,oCAAoC;IACrE,wEAAwE;IACxE,8EAA8E;IAC9E,mDAAmD;IACnD,oBAAoB,EAAE,yBAAyB;IAC/C,sBAAsB,EAAE,2BAA2B;IACnD,kBAAkB,EAAE,uBAAuB;IAC3C,0BAA0B,EAAE,+BAA+B;IAC3D,+EAA+E;IAC/E,8DAA8D;IAC9D,iBAAiB,EAAE,6BAA6B;IAChD,4BAA4B,EAAE,wCAAwC;IACtE,mBAAmB,EAAE,+BAA+B;IACpD,uBAAuB,EAAE,mCAAmC;IAC5D,eAAe,EAAE,2BAA2B;IAC5C,2EAA2E;IAC3E,uEAAuE;IACvE,6EAA6E;IAC7E,+BAA+B;IAC/B,qCAAqC,EAAE,0CAA0C;IACjF,oBAAoB,EAAE,yBAAyB;IAC/C,8BAA8B,EAAE,mCAAmC;IACnE,0EAA0E;IAC1E,0EAA0E;IAC1E,yCAAyC,EAAE,8CAA8C;IACzF,sCAAsC,EAAE,wDAAwD;CACnG,CAAC"}
|
|
1
|
+
{"version":3,"file":"topics.js","sourceRoot":"","sources":["../../../src/kafka/topics.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@ export class GuardianIdentifierDto {
|
|
|
13
13
|
}
|
|
14
14
|
__decorate([
|
|
15
15
|
ApiProperty({
|
|
16
|
-
description: 'Phone number
|
|
16
|
+
description: 'Phone number of an external guardian (older apps). Prefer relationshipId, which names either kind.',
|
|
17
17
|
example: '+1234567890',
|
|
18
18
|
required: false,
|
|
19
19
|
type: 'string'
|
|
@@ -24,7 +24,7 @@ __decorate([
|
|
|
24
24
|
], GuardianIdentifierDto.prototype, "phoneNumber", void 0);
|
|
25
25
|
__decorate([
|
|
26
26
|
ApiProperty({
|
|
27
|
-
description: '
|
|
27
|
+
description: 'The guardian entry id - `id` of an app-user guardian relation or of an external guardian (since grm-shared-library 1.1.248)',
|
|
28
28
|
example: 789,
|
|
29
29
|
required: false,
|
|
30
30
|
type: 'number'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guardian-identifier.dto.js","sourceRoot":"","sources":["../../../../../src/modules/user/dtos/guardian-identifier.dto.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAc,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7E,MAAM,OAAO,qBAAqB;CAoBjC;AAXG;IARC,WAAW,CAAC;QACT,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"guardian-identifier.dto.js","sourceRoot":"","sources":["../../../../../src/modules/user/dtos/guardian-identifier.dto.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAc,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE7E,MAAM,OAAO,qBAAqB;CAoBjC;AAXG;IARC,WAAW,CAAC;QACT,WAAW,EAAE,oGAAoG;QACjH,OAAO,EAAE,aAAa;QACtB,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,QAAQ;KACjB,CAAC;IACD,QAAQ,EAAE;IACV,UAAU,EAAE;;0DACQ;AAUrB;IARC,WAAW,CAAC;QACT,WAAW,EAAE,6HAA6H;QAC1I,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,QAAQ;KACjB,CAAC;IACD,QAAQ,EAAE;IACV,UAAU,EAAE;;6DACW"}
|
|
@@ -16,4 +16,5 @@ export * from './interfaces/guardian';
|
|
|
16
16
|
export * from './interfaces/guardian-relation';
|
|
17
17
|
export * from './interfaces/guardians-response';
|
|
18
18
|
export * from './interfaces/account-analytics';
|
|
19
|
+
export * from './utils/app-account.util';
|
|
19
20
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/user/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,wCAAwC,CAAC;AAEvD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/user/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qCAAqC,CAAC;AACpD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,8CAA8C,CAAC;AAC7D,cAAc,wCAAwC,CAAC;AAEvD,cAAc,0BAA0B,CAAC;AACzC,cAAc,oCAAoC,CAAC;AACnD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,uBAAuB,CAAC;AACtC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAE/C,cAAc,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Roles } from '../../role/enums/role.enum';
|
|
2
|
+
/**
|
|
3
|
+
* App accounts and staff accounts.
|
|
4
|
+
*
|
|
5
|
+
* Each brand's mobile app (G4S Kenya, GeoSHIELD, SGA Security, ...) is its own
|
|
6
|
+
* product for one organization's customers, so an account made in one app is an
|
|
7
|
+
* account with that organization only. Signing in to another brand's app means
|
|
8
|
+
* registering with that brand. One person may therefore hold several app
|
|
9
|
+
* accounts - one per organization - with the same phone number and e-mail.
|
|
10
|
+
*
|
|
11
|
+
* Staff (Super-Admin, organization and control-centre staff, responders,
|
|
12
|
+
* corporate-client admins) keep one platform-wide account each: their e-mail and
|
|
13
|
+
* phone number stay unique across the whole platform.
|
|
14
|
+
*
|
|
15
|
+
* An APP ACCOUNT is one whose only role is Mobile-User. That is the same rule the
|
|
16
|
+
* database's unique indexes use (`roles = '{Mobile-User}'`), so code and schema
|
|
17
|
+
* can never disagree about which kind an account is. An account holding
|
|
18
|
+
* Mobile-User beside a staff role is a staff account that also uses an app.
|
|
19
|
+
*/
|
|
20
|
+
export const APP_ACCOUNT_ROLE = Roles.MOBILE_USER;
|
|
21
|
+
/** An account whose only role is Mobile-User: unique within its organization, not platform-wide. */
|
|
22
|
+
export function isAppAccount(roles) {
|
|
23
|
+
return Array.isArray(roles) && roles.length === 1 && roles[0] === APP_ACCOUNT_ROLE;
|
|
24
|
+
}
|
|
25
|
+
/** Holds the Mobile-User role, alone or beside staff roles: someone who can use a brand's app. */
|
|
26
|
+
export function hasAppRole(roles) {
|
|
27
|
+
return Array.isArray(roles) && roles.includes(APP_ACCOUNT_ROLE);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Parses `APP_ORGANIZATIONS`. Blank means "none configured". A malformed entry
|
|
31
|
+
* throws: a typo here would let an app sign people in to the wrong organization,
|
|
32
|
+
* so it must stop the service at boot rather than be skipped.
|
|
33
|
+
*/
|
|
34
|
+
export function parseAppOrganizations(raw) {
|
|
35
|
+
const map = new Map();
|
|
36
|
+
for (const entry of String(raw !== null && raw !== void 0 ? raw : '').split(',')) {
|
|
37
|
+
const trimmed = entry.trim();
|
|
38
|
+
if (!trimmed)
|
|
39
|
+
continue;
|
|
40
|
+
const match = /^([A-Za-z0-9_-]+)\s*:\s*(\d+)$/.exec(trimmed);
|
|
41
|
+
if (!match)
|
|
42
|
+
throw new Error(`APP_ORGANIZATIONS: "${trimmed}" is not <appId>:<organizationId>`);
|
|
43
|
+
const [, appId, id] = match;
|
|
44
|
+
const organizationId = Number(id);
|
|
45
|
+
if (!Number.isSafeInteger(organizationId) || organizationId <= 0) {
|
|
46
|
+
throw new Error(`APP_ORGANIZATIONS: "${trimmed}" names no valid organization`);
|
|
47
|
+
}
|
|
48
|
+
const existing = map.get(appId);
|
|
49
|
+
if (existing !== undefined && existing !== organizationId) {
|
|
50
|
+
throw new Error(`APP_ORGANIZATIONS: ${appId} is given two organizations (${existing} and ${organizationId})`);
|
|
51
|
+
}
|
|
52
|
+
map.set(appId, organizationId);
|
|
53
|
+
}
|
|
54
|
+
return map;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Whether a signed-in account is being used from another organization's app: the
|
|
58
|
+
* request names an app (`X-App-Id`) that belongs to organization A, and the account
|
|
59
|
+
* is an app user of organization B.
|
|
60
|
+
*
|
|
61
|
+
* Unknown here means "not a mismatch": no app named, an app with no configured
|
|
62
|
+
* organization, or an account that is staff only. Those keep working as before.
|
|
63
|
+
*/
|
|
64
|
+
export function isAccountFromAnotherApp(appOrganizations, appId, account) {
|
|
65
|
+
if (!appId)
|
|
66
|
+
return false;
|
|
67
|
+
const expected = appOrganizations.get(appId);
|
|
68
|
+
if (expected === undefined)
|
|
69
|
+
return false;
|
|
70
|
+
if (!hasAppRole(account.roles))
|
|
71
|
+
return false;
|
|
72
|
+
return Number(account.organizationId) !== expected;
|
|
73
|
+
}
|
|
74
|
+
/** Error codes a client can act on, for the account rules above. */
|
|
75
|
+
export const APP_ACCOUNT_ERROR_CODES = {
|
|
76
|
+
/** A token or session belongs to another organization's app: sign out and sign in again here. */
|
|
77
|
+
APP_ACCOUNT_MISMATCH: 'APP_ACCOUNT_MISMATCH',
|
|
78
|
+
/** A sign-in names an app and an organization that do not belong together. */
|
|
79
|
+
APP_ORGANIZATION_MISMATCH: 'APP_ORGANIZATION_MISMATCH',
|
|
80
|
+
/** An older app asked for "the" account of a number that has accounts with several organizations. */
|
|
81
|
+
ACCOUNT_AMBIGUOUS: 'ACCOUNT_AMBIGUOUS',
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=app-account.util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-account.util.js","sourceRoot":"","sources":["../../../../../src/modules/user/utils/app-account.util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC;AAElD,oGAAoG;AACpG,MAAM,UAAU,YAAY,CAAC,KAA2C;IACpE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,gBAAgB,CAAC;AACvF,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,UAAU,CAAC,KAA2C;IAClE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AACpE,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,GAA8B;IAChE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,GAAG,aAAH,GAAG,cAAH,GAAG,GAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,MAAM,KAAK,GAAG,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7D,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,mCAAmC,CAAC,CAAC;QAC/F,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;QAC5B,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QAClC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,IAAI,cAAc,IAAI,CAAC,EAAE,CAAC;YAC/D,MAAM,IAAI,KAAK,CAAC,uBAAuB,OAAO,+BAA+B,CAAC,CAAC;QACnF,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YACxD,MAAM,IAAI,KAAK,CAAC,sBAAsB,KAAK,gCAAgC,QAAQ,QAAQ,cAAc,GAAG,CAAC,CAAC;QAClH,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB,CACnC,gBAAkC,EAClC,KAAgC,EAChC,OAAsF;IAEtF,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,OAAO,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,QAAQ,CAAC;AACvD,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACnC,iGAAiG;IACjG,oBAAoB,EAAE,sBAAsB;IAC5C,8EAA8E;IAC9E,yBAAyB,EAAE,2BAA2B;IACtD,qGAAqG;IACrG,iBAAiB,EAAE,mBAAmB;CAChC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** What changed about somebody's guardians - for logs and analytics; every reason means "refresh". */
|
|
2
|
+
export declare enum GuardiansChangedReason {
|
|
3
|
+
/** A guardian was added. */
|
|
4
|
+
ADDED = "ADDED",
|
|
5
|
+
/** A guardian was removed by the person they guard. */
|
|
6
|
+
REMOVED = "REMOVED",
|
|
7
|
+
/** Another guardian became the primary one. */
|
|
8
|
+
PRIMARY_CHANGED = "PRIMARY_CHANGED",
|
|
9
|
+
/** A guardian on the list by phone number proved that number in the same organization's app, and is now an app guardian. */
|
|
10
|
+
PROMOTED = "PROMOTED",
|
|
11
|
+
/** An app guardian's account was deleted; they stay on the list by phone number. */
|
|
12
|
+
DEMOTED = "DEMOTED",
|
|
13
|
+
/** A guardian stopped looking after one of their dependents. */
|
|
14
|
+
DEPENDENT_REMOVED = "DEPENDENT_REMOVED"
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Payload of `KAFKA_TOPICS.GUARDIANS_CHANGED`: somebody's guardian list changed,
|
|
18
|
+
* and these people's apps should read their guardians and dependents again.
|
|
19
|
+
*
|
|
20
|
+
* Ids only - no names, numbers or relationships. The apps read the lists through
|
|
21
|
+
* the guardian API, which applies its own access rules.
|
|
22
|
+
*/
|
|
23
|
+
export declare class GuardiansChangedPayloadDto {
|
|
24
|
+
/** The organization whose app the people use. Pushes go only to devices of this organization. */
|
|
25
|
+
organizationId: number;
|
|
26
|
+
/** Whose guardian list changed. */
|
|
27
|
+
dependentId: number;
|
|
28
|
+
/** Every app user whose guardians or dependents changed: the dependent and any app guardian involved. */
|
|
29
|
+
userIds: number[];
|
|
30
|
+
reason: GuardiansChangedReason;
|
|
31
|
+
occurredAt: string;
|
|
32
|
+
}
|
|
@@ -8,3 +8,4 @@ export * from './dtos/otp/create-otp-payload.dto';
|
|
|
8
8
|
export * from './dtos/otp/otp-payload.dto';
|
|
9
9
|
export * from './dtos/password/password-reset-payload.dto';
|
|
10
10
|
export * from './dtos/account-deletion/account-deletion-request-payload.dto';
|
|
11
|
+
export * from './dtos/user/guardians-changed-payload.dto';
|
|
@@ -61,7 +61,7 @@ export interface AccountAnalyticsKindRow {
|
|
|
61
61
|
/** Of the accounts created in the period, how far each got - as they stand now. */
|
|
62
62
|
export interface AccountAnalyticsFunnel {
|
|
63
63
|
created: number;
|
|
64
|
-
/**
|
|
64
|
+
/** Proved their phone or e-mail: a sign-in code, Google or Apple (the older app: its one-time code). */
|
|
65
65
|
verified: number;
|
|
66
66
|
acceptedTerms: number;
|
|
67
67
|
/** Signed in at least once. */
|
|
@@ -84,7 +84,7 @@ export interface AccountAnalyticsAccounts {
|
|
|
84
84
|
/** Active accounts that were created in an earlier period. */
|
|
85
85
|
returning: number;
|
|
86
86
|
funnel: AccountAnalyticsFunnel;
|
|
87
|
-
/** Now: never
|
|
87
|
+
/** Now: never proved their phone or e-mail (see `AccountAnalyticsFunnel.verified`). */
|
|
88
88
|
pendingNow: number;
|
|
89
89
|
/** Now: never signed in. */
|
|
90
90
|
neverSignedIn: number;
|
|
@@ -104,12 +104,16 @@ export interface AccountAnalyticsAccounts {
|
|
|
104
104
|
recency: AccountAnalyticsCount<AccountRecencyBand>[];
|
|
105
105
|
}
|
|
106
106
|
/**
|
|
107
|
-
* How somebody signed in:
|
|
108
|
-
* - PASSWORD
|
|
109
|
-
* - OTP
|
|
110
|
-
* -
|
|
107
|
+
* How somebody signed in - or, for a sign-up, made their account:
|
|
108
|
+
* - PASSWORD e-mail and password (the admin and the web);
|
|
109
|
+
* - OTP the older app (before 1.0.18): phone number and one code sent by SMS and e-mail together;
|
|
110
|
+
* - PHONE_CODE a code to the phone by SMS or a call, or a WhatsApp message from it - proves the number;
|
|
111
|
+
* - EMAIL_CODE a code to the e-mail - proves the e-mail only;
|
|
112
|
+
* - GOOGLE Google vouches for the e-mail;
|
|
113
|
+
* - APPLE Apple vouches for the e-mail (possibly a private relay address);
|
|
114
|
+
* - REVIEWER the app-store reviewers' account.
|
|
111
115
|
*/
|
|
112
|
-
export type AccountSignInMethod = 'PASSWORD' | 'OTP' | 'REVIEWER';
|
|
116
|
+
export type AccountSignInMethod = 'PASSWORD' | 'OTP' | 'PHONE_CODE' | 'EMAIL_CODE' | 'GOOGLE' | 'APPLE' | 'REVIEWER';
|
|
113
117
|
export interface AccountAnalyticsMethodRow {
|
|
114
118
|
method: string;
|
|
115
119
|
succeeded: number;
|
|
@@ -127,8 +131,13 @@ export interface AccountAnalyticsSignIns {
|
|
|
127
131
|
firstSignIns: number;
|
|
128
132
|
/** Failed for an e-mail or a code that matches no account (counted, never stored). */
|
|
129
133
|
unknownAccount: number;
|
|
134
|
+
/**
|
|
135
|
+
* By AccountSignInMethod. A wrong phone or e-mail code is not a failed sign-in - it is
|
|
136
|
+
* counted with the codes (`AccountAnalyticsVerificationCodes`) - so PHONE_CODE and
|
|
137
|
+
* EMAIL_CODE fail only for a switched-off account.
|
|
138
|
+
*/
|
|
130
139
|
byMethod: AccountAnalyticsMethodRow[];
|
|
131
|
-
/** INVALID_CREDENTIALS, UNVERIFIED, UNKNOWN_ACCOUNT, INVALID_TOKEN, ERROR... */
|
|
140
|
+
/** INVALID_CREDENTIALS, UNVERIFIED, UNKNOWN_ACCOUNT, INVALID_TOKEN, INVALID_ID_TOKEN, DISABLED, EMAIL_IN_USE, EMAIL_REQUIRED, ERROR... */
|
|
132
141
|
failureReasons: AccountAnalyticsCount[];
|
|
133
142
|
averageDailyUsers: number;
|
|
134
143
|
peakDailyUsers: number;
|
|
@@ -141,6 +150,11 @@ export interface AccountAnalyticsOtpActionRow {
|
|
|
141
150
|
sent: number;
|
|
142
151
|
verified: number;
|
|
143
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* The older app's one-time codes (before 1.0.18): one code to the e-mail and the phone
|
|
155
|
+
* together, for signing up, in and confirming. The current app's codes are in
|
|
156
|
+
* `AccountAnalyticsSignInOptions.codes`.
|
|
157
|
+
*/
|
|
144
158
|
export interface AccountAnalyticsOtp {
|
|
145
159
|
/** First sends and resends. */
|
|
146
160
|
sent: number;
|
|
@@ -237,6 +251,166 @@ export interface AccountAnalyticsPrevious {
|
|
|
237
251
|
deletionRequests: number;
|
|
238
252
|
guardianLinks: number;
|
|
239
253
|
}
|
|
254
|
+
/** How a code travels. SMS and VOICE carry it to the phone; WHATSAPP is the person messaging us FROM the phone; EMAIL. */
|
|
255
|
+
export type AccountVerificationChannel = 'SMS' | 'VOICE' | 'WHATSAPP' | 'EMAIL';
|
|
256
|
+
/** What a code is for: signing in (or up), or proving the phone number of an account already signed in. */
|
|
257
|
+
export type AccountVerificationPurpose = 'SIGN_IN' | 'VERIFY_PHONE';
|
|
258
|
+
/** One channel's codes for one purpose, in the period. */
|
|
259
|
+
export interface AccountAnalyticsCodeChannelRow {
|
|
260
|
+
purpose: AccountVerificationPurpose | string;
|
|
261
|
+
channel: AccountVerificationChannel | string;
|
|
262
|
+
/** Codes sent - for WhatsApp, the message the person was asked to send us. */
|
|
263
|
+
sent: number;
|
|
264
|
+
/** Refused before anything was sent: asked for too often, a number already on another account, a channel that cannot reach it. */
|
|
265
|
+
refused: number;
|
|
266
|
+
/** The SMS or call provider could not take it. The app offers the other channels. */
|
|
267
|
+
notDelivered: number;
|
|
268
|
+
confirmed: number;
|
|
269
|
+
wrongCode: number;
|
|
270
|
+
expired: number;
|
|
271
|
+
/** WhatsApp: the message came from a number other than the one being proven. */
|
|
272
|
+
wrongNumber: number;
|
|
273
|
+
/** confirmed / sent; null with none sent. */
|
|
274
|
+
confirmationRate: number | null;
|
|
275
|
+
}
|
|
276
|
+
/** Codes by the country of the number (or of the app, for an e-mail code) and channel, in the period. */
|
|
277
|
+
export interface AccountAnalyticsCodeCountryRow {
|
|
278
|
+
/** KE, UG, TZ - or UNKNOWN. */
|
|
279
|
+
country: string;
|
|
280
|
+
channel: AccountVerificationChannel | string;
|
|
281
|
+
sent: number;
|
|
282
|
+
notDelivered: number;
|
|
283
|
+
confirmed: number;
|
|
284
|
+
}
|
|
285
|
+
/** The current app's codes (1.0.18 on): to the phone only, or to the e-mail only - never both. */
|
|
286
|
+
export interface AccountAnalyticsVerificationCodes {
|
|
287
|
+
sent: number;
|
|
288
|
+
refused: number;
|
|
289
|
+
notDelivered: number;
|
|
290
|
+
confirmed: number;
|
|
291
|
+
wrongCode: number;
|
|
292
|
+
expired: number;
|
|
293
|
+
wrongNumber: number;
|
|
294
|
+
confirmationRate: number | null;
|
|
295
|
+
/** Biggest first. */
|
|
296
|
+
byChannel: AccountAnalyticsCodeChannelRow[];
|
|
297
|
+
byCountry: AccountAnalyticsCodeCountryRow[];
|
|
298
|
+
/** Why codes were refused: RATE_LIMITED, PHONE_IN_USE, CHANNEL_UNAVAILABLE. */
|
|
299
|
+
refusals: AccountAnalyticsCount[];
|
|
300
|
+
}
|
|
301
|
+
/** App users making their own account, in the period. */
|
|
302
|
+
export interface AccountAnalyticsSignUps {
|
|
303
|
+
/** A phone or e-mail code confirmed that matched no account: the app showed the short sign-up form. */
|
|
304
|
+
formsStarted: number;
|
|
305
|
+
/** Accounts made from that form. Google and Apple make the account straight away, with no form. */
|
|
306
|
+
formsCompleted: number;
|
|
307
|
+
/** formsCompleted / formsStarted; null with none started. */
|
|
308
|
+
completionRate: number | null;
|
|
309
|
+
/** Sign-ups refused - the e-mail or number already has an account, the form came back too late. */
|
|
310
|
+
refused: number;
|
|
311
|
+
/** EMAIL_IN_USE, PHONE_IN_USE, EMAIL_REQUIRED, REGISTRATION_EXPIRED. */
|
|
312
|
+
failureReasons: AccountAnalyticsCount[];
|
|
313
|
+
/**
|
|
314
|
+
* App (Mobile-User) accounts created in the period, by how: PHONE_CODE, EMAIL_CODE,
|
|
315
|
+
* GOOGLE, APPLE, OTP (the older app) - and OTHER: made for the person (a corporate
|
|
316
|
+
* member, a partner's caller) or before sign-ups were recorded.
|
|
317
|
+
*/
|
|
318
|
+
byMethod: AccountAnalyticsCount[];
|
|
319
|
+
}
|
|
320
|
+
export interface AccountAnalyticsPhoneCountryRow {
|
|
321
|
+
country: string;
|
|
322
|
+
appUsers: number;
|
|
323
|
+
verified: number;
|
|
324
|
+
unverified: number;
|
|
325
|
+
noNumber: number;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* App users' phone numbers - the number a responder calls - as they stand now. A number
|
|
329
|
+
* is verified only when a code to it, or a WhatsApp message from it, proved it; a number
|
|
330
|
+
* saved with "Verify later" is shown to the dispatcher as not verified.
|
|
331
|
+
*/
|
|
332
|
+
export interface AccountAnalyticsPhoneNumbers {
|
|
333
|
+
appUsers: number;
|
|
334
|
+
withNumber: number;
|
|
335
|
+
verified: number;
|
|
336
|
+
unverified: number;
|
|
337
|
+
noNumber: number;
|
|
338
|
+
/** verified / appUsers; null with none. */
|
|
339
|
+
verifiedRate: number | null;
|
|
340
|
+
/**
|
|
341
|
+
* Every app user once: how the number was proven - SMS, VOICE, WHATSAPP, LEGACY_OTP (the
|
|
342
|
+
* older app's code, counted where its SMS always arrived) - or UNVERIFIED, or NONE.
|
|
343
|
+
*/
|
|
344
|
+
byState: AccountAnalyticsCount[];
|
|
345
|
+
byCountry: AccountAnalyticsPhoneCountryRow[];
|
|
346
|
+
/** In the period: numbers proven by somebody already signed in (after Google, Apple or an e-mail code), by channel. */
|
|
347
|
+
verifiedInPeriod: AccountAnalyticsCount[];
|
|
348
|
+
/** In the period: "Verify later" - a number saved without proving it. */
|
|
349
|
+
deferred: number;
|
|
350
|
+
/** Now: app users whose e-mail is proven (an e-mail code, Google or Apple). */
|
|
351
|
+
emailVerified: number;
|
|
352
|
+
}
|
|
353
|
+
/** Google or Apple. */
|
|
354
|
+
export interface AccountAnalyticsProviderRow {
|
|
355
|
+
provider: 'GOOGLE' | 'APPLE' | string;
|
|
356
|
+
/** Accounts linked to it now. */
|
|
357
|
+
linkedAccounts: number;
|
|
358
|
+
/** In the period. */
|
|
359
|
+
signIns: number;
|
|
360
|
+
/** Accounts it created, in the period. */
|
|
361
|
+
newAccounts: number;
|
|
362
|
+
/** Linked to an account that already had the same proven e-mail, in the period. */
|
|
363
|
+
linkedExisting: number;
|
|
364
|
+
/** The provider's token did not check out, or the account could not be used (switched off, e-mail taken or missing). */
|
|
365
|
+
failed: number;
|
|
366
|
+
}
|
|
367
|
+
/** Sign-ins in one country by one way in, in the period. */
|
|
368
|
+
export interface AccountAnalyticsMethodCountryRow {
|
|
369
|
+
/** The account's country (KE, UG, TZ), or UNKNOWN. */
|
|
370
|
+
country: string;
|
|
371
|
+
method: AccountSignInMethod | string;
|
|
372
|
+
signIns: number;
|
|
373
|
+
}
|
|
374
|
+
export interface AccountAnalyticsSignInOptionsPoint {
|
|
375
|
+
/** As `AccountAnalyticsPoint.bucket`. */
|
|
376
|
+
bucket: string;
|
|
377
|
+
/** Successful sign-ins in the bucket by AccountSignInMethod; methods with none are left out. */
|
|
378
|
+
byMethod: Record<string, number>;
|
|
379
|
+
/** The current app's codes. */
|
|
380
|
+
codesSent: number;
|
|
381
|
+
codesConfirmed: number;
|
|
382
|
+
}
|
|
383
|
+
/** The same figures for the previous period of the same length. */
|
|
384
|
+
export interface AccountAnalyticsSignInOptionsPrevious {
|
|
385
|
+
/** Sign-ins by PHONE_CODE, EMAIL_CODE, GOOGLE or APPLE. */
|
|
386
|
+
currentAppSignIns: number;
|
|
387
|
+
/** Sign-ins by the older app's code (OTP). */
|
|
388
|
+
olderAppSignIns: number;
|
|
389
|
+
codesSent: number;
|
|
390
|
+
codesConfirmed: number;
|
|
391
|
+
phonesVerified: number;
|
|
392
|
+
deferred: number;
|
|
393
|
+
formsCompleted: number;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* The ways into the app since 1.0.18 - a code to the phone (SMS, a call, WhatsApp), a code
|
|
397
|
+
* to the e-mail, Google, Apple - next to the older app's SMS-and-e-mail code, and whether
|
|
398
|
+
* the phone numbers responders call are proven.
|
|
399
|
+
*/
|
|
400
|
+
export interface AccountAnalyticsSignInOptions {
|
|
401
|
+
/** People who signed in during the period, each by the way they signed in LAST. */
|
|
402
|
+
lastMethodUsed: AccountAnalyticsCount[];
|
|
403
|
+
byCountry: AccountAnalyticsMethodCountryRow[];
|
|
404
|
+
/** One point per bucket, as `AccountAnalytics.timeline`. */
|
|
405
|
+
timeline: AccountAnalyticsSignInOptionsPoint[];
|
|
406
|
+
codes: AccountAnalyticsVerificationCodes;
|
|
407
|
+
signUps: AccountAnalyticsSignUps;
|
|
408
|
+
phones: AccountAnalyticsPhoneNumbers;
|
|
409
|
+
/** GOOGLE and APPLE, always both. */
|
|
410
|
+
providers: AccountAnalyticsProviderRow[];
|
|
411
|
+
/** Absent for "forever". */
|
|
412
|
+
previous: AccountAnalyticsSignInOptionsPrevious | null;
|
|
413
|
+
}
|
|
240
414
|
/** A Super-Admin's view of every organization: one row each, biggest first. */
|
|
241
415
|
export interface AccountAnalyticsOrganizationRow {
|
|
242
416
|
organizationId: number;
|
|
@@ -266,6 +440,8 @@ export interface AccountAnalytics {
|
|
|
266
440
|
passwords: AccountAnalyticsPasswords;
|
|
267
441
|
guardians: AccountAnalyticsGuardians;
|
|
268
442
|
deletions: AccountAnalyticsDeletions;
|
|
443
|
+
/** The ways into the app, codes by channel and proven phone numbers. Absent only from a clarion-authentication older than this field. */
|
|
444
|
+
signInOptions?: AccountAnalyticsSignInOptions;
|
|
269
445
|
/** A Super-Admin looking at every organization only. */
|
|
270
446
|
byOrganization?: AccountAnalyticsOrganizationRow[];
|
|
271
447
|
}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { GuardianRelationship } from "../enums/guardian-relationship.enum";
|
|
2
2
|
export interface Guardian {
|
|
3
|
+
/**
|
|
4
|
+
* The guardian entry's own id. External and app-user guardians share one table
|
|
5
|
+
* and one id space, so either kind can be removed or made primary by it
|
|
6
|
+
* (`GuardianIdentifierDto.relationshipId`). Absent only from responses of
|
|
7
|
+
* clarion-authentication builds older than grm-shared-library 1.1.248.
|
|
8
|
+
*/
|
|
9
|
+
id?: number;
|
|
3
10
|
userId?: number;
|
|
4
11
|
name: string;
|
|
5
12
|
phoneNumber: string;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Roles } from '../../role/enums/role.enum';
|
|
2
|
+
/**
|
|
3
|
+
* App accounts and staff accounts.
|
|
4
|
+
*
|
|
5
|
+
* Each brand's mobile app (G4S Kenya, GeoSHIELD, SGA Security, ...) is its own
|
|
6
|
+
* product for one organization's customers, so an account made in one app is an
|
|
7
|
+
* account with that organization only. Signing in to another brand's app means
|
|
8
|
+
* registering with that brand. One person may therefore hold several app
|
|
9
|
+
* accounts - one per organization - with the same phone number and e-mail.
|
|
10
|
+
*
|
|
11
|
+
* Staff (Super-Admin, organization and control-centre staff, responders,
|
|
12
|
+
* corporate-client admins) keep one platform-wide account each: their e-mail and
|
|
13
|
+
* phone number stay unique across the whole platform.
|
|
14
|
+
*
|
|
15
|
+
* An APP ACCOUNT is one whose only role is Mobile-User. That is the same rule the
|
|
16
|
+
* database's unique indexes use (`roles = '{Mobile-User}'`), so code and schema
|
|
17
|
+
* can never disagree about which kind an account is. An account holding
|
|
18
|
+
* Mobile-User beside a staff role is a staff account that also uses an app.
|
|
19
|
+
*/
|
|
20
|
+
export declare const APP_ACCOUNT_ROLE = Roles.MOBILE_USER;
|
|
21
|
+
/** An account whose only role is Mobile-User: unique within its organization, not platform-wide. */
|
|
22
|
+
export declare function isAppAccount(roles: readonly string[] | null | undefined): boolean;
|
|
23
|
+
/** Holds the Mobile-User role, alone or beside staff roles: someone who can use a brand's app. */
|
|
24
|
+
export declare function hasAppRole(roles: readonly string[] | null | undefined): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Which organization each brand's app belongs to, as configured in
|
|
27
|
+
* `APP_ORGANIZATIONS` - for example `GardaWorld:48,G4S:49,SGA:51`. The ids differ
|
|
28
|
+
* per environment (Dev has its own organizations), which is why this is
|
|
29
|
+
* configuration and not code.
|
|
30
|
+
*/
|
|
31
|
+
export type AppOrganizations = ReadonlyMap<string, number>;
|
|
32
|
+
/**
|
|
33
|
+
* Parses `APP_ORGANIZATIONS`. Blank means "none configured". A malformed entry
|
|
34
|
+
* throws: a typo here would let an app sign people in to the wrong organization,
|
|
35
|
+
* so it must stop the service at boot rather than be skipped.
|
|
36
|
+
*/
|
|
37
|
+
export declare function parseAppOrganizations(raw: string | null | undefined): AppOrganizations;
|
|
38
|
+
/**
|
|
39
|
+
* Whether a signed-in account is being used from another organization's app: the
|
|
40
|
+
* request names an app (`X-App-Id`) that belongs to organization A, and the account
|
|
41
|
+
* is an app user of organization B.
|
|
42
|
+
*
|
|
43
|
+
* Unknown here means "not a mismatch": no app named, an app with no configured
|
|
44
|
+
* organization, or an account that is staff only. Those keep working as before.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isAccountFromAnotherApp(appOrganizations: AppOrganizations, appId: string | null | undefined, account: {
|
|
47
|
+
roles?: readonly string[] | null;
|
|
48
|
+
organizationId?: number | string | null;
|
|
49
|
+
}): boolean;
|
|
50
|
+
/** Error codes a client can act on, for the account rules above. */
|
|
51
|
+
export declare const APP_ACCOUNT_ERROR_CODES: {
|
|
52
|
+
/** A token or session belongs to another organization's app: sign out and sign in again here. */
|
|
53
|
+
readonly APP_ACCOUNT_MISMATCH: "APP_ACCOUNT_MISMATCH";
|
|
54
|
+
/** A sign-in names an app and an organization that do not belong together. */
|
|
55
|
+
readonly APP_ORGANIZATION_MISMATCH: "APP_ORGANIZATION_MISMATCH";
|
|
56
|
+
/** An older app asked for "the" account of a number that has accounts with several organizations. */
|
|
57
|
+
readonly ACCOUNT_AMBIGUOUS: "ACCOUNT_AMBIGUOUS";
|
|
58
|
+
};
|
|
59
|
+
export type AppAccountErrorCode = typeof APP_ACCOUNT_ERROR_CODES[keyof typeof APP_ACCOUNT_ERROR_CODES];
|
package/package.json
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "grm-shared-library",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"main": "dist/cjs/index.js",
|
|
5
|
-
"module": "dist/esm/index.js",
|
|
6
|
-
"types": "dist/types/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"types": "./dist/types/index.d.ts",
|
|
10
|
-
"import": "./dist/esm/index.js",
|
|
11
|
-
"require": "./dist/cjs/index.js"
|
|
12
|
-
},
|
|
13
|
-
"./dist/modules/*": {
|
|
14
|
-
"types": "./dist/types/modules/*.d.ts",
|
|
15
|
-
"import": "./dist/esm/modules/*.js",
|
|
16
|
-
"require": "./dist/cjs/modules/*.js"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist/**/*"
|
|
21
|
-
],
|
|
22
|
-
"scripts": {
|
|
23
|
-
"clean": "rimraf dist dist-test",
|
|
24
|
-
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
25
|
-
"build:esm": "tsc -p tsconfig.esm.json",
|
|
26
|
-
"build:types": "tsc -p tsconfig.types.json",
|
|
27
|
-
"build": "npm run clean && npm run build:types && npm run build:cjs && npm run build:esm",
|
|
28
|
-
"prepublishOnly": "npm run build",
|
|
29
|
-
"pretest": "rimraf dist-test",
|
|
30
|
-
"test": "tsc -p tsconfig.spec.json && node --test \"dist-test/**/*.spec.js\""
|
|
31
|
-
},
|
|
32
|
-
"keywords": [],
|
|
33
|
-
"author": "",
|
|
34
|
-
"license": "ISC",
|
|
35
|
-
"description": "",
|
|
36
|
-
"publishConfig": {
|
|
37
|
-
"access": "public"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@types/express": "^5.0.3",
|
|
41
|
-
"@types/geojson": "^7946.0.14",
|
|
42
|
-
"@types/node": "^22.10.5",
|
|
43
|
-
"rimraf": "^5.0.5",
|
|
44
|
-
"typescript": "^5.7.3"
|
|
45
|
-
},
|
|
46
|
-
"dependencies": {
|
|
47
|
-
"@nestjs/common": "^11.0.0",
|
|
48
|
-
"@nestjs/
|
|
49
|
-
"@nestjs/
|
|
50
|
-
"@nestjs/
|
|
51
|
-
"@nestjs/
|
|
52
|
-
"@
|
|
53
|
-
"
|
|
54
|
-
"class-
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
},
|
|
63
|
-
"peerDependencies": {
|
|
64
|
-
"@nestjs/common": "^11.0.0",
|
|
65
|
-
"@nestjs/
|
|
66
|
-
"@nestjs/
|
|
67
|
-
"@
|
|
68
|
-
"
|
|
69
|
-
"class-
|
|
70
|
-
"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "grm-shared-library",
|
|
3
|
+
"version": "1.1.248",
|
|
4
|
+
"main": "dist/cjs/index.js",
|
|
5
|
+
"module": "dist/esm/index.js",
|
|
6
|
+
"types": "dist/types/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/types/index.d.ts",
|
|
10
|
+
"import": "./dist/esm/index.js",
|
|
11
|
+
"require": "./dist/cjs/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./dist/modules/*": {
|
|
14
|
+
"types": "./dist/types/modules/*.d.ts",
|
|
15
|
+
"import": "./dist/esm/modules/*.js",
|
|
16
|
+
"require": "./dist/cjs/modules/*.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**/*"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"clean": "rimraf dist dist-test",
|
|
24
|
+
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
25
|
+
"build:esm": "tsc -p tsconfig.esm.json",
|
|
26
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
27
|
+
"build": "npm run clean && npm run build:types && npm run build:cjs && npm run build:esm",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"pretest": "rimraf dist-test",
|
|
30
|
+
"test": "tsc -p tsconfig.spec.json && node --test \"dist-test/**/*.spec.js\""
|
|
31
|
+
},
|
|
32
|
+
"keywords": [],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"description": "",
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/express": "^5.0.3",
|
|
41
|
+
"@types/geojson": "^7946.0.14",
|
|
42
|
+
"@types/node": "^22.10.5",
|
|
43
|
+
"rimraf": "^5.0.5",
|
|
44
|
+
"typescript": "^5.7.3"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@nestjs/common": "^11.0.0",
|
|
48
|
+
"@nestjs/config": "^4.0.0",
|
|
49
|
+
"@nestjs/core": "^11.0.0",
|
|
50
|
+
"@nestjs/mapped-types": "^2.0.6",
|
|
51
|
+
"@nestjs/microservices": "^11.0.0",
|
|
52
|
+
"@nestjs/swagger": "^11.2.0",
|
|
53
|
+
"@sentry/node": "^8.0.0",
|
|
54
|
+
"class-transformer": "^0.5.0",
|
|
55
|
+
"class-validator": "^0.14.0",
|
|
56
|
+
"express": "^5.1.0",
|
|
57
|
+
"geojson": "^0.5.0",
|
|
58
|
+
"grm-shared-library": "^1.1.101",
|
|
59
|
+
"libphonenumber-js": "^1.13.8",
|
|
60
|
+
"rxjs": "^7.8.2",
|
|
61
|
+
"swagger-ui-express": "^5.0.1"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@nestjs/common": "^11.0.0",
|
|
65
|
+
"@nestjs/config": "^4.0.0",
|
|
66
|
+
"@nestjs/core": "^11.0.0",
|
|
67
|
+
"@nestjs/microservices": "^11.0.0",
|
|
68
|
+
"@sentry/node": "^8.0.0",
|
|
69
|
+
"class-transformer": "^0.5.0",
|
|
70
|
+
"class-validator": "^0.14.0"
|
|
71
|
+
}
|
|
72
|
+
}
|