grm-shared-library 1.1.191 → 1.1.193

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 (103) hide show
  1. package/dist/cjs/index.js +2 -0
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/modules/entitlement/constants/entitlement-defaults.const.js +20 -0
  4. package/dist/cjs/modules/entitlement/constants/entitlement-defaults.const.js.map +1 -0
  5. package/dist/cjs/modules/entitlement/dtos/consume-trial-alert.dto.js +53 -0
  6. package/dist/cjs/modules/entitlement/dtos/consume-trial-alert.dto.js.map +1 -0
  7. package/dist/cjs/modules/entitlement/dtos/evaluate-entitlement.dto.js +55 -0
  8. package/dist/cjs/modules/entitlement/dtos/evaluate-entitlement.dto.js.map +1 -0
  9. package/dist/cjs/modules/entitlement/dtos/grant-premium-trial.dto.js +57 -0
  10. package/dist/cjs/modules/entitlement/dtos/grant-premium-trial.dto.js.map +1 -0
  11. package/dist/cjs/modules/entitlement/dtos/revoke-premium-trial.dto.js +26 -0
  12. package/dist/cjs/modules/entitlement/dtos/revoke-premium-trial.dto.js.map +1 -0
  13. package/dist/cjs/modules/entitlement/enums/entitlement-decision-reason.enum.js +34 -0
  14. package/dist/cjs/modules/entitlement/enums/entitlement-decision-reason.enum.js.map +1 -0
  15. package/dist/cjs/modules/entitlement/enums/incident-entitlement-scope.enum.js +19 -0
  16. package/dist/cjs/modules/entitlement/enums/incident-entitlement-scope.enum.js.map +1 -0
  17. package/dist/cjs/modules/entitlement/enums/incident-entitlement-tier.enum.js +27 -0
  18. package/dist/cjs/modules/entitlement/enums/incident-entitlement-tier.enum.js.map +1 -0
  19. package/dist/cjs/modules/entitlement/enums/premium-trial-source.enum.js +12 -0
  20. package/dist/cjs/modules/entitlement/enums/premium-trial-source.enum.js.map +1 -0
  21. package/dist/cjs/modules/entitlement/enums/premium-trial-status.enum.js +18 -0
  22. package/dist/cjs/modules/entitlement/enums/premium-trial-status.enum.js.map +1 -0
  23. package/dist/cjs/modules/entitlement/index.js +34 -0
  24. package/dist/cjs/modules/entitlement/index.js.map +1 -0
  25. package/dist/cjs/modules/entitlement/interfaces/entitlement-evaluation.js +3 -0
  26. package/dist/cjs/modules/entitlement/interfaces/entitlement-evaluation.js.map +1 -0
  27. package/dist/cjs/modules/entitlement/utils/entitlement.util.js +49 -0
  28. package/dist/cjs/modules/entitlement/utils/entitlement.util.js.map +1 -0
  29. package/dist/cjs/modules/system-user/constants/system-user.const.js +31 -0
  30. package/dist/cjs/modules/system-user/constants/system-user.const.js.map +1 -0
  31. package/dist/cjs/modules/system-user/index.js +27 -0
  32. package/dist/cjs/modules/system-user/index.js.map +1 -0
  33. package/dist/cjs/modules/system-user/interfaces/system-user-env-source.js +3 -0
  34. package/dist/cjs/modules/system-user/interfaces/system-user-env-source.js.map +1 -0
  35. package/dist/cjs/modules/system-user/services/system-user.service.js +60 -0
  36. package/dist/cjs/modules/system-user/services/system-user.service.js.map +1 -0
  37. package/dist/cjs/modules/system-user/system-user.module.js +33 -0
  38. package/dist/cjs/modules/system-user/system-user.module.js.map +1 -0
  39. package/dist/cjs/modules/system-user/utils/system-user.util.js +57 -0
  40. package/dist/cjs/modules/system-user/utils/system-user.util.js.map +1 -0
  41. package/dist/esm/index.js +2 -0
  42. package/dist/esm/index.js.map +1 -1
  43. package/dist/esm/modules/entitlement/constants/entitlement-defaults.const.js +17 -0
  44. package/dist/esm/modules/entitlement/constants/entitlement-defaults.const.js.map +1 -0
  45. package/dist/esm/modules/entitlement/dtos/consume-trial-alert.dto.js +49 -0
  46. package/dist/esm/modules/entitlement/dtos/consume-trial-alert.dto.js.map +1 -0
  47. package/dist/esm/modules/entitlement/dtos/evaluate-entitlement.dto.js +51 -0
  48. package/dist/esm/modules/entitlement/dtos/evaluate-entitlement.dto.js.map +1 -0
  49. package/dist/esm/modules/entitlement/dtos/grant-premium-trial.dto.js +53 -0
  50. package/dist/esm/modules/entitlement/dtos/grant-premium-trial.dto.js.map +1 -0
  51. package/dist/esm/modules/entitlement/dtos/revoke-premium-trial.dto.js +22 -0
  52. package/dist/esm/modules/entitlement/dtos/revoke-premium-trial.dto.js.map +1 -0
  53. package/dist/esm/modules/entitlement/enums/entitlement-decision-reason.enum.js +31 -0
  54. package/dist/esm/modules/entitlement/enums/entitlement-decision-reason.enum.js.map +1 -0
  55. package/dist/esm/modules/entitlement/enums/incident-entitlement-scope.enum.js +16 -0
  56. package/dist/esm/modules/entitlement/enums/incident-entitlement-scope.enum.js.map +1 -0
  57. package/dist/esm/modules/entitlement/enums/incident-entitlement-tier.enum.js +24 -0
  58. package/dist/esm/modules/entitlement/enums/incident-entitlement-tier.enum.js.map +1 -0
  59. package/dist/esm/modules/entitlement/enums/premium-trial-source.enum.js +9 -0
  60. package/dist/esm/modules/entitlement/enums/premium-trial-source.enum.js.map +1 -0
  61. package/dist/esm/modules/entitlement/enums/premium-trial-status.enum.js +15 -0
  62. package/dist/esm/modules/entitlement/enums/premium-trial-status.enum.js.map +1 -0
  63. package/dist/esm/modules/entitlement/index.js +18 -0
  64. package/dist/esm/modules/entitlement/index.js.map +1 -0
  65. package/dist/esm/modules/entitlement/interfaces/entitlement-evaluation.js +2 -0
  66. package/dist/esm/modules/entitlement/interfaces/entitlement-evaluation.js.map +1 -0
  67. package/dist/esm/modules/entitlement/utils/entitlement.util.js +42 -0
  68. package/dist/esm/modules/entitlement/utils/entitlement.util.js.map +1 -0
  69. package/dist/esm/modules/system-user/constants/system-user.const.js +28 -0
  70. package/dist/esm/modules/system-user/constants/system-user.const.js.map +1 -0
  71. package/dist/esm/modules/system-user/index.js +11 -0
  72. package/dist/esm/modules/system-user/index.js.map +1 -0
  73. package/dist/esm/modules/system-user/interfaces/system-user-env-source.js +2 -0
  74. package/dist/esm/modules/system-user/interfaces/system-user-env-source.js.map +1 -0
  75. package/dist/esm/modules/system-user/services/system-user.service.js +57 -0
  76. package/dist/esm/modules/system-user/services/system-user.service.js.map +1 -0
  77. package/dist/esm/modules/system-user/system-user.module.js +30 -0
  78. package/dist/esm/modules/system-user/system-user.module.js.map +1 -0
  79. package/dist/esm/modules/system-user/utils/system-user.util.js +53 -0
  80. package/dist/esm/modules/system-user/utils/system-user.util.js.map +1 -0
  81. package/dist/types/index.d.ts +2 -0
  82. package/dist/types/interfaces/pagination.d.ts +10 -0
  83. package/dist/types/modules/entitlement/constants/entitlement-defaults.const.d.ts +16 -0
  84. package/dist/types/modules/entitlement/dtos/consume-trial-alert.dto.d.ts +11 -0
  85. package/dist/types/modules/entitlement/dtos/evaluate-entitlement.dto.d.ts +11 -0
  86. package/dist/types/modules/entitlement/dtos/grant-premium-trial.dto.d.ts +8 -0
  87. package/dist/types/modules/entitlement/dtos/revoke-premium-trial.dto.d.ts +4 -0
  88. package/dist/types/modules/entitlement/enums/entitlement-decision-reason.enum.d.ts +29 -0
  89. package/dist/types/modules/entitlement/enums/incident-entitlement-scope.enum.d.ts +14 -0
  90. package/dist/types/modules/entitlement/enums/incident-entitlement-tier.enum.d.ts +22 -0
  91. package/dist/types/modules/entitlement/enums/premium-trial-source.enum.d.ts +7 -0
  92. package/dist/types/modules/entitlement/enums/premium-trial-status.enum.d.ts +13 -0
  93. package/dist/types/modules/entitlement/index.d.ts +12 -0
  94. package/dist/types/modules/entitlement/interfaces/entitlement-evaluation.d.ts +91 -0
  95. package/dist/types/modules/entitlement/utils/entitlement.util.d.ts +22 -0
  96. package/dist/types/modules/incident/intefaces/incident.d.ts +11 -0
  97. package/dist/types/modules/system-user/constants/system-user.const.d.ts +24 -0
  98. package/dist/types/modules/system-user/index.d.ts +5 -0
  99. package/dist/types/modules/system-user/interfaces/system-user-env-source.d.ts +10 -0
  100. package/dist/types/modules/system-user/services/system-user.service.d.ts +26 -0
  101. package/dist/types/modules/system-user/system-user.module.d.ts +13 -0
  102. package/dist/types/modules/system-user/utils/system-user.util.d.ts +41 -0
  103. package/package.json +5 -3
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Canonical environment variable that carries the platform "system user" id.
3
+ *
4
+ * The system user is a real row in the clarion-authentication `users` table
5
+ * that services stamp on records they create or mutate on their own behalf —
6
+ * i.e. when there is no authenticated human in the request (auto-assignment,
7
+ * automated status changes, service-to-service document uploads).
8
+ *
9
+ * It is deliberately NOT a compile-time constant: it is an environment-specific
10
+ * database row id, so dev / staging / production each carry their own value.
11
+ * The library owns the *contract* (key name, parsing, validation, fallback
12
+ * policy); the deployment owns the *value* (see clarion-deployment configmap).
13
+ */
14
+ export const SYSTEM_USER_ID_ENV_KEY = 'SYSTEM_USER_ID';
15
+ /**
16
+ * Per-service keys that predate {@link SYSTEM_USER_ID_ENV_KEY}.
17
+ *
18
+ * Still read — in order — when the canonical key is absent, so that a rollback
19
+ * to an older ConfigMap does not take a service down. Remove once every
20
+ * environment has been migrated to the canonical key.
21
+ *
22
+ * @deprecated Set {@link SYSTEM_USER_ID_ENV_KEY} instead.
23
+ */
24
+ export const LEGACY_SYSTEM_USER_ID_ENV_KEYS = [
25
+ 'BILLING_DMS_SERVICE_USER_ID',
26
+ 'NEWSFEED_DMS_SERVICE_USER_ID',
27
+ ];
28
+ //# sourceMappingURL=system-user.const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-user.const.js","sourceRoot":"","sources":["../../../../../src/modules/system-user/constants/system-user.const.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,gBAAgB,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAsB;IAC7D,6BAA6B;IAC7B,8BAA8B;CACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ // Constants
2
+ export * from './constants/system-user.const';
3
+ // Interfaces
4
+ export * from './interfaces/system-user-env-source';
5
+ // Utilities
6
+ export * from './utils/system-user.util';
7
+ // Services
8
+ export * from './services/system-user.service';
9
+ // Module
10
+ export * from './system-user.module';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/modules/system-user/index.ts"],"names":[],"mappings":"AAAA,YAAY;AACZ,cAAc,+BAA+B,CAAC;AAE9C,aAAa;AACb,cAAc,qCAAqC,CAAC;AAEpD,YAAY;AACZ,cAAc,0BAA0B,CAAC;AAEzC,WAAW;AACX,cAAc,gCAAgC,CAAC;AAE/C,SAAS;AACT,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=system-user-env-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-user-env-source.js","sourceRoot":"","sources":["../../../../../src/modules/system-user/interfaces/system-user-env-source.ts"],"names":[],"mappings":""}
@@ -0,0 +1,57 @@
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
+ var SystemUserService_1;
11
+ import { Injectable, Logger } from '@nestjs/common';
12
+ import { ConfigService } from '@nestjs/config';
13
+ import { SYSTEM_USER_ID_ENV_KEY } from '../constants/system-user.const';
14
+ import { resolveSystemUserId } from '../utils/system-user.util';
15
+ /**
16
+ * Single source of truth for the platform system user id inside a service.
17
+ *
18
+ * Resolution happens once, on module init, so a mis-set `SYSTEM_USER_ID`
19
+ * fails the pod's startup probe instead of surfacing later as records stamped
20
+ * with a user id that clarion-authentication cannot resolve.
21
+ *
22
+ * @example
23
+ * constructor(private readonly systemUser: SystemUserService) {}
24
+ * ...
25
+ * const actorId = userContext?.userId ?? this.systemUser.id;
26
+ */
27
+ let SystemUserService = SystemUserService_1 = class SystemUserService {
28
+ constructor(configService) {
29
+ this.configService = configService;
30
+ this.logger = new Logger(SystemUserService_1.name);
31
+ this.resolvedId = null;
32
+ }
33
+ onModuleInit() {
34
+ this.resolvedId = resolveSystemUserId(this.configService, {
35
+ onLegacyKeyUsed: (key) => this.logger.warn(`Resolved the system user id from deprecated env key "${key}". ` +
36
+ `Set ${SYSTEM_USER_ID_ENV_KEY} instead — legacy keys will be removed.`),
37
+ });
38
+ this.logger.log(`System user id resolved to ${this.resolvedId}`);
39
+ }
40
+ /**
41
+ * The system user id. Throws if read before module init completed, which
42
+ * only happens if a provider resolves it inside its own constructor.
43
+ */
44
+ get id() {
45
+ if (this.resolvedId === null) {
46
+ // Resolve on demand so constructor-time reads still work.
47
+ this.resolvedId = resolveSystemUserId(this.configService);
48
+ }
49
+ return this.resolvedId;
50
+ }
51
+ };
52
+ SystemUserService = SystemUserService_1 = __decorate([
53
+ Injectable(),
54
+ __metadata("design:paramtypes", [ConfigService])
55
+ ], SystemUserService);
56
+ export { SystemUserService };
57
+ //# sourceMappingURL=system-user.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-user.service.js","sourceRoot":"","sources":["../../../../../src/modules/system-user/services/system-user.service.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,EAAgB,MAAM,gBAAgB,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE;;;;;;;;;;;GAWG;AAEI,IAAM,iBAAiB,yBAAvB,MAAM,iBAAiB;IAI1B,YAA6B,aAA4B;QAA5B,kBAAa,GAAb,aAAa,CAAe;QAHxC,WAAM,GAAG,IAAI,MAAM,CAAC,mBAAiB,CAAC,IAAI,CAAC,CAAC;QACrD,eAAU,GAAkB,IAAI,CAAC;IAEoB,CAAC;IAE9D,YAAY;QACR,IAAI,CAAC,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,EAAE;YACtD,eAAe,EAAE,CAAC,GAAG,EAAE,EAAE,CACrB,IAAI,CAAC,MAAM,CAAC,IAAI,CACZ,wDAAwD,GAAG,KAAK;gBAChE,OAAO,sBAAsB,yCAAyC,CACzE;SACR,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,8BAA8B,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACrE,CAAC;IAED;;;OAGG;IACH,IAAI,EAAE;QACF,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;YAC3B,0DAA0D;YAC1D,IAAI,CAAC,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;CACJ,CAAA;AA5BY,iBAAiB;IAD7B,UAAU,EAAE;qCAKmC,aAAa;GAJhD,iBAAiB,CA4B7B"}
@@ -0,0 +1,30 @@
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
+ import { Global, Module } from '@nestjs/common';
8
+ import { SystemUserService } from './services/system-user.service';
9
+ /**
10
+ * Global module exposing {@link SystemUserService} to every provider in the
11
+ * host application. Import once in the service's root `AppModule`:
12
+ *
13
+ * @example
14
+ * @Module({ imports: [ConfigModule.forRoot({ ... }), SystemUserModule] })
15
+ * export class AppModule {}
16
+ *
17
+ * Requires `ConfigModule` to be global (the convention across clarion
18
+ * services) or otherwise available where this module is imported.
19
+ */
20
+ let SystemUserModule = class SystemUserModule {
21
+ };
22
+ SystemUserModule = __decorate([
23
+ Global(),
24
+ Module({
25
+ providers: [SystemUserService],
26
+ exports: [SystemUserService],
27
+ })
28
+ ], SystemUserModule);
29
+ export { SystemUserModule };
30
+ //# sourceMappingURL=system-user.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-user.module.js","sourceRoot":"","sources":["../../../../src/modules/system-user/system-user.module.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE;;;;;;;;;;GAUG;AAMI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAI,CAAA;AAApB,gBAAgB;IAL5B,MAAM,EAAE;IACR,MAAM,CAAC;QACJ,SAAS,EAAE,CAAC,iBAAiB,CAAC;QAC9B,OAAO,EAAE,CAAC,iBAAiB,CAAC;KAC/B,CAAC;GACW,gBAAgB,CAAI"}
@@ -0,0 +1,53 @@
1
+ import { LEGACY_SYSTEM_USER_ID_ENV_KEYS, SYSTEM_USER_ID_ENV_KEY } from '../constants/system-user.const';
2
+ /**
3
+ * Parses a raw environment value into a usable user id.
4
+ *
5
+ * Returns `null` for anything that is not a positive integer — including
6
+ * `'0'`, `'-1'`, `'abc'` and the empty string — so that a typo'd ConfigMap
7
+ * entry surfaces as a clear failure rather than silently stamping user `0`
8
+ * onto production records.
9
+ */
10
+ export function parseSystemUserId(raw) {
11
+ if (raw === null || raw === undefined) {
12
+ return null;
13
+ }
14
+ const text = String(raw).trim();
15
+ if (!text || !/^\d+$/.test(text)) {
16
+ return null;
17
+ }
18
+ const parsed = Number(text);
19
+ return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
20
+ }
21
+ /**
22
+ * Resolves the platform system user id from the environment.
23
+ *
24
+ * Precedence: {@link SYSTEM_USER_ID_ENV_KEY} → each legacy key in order →
25
+ * `options.fallback`. Throws when nothing resolves and no fallback is given,
26
+ * which is the intended behaviour at startup: a service that stamps records
27
+ * with the system user should refuse to boot rather than write a wrong id.
28
+ *
29
+ * @example
30
+ * // In a Nest provider that already injects ConfigService:
31
+ * this.systemUserId = resolveSystemUserId(this.configService);
32
+ */
33
+ export function resolveSystemUserId(source, options = {}) {
34
+ const { legacyKeys = LEGACY_SYSTEM_USER_ID_ENV_KEYS, fallback, onLegacyKeyUsed } = options;
35
+ const canonical = parseSystemUserId(source.get(SYSTEM_USER_ID_ENV_KEY));
36
+ if (canonical !== null) {
37
+ return canonical;
38
+ }
39
+ for (const key of legacyKeys) {
40
+ const legacy = parseSystemUserId(source.get(key));
41
+ if (legacy !== null) {
42
+ onLegacyKeyUsed === null || onLegacyKeyUsed === void 0 ? void 0 : onLegacyKeyUsed(key);
43
+ return legacy;
44
+ }
45
+ }
46
+ if (fallback !== undefined) {
47
+ return fallback;
48
+ }
49
+ throw new Error(`${SYSTEM_USER_ID_ENV_KEY} is not set to a positive integer. ` +
50
+ `Set it to the id of the platform system user in clarion-authentication ` +
51
+ `(checked legacy keys: ${legacyKeys.length ? legacyKeys.join(', ') : 'none'}).`);
52
+ }
53
+ //# sourceMappingURL=system-user.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system-user.util.js","sourceRoot":"","sources":["../../../../../src/modules/system-user/utils/system-user.util.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAqBxG;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC1C,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACtE,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CAC/B,MAA2B,EAC3B,UAAsC,EAAE;IAExC,MAAM,EAAE,UAAU,GAAG,8BAA8B,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;IAE3F,MAAM,SAAS,GAAG,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC;IACxE,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAG,GAAG,CAAC,CAAC;YACvB,OAAO,MAAM,CAAC;QAClB,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,MAAM,IAAI,KAAK,CACX,GAAG,sBAAsB,qCAAqC;QAC9D,yEAAyE;QACzE,yBAAyB,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAClF,CAAC;AACN,CAAC"}
@@ -19,6 +19,8 @@ export * from './modules/chat/index';
19
19
  export * from './modules/country/index';
20
20
  export * from './modules/phone/index';
21
21
  export * from './modules/tracking/index';
22
+ export * from './modules/entitlement/index';
23
+ export * from './modules/system-user/index';
22
24
  export * from './interfaces/server-message';
23
25
  export * from './interfaces/i-request-with-user';
24
26
  export * from './interfaces/validated-user';
@@ -5,6 +5,7 @@ import { Organization } from "../modules/organization";
5
5
  import { ResponseUnit } from "../modules/response-unit";
6
6
  import { User } from "../modules/user";
7
7
  import { WebNotification } from "../modules/web-notification";
8
+ import { IncidentEntitlementScope } from "../modules/entitlement/enums/incident-entitlement-scope.enum";
8
9
  export interface CursorPaginatedResponse<T> {
9
10
  data: T[];
10
11
  nextCursor: string | null;
@@ -17,6 +18,15 @@ export interface PaginationParams {
17
18
  sortBy?: string;
18
19
  sortOrder?: 'ASC' | 'DESC';
19
20
  }
21
+ /**
22
+ * Incident list query. Extends the generic pagination contract with the premium
23
+ * entitlement filter: the primary admin views ask for `ENTITLED` so Free-user
24
+ * incidents stay hidden, and the dedicated "Incident List - Free Users" view
25
+ * asks for `FREE`. Omitting it preserves the pre-entitlement behaviour (`ALL`).
26
+ */
27
+ export interface IncidentQueryParams extends PaginationParams {
28
+ entitlementScope?: IncidentEntitlementScope;
29
+ }
20
30
  export interface PaginatedResponse<T> {
21
31
  data: T[];
22
32
  meta: {
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Platform defaults for the premium trial. A deployment overrides these with
3
+ * `BILLING_TRIAL_*` environment variables, and an organization can override them
4
+ * again through its billing config - so these are the last fallback, not policy.
5
+ */
6
+ export declare const PREMIUM_TRIAL_DEFAULTS: {
7
+ /** Alerts a trial user may raise as if they were premium. */
8
+ readonly MAX_INCIDENTS: 2;
9
+ /** Days the trial window stays open from enrolment. */
10
+ readonly DURATION_DAYS: 30;
11
+ };
12
+ /**
13
+ * Header used to carry a caller-supplied idempotency key on entitlement
14
+ * mutations. Kept here so producer and consumer cannot drift.
15
+ */
16
+ export declare const ENTITLEMENT_IDEMPOTENCY_HEADER = "x-entitlement-idempotency-key";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Records that one trial alert was spent. `incidentId` is the idempotency key:
3
+ * replaying the same incident never double-counts, so the caller can retry
4
+ * freely after a transient failure.
5
+ */
6
+ export declare class ConsumeTrialAlertDto {
7
+ userId: number;
8
+ organizationId: number;
9
+ incidentId: number;
10
+ incidentTypeId?: number;
11
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Service-to-service entitlement question. Sent by clarion-incident before an
3
+ * incident of class `Incident` is created, and by any other service that needs
4
+ * to know whether a user may reach the provider control room.
5
+ */
6
+ export declare class EvaluateEntitlementDto {
7
+ userId: number;
8
+ organizationId: number;
9
+ incidentTypeId?: number;
10
+ autoEnrollTrial?: boolean;
11
+ }
@@ -0,0 +1,8 @@
1
+ /** Operator-initiated trial grant (or extension of an existing trial). */
2
+ export declare class GrantPremiumTrialDto {
3
+ userId: number;
4
+ organizationId: number;
5
+ maxIncidents?: number;
6
+ durationDays?: number;
7
+ reason?: string;
8
+ }
@@ -0,0 +1,4 @@
1
+ /** Operator-initiated trial revocation. */
2
+ export declare class RevokePremiumTrialDto {
3
+ reason?: string;
4
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Why an entitlement evaluation produced its tier. Persisted in the incident
3
+ * entitlement snapshot for audit/support and surfaced to the mobile client so it
4
+ * can pick the right subscription banner without a second round trip.
5
+ */
6
+ export declare enum EntitlementDecisionReason {
7
+ /** An active subscription entitlement covers the requested incident type. */
8
+ ACTIVE_SUBSCRIPTION = "ACTIVE_SUBSCRIPTION",
9
+ /** No subscription, but an active premium trial with alerts remaining. */
10
+ ACTIVE_TRIAL = "ACTIVE_TRIAL",
11
+ /** The user has never held a subscription or trial for this organization. */
12
+ NO_ENTITLEMENT = "NO_ENTITLEMENT",
13
+ /** An entitlement exists but its package does not cover this incident type. */
14
+ INCIDENT_TYPE_NOT_COVERED = "INCIDENT_TYPE_NOT_COVERED",
15
+ /** The user's subscription lapsed — drives the "renew" banner on mobile. */
16
+ SUBSCRIPTION_EXPIRED = "SUBSCRIPTION_EXPIRED",
17
+ /** The trial period is still open but every trial alert has been used. */
18
+ TRIAL_EXHAUSTED = "TRIAL_EXHAUSTED",
19
+ /** The trial window elapsed. */
20
+ TRIAL_EXPIRED = "TRIAL_EXPIRED",
21
+ /** The trial was revoked by an operator. */
22
+ TRIAL_REVOKED = "TRIAL_REVOKED",
23
+ /** Trials are switched off for this organization/deployment. */
24
+ TRIAL_DISABLED = "TRIAL_DISABLED",
25
+ /** Entitlement does not gate this record (e.g. grievance class). */
26
+ NOT_APPLICABLE = "NOT_APPLICABLE",
27
+ /** Billing could not be reached; the configured fail-open/closed default applied. */
28
+ EVALUATION_UNAVAILABLE = "EVALUATION_UNAVAILABLE"
29
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * List filter applied to incident queries.
3
+ *
4
+ * ALL — no entitlement filter (default; preserves legacy behaviour).
5
+ * ENTITLED — everything except Free-user incidents. Used by the primary admin
6
+ * incident list, map and kanban views.
7
+ * FREE — only Free-user incidents. Backs the "Incident List - Free Users"
8
+ * admin view.
9
+ */
10
+ export declare enum IncidentEntitlementScope {
11
+ ALL = "ALL",
12
+ ENTITLED = "ENTITLED",
13
+ FREE = "FREE"
14
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Premium entitlement classification stamped on every incident at creation time.
3
+ *
4
+ * The tier is derived server-side by clarion-billing and is NEVER accepted from a
5
+ * client payload. It drives three behaviours across the platform:
6
+ *
7
+ * - `FREE` incidents are not published to the realtime (live-updates) channel,
8
+ * are not auto-assigned to operators, and are hidden from the primary
9
+ * admin incident list / map / kanban views.
10
+ * - `PREMIUM` and `TRIAL` incidents behave exactly as incidents did before
11
+ * entitlement enforcement (full provider routing + live updates).
12
+ * - `NOT_APPLICABLE` covers everything entitlement does not gate: grievances,
13
+ * incidents created before enforcement shipped, and any incident whose
14
+ * entitlement could not be attributed to a user. It is treated as entitled
15
+ * so historical and non-gated data keeps its existing behaviour.
16
+ */
17
+ export declare enum IncidentEntitlementTier {
18
+ PREMIUM = "PREMIUM",
19
+ TRIAL = "TRIAL",
20
+ FREE = "FREE",
21
+ NOT_APPLICABLE = "NOT_APPLICABLE"
22
+ }
@@ -0,0 +1,7 @@
1
+ /** How a premium trial came to exist. */
2
+ export declare enum PremiumTrialSource {
3
+ /** Created lazily the first time entitlement was evaluated for the user. */
4
+ AUTO_ENROLL = "AUTO_ENROLL",
5
+ /** Granted explicitly by an operator/admin. */
6
+ MANUAL_GRANT = "MANUAL_GRANT"
7
+ }
@@ -0,0 +1,13 @@
1
+ /** Lifecycle of a user's premium trial within one organization. */
2
+ export declare enum PremiumTrialStatus {
3
+ /** Within the trial window with at least one alert remaining. */
4
+ ACTIVE = "ACTIVE",
5
+ /** Within the trial window but every allotted alert has been used. */
6
+ EXHAUSTED = "EXHAUSTED",
7
+ /** The trial window elapsed. */
8
+ EXPIRED = "EXPIRED",
9
+ /** Cancelled by an operator before it ran its course. */
10
+ REVOKED = "REVOKED",
11
+ /** Superseded because the user took out a paid subscription. */
12
+ CONVERTED = "CONVERTED"
13
+ }
@@ -0,0 +1,12 @@
1
+ export * from './enums/incident-entitlement-tier.enum';
2
+ export * from './enums/incident-entitlement-scope.enum';
3
+ export * from './enums/entitlement-decision-reason.enum';
4
+ export * from './enums/premium-trial-status.enum';
5
+ export * from './enums/premium-trial-source.enum';
6
+ export * from './interfaces/entitlement-evaluation';
7
+ export * from './constants/entitlement-defaults.const';
8
+ export * from './dtos/evaluate-entitlement.dto';
9
+ export * from './dtos/consume-trial-alert.dto';
10
+ export * from './dtos/grant-premium-trial.dto';
11
+ export * from './dtos/revoke-premium-trial.dto';
12
+ export * from './utils/entitlement.util';
@@ -0,0 +1,91 @@
1
+ import { EntitlementDecisionReason } from '../enums/entitlement-decision-reason.enum';
2
+ import { IncidentEntitlementTier } from '../enums/incident-entitlement-tier.enum';
3
+ import { PremiumTrialSource } from '../enums/premium-trial-source.enum';
4
+ import { PremiumTrialStatus } from '../enums/premium-trial-status.enum';
5
+ /** Compact view of the subscription entitlement backing a premium decision. */
6
+ export interface EntitlementSubscriptionSummary {
7
+ subscriptionId?: number | null;
8
+ packageId?: number | null;
9
+ packageName?: string | null;
10
+ /** `EntitlementSourceType` from clarion-billing (primary / member / beneficiary). */
11
+ sourceType?: string | null;
12
+ startsAt?: string | null;
13
+ expiresAt?: string | null;
14
+ /** Incident type ids the package covers. An empty array means "every type". */
15
+ incidentTypeIds?: number[];
16
+ }
17
+ /** Compact view of a user's premium trial within one organization. */
18
+ export interface EntitlementTrialSummary {
19
+ trialId: number;
20
+ status: PremiumTrialStatus;
21
+ source: PremiumTrialSource;
22
+ /** Alerts the trial grants in total (default 2). */
23
+ maxIncidents: number;
24
+ incidentsUsed: number;
25
+ /** Never negative - clamped at zero once the allotment is spent. */
26
+ incidentsRemaining: number;
27
+ startsAt: string;
28
+ expiresAt: string;
29
+ /** Whole days left in the trial window; zero once elapsed. */
30
+ daysRemaining: number;
31
+ }
32
+ /**
33
+ * The single answer every caller needs about a user's premium standing.
34
+ *
35
+ * Produced by clarion-billing (`POST /billing/entitlements/evaluate` for
36
+ * service-to-service calls, `GET /billing/entitlements/me` for the mobile app)
37
+ * and consumed by clarion-incident to stamp the incident, and by the mobile app
38
+ * to pick its subscription banner.
39
+ */
40
+ export interface EntitlementEvaluation {
41
+ userId: number;
42
+ organizationId: number;
43
+ tier: IncidentEntitlementTier;
44
+ /** True for PREMIUM/TRIAL/NOT_APPLICABLE - i.e. the alert reaches the provider. */
45
+ canAlertProvider: boolean;
46
+ reason: EntitlementDecisionReason;
47
+ evaluatedAt: string;
48
+ /** Echoes the incident type the decision was scoped to, when one was supplied. */
49
+ incidentTypeId?: number | null;
50
+ /**
51
+ * True when the answer was produced without a live billing decision (the
52
+ * caller's configured fail-open/fail-closed default applied). Never set by
53
+ * billing itself - only by clients that had to degrade.
54
+ */
55
+ degraded?: boolean;
56
+ /** Present when an ACTIVE subscription entitlement backs the decision. */
57
+ subscription?: EntitlementSubscriptionSummary | null;
58
+ /** Present whenever the user has a trial record, whatever its status. */
59
+ trial?: EntitlementTrialSummary | null;
60
+ /**
61
+ * Present when the user holds no active entitlement but previously had one
62
+ * that lapsed. Drives the mobile "your subscription expired - renew" banner,
63
+ * which must be distinguishable from a never-subscribed free user.
64
+ */
65
+ expiredSubscription?: EntitlementSubscriptionSummary | null;
66
+ }
67
+ /**
68
+ * Audit trail persisted alongside every incident (jsonb). Deliberately a
69
+ * point-in-time copy: re-evaluating later can produce a different answer, and
70
+ * incident history must reflect what was true when the alert was raised.
71
+ */
72
+ export interface IncidentEntitlementSnapshot {
73
+ tier: IncidentEntitlementTier;
74
+ reason: EntitlementDecisionReason;
75
+ evaluatedAt: string;
76
+ /** The user the decision was made for (creator, or the reporter's system user). */
77
+ evaluatedUserId?: number | null;
78
+ degraded?: boolean;
79
+ subscriptionId?: number | null;
80
+ packageId?: number | null;
81
+ sourceType?: string | null;
82
+ trialId?: number | null;
83
+ /** Alerts left on the trial AFTER this incident consumed one, when applicable. */
84
+ trialIncidentsRemaining?: number | null;
85
+ }
86
+ /** Result of consuming one trial alert; idempotent per (trial, incident). */
87
+ export interface TrialConsumptionResult {
88
+ /** False when the incident had already been counted against the trial. */
89
+ consumed: boolean;
90
+ trial: EntitlementTrialSummary | null;
91
+ }
@@ -0,0 +1,22 @@
1
+ import { IncidentEntitlementScope } from '../enums/incident-entitlement-scope.enum';
2
+ import { IncidentEntitlementTier } from '../enums/incident-entitlement-tier.enum';
3
+ import { PremiumTrialStatus } from '../enums/premium-trial-status.enum';
4
+ /**
5
+ * Whether a tier reaches the provider control room.
6
+ *
7
+ * Everything except `FREE` counts as entitled: `NOT_APPLICABLE` covers
8
+ * grievances and pre-enforcement incidents, which must keep behaving exactly as
9
+ * they did before entitlement gating existed.
10
+ */
11
+ export declare function isEntitledTier(tier?: IncidentEntitlementTier | string | null): boolean;
12
+ /** Whether an incident was raised by a Free user (no subscription, no trial). */
13
+ export declare function isFreeUserTier(tier?: IncidentEntitlementTier | string | null): boolean;
14
+ /** True while the trial still grants premium behaviour. */
15
+ export declare function isTrialUsable(status?: PremiumTrialStatus | string | null): boolean;
16
+ /**
17
+ * Parses a client-supplied entitlement scope. Unknown/absent values fall back to
18
+ * `ALL` so an unrecognised query string never silently hides incidents.
19
+ */
20
+ export declare function parseIncidentEntitlementScope(value?: string | null): IncidentEntitlementScope;
21
+ /** Whole days remaining until `expiresAt`, floored at zero. */
22
+ export declare function trialDaysRemaining(expiresAt: Date | string, now?: Date): number;
@@ -14,6 +14,8 @@ import { IncidentResponseUnitAssignment } from "./incident-response-unit-assignm
14
14
  import { IncidentType } from "./incident-type";
15
15
  import { IncidentReport } from "./incident-report";
16
16
  import { IncidentEmergencyType } from "../enums/incident-emergency-type.enum";
17
+ import { IncidentEntitlementSnapshot } from "../../entitlement/interfaces/entitlement-evaluation";
18
+ import { IncidentEntitlementTier } from "../../entitlement/enums/incident-entitlement-tier.enum";
17
19
  export interface Incident {
18
20
  id?: number;
19
21
  appId: IncidentAppId;
@@ -46,6 +48,15 @@ export interface Incident {
46
48
  workflowTaskQueueName: IncidentWorkflowTaskQueueName;
47
49
  controlCentreId: number;
48
50
  organizationId: number;
51
+ /**
52
+ * Premium standing of the reporting user at the moment the incident was
53
+ * raised. Derived server-side by clarion-billing - never accepted from a
54
+ * client payload. `FREE` incidents are withheld from live updates and from
55
+ * the primary admin list/map/kanban views.
56
+ */
57
+ entitlementTier?: IncidentEntitlementTier;
58
+ /** Point-in-time audit of how `entitlementTier` was decided. */
59
+ entitlementSnapshot?: IncidentEntitlementSnapshot | null;
49
60
  createdAt?: string;
50
61
  updatedAt?: string;
51
62
  category?: IncidentCategory;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Canonical environment variable that carries the platform "system user" id.
3
+ *
4
+ * The system user is a real row in the clarion-authentication `users` table
5
+ * that services stamp on records they create or mutate on their own behalf —
6
+ * i.e. when there is no authenticated human in the request (auto-assignment,
7
+ * automated status changes, service-to-service document uploads).
8
+ *
9
+ * It is deliberately NOT a compile-time constant: it is an environment-specific
10
+ * database row id, so dev / staging / production each carry their own value.
11
+ * The library owns the *contract* (key name, parsing, validation, fallback
12
+ * policy); the deployment owns the *value* (see clarion-deployment configmap).
13
+ */
14
+ export declare const SYSTEM_USER_ID_ENV_KEY = "SYSTEM_USER_ID";
15
+ /**
16
+ * Per-service keys that predate {@link SYSTEM_USER_ID_ENV_KEY}.
17
+ *
18
+ * Still read — in order — when the canonical key is absent, so that a rollback
19
+ * to an older ConfigMap does not take a service down. Remove once every
20
+ * environment has been migrated to the canonical key.
21
+ *
22
+ * @deprecated Set {@link SYSTEM_USER_ID_ENV_KEY} instead.
23
+ */
24
+ export declare const LEGACY_SYSTEM_USER_ID_ENV_KEYS: readonly string[];
@@ -0,0 +1,5 @@
1
+ export * from './constants/system-user.const';
2
+ export * from './interfaces/system-user-env-source';
3
+ export * from './utils/system-user.util';
4
+ export * from './services/system-user.service';
5
+ export * from './system-user.module';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Minimal read surface needed to resolve the system user id.
3
+ *
4
+ * Structurally satisfied by `ConfigService` from `@nestjs/config`, so callers
5
+ * can pass their existing config service straight through without the shared
6
+ * library taking a hard dependency on it.
7
+ */
8
+ export interface SystemUserEnvSource {
9
+ get<T = string>(key: string): T | undefined;
10
+ }
@@ -0,0 +1,26 @@
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { ConfigService } from '@nestjs/config';
3
+ /**
4
+ * Single source of truth for the platform system user id inside a service.
5
+ *
6
+ * Resolution happens once, on module init, so a mis-set `SYSTEM_USER_ID`
7
+ * fails the pod's startup probe instead of surfacing later as records stamped
8
+ * with a user id that clarion-authentication cannot resolve.
9
+ *
10
+ * @example
11
+ * constructor(private readonly systemUser: SystemUserService) {}
12
+ * ...
13
+ * const actorId = userContext?.userId ?? this.systemUser.id;
14
+ */
15
+ export declare class SystemUserService implements OnModuleInit {
16
+ private readonly configService;
17
+ private readonly logger;
18
+ private resolvedId;
19
+ constructor(configService: ConfigService);
20
+ onModuleInit(): void;
21
+ /**
22
+ * The system user id. Throws if read before module init completed, which
23
+ * only happens if a provider resolves it inside its own constructor.
24
+ */
25
+ get id(): number;
26
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Global module exposing {@link SystemUserService} to every provider in the
3
+ * host application. Import once in the service's root `AppModule`:
4
+ *
5
+ * @example
6
+ * @Module({ imports: [ConfigModule.forRoot({ ... }), SystemUserModule] })
7
+ * export class AppModule {}
8
+ *
9
+ * Requires `ConfigModule` to be global (the convention across clarion
10
+ * services) or otherwise available where this module is imported.
11
+ */
12
+ export declare class SystemUserModule {
13
+ }