@voyantjs/notifications 0.1.1 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EAErB,MAAM,aAAa,CAAA;AAEpB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAC7C;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC7C,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,oBAAoB,CAoB5F"}
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EAErB,MAAM,aAAa,CAAA;AAEpB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAC7C;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAA;IAC7C,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG,oBAAoB,CAmB5F"}
@@ -8,7 +8,6 @@ export function createLocalProvider(options = {}) {
8
8
  const channels = options.channels ?? ["email", "sms"];
9
9
  const sink = options.sink ??
10
10
  ((payload) => {
11
- // biome-ignore lint/suspicious/noConsole: local provider is console-based by design
12
11
  console.log(`[notifications:${name}]`, payload);
13
12
  });
14
13
  let counter = 0;
@@ -0,0 +1,153 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import type { NotificationDeliveryListQuery, NotificationService, SendInvoiceNotificationInput, SendNotificationInput, SendPaymentSessionNotificationInput } from "./service-shared.js";
3
+ export declare function listDeliveries(db: PostgresJsDatabase, query: NotificationDeliveryListQuery): Promise<{
4
+ data: {
5
+ id: string;
6
+ templateId: string | null;
7
+ templateSlug: string | null;
8
+ targetType: "other" | "booking" | "invoice" | "booking_payment_schedule" | "booking_guarantee" | "payment_session" | "person" | "organization";
9
+ targetId: string | null;
10
+ personId: string | null;
11
+ organizationId: string | null;
12
+ bookingId: string | null;
13
+ invoiceId: string | null;
14
+ paymentSessionId: string | null;
15
+ channel: "email" | "sms";
16
+ provider: string;
17
+ providerMessageId: string | null;
18
+ status: "cancelled" | "pending" | "failed" | "sent";
19
+ toAddress: string;
20
+ fromAddress: string | null;
21
+ subject: string | null;
22
+ htmlBody: string | null;
23
+ textBody: string | null;
24
+ payloadData: Record<string, unknown> | null;
25
+ metadata: Record<string, unknown> | null;
26
+ errorMessage: string | null;
27
+ scheduledFor: Date | null;
28
+ sentAt: Date | null;
29
+ failedAt: Date | null;
30
+ createdAt: Date;
31
+ updatedAt: Date;
32
+ }[];
33
+ total: number;
34
+ limit: number;
35
+ offset: number;
36
+ }>;
37
+ export declare function getDeliveryById(db: PostgresJsDatabase, id: string): Promise<{
38
+ id: string;
39
+ templateId: string | null;
40
+ templateSlug: string | null;
41
+ targetType: "other" | "booking" | "invoice" | "booking_payment_schedule" | "booking_guarantee" | "payment_session" | "person" | "organization";
42
+ targetId: string | null;
43
+ personId: string | null;
44
+ organizationId: string | null;
45
+ bookingId: string | null;
46
+ invoiceId: string | null;
47
+ paymentSessionId: string | null;
48
+ channel: "email" | "sms";
49
+ provider: string;
50
+ providerMessageId: string | null;
51
+ status: "cancelled" | "pending" | "failed" | "sent";
52
+ toAddress: string;
53
+ fromAddress: string | null;
54
+ subject: string | null;
55
+ htmlBody: string | null;
56
+ textBody: string | null;
57
+ payloadData: Record<string, unknown> | null;
58
+ metadata: Record<string, unknown> | null;
59
+ errorMessage: string | null;
60
+ scheduledFor: Date | null;
61
+ sentAt: Date | null;
62
+ failedAt: Date | null;
63
+ createdAt: Date;
64
+ updatedAt: Date;
65
+ } | null>;
66
+ export declare function sendNotification(db: PostgresJsDatabase, dispatcher: NotificationService, input: SendNotificationInput): Promise<{
67
+ id: string;
68
+ templateId: string | null;
69
+ templateSlug: string | null;
70
+ targetType: "other" | "booking" | "invoice" | "booking_payment_schedule" | "booking_guarantee" | "payment_session" | "person" | "organization";
71
+ targetId: string | null;
72
+ personId: string | null;
73
+ organizationId: string | null;
74
+ bookingId: string | null;
75
+ invoiceId: string | null;
76
+ paymentSessionId: string | null;
77
+ channel: "email" | "sms";
78
+ provider: string;
79
+ providerMessageId: string | null;
80
+ status: "cancelled" | "pending" | "failed" | "sent";
81
+ toAddress: string;
82
+ fromAddress: string | null;
83
+ subject: string | null;
84
+ htmlBody: string | null;
85
+ textBody: string | null;
86
+ payloadData: Record<string, unknown> | null;
87
+ metadata: Record<string, unknown> | null;
88
+ errorMessage: string | null;
89
+ scheduledFor: Date | null;
90
+ sentAt: Date | null;
91
+ failedAt: Date | null;
92
+ createdAt: Date;
93
+ updatedAt: Date;
94
+ } | null>;
95
+ export declare function sendPaymentSessionNotification(db: PostgresJsDatabase, dispatcher: NotificationService, sessionId: string, input: SendPaymentSessionNotificationInput): Promise<{
96
+ id: string;
97
+ templateId: string | null;
98
+ templateSlug: string | null;
99
+ targetType: "other" | "booking" | "invoice" | "booking_payment_schedule" | "booking_guarantee" | "payment_session" | "person" | "organization";
100
+ targetId: string | null;
101
+ personId: string | null;
102
+ organizationId: string | null;
103
+ bookingId: string | null;
104
+ invoiceId: string | null;
105
+ paymentSessionId: string | null;
106
+ channel: "email" | "sms";
107
+ provider: string;
108
+ providerMessageId: string | null;
109
+ status: "cancelled" | "pending" | "failed" | "sent";
110
+ toAddress: string;
111
+ fromAddress: string | null;
112
+ subject: string | null;
113
+ htmlBody: string | null;
114
+ textBody: string | null;
115
+ payloadData: Record<string, unknown> | null;
116
+ metadata: Record<string, unknown> | null;
117
+ errorMessage: string | null;
118
+ scheduledFor: Date | null;
119
+ sentAt: Date | null;
120
+ failedAt: Date | null;
121
+ createdAt: Date;
122
+ updatedAt: Date;
123
+ } | null>;
124
+ export declare function sendInvoiceNotification(db: PostgresJsDatabase, dispatcher: NotificationService, invoiceId: string, input: SendInvoiceNotificationInput): Promise<{
125
+ id: string;
126
+ templateId: string | null;
127
+ templateSlug: string | null;
128
+ targetType: "other" | "booking" | "invoice" | "booking_payment_schedule" | "booking_guarantee" | "payment_session" | "person" | "organization";
129
+ targetId: string | null;
130
+ personId: string | null;
131
+ organizationId: string | null;
132
+ bookingId: string | null;
133
+ invoiceId: string | null;
134
+ paymentSessionId: string | null;
135
+ channel: "email" | "sms";
136
+ provider: string;
137
+ providerMessageId: string | null;
138
+ status: "cancelled" | "pending" | "failed" | "sent";
139
+ toAddress: string;
140
+ fromAddress: string | null;
141
+ subject: string | null;
142
+ htmlBody: string | null;
143
+ textBody: string | null;
144
+ payloadData: Record<string, unknown> | null;
145
+ metadata: Record<string, unknown> | null;
146
+ errorMessage: string | null;
147
+ scheduledFor: Date | null;
148
+ sentAt: Date | null;
149
+ failedAt: Date | null;
150
+ createdAt: Date;
151
+ updatedAt: Date;
152
+ } | null>;
153
+ //# sourceMappingURL=service-deliveries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-deliveries.d.ts","sourceRoot":"","sources":["../src/service-deliveries.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,KAAK,EACV,6BAA6B,EAC7B,mBAAmB,EACnB,4BAA4B,EAC5B,qBAAqB,EACrB,mCAAmC,EACpC,MAAM,qBAAqB,CAAA;AAY5B,wBAAsB,cAAc,CAAC,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgChG;AAED,wBAAsB,eAAe,CAAC,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAOvE;AAED,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,mBAAmB,EAC/B,KAAK,EAAE,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAmH7B;AAED,wBAAsB,8BAA8B,CAClD,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,mBAAmB,EAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA8F3C;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,mBAAmB,EAC/B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,4BAA4B;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4FpC"}
@@ -0,0 +1,334 @@
1
+ import { bookings } from "@voyantjs/bookings/schema";
2
+ import { invoices, paymentSessions } from "@voyantjs/finance";
3
+ import { desc, eq, sql } from "drizzle-orm";
4
+ import { notificationDeliveries } from "./schema.js";
5
+ import { buildWhereClause, listBookingNotificationParticipants, NotificationError, paginate, renderNotificationTemplate, resolveReminderRecipient, toTimestamp, } from "./service-shared.js";
6
+ import { getTemplateById, getTemplateBySlug } from "./service-templates.js";
7
+ export async function listDeliveries(db, query) {
8
+ const conditions = [];
9
+ if (query.channel)
10
+ conditions.push(eq(notificationDeliveries.channel, query.channel));
11
+ if (query.provider)
12
+ conditions.push(eq(notificationDeliveries.provider, query.provider));
13
+ if (query.status)
14
+ conditions.push(eq(notificationDeliveries.status, query.status));
15
+ if (query.templateSlug)
16
+ conditions.push(eq(notificationDeliveries.templateSlug, query.templateSlug));
17
+ if (query.targetType)
18
+ conditions.push(eq(notificationDeliveries.targetType, query.targetType));
19
+ if (query.targetId)
20
+ conditions.push(eq(notificationDeliveries.targetId, query.targetId));
21
+ if (query.bookingId)
22
+ conditions.push(eq(notificationDeliveries.bookingId, query.bookingId));
23
+ if (query.invoiceId)
24
+ conditions.push(eq(notificationDeliveries.invoiceId, query.invoiceId));
25
+ if (query.paymentSessionId) {
26
+ conditions.push(eq(notificationDeliveries.paymentSessionId, query.paymentSessionId));
27
+ }
28
+ if (query.personId)
29
+ conditions.push(eq(notificationDeliveries.personId, query.personId));
30
+ if (query.organizationId) {
31
+ conditions.push(eq(notificationDeliveries.organizationId, query.organizationId));
32
+ }
33
+ const where = buildWhereClause(conditions);
34
+ return paginate(db
35
+ .select()
36
+ .from(notificationDeliveries)
37
+ .where(where)
38
+ .limit(query.limit)
39
+ .offset(query.offset)
40
+ .orderBy(desc(notificationDeliveries.createdAt)), db.select({ total: sql `count(*)::int` }).from(notificationDeliveries).where(where), query.limit, query.offset);
41
+ }
42
+ export async function getDeliveryById(db, id) {
43
+ const [row] = await db
44
+ .select()
45
+ .from(notificationDeliveries)
46
+ .where(eq(notificationDeliveries.id, id))
47
+ .limit(1);
48
+ return row ?? null;
49
+ }
50
+ export async function sendNotification(db, dispatcher, input) {
51
+ let template = null;
52
+ if (input.templateId) {
53
+ template = await getTemplateById(db, input.templateId);
54
+ }
55
+ else if (input.templateSlug) {
56
+ template = await getTemplateBySlug(db, input.templateSlug);
57
+ }
58
+ if ((input.templateId || input.templateSlug) && !template) {
59
+ throw new NotificationError("Notification template not found");
60
+ }
61
+ const data = input.data ?? {};
62
+ const channel = input.channel ?? template?.channel;
63
+ if (!channel) {
64
+ throw new NotificationError("Notification channel is required");
65
+ }
66
+ const provider = input.provider ?? template?.provider ?? dispatcher.getProvider(channel)?.name;
67
+ if (!provider) {
68
+ throw new NotificationError(`No notification provider available for channel "${channel}"`);
69
+ }
70
+ const subject = input.subject ?? renderNotificationTemplate(template?.subjectTemplate, data);
71
+ const html = input.html ?? renderNotificationTemplate(template?.htmlTemplate, data);
72
+ const text = input.text ?? renderNotificationTemplate(template?.textTemplate, data);
73
+ const [pending] = await db
74
+ .insert(notificationDeliveries)
75
+ .values({
76
+ templateId: template?.id ?? null,
77
+ templateSlug: template?.slug ?? input.templateSlug ?? null,
78
+ targetType: input.targetType,
79
+ targetId: input.targetId ?? null,
80
+ personId: input.personId ?? null,
81
+ organizationId: input.organizationId ?? null,
82
+ bookingId: input.bookingId ?? null,
83
+ invoiceId: input.invoiceId ?? null,
84
+ paymentSessionId: input.paymentSessionId ?? null,
85
+ channel,
86
+ provider,
87
+ providerMessageId: null,
88
+ status: "pending",
89
+ toAddress: input.to,
90
+ fromAddress: input.from ?? template?.fromAddress ?? null,
91
+ subject: subject ?? null,
92
+ htmlBody: html ?? null,
93
+ textBody: text ?? null,
94
+ payloadData: data,
95
+ metadata: input.metadata ?? null,
96
+ errorMessage: null,
97
+ scheduledFor: toTimestamp(input.scheduledFor),
98
+ sentAt: null,
99
+ failedAt: null,
100
+ })
101
+ .returning();
102
+ if (!pending) {
103
+ throw new NotificationError("Failed to create notification delivery");
104
+ }
105
+ try {
106
+ const result = provider === dispatcher.getProvider(channel)?.name
107
+ ? await dispatcher.send({
108
+ to: input.to,
109
+ channel,
110
+ provider,
111
+ template: template?.slug ?? input.templateSlug ?? "direct",
112
+ data,
113
+ from: input.from ?? template?.fromAddress ?? undefined,
114
+ subject: subject ?? undefined,
115
+ html: html ?? undefined,
116
+ text: text ?? undefined,
117
+ })
118
+ : await dispatcher.sendWith(provider, {
119
+ to: input.to,
120
+ channel,
121
+ provider,
122
+ template: template?.slug ?? input.templateSlug ?? "direct",
123
+ data,
124
+ from: input.from ?? template?.fromAddress ?? undefined,
125
+ subject: subject ?? undefined,
126
+ html: html ?? undefined,
127
+ text: text ?? undefined,
128
+ });
129
+ const [sent] = await db
130
+ .update(notificationDeliveries)
131
+ .set({
132
+ status: "sent",
133
+ providerMessageId: result.id ?? null,
134
+ sentAt: new Date(),
135
+ errorMessage: null,
136
+ updatedAt: new Date(),
137
+ })
138
+ .where(eq(notificationDeliveries.id, pending.id))
139
+ .returning();
140
+ return sent ?? null;
141
+ }
142
+ catch (error) {
143
+ const message = error instanceof Error ? error.message : "Notification send failed";
144
+ const [failed] = await db
145
+ .update(notificationDeliveries)
146
+ .set({
147
+ status: "failed",
148
+ failedAt: new Date(),
149
+ errorMessage: message,
150
+ updatedAt: new Date(),
151
+ })
152
+ .where(eq(notificationDeliveries.id, pending.id))
153
+ .returning();
154
+ throw new NotificationError(failed?.errorMessage ?? message);
155
+ }
156
+ }
157
+ export async function sendPaymentSessionNotification(db, dispatcher, sessionId, input) {
158
+ const [session] = await db
159
+ .select()
160
+ .from(paymentSessions)
161
+ .where(eq(paymentSessions.id, sessionId))
162
+ .limit(1);
163
+ if (!session) {
164
+ return null;
165
+ }
166
+ const booking = session.bookingId
167
+ ? ((await db.select().from(bookings).where(eq(bookings.id, session.bookingId)).limit(1))[0] ??
168
+ null)
169
+ : null;
170
+ const invoice = session.invoiceId
171
+ ? ((await db.select().from(invoices).where(eq(invoices.id, session.invoiceId)).limit(1))[0] ??
172
+ null)
173
+ : null;
174
+ const participants = booking ? await listBookingNotificationParticipants(db, booking.id) : [];
175
+ const recipient = resolveReminderRecipient(participants);
176
+ const to = input.to ?? session.payerEmail ?? recipient?.email ?? null;
177
+ if (!to) {
178
+ throw new NotificationError("No recipient available for payment session notification");
179
+ }
180
+ return sendNotification(db, dispatcher, {
181
+ templateId: input.templateId ?? null,
182
+ templateSlug: input.templateSlug ?? null,
183
+ channel: input.channel,
184
+ provider: input.provider ?? null,
185
+ to,
186
+ from: input.from ?? null,
187
+ subject: input.subject ?? null,
188
+ html: input.html ?? null,
189
+ text: input.text ?? null,
190
+ data: {
191
+ paymentSession: {
192
+ id: session.id,
193
+ status: session.status,
194
+ provider: session.provider,
195
+ currency: session.currency,
196
+ amountCents: session.amountCents,
197
+ redirectUrl: session.redirectUrl,
198
+ returnUrl: session.returnUrl,
199
+ cancelUrl: session.cancelUrl,
200
+ expiresAt: session.expiresAt,
201
+ paymentMethod: session.paymentMethod,
202
+ externalReference: session.externalReference,
203
+ },
204
+ booking: booking
205
+ ? {
206
+ id: booking.id,
207
+ bookingNumber: booking.bookingNumber,
208
+ startDate: booking.startDate,
209
+ endDate: booking.endDate,
210
+ sellCurrency: booking.sellCurrency,
211
+ sellAmountCents: booking.sellAmountCents,
212
+ }
213
+ : null,
214
+ invoice: invoice
215
+ ? {
216
+ id: invoice.id,
217
+ invoiceNumber: invoice.invoiceNumber,
218
+ invoiceType: invoice.invoiceType,
219
+ status: invoice.status,
220
+ currency: invoice.currency,
221
+ totalCents: invoice.totalCents,
222
+ balanceDueCents: invoice.balanceDueCents,
223
+ issueDate: invoice.issueDate,
224
+ dueDate: invoice.dueDate,
225
+ }
226
+ : null,
227
+ participant: recipient
228
+ ? {
229
+ firstName: recipient.firstName,
230
+ lastName: recipient.lastName,
231
+ email: recipient.email,
232
+ }
233
+ : null,
234
+ ...(input.data ?? {}),
235
+ },
236
+ targetType: "payment_session",
237
+ targetId: session.id,
238
+ bookingId: session.bookingId ?? null,
239
+ invoiceId: session.invoiceId ?? null,
240
+ paymentSessionId: session.id,
241
+ personId: session.payerPersonId ?? booking?.personId ?? null,
242
+ organizationId: session.payerOrganizationId ?? booking?.organizationId ?? null,
243
+ metadata: input.metadata ?? null,
244
+ scheduledFor: input.scheduledFor ?? null,
245
+ });
246
+ }
247
+ export async function sendInvoiceNotification(db, dispatcher, invoiceId, input) {
248
+ const [invoice] = await db.select().from(invoices).where(eq(invoices.id, invoiceId)).limit(1);
249
+ if (!invoice) {
250
+ return null;
251
+ }
252
+ const [booking] = await db
253
+ .select()
254
+ .from(bookings)
255
+ .where(eq(bookings.id, invoice.bookingId))
256
+ .limit(1);
257
+ const participants = booking ? await listBookingNotificationParticipants(db, booking.id) : [];
258
+ const recipient = resolveReminderRecipient(participants);
259
+ const [latestSession] = await db
260
+ .select()
261
+ .from(paymentSessions)
262
+ .where(eq(paymentSessions.invoiceId, invoice.id))
263
+ .orderBy(desc(paymentSessions.createdAt))
264
+ .limit(1);
265
+ const to = input.to ?? latestSession?.payerEmail ?? recipient?.email ?? null;
266
+ if (!to) {
267
+ throw new NotificationError("No recipient available for invoice notification");
268
+ }
269
+ return sendNotification(db, dispatcher, {
270
+ templateId: input.templateId ?? null,
271
+ templateSlug: input.templateSlug ?? null,
272
+ channel: input.channel,
273
+ provider: input.provider ?? null,
274
+ to,
275
+ from: input.from ?? null,
276
+ subject: input.subject ?? null,
277
+ html: input.html ?? null,
278
+ text: input.text ?? null,
279
+ data: {
280
+ invoice: {
281
+ id: invoice.id,
282
+ invoiceNumber: invoice.invoiceNumber,
283
+ invoiceType: invoice.invoiceType,
284
+ status: invoice.status,
285
+ currency: invoice.currency,
286
+ subtotalCents: invoice.subtotalCents,
287
+ taxCents: invoice.taxCents,
288
+ totalCents: invoice.totalCents,
289
+ paidCents: invoice.paidCents,
290
+ balanceDueCents: invoice.balanceDueCents,
291
+ issueDate: invoice.issueDate,
292
+ dueDate: invoice.dueDate,
293
+ },
294
+ booking: booking
295
+ ? {
296
+ id: booking.id,
297
+ bookingNumber: booking.bookingNumber,
298
+ startDate: booking.startDate,
299
+ endDate: booking.endDate,
300
+ sellCurrency: booking.sellCurrency,
301
+ sellAmountCents: booking.sellAmountCents,
302
+ }
303
+ : null,
304
+ paymentSession: latestSession
305
+ ? {
306
+ id: latestSession.id,
307
+ status: latestSession.status,
308
+ provider: latestSession.provider,
309
+ redirectUrl: latestSession.redirectUrl,
310
+ expiresAt: latestSession.expiresAt,
311
+ amountCents: latestSession.amountCents,
312
+ currency: latestSession.currency,
313
+ }
314
+ : null,
315
+ participant: recipient
316
+ ? {
317
+ firstName: recipient.firstName,
318
+ lastName: recipient.lastName,
319
+ email: recipient.email,
320
+ }
321
+ : null,
322
+ ...(input.data ?? {}),
323
+ },
324
+ targetType: "invoice",
325
+ targetId: invoice.id,
326
+ bookingId: invoice.bookingId,
327
+ invoiceId: invoice.id,
328
+ paymentSessionId: latestSession?.id ?? null,
329
+ personId: invoice.personId ?? booking?.personId ?? null,
330
+ organizationId: invoice.organizationId ?? booking?.organizationId ?? null,
331
+ metadata: input.metadata ?? null,
332
+ scheduledFor: input.scheduledFor ?? null,
333
+ });
334
+ }
@@ -0,0 +1,4 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import type { NotificationService, ReminderSweepResult, RunDueRemindersInput } from "./service-shared.js";
3
+ export declare function runDueReminders(db: PostgresJsDatabase, dispatcher: NotificationService, input?: RunDueRemindersInput): Promise<ReminderSweepResult>;
4
+ //# sourceMappingURL=service-reminders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-reminders.d.ts","sourceRoot":"","sources":["../src/service-reminders.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAIjE,OAAO,KAAK,EAGV,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAoM5B,wBAAsB,eAAe,CACnC,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,mBAAmB,EAC/B,KAAK,GAAE,oBAAyB,gCA+CjC"}