@contractspec/module.notifications 1.56.1 → 1.58.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.
- package/dist/browser/channels/index.js +124 -0
- package/dist/browser/contracts/index.js +340 -0
- package/dist/browser/entities/index.js +223 -0
- package/dist/browser/index.js +864 -0
- package/dist/browser/notifications.capability.js +16 -0
- package/dist/browser/notifications.feature.js +34 -0
- package/dist/browser/templates/index.js +147 -0
- package/dist/channels/index.d.ts +64 -67
- package/dist/channels/index.d.ts.map +1 -1
- package/dist/channels/index.js +123 -125
- package/dist/contracts/index.d.ts +571 -577
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +324 -416
- package/dist/entities/index.d.ts +145 -150
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +215 -245
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +864 -6
- package/dist/node/channels/index.js +124 -0
- package/dist/node/contracts/index.js +340 -0
- package/dist/node/entities/index.js +223 -0
- package/dist/node/index.js +864 -0
- package/dist/node/notifications.capability.js +16 -0
- package/dist/node/notifications.feature.js +34 -0
- package/dist/node/templates/index.js +147 -0
- package/dist/notifications.capability.d.ts +1 -6
- package/dist/notifications.capability.d.ts.map +1 -1
- package/dist/notifications.capability.js +17 -20
- package/dist/notifications.feature.d.ts +1 -7
- package/dist/notifications.feature.d.ts.map +1 -1
- package/dist/notifications.feature.js +33 -75
- package/dist/templates/index.d.ts +47 -50
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/index.js +127 -181
- package/package.json +102 -27
- package/dist/channels/index.js.map +0 -1
- package/dist/contracts/index.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/notifications.capability.js.map +0 -1
- package/dist/notifications.feature.js.map +0 -1
- package/dist/templates/index.js.map +0 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
// src/channels/index.ts
|
|
2
|
+
class InAppChannel {
|
|
3
|
+
channelId = "IN_APP";
|
|
4
|
+
async send(_notification) {
|
|
5
|
+
return {
|
|
6
|
+
success: true,
|
|
7
|
+
responseMessage: "Stored in database"
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
async isAvailable() {
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class ConsoleChannel {
|
|
16
|
+
channelId = "CONSOLE";
|
|
17
|
+
async send(notification) {
|
|
18
|
+
console.log(`\uD83D\uDCEC [${notification.id}] ${notification.title}`);
|
|
19
|
+
console.log(` ${notification.body}`);
|
|
20
|
+
if (notification.actionUrl) {
|
|
21
|
+
console.log(` Action: ${notification.actionUrl}`);
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
success: true,
|
|
25
|
+
responseMessage: "Logged to console"
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
async isAvailable() {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class EmailChannel {
|
|
34
|
+
channelId = "EMAIL";
|
|
35
|
+
async isAvailable() {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class PushChannel {
|
|
41
|
+
channelId = "PUSH";
|
|
42
|
+
async isAvailable() {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
class WebhookChannel {
|
|
48
|
+
channelId = "WEBHOOK";
|
|
49
|
+
async send(notification) {
|
|
50
|
+
if (!notification.webhook?.url) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
responseMessage: "No webhook URL configured"
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch(notification.webhook.url, {
|
|
58
|
+
method: "POST",
|
|
59
|
+
headers: {
|
|
60
|
+
"Content-Type": "application/json",
|
|
61
|
+
...notification.webhook.headers
|
|
62
|
+
},
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
id: notification.id,
|
|
65
|
+
title: notification.title,
|
|
66
|
+
body: notification.body,
|
|
67
|
+
actionUrl: notification.actionUrl,
|
|
68
|
+
metadata: notification.metadata
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
success: response.ok,
|
|
73
|
+
responseCode: String(response.status),
|
|
74
|
+
responseMessage: response.statusText
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
responseMessage: error instanceof Error ? error.message : "Unknown error"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async isAvailable() {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class ChannelRegistry {
|
|
89
|
+
channels = new Map;
|
|
90
|
+
register(channel) {
|
|
91
|
+
this.channels.set(channel.channelId, channel);
|
|
92
|
+
}
|
|
93
|
+
get(channelId) {
|
|
94
|
+
return this.channels.get(channelId);
|
|
95
|
+
}
|
|
96
|
+
getAll() {
|
|
97
|
+
return Array.from(this.channels.values());
|
|
98
|
+
}
|
|
99
|
+
async getAvailable() {
|
|
100
|
+
const available = [];
|
|
101
|
+
for (const channel of this.channels.values()) {
|
|
102
|
+
if (await channel.isAvailable()) {
|
|
103
|
+
available.push(channel);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return available;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function createChannelRegistry() {
|
|
110
|
+
const registry = new ChannelRegistry;
|
|
111
|
+
registry.register(new InAppChannel);
|
|
112
|
+
registry.register(new ConsoleChannel);
|
|
113
|
+
registry.register(new WebhookChannel);
|
|
114
|
+
return registry;
|
|
115
|
+
}
|
|
116
|
+
export {
|
|
117
|
+
createChannelRegistry,
|
|
118
|
+
WebhookChannel,
|
|
119
|
+
PushChannel,
|
|
120
|
+
InAppChannel,
|
|
121
|
+
EmailChannel,
|
|
122
|
+
ConsoleChannel,
|
|
123
|
+
ChannelRegistry
|
|
124
|
+
};
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
// src/contracts/index.ts
|
|
2
|
+
import {
|
|
3
|
+
defineCommand,
|
|
4
|
+
defineQuery,
|
|
5
|
+
defineSchemaModel
|
|
6
|
+
} from "@contractspec/lib.contracts";
|
|
7
|
+
import { ScalarTypeEnum, defineEnum } from "@contractspec/lib.schema";
|
|
8
|
+
var OWNERS = ["platform.notifications"];
|
|
9
|
+
var NotificationStatusSchemaEnum = defineEnum("NotificationStatus", [
|
|
10
|
+
"PENDING",
|
|
11
|
+
"SENT",
|
|
12
|
+
"DELIVERED",
|
|
13
|
+
"READ",
|
|
14
|
+
"FAILED",
|
|
15
|
+
"CANCELLED"
|
|
16
|
+
]);
|
|
17
|
+
var NotificationChannelSchemaEnum = defineEnum("NotificationChannel", [
|
|
18
|
+
"EMAIL",
|
|
19
|
+
"IN_APP",
|
|
20
|
+
"PUSH",
|
|
21
|
+
"WEBHOOK"
|
|
22
|
+
]);
|
|
23
|
+
var NotificationFilterEnum = defineEnum("NotificationFilter", [
|
|
24
|
+
"unread",
|
|
25
|
+
"read",
|
|
26
|
+
"all"
|
|
27
|
+
]);
|
|
28
|
+
var NotificationModel = defineSchemaModel({
|
|
29
|
+
name: "Notification",
|
|
30
|
+
description: "A notification sent to a user",
|
|
31
|
+
fields: {
|
|
32
|
+
id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
33
|
+
userId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
34
|
+
title: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
35
|
+
body: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
36
|
+
type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
37
|
+
status: { type: NotificationStatusSchemaEnum, isOptional: false },
|
|
38
|
+
channels: {
|
|
39
|
+
type: NotificationChannelSchemaEnum,
|
|
40
|
+
isArray: true,
|
|
41
|
+
isOptional: false
|
|
42
|
+
},
|
|
43
|
+
actionUrl: { type: ScalarTypeEnum.URL(), isOptional: true },
|
|
44
|
+
readAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
|
|
45
|
+
createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
var NotificationPreferenceModel = defineSchemaModel({
|
|
49
|
+
name: "NotificationPreference",
|
|
50
|
+
description: "User notification preferences",
|
|
51
|
+
fields: {
|
|
52
|
+
userId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
53
|
+
globalEnabled: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
54
|
+
channelPreferences: {
|
|
55
|
+
type: ScalarTypeEnum.JSONObject(),
|
|
56
|
+
isOptional: false
|
|
57
|
+
},
|
|
58
|
+
typePreferences: { type: ScalarTypeEnum.JSONObject(), isOptional: false },
|
|
59
|
+
quietHoursStart: {
|
|
60
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
61
|
+
isOptional: true
|
|
62
|
+
},
|
|
63
|
+
quietHoursEnd: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
64
|
+
timezone: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
65
|
+
digestEnabled: { type: ScalarTypeEnum.Boolean(), isOptional: false },
|
|
66
|
+
digestFrequency: {
|
|
67
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
68
|
+
isOptional: true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
var SendNotificationInputModel = defineSchemaModel({
|
|
73
|
+
name: "SendNotificationInput",
|
|
74
|
+
description: "Input for sending a notification",
|
|
75
|
+
fields: {
|
|
76
|
+
userId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
77
|
+
templateId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
78
|
+
title: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
79
|
+
body: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
80
|
+
type: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
|
|
81
|
+
channels: {
|
|
82
|
+
type: NotificationChannelSchemaEnum,
|
|
83
|
+
isArray: true,
|
|
84
|
+
isOptional: true
|
|
85
|
+
},
|
|
86
|
+
actionUrl: { type: ScalarTypeEnum.URL(), isOptional: true },
|
|
87
|
+
variables: { type: ScalarTypeEnum.JSONObject(), isOptional: true },
|
|
88
|
+
metadata: { type: ScalarTypeEnum.JSONObject(), isOptional: true }
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
var ListNotificationsInputModel = defineSchemaModel({
|
|
92
|
+
name: "ListNotificationsInput",
|
|
93
|
+
description: "Input for listing notifications",
|
|
94
|
+
fields: {
|
|
95
|
+
status: { type: NotificationFilterEnum, isOptional: true },
|
|
96
|
+
type: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
97
|
+
limit: {
|
|
98
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
99
|
+
isOptional: true,
|
|
100
|
+
defaultValue: 20
|
|
101
|
+
},
|
|
102
|
+
offset: {
|
|
103
|
+
type: ScalarTypeEnum.Int_unsecure(),
|
|
104
|
+
isOptional: true,
|
|
105
|
+
defaultValue: 0
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
var ListNotificationsOutputModel = defineSchemaModel({
|
|
110
|
+
name: "ListNotificationsOutput",
|
|
111
|
+
description: "Output for listing notifications",
|
|
112
|
+
fields: {
|
|
113
|
+
notifications: {
|
|
114
|
+
type: NotificationModel,
|
|
115
|
+
isArray: true,
|
|
116
|
+
isOptional: false
|
|
117
|
+
},
|
|
118
|
+
total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
|
|
119
|
+
unreadCount: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
var UpdatePreferencesInputModel = defineSchemaModel({
|
|
123
|
+
name: "UpdateNotificationPreferencesInput",
|
|
124
|
+
description: "Input for updating notification preferences",
|
|
125
|
+
fields: {
|
|
126
|
+
globalEnabled: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
127
|
+
channelPreferences: { type: ScalarTypeEnum.JSONObject(), isOptional: true },
|
|
128
|
+
typePreferences: { type: ScalarTypeEnum.JSONObject(), isOptional: true },
|
|
129
|
+
quietHoursStart: {
|
|
130
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
131
|
+
isOptional: true
|
|
132
|
+
},
|
|
133
|
+
quietHoursEnd: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
134
|
+
timezone: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
|
|
135
|
+
digestEnabled: { type: ScalarTypeEnum.Boolean(), isOptional: true },
|
|
136
|
+
digestFrequency: {
|
|
137
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
138
|
+
isOptional: true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
var SendNotificationContract = defineCommand({
|
|
143
|
+
meta: {
|
|
144
|
+
key: "notifications.send",
|
|
145
|
+
version: "1.0.0",
|
|
146
|
+
stability: "stable",
|
|
147
|
+
owners: [...OWNERS],
|
|
148
|
+
tags: ["notifications", "send"],
|
|
149
|
+
description: "Send a notification to a user.",
|
|
150
|
+
goal: "Deliver notifications across multiple channels.",
|
|
151
|
+
context: "Called by services when events require user notification."
|
|
152
|
+
},
|
|
153
|
+
io: {
|
|
154
|
+
input: SendNotificationInputModel,
|
|
155
|
+
output: NotificationModel,
|
|
156
|
+
errors: {
|
|
157
|
+
USER_NOT_FOUND: {
|
|
158
|
+
description: "Target user does not exist",
|
|
159
|
+
http: 404,
|
|
160
|
+
gqlCode: "USER_NOT_FOUND",
|
|
161
|
+
when: "User ID is invalid"
|
|
162
|
+
},
|
|
163
|
+
TEMPLATE_NOT_FOUND: {
|
|
164
|
+
description: "Notification template does not exist",
|
|
165
|
+
http: 404,
|
|
166
|
+
gqlCode: "TEMPLATE_NOT_FOUND",
|
|
167
|
+
when: "Template ID is invalid"
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
policy: {
|
|
172
|
+
auth: "user"
|
|
173
|
+
},
|
|
174
|
+
sideEffects: {
|
|
175
|
+
emits: [
|
|
176
|
+
{
|
|
177
|
+
key: "notification.sent",
|
|
178
|
+
version: "1.0.0",
|
|
179
|
+
when: "Notification is sent",
|
|
180
|
+
payload: NotificationModel
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
var ListNotificationsContract = defineQuery({
|
|
186
|
+
meta: {
|
|
187
|
+
key: "notifications.list",
|
|
188
|
+
version: "1.0.0",
|
|
189
|
+
stability: "stable",
|
|
190
|
+
owners: [...OWNERS],
|
|
191
|
+
tags: ["notifications", "list"],
|
|
192
|
+
description: "List notifications for the current user.",
|
|
193
|
+
goal: "Show user their notifications.",
|
|
194
|
+
context: "Notification center UI."
|
|
195
|
+
},
|
|
196
|
+
io: {
|
|
197
|
+
input: ListNotificationsInputModel,
|
|
198
|
+
output: ListNotificationsOutputModel
|
|
199
|
+
},
|
|
200
|
+
policy: {
|
|
201
|
+
auth: "user"
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
var MarkNotificationReadContract = defineCommand({
|
|
205
|
+
meta: {
|
|
206
|
+
key: "notifications.markRead",
|
|
207
|
+
version: "1.0.0",
|
|
208
|
+
stability: "stable",
|
|
209
|
+
owners: [...OWNERS],
|
|
210
|
+
tags: ["notifications", "read"],
|
|
211
|
+
description: "Mark a notification as read.",
|
|
212
|
+
goal: "Track which notifications user has seen.",
|
|
213
|
+
context: "User clicks on a notification."
|
|
214
|
+
},
|
|
215
|
+
io: {
|
|
216
|
+
input: defineSchemaModel({
|
|
217
|
+
name: "MarkNotificationReadInput",
|
|
218
|
+
fields: {
|
|
219
|
+
notificationId: {
|
|
220
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
221
|
+
isOptional: false
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}),
|
|
225
|
+
output: NotificationModel
|
|
226
|
+
},
|
|
227
|
+
policy: {
|
|
228
|
+
auth: "user"
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
var MarkAllNotificationsReadContract = defineCommand({
|
|
232
|
+
meta: {
|
|
233
|
+
key: "notifications.markAllRead",
|
|
234
|
+
version: "1.0.0",
|
|
235
|
+
stability: "stable",
|
|
236
|
+
owners: [...OWNERS],
|
|
237
|
+
tags: ["notifications", "read"],
|
|
238
|
+
description: "Mark all notifications as read.",
|
|
239
|
+
goal: "Clear notification badge.",
|
|
240
|
+
context: 'User clicks "mark all as read".'
|
|
241
|
+
},
|
|
242
|
+
io: {
|
|
243
|
+
input: null,
|
|
244
|
+
output: defineSchemaModel({
|
|
245
|
+
name: "MarkAllNotificationsReadOutput",
|
|
246
|
+
fields: {
|
|
247
|
+
markedCount: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
},
|
|
251
|
+
policy: {
|
|
252
|
+
auth: "user"
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
var GetNotificationPreferencesContract = defineQuery({
|
|
256
|
+
meta: {
|
|
257
|
+
key: "notifications.preferences.get",
|
|
258
|
+
version: "1.0.0",
|
|
259
|
+
stability: "stable",
|
|
260
|
+
owners: [...OWNERS],
|
|
261
|
+
tags: ["notifications", "preferences", "get"],
|
|
262
|
+
description: "Get notification preferences for current user.",
|
|
263
|
+
goal: "Show user their notification settings.",
|
|
264
|
+
context: "Notification settings page."
|
|
265
|
+
},
|
|
266
|
+
io: {
|
|
267
|
+
input: null,
|
|
268
|
+
output: NotificationPreferenceModel
|
|
269
|
+
},
|
|
270
|
+
policy: {
|
|
271
|
+
auth: "user"
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
var UpdateNotificationPreferencesContract = defineCommand({
|
|
275
|
+
meta: {
|
|
276
|
+
key: "notifications.preferences.update",
|
|
277
|
+
version: "1.0.0",
|
|
278
|
+
stability: "stable",
|
|
279
|
+
owners: [...OWNERS],
|
|
280
|
+
tags: ["notifications", "preferences", "update"],
|
|
281
|
+
description: "Update notification preferences.",
|
|
282
|
+
goal: "Allow user to control notification delivery.",
|
|
283
|
+
context: "Notification settings page."
|
|
284
|
+
},
|
|
285
|
+
io: {
|
|
286
|
+
input: UpdatePreferencesInputModel,
|
|
287
|
+
output: NotificationPreferenceModel
|
|
288
|
+
},
|
|
289
|
+
policy: {
|
|
290
|
+
auth: "user"
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
var DeleteNotificationContract = defineCommand({
|
|
294
|
+
meta: {
|
|
295
|
+
key: "notifications.delete",
|
|
296
|
+
version: "1.0.0",
|
|
297
|
+
stability: "stable",
|
|
298
|
+
owners: [...OWNERS],
|
|
299
|
+
tags: ["notifications", "delete"],
|
|
300
|
+
description: "Delete a notification.",
|
|
301
|
+
goal: "Allow user to remove unwanted notifications.",
|
|
302
|
+
context: "User dismisses a notification."
|
|
303
|
+
},
|
|
304
|
+
io: {
|
|
305
|
+
input: defineSchemaModel({
|
|
306
|
+
name: "DeleteNotificationInput",
|
|
307
|
+
fields: {
|
|
308
|
+
notificationId: {
|
|
309
|
+
type: ScalarTypeEnum.String_unsecure(),
|
|
310
|
+
isOptional: false
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}),
|
|
314
|
+
output: defineSchemaModel({
|
|
315
|
+
name: "DeleteNotificationOutput",
|
|
316
|
+
fields: {
|
|
317
|
+
success: { type: ScalarTypeEnum.Boolean(), isOptional: false }
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
},
|
|
321
|
+
policy: {
|
|
322
|
+
auth: "user"
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
export {
|
|
326
|
+
UpdatePreferencesInputModel,
|
|
327
|
+
UpdateNotificationPreferencesContract,
|
|
328
|
+
SendNotificationInputModel,
|
|
329
|
+
SendNotificationContract,
|
|
330
|
+
NotificationPreferenceModel,
|
|
331
|
+
NotificationModel,
|
|
332
|
+
NotificationFilterEnum,
|
|
333
|
+
MarkNotificationReadContract,
|
|
334
|
+
MarkAllNotificationsReadContract,
|
|
335
|
+
ListNotificationsOutputModel,
|
|
336
|
+
ListNotificationsInputModel,
|
|
337
|
+
ListNotificationsContract,
|
|
338
|
+
GetNotificationPreferencesContract,
|
|
339
|
+
DeleteNotificationContract
|
|
340
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// src/entities/index.ts
|
|
2
|
+
import {
|
|
3
|
+
defineEntity,
|
|
4
|
+
defineEntityEnum,
|
|
5
|
+
field,
|
|
6
|
+
index
|
|
7
|
+
} from "@contractspec/lib.schema";
|
|
8
|
+
var NotificationStatusEnum = defineEntityEnum({
|
|
9
|
+
name: "NotificationStatus",
|
|
10
|
+
values: [
|
|
11
|
+
"PENDING",
|
|
12
|
+
"SENT",
|
|
13
|
+
"DELIVERED",
|
|
14
|
+
"READ",
|
|
15
|
+
"FAILED",
|
|
16
|
+
"CANCELLED"
|
|
17
|
+
],
|
|
18
|
+
schema: "lssm_notifications",
|
|
19
|
+
description: "Status of a notification."
|
|
20
|
+
});
|
|
21
|
+
var NotificationChannelEnum = defineEntityEnum({
|
|
22
|
+
name: "NotificationChannel",
|
|
23
|
+
values: ["EMAIL", "IN_APP", "PUSH", "WEBHOOK", "SMS"],
|
|
24
|
+
schema: "lssm_notifications",
|
|
25
|
+
description: "Delivery channel for notifications."
|
|
26
|
+
});
|
|
27
|
+
var NotificationEntity = defineEntity({
|
|
28
|
+
name: "Notification",
|
|
29
|
+
description: "An individual notification to be delivered to a user.",
|
|
30
|
+
schema: "lssm_notifications",
|
|
31
|
+
map: "notification",
|
|
32
|
+
fields: {
|
|
33
|
+
id: field.id({ description: "Unique notification ID" }),
|
|
34
|
+
userId: field.foreignKey({ description: "Target user ID" }),
|
|
35
|
+
orgId: field.string({
|
|
36
|
+
isOptional: true,
|
|
37
|
+
description: "Organization context"
|
|
38
|
+
}),
|
|
39
|
+
templateId: field.string({
|
|
40
|
+
isOptional: true,
|
|
41
|
+
description: "Template used"
|
|
42
|
+
}),
|
|
43
|
+
title: field.string({ description: "Notification title" }),
|
|
44
|
+
body: field.string({ description: "Notification body" }),
|
|
45
|
+
actionUrl: field.string({ isOptional: true, description: "Action URL" }),
|
|
46
|
+
imageUrl: field.string({ isOptional: true, description: "Image URL" }),
|
|
47
|
+
type: field.string({
|
|
48
|
+
description: "Notification type (e.g., mention, update)"
|
|
49
|
+
}),
|
|
50
|
+
category: field.string({
|
|
51
|
+
isOptional: true,
|
|
52
|
+
description: "Notification category"
|
|
53
|
+
}),
|
|
54
|
+
priority: field.enum("NotificationPriority", { default: "NORMAL" }),
|
|
55
|
+
channels: field.string({
|
|
56
|
+
isArray: true,
|
|
57
|
+
description: "Target delivery channels"
|
|
58
|
+
}),
|
|
59
|
+
status: field.enum("NotificationStatus", { default: "PENDING" }),
|
|
60
|
+
sentAt: field.dateTime({ isOptional: true }),
|
|
61
|
+
deliveredAt: field.dateTime({ isOptional: true }),
|
|
62
|
+
readAt: field.dateTime({ isOptional: true }),
|
|
63
|
+
metadata: field.json({
|
|
64
|
+
isOptional: true,
|
|
65
|
+
description: "Additional metadata"
|
|
66
|
+
}),
|
|
67
|
+
variables: field.json({
|
|
68
|
+
isOptional: true,
|
|
69
|
+
description: "Template variables used"
|
|
70
|
+
}),
|
|
71
|
+
triggeredBy: field.string({
|
|
72
|
+
isOptional: true,
|
|
73
|
+
description: "Event/action that triggered"
|
|
74
|
+
}),
|
|
75
|
+
sourceId: field.string({
|
|
76
|
+
isOptional: true,
|
|
77
|
+
description: "Source entity ID"
|
|
78
|
+
}),
|
|
79
|
+
sourceType: field.string({
|
|
80
|
+
isOptional: true,
|
|
81
|
+
description: "Source entity type"
|
|
82
|
+
}),
|
|
83
|
+
createdAt: field.createdAt(),
|
|
84
|
+
updatedAt: field.updatedAt(),
|
|
85
|
+
expiresAt: field.dateTime({
|
|
86
|
+
isOptional: true,
|
|
87
|
+
description: "Notification expiry"
|
|
88
|
+
}),
|
|
89
|
+
deliveryLogs: field.hasMany("DeliveryLog")
|
|
90
|
+
},
|
|
91
|
+
indexes: [
|
|
92
|
+
index.on(["userId", "status", "createdAt"]),
|
|
93
|
+
index.on(["userId", "readAt"]),
|
|
94
|
+
index.on(["orgId", "createdAt"]),
|
|
95
|
+
index.on(["type", "createdAt"])
|
|
96
|
+
],
|
|
97
|
+
enums: [NotificationStatusEnum, NotificationChannelEnum]
|
|
98
|
+
});
|
|
99
|
+
var NotificationPriorityEnum = defineEntityEnum({
|
|
100
|
+
name: "NotificationPriority",
|
|
101
|
+
values: ["LOW", "NORMAL", "HIGH", "URGENT"],
|
|
102
|
+
schema: "lssm_notifications",
|
|
103
|
+
description: "Priority level of a notification."
|
|
104
|
+
});
|
|
105
|
+
var NotificationTemplateEntity = defineEntity({
|
|
106
|
+
name: "NotificationTemplate",
|
|
107
|
+
description: "Reusable notification template.",
|
|
108
|
+
schema: "lssm_notifications",
|
|
109
|
+
map: "notification_template",
|
|
110
|
+
fields: {
|
|
111
|
+
id: field.id(),
|
|
112
|
+
templateId: field.string({
|
|
113
|
+
isUnique: true,
|
|
114
|
+
description: "Template identifier"
|
|
115
|
+
}),
|
|
116
|
+
name: field.string({ description: "Template display name" }),
|
|
117
|
+
description: field.string({ isOptional: true }),
|
|
118
|
+
emailSubject: field.string({ isOptional: true }),
|
|
119
|
+
emailBody: field.string({ isOptional: true }),
|
|
120
|
+
inAppTitle: field.string({ isOptional: true }),
|
|
121
|
+
inAppBody: field.string({ isOptional: true }),
|
|
122
|
+
pushTitle: field.string({ isOptional: true }),
|
|
123
|
+
pushBody: field.string({ isOptional: true }),
|
|
124
|
+
defaultChannels: field.string({ isArray: true }),
|
|
125
|
+
category: field.string({ isOptional: true }),
|
|
126
|
+
priority: field.enum("NotificationPriority", { default: "NORMAL" }),
|
|
127
|
+
variablesSchema: field.json({
|
|
128
|
+
isOptional: true,
|
|
129
|
+
description: "JSON schema for variables"
|
|
130
|
+
}),
|
|
131
|
+
enabled: field.boolean({ default: true }),
|
|
132
|
+
createdAt: field.createdAt(),
|
|
133
|
+
updatedAt: field.updatedAt()
|
|
134
|
+
},
|
|
135
|
+
enums: [NotificationPriorityEnum]
|
|
136
|
+
});
|
|
137
|
+
var NotificationPreferenceEntity = defineEntity({
|
|
138
|
+
name: "NotificationPreference",
|
|
139
|
+
description: "User notification preferences by type and channel.",
|
|
140
|
+
schema: "lssm_notifications",
|
|
141
|
+
map: "notification_preference",
|
|
142
|
+
fields: {
|
|
143
|
+
id: field.id(),
|
|
144
|
+
userId: field.foreignKey(),
|
|
145
|
+
globalEnabled: field.boolean({ default: true }),
|
|
146
|
+
quietHoursStart: field.string({
|
|
147
|
+
isOptional: true,
|
|
148
|
+
description: "Quiet hours start (HH:MM)"
|
|
149
|
+
}),
|
|
150
|
+
quietHoursEnd: field.string({
|
|
151
|
+
isOptional: true,
|
|
152
|
+
description: "Quiet hours end (HH:MM)"
|
|
153
|
+
}),
|
|
154
|
+
timezone: field.string({ default: '"UTC"' }),
|
|
155
|
+
channelPreferences: field.json({
|
|
156
|
+
description: "Channel-level preferences"
|
|
157
|
+
}),
|
|
158
|
+
typePreferences: field.json({ description: "Type-level preferences" }),
|
|
159
|
+
digestEnabled: field.boolean({ default: false }),
|
|
160
|
+
digestFrequency: field.string({
|
|
161
|
+
isOptional: true,
|
|
162
|
+
description: "daily, weekly, etc."
|
|
163
|
+
}),
|
|
164
|
+
digestTime: field.string({
|
|
165
|
+
isOptional: true,
|
|
166
|
+
description: "Digest send time (HH:MM)"
|
|
167
|
+
}),
|
|
168
|
+
createdAt: field.createdAt(),
|
|
169
|
+
updatedAt: field.updatedAt()
|
|
170
|
+
},
|
|
171
|
+
indexes: [index.unique(["userId"])]
|
|
172
|
+
});
|
|
173
|
+
var DeliveryLogEntity = defineEntity({
|
|
174
|
+
name: "DeliveryLog",
|
|
175
|
+
description: "Log of notification delivery attempts.",
|
|
176
|
+
schema: "lssm_notifications",
|
|
177
|
+
map: "delivery_log",
|
|
178
|
+
fields: {
|
|
179
|
+
id: field.id(),
|
|
180
|
+
notificationId: field.foreignKey(),
|
|
181
|
+
channel: field.enum("NotificationChannel"),
|
|
182
|
+
status: field.enum("NotificationStatus"),
|
|
183
|
+
attemptedAt: field.dateTime(),
|
|
184
|
+
deliveredAt: field.dateTime({ isOptional: true }),
|
|
185
|
+
responseCode: field.string({ isOptional: true }),
|
|
186
|
+
responseMessage: field.string({ isOptional: true }),
|
|
187
|
+
externalId: field.string({
|
|
188
|
+
isOptional: true,
|
|
189
|
+
description: "Provider message ID"
|
|
190
|
+
}),
|
|
191
|
+
metadata: field.json({ isOptional: true }),
|
|
192
|
+
notification: field.belongsTo("Notification", ["notificationId"], ["id"], {
|
|
193
|
+
onDelete: "Cascade"
|
|
194
|
+
})
|
|
195
|
+
},
|
|
196
|
+
indexes: [index.on(["notificationId", "channel"])]
|
|
197
|
+
});
|
|
198
|
+
var notificationEntities = [
|
|
199
|
+
NotificationEntity,
|
|
200
|
+
NotificationTemplateEntity,
|
|
201
|
+
NotificationPreferenceEntity,
|
|
202
|
+
DeliveryLogEntity
|
|
203
|
+
];
|
|
204
|
+
var notificationsSchemaContribution = {
|
|
205
|
+
moduleId: "@contractspec/module.notifications",
|
|
206
|
+
entities: notificationEntities,
|
|
207
|
+
enums: [
|
|
208
|
+
NotificationStatusEnum,
|
|
209
|
+
NotificationChannelEnum,
|
|
210
|
+
NotificationPriorityEnum
|
|
211
|
+
]
|
|
212
|
+
};
|
|
213
|
+
export {
|
|
214
|
+
notificationsSchemaContribution,
|
|
215
|
+
notificationEntities,
|
|
216
|
+
NotificationTemplateEntity,
|
|
217
|
+
NotificationStatusEnum,
|
|
218
|
+
NotificationPriorityEnum,
|
|
219
|
+
NotificationPreferenceEntity,
|
|
220
|
+
NotificationEntity,
|
|
221
|
+
NotificationChannelEnum,
|
|
222
|
+
DeliveryLogEntity
|
|
223
|
+
};
|