@happyvertical/smrt-messages 0.60.10 → 0.60.12

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 (31) hide show
  1. package/AGENTS.md +10 -0
  2. package/README.md +34 -0
  3. package/agents/notification-outbox.md +48 -2
  4. package/dist/chunks/{AccountCollection-By48bdwt.js → AccountCollection-C3mH6s-q.js} +2 -2
  5. package/dist/chunks/{AccountCollection-By48bdwt.js.map → AccountCollection-C3mH6s-q.js.map} +1 -1
  6. package/dist/chunks/{Email-CMUK3aWU.js → Email-CvQfps_w.js} +3 -3
  7. package/dist/chunks/{Email-CMUK3aWU.js.map → Email-CvQfps_w.js.map} +1 -1
  8. package/dist/chunks/{EmailFolder-DLJvqNqI.js → EmailFolder-Bb0y9h7I.js} +2 -2
  9. package/dist/chunks/{EmailFolder-DLJvqNqI.js.map → EmailFolder-Bb0y9h7I.js.map} +1 -1
  10. package/dist/chunks/{Message-DXpqot5f.js → Message-Dn0WWplz.js} +4 -4
  11. package/dist/chunks/{Message-DXpqot5f.js.map → Message-Dn0WWplz.js.map} +1 -1
  12. package/dist/chunks/{MessageCollection-CMGaSGBc.js → MessageCollection-BHz_udee.js} +2 -2
  13. package/dist/chunks/{MessageCollection-CMGaSGBc.js.map → MessageCollection-BHz_udee.js.map} +1 -1
  14. package/dist/chunks/__smrt-register__-Dftmkczm.js +6 -0
  15. package/dist/chunks/__smrt-register__-Dftmkczm.js.map +1 -0
  16. package/dist/collections/NotificationOptOutCollection.d.ts +6 -0
  17. package/dist/collections/NotificationOptOutCollection.d.ts.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +264 -55
  21. package/dist/index.js.map +1 -1
  22. package/dist/manifest.json +330 -1
  23. package/dist/models/NotificationOptOut.d.ts +44 -0
  24. package/dist/models/NotificationOptOut.d.ts.map +1 -0
  25. package/dist/services/NotificationOptOutService.d.ts +80 -0
  26. package/dist/services/NotificationOptOutService.d.ts.map +1 -0
  27. package/dist/smrt-knowledge.json +104 -10
  28. package/dist/smrt-knowledge.okf.md +4 -2
  29. package/package.json +9 -9
  30. package/dist/chunks/__smrt-register__-CaGLtiEU.js +0 -6
  31. package/dist/chunks/__smrt-register__-CaGLtiEU.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-messages",
5
- "packageVersion": "0.60.10",
5
+ "packageVersion": "0.60.12",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-messages:AccountCollection": {
8
8
  "name": "accountcollection",
@@ -3759,6 +3759,136 @@
3759
3759
  },
3760
3760
  "importPath": "@happyvertical/smrt-messages"
3761
3761
  },
3762
+ "@happyvertical/smrt-messages:NotificationOptOutCollection": {
3763
+ "name": "notificationoptoutcollection",
3764
+ "className": "NotificationOptOutCollection",
3765
+ "qualifiedName": "@happyvertical/smrt-messages:NotificationOptOutCollection",
3766
+ "collection": "notificationoptouts",
3767
+ "filePath": "/home/runner/work/smrt/smrt/packages/messages/src/collections/NotificationOptOutCollection.ts",
3768
+ "packageName": "@happyvertical/smrt-messages",
3769
+ "fields": {},
3770
+ "methods": {},
3771
+ "decoratorConfig": {
3772
+ "tableName": "notification_opt_outs",
3773
+ "api": false,
3774
+ "mcp": false,
3775
+ "cli": false
3776
+ },
3777
+ "extends": "SmrtCollection",
3778
+ "extendsTypeArg": "NotificationOptOut",
3779
+ "exportName": "NotificationOptOutCollection",
3780
+ "collectionExportName": "NotificationOptOutCollectionCollection",
3781
+ "collectionOf": "@happyvertical/smrt-messages:NotificationOptOut",
3782
+ "inheritedExposure": [
3783
+ "api",
3784
+ "mcp",
3785
+ "cli"
3786
+ ],
3787
+ "schema": {
3788
+ "tableName": "notification_opt_outs",
3789
+ "ddl": "CREATE TABLE IF NOT EXISTS \"notification_opt_outs\" (\n \"_sync_origin_device_id\" TEXT,\n \"_sync_revision\" INTEGER,\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID NOT NULL,\n \"recipient_user_id\" UUID NOT NULL,\n \"channel\" TEXT NOT NULL DEFAULT 'email',\n \"scope\" TEXT NOT NULL,\n \"opted_out_at\" TIMESTAMP,\n \"updated_by\" TEXT\n);",
3790
+ "columns": {
3791
+ "_sync_origin_device_id": {
3792
+ "type": "TEXT"
3793
+ },
3794
+ "_sync_revision": {
3795
+ "type": "INTEGER"
3796
+ },
3797
+ "id": {
3798
+ "type": "UUID",
3799
+ "primaryKey": true,
3800
+ "referenceKind": "id",
3801
+ "notNull": true
3802
+ },
3803
+ "slug": {
3804
+ "type": "TEXT",
3805
+ "notNull": true
3806
+ },
3807
+ "context": {
3808
+ "type": "TEXT",
3809
+ "notNull": true,
3810
+ "default": ""
3811
+ },
3812
+ "created_at": {
3813
+ "type": "TIMESTAMP",
3814
+ "notNull": true,
3815
+ "default": "current_timestamp"
3816
+ },
3817
+ "updated_at": {
3818
+ "type": "TIMESTAMP",
3819
+ "notNull": true,
3820
+ "default": "current_timestamp"
3821
+ },
3822
+ "tenant_id": {
3823
+ "type": "UUID",
3824
+ "referenceKind": "tenantId",
3825
+ "notNull": true,
3826
+ "unique": false
3827
+ },
3828
+ "recipient_user_id": {
3829
+ "type": "UUID",
3830
+ "referenceKind": "crossPackageRef",
3831
+ "notNull": true,
3832
+ "unique": false
3833
+ },
3834
+ "channel": {
3835
+ "type": "TEXT",
3836
+ "notNull": true,
3837
+ "unique": false,
3838
+ "default": "email"
3839
+ },
3840
+ "scope": {
3841
+ "type": "TEXT",
3842
+ "notNull": true,
3843
+ "unique": false
3844
+ },
3845
+ "opted_out_at": {
3846
+ "type": "TIMESTAMP",
3847
+ "notNull": false,
3848
+ "unique": false
3849
+ },
3850
+ "updated_by": {
3851
+ "type": "TEXT",
3852
+ "notNull": false,
3853
+ "unique": false
3854
+ }
3855
+ },
3856
+ "indexes": [
3857
+ {
3858
+ "name": "notification_opt_outs_tenant_id_recipient_user_id_idx",
3859
+ "columns": [
3860
+ "tenant_id",
3861
+ "recipient_user_id",
3862
+ "channel",
3863
+ "scope"
3864
+ ],
3865
+ "unique": true
3866
+ },
3867
+ {
3868
+ "name": "notification_opt_outs_slug_context_idx",
3869
+ "columns": [
3870
+ "slug",
3871
+ "context"
3872
+ ]
3873
+ },
3874
+ {
3875
+ "name": "notification_opt_outs_tenant_id_created_at_idx",
3876
+ "columns": [
3877
+ "tenant_id",
3878
+ "created_at"
3879
+ ]
3880
+ },
3881
+ {
3882
+ "name": "notification_opt_outs_recipient_user_id_idx",
3883
+ "columns": [
3884
+ "recipient_user_id"
3885
+ ]
3886
+ }
3887
+ ],
3888
+ "version": "a13e93c1"
3889
+ },
3890
+ "importPath": "@happyvertical/smrt-messages"
3891
+ },
3762
3892
  "@happyvertical/smrt-messages:PersonaMessageRouteCollection": {
3763
3893
  "name": "personamessageroutecollection",
3764
3894
  "className": "PersonaMessageRouteCollection",
@@ -8975,6 +9105,205 @@
8975
9105
  },
8976
9106
  "importPath": "@happyvertical/smrt-messages"
8977
9107
  },
9108
+ "@happyvertical/smrt-messages:NotificationOptOut": {
9109
+ "name": "notificationoptout",
9110
+ "className": "NotificationOptOut",
9111
+ "qualifiedName": "@happyvertical/smrt-messages:NotificationOptOut",
9112
+ "collection": "notificationoptouts",
9113
+ "description": "One person's opt-out of one notification channel for one scope, in one tenant: the preference store behind the outbox's isSuppressed hook.",
9114
+ "filePath": "/home/runner/work/smrt/smrt/packages/messages/src/models/NotificationOptOut.ts",
9115
+ "packageName": "@happyvertical/smrt-messages",
9116
+ "fields": {
9117
+ "tenantId": {
9118
+ "type": "text",
9119
+ "required": true,
9120
+ "_meta": {
9121
+ "sqlType": "UUID",
9122
+ "__tenancy": {
9123
+ "isTenantIdField": true,
9124
+ "autoFilter": true,
9125
+ "required": true,
9126
+ "autoPopulate": true,
9127
+ "nullable": false,
9128
+ "mode": "required",
9129
+ "field": "tenantId",
9130
+ "allowSuperAdminBypass": false
9131
+ }
9132
+ }
9133
+ },
9134
+ "recipientUserId": {
9135
+ "type": "crossPackageRef",
9136
+ "required": true,
9137
+ "related": "@happyvertical/smrt-users:User"
9138
+ },
9139
+ "channel": {
9140
+ "type": "text",
9141
+ "required": true,
9142
+ "default": "email",
9143
+ "_meta": {
9144
+ "required": true
9145
+ },
9146
+ "enum": [
9147
+ "email"
9148
+ ]
9149
+ },
9150
+ "scope": {
9151
+ "type": "text",
9152
+ "required": true,
9153
+ "_meta": {
9154
+ "required": true
9155
+ }
9156
+ },
9157
+ "optedOutAt": {
9158
+ "type": "datetime",
9159
+ "required": false
9160
+ },
9161
+ "updatedBy": {
9162
+ "type": "text",
9163
+ "required": false
9164
+ }
9165
+ },
9166
+ "methods": {},
9167
+ "decoratorConfig": {
9168
+ "tableName": "notification_opt_outs",
9169
+ "api": false,
9170
+ "mcp": false,
9171
+ "cli": false,
9172
+ "conflictColumns": [
9173
+ "tenant_id",
9174
+ "recipient_user_id",
9175
+ "channel",
9176
+ "scope"
9177
+ ],
9178
+ "tenantScoped": {
9179
+ "mode": "required"
9180
+ }
9181
+ },
9182
+ "extends": "SmrtObject",
9183
+ "exportName": "NotificationOptOut",
9184
+ "collectionExportName": "NotificationOptOutCollection",
9185
+ "validationRules": [
9186
+ {
9187
+ "field": "recipientUserId",
9188
+ "rule": "required",
9189
+ "fieldType": "crossPackageRef"
9190
+ },
9191
+ {
9192
+ "field": "channel",
9193
+ "rule": "required",
9194
+ "fieldType": "text"
9195
+ },
9196
+ {
9197
+ "field": "scope",
9198
+ "rule": "required",
9199
+ "fieldType": "text"
9200
+ }
9201
+ ],
9202
+ "schema": {
9203
+ "tableName": "notification_opt_outs",
9204
+ "ddl": "CREATE TABLE IF NOT EXISTS \"notification_opt_outs\" (\n \"_sync_origin_device_id\" TEXT,\n \"_sync_revision\" INTEGER,\n \"id\" UUID PRIMARY KEY NOT NULL,\n \"slug\" TEXT NOT NULL,\n \"context\" TEXT NOT NULL DEFAULT '',\n \"created_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"updated_at\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\n \"tenant_id\" UUID NOT NULL,\n \"recipient_user_id\" UUID NOT NULL,\n \"channel\" TEXT NOT NULL DEFAULT 'email',\n \"scope\" TEXT NOT NULL,\n \"opted_out_at\" TIMESTAMP,\n \"updated_by\" TEXT\n);",
9205
+ "columns": {
9206
+ "_sync_origin_device_id": {
9207
+ "type": "TEXT"
9208
+ },
9209
+ "_sync_revision": {
9210
+ "type": "INTEGER"
9211
+ },
9212
+ "id": {
9213
+ "type": "UUID",
9214
+ "primaryKey": true,
9215
+ "referenceKind": "id",
9216
+ "notNull": true
9217
+ },
9218
+ "slug": {
9219
+ "type": "TEXT",
9220
+ "notNull": true
9221
+ },
9222
+ "context": {
9223
+ "type": "TEXT",
9224
+ "notNull": true,
9225
+ "default": ""
9226
+ },
9227
+ "created_at": {
9228
+ "type": "TIMESTAMP",
9229
+ "notNull": true,
9230
+ "default": "current_timestamp"
9231
+ },
9232
+ "updated_at": {
9233
+ "type": "TIMESTAMP",
9234
+ "notNull": true,
9235
+ "default": "current_timestamp"
9236
+ },
9237
+ "tenant_id": {
9238
+ "type": "UUID",
9239
+ "referenceKind": "tenantId",
9240
+ "notNull": true,
9241
+ "unique": false
9242
+ },
9243
+ "recipient_user_id": {
9244
+ "type": "UUID",
9245
+ "referenceKind": "crossPackageRef",
9246
+ "notNull": true,
9247
+ "unique": false
9248
+ },
9249
+ "channel": {
9250
+ "type": "TEXT",
9251
+ "notNull": true,
9252
+ "unique": false,
9253
+ "default": "email"
9254
+ },
9255
+ "scope": {
9256
+ "type": "TEXT",
9257
+ "notNull": true,
9258
+ "unique": false
9259
+ },
9260
+ "opted_out_at": {
9261
+ "type": "TIMESTAMP",
9262
+ "notNull": false,
9263
+ "unique": false
9264
+ },
9265
+ "updated_by": {
9266
+ "type": "TEXT",
9267
+ "notNull": false,
9268
+ "unique": false
9269
+ }
9270
+ },
9271
+ "indexes": [
9272
+ {
9273
+ "name": "notification_opt_outs_tenant_id_recipient_user_id_idx",
9274
+ "columns": [
9275
+ "tenant_id",
9276
+ "recipient_user_id",
9277
+ "channel",
9278
+ "scope"
9279
+ ],
9280
+ "unique": true
9281
+ },
9282
+ {
9283
+ "name": "notification_opt_outs_slug_context_idx",
9284
+ "columns": [
9285
+ "slug",
9286
+ "context"
9287
+ ]
9288
+ },
9289
+ {
9290
+ "name": "notification_opt_outs_tenant_id_created_at_idx",
9291
+ "columns": [
9292
+ "tenant_id",
9293
+ "created_at"
9294
+ ]
9295
+ },
9296
+ {
9297
+ "name": "notification_opt_outs_recipient_user_id_idx",
9298
+ "columns": [
9299
+ "recipient_user_id"
9300
+ ]
9301
+ }
9302
+ ],
9303
+ "version": "a13e93c1"
9304
+ },
9305
+ "importPath": "@happyvertical/smrt-messages"
9306
+ },
8978
9307
  "@happyvertical/smrt-messages:PersonaMessageRoute": {
8979
9308
  "name": "personamessageroute",
8980
9309
  "className": "PersonaMessageRoute",
@@ -0,0 +1,44 @@
1
+ import type { SmrtObjectOptions } from '@happyvertical/smrt-core';
2
+ import '../__smrt-register__.js';
3
+ import { SmrtObject } from '@happyvertical/smrt-core';
4
+ import type { NotificationDeliveryChannel } from './NotificationDelivery.js';
5
+ /** `*` (everything in the tenant) or a host key such as `project:<uuid>`. */
6
+ export declare const NOTIFICATION_OPT_OUT_SCOPE_PATTERN: RegExp;
7
+ /** The scope that matches every notification of the channel in the tenant. */
8
+ export declare const NOTIFICATION_OPT_OUT_ALL_SCOPE = "*";
9
+ export declare function isValidNotificationOptOutScope(scope: unknown): scope is string;
10
+ export interface NotificationOptOutOptions extends SmrtObjectOptions {
11
+ tenantId?: string;
12
+ recipientUserId?: string;
13
+ channel?: NotificationDeliveryChannel;
14
+ scope?: string;
15
+ optedOutAt?: Date | null;
16
+ updatedBy?: string;
17
+ }
18
+ /**
19
+ * One person's opt-out of one notification channel for one scope, in one
20
+ * tenant: the preference store behind the outbox's `isSuppressed` hook.
21
+ *
22
+ * Identity is `(tenant, recipient, channel, scope)` (the conflict identity).
23
+ * `optedOutAt` is set while the person is opted out and cleared by an opt-in,
24
+ * so the row keeps its history. `scope` is a host-defined key validated by
25
+ * {@link NOTIFICATION_OPT_OUT_SCOPE_PATTERN}. Read and change rows through
26
+ * `NotificationOptOutService`; the generated REST/MCP/CLI are off because the
27
+ * service is the authorization boundary.
28
+ */
29
+ export declare class NotificationOptOut extends SmrtObject {
30
+ tenantId: string;
31
+ /** The person who opted out (`smrt-users:User`, uuid). */
32
+ recipientUserId: string;
33
+ /** Channel opted out of; only `email` today. */
34
+ channel: NotificationDeliveryChannel;
35
+ /** `*` or a host key such as `project:<uuid>`. */
36
+ scope: string;
37
+ /** When the opt-out took effect; null once the person opted back in. */
38
+ optedOutAt: Date | null;
39
+ /** Who last changed the row: the person's user id, or `system` for host code. */
40
+ updatedBy: string;
41
+ constructor(options?: NotificationOptOutOptions);
42
+ get isOptedOut(): boolean;
43
+ }
44
+ //# sourceMappingURL=NotificationOptOut.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationOptOut.d.ts","sourceRoot":"","sources":["../../src/models/NotificationOptOut.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,yBAAyB,CAAC;AACjC,OAAO,EAGL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AAE7E,6EAA6E;AAC7E,eAAO,MAAM,kCAAkC,QACI,CAAC;AAEpD,8EAA8E;AAC9E,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,CAIjB;AAED,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,2BAA2B,CAAC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAQa,kBAAmB,SAAQ,UAAU;IAEhD,QAAQ,SAAM;IAEd,0DAA0D;IAE1D,eAAe,SAAM;IAErB,gDAAgD;IAEhD,OAAO,EAAE,2BAA2B,CAAW;IAE/C,kDAAkD;IAElD,KAAK,SAAM;IAEX,wEAAwE;IACxE,UAAU,EAAE,IAAI,GAAG,IAAI,CAAQ;IAE/B,iFAAiF;IACjF,SAAS,SAAM;gBAEH,OAAO,GAAE,yBAA8B;IAWnD,IAAI,UAAU,IAAI,OAAO,CAExB;CACF"}
@@ -0,0 +1,80 @@
1
+ import { type SmrtClassOptions } from '@happyvertical/smrt-core';
2
+ import { type NotificationDeliveryChannel } from '../models/NotificationDelivery.js';
3
+ import { NotificationOptOut } from '../models/NotificationOptOut.js';
4
+ import type { NotificationSuppressionRequest } from './NotificationOutboxService.js';
5
+ /** The signed-in person making a request, as the host authenticated them. */
6
+ export interface NotificationOptOutPrincipal {
7
+ userId: string;
8
+ /**
9
+ * The tenant the principal is authenticated in. Required and must equal the
10
+ * request's tenant: a principal never acts in another tenant. A host whose
11
+ * recipient is authenticated elsewhere (e.g. a member of a child tenant)
12
+ * authorizes the recipient itself and makes a trusted call without a
13
+ * principal instead.
14
+ */
15
+ tenantId: string;
16
+ }
17
+ export interface NotificationOptOutKey {
18
+ tenantId: string;
19
+ recipientUserId: string;
20
+ channel: NotificationDeliveryChannel;
21
+ /** `*` or a host key such as `project:<uuid>`. */
22
+ scope: string;
23
+ }
24
+ export interface NotificationOptOutChange extends NotificationOptOutKey {
25
+ /**
26
+ * The signed-in person, authenticated in this tenant. When present only the
27
+ * recipient themself may change the row, and only in the principal's own
28
+ * tenant; when omitted the call is trusted host code that has already
29
+ * authenticated the recipient (e.g. a signed unsubscribe link, or a host
30
+ * route whose member belongs to a child tenant of the delivery tenant).
31
+ */
32
+ principal?: NotificationOptOutPrincipal;
33
+ }
34
+ export interface NotificationOptOutListRequest {
35
+ tenantId: string;
36
+ recipientUserId: string;
37
+ principal: NotificationOptOutPrincipal;
38
+ }
39
+ export type NotificationOptOutDenialReason = 'principal' | 'tenant';
40
+ /** Thrown when a principal tries to read or change another person's opt-out. */
41
+ export declare class NotificationOptOutDeniedError extends Error {
42
+ readonly reason: NotificationOptOutDenialReason;
43
+ constructor(reason: NotificationOptOutDenialReason, message: string);
44
+ }
45
+ /**
46
+ * The per-recipient opt-out ledger behind the outbox's `isSuppressed` hook.
47
+ *
48
+ * Writes are idempotent and, with a `principal`, limited to the recipient's
49
+ * own rows. {@link isOptedOut} is a trusted read for suppression: it runs
50
+ * where the recipient is not the caller (a manager enqueues, a worker
51
+ * dispatches) and is always scoped to the given tenant.
52
+ */
53
+ export declare class NotificationOptOutService {
54
+ private readonly options;
55
+ constructor(options: {
56
+ db: SmrtClassOptions['db'];
57
+ });
58
+ private collection;
59
+ /** Opt the recipient out of `scope`; a repeat leaves the row untouched. */
60
+ optOut(change: NotificationOptOutChange): Promise<NotificationOptOut>;
61
+ /** Clear an opt-out; a repeat, or no row at all, is a no-op. */
62
+ optIn(change: NotificationOptOutChange): Promise<NotificationOptOut>;
63
+ /**
64
+ * Whether the recipient has opted out of `scope` (a `*` row matches every
65
+ * scope). Trusted read: no principal, always under the tenant's scope.
66
+ */
67
+ isOptedOut(key: NotificationOptOutKey): Promise<boolean>;
68
+ /** The recipient's own active opt-outs, in one tenant. */
69
+ listForRecipient(request: NotificationOptOutListRequest): Promise<NotificationOptOut[]>;
70
+ private change;
71
+ }
72
+ /**
73
+ * Build an `isSuppressed` function for `NotificationOutboxOptions` from the
74
+ * ledger. `scopeOf` maps a notification to the scope a recipient can opt out
75
+ * of (e.g. `project:<uuid>` from its `sourceRef`), or null when the
76
+ * notification is not opt-out-able. A `*` opt-out suppresses any notification
77
+ * `scopeOf` maps to a scope; returning `'*'` checks only the tenant-wide row.
78
+ */
79
+ export declare function optOutSuppression(service: Pick<NotificationOptOutService, 'isOptedOut'>, scopeOf: (request: NotificationSuppressionRequest) => string | null | Promise<string | null>): (request: NotificationSuppressionRequest) => Promise<boolean>;
80
+ //# sourceMappingURL=NotificationOptOutService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationOptOutService.d.ts","sourceRoot":"","sources":["../../src/services/NotificationOptOutService.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAGL,kBAAkB,EACnB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAC;AAErF,6EAA6E;AAC7E,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,2BAA2B,CAAC;IACrC,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAyB,SAAQ,qBAAqB;IACrE;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,2BAA2B,CAAC;CACxC;AAED,MAAM,MAAM,8BAA8B,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEpE,gFAAgF;AAChF,qBAAa,6BAA8B,SAAQ,KAAK;IAEpD,QAAQ,CAAC,MAAM,EAAE,8BAA8B;gBAAtC,MAAM,EAAE,8BAA8B,EAC/C,OAAO,EAAE,MAAM;CAKlB;AA+CD;;;;;;;GAOG;AACH,qBAAa,yBAAyB;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE;QAAE,EAAE,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAA;KAAE;IAEpE,OAAO,CAAC,UAAU;IAIlB,2EAA2E;IACrE,MAAM,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI3E,gEAAgE;IAC1D,KAAK,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI1E;;;OAGG;IACG,UAAU,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,OAAO,CAAC;IAc9D,0DAA0D;IACpD,gBAAgB,CACpB,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,kBAAkB,EAAE,CAAC;YAmBlB,MAAM;CA6DrB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,CAAC,yBAAyB,EAAE,YAAY,CAAC,EACtD,OAAO,EAAE,CACP,OAAO,EAAE,8BAA8B,KACpC,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAC1C,CAAC,OAAO,EAAE,8BAA8B,KAAK,OAAO,CAAC,OAAO,CAAC,CAW/D"}