@voyantjs/notifications 0.1.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.
@@ -0,0 +1,2 @@
1
+ export { sendDueNotificationReminders } from "./send-due-reminders.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1 @@
1
+ export { sendDueNotificationReminders } from "./send-due-reminders.js";
@@ -0,0 +1,18 @@
1
+ import type { NotificationProvider } from "../types.js";
2
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
+ type NotificationTaskEnv = {
4
+ RESEND_API_KEY?: unknown;
5
+ EMAIL_FROM?: unknown;
6
+ };
7
+ export declare function sendDueNotificationReminders(db: PostgresJsDatabase, env: NotificationTaskEnv, input?: {
8
+ now?: string | null;
9
+ }, options?: {
10
+ resolveProviders?: (env: NotificationTaskEnv) => ReadonlyArray<NotificationProvider>;
11
+ }): Promise<{
12
+ processed: number;
13
+ sent: number;
14
+ skipped: number;
15
+ failed: number;
16
+ }>;
17
+ export {};
18
+ //# sourceMappingURL=send-due-reminders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"send-due-reminders.d.ts","sourceRoot":"","sources":["../../src/tasks/send-due-reminders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,KAAK,mBAAmB,GAAG;IACzB,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,wBAAsB,4BAA4B,CAChD,EAAE,EAAE,kBAAkB,EACtB,GAAG,EAAE,mBAAmB,EACxB,KAAK,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAO,EACnC,OAAO,GAAE;IACP,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,aAAa,CAAC,oBAAoB,CAAC,CAAA;CAChF;;;;;GAMP"}
@@ -0,0 +1,6 @@
1
+ import { createDefaultNotificationProviders } from "../provider-resolution.js";
2
+ import { createNotificationService, notificationsService } from "../service.js";
3
+ export async function sendDueNotificationReminders(db, env, input = {}, options = {}) {
4
+ const dispatcher = createNotificationService(options.resolveProviders?.(env) ?? createDefaultNotificationProviders(env));
5
+ return notificationsService.runDueReminders(db, dispatcher, input);
6
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Channel over which a notification is delivered. Built-in channels are
3
+ * `"email"` and `"sms"`, but providers may declare additional channel
4
+ * identifiers (e.g. `"slack"`, `"push"`).
5
+ */
6
+ export type NotificationChannel = "email" | "sms" | (string & {});
7
+ /**
8
+ * Payload describing a single notification to send. The `template` and
9
+ * `data` fields are interpreted by the handling provider.
10
+ */
11
+ export interface NotificationPayload {
12
+ /** Recipient address (email address, phone number, channel id, ...). */
13
+ to: string;
14
+ /** Channel this notification targets. */
15
+ channel: NotificationChannel;
16
+ /** Optional provider hint when the caller wants a specific provider. */
17
+ provider?: string;
18
+ /** Template identifier — interpretation is provider-specific. */
19
+ template: string;
20
+ /** Data passed to the template for rendering. */
21
+ data?: unknown;
22
+ /** Optional sender override. Providers may have their own defaults. */
23
+ from?: string;
24
+ /** Optional subject line (email-only). */
25
+ subject?: string;
26
+ /** Optional pre-rendered HTML body. */
27
+ html?: string;
28
+ /** Optional pre-rendered text body. */
29
+ text?: string;
30
+ }
31
+ /**
32
+ * Result returned after a provider handles a send.
33
+ */
34
+ export interface NotificationResult {
35
+ /** Provider-assigned message/send id, if available. */
36
+ id?: string;
37
+ /** Name of the provider that handled the send. */
38
+ provider: string;
39
+ }
40
+ /**
41
+ * A pluggable notification provider. Implementations target one or more
42
+ * channels and handle the actual delivery (HTTP call, SMTP, etc.).
43
+ *
44
+ * Built-in implementations:
45
+ * - {@link createLocalProvider} — logs to console (dev)
46
+ * - {@link createResendProvider} — Resend email API
47
+ *
48
+ * Additional providers can be added by implementing this interface.
49
+ */
50
+ export interface NotificationProvider {
51
+ /** Unique provider name (e.g. "resend", "local", "twilio"). */
52
+ readonly name: string;
53
+ /** Channels this provider can handle. */
54
+ readonly channels: ReadonlyArray<NotificationChannel>;
55
+ /** Deliver the notification. Throws on failure. */
56
+ send(payload: NotificationPayload): Promise<NotificationResult>;
57
+ }
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEjE;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAA;IACV,yCAAyC;IACzC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IACrD,mDAAmD;IACnD,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAChE"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,275 @@
1
+ import { z } from "zod";
2
+ export declare const notificationChannelSchema: z.ZodEnum<{
3
+ email: "email";
4
+ sms: "sms";
5
+ }>;
6
+ export declare const notificationTemplateStatusSchema: z.ZodEnum<{
7
+ draft: "draft";
8
+ active: "active";
9
+ archived: "archived";
10
+ }>;
11
+ export declare const notificationDeliveryStatusSchema: z.ZodEnum<{
12
+ cancelled: "cancelled";
13
+ pending: "pending";
14
+ failed: "failed";
15
+ sent: "sent";
16
+ }>;
17
+ export declare const notificationTargetTypeSchema: z.ZodEnum<{
18
+ other: "other";
19
+ booking: "booking";
20
+ invoice: "invoice";
21
+ booking_payment_schedule: "booking_payment_schedule";
22
+ booking_guarantee: "booking_guarantee";
23
+ payment_session: "payment_session";
24
+ person: "person";
25
+ organization: "organization";
26
+ }>;
27
+ export declare const notificationReminderStatusSchema: z.ZodEnum<{
28
+ draft: "draft";
29
+ active: "active";
30
+ archived: "archived";
31
+ }>;
32
+ export declare const notificationReminderTargetTypeSchema: z.ZodEnum<{
33
+ booking_payment_schedule: "booking_payment_schedule";
34
+ }>;
35
+ export declare const notificationReminderRunStatusSchema: z.ZodEnum<{
36
+ failed: "failed";
37
+ sent: "sent";
38
+ processing: "processing";
39
+ skipped: "skipped";
40
+ }>;
41
+ export declare const insertNotificationTemplateSchema: z.ZodObject<{
42
+ slug: z.ZodString;
43
+ name: z.ZodString;
44
+ channel: z.ZodEnum<{
45
+ email: "email";
46
+ sms: "sms";
47
+ }>;
48
+ provider: z.ZodNullable<z.ZodOptional<z.ZodString>>;
49
+ status: z.ZodDefault<z.ZodEnum<{
50
+ draft: "draft";
51
+ active: "active";
52
+ archived: "archived";
53
+ }>>;
54
+ subjectTemplate: z.ZodNullable<z.ZodOptional<z.ZodString>>;
55
+ htmlTemplate: z.ZodNullable<z.ZodOptional<z.ZodString>>;
56
+ textTemplate: z.ZodNullable<z.ZodOptional<z.ZodString>>;
57
+ fromAddress: z.ZodNullable<z.ZodOptional<z.ZodString>>;
58
+ isSystem: z.ZodDefault<z.ZodBoolean>;
59
+ metadata: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
60
+ }, z.core.$strip>;
61
+ export declare const updateNotificationTemplateSchema: z.ZodObject<{
62
+ slug: z.ZodOptional<z.ZodString>;
63
+ name: z.ZodOptional<z.ZodString>;
64
+ channel: z.ZodOptional<z.ZodEnum<{
65
+ email: "email";
66
+ sms: "sms";
67
+ }>>;
68
+ provider: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
69
+ status: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
70
+ draft: "draft";
71
+ active: "active";
72
+ archived: "archived";
73
+ }>>>;
74
+ subjectTemplate: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
75
+ htmlTemplate: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
76
+ textTemplate: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
77
+ fromAddress: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
78
+ isSystem: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
79
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
80
+ }, z.core.$strip>;
81
+ export declare const notificationTemplateListQuerySchema: z.ZodObject<{
82
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
83
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
84
+ channel: z.ZodOptional<z.ZodEnum<{
85
+ email: "email";
86
+ sms: "sms";
87
+ }>>;
88
+ provider: z.ZodOptional<z.ZodString>;
89
+ status: z.ZodOptional<z.ZodEnum<{
90
+ draft: "draft";
91
+ active: "active";
92
+ archived: "archived";
93
+ }>>;
94
+ search: z.ZodOptional<z.ZodString>;
95
+ }, z.core.$strip>;
96
+ export declare const notificationDeliveryListQuerySchema: z.ZodObject<{
97
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
98
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
99
+ channel: z.ZodOptional<z.ZodEnum<{
100
+ email: "email";
101
+ sms: "sms";
102
+ }>>;
103
+ provider: z.ZodOptional<z.ZodString>;
104
+ status: z.ZodOptional<z.ZodEnum<{
105
+ cancelled: "cancelled";
106
+ pending: "pending";
107
+ failed: "failed";
108
+ sent: "sent";
109
+ }>>;
110
+ templateSlug: z.ZodOptional<z.ZodString>;
111
+ targetType: z.ZodOptional<z.ZodEnum<{
112
+ other: "other";
113
+ booking: "booking";
114
+ invoice: "invoice";
115
+ booking_payment_schedule: "booking_payment_schedule";
116
+ booking_guarantee: "booking_guarantee";
117
+ payment_session: "payment_session";
118
+ person: "person";
119
+ organization: "organization";
120
+ }>>;
121
+ targetId: z.ZodOptional<z.ZodString>;
122
+ bookingId: z.ZodOptional<z.ZodString>;
123
+ invoiceId: z.ZodOptional<z.ZodString>;
124
+ paymentSessionId: z.ZodOptional<z.ZodString>;
125
+ personId: z.ZodOptional<z.ZodString>;
126
+ organizationId: z.ZodOptional<z.ZodString>;
127
+ }, z.core.$strip>;
128
+ export declare const insertNotificationReminderRuleSchema: z.ZodObject<{
129
+ slug: z.ZodString;
130
+ name: z.ZodString;
131
+ status: z.ZodDefault<z.ZodEnum<{
132
+ draft: "draft";
133
+ active: "active";
134
+ archived: "archived";
135
+ }>>;
136
+ targetType: z.ZodEnum<{
137
+ booking_payment_schedule: "booking_payment_schedule";
138
+ }>;
139
+ channel: z.ZodEnum<{
140
+ email: "email";
141
+ sms: "sms";
142
+ }>;
143
+ provider: z.ZodNullable<z.ZodOptional<z.ZodString>>;
144
+ templateId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
145
+ templateSlug: z.ZodNullable<z.ZodOptional<z.ZodString>>;
146
+ relativeDaysFromDueDate: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
147
+ isSystem: z.ZodDefault<z.ZodBoolean>;
148
+ metadata: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
149
+ }, z.core.$strip>;
150
+ export declare const updateNotificationReminderRuleSchema: z.ZodObject<{
151
+ slug: z.ZodOptional<z.ZodString>;
152
+ name: z.ZodOptional<z.ZodString>;
153
+ status: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
154
+ draft: "draft";
155
+ active: "active";
156
+ archived: "archived";
157
+ }>>>;
158
+ targetType: z.ZodOptional<z.ZodEnum<{
159
+ booking_payment_schedule: "booking_payment_schedule";
160
+ }>>;
161
+ channel: z.ZodOptional<z.ZodEnum<{
162
+ email: "email";
163
+ sms: "sms";
164
+ }>>;
165
+ provider: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
166
+ templateId: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
167
+ templateSlug: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
168
+ relativeDaysFromDueDate: z.ZodOptional<z.ZodDefault<z.ZodCoercedNumber<unknown>>>;
169
+ isSystem: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
170
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>>;
171
+ }, z.core.$strip>;
172
+ export declare const notificationReminderRuleListQuerySchema: z.ZodObject<{
173
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
174
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
175
+ status: z.ZodOptional<z.ZodEnum<{
176
+ draft: "draft";
177
+ active: "active";
178
+ archived: "archived";
179
+ }>>;
180
+ targetType: z.ZodOptional<z.ZodEnum<{
181
+ booking_payment_schedule: "booking_payment_schedule";
182
+ }>>;
183
+ channel: z.ZodOptional<z.ZodEnum<{
184
+ email: "email";
185
+ sms: "sms";
186
+ }>>;
187
+ search: z.ZodOptional<z.ZodString>;
188
+ }, z.core.$strip>;
189
+ export declare const notificationReminderRunListQuerySchema: z.ZodObject<{
190
+ limit: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
191
+ offset: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
192
+ reminderRuleId: z.ZodOptional<z.ZodString>;
193
+ targetType: z.ZodOptional<z.ZodEnum<{
194
+ booking_payment_schedule: "booking_payment_schedule";
195
+ }>>;
196
+ targetId: z.ZodOptional<z.ZodString>;
197
+ bookingId: z.ZodOptional<z.ZodString>;
198
+ status: z.ZodOptional<z.ZodEnum<{
199
+ failed: "failed";
200
+ sent: "sent";
201
+ processing: "processing";
202
+ skipped: "skipped";
203
+ }>>;
204
+ }, z.core.$strip>;
205
+ export declare const runDueRemindersSchema: z.ZodObject<{
206
+ now: z.ZodNullable<z.ZodOptional<z.ZodString>>;
207
+ }, z.core.$strip>;
208
+ export declare const sendPaymentSessionNotificationSchema: z.ZodObject<{
209
+ templateId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
210
+ templateSlug: z.ZodNullable<z.ZodOptional<z.ZodString>>;
211
+ channel: z.ZodDefault<z.ZodEnum<{
212
+ email: "email";
213
+ sms: "sms";
214
+ }>>;
215
+ provider: z.ZodNullable<z.ZodOptional<z.ZodString>>;
216
+ to: z.ZodNullable<z.ZodOptional<z.ZodString>>;
217
+ from: z.ZodNullable<z.ZodOptional<z.ZodString>>;
218
+ subject: z.ZodNullable<z.ZodOptional<z.ZodString>>;
219
+ html: z.ZodNullable<z.ZodOptional<z.ZodString>>;
220
+ text: z.ZodNullable<z.ZodOptional<z.ZodString>>;
221
+ data: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
222
+ metadata: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
223
+ scheduledFor: z.ZodNullable<z.ZodOptional<z.ZodString>>;
224
+ }, z.core.$strip>;
225
+ export declare const sendInvoiceNotificationSchema: z.ZodObject<{
226
+ templateId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
227
+ templateSlug: z.ZodNullable<z.ZodOptional<z.ZodString>>;
228
+ channel: z.ZodDefault<z.ZodEnum<{
229
+ email: "email";
230
+ sms: "sms";
231
+ }>>;
232
+ provider: z.ZodNullable<z.ZodOptional<z.ZodString>>;
233
+ to: z.ZodNullable<z.ZodOptional<z.ZodString>>;
234
+ from: z.ZodNullable<z.ZodOptional<z.ZodString>>;
235
+ subject: z.ZodNullable<z.ZodOptional<z.ZodString>>;
236
+ html: z.ZodNullable<z.ZodOptional<z.ZodString>>;
237
+ text: z.ZodNullable<z.ZodOptional<z.ZodString>>;
238
+ data: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
239
+ metadata: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
240
+ scheduledFor: z.ZodNullable<z.ZodOptional<z.ZodString>>;
241
+ }, z.core.$strip>;
242
+ export declare const sendNotificationSchema: z.ZodObject<{
243
+ templateId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
244
+ templateSlug: z.ZodNullable<z.ZodOptional<z.ZodString>>;
245
+ channel: z.ZodOptional<z.ZodEnum<{
246
+ email: "email";
247
+ sms: "sms";
248
+ }>>;
249
+ provider: z.ZodNullable<z.ZodOptional<z.ZodString>>;
250
+ to: z.ZodString;
251
+ from: z.ZodNullable<z.ZodOptional<z.ZodString>>;
252
+ subject: z.ZodNullable<z.ZodOptional<z.ZodString>>;
253
+ html: z.ZodNullable<z.ZodOptional<z.ZodString>>;
254
+ text: z.ZodNullable<z.ZodOptional<z.ZodString>>;
255
+ data: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
256
+ targetType: z.ZodDefault<z.ZodEnum<{
257
+ other: "other";
258
+ booking: "booking";
259
+ invoice: "invoice";
260
+ booking_payment_schedule: "booking_payment_schedule";
261
+ booking_guarantee: "booking_guarantee";
262
+ payment_session: "payment_session";
263
+ person: "person";
264
+ organization: "organization";
265
+ }>>;
266
+ targetId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
267
+ bookingId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
268
+ invoiceId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
269
+ paymentSessionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
270
+ personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
271
+ organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
272
+ metadata: z.ZodNullable<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
273
+ scheduledFor: z.ZodNullable<z.ZodOptional<z.ZodString>>;
274
+ }, z.core.$strip>;
275
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,yBAAyB;;;EAA2B,CAAA;AACjE,eAAO,MAAM,gCAAgC;;;;EAA0C,CAAA;AACvF,eAAO,MAAM,gCAAgC;;;;;EAAqD,CAAA;AAClG,eAAO,MAAM,4BAA4B;;;;;;;;;EASvC,CAAA;AACF,eAAO,MAAM,gCAAgC;;;;EAA0C,CAAA;AACvF,eAAO,MAAM,oCAAoC;;EAAuC,CAAA;AACxF,eAAO,MAAM,mCAAmC;;;;;EAAsD,CAAA;AAqBtG,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;iBAAiC,CAAA;AAC9E,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;iBAA2C,CAAA;AAExF,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;iBAK9C,CAAA;AAEF,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAY9C,CAAA;AAgBF,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;iBAMhD,CAAA;AAED,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;iBAI7C,CAAA;AAEJ,eAAO,MAAM,uCAAuC;;;;;;;;;;;;;;;;iBAKlD,CAAA;AAEF,eAAO,MAAM,sCAAsC;;;;;;;;;;;;;;;iBAMjD,CAAA;AAEF,eAAO,MAAM,qBAAqB;;iBAEhC,CAAA;AAiBF,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;iBAKhD,CAAA;AAED,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;iBAKzC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwB/B,CAAA"}
@@ -0,0 +1,138 @@
1
+ import { z } from "zod";
2
+ export const notificationChannelSchema = z.enum(["email", "sms"]);
3
+ export const notificationTemplateStatusSchema = z.enum(["draft", "active", "archived"]);
4
+ export const notificationDeliveryStatusSchema = z.enum(["pending", "sent", "failed", "cancelled"]);
5
+ export const notificationTargetTypeSchema = z.enum([
6
+ "booking",
7
+ "booking_payment_schedule",
8
+ "booking_guarantee",
9
+ "invoice",
10
+ "payment_session",
11
+ "person",
12
+ "organization",
13
+ "other",
14
+ ]);
15
+ export const notificationReminderStatusSchema = z.enum(["draft", "active", "archived"]);
16
+ export const notificationReminderTargetTypeSchema = z.enum(["booking_payment_schedule"]);
17
+ export const notificationReminderRunStatusSchema = z.enum(["processing", "sent", "skipped", "failed"]);
18
+ const paginationSchema = z.object({
19
+ limit: z.coerce.number().int().min(1).max(100).default(20),
20
+ offset: z.coerce.number().int().min(0).default(0),
21
+ });
22
+ const notificationTemplateCoreSchema = z.object({
23
+ slug: z.string().min(1).max(255),
24
+ name: z.string().min(1).max(255),
25
+ channel: notificationChannelSchema,
26
+ provider: z.string().max(255).optional().nullable(),
27
+ status: notificationTemplateStatusSchema.default("draft"),
28
+ subjectTemplate: z.string().max(2000).optional().nullable(),
29
+ htmlTemplate: z.string().optional().nullable(),
30
+ textTemplate: z.string().optional().nullable(),
31
+ fromAddress: z.string().max(500).optional().nullable(),
32
+ isSystem: z.boolean().default(false),
33
+ metadata: z.record(z.string(), z.unknown()).optional().nullable(),
34
+ });
35
+ export const insertNotificationTemplateSchema = notificationTemplateCoreSchema;
36
+ export const updateNotificationTemplateSchema = notificationTemplateCoreSchema.partial();
37
+ export const notificationTemplateListQuerySchema = paginationSchema.extend({
38
+ channel: notificationChannelSchema.optional(),
39
+ provider: z.string().optional(),
40
+ status: notificationTemplateStatusSchema.optional(),
41
+ search: z.string().optional(),
42
+ });
43
+ export const notificationDeliveryListQuerySchema = paginationSchema.extend({
44
+ channel: notificationChannelSchema.optional(),
45
+ provider: z.string().optional(),
46
+ status: notificationDeliveryStatusSchema.optional(),
47
+ templateSlug: z.string().optional(),
48
+ targetType: notificationTargetTypeSchema.optional(),
49
+ targetId: z.string().optional(),
50
+ bookingId: z.string().optional(),
51
+ invoiceId: z.string().optional(),
52
+ paymentSessionId: z.string().optional(),
53
+ personId: z.string().optional(),
54
+ organizationId: z.string().optional(),
55
+ });
56
+ const notificationReminderRuleCoreSchema = z.object({
57
+ slug: z.string().min(1).max(255),
58
+ name: z.string().min(1).max(255),
59
+ status: notificationReminderStatusSchema.default("draft"),
60
+ targetType: notificationReminderTargetTypeSchema,
61
+ channel: notificationChannelSchema,
62
+ provider: z.string().max(255).optional().nullable(),
63
+ templateId: z.string().optional().nullable(),
64
+ templateSlug: z.string().max(255).optional().nullable(),
65
+ relativeDaysFromDueDate: z.coerce.number().int().min(-365).max(365).default(0),
66
+ isSystem: z.boolean().default(false),
67
+ metadata: z.record(z.string(), z.unknown()).optional().nullable(),
68
+ });
69
+ export const insertNotificationReminderRuleSchema = notificationReminderRuleCoreSchema.refine((value) => Boolean(value.templateId || value.templateSlug), {
70
+ message: "templateId or templateSlug is required",
71
+ path: ["templateId"],
72
+ });
73
+ export const updateNotificationReminderRuleSchema = notificationReminderRuleCoreSchema
74
+ .partial()
75
+ .refine((value) => value.templateId !== "" && value.templateSlug !== "", {
76
+ message: "templateId and templateSlug cannot be empty strings",
77
+ });
78
+ export const notificationReminderRuleListQuerySchema = paginationSchema.extend({
79
+ status: notificationReminderStatusSchema.optional(),
80
+ targetType: notificationReminderTargetTypeSchema.optional(),
81
+ channel: notificationChannelSchema.optional(),
82
+ search: z.string().optional(),
83
+ });
84
+ export const notificationReminderRunListQuerySchema = paginationSchema.extend({
85
+ reminderRuleId: z.string().optional(),
86
+ targetType: notificationReminderTargetTypeSchema.optional(),
87
+ targetId: z.string().optional(),
88
+ bookingId: z.string().optional(),
89
+ status: notificationReminderRunStatusSchema.optional(),
90
+ });
91
+ export const runDueRemindersSchema = z.object({
92
+ now: z.string().datetime().optional().nullable(),
93
+ });
94
+ const transportNotificationCoreSchema = z.object({
95
+ templateId: z.string().optional().nullable(),
96
+ templateSlug: z.string().optional().nullable(),
97
+ channel: notificationChannelSchema.default("email"),
98
+ provider: z.string().optional().nullable(),
99
+ to: z.string().min(1).optional().nullable(),
100
+ from: z.string().max(500).optional().nullable(),
101
+ subject: z.string().max(2000).optional().nullable(),
102
+ html: z.string().optional().nullable(),
103
+ text: z.string().optional().nullable(),
104
+ data: z.record(z.string(), z.unknown()).optional().nullable(),
105
+ metadata: z.record(z.string(), z.unknown()).optional().nullable(),
106
+ scheduledFor: z.string().optional().nullable(),
107
+ });
108
+ export const sendPaymentSessionNotificationSchema = transportNotificationCoreSchema.refine((value) => Boolean(value.templateId || value.templateSlug || value.subject || value.html || value.text), {
109
+ message: "templateId, templateSlug, or direct content is required",
110
+ });
111
+ export const sendInvoiceNotificationSchema = transportNotificationCoreSchema.refine((value) => Boolean(value.templateId || value.templateSlug || value.subject || value.html || value.text), {
112
+ message: "templateId, templateSlug, or direct content is required",
113
+ });
114
+ export const sendNotificationSchema = z
115
+ .object({
116
+ templateId: z.string().optional().nullable(),
117
+ templateSlug: z.string().optional().nullable(),
118
+ channel: notificationChannelSchema.optional(),
119
+ provider: z.string().optional().nullable(),
120
+ to: z.string().min(1),
121
+ from: z.string().max(500).optional().nullable(),
122
+ subject: z.string().max(2000).optional().nullable(),
123
+ html: z.string().optional().nullable(),
124
+ text: z.string().optional().nullable(),
125
+ data: z.record(z.string(), z.unknown()).optional().nullable(),
126
+ targetType: notificationTargetTypeSchema.default("other"),
127
+ targetId: z.string().optional().nullable(),
128
+ bookingId: z.string().optional().nullable(),
129
+ invoiceId: z.string().optional().nullable(),
130
+ paymentSessionId: z.string().optional().nullable(),
131
+ personId: z.string().optional().nullable(),
132
+ organizationId: z.string().optional().nullable(),
133
+ metadata: z.record(z.string(), z.unknown()).optional().nullable(),
134
+ scheduledFor: z.string().optional().nullable(),
135
+ })
136
+ .refine((value) => Boolean(value.templateId || value.templateSlug || value.subject || value.html || value.text), {
137
+ message: "templateId, templateSlug, or direct content is required",
138
+ });
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@voyantjs/notifications",
3
+ "version": "0.1.0",
4
+ "license": "FSL-1.1-Apache-2.0",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ },
11
+ "./schema": {
12
+ "types": "./dist/schema.d.ts",
13
+ "import": "./dist/schema.js"
14
+ },
15
+ "./types": {
16
+ "types": "./dist/types.d.ts",
17
+ "import": "./dist/types.js"
18
+ },
19
+ "./validation": {
20
+ "types": "./dist/validation.d.ts",
21
+ "import": "./dist/validation.js"
22
+ },
23
+ "./routes": {
24
+ "types": "./dist/routes.d.ts",
25
+ "import": "./dist/routes.js"
26
+ },
27
+ "./service": {
28
+ "types": "./dist/service.d.ts",
29
+ "import": "./dist/service.js"
30
+ },
31
+ "./tasks": {
32
+ "types": "./dist/tasks/index.d.ts",
33
+ "import": "./dist/tasks/index.js"
34
+ },
35
+ "./providers/local": {
36
+ "types": "./dist/providers/local.d.ts",
37
+ "import": "./dist/providers/local.js"
38
+ },
39
+ "./providers/resend": {
40
+ "types": "./dist/providers/resend.d.ts",
41
+ "import": "./dist/providers/resend.js"
42
+ },
43
+ "./provider-resolution": {
44
+ "types": "./dist/provider-resolution.d.ts",
45
+ "import": "./dist/provider-resolution.js"
46
+ }
47
+ },
48
+ "dependencies": {
49
+ "drizzle-orm": "^0.45.2",
50
+ "hono": "^4.12.10",
51
+ "zod": "^4.3.6",
52
+ "@voyantjs/bookings": "0.1.0",
53
+ "@voyantjs/core": "0.1.0",
54
+ "@voyantjs/db": "0.1.0",
55
+ "@voyantjs/hono": "0.1.0",
56
+ "@voyantjs/finance": "0.1.0"
57
+ },
58
+ "devDependencies": {
59
+ "typescript": "^6.0.2",
60
+ "vitest": "^4.1.2",
61
+ "@voyantjs/voyant-typescript-config": "0.1.0"
62
+ },
63
+ "files": [
64
+ "dist"
65
+ ],
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "scripts": {
70
+ "typecheck": "tsc --noEmit",
71
+ "lint": "biome check src/",
72
+ "test": "vitest run",
73
+ "build": "tsc -p tsconfig.json",
74
+ "clean": "rm -rf dist"
75
+ },
76
+ "main": "./dist/index.js",
77
+ "types": "./dist/index.d.ts"
78
+ }