@dudousxd/nestjs-notifications-preferences 0.2.0 → 0.4.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 (37) hide show
  1. package/dist/category-registry.d.ts +35 -0
  2. package/dist/category-registry.d.ts.map +1 -0
  3. package/dist/category-registry.js +78 -0
  4. package/dist/category-registry.js.map +1 -0
  5. package/dist/in-memory.preference-center.store.d.ts +20 -0
  6. package/dist/in-memory.preference-center.store.d.ts.map +1 -0
  7. package/dist/in-memory.preference-center.store.js +75 -0
  8. package/dist/in-memory.preference-center.store.js.map +1 -0
  9. package/dist/index.d.ts +8 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +15 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/preference-center.controller.d.ts +36 -0
  14. package/dist/preference-center.controller.d.ts.map +1 -0
  15. package/dist/preference-center.controller.js +104 -0
  16. package/dist/preference-center.controller.js.map +1 -0
  17. package/dist/preference-center.gate.d.ts +28 -0
  18. package/dist/preference-center.gate.d.ts.map +1 -0
  19. package/dist/preference-center.gate.js +62 -0
  20. package/dist/preference-center.gate.js.map +1 -0
  21. package/dist/preference-center.interfaces.d.ts +87 -0
  22. package/dist/preference-center.interfaces.d.ts.map +1 -0
  23. package/dist/preference-center.interfaces.js +3 -0
  24. package/dist/preference-center.interfaces.js.map +1 -0
  25. package/dist/preference-center.service.d.ts +41 -0
  26. package/dist/preference-center.service.d.ts.map +1 -0
  27. package/dist/preference-center.service.js +124 -0
  28. package/dist/preference-center.service.js.map +1 -0
  29. package/dist/preferences.module.d.ts +23 -1
  30. package/dist/preferences.module.d.ts.map +1 -1
  31. package/dist/preferences.module.js +36 -1
  32. package/dist/preferences.module.js.map +1 -1
  33. package/dist/tokens.d.ts +4 -0
  34. package/dist/tokens.d.ts.map +1 -1
  35. package/dist/tokens.js +5 -1
  36. package/dist/tokens.js.map +1 -1
  37. package/package.json +5 -5
@@ -0,0 +1,35 @@
1
+ import type { Notification } from '@dudousxd/nestjs-notifications-core';
2
+ import type { CategoryDefinition } from './preference-center.interfaces';
3
+ /** The category key used when a notification declares none. */
4
+ export declare const DEFAULT_CATEGORY = "general";
5
+ /**
6
+ * Resolve a notification's category. Reads an explicit `category` property/getter off the
7
+ * notification; falls back to {@link DEFAULT_CATEGORY} when absent.
8
+ *
9
+ * ```ts
10
+ * class InvoicePaid { readonly category = 'billing'; ... }
11
+ * getCategory(new InvoicePaid()); // 'billing'
12
+ * ```
13
+ */
14
+ export declare function getCategory(notification: Notification): string;
15
+ /**
16
+ * Holds the app's {@link CategoryDefinition}s (provided via module options) and answers lookups.
17
+ * Unknown categories resolve to a synthesized definition so the system never hard-fails on a
18
+ * category the app forgot to register.
19
+ */
20
+ export declare class CategoryRegistry {
21
+ private readonly byKey;
22
+ constructor(categories: CategoryDefinition[]);
23
+ /** All registered category definitions, in registration order. */
24
+ all(): CategoryDefinition[];
25
+ /** Look up a definition by key, or `undefined` if not registered. */
26
+ find(key: string): CategoryDefinition | undefined;
27
+ /**
28
+ * Resolve a definition for a key, synthesizing a permissive default for unknown keys so
29
+ * downstream code always has a definition to work with.
30
+ */
31
+ get(key: string): CategoryDefinition;
32
+ /** Resolve the category key for a notification (explicit `category` or the default). */
33
+ resolve(notification: Notification): string;
34
+ }
35
+ //# sourceMappingURL=category-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"category-registry.d.ts","sourceRoot":"","sources":["../src/category-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAO1C;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM,CAG9D;AAED;;;;GAIG;AACH,qBACa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyC;gBAEb,UAAU,EAAE,kBAAkB,EAAE;IAMlF,kEAAkE;IAClE,GAAG,IAAI,kBAAkB,EAAE;IAI3B,qEAAqE;IACrE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIjD;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,kBAAkB;IAYpC,wFAAwF;IACxF,OAAO,CAAC,YAAY,EAAE,YAAY,GAAG,MAAM;CAG5C"}
@@ -0,0 +1,78 @@
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
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.CategoryRegistry = exports.DEFAULT_CATEGORY = void 0;
16
+ exports.getCategory = getCategory;
17
+ const common_1 = require("@nestjs/common");
18
+ const tokens_1 = require("./tokens");
19
+ /** The category key used when a notification declares none. */
20
+ exports.DEFAULT_CATEGORY = 'general';
21
+ /**
22
+ * Resolve a notification's category. Reads an explicit `category` property/getter off the
23
+ * notification; falls back to {@link DEFAULT_CATEGORY} when absent.
24
+ *
25
+ * ```ts
26
+ * class InvoicePaid { readonly category = 'billing'; ... }
27
+ * getCategory(new InvoicePaid()); // 'billing'
28
+ * ```
29
+ */
30
+ function getCategory(notification) {
31
+ const category = notification.category;
32
+ return typeof category === 'string' && category.length > 0 ? category : exports.DEFAULT_CATEGORY;
33
+ }
34
+ /**
35
+ * Holds the app's {@link CategoryDefinition}s (provided via module options) and answers lookups.
36
+ * Unknown categories resolve to a synthesized definition so the system never hard-fails on a
37
+ * category the app forgot to register.
38
+ */
39
+ let CategoryRegistry = class CategoryRegistry {
40
+ byKey = new Map();
41
+ constructor(categories) {
42
+ for (const category of categories) {
43
+ this.byKey.set(category.key, { allowDigest: true, ...category });
44
+ }
45
+ }
46
+ /** All registered category definitions, in registration order. */
47
+ all() {
48
+ return [...this.byKey.values()];
49
+ }
50
+ /** Look up a definition by key, or `undefined` if not registered. */
51
+ find(key) {
52
+ return this.byKey.get(key);
53
+ }
54
+ /**
55
+ * Resolve a definition for a key, synthesizing a permissive default for unknown keys so
56
+ * downstream code always has a definition to work with.
57
+ */
58
+ get(key) {
59
+ return (this.byKey.get(key) ?? {
60
+ key,
61
+ label: key,
62
+ defaultChannels: [],
63
+ mandatory: false,
64
+ allowDigest: true,
65
+ });
66
+ }
67
+ /** Resolve the category key for a notification (explicit `category` or the default). */
68
+ resolve(notification) {
69
+ return getCategory(notification);
70
+ }
71
+ };
72
+ exports.CategoryRegistry = CategoryRegistry;
73
+ exports.CategoryRegistry = CategoryRegistry = __decorate([
74
+ (0, common_1.Injectable)(),
75
+ __param(0, (0, common_1.Inject)(tokens_1.PREFERENCE_CENTER_CATEGORIES)),
76
+ __metadata("design:paramtypes", [Array])
77
+ ], CategoryRegistry);
78
+ //# sourceMappingURL=category-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"category-registry.js","sourceRoot":"","sources":["../src/category-registry.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAsBA,kCAGC;AAxBD,2CAAoD;AAEpD,qCAAwD;AAExD,+DAA+D;AAClD,QAAA,gBAAgB,GAAG,SAAS,CAAC;AAO1C;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,YAA0B;IACpD,MAAM,QAAQ,GAAI,YAA4B,CAAC,QAAQ,CAAC;IACxD,OAAO,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,wBAAgB,CAAC;AAC3F,CAAC;AAED;;;;GAIG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IACV,KAAK,GAAG,IAAI,GAAG,EAA8B,CAAC;IAE/D,YAAkD,UAAgC;QAChF,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,kEAAkE;IAClE,GAAG;QACD,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,qEAAqE;IACrE,IAAI,CAAC,GAAW;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,GAAW;QACb,OAAO,CACL,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI;YACrB,GAAG;YACH,KAAK,EAAE,GAAG;YACV,eAAe,EAAE,EAAE;YACnB,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,IAAI;SAClB,CACF,CAAC;IACJ,CAAC;IAED,wFAAwF;IACxF,OAAO,CAAC,YAA0B;QAChC,OAAO,WAAW,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;CACF,CAAA;AAvCY,4CAAgB;2BAAhB,gBAAgB;IAD5B,IAAA,mBAAU,GAAE;IAIE,WAAA,IAAA,eAAM,EAAC,qCAA4B,CAAC,CAAA;;GAHtC,gBAAgB,CAuC5B"}
@@ -0,0 +1,20 @@
1
+ import type { NotifiableRef } from '@dudousxd/nestjs-notifications-core';
2
+ import type { CategoryPreference, DigestFrequency, PreferenceCenterStore, PreferenceMatrix } from './preference-center.interfaces';
3
+ /**
4
+ * In-memory {@link PreferenceCenterStore} for tests and prototyping. Holds each notifiable's
5
+ * stored category preferences. Not for production — state is lost on restart.
6
+ */
7
+ export declare class InMemoryPreferenceCenterStore implements PreferenceCenterStore {
8
+ /** scopeKey -> (category -> CategoryPreference). */
9
+ private readonly matrices;
10
+ getMatrix(ref: NotifiableRef, tenantId?: string): Promise<PreferenceMatrix>;
11
+ setChannel(ref: NotifiableRef, category: string, channel: string, enabled: boolean, tenantId?: string): Promise<void>;
12
+ setDigest(ref: NotifiableRef, category: string, digest: DigestFrequency, tenantId?: string): Promise<void>;
13
+ setCategory(ref: NotifiableRef, category: string, pref: CategoryPreference, tenantId?: string): Promise<void>;
14
+ resetCategory(ref: NotifiableRef, category: string, tenantId?: string): Promise<void>;
15
+ /** Get (or create) the per-scope category map. */
16
+ private bucket;
17
+ /** Get (or create) a category preference within a scope. */
18
+ private ensure;
19
+ }
20
+ //# sourceMappingURL=in-memory.preference-center.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.preference-center.store.d.ts","sourceRoot":"","sources":["../src/in-memory.preference-center.store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,KAAK,EACV,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EACjB,MAAM,gCAAgC,CAAC;AAOxC;;;GAGG;AACH,qBACa,6BAA8B,YAAW,qBAAqB;IACzE,oDAAoD;IACpD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsD;IAEzE,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAW3E,UAAU,CACd,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAKV,SAAS,CACb,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAKV,WAAW,CACf,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAQV,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3F,kDAAkD;IAClD,OAAO,CAAC,MAAM;IAUd,4DAA4D;IAC5D,OAAO,CAAC,MAAM;CASf"}
@@ -0,0 +1,75 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.InMemoryPreferenceCenterStore = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ /** Build a stable key for a (tenant, notifiable) scope. */
12
+ function scopeKey(ref, tenantId) {
13
+ return JSON.stringify([tenantId ?? null, ref.type, String(ref.id)]);
14
+ }
15
+ /**
16
+ * In-memory {@link PreferenceCenterStore} for tests and prototyping. Holds each notifiable's
17
+ * stored category preferences. Not for production — state is lost on restart.
18
+ */
19
+ let InMemoryPreferenceCenterStore = class InMemoryPreferenceCenterStore {
20
+ /** scopeKey -> (category -> CategoryPreference). */
21
+ matrices = new Map();
22
+ async getMatrix(ref, tenantId) {
23
+ const stored = this.matrices.get(scopeKey(ref, tenantId));
24
+ const categories = {};
25
+ if (stored) {
26
+ for (const [key, pref] of stored) {
27
+ categories[key] = { ...pref, channels: { ...pref.channels } };
28
+ }
29
+ }
30
+ return { ref, tenantId, categories };
31
+ }
32
+ async setChannel(ref, category, channel, enabled, tenantId) {
33
+ const pref = this.ensure(ref, category, tenantId);
34
+ pref.channels[channel] = enabled;
35
+ }
36
+ async setDigest(ref, category, digest, tenantId) {
37
+ const pref = this.ensure(ref, category, tenantId);
38
+ pref.digest = digest;
39
+ }
40
+ async setCategory(ref, category, pref, tenantId) {
41
+ this.bucket(ref, tenantId).set(category, {
42
+ category,
43
+ digest: pref.digest,
44
+ channels: { ...pref.channels },
45
+ });
46
+ }
47
+ async resetCategory(ref, category, tenantId) {
48
+ this.matrices.get(scopeKey(ref, tenantId))?.delete(category);
49
+ }
50
+ /** Get (or create) the per-scope category map. */
51
+ bucket(ref, tenantId) {
52
+ const key = scopeKey(ref, tenantId);
53
+ let bucket = this.matrices.get(key);
54
+ if (!bucket) {
55
+ bucket = new Map();
56
+ this.matrices.set(key, bucket);
57
+ }
58
+ return bucket;
59
+ }
60
+ /** Get (or create) a category preference within a scope. */
61
+ ensure(ref, category, tenantId) {
62
+ const bucket = this.bucket(ref, tenantId);
63
+ let pref = bucket.get(category);
64
+ if (!pref) {
65
+ pref = { category, channels: {}, digest: 'instant' };
66
+ bucket.set(category, pref);
67
+ }
68
+ return pref;
69
+ }
70
+ };
71
+ exports.InMemoryPreferenceCenterStore = InMemoryPreferenceCenterStore;
72
+ exports.InMemoryPreferenceCenterStore = InMemoryPreferenceCenterStore = __decorate([
73
+ (0, common_1.Injectable)()
74
+ ], InMemoryPreferenceCenterStore);
75
+ //# sourceMappingURL=in-memory.preference-center.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.preference-center.store.js","sourceRoot":"","sources":["../src/in-memory.preference-center.store.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,13 @@
1
1
  export type { PreferenceKey, PreferenceScope, PreferenceStore } from './interfaces';
2
- export { NOTIFICATION_PREFERENCE_STORE } from './tokens';
2
+ export { NOTIFICATION_PREFERENCE_STORE, PREFERENCE_CENTER_CATEGORIES, PREFERENCE_CENTER_STORE, } from './tokens';
3
3
  export { InMemoryPreferenceStore } from './in-memory.store';
4
4
  export { NotificationPreferences, type PreferenceTarget, type ScopedPreferences, } from './notification-preferences';
5
5
  export { PreferenceGateAdapter } from './preference-gate.adapter';
6
- export { PreferencesModule, type PreferencesModuleOptions, } from './preferences.module';
6
+ export { PreferencesModule, type PreferencesModuleOptions, type PreferenceCenterModuleOptions, } from './preferences.module';
7
+ export type { CategoryDefinition, CategoryPreference, ChannelPreference, DigestFrequency, PreferenceCenterStore, PreferenceMatrix, PreferenceResolution, } from './preference-center.interfaces';
8
+ export { CategoryRegistry, DEFAULT_CATEGORY, getCategory, } from './category-registry';
9
+ export { InMemoryPreferenceCenterStore } from './in-memory.preference-center.store';
10
+ export { PreferenceCenterService } from './preference-center.service';
11
+ export { PreferenceCenterGate } from './preference-center.gate';
12
+ export { createPreferenceCenterController, type PreferenceCenterControllerOptions, } from './preference-center.controller';
7
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,6BAA6B,EAAE,MAAM,UAAU,CAAC;AACzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EACL,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EACL,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,GACvB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,GACnC,MAAM,sBAAsB,CAAC;AAG9B,YAAY,EACV,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACL,gCAAgC,EAChC,KAAK,iCAAiC,GACvC,MAAM,gCAAgC,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PreferencesModule = exports.PreferenceGateAdapter = exports.NotificationPreferences = exports.InMemoryPreferenceStore = exports.NOTIFICATION_PREFERENCE_STORE = void 0;
3
+ exports.createPreferenceCenterController = exports.PreferenceCenterGate = exports.PreferenceCenterService = exports.InMemoryPreferenceCenterStore = exports.getCategory = exports.DEFAULT_CATEGORY = exports.CategoryRegistry = exports.PreferencesModule = exports.PreferenceGateAdapter = exports.NotificationPreferences = exports.InMemoryPreferenceStore = exports.PREFERENCE_CENTER_STORE = exports.PREFERENCE_CENTER_CATEGORIES = exports.NOTIFICATION_PREFERENCE_STORE = void 0;
4
4
  var tokens_1 = require("./tokens");
5
5
  Object.defineProperty(exports, "NOTIFICATION_PREFERENCE_STORE", { enumerable: true, get: function () { return tokens_1.NOTIFICATION_PREFERENCE_STORE; } });
6
+ Object.defineProperty(exports, "PREFERENCE_CENTER_CATEGORIES", { enumerable: true, get: function () { return tokens_1.PREFERENCE_CENTER_CATEGORIES; } });
7
+ Object.defineProperty(exports, "PREFERENCE_CENTER_STORE", { enumerable: true, get: function () { return tokens_1.PREFERENCE_CENTER_STORE; } });
6
8
  var in_memory_store_1 = require("./in-memory.store");
7
9
  Object.defineProperty(exports, "InMemoryPreferenceStore", { enumerable: true, get: function () { return in_memory_store_1.InMemoryPreferenceStore; } });
8
10
  var notification_preferences_1 = require("./notification-preferences");
@@ -11,4 +13,16 @@ var preference_gate_adapter_1 = require("./preference-gate.adapter");
11
13
  Object.defineProperty(exports, "PreferenceGateAdapter", { enumerable: true, get: function () { return preference_gate_adapter_1.PreferenceGateAdapter; } });
12
14
  var preferences_module_1 = require("./preferences.module");
13
15
  Object.defineProperty(exports, "PreferencesModule", { enumerable: true, get: function () { return preferences_module_1.PreferencesModule; } });
16
+ var category_registry_1 = require("./category-registry");
17
+ Object.defineProperty(exports, "CategoryRegistry", { enumerable: true, get: function () { return category_registry_1.CategoryRegistry; } });
18
+ Object.defineProperty(exports, "DEFAULT_CATEGORY", { enumerable: true, get: function () { return category_registry_1.DEFAULT_CATEGORY; } });
19
+ Object.defineProperty(exports, "getCategory", { enumerable: true, get: function () { return category_registry_1.getCategory; } });
20
+ var in_memory_preference_center_store_1 = require("./in-memory.preference-center.store");
21
+ Object.defineProperty(exports, "InMemoryPreferenceCenterStore", { enumerable: true, get: function () { return in_memory_preference_center_store_1.InMemoryPreferenceCenterStore; } });
22
+ var preference_center_service_1 = require("./preference-center.service");
23
+ Object.defineProperty(exports, "PreferenceCenterService", { enumerable: true, get: function () { return preference_center_service_1.PreferenceCenterService; } });
24
+ var preference_center_gate_1 = require("./preference-center.gate");
25
+ Object.defineProperty(exports, "PreferenceCenterGate", { enumerable: true, get: function () { return preference_center_gate_1.PreferenceCenterGate; } });
26
+ var preference_center_controller_1 = require("./preference-center.controller");
27
+ Object.defineProperty(exports, "createPreferenceCenterController", { enumerable: true, get: function () { return preference_center_controller_1.createPreferenceCenterController; } });
14
28
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,mCAAyD;AAAhD,uHAAA,6BAA6B,OAAA;AACtC,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uEAIoC;AAHlC,mIAAA,uBAAuB,OAAA;AAIzB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,2DAG8B;AAF5B,uHAAA,iBAAiB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AACA,mCAIkB;AAHhB,uHAAA,6BAA6B,OAAA;AAC7B,sHAAA,4BAA4B,OAAA;AAC5B,iHAAA,uBAAuB,OAAA;AAEzB,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uEAIoC;AAHlC,mIAAA,uBAAuB,OAAA;AAIzB,qEAAkE;AAAzD,gIAAA,qBAAqB,OAAA;AAC9B,2DAI8B;AAH5B,uHAAA,iBAAiB,OAAA;AAenB,yDAI6B;AAH3B,qHAAA,gBAAgB,OAAA;AAChB,qHAAA,gBAAgB,OAAA;AAChB,gHAAA,WAAW,OAAA;AAEb,yFAAoF;AAA3E,kJAAA,6BAA6B,OAAA;AACtC,yEAAsE;AAA7D,oIAAA,uBAAuB,OAAA;AAChC,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,+EAGwC;AAFtC,gJAAA,gCAAgC,OAAA"}
@@ -0,0 +1,36 @@
1
+ import type { NotifiableRef } from '@dudousxd/nestjs-notifications-core';
2
+ import { type CanActivate, type Type } from '@nestjs/common';
3
+ /** Options for {@link createPreferenceCenterController}. */
4
+ export interface PreferenceCenterControllerOptions {
5
+ /**
6
+ * Resolves the current notifiable from the request (e.g. from `req.user`). May be async.
7
+ * The returned ref scopes every read/write to that notifiable.
8
+ */
9
+ resolveRef: (req: any) => NotifiableRef | Promise<NotifiableRef>;
10
+ /** Optional resolver for the tenant scope (multi-tenant apps). May be async. */
11
+ resolveTenant?: (req: any) => string | undefined | Promise<string | undefined>;
12
+ /** Controller base path. Default `'preferences'`. */
13
+ path?: string;
14
+ /** Guards to protect the endpoints with (e.g. your auth guard). Applied via `@UseGuards`. */
15
+ guards?: Array<Type<CanActivate> | CanActivate>;
16
+ }
17
+ /**
18
+ * Builds a `@Controller('preferences')` exposing the preference-center backend that a UI (e.g.
19
+ * the React package) consumes:
20
+ *
21
+ * - `GET /preferences/categories` — the configured category definitions
22
+ * - `GET /preferences` — the resolved matrix for the current notifiable
23
+ * - `PUT /preferences/:category/channels/:channel` — body `{ enabled: boolean }`
24
+ * - `PUT /preferences/:category/digest` — body `{ digest: DigestFrequency }`
25
+ *
26
+ * Mount it by adding the returned class to a module's `controllers`, alongside
27
+ * `PreferencesModule.forCenter(...)` (which provides {@link PreferenceCenterService}):
28
+ *
29
+ * ```ts
30
+ * const PreferenceCenterController = createPreferenceCenterController({
31
+ * resolveRef: (req) => ({ type: 'User', id: req.user.id }),
32
+ * });
33
+ * ```
34
+ */
35
+ export declare function createPreferenceCenterController(options: PreferenceCenterControllerOptions): Type<unknown>;
36
+ //# sourceMappingURL=preference-center.controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.controller.d.ts","sourceRoot":"","sources":["../src/preference-center.controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAEL,KAAK,WAAW,EAMhB,KAAK,IAAI,EAEV,MAAM,gBAAgB,CAAC;AAQxB,4DAA4D;AAC5D,MAAM,WAAW,iCAAiC;IAChD;;;OAGG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACjE,gFAAgF;IAChF,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC/E,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6FAA6F;IAC7F,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,CAAC;CACjD;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,iCAAiC,GACzC,IAAI,CAAC,OAAO,CAAC,CAgDf"}
@@ -0,0 +1,104 @@
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
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createPreferenceCenterController = createPreferenceCenterController;
16
+ const common_1 = require("@nestjs/common");
17
+ const preference_center_service_1 = require("./preference-center.service");
18
+ /**
19
+ * Builds a `@Controller('preferences')` exposing the preference-center backend that a UI (e.g.
20
+ * the React package) consumes:
21
+ *
22
+ * - `GET /preferences/categories` — the configured category definitions
23
+ * - `GET /preferences` — the resolved matrix for the current notifiable
24
+ * - `PUT /preferences/:category/channels/:channel` — body `{ enabled: boolean }`
25
+ * - `PUT /preferences/:category/digest` — body `{ digest: DigestFrequency }`
26
+ *
27
+ * Mount it by adding the returned class to a module's `controllers`, alongside
28
+ * `PreferencesModule.forCenter(...)` (which provides {@link PreferenceCenterService}):
29
+ *
30
+ * ```ts
31
+ * const PreferenceCenterController = createPreferenceCenterController({
32
+ * resolveRef: (req) => ({ type: 'User', id: req.user.id }),
33
+ * });
34
+ * ```
35
+ */
36
+ function createPreferenceCenterController(options) {
37
+ let PreferenceCenterController = class PreferenceCenterController {
38
+ preferences;
39
+ constructor(preferences) {
40
+ this.preferences = preferences;
41
+ }
42
+ categories() {
43
+ return this.preferences.listCategories();
44
+ }
45
+ async matrix(req) {
46
+ const ref = await options.resolveRef(req);
47
+ const tenantId = await options.resolveTenant?.(req);
48
+ return this.preferences.getMatrix(ref, tenantId);
49
+ }
50
+ async setChannel(req, category, channel, body) {
51
+ const ref = await options.resolveRef(req);
52
+ const tenantId = await options.resolveTenant?.(req);
53
+ await this.preferences.setChannel(ref, category, channel, body.enabled, tenantId);
54
+ return this.preferences.getMatrix(ref, tenantId);
55
+ }
56
+ async setDigest(req, category, body) {
57
+ const ref = await options.resolveRef(req);
58
+ const tenantId = await options.resolveTenant?.(req);
59
+ await this.preferences.setDigest(ref, category, body.digest, tenantId);
60
+ return this.preferences.getMatrix(ref, tenantId);
61
+ }
62
+ };
63
+ __decorate([
64
+ (0, common_1.Get)('categories'),
65
+ __metadata("design:type", Function),
66
+ __metadata("design:paramtypes", []),
67
+ __metadata("design:returntype", Array)
68
+ ], PreferenceCenterController.prototype, "categories", null);
69
+ __decorate([
70
+ (0, common_1.Get)(),
71
+ __param(0, (0, common_1.Req)()),
72
+ __metadata("design:type", Function),
73
+ __metadata("design:paramtypes", [Object]),
74
+ __metadata("design:returntype", Promise)
75
+ ], PreferenceCenterController.prototype, "matrix", null);
76
+ __decorate([
77
+ (0, common_1.Put)(':category/channels/:channel'),
78
+ __param(0, (0, common_1.Req)()),
79
+ __param(1, (0, common_1.Param)('category')),
80
+ __param(2, (0, common_1.Param)('channel')),
81
+ __param(3, (0, common_1.Body)()),
82
+ __metadata("design:type", Function),
83
+ __metadata("design:paramtypes", [Object, String, String, Object]),
84
+ __metadata("design:returntype", Promise)
85
+ ], PreferenceCenterController.prototype, "setChannel", null);
86
+ __decorate([
87
+ (0, common_1.Put)(':category/digest'),
88
+ __param(0, (0, common_1.Req)()),
89
+ __param(1, (0, common_1.Param)('category')),
90
+ __param(2, (0, common_1.Body)()),
91
+ __metadata("design:type", Function),
92
+ __metadata("design:paramtypes", [Object, String, Object]),
93
+ __metadata("design:returntype", Promise)
94
+ ], PreferenceCenterController.prototype, "setDigest", null);
95
+ PreferenceCenterController = __decorate([
96
+ (0, common_1.Controller)(options.path ?? 'preferences'),
97
+ __metadata("design:paramtypes", [preference_center_service_1.PreferenceCenterService])
98
+ ], PreferenceCenterController);
99
+ if (options.guards && options.guards.length > 0) {
100
+ (0, common_1.UseGuards)(...options.guards)(PreferenceCenterController);
101
+ }
102
+ return PreferenceCenterController;
103
+ }
104
+ //# sourceMappingURL=preference-center.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.controller.js","sourceRoot":"","sources":["../src/preference-center.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AA8DA,4EAkDC;AA/GD,2CAUwB;AAMxB,2EAAsE;AA2BtE;;;;;;;;;;;;;;;;;GAiBG;AACH,SAAgB,gCAAgC,CAC9C,OAA0C;IAE1C,IACM,0BAA0B,GADhC,MACM,0BAA0B;QACD;QAA7B,YAA6B,WAAoC;YAApC,gBAAW,GAAX,WAAW,CAAyB;QAAG,CAAC;QAGrE,UAAU;YACR,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC;QAC3C,CAAC;QAGK,AAAN,KAAK,CAAC,MAAM,CAAQ,GAAQ;YAC1B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC;YACpD,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;QAGK,AAAN,KAAK,CAAC,UAAU,CACP,GAAQ,EACI,QAAgB,EACjB,OAAe,EACzB,IAAoB;YAE5B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC;YACpD,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YAClF,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;QAGK,AAAN,KAAK,CAAC,SAAS,CACN,GAAQ,EACI,QAAgB,EAC3B,IAAmB;YAE3B,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC;YACpD,MAAM,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YACvE,OAAO,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;KACF,CAAA;IAnCC;QADC,IAAA,YAAG,EAAC,YAAY,CAAC;;;;gEAGjB;IAGK;QADL,IAAA,YAAG,GAAE;QACQ,WAAA,IAAA,YAAG,GAAE,CAAA;;;;4DAIlB;IAGK;QADL,IAAA,YAAG,EAAC,6BAA6B,CAAC;QAEhC,WAAA,IAAA,YAAG,GAAE,CAAA;QACL,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;QACjB,WAAA,IAAA,cAAK,EAAC,SAAS,CAAC,CAAA;QAChB,WAAA,IAAA,aAAI,GAAE,CAAA;;;;gEAMR;IAGK;QADL,IAAA,YAAG,EAAC,kBAAkB,CAAC;QAErB,WAAA,IAAA,YAAG,GAAE,CAAA;QACL,WAAA,IAAA,cAAK,EAAC,UAAU,CAAC,CAAA;QACjB,WAAA,IAAA,aAAI,GAAE,CAAA;;;;+DAMR;IAtCG,0BAA0B;QAD/B,IAAA,mBAAU,EAAC,OAAO,CAAC,IAAI,IAAI,aAAa,CAAC;yCAEE,mDAAuB;OAD7D,0BAA0B,CAuC/B;IAED,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAChD,IAAA,kBAAS,EAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,0BAA0B,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,0BAA0B,CAAC;AACpC,CAAC"}
@@ -0,0 +1,28 @@
1
+ import { type ChannelGateContext, type PreferenceGate } from '@dudousxd/nestjs-notifications-core';
2
+ import { CategoryRegistry } from './category-registry';
3
+ import { PreferenceCenterService } from './preference-center.service';
4
+ /**
5
+ * Core {@link PreferenceGate} backed by the {@link PreferenceCenterService}. Bound to the core
6
+ * `NOTIFICATION_PREFERENCE_GATE` token by {@link PreferencesModule.forCenter} so the
7
+ * ChannelRunner consults it before every delivery.
8
+ *
9
+ * For each delivery it resolves:
10
+ * - the notification's **category** (its `category` property, else `general`),
11
+ * - the **channel** being attempted,
12
+ * - the notifiable **ref** + **tenant** from the gate context,
13
+ *
14
+ * then asks the service whether instant delivery is allowed:
15
+ * - **Mandatory** categories (e.g. `security`) are always allowed.
16
+ * - A disabled (category × channel) toggle blocks the channel.
17
+ * - **Digest suppression:** when the category's digest is not `instant` (`daily`/`weekly`/
18
+ * `off`), instant delivery on every channel is SUPPRESSED. A scheduled digest job (out of
19
+ * scope for this package) would collect the suppressed notifications and send them in a
20
+ * batch at the chosen cadence.
21
+ */
22
+ export declare class PreferenceCenterGate implements PreferenceGate {
23
+ private readonly service;
24
+ private readonly registry;
25
+ constructor(service: PreferenceCenterService, registry: CategoryRegistry);
26
+ isAllowed({ notifiable, notification, channel, tenant, }: ChannelGateContext): Promise<boolean>;
27
+ }
28
+ //# sourceMappingURL=preference-center.gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.gate.d.ts","sourceRoot":"","sources":["../src/preference-center.gate.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EAEpB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBACa,oBAAqB,YAAW,cAAc;IAEvD,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADR,OAAO,EAAE,uBAAuB,EAChC,QAAQ,EAAE,gBAAgB;IAGvC,SAAS,CAAC,EACd,UAAU,EACV,YAAY,EACZ,OAAO,EACP,MAAM,GACP,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC;CAkBzC"}
@@ -0,0 +1,62 @@
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.PreferenceCenterGate = void 0;
13
+ const nestjs_notifications_core_1 = require("@dudousxd/nestjs-notifications-core");
14
+ const common_1 = require("@nestjs/common");
15
+ const category_registry_1 = require("./category-registry");
16
+ const preference_center_service_1 = require("./preference-center.service");
17
+ /**
18
+ * Core {@link PreferenceGate} backed by the {@link PreferenceCenterService}. Bound to the core
19
+ * `NOTIFICATION_PREFERENCE_GATE` token by {@link PreferencesModule.forCenter} so the
20
+ * ChannelRunner consults it before every delivery.
21
+ *
22
+ * For each delivery it resolves:
23
+ * - the notification's **category** (its `category` property, else `general`),
24
+ * - the **channel** being attempted,
25
+ * - the notifiable **ref** + **tenant** from the gate context,
26
+ *
27
+ * then asks the service whether instant delivery is allowed:
28
+ * - **Mandatory** categories (e.g. `security`) are always allowed.
29
+ * - A disabled (category × channel) toggle blocks the channel.
30
+ * - **Digest suppression:** when the category's digest is not `instant` (`daily`/`weekly`/
31
+ * `off`), instant delivery on every channel is SUPPRESSED. A scheduled digest job (out of
32
+ * scope for this package) would collect the suppressed notifications and send them in a
33
+ * batch at the chosen cadence.
34
+ */
35
+ let PreferenceCenterGate = class PreferenceCenterGate {
36
+ service;
37
+ registry;
38
+ constructor(service, registry) {
39
+ this.service = service;
40
+ this.registry = registry;
41
+ }
42
+ async isAllowed({ notifiable, notification, channel, tenant, }) {
43
+ let ref;
44
+ try {
45
+ ref = (0, nestjs_notifications_core_1.notifiableRef)(notifiable);
46
+ }
47
+ catch {
48
+ // No stable reference (e.g. an anonymous notifiable) — nothing to gate against; allow.
49
+ return true;
50
+ }
51
+ const category = this.registry.resolve(notification);
52
+ const { allowed } = await this.service.resolve({ type: ref.type, id: String(ref.id) }, category, channel, tenant);
53
+ return allowed;
54
+ }
55
+ };
56
+ exports.PreferenceCenterGate = PreferenceCenterGate;
57
+ exports.PreferenceCenterGate = PreferenceCenterGate = __decorate([
58
+ (0, common_1.Injectable)(),
59
+ __metadata("design:paramtypes", [preference_center_service_1.PreferenceCenterService,
60
+ category_registry_1.CategoryRegistry])
61
+ ], PreferenceCenterGate);
62
+ //# sourceMappingURL=preference-center.gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.gate.js","sourceRoot":"","sources":["../src/preference-center.gate.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,mFAI6C;AAC7C,2CAA4C;AAC5C,2DAAuD;AACvD,2EAAsE;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAEZ;IACA;IAFnB,YACmB,OAAgC,EAChC,QAA0B;QAD1B,YAAO,GAAP,OAAO,CAAyB;QAChC,aAAQ,GAAR,QAAQ,CAAkB;IAC1C,CAAC;IAEJ,KAAK,CAAC,SAAS,CAAC,EACd,UAAU,EACV,YAAY,EACZ,OAAO,EACP,MAAM,GACa;QACnB,IAAI,GAA0C,CAAC;QAC/C,IAAI,CAAC;YACH,GAAG,GAAG,IAAA,yCAAa,EAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,uFAAuF;YACvF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACrD,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAC5C,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EACtC,QAAQ,EACR,OAAO,EACP,MAAM,CACP,CAAC;QACF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAA;AA7BY,oDAAoB;+BAApB,oBAAoB;IADhC,IAAA,mBAAU,GAAE;qCAGiB,mDAAuB;QACtB,oCAAgB;GAHlC,oBAAoB,CA6BhC"}
@@ -0,0 +1,87 @@
1
+ import type { NotifiableRef } from '@dudousxd/nestjs-notifications-core';
2
+ /**
3
+ * How often a category's notifications should be delivered on a channel:
4
+ *
5
+ * - `instant` — deliver immediately (the default; the gate lets instant delivery through).
6
+ * - `daily` / `weekly` — batch into a digest; instant delivery is suppressed and a scheduled
7
+ * digest job would collect+send these (digest batching/sending is out of scope here).
8
+ * - `off` — never deliver for this category (equivalent to disabling every channel).
9
+ */
10
+ export type DigestFrequency = 'instant' | 'daily' | 'weekly' | 'off';
11
+ /**
12
+ * App-level declaration of a notification category. Provided through the module options and
13
+ * held by the {@link CategoryRegistry}. Categories form the rows of the preference matrix.
14
+ */
15
+ export interface CategoryDefinition {
16
+ /** Stable key matched against a notification's `category` (e.g. `billing`, `security`). */
17
+ key: string;
18
+ /** Human-readable label for the preference UI. */
19
+ label: string;
20
+ /** Optional longer description shown alongside the label. */
21
+ description?: string;
22
+ /** Channels enabled by default when a notifiable has no stored preference for this category. */
23
+ defaultChannels?: string[];
24
+ /**
25
+ * Mandatory (non-overridable) categories — e.g. `security`. The gate always allows these
26
+ * regardless of stored preferences, and digest is forced to `instant`.
27
+ */
28
+ mandatory?: boolean;
29
+ /** Whether the UI should expose a digest control for this category. Default true. */
30
+ allowDigest?: boolean;
31
+ }
32
+ /** A single channel toggle for a category. */
33
+ export interface ChannelPreference {
34
+ channel: string;
35
+ enabled: boolean;
36
+ }
37
+ /**
38
+ * A notifiable's stored preference for one category: the per-channel toggles plus the digest
39
+ * frequency. A missing channel falls back to the category's `defaultChannels`.
40
+ */
41
+ export interface CategoryPreference {
42
+ /** The category key these preferences apply to. */
43
+ category: string;
44
+ /** Per-channel enabled flags. Channels absent here use the category defaults. */
45
+ channels: Record<string, boolean>;
46
+ /** Delivery cadence for this category. */
47
+ digest: DigestFrequency;
48
+ }
49
+ /**
50
+ * The full per-notifiable preference set: every {@link CategoryPreference} keyed by category,
51
+ * plus the scope (notifiable ref + optional tenant) it belongs to.
52
+ */
53
+ export interface PreferenceMatrix {
54
+ /** The notifiable this matrix belongs to. */
55
+ ref: NotifiableRef;
56
+ /** Tenant scope; undefined in single-tenant apps. */
57
+ tenantId?: string;
58
+ /** Stored category preferences, keyed by category key. */
59
+ categories: Record<string, CategoryPreference>;
60
+ }
61
+ /**
62
+ * Persistence for the preference center. Stores the per-(category × channel) toggles and the
63
+ * per-category digest frequency for each notifiable (and tenant). Implement against your
64
+ * datastore, or use the bundled {@link InMemoryPreferenceCenterStore}.
65
+ *
66
+ * `ref` is a {@link NotifiableRef} (`{ type, id }`).
67
+ */
68
+ export interface PreferenceCenterStore {
69
+ /** Return the stored matrix for a notifiable (and tenant). Only explicitly-set values. */
70
+ getMatrix(ref: NotifiableRef, tenantId?: string): Promise<PreferenceMatrix>;
71
+ /** Toggle a single (category × channel). */
72
+ setChannel(ref: NotifiableRef, category: string, channel: string, enabled: boolean, tenantId?: string): Promise<void>;
73
+ /** Set the digest frequency for a category. */
74
+ setDigest(ref: NotifiableRef, category: string, digest: DigestFrequency, tenantId?: string): Promise<void>;
75
+ /** Replace a category's full preference in one call. */
76
+ setCategory(ref: NotifiableRef, category: string, pref: CategoryPreference, tenantId?: string): Promise<void>;
77
+ /** Drop a category's stored preference, reverting it to the registry defaults. */
78
+ resetCategory(ref: NotifiableRef, category: string, tenantId?: string): Promise<void>;
79
+ }
80
+ /** Outcome of resolving a (category × channel) preference for delivery. */
81
+ export interface PreferenceResolution {
82
+ /** Whether the channel may deliver instantly for this category right now. */
83
+ allowed: boolean;
84
+ /** The effective digest frequency for this category. */
85
+ digest: DigestFrequency;
86
+ }
87
+ //# sourceMappingURL=preference-center.interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.interfaces.d.ts","sourceRoot":"","sources":["../src/preference-center.interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAErE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,2FAA2F;IAC3F,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,qFAAqF;IACrF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,0CAA0C;IAC1C,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,GAAG,EAAE,aAAa,CAAC;IACnB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAChD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,0FAA0F;IAC1F,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC5E,4CAA4C;IAC5C,UAAU,CACR,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,+CAA+C;IAC/C,SAAS,CACP,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,wDAAwD;IACxD,WAAW,CACT,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,kFAAkF;IAClF,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACvF;AAED,2EAA2E;AAC3E,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,OAAO,EAAE,OAAO,CAAC;IACjB,wDAAwD;IACxD,MAAM,EAAE,eAAe,CAAC;CACzB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=preference-center.interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.interfaces.js","sourceRoot":"","sources":["../src/preference-center.interfaces.ts"],"names":[],"mappings":""}
@@ -0,0 +1,41 @@
1
+ import type { NotifiableRef } from '@dudousxd/nestjs-notifications-core';
2
+ import { CategoryRegistry } from './category-registry';
3
+ import type { CategoryDefinition, CategoryPreference, DigestFrequency, PreferenceCenterStore, PreferenceMatrix, PreferenceResolution } from './preference-center.interfaces';
4
+ /**
5
+ * Injectable façade over a {@link PreferenceCenterStore} and the {@link CategoryRegistry}. It
6
+ * merges stored preferences with category defaults, exposes the matrix for a UI, and resolves a
7
+ * single (category × channel) decision for the gate.
8
+ */
9
+ export declare class PreferenceCenterService {
10
+ private readonly store;
11
+ private readonly registry;
12
+ constructor(store: PreferenceCenterStore, registry: CategoryRegistry);
13
+ /** The configured category definitions (for the UI). */
14
+ listCategories(): CategoryDefinition[];
15
+ /**
16
+ * The resolved matrix for a notifiable: every registered category, each filled in with the
17
+ * notifiable's stored values merged over the category defaults. Mandatory categories are
18
+ * normalized to `instant` digest with their default channels forced on.
19
+ */
20
+ getMatrix(ref: NotifiableRef, tenantId?: string): Promise<PreferenceMatrix>;
21
+ /** Toggle one (category × channel) for a notifiable. */
22
+ setChannel(ref: NotifiableRef, category: string, channel: string, enabled: boolean, tenantId?: string): Promise<void>;
23
+ /** Set the digest frequency for a category. */
24
+ setDigest(ref: NotifiableRef, category: string, digest: DigestFrequency, tenantId?: string): Promise<void>;
25
+ /** Replace a category's full preference. */
26
+ setCategory(ref: NotifiableRef, category: string, pref: CategoryPreference, tenantId?: string): Promise<void>;
27
+ /** Revert a category to the registry defaults. */
28
+ resetCategory(ref: NotifiableRef, category: string, tenantId?: string): Promise<void>;
29
+ /**
30
+ * Resolve whether `channel` may deliver instantly for `category` to this notifiable.
31
+ *
32
+ * - Mandatory categories are always `{ allowed: true, digest: 'instant' }`.
33
+ * - If the channel is disabled (stored, or not in defaults), `allowed` is false.
34
+ * - If the category's digest is not `instant`, instant delivery is suppressed (`allowed`
35
+ * false) — a scheduled digest job would batch+send these; batching is out of scope here.
36
+ */
37
+ resolve(ref: NotifiableRef, category: string, channel: string, tenantId?: string): Promise<PreferenceResolution>;
38
+ /** Merge a stored category preference over the registry defaults. */
39
+ private merge;
40
+ }
41
+ //# sourceMappingURL=preference-center.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.service.d.ts","sourceRoot":"","sources":["../src/preference-center.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EACV,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;AAGxC;;;;GAIG;AACH,qBACa,uBAAuB;IAEC,OAAO,CAAC,QAAQ,CAAC,KAAK;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBADyB,KAAK,EAAE,qBAAqB,EAC7D,QAAQ,EAAE,gBAAgB;IAG7C,wDAAwD;IACxD,cAAc,IAAI,kBAAkB,EAAE;IAItC;;;;OAIG;IACG,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAejF,wDAAwD;IAClD,UAAU,CACd,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAIhB,+CAA+C;IACzC,SAAS,CACb,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAIhB,4CAA4C;IACtC,WAAW,CACf,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,kBAAkB,EACxB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAIhB,kDAAkD;IAC5C,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3F;;;;;;;OAOG;IACG,OAAO,CACX,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,oBAAoB,CAAC;IAsBhC,qEAAqE;IACrE,OAAO,CAAC,KAAK;CAuBd"}
@@ -0,0 +1,124 @@
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
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.PreferenceCenterService = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const category_registry_1 = require("./category-registry");
18
+ const tokens_1 = require("./tokens");
19
+ /**
20
+ * Injectable façade over a {@link PreferenceCenterStore} and the {@link CategoryRegistry}. It
21
+ * merges stored preferences with category defaults, exposes the matrix for a UI, and resolves a
22
+ * single (category × channel) decision for the gate.
23
+ */
24
+ let PreferenceCenterService = class PreferenceCenterService {
25
+ store;
26
+ registry;
27
+ constructor(store, registry) {
28
+ this.store = store;
29
+ this.registry = registry;
30
+ }
31
+ /** The configured category definitions (for the UI). */
32
+ listCategories() {
33
+ return this.registry.all();
34
+ }
35
+ /**
36
+ * The resolved matrix for a notifiable: every registered category, each filled in with the
37
+ * notifiable's stored values merged over the category defaults. Mandatory categories are
38
+ * normalized to `instant` digest with their default channels forced on.
39
+ */
40
+ async getMatrix(ref, tenantId) {
41
+ const stored = await this.store.getMatrix(ref, tenantId);
42
+ const categories = {};
43
+ for (const def of this.registry.all()) {
44
+ categories[def.key] = this.merge(def, stored.categories[def.key]);
45
+ }
46
+ // Preserve any stored categories not present in the registry (e.g. legacy keys).
47
+ for (const [key, pref] of Object.entries(stored.categories)) {
48
+ if (!categories[key]) {
49
+ categories[key] = this.merge(this.registry.get(key), pref);
50
+ }
51
+ }
52
+ return { ref, tenantId, categories };
53
+ }
54
+ /** Toggle one (category × channel) for a notifiable. */
55
+ async setChannel(ref, category, channel, enabled, tenantId) {
56
+ await this.store.setChannel(ref, category, channel, enabled, tenantId);
57
+ }
58
+ /** Set the digest frequency for a category. */
59
+ async setDigest(ref, category, digest, tenantId) {
60
+ await this.store.setDigest(ref, category, digest, tenantId);
61
+ }
62
+ /** Replace a category's full preference. */
63
+ async setCategory(ref, category, pref, tenantId) {
64
+ await this.store.setCategory(ref, category, pref, tenantId);
65
+ }
66
+ /** Revert a category to the registry defaults. */
67
+ async resetCategory(ref, category, tenantId) {
68
+ await this.store.resetCategory(ref, category, tenantId);
69
+ }
70
+ /**
71
+ * Resolve whether `channel` may deliver instantly for `category` to this notifiable.
72
+ *
73
+ * - Mandatory categories are always `{ allowed: true, digest: 'instant' }`.
74
+ * - If the channel is disabled (stored, or not in defaults), `allowed` is false.
75
+ * - If the category's digest is not `instant`, instant delivery is suppressed (`allowed`
76
+ * false) — a scheduled digest job would batch+send these; batching is out of scope here.
77
+ */
78
+ async resolve(ref, category, channel, tenantId) {
79
+ const def = this.registry.get(category);
80
+ if (def.mandatory) {
81
+ return { allowed: true, digest: 'instant' };
82
+ }
83
+ const stored = await this.store.getMatrix(ref, tenantId);
84
+ const pref = this.merge(def, stored.categories[category]);
85
+ if (pref.digest === 'off') {
86
+ return { allowed: false, digest: 'off' };
87
+ }
88
+ const channelEnabled = pref.channels[channel] ?? false;
89
+ if (!channelEnabled) {
90
+ return { allowed: false, digest: pref.digest };
91
+ }
92
+ // Non-instant digest: suppress instant delivery; the digest job collects+sends later.
93
+ return { allowed: pref.digest === 'instant', digest: pref.digest };
94
+ }
95
+ /** Merge a stored category preference over the registry defaults. */
96
+ merge(def, stored) {
97
+ const channels = {};
98
+ for (const channel of def.defaultChannels ?? []) {
99
+ channels[channel] = true;
100
+ }
101
+ if (stored) {
102
+ Object.assign(channels, stored.channels);
103
+ }
104
+ if (def.mandatory) {
105
+ // Mandatory categories are non-overridable: defaults on, instant cadence.
106
+ for (const channel of def.defaultChannels ?? []) {
107
+ channels[channel] = true;
108
+ }
109
+ return { category: def.key, channels, digest: 'instant' };
110
+ }
111
+ return {
112
+ category: def.key,
113
+ channels,
114
+ digest: stored?.digest ?? 'instant',
115
+ };
116
+ }
117
+ };
118
+ exports.PreferenceCenterService = PreferenceCenterService;
119
+ exports.PreferenceCenterService = PreferenceCenterService = __decorate([
120
+ (0, common_1.Injectable)(),
121
+ __param(0, (0, common_1.Inject)(tokens_1.PREFERENCE_CENTER_STORE)),
122
+ __metadata("design:paramtypes", [Object, category_registry_1.CategoryRegistry])
123
+ ], PreferenceCenterService);
124
+ //# sourceMappingURL=preference-center.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preference-center.service.js","sourceRoot":"","sources":["../src/preference-center.service.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { type DynamicModule, type Type } from '@nestjs/common';
2
2
  import type { PreferenceStore } from './interfaces';
3
+ import type { CategoryDefinition, PreferenceCenterStore } from './preference-center.interfaces';
3
4
  /** Options for {@link PreferencesModule.forRoot}. */
4
5
  export interface PreferencesModuleOptions {
5
6
  /** A {@link PreferenceStore} class to instantiate; defaults to {@link InMemoryPreferenceStore}. */
@@ -7,16 +8,37 @@ export interface PreferencesModuleOptions {
7
8
  /** Register globally so the preferences service and gate are available app-wide. Default true. */
8
9
  global?: boolean;
9
10
  }
11
+ /** Options for {@link PreferencesModule.forCenter}. */
12
+ export interface PreferenceCenterModuleOptions {
13
+ /** The app's category definitions (the rows of the preference matrix). */
14
+ categories: CategoryDefinition[];
15
+ /**
16
+ * A {@link PreferenceCenterStore} class to instantiate; defaults to
17
+ * {@link InMemoryPreferenceCenterStore}.
18
+ */
19
+ store?: Type<PreferenceCenterStore>;
20
+ /** Register globally so the service and gate are available app-wide. Default true. */
21
+ global?: boolean;
22
+ }
10
23
  /**
11
24
  * Registers channel preferences. Binds the core `NOTIFICATION_PREFERENCE_GATE` token to a
12
25
  * store-backed gate so the ChannelRunner automatically skips muted channels.
13
26
  *
14
27
  * ```ts
15
- * PreferencesModule.forRoot() // in-memory store
28
+ * PreferencesModule.forRoot() // in-memory store (simple opt-out)
16
29
  * PreferencesModule.forRoot({ store: PrismaPrefStore }) // your store
30
+ * PreferencesModule.forCenter({ categories }) // full preference center
17
31
  * ```
18
32
  */
19
33
  export declare class PreferencesModule {
34
+ /** Simple per-channel opt-out muting (unchanged). */
20
35
  static forRoot(options?: PreferencesModuleOptions): DynamicModule;
36
+ /**
37
+ * Full preference center: per-(category × channel) toggles + per-category digest frequency.
38
+ * Wires the {@link CategoryRegistry}, the {@link PreferenceCenterStore}, the
39
+ * {@link PreferenceCenterService}, and binds {@link PreferenceCenterGate} to the core
40
+ * `NOTIFICATION_PREFERENCE_GATE` token (so it replaces the simple opt-out gate).
41
+ */
42
+ static forCenter(options: PreferenceCenterModuleOptions): DynamicModule;
21
43
  }
22
44
  //# sourceMappingURL=preferences.module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.module.d.ts","sourceRoot":"","sources":["../src/preferences.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAyB,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKpD,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,mGAAmG;IACnG,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9B,kGAAkG;IAClG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,qBACa,iBAAiB;IAC5B,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,wBAA6B,GAAG,aAAa;CAgBtE"}
1
+ {"version":3,"file":"preferences.module.d.ts","sourceRoot":"","sources":["../src/preferences.module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAAyB,KAAK,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAItF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAShG,qDAAqD;AACrD,MAAM,WAAW,wBAAwB;IACvC,mGAAmG;IACnG,KAAK,CAAC,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;IAC9B,kGAAkG;IAClG,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,uDAAuD;AACvD,MAAM,WAAW,6BAA6B;IAC5C,0EAA0E;IAC1E,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACpC,sFAAsF;IACtF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,qBACa,iBAAiB;IAC5B,qDAAqD;IACrD,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,wBAA6B,GAAG,aAAa;IAiBrE;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,6BAA6B,GAAG,aAAa;CAuBxE"}
@@ -10,8 +10,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.PreferencesModule = void 0;
11
11
  const nestjs_notifications_core_1 = require("@dudousxd/nestjs-notifications-core");
12
12
  const common_1 = require("@nestjs/common");
13
+ const category_registry_1 = require("./category-registry");
14
+ const in_memory_preference_center_store_1 = require("./in-memory.preference-center.store");
13
15
  const in_memory_store_1 = require("./in-memory.store");
14
16
  const notification_preferences_1 = require("./notification-preferences");
17
+ const preference_center_gate_1 = require("./preference-center.gate");
18
+ const preference_center_service_1 = require("./preference-center.service");
15
19
  const preference_gate_adapter_1 = require("./preference-gate.adapter");
16
20
  const tokens_1 = require("./tokens");
17
21
  /**
@@ -19,11 +23,13 @@ const tokens_1 = require("./tokens");
19
23
  * store-backed gate so the ChannelRunner automatically skips muted channels.
20
24
  *
21
25
  * ```ts
22
- * PreferencesModule.forRoot() // in-memory store
26
+ * PreferencesModule.forRoot() // in-memory store (simple opt-out)
23
27
  * PreferencesModule.forRoot({ store: PrismaPrefStore }) // your store
28
+ * PreferencesModule.forCenter({ categories }) // full preference center
24
29
  * ```
25
30
  */
26
31
  let PreferencesModule = PreferencesModule_1 = class PreferencesModule {
32
+ /** Simple per-channel opt-out muting (unchanged). */
27
33
  static forRoot(options = {}) {
28
34
  const storeClass = options.store ?? in_memory_store_1.InMemoryPreferenceStore;
29
35
  const providers = [
@@ -40,6 +46,35 @@ let PreferencesModule = PreferencesModule_1 = class PreferencesModule {
40
46
  exports: [notification_preferences_1.NotificationPreferences, tokens_1.NOTIFICATION_PREFERENCE_STORE],
41
47
  };
42
48
  }
49
+ /**
50
+ * Full preference center: per-(category × channel) toggles + per-category digest frequency.
51
+ * Wires the {@link CategoryRegistry}, the {@link PreferenceCenterStore}, the
52
+ * {@link PreferenceCenterService}, and binds {@link PreferenceCenterGate} to the core
53
+ * `NOTIFICATION_PREFERENCE_GATE` token (so it replaces the simple opt-out gate).
54
+ */
55
+ static forCenter(options) {
56
+ const storeClass = options.store ?? in_memory_preference_center_store_1.InMemoryPreferenceCenterStore;
57
+ const providers = [
58
+ { provide: tokens_1.PREFERENCE_CENTER_CATEGORIES, useValue: options.categories },
59
+ category_registry_1.CategoryRegistry,
60
+ storeClass,
61
+ { provide: tokens_1.PREFERENCE_CENTER_STORE, useExisting: storeClass },
62
+ preference_center_service_1.PreferenceCenterService,
63
+ preference_center_gate_1.PreferenceCenterGate,
64
+ { provide: nestjs_notifications_core_1.NOTIFICATION_PREFERENCE_GATE, useExisting: preference_center_gate_1.PreferenceCenterGate },
65
+ ];
66
+ return {
67
+ module: PreferencesModule_1,
68
+ global: options.global ?? true,
69
+ providers,
70
+ exports: [
71
+ preference_center_service_1.PreferenceCenterService,
72
+ category_registry_1.CategoryRegistry,
73
+ tokens_1.PREFERENCE_CENTER_STORE,
74
+ tokens_1.PREFERENCE_CENTER_CATEGORIES,
75
+ ],
76
+ };
77
+ }
43
78
  };
44
79
  exports.PreferencesModule = PreferencesModule;
45
80
  exports.PreferencesModule = PreferencesModule = PreferencesModule_1 = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"preferences.module.js","sourceRoot":"","sources":["../src/preferences.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAmF;AACnF,2CAAsF;AACtF,uDAA4D;AAE5D,yEAAqE;AACrE,uEAAkE;AAClE,qCAAyD;AAUzD;;;;;;;;GAQG;AAEI,IAAM,iBAAiB,yBAAvB,MAAM,iBAAiB;IAC5B,MAAM,CAAC,OAAO,CAAC,UAAoC,EAAE;QACnD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,IAAI,yCAAuB,CAAC;QAC5D,MAAM,SAAS,GAAe;YAC5B,UAAU;YACV,EAAE,OAAO,EAAE,sCAA6B,EAAE,WAAW,EAAE,UAAU,EAAE;YACnE,kDAAuB;YACvB,+CAAqB;YACrB,EAAE,OAAO,EAAE,wDAA4B,EAAE,WAAW,EAAE,+CAAqB,EAAE;SAC9E,CAAC;QACF,OAAO;YACL,MAAM,EAAE,mBAAiB;YACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;YAC9B,SAAS;YACT,OAAO,EAAE,CAAC,kDAAuB,EAAE,sCAA6B,CAAC;SAClE,CAAC;IACJ,CAAC;CACF,CAAA;AAjBY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,iBAAiB,CAiB7B"}
1
+ {"version":3,"file":"preferences.module.js","sourceRoot":"","sources":["../src/preferences.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,mFAAmF;AACnF,2CAAsF;AACtF,2DAAuD;AACvD,2FAAoF;AACpF,uDAA4D;AAE5D,yEAAqE;AACrE,qEAAgE;AAEhE,2EAAsE;AACtE,uEAAkE;AAClE,qCAIkB;AAuBlB;;;;;;;;;GASG;AAEI,IAAM,iBAAiB,yBAAvB,MAAM,iBAAiB;IAC5B,qDAAqD;IACrD,MAAM,CAAC,OAAO,CAAC,UAAoC,EAAE;QACnD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,IAAI,yCAAuB,CAAC;QAC5D,MAAM,SAAS,GAAe;YAC5B,UAAU;YACV,EAAE,OAAO,EAAE,sCAA6B,EAAE,WAAW,EAAE,UAAU,EAAE;YACnE,kDAAuB;YACvB,+CAAqB;YACrB,EAAE,OAAO,EAAE,wDAA4B,EAAE,WAAW,EAAE,+CAAqB,EAAE;SAC9E,CAAC;QACF,OAAO;YACL,MAAM,EAAE,mBAAiB;YACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;YAC9B,SAAS;YACT,OAAO,EAAE,CAAC,kDAAuB,EAAE,sCAA6B,CAAC;SAClE,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,SAAS,CAAC,OAAsC;QACrD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,IAAI,iEAA6B,CAAC;QAClE,MAAM,SAAS,GAAe;YAC5B,EAAE,OAAO,EAAE,qCAA4B,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE;YACvE,oCAAgB;YAChB,UAAU;YACV,EAAE,OAAO,EAAE,gCAAuB,EAAE,WAAW,EAAE,UAAU,EAAE;YAC7D,mDAAuB;YACvB,6CAAoB;YACpB,EAAE,OAAO,EAAE,wDAA4B,EAAE,WAAW,EAAE,6CAAoB,EAAE;SAC7E,CAAC;QACF,OAAO;YACL,MAAM,EAAE,mBAAiB;YACzB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI;YAC9B,SAAS;YACT,OAAO,EAAE;gBACP,mDAAuB;gBACvB,oCAAgB;gBAChB,gCAAuB;gBACvB,qCAA4B;aAC7B;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAhDY,8CAAiB;4BAAjB,iBAAiB;IAD7B,IAAA,eAAM,EAAC,EAAE,CAAC;GACE,iBAAiB,CAgD7B"}
package/dist/tokens.d.ts CHANGED
@@ -1,3 +1,7 @@
1
1
  /** DI token for the {@link PreferenceStore} implementation backing the preferences package. */
2
2
  export declare const NOTIFICATION_PREFERENCE_STORE: unique symbol;
3
+ /** DI token for the {@link PreferenceCenterStore} implementation backing the preference center. */
4
+ export declare const PREFERENCE_CENTER_STORE: unique symbol;
5
+ /** DI token for the array of {@link CategoryDefinition}s configured for the preference center. */
6
+ export declare const PREFERENCE_CENTER_CATEGORIES: unique symbol;
3
7
  //# sourceMappingURL=tokens.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,eAAO,MAAM,6BAA6B,eAA0C,CAAC"}
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,eAAO,MAAM,6BAA6B,eAA0C,CAAC;AAErF,mGAAmG;AACnG,eAAO,MAAM,uBAAuB,eAAoC,CAAC;AAEzE,kGAAkG;AAClG,eAAO,MAAM,4BAA4B,eAAyC,CAAC"}
package/dist/tokens.js CHANGED
@@ -1,6 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NOTIFICATION_PREFERENCE_STORE = void 0;
3
+ exports.PREFERENCE_CENTER_CATEGORIES = exports.PREFERENCE_CENTER_STORE = exports.NOTIFICATION_PREFERENCE_STORE = void 0;
4
4
  /** DI token for the {@link PreferenceStore} implementation backing the preferences package. */
5
5
  exports.NOTIFICATION_PREFERENCE_STORE = Symbol('NOTIFICATION_PREFERENCE_STORE');
6
+ /** DI token for the {@link PreferenceCenterStore} implementation backing the preference center. */
7
+ exports.PREFERENCE_CENTER_STORE = Symbol('PREFERENCE_CENTER_STORE');
8
+ /** DI token for the array of {@link CategoryDefinition}s configured for the preference center. */
9
+ exports.PREFERENCE_CENTER_CATEGORIES = Symbol('PREFERENCE_CENTER_CATEGORIES');
6
10
  //# sourceMappingURL=tokens.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":";;;AAAA,+FAA+F;AAClF,QAAA,6BAA6B,GAAG,MAAM,CAAC,+BAA+B,CAAC,CAAC"}
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":";;;AAAA,+FAA+F;AAClF,QAAA,6BAA6B,GAAG,MAAM,CAAC,+BAA+B,CAAC,CAAC;AAErF,mGAAmG;AACtF,QAAA,uBAAuB,GAAG,MAAM,CAAC,yBAAyB,CAAC,CAAC;AAEzE,kGAAkG;AACrF,QAAA,4BAA4B,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-notifications-preferences",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Per-user, per-tenant channel preferences for nestjs-notifications — opt-out muting enforced via the core PreferenceGate",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -20,10 +20,10 @@
20
20
  "@nestjs/common": "^10.0.0 || ^11.0.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@nestjs/common": "^11.0.0",
24
- "reflect-metadata": "^0.2.2",
25
- "typescript": "^5.7.2",
26
- "@dudousxd/nestjs-notifications-core": "^0.4.0"
23
+ "@nestjs/common": "11.1.26",
24
+ "reflect-metadata": "0.2.2",
25
+ "typescript": "5.9.3",
26
+ "@dudousxd/nestjs-notifications-core": "^0.5.0"
27
27
  },
28
28
  "scripts": {
29
29
  "build": "tsc -p tsconfig.json",