@voyant-travel/notifications 0.111.7

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 (96) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +179 -0
  3. package/dist/index.d.ts +61 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +196 -0
  6. package/dist/liquid.d.ts +5 -0
  7. package/dist/liquid.d.ts.map +1 -0
  8. package/dist/liquid.js +156 -0
  9. package/dist/providers/local.d.ts +22 -0
  10. package/dist/providers/local.d.ts.map +1 -0
  11. package/dist/providers/local.js +23 -0
  12. package/dist/providers/voyant-cloud-email.d.ts +27 -0
  13. package/dist/providers/voyant-cloud-email.d.ts.map +1 -0
  14. package/dist/providers/voyant-cloud-email.js +73 -0
  15. package/dist/providers/voyant-cloud-sms.d.ts +26 -0
  16. package/dist/providers/voyant-cloud-sms.d.ts.map +1 -0
  17. package/dist/providers/voyant-cloud-sms.js +24 -0
  18. package/dist/routes.d.ts +1546 -0
  19. package/dist/routes.d.ts.map +1 -0
  20. package/dist/routes.js +337 -0
  21. package/dist/schema.d.ts +2119 -0
  22. package/dist/schema.d.ts.map +1 -0
  23. package/dist/schema.js +356 -0
  24. package/dist/service-booking-document-lifecycle.d.ts +99 -0
  25. package/dist/service-booking-document-lifecycle.d.ts.map +1 -0
  26. package/dist/service-booking-document-lifecycle.js +259 -0
  27. package/dist/service-booking-documents.d.ts +256 -0
  28. package/dist/service-booking-documents.d.ts.map +1 -0
  29. package/dist/service-booking-documents.js +323 -0
  30. package/dist/service-deliveries.d.ts +183 -0
  31. package/dist/service-deliveries.d.ts.map +1 -0
  32. package/dist/service-deliveries.js +413 -0
  33. package/dist/service-delivery-metadata.d.ts +42 -0
  34. package/dist/service-delivery-metadata.d.ts.map +1 -0
  35. package/dist/service-delivery-metadata.js +114 -0
  36. package/dist/service-reminder-authoring.d.ts +33 -0
  37. package/dist/service-reminder-authoring.d.ts.map +1 -0
  38. package/dist/service-reminder-authoring.js +247 -0
  39. package/dist/service-reminder-booking-context.d.ts +94 -0
  40. package/dist/service-reminder-booking-context.d.ts.map +1 -0
  41. package/dist/service-reminder-booking-context.js +164 -0
  42. package/dist/service-reminder-events.d.ts +33 -0
  43. package/dist/service-reminder-events.d.ts.map +1 -0
  44. package/dist/service-reminder-events.js +178 -0
  45. package/dist/service-reminder-run-state.d.ts +114 -0
  46. package/dist/service-reminder-run-state.d.ts.map +1 -0
  47. package/dist/service-reminder-run-state.js +100 -0
  48. package/dist/service-reminder-stage-runs.d.ts +6 -0
  49. package/dist/service-reminder-stage-runs.d.ts.map +1 -0
  50. package/dist/service-reminder-stage-runs.js +310 -0
  51. package/dist/service-reminders.d.ts +30 -0
  52. package/dist/service-reminders.d.ts.map +1 -0
  53. package/dist/service-reminders.js +189 -0
  54. package/dist/service-sequence-targets.d.ts +50 -0
  55. package/dist/service-sequence-targets.d.ts.map +1 -0
  56. package/dist/service-sequence-targets.js +136 -0
  57. package/dist/service-sequence.d.ts +68 -0
  58. package/dist/service-sequence.d.ts.map +1 -0
  59. package/dist/service-sequence.js +316 -0
  60. package/dist/service-shared.d.ts +107 -0
  61. package/dist/service-shared.d.ts.map +1 -0
  62. package/dist/service-shared.js +159 -0
  63. package/dist/service-stages.d.ts +23 -0
  64. package/dist/service-stages.d.ts.map +1 -0
  65. package/dist/service-stages.js +203 -0
  66. package/dist/service-template-data.d.ts +19 -0
  67. package/dist/service-template-data.d.ts.map +1 -0
  68. package/dist/service-template-data.js +278 -0
  69. package/dist/service-templates.d.ts +260 -0
  70. package/dist/service-templates.d.ts.map +1 -0
  71. package/dist/service-templates.js +293 -0
  72. package/dist/service.d.ts +273 -0
  73. package/dist/service.d.ts.map +1 -0
  74. package/dist/service.js +51 -0
  75. package/dist/task-runtime.d.ts +19 -0
  76. package/dist/task-runtime.d.ts.map +1 -0
  77. package/dist/task-runtime.js +11 -0
  78. package/dist/tasks/deliver-reminder.d.ts +9 -0
  79. package/dist/tasks/deliver-reminder.d.ts.map +1 -0
  80. package/dist/tasks/deliver-reminder.js +12 -0
  81. package/dist/tasks/index.d.ts +3 -0
  82. package/dist/tasks/index.d.ts.map +1 -0
  83. package/dist/tasks/index.js +2 -0
  84. package/dist/tasks/send-due-reminders.d.ts +7 -0
  85. package/dist/tasks/send-due-reminders.d.ts.map +1 -0
  86. package/dist/tasks/send-due-reminders.js +31 -0
  87. package/dist/template-authoring.d.ts +23 -0
  88. package/dist/template-authoring.d.ts.map +1 -0
  89. package/dist/template-authoring.js +386 -0
  90. package/dist/types.d.ts +82 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +1 -0
  93. package/dist/validation.d.ts +1093 -0
  94. package/dist/validation.d.ts.map +1 -0
  95. package/dist/validation.js +451 -0
  96. package/package.json +102 -0
@@ -0,0 +1,178 @@
1
+ import { bookings, bookingTravelers } from "@voyant-travel/bookings/schema";
2
+ import { and, desc, eq } from "drizzle-orm";
3
+ import { notificationReminderRules, notificationReminderRuns } from "./schema.js";
4
+ import { sendNotification } from "./service-deliveries.js";
5
+ import { getBookingEventDocumentContext, getBookingPaymentNotificationContext, hasOutstandingBookingBalance, serializeBookingPaymentContext, } from "./service-reminder-booking-context.js";
6
+ import { markReminderRunFailed, markReminderRunSent, markReminderRunSkipped, } from "./service-reminder-run-state.js";
7
+ import { buildReminderDedupeKey, listBookingNotificationItems, resolveReminderRecipient, } from "./service-shared.js";
8
+ async function sendBookingEventReminder(db, dispatcher, rule, input, runtime = {}) {
9
+ const now = new Date();
10
+ const dedupeKey = buildReminderDedupeKey(rule.id, input.bookingId, input.targetType);
11
+ const [existingRun] = await db
12
+ .select({ id: notificationReminderRuns.id })
13
+ .from(notificationReminderRuns)
14
+ .where(eq(notificationReminderRuns.dedupeKey, dedupeKey))
15
+ .limit(1);
16
+ if (existingRun) {
17
+ return null;
18
+ }
19
+ const [booking] = await db
20
+ .select()
21
+ .from(bookings)
22
+ .where(eq(bookings.id, input.bookingId))
23
+ .limit(1);
24
+ if (!booking) {
25
+ const [run] = await db
26
+ .insert(notificationReminderRuns)
27
+ .values({
28
+ reminderRuleId: rule.id,
29
+ targetType: input.targetType,
30
+ targetId: input.bookingId,
31
+ dedupeKey,
32
+ bookingId: input.bookingId,
33
+ personId: null,
34
+ organizationId: null,
35
+ paymentSessionId: input.paymentSessionId ?? null,
36
+ notificationDeliveryId: null,
37
+ status: "skipped",
38
+ recipient: null,
39
+ scheduledFor: now,
40
+ processedAt: now,
41
+ errorMessage: "Booking not found for notification event",
42
+ metadata: {
43
+ eventTargetType: input.targetType,
44
+ ...(input.eventData ?? {}),
45
+ },
46
+ })
47
+ .returning();
48
+ return run ?? null;
49
+ }
50
+ const [participants, items, paymentContext, documentContext] = await Promise.all([
51
+ db
52
+ .select({
53
+ id: bookingTravelers.id,
54
+ firstName: bookingTravelers.firstName,
55
+ lastName: bookingTravelers.lastName,
56
+ email: bookingTravelers.email,
57
+ participantType: bookingTravelers.participantType,
58
+ isPrimary: bookingTravelers.isPrimary,
59
+ })
60
+ .from(bookingTravelers)
61
+ .where(eq(bookingTravelers.bookingId, booking.id))
62
+ .orderBy(desc(bookingTravelers.isPrimary), bookingTravelers.createdAt),
63
+ listBookingNotificationItems(db, booking.id),
64
+ getBookingPaymentNotificationContext(db, booking.id),
65
+ input.targetType === "booking_confirmed" && rule.channel === "email"
66
+ ? getBookingEventDocumentContext(db, booking.id, runtime.documentAttachmentResolver)
67
+ : Promise.resolve({ documents: [], attachments: [] }),
68
+ ]);
69
+ const recipient = resolveReminderRecipient(booking, participants);
70
+ const [processingRun] = await db
71
+ .insert(notificationReminderRuns)
72
+ .values({
73
+ reminderRuleId: rule.id,
74
+ targetType: input.targetType,
75
+ targetId: booking.id,
76
+ dedupeKey,
77
+ bookingId: booking.id,
78
+ personId: booking.personId ?? null,
79
+ organizationId: booking.organizationId ?? null,
80
+ paymentSessionId: input.paymentSessionId ?? null,
81
+ notificationDeliveryId: null,
82
+ status: "processing",
83
+ recipient: recipient?.email ?? null,
84
+ scheduledFor: now,
85
+ processedAt: now,
86
+ errorMessage: null,
87
+ metadata: {
88
+ eventTargetType: input.targetType,
89
+ bookingNumber: booking.bookingNumber,
90
+ ...(input.eventData ?? {}),
91
+ },
92
+ })
93
+ .onConflictDoNothing({ target: notificationReminderRuns.dedupeKey })
94
+ .returning();
95
+ if (!processingRun) {
96
+ return null;
97
+ }
98
+ if (!recipient?.email) {
99
+ return markReminderRunSkipped(db, processingRun.id, now, "No traveler email available for booking notification event");
100
+ }
101
+ try {
102
+ const delivery = await sendNotification(db, dispatcher, {
103
+ templateId: rule.templateId ?? null,
104
+ templateSlug: rule.templateSlug ?? null,
105
+ channel: rule.channel,
106
+ provider: rule.provider ?? null,
107
+ to: recipient.email,
108
+ data: {
109
+ bookingId: booking.id,
110
+ bookingNumber: booking.bookingNumber,
111
+ trigger: input.targetType,
112
+ event: input.eventData ?? {},
113
+ traveler: {
114
+ firstName: recipient.firstName,
115
+ lastName: recipient.lastName,
116
+ email: recipient.email,
117
+ participantType: recipient.participantType,
118
+ isPrimary: recipient.isPrimary,
119
+ },
120
+ travelers: participants,
121
+ booking: {
122
+ id: booking.id,
123
+ bookingNumber: booking.bookingNumber,
124
+ status: booking.status,
125
+ startDate: booking.startDate,
126
+ endDate: booking.endDate,
127
+ sellCurrency: booking.sellCurrency,
128
+ sellAmountCents: booking.sellAmountCents,
129
+ },
130
+ ...serializeBookingPaymentContext(paymentContext),
131
+ payment: input.targetType === "payment_complete"
132
+ ? {
133
+ isPaidInFull: true,
134
+ paymentSessionId: input.paymentSessionId ?? null,
135
+ }
136
+ : null,
137
+ documents: documentContext.documents,
138
+ items,
139
+ },
140
+ attachments: documentContext.attachments.length > 0 ? documentContext.attachments : null,
141
+ targetType: input.targetType === "payment_complete" ? "payment_session" : "booking",
142
+ targetId: input.targetType === "payment_complete"
143
+ ? (input.paymentSessionId ?? booking.id)
144
+ : booking.id,
145
+ bookingId: booking.id,
146
+ paymentSessionId: input.paymentSessionId ?? null,
147
+ personId: booking.personId ?? null,
148
+ organizationId: booking.organizationId ?? null,
149
+ metadata: {
150
+ reminderRuleId: rule.id,
151
+ reminderRunId: processingRun.id,
152
+ eventTargetType: input.targetType,
153
+ bookingDocumentKeys: documentContext.documents.map((document) => document.key),
154
+ },
155
+ scheduledFor: now.toISOString(),
156
+ });
157
+ return markReminderRunSent(db, processingRun.id, new Date(), delivery?.id ?? null);
158
+ }
159
+ catch (error) {
160
+ const message = error instanceof Error ? error.message : "Notification event delivery failed";
161
+ return markReminderRunFailed(db, processingRun.id, new Date(), message);
162
+ }
163
+ }
164
+ export async function dispatchReminderEventRules(db, dispatcher, input, runtime = {}) {
165
+ const rules = await db
166
+ .select()
167
+ .from(notificationReminderRules)
168
+ .where(and(eq(notificationReminderRules.status, "active"), eq(notificationReminderRules.targetType, input.targetType)))
169
+ .orderBy(notificationReminderRules.createdAt);
170
+ const results = [];
171
+ for (const rule of rules) {
172
+ results.push(await sendBookingEventReminder(db, dispatcher, rule, input, runtime));
173
+ }
174
+ return results;
175
+ }
176
+ export async function bookingIsPaidInFullForNotification(db, bookingId) {
177
+ return !(await hasOutstandingBookingBalance(db, bookingId));
178
+ }
@@ -0,0 +1,114 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import { notificationReminderRuns } from "./schema.js";
3
+ import type { NotificationReminderRuleRow, ReminderQueueResult, ReminderSweepResult } from "./service-shared.js";
4
+ export type ReminderDeliveryEnqueuer = (input: {
5
+ reminderRunId: string;
6
+ }) => Promise<void>;
7
+ export type NotificationReminderRunRow = typeof notificationReminderRuns.$inferSelect;
8
+ export declare function buildReminderSweepSummary(): ReminderSweepResult;
9
+ export declare function buildReminderQueueSummary(): ReminderQueueResult;
10
+ export declare function getReminderRuleById(db: PostgresJsDatabase, reminderRuleId: string): Promise<{
11
+ id: string;
12
+ slug: string;
13
+ name: string;
14
+ status: "draft" | "active" | "archived";
15
+ targetType: "invoice" | "booking_payment_schedule" | "booking_confirmed" | "payment_complete" | "booking_cancelled_non_payment";
16
+ channel: "email" | "sms";
17
+ provider: string | null;
18
+ templateId: string | null;
19
+ templateSlug: string | null;
20
+ priority: number;
21
+ suppressionGroup: string | null;
22
+ isSystem: boolean;
23
+ metadata: Record<string, unknown> | null;
24
+ createdAt: Date;
25
+ updatedAt: Date;
26
+ } | null>;
27
+ export declare function getReminderRunById(db: PostgresJsDatabase, reminderRunId: string): Promise<{
28
+ id: string;
29
+ reminderRuleId: string;
30
+ targetType: "invoice" | "booking_payment_schedule" | "booking_confirmed" | "payment_complete" | "booking_cancelled_non_payment";
31
+ targetId: string;
32
+ dedupeKey: string;
33
+ bookingId: string | null;
34
+ personId: string | null;
35
+ organizationId: string | null;
36
+ paymentSessionId: string | null;
37
+ notificationDeliveryId: string | null;
38
+ status: "sent" | "failed" | "queued" | "processing" | "skipped";
39
+ recipient: string | null;
40
+ scheduledFor: Date;
41
+ processedAt: Date;
42
+ errorMessage: string | null;
43
+ metadata: Record<string, unknown> | null;
44
+ createdAt: Date;
45
+ updatedAt: Date;
46
+ } | null>;
47
+ export declare function markReminderRunSkipped(db: PostgresJsDatabase, reminderRunId: string, now: Date, errorMessage: string): Promise<{
48
+ id: string;
49
+ reminderRuleId: string;
50
+ targetType: "invoice" | "booking_payment_schedule" | "booking_confirmed" | "payment_complete" | "booking_cancelled_non_payment";
51
+ targetId: string;
52
+ dedupeKey: string;
53
+ bookingId: string | null;
54
+ personId: string | null;
55
+ organizationId: string | null;
56
+ paymentSessionId: string | null;
57
+ notificationDeliveryId: string | null;
58
+ status: "sent" | "failed" | "queued" | "processing" | "skipped";
59
+ recipient: string | null;
60
+ scheduledFor: Date;
61
+ processedAt: Date;
62
+ errorMessage: string | null;
63
+ metadata: Record<string, unknown> | null;
64
+ createdAt: Date;
65
+ updatedAt: Date;
66
+ } | null>;
67
+ export declare function markReminderRunFailed(db: PostgresJsDatabase, reminderRunId: string, now: Date, errorMessage: string): Promise<{
68
+ id: string;
69
+ reminderRuleId: string;
70
+ targetType: "invoice" | "booking_payment_schedule" | "booking_confirmed" | "payment_complete" | "booking_cancelled_non_payment";
71
+ targetId: string;
72
+ dedupeKey: string;
73
+ bookingId: string | null;
74
+ personId: string | null;
75
+ organizationId: string | null;
76
+ paymentSessionId: string | null;
77
+ notificationDeliveryId: string | null;
78
+ status: "sent" | "failed" | "queued" | "processing" | "skipped";
79
+ recipient: string | null;
80
+ scheduledFor: Date;
81
+ processedAt: Date;
82
+ errorMessage: string | null;
83
+ metadata: Record<string, unknown> | null;
84
+ createdAt: Date;
85
+ updatedAt: Date;
86
+ } | null>;
87
+ export declare function markReminderRunSent(db: PostgresJsDatabase, reminderRunId: string, now: Date, notificationDeliveryId: string | null): Promise<{
88
+ id: string;
89
+ reminderRuleId: string;
90
+ targetType: "invoice" | "booking_payment_schedule" | "booking_confirmed" | "payment_complete" | "booking_cancelled_non_payment";
91
+ targetId: string;
92
+ dedupeKey: string;
93
+ bookingId: string | null;
94
+ personId: string | null;
95
+ organizationId: string | null;
96
+ paymentSessionId: string | null;
97
+ notificationDeliveryId: string | null;
98
+ status: "sent" | "failed" | "queued" | "processing" | "skipped";
99
+ recipient: string | null;
100
+ scheduledFor: Date;
101
+ processedAt: Date;
102
+ errorMessage: string | null;
103
+ metadata: Record<string, unknown> | null;
104
+ createdAt: Date;
105
+ updatedAt: Date;
106
+ } | null>;
107
+ export type ChannelOverride = {
108
+ channel: "email" | "sms";
109
+ templateId: string | null;
110
+ templateSlug: string | null;
111
+ provider: string | null;
112
+ };
113
+ export declare function resolveChannelOverride(db: PostgresJsDatabase, run: NotificationReminderRunRow, rule: NotificationReminderRuleRow): Promise<ChannelOverride>;
114
+ //# sourceMappingURL=service-reminder-run-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-reminder-run-state.d.ts","sourceRoot":"","sources":["../src/service-reminder-run-state.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,EAEL,wBAAwB,EAEzB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EACV,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAA;AAE5B,MAAM,MAAM,wBAAwB,GAAG,CAAC,KAAK,EAAE;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1F,MAAM,MAAM,0BAA0B,GAAG,OAAO,wBAAwB,CAAC,YAAY,CAAA;AAErF,wBAAgB,yBAAyB,IAAI,mBAAmB,CAO/D;AAED,wBAAgB,yBAAyB,IAAI,mBAAmB,CAO/D;AAED,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM;;;;;;;;;;;;;;;;UAOvF;AAED,wBAAsB,kBAAkB,CAAC,EAAE,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM;;;;;;;;;;;;;;;;;;;UAOrF;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,kBAAkB,EACtB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,IAAI,EACT,YAAY,EAAE,MAAM;;;;;;;;;;;;;;;;;;;UAcrB;AAED,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,kBAAkB,EACtB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,IAAI,EACT,YAAY,EAAE,MAAM;;;;;;;;;;;;;;;;;;;UAcrB;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,kBAAkB,EACtB,aAAa,EAAE,MAAM,EACrB,GAAG,EAAE,IAAI,EACT,sBAAsB,EAAE,MAAM,GAAG,IAAI;;;;;;;;;;;;;;;;;;;UAetC;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,OAAO,GAAG,KAAK,CAAA;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,kBAAkB,EACtB,GAAG,EAAE,0BAA0B,EAC/B,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,eAAe,CAAC,CA0B1B"}
@@ -0,0 +1,100 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { notificationReminderRules, notificationReminderRuns, notificationReminderStageChannels, } from "./schema.js";
3
+ export function buildReminderSweepSummary() {
4
+ return {
5
+ processed: 0,
6
+ sent: 0,
7
+ skipped: 0,
8
+ failed: 0,
9
+ };
10
+ }
11
+ export function buildReminderQueueSummary() {
12
+ return {
13
+ processed: 0,
14
+ queued: 0,
15
+ skipped: 0,
16
+ failed: 0,
17
+ };
18
+ }
19
+ export async function getReminderRuleById(db, reminderRuleId) {
20
+ const [rule] = await db
21
+ .select()
22
+ .from(notificationReminderRules)
23
+ .where(eq(notificationReminderRules.id, reminderRuleId))
24
+ .limit(1);
25
+ return rule ?? null;
26
+ }
27
+ export async function getReminderRunById(db, reminderRunId) {
28
+ const [run] = await db
29
+ .select()
30
+ .from(notificationReminderRuns)
31
+ .where(eq(notificationReminderRuns.id, reminderRunId))
32
+ .limit(1);
33
+ return run ?? null;
34
+ }
35
+ export async function markReminderRunSkipped(db, reminderRunId, now, errorMessage) {
36
+ const [run] = await db
37
+ .update(notificationReminderRuns)
38
+ .set({
39
+ status: "skipped",
40
+ errorMessage,
41
+ processedAt: now,
42
+ updatedAt: now,
43
+ })
44
+ .where(eq(notificationReminderRuns.id, reminderRunId))
45
+ .returning();
46
+ return run ?? null;
47
+ }
48
+ export async function markReminderRunFailed(db, reminderRunId, now, errorMessage) {
49
+ const [run] = await db
50
+ .update(notificationReminderRuns)
51
+ .set({
52
+ status: "failed",
53
+ errorMessage,
54
+ processedAt: now,
55
+ updatedAt: now,
56
+ })
57
+ .where(eq(notificationReminderRuns.id, reminderRunId))
58
+ .returning();
59
+ return run ?? null;
60
+ }
61
+ export async function markReminderRunSent(db, reminderRunId, now, notificationDeliveryId) {
62
+ const [run] = await db
63
+ .update(notificationReminderRuns)
64
+ .set({
65
+ notificationDeliveryId,
66
+ status: "sent",
67
+ processedAt: now,
68
+ updatedAt: now,
69
+ errorMessage: null,
70
+ })
71
+ .where(eq(notificationReminderRuns.id, reminderRunId))
72
+ .returning();
73
+ return run ?? null;
74
+ }
75
+ export async function resolveChannelOverride(db, run, rule) {
76
+ const stageChannelId = run.metadata && typeof run.metadata === "object"
77
+ ? run.metadata.stageChannelId
78
+ : undefined;
79
+ if (stageChannelId) {
80
+ const [stageChannel] = await db
81
+ .select()
82
+ .from(notificationReminderStageChannels)
83
+ .where(eq(notificationReminderStageChannels.id, stageChannelId))
84
+ .limit(1);
85
+ if (stageChannel) {
86
+ return {
87
+ channel: stageChannel.channel,
88
+ templateId: stageChannel.templateId ?? null,
89
+ templateSlug: stageChannel.templateSlug ?? null,
90
+ provider: stageChannel.provider ?? null,
91
+ };
92
+ }
93
+ }
94
+ return {
95
+ channel: rule.channel,
96
+ templateId: rule.templateId ?? null,
97
+ templateSlug: rule.templateSlug ?? null,
98
+ provider: rule.provider ?? null,
99
+ };
100
+ }
@@ -0,0 +1,6 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import { type ReminderDeliveryEnqueuer } from "./service-reminder-run-state.js";
3
+ import type { NotificationService, ReminderQueueResult, ReminderSweepResult, RunDueRemindersInput } from "./service-shared.js";
4
+ export declare function runStageBasedDueReminders(db: PostgresJsDatabase, dispatcher: NotificationService, input?: RunDueRemindersInput): Promise<ReminderSweepResult>;
5
+ export declare function queueStageBasedDueReminders(db: PostgresJsDatabase, enqueueDelivery: ReminderDeliveryEnqueuer, input?: RunDueRemindersInput): Promise<ReminderQueueResult>;
6
+ //# sourceMappingURL=service-reminder-stage-runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-reminder-stage-runs.d.ts","sourceRoot":"","sources":["../src/service-reminder-stage-runs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAcjE,OAAO,EAML,KAAK,wBAAwB,EAC9B,MAAM,iCAAiC,CAAA;AAcxC,OAAO,KAAK,EAEV,mBAAmB,EACnB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,qBAAqB,CAAA;AAsV5B,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,kBAAkB,EACtB,UAAU,EAAE,mBAAmB,EAC/B,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CA6B9B;AAED,wBAAsB,2BAA2B,CAC/C,EAAE,EAAE,kBAAkB,EACtB,eAAe,EAAE,wBAAwB,EACzC,KAAK,GAAE,oBAAyB,GAC/B,OAAO,CAAC,mBAAmB,CAAC,CA6B9B"}