@rytass/bpm-core-nestjs-module 0.9.1 → 0.11.0

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 (68) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +17 -5
  3. package/package.json +3 -3
  4. package/src/lib/attachment/attachment-options.js +7 -1
  5. package/src/lib/attachment/attachment-options.js.map +1 -1
  6. package/src/lib/attachment/attachment.service.js +7 -0
  7. package/src/lib/attachment/attachment.service.js.map +1 -1
  8. package/src/lib/bpm/bpm-root.module.d.ts +11 -0
  9. package/src/lib/bpm/bpm-root.module.js.map +1 -1
  10. package/src/lib/calendar/calendar.module.d.ts +12 -0
  11. package/src/lib/calendar/calendar.module.js.map +1 -1
  12. package/src/lib/common/filters/all-exceptions.filter.d.ts +11 -0
  13. package/src/lib/common/filters/all-exceptions.filter.js +35 -1
  14. package/src/lib/common/filters/all-exceptions.filter.js.map +1 -1
  15. package/src/lib/form-data-source/form-data-source-value-resolver.service.d.ts +6 -7
  16. package/src/lib/form-data-source/form-data-source-value-resolver.service.js +91 -291
  17. package/src/lib/form-data-source/form-data-source-value-resolver.service.js.map +1 -1
  18. package/src/lib/form-data-source/form-data-source.queries.d.ts +24 -0
  19. package/src/lib/form-data-source/form-data-source.queries.js +179 -7
  20. package/src/lib/form-data-source/form-data-source.queries.js.map +1 -1
  21. package/src/lib/form-data-source/form-data-source.service.d.ts +36 -21
  22. package/src/lib/form-data-source/form-data-source.service.js +143 -359
  23. package/src/lib/form-data-source/form-data-source.service.js.map +1 -1
  24. package/src/lib/form-data-source/form-data-source.types.d.ts +17 -0
  25. package/src/lib/form-data-source/form-data-source.types.js.map +1 -1
  26. package/src/lib/form-data-source/form-data-source.validation.d.ts +78 -0
  27. package/src/lib/form-data-source/form-data-source.validation.js +409 -0
  28. package/src/lib/form-data-source/form-data-source.validation.js.map +1 -0
  29. package/src/lib/migrations/0000000021000-notification-silenced.d.ts +15 -0
  30. package/src/lib/migrations/0000000021000-notification-silenced.js +31 -0
  31. package/src/lib/migrations/0000000021000-notification-silenced.js.map +1 -0
  32. package/src/lib/migrations/index.d.ts +1 -0
  33. package/src/lib/migrations/index.js +3 -0
  34. package/src/lib/migrations/index.js.map +1 -1
  35. package/src/lib/notification/index.d.ts +1 -0
  36. package/src/lib/notification/index.js +1 -0
  37. package/src/lib/notification/index.js.map +1 -1
  38. package/src/lib/notification/notification-delivery.service.d.ts +26 -1
  39. package/src/lib/notification/notification-delivery.service.js +205 -20
  40. package/src/lib/notification/notification-delivery.service.js.map +1 -1
  41. package/src/lib/notification/notification-dispatcher.token.d.ts +13 -0
  42. package/src/lib/notification/notification-dispatcher.token.js.map +1 -1
  43. package/src/lib/notification/notification-observer.token.d.ts +6 -0
  44. package/src/lib/notification/notification-observer.token.js.map +1 -1
  45. package/src/lib/notification/notification-options.d.ts +43 -0
  46. package/src/lib/notification/notification-options.js +45 -4
  47. package/src/lib/notification/notification-options.js.map +1 -1
  48. package/src/lib/notification/notification-schedule.d.ts +41 -0
  49. package/src/lib/notification/notification-schedule.js +158 -0
  50. package/src/lib/notification/notification-schedule.js.map +1 -0
  51. package/src/lib/notification/notification.entity.d.ts +12 -0
  52. package/src/lib/notification/notification.entity.js +5 -0
  53. package/src/lib/notification/notification.entity.js.map +1 -1
  54. package/src/lib/notification/notification.service.d.ts +10 -0
  55. package/src/lib/notification/notification.service.js +100 -21
  56. package/src/lib/notification/notification.service.js.map +1 -1
  57. package/src/lib/template/index.d.ts +1 -0
  58. package/src/lib/template/index.js +1 -0
  59. package/src/lib/template/index.js.map +1 -1
  60. package/src/lib/template/template-observer.token.d.ts +67 -0
  61. package/src/lib/template/template-observer.token.js +16 -0
  62. package/src/lib/template/template-observer.token.js.map +1 -0
  63. package/src/lib/template/template.mutations.d.ts +1 -1
  64. package/src/lib/template/template.mutations.js +4 -3
  65. package/src/lib/template/template.mutations.js.map +1 -1
  66. package/src/lib/template/template.service.d.ts +18 -2
  67. package/src/lib/template/template.service.js +117 -17
  68. package/src/lib/template/template.service.js.map +1 -1
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_BPM_NOTIFICATION_OPTIONS = exports.BPM_NOTIFICATION_OPTIONS = void 0;
4
4
  exports.resolveBPMNotificationOptions = resolveBPMNotificationOptions;
5
+ const notification_schedule_1 = require("./notification-schedule");
5
6
  const notification_enums_1 = require("./notification.enums");
6
7
  exports.BPM_NOTIFICATION_OPTIONS = Symbol('BPM_NOTIFICATION_OPTIONS');
7
8
  exports.DEFAULT_BPM_NOTIFICATION_OPTIONS = {
@@ -18,10 +19,13 @@ exports.DEFAULT_BPM_NOTIFICATION_OPTIONS = {
18
19
  defaultEmailPreferenceEnabled: true,
19
20
  defaultInAppPreferenceEnabled: true,
20
21
  deliveryBatchSize: 25,
22
+ deliveryDispatchTimeoutMs: 30_000,
21
23
  deliveryMaxAttempts: 3,
22
24
  deliveryRetryBaseDelayMs: 60_000,
23
25
  deliveryScanIntervalMs: 30_000,
24
26
  deliverySchedulerEnabled: false,
27
+ emailDigestHour: notification_schedule_1.DEFAULT_EMAIL_DIGEST_HOUR,
28
+ quietHoursTimeZone: null,
25
29
  slaBusinessCalendarTimeZone: 'UTC',
26
30
  slaScanIntervalMs: 60_000,
27
31
  slaSchedulerEnabled: false,
@@ -42,9 +46,11 @@ function resolveBPMNotificationOptions(options = {}) {
42
46
  const emailFrom = normalizeText(options.notificationEmailFrom);
43
47
  const webhookSigningSecret = normalizeText(options.notificationWebhookSigningSecret);
44
48
  const webhookEndpointUrl = normalizeText(options.notificationWebhookEndpointUrl);
49
+ const slaBusinessCalendarTimeZone = normalizeTimeZone(options.notificationSlaBusinessCalendarTimeZone, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.slaBusinessCalendarTimeZone);
45
50
  return {
46
51
  deliveryScanIntervalMs: normalizeInterval(options.notificationDeliveryScanIntervalMs, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.deliveryScanIntervalMs),
47
52
  deliveryBatchSize: normalizePositiveInteger(options.notificationDeliveryBatchSize, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.deliveryBatchSize),
53
+ deliveryDispatchTimeoutMs: normalizeTimeout(options.notificationDeliveryDispatchTimeoutMs, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.deliveryDispatchTimeoutMs),
48
54
  deliveryMaxAttempts: normalizePositiveInteger(options.notificationDeliveryMaxAttempts, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.deliveryMaxAttempts),
49
55
  deliveryRetryBaseDelayMs: normalizeInterval(options.notificationDeliveryRetryBaseDelayMs, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.deliveryRetryBaseDelayMs),
50
56
  deliverySchedulerEnabled: options.notificationDeliverySchedulerEnabled ??
@@ -70,7 +76,13 @@ function resolveBPMNotificationOptions(options = {}) {
70
76
  exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.defaultEmailPreferenceEnabled,
71
77
  defaultInAppPreferenceEnabled: options.notificationDefaultInAppPreferenceEnabled ??
72
78
  exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.defaultInAppPreferenceEnabled,
73
- slaBusinessCalendarTimeZone: normalizeTimeZone(options.notificationSlaBusinessCalendarTimeZone),
79
+ emailDigestHour: (0, notification_schedule_1.normalizeDigestHour)(options.notificationEmailDigestHour),
80
+ // Left null when unset so `NotificationService` can read the zone off the
81
+ // registered business calendar. Resolving it here would silently mean UTC
82
+ // for every host that supplies its own calendar — the calendar knows the
83
+ // zone, but it does not exist yet at option-flattening time.
84
+ quietHoursTimeZone: normalizeOptionalTimeZone(options.notificationQuietHoursTimeZone),
85
+ slaBusinessCalendarTimeZone,
74
86
  slaScanIntervalMs: normalizeInterval(options.notificationSlaScanIntervalMs, exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.slaScanIntervalMs),
75
87
  slaSchedulerEnabled: options.notificationSlaSchedulerEnabled ??
76
88
  exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.slaSchedulerEnabled,
@@ -101,21 +113,39 @@ function normalizePort(value) {
101
113
  ? value
102
114
  : null;
103
115
  }
116
+ /**
117
+ * As {@link normalizeTimeZone}, but reports "not configured" as `null` instead
118
+ * of substituting a fallback. An unreadable zone is treated as absent, so the
119
+ * caller's own fallback applies rather than a silently wrong zone.
120
+ */
121
+ function normalizeOptionalTimeZone(value) {
122
+ const trimmedValue = value?.trim() ?? '';
123
+ if (!trimmedValue) {
124
+ return null;
125
+ }
126
+ try {
127
+ new Intl.DateTimeFormat('en-CA', { timeZone: trimmedValue });
128
+ return trimmedValue;
129
+ }
130
+ catch {
131
+ return null;
132
+ }
133
+ }
104
134
  /**
105
135
  * Rejects unknown IANA zones at wiring time rather than letting every SLA
106
136
  * calculation throw later inside `Intl.DateTimeFormat`.
107
137
  */
108
- function normalizeTimeZone(value) {
138
+ function normalizeTimeZone(value, fallback) {
109
139
  const trimmedValue = value?.trim() ?? '';
110
140
  if (!trimmedValue) {
111
- return exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.slaBusinessCalendarTimeZone;
141
+ return fallback;
112
142
  }
113
143
  try {
114
144
  new Intl.DateTimeFormat('en-CA', { timeZone: trimmedValue });
115
145
  return trimmedValue;
116
146
  }
117
147
  catch {
118
- return exports.DEFAULT_BPM_NOTIFICATION_OPTIONS.slaBusinessCalendarTimeZone;
148
+ return fallback;
119
149
  }
120
150
  }
121
151
  function normalizeInterval(value, fallback) {
@@ -124,6 +154,17 @@ function normalizeInterval(value, fallback) {
124
154
  }
125
155
  return Math.max(value, 1000);
126
156
  }
157
+ /**
158
+ * Unlike {@link normalizeInterval} this accepts `0`, which means "wait
159
+ * indefinitely" for a dispatch, and imposes no 1000ms floor: a host may want a
160
+ * tight timeout without that being mistaken for a scan loop.
161
+ */
162
+ function normalizeTimeout(value, fallback) {
163
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
164
+ return fallback;
165
+ }
166
+ return value;
167
+ }
127
168
  function normalizePositiveInteger(value, fallback) {
128
169
  if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
129
170
  return fallback;
@@ -1 +1 @@
1
- {"version":3,"file":"notification-options.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/notification/notification-options.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"notification-options.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/notification/notification-options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { NotificationDigestModeEnum } from './notification.enums';
2
+ export interface NotificationQuietHours {
3
+ readonly quietHoursEnd: string | null;
4
+ readonly quietHoursStart: string | null;
5
+ readonly timeZone: string;
6
+ }
7
+ /**
8
+ * Whether `at` falls inside the recipient's quiet hours.
9
+ *
10
+ * A window whose start equals its end is treated as **no** quiet hours rather
11
+ * than as all day: the destructive reading of an ambiguous setting is the one
12
+ * that silently swallows every notification.
13
+ */
14
+ export declare function isWithinQuietHours(at: Date, { quietHoursEnd, quietHoursStart, timeZone }: NotificationQuietHours): boolean;
15
+ /**
16
+ * The instant the current quiet period ends, or `null` when `at` is not inside
17
+ * one.
18
+ */
19
+ export declare function resolveQuietHoursEnd(at: Date, quietHours: NotificationQuietHours): Date | null;
20
+ export interface EmailReleaseOptions extends NotificationQuietHours {
21
+ /** Local hour at which a `DAILY` recipient's held email is flushed. */
22
+ readonly digestHour: number;
23
+ readonly digestMode: NotificationDigestModeEnum;
24
+ }
25
+ /**
26
+ * When an email notification created at `at` may actually be sent, or `null`
27
+ * when it may go out immediately.
28
+ *
29
+ * The returned instant is written to the row's `nextRetryAt`, which is exactly
30
+ * what the delivery scan already treats as "not before": deferring reuses the
31
+ * retry machinery instead of adding a second scheduler, and means quiet hours
32
+ * *delay* a notification rather than drop it.
33
+ */
34
+ export declare function resolveEmailReleaseAt(at: Date, options: EmailReleaseOptions): Date | null;
35
+ export declare const DEFAULT_EMAIL_DIGEST_HOUR = 9;
36
+ /**
37
+ * Last-resort zone for quiet hours, used only when neither
38
+ * `notificationQuietHoursTimeZone` nor a registered business calendar answers.
39
+ */
40
+ export declare const DEFAULT_QUIET_HOURS_TIME_ZONE = "UTC";
41
+ export declare function normalizeDigestHour(value: number | undefined): number;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_QUIET_HOURS_TIME_ZONE = exports.DEFAULT_EMAIL_DIGEST_HOUR = void 0;
4
+ exports.isWithinQuietHours = isWithinQuietHours;
5
+ exports.resolveQuietHoursEnd = resolveQuietHoursEnd;
6
+ exports.resolveEmailReleaseAt = resolveEmailReleaseAt;
7
+ exports.normalizeDigestHour = normalizeDigestHour;
8
+ const notification_enums_1 = require("./notification.enums");
9
+ const MINUTES_PER_DAY = 24 * 60;
10
+ const MS_PER_MINUTE = 60_000;
11
+ const MS_PER_DAY = 24 * 60 * MS_PER_MINUTE;
12
+ /**
13
+ * A `time` column value as stored by `notification_preferences`, expressed as
14
+ * minutes since local midnight. `null` when the preference is unset or holds a
15
+ * value the DTO pattern would have rejected — a stored value BPM cannot read
16
+ * must degrade to "no quiet hours" rather than throw during delivery.
17
+ */
18
+ function parseTimeOfDay(value) {
19
+ const match = /^([01]\d|2[0-3]):([0-5]\d)(?::[0-5]\d)?$/.exec(value?.trim() ?? '');
20
+ if (!match) {
21
+ return null;
22
+ }
23
+ return Number(match[1]) * 60 + Number(match[2]);
24
+ }
25
+ function readZonedWallClock(at, timeZone) {
26
+ const parts = new Intl.DateTimeFormat('en-CA', {
27
+ day: '2-digit',
28
+ hour: '2-digit',
29
+ hour12: false,
30
+ minute: '2-digit',
31
+ month: '2-digit',
32
+ timeZone,
33
+ year: 'numeric',
34
+ }).formatToParts(at);
35
+ const read = (type) => Number(parts.find((part) => part.type === type)?.value ?? '0');
36
+ // `hourCycle: h23` is what `hour12: false` resolves to in every runtime this
37
+ // package supports, but Node has historically rendered midnight as `24`.
38
+ const hour = read('hour');
39
+ return {
40
+ day: read('day'),
41
+ hour: hour === 24 ? 0 : hour,
42
+ minute: read('minute'),
43
+ month: read('month'),
44
+ year: read('year'),
45
+ };
46
+ }
47
+ /** How far ahead of UTC the zone's local clock runs at `at`, in milliseconds. */
48
+ function readZoneOffsetMs(at, timeZone) {
49
+ const wallClock = readZonedWallClock(at, timeZone);
50
+ return (Date.UTC(wallClock.year, wallClock.month - 1, wallClock.day, wallClock.hour, wallClock.minute) -
51
+ // The formatter drops seconds and milliseconds, so compare against an
52
+ // instant truncated the same way.
53
+ Math.floor(at.getTime() / MS_PER_MINUTE) * MS_PER_MINUTE);
54
+ }
55
+ /**
56
+ * The instant at which the zone's local clock reads the given wall-clock time.
57
+ *
58
+ * Resolved in two passes because the offset to apply is itself a function of
59
+ * the instant: the first pass guesses using the offset in force at the naive
60
+ * UTC reading, the second re-reads the offset at that guess. That settles
61
+ * every case except a wall-clock time inside a spring-forward gap, which does
62
+ * not exist locally and lands on the instant the clock jumps to.
63
+ */
64
+ function zonedWallClockToInstant(wallClock, timeZone) {
65
+ const naiveUtc = Date.UTC(wallClock.year, wallClock.month - 1, wallClock.day, wallClock.hour, wallClock.minute);
66
+ const firstGuess = new Date(naiveUtc - readZoneOffsetMs(new Date(naiveUtc), timeZone));
67
+ return new Date(naiveUtc - readZoneOffsetMs(firstGuess, timeZone));
68
+ }
69
+ /**
70
+ * The first instant at or after `at` whose local clock reads
71
+ * `minuteOfDay`. Returns `at` itself when it already lands exactly there.
72
+ */
73
+ function nextLocalTimeOfDay(at, timeZone, minuteOfDay) {
74
+ const wallClock = readZonedWallClock(at, timeZone);
75
+ const sameDay = zonedWallClockToInstant({
76
+ ...wallClock,
77
+ hour: Math.floor(minuteOfDay / 60),
78
+ minute: minuteOfDay % 60,
79
+ }, timeZone);
80
+ if (sameDay.getTime() >= at.getTime()) {
81
+ return sameDay;
82
+ }
83
+ // Step a day forward through the instant rather than the calendar so a
84
+ // month or year boundary needs no special case, then re-anchor the local
85
+ // time in case the offset changed overnight.
86
+ const nextDay = readZonedWallClock(new Date(sameDay.getTime() + MS_PER_DAY), timeZone);
87
+ return zonedWallClockToInstant({
88
+ ...nextDay,
89
+ hour: Math.floor(minuteOfDay / 60),
90
+ minute: minuteOfDay % 60,
91
+ }, timeZone);
92
+ }
93
+ /**
94
+ * Whether `at` falls inside the recipient's quiet hours.
95
+ *
96
+ * A window whose start equals its end is treated as **no** quiet hours rather
97
+ * than as all day: the destructive reading of an ambiguous setting is the one
98
+ * that silently swallows every notification.
99
+ */
100
+ function isWithinQuietHours(at, { quietHoursEnd, quietHoursStart, timeZone }) {
101
+ const start = parseTimeOfDay(quietHoursStart);
102
+ const end = parseTimeOfDay(quietHoursEnd);
103
+ if (start === null || end === null || start === end) {
104
+ return false;
105
+ }
106
+ const wallClock = readZonedWallClock(at, timeZone);
107
+ const minuteOfDay = wallClock.hour * 60 + wallClock.minute;
108
+ return start < end
109
+ ? minuteOfDay >= start && minuteOfDay < end
110
+ : // A window that wraps past midnight (22:00–08:00) is the common case.
111
+ minuteOfDay >= start || minuteOfDay < end;
112
+ }
113
+ /**
114
+ * The instant the current quiet period ends, or `null` when `at` is not inside
115
+ * one.
116
+ */
117
+ function resolveQuietHoursEnd(at, quietHours) {
118
+ if (!isWithinQuietHours(at, quietHours)) {
119
+ return null;
120
+ }
121
+ const end = parseTimeOfDay(quietHours.quietHoursEnd);
122
+ return end === null
123
+ ? null
124
+ : nextLocalTimeOfDay(at, quietHours.timeZone, end % MINUTES_PER_DAY);
125
+ }
126
+ /**
127
+ * When an email notification created at `at` may actually be sent, or `null`
128
+ * when it may go out immediately.
129
+ *
130
+ * The returned instant is written to the row's `nextRetryAt`, which is exactly
131
+ * what the delivery scan already treats as "not before": deferring reuses the
132
+ * retry machinery instead of adding a second scheduler, and means quiet hours
133
+ * *delay* a notification rather than drop it.
134
+ */
135
+ function resolveEmailReleaseAt(at, options) {
136
+ const digestAt = options.digestMode === notification_enums_1.NotificationDigestModeEnum.DAILY
137
+ ? nextLocalTimeOfDay(at, options.timeZone, normalizeDigestHour(options.digestHour) * 60)
138
+ : at;
139
+ // Re-checked at the digest boundary, not at `at`: a digest hour that itself
140
+ // falls inside the quiet window must still wait for the window to close.
141
+ const releaseAt = resolveQuietHoursEnd(digestAt, options) ?? digestAt;
142
+ return releaseAt.getTime() > at.getTime() ? releaseAt : null;
143
+ }
144
+ exports.DEFAULT_EMAIL_DIGEST_HOUR = 9;
145
+ /**
146
+ * Last-resort zone for quiet hours, used only when neither
147
+ * `notificationQuietHoursTimeZone` nor a registered business calendar answers.
148
+ */
149
+ exports.DEFAULT_QUIET_HOURS_TIME_ZONE = 'UTC';
150
+ function normalizeDigestHour(value) {
151
+ return typeof value === 'number' &&
152
+ Number.isInteger(value) &&
153
+ value >= 0 &&
154
+ value <= 23
155
+ ? value
156
+ : exports.DEFAULT_EMAIL_DIGEST_HOUR;
157
+ }
158
+ //# sourceMappingURL=notification-schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-schedule.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/notification/notification-schedule.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,18 @@ export declare class NotificationEntity {
19
19
  * default list without deleting the record, so statistics and audits keep it.
20
20
  */
21
21
  archivedAt: Date | null;
22
+ /**
23
+ * The row was recorded but deliberately not announced, because the
24
+ * recipient's preferences asked for quiet — `inAppEnabled: false`, or the
25
+ * notification arriving inside their quiet hours.
26
+ *
27
+ * BPM keeps writing the row either way: "do not interrupt me" and "do not
28
+ * keep a record" are different requests, and a notification centre that
29
+ * silently loses an approval task is the worse failure. Hosts driving a
30
+ * realtime channel should skip the toast or push for a silenced row and
31
+ * style it as read-later in the list.
32
+ */
33
+ silenced: boolean;
22
34
  attemptCount: number;
23
35
  lastAttemptAt: Date | null;
24
36
  nextRetryAt: Date | null;
@@ -105,6 +105,11 @@ tslib_1.__decorate([
105
105
  (0, graphql_1.Field)(() => Date, { nullable: true }),
106
106
  tslib_1.__metadata("design:type", Object)
107
107
  ], NotificationEntity.prototype, "archivedAt", void 0);
108
+ tslib_1.__decorate([
109
+ (0, typeorm_1.Column)('boolean', { name: 'silenced', default: false }),
110
+ (0, graphql_1.Field)(),
111
+ tslib_1.__metadata("design:type", Boolean)
112
+ ], NotificationEntity.prototype, "silenced", void 0);
108
113
  tslib_1.__decorate([
109
114
  (0, typeorm_1.Column)('integer', { name: 'attempt_count', default: 0 }),
110
115
  (0, graphql_1.Field)(() => Number),
@@ -1 +1 @@
1
- {"version":3,"file":"notification.entity.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/notification/notification.entity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"notification.entity.js","sourceRoot":"","sources":["../../../../../../libs/bpm-core/src/lib/notification/notification.entity.ts"],"names":[],"mappings":"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"}
@@ -138,6 +138,16 @@ export declare class NotificationService {
138
138
  * approval.
139
139
  */
140
140
  private notifyObserver;
141
+ /**
142
+ * The zone the recipients' bare `HH:mm` quiet-hours preferences are read in.
143
+ *
144
+ * Falls back to the registered business calendar rather than to UTC: the
145
+ * calendar already states where the host's people are, and a host that
146
+ * supplied one would otherwise get quiet hours silently offset by its whole
147
+ * UTC offset. Resolved here rather than in the flattened options because the
148
+ * calendar is a DI provider that does not exist at wiring time.
149
+ */
150
+ private readQuietHoursTimeZone;
141
151
  private readHostObserver;
142
152
  private recordSlaActivity;
143
153
  private runSlaTimeoutHook;
@@ -8,6 +8,7 @@ const common_1 = require("@nestjs/common");
8
8
  const core_1 = require("@nestjs/core");
9
9
  const typeorm_1 = require("@nestjs/typeorm");
10
10
  const typeorm_2 = require("typeorm");
11
+ const business_calendar_token_1 = require("../calendar/business-calendar.token");
11
12
  const iso_duration_1 = require("../common/iso-duration");
12
13
  const activity_log_entity_1 = require("../workflow-engine/activity-log.entity");
13
14
  const approval_instance_entity_1 = require("../workflow-engine/approval-instance.entity");
@@ -18,6 +19,7 @@ const workflow_engine_tokens_1 = require("../workflow-engine/workflow-engine.tok
18
19
  const workflow_engine_enums_1 = require("../workflow-engine/workflow-engine.enums");
19
20
  const notification_delivery_service_1 = require("./notification-delivery.service");
20
21
  const notification_preference_entity_1 = require("./notification-preference.entity");
22
+ const notification_schedule_1 = require("./notification-schedule");
21
23
  const notification_entity_1 = require("./notification.entity");
22
24
  const notification_enums_1 = require("./notification.enums");
23
25
  const ACTIONABLE_NOTIFICATION_TYPES = [
@@ -507,27 +509,44 @@ let NotificationService = NotificationService_1 = class NotificationService {
507
509
  }, Promise.resolve(0));
508
510
  return createdNotifications > 0;
509
511
  }
510
- async createNotifications(input, manager) {
512
+ async createNotifications(input, manager, now = new Date()) {
511
513
  const preference = await this.getPreference(input.recipientMemberId);
512
514
  const repository = manager
513
515
  ? manager.getRepository(notification_entity_1.NotificationEntity)
514
516
  : this.notificationRepository;
515
- const notifications = input.channels.flatMap((channel) => isChannelEnabled(channel, preference, this.notificationOptions)
516
- ? [
517
- createNotificationEntity({
518
- channel,
519
- input,
520
- options: this.notificationOptions,
521
- repository,
522
- }),
523
- ]
524
- : []);
517
+ const quietHoursTimeZone = this.readQuietHoursTimeZone();
518
+ const notifications = input.channels.flatMap((channel) => {
519
+ const delivery = resolveChannelDelivery({
520
+ at: now,
521
+ channel,
522
+ options: this.notificationOptions,
523
+ preference,
524
+ quietHoursTimeZone,
525
+ });
526
+ return delivery.record
527
+ ? [
528
+ createNotificationEntity({
529
+ channel,
530
+ input,
531
+ now,
532
+ options: this.notificationOptions,
533
+ releaseAt: delivery.releaseAt,
534
+ repository,
535
+ silenced: delivery.silenced,
536
+ }),
537
+ ]
538
+ : [];
539
+ });
525
540
  if (notifications.length === 0) {
526
541
  return [];
527
542
  }
528
543
  const savedNotifications = await repository.save(notifications);
529
544
  await Promise.all(savedNotifications
530
- .filter((notification) => notification.channel !== notification_enums_1.NotificationChannelEnum.IN_APP)
545
+ .filter((notification) => notification.channel !== notification_enums_1.NotificationChannelEnum.IN_APP &&
546
+ // A row held for quiet hours or a daily digest carries its release
547
+ // instant in `nextRetryAt`; the delivery scan is what picks it up
548
+ // once that instant passes.
549
+ notification.nextRetryAt === null)
531
550
  .map((notification) => manager
532
551
  ? Promise.resolve(false)
533
552
  : this.deliveryService.deliverNotification(notification, this.notificationOptions)));
@@ -561,6 +580,28 @@ let NotificationService = NotificationService_1 = class NotificationService {
561
580
  this.logger.error(`BPM_NOTIFICATION_OBSERVER failed for ${notifications.length} notification(s)`, error instanceof Error ? error.stack : String(error));
562
581
  }
563
582
  }
583
+ /**
584
+ * The zone the recipients' bare `HH:mm` quiet-hours preferences are read in.
585
+ *
586
+ * Falls back to the registered business calendar rather than to UTC: the
587
+ * calendar already states where the host's people are, and a host that
588
+ * supplied one would otherwise get quiet hours silently offset by its whole
589
+ * UTC offset. Resolved here rather than in the flattened options because the
590
+ * calendar is a DI provider that does not exist at wiring time.
591
+ */
592
+ readQuietHoursTimeZone() {
593
+ if (this.notificationOptions.quietHoursTimeZone) {
594
+ return this.notificationOptions.quietHoursTimeZone;
595
+ }
596
+ try {
597
+ return this.moduleRef.get(business_calendar_token_1.BPM_BUSINESS_CALENDAR, {
598
+ strict: false,
599
+ }).timeZone;
600
+ }
601
+ catch {
602
+ return notification_schedule_1.DEFAULT_QUIET_HOURS_TIME_ZONE;
603
+ }
604
+ }
564
605
  readHostObserver() {
565
606
  try {
566
607
  return this.moduleRef.get(notification_observer_token_1.BPM_NOTIFICATION_OBSERVER, { strict: false });
@@ -769,14 +810,49 @@ function isUniqueConstraintViolation(error) {
769
810
  'code' in error &&
770
811
  error.code === '23505');
771
812
  }
772
- function isChannelEnabled(channel, preference, options) {
813
+ /**
814
+ * Splits a channel's fate into "is it recorded" and "is it announced", which
815
+ * `inAppEnabled` used to conflate.
816
+ *
817
+ * The member preference decides announcement. Recording is the host's call:
818
+ * `options.inAppEnabled` is a wiring-level switch for running BPM without
819
+ * notification-centre data at all, not something a member can trip. Email and
820
+ * webhook have no BPM-side record to lose, so for them the two answers stay
821
+ * the same — except in time, where quiet hours and the daily digest push
822
+ * delivery later rather than dropping it.
823
+ */
824
+ function resolveChannelDelivery({ at, channel, options, preference, quietHoursTimeZone, }) {
825
+ const quietHours = {
826
+ quietHoursEnd: preference.quietHoursEnd,
827
+ quietHoursStart: preference.quietHoursStart,
828
+ timeZone: quietHoursTimeZone,
829
+ };
773
830
  if (channel === notification_enums_1.NotificationChannelEnum.IN_APP) {
774
- return options.inAppEnabled && preference.inAppEnabled;
831
+ return {
832
+ releaseAt: null,
833
+ record: options.inAppEnabled,
834
+ silenced: !preference.inAppEnabled || (0, notification_schedule_1.isWithinQuietHours)(at, quietHours),
835
+ };
775
836
  }
776
837
  if (channel === notification_enums_1.NotificationChannelEnum.EMAIL) {
777
- return options.emailEnabled && preference.emailEnabled;
778
- }
779
- return options.webhookEnabled;
838
+ const record = options.emailEnabled && preference.emailEnabled;
839
+ return {
840
+ releaseAt: record
841
+ ? (0, notification_schedule_1.resolveEmailReleaseAt)(at, {
842
+ ...quietHours,
843
+ digestHour: options.emailDigestHour,
844
+ digestMode: preference.emailDigestMode,
845
+ })
846
+ : null,
847
+ record,
848
+ silenced: false,
849
+ };
850
+ }
851
+ return {
852
+ releaseAt: null,
853
+ record: options.webhookEnabled,
854
+ silenced: false,
855
+ };
780
856
  }
781
857
  function hasSlaEscalationStep(task) {
782
858
  return task.delegationChain.some((step) => step['reason'] === notification_enums_1.SLA_ESCALATION_DELEGATION_REASON);
@@ -793,7 +869,7 @@ function isSlaTimeoutActionEnabled(action, options) {
793
869
  }
794
870
  return options.slaTimeoutRemindEnabled;
795
871
  }
796
- function createNotificationEntity({ channel, input, options, repository, }) {
872
+ function createNotificationEntity({ channel, input, now, options, releaseAt, repository, silenced, }) {
797
873
  const renderedTemplate = (0, notification_template_1.renderNotificationTemplate)({
798
874
  customTemplate: input.customTemplate,
799
875
  engine: options.templateEngine,
@@ -808,18 +884,21 @@ function createNotificationEntity({ channel, input, options, repository, }) {
808
884
  attemptCount: 0,
809
885
  body: renderedTemplate.body,
810
886
  channel,
811
- deliveredAt: isInApp ? new Date() : null,
887
+ // An in-app row is "delivered" the moment it exists, silenced or not:
888
+ // what silencing withholds is the announcement, not the record.
889
+ deliveredAt: isInApp ? now : null,
812
890
  deliveryError: null,
813
891
  deliveryTarget: null,
814
892
  instanceId: input.instanceId,
815
893
  lastAttemptAt: null,
816
- nextRetryAt: null,
894
+ nextRetryAt: releaseAt,
817
895
  payload: input.payload,
818
896
  readAt: null,
819
897
  recipientMemberId: input.recipientMemberId,
820
898
  resolution: null,
821
899
  resolvedAt: null,
822
- sentAt: isInApp ? new Date() : null,
900
+ sentAt: isInApp ? now : null,
901
+ silenced,
823
902
  status: isInApp
824
903
  ? notification_enums_1.NotificationStatusEnum.SENT
825
904
  : notification_enums_1.NotificationStatusEnum.PENDING,