@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,159 @@
1
+ import { bookingItems, bookingTravelers } from "@voyant-travel/bookings/schema";
2
+ import { and, desc, eq } from "drizzle-orm";
3
+ import { renderLiquidTemplate } from "./liquid.js";
4
+ import { enrichBookingItem, normalizeNotificationTemplateData } from "./service-template-data.js";
5
+ export { normalizeNotificationTemplateData } from "./service-template-data.js";
6
+ export class NotificationError extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = "NotificationError";
10
+ }
11
+ }
12
+ export function createNotificationService(providers) {
13
+ const byChannel = new Map();
14
+ const byName = new Map();
15
+ for (const provider of providers) {
16
+ byName.set(provider.name, provider);
17
+ for (const channel of provider.channels) {
18
+ byChannel.set(channel, provider);
19
+ }
20
+ }
21
+ return {
22
+ async send(payload) {
23
+ const hintedProvider = payload.provider ? byName.get(payload.provider) : null;
24
+ const provider = hintedProvider ?? byChannel.get(payload.channel);
25
+ if (!provider) {
26
+ throw new NotificationError(`No notification provider registered for channel "${payload.channel}"`);
27
+ }
28
+ return provider.send(payload);
29
+ },
30
+ async sendWith(providerName, payload) {
31
+ const provider = byName.get(providerName);
32
+ if (!provider) {
33
+ throw new NotificationError(`No notification provider registered with name "${providerName}"`);
34
+ }
35
+ return provider.send(payload);
36
+ },
37
+ getProvider(channel) {
38
+ return byChannel.get(channel);
39
+ },
40
+ getProviderByName(providerName) {
41
+ return byName.get(providerName);
42
+ },
43
+ };
44
+ }
45
+ export function summarizeNotificationAttachments(attachments) {
46
+ if (!attachments || attachments.length === 0) {
47
+ return [];
48
+ }
49
+ return attachments.map((attachment) => ({
50
+ filename: attachment.filename,
51
+ path: attachment.path ?? null,
52
+ contentType: attachment.contentType ?? null,
53
+ disposition: attachment.disposition ?? null,
54
+ contentId: attachment.contentId ?? null,
55
+ }));
56
+ }
57
+ export function renderNotificationTemplate(template, data) {
58
+ return renderLiquidTemplate(template, normalizeNotificationTemplateData(data));
59
+ }
60
+ export function previewNotificationTemplate(input) {
61
+ const data = normalizeNotificationTemplateData(input.data ?? {});
62
+ return {
63
+ channel: input.channel,
64
+ provider: input.provider ?? null,
65
+ fromAddress: input.fromAddress ?? null,
66
+ subject: renderNotificationTemplate(input.subjectTemplate, data),
67
+ html: renderNotificationTemplate(input.htmlTemplate, data),
68
+ text: renderNotificationTemplate(input.textTemplate, data),
69
+ };
70
+ }
71
+ export function toTimestamp(value) {
72
+ return value ? new Date(value) : null;
73
+ }
74
+ export function startOfUtcDay(value) {
75
+ return new Date(Date.UTC(value.getUTCFullYear(), value.getUTCMonth(), value.getUTCDate()));
76
+ }
77
+ export function addUtcDays(value, days) {
78
+ return new Date(value.getTime() + days * 24 * 60 * 60 * 1000);
79
+ }
80
+ export function toDateString(value) {
81
+ return value.toISOString().slice(0, 10);
82
+ }
83
+ export function buildReminderDedupeKey(ruleId, targetId, runDate) {
84
+ return `${ruleId}:${targetId}:${runDate}`;
85
+ }
86
+ export function resolveReminderRecipient(booking, participants) {
87
+ if (booking?.contactEmail) {
88
+ return {
89
+ email: booking.contactEmail,
90
+ firstName: booking.contactFirstName ?? "",
91
+ lastName: booking.contactLastName ?? "",
92
+ participantType: "booking_contact",
93
+ isPrimary: true,
94
+ };
95
+ }
96
+ const withEmail = participants.filter((traveler) => traveler.email);
97
+ if (withEmail.length === 0) {
98
+ return null;
99
+ }
100
+ const nonStaffWithEmail = withEmail.filter((traveler) => traveler.participantType !== "staff");
101
+ const primary = nonStaffWithEmail.find((traveler) => traveler.isPrimary) ??
102
+ withEmail.find((traveler) => traveler.isPrimary);
103
+ if (primary) {
104
+ return primary;
105
+ }
106
+ const preferredTypes = ["traveler", "occupant", "other"];
107
+ for (const type of preferredTypes) {
108
+ const match = nonStaffWithEmail.find((traveler) => traveler.participantType === type);
109
+ if (match) {
110
+ return match;
111
+ }
112
+ }
113
+ return nonStaffWithEmail[0] ?? withEmail[0] ?? null;
114
+ }
115
+ export async function listBookingNotificationParticipants(db, bookingId) {
116
+ return db
117
+ .select({
118
+ id: bookingTravelers.id,
119
+ firstName: bookingTravelers.firstName,
120
+ lastName: bookingTravelers.lastName,
121
+ email: bookingTravelers.email,
122
+ participantType: bookingTravelers.participantType,
123
+ isPrimary: bookingTravelers.isPrimary,
124
+ })
125
+ .from(bookingTravelers)
126
+ .where(eq(bookingTravelers.bookingId, bookingId))
127
+ .orderBy(desc(bookingTravelers.isPrimary), bookingTravelers.createdAt);
128
+ }
129
+ export async function listBookingNotificationItems(db, bookingId) {
130
+ const rows = await db
131
+ .select({
132
+ id: bookingItems.id,
133
+ title: bookingItems.title,
134
+ description: bookingItems.description,
135
+ quantity: bookingItems.quantity,
136
+ itemType: bookingItems.itemType,
137
+ serviceDate: bookingItems.serviceDate,
138
+ sellCurrency: bookingItems.sellCurrency,
139
+ unitSellAmountCents: bookingItems.unitSellAmountCents,
140
+ totalSellAmountCents: bookingItems.totalSellAmountCents,
141
+ })
142
+ .from(bookingItems)
143
+ .where(eq(bookingItems.bookingId, bookingId))
144
+ .orderBy(bookingItems.createdAt);
145
+ return rows.map((row) => enrichBookingItem(row));
146
+ }
147
+ export async function paginate(rowsPromise, totalPromise, limit, offset) {
148
+ const [data, totalRows] = await Promise.all([rowsPromise, totalPromise]);
149
+ return {
150
+ data,
151
+ total: totalRows[0]?.total ?? 0,
152
+ limit,
153
+ offset,
154
+ };
155
+ }
156
+ export function buildWhereClause(conditions) {
157
+ const filtered = conditions.filter((condition) => Boolean(condition));
158
+ return filtered.length > 0 ? and(...filtered) : undefined;
159
+ }
@@ -0,0 +1,23 @@
1
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
+ import type { z } from "zod";
3
+ import { type NotificationReminderRuleStage, type NotificationReminderStageChannel, type NotificationSettings } from "./schema.js";
4
+ import type { insertNotificationReminderRuleStageSchema, insertNotificationReminderStageChannelSchema, reorderReminderRuleStagesSchema, updateNotificationReminderRuleStageSchema, updateNotificationReminderStageChannelSchema, updateNotificationSettingsSchema } from "./validation.js";
5
+ export type CreateReminderRuleStageInput = z.infer<typeof insertNotificationReminderRuleStageSchema>;
6
+ export type UpdateReminderRuleStageInput = z.infer<typeof updateNotificationReminderRuleStageSchema>;
7
+ export type CreateReminderStageChannelInput = z.infer<typeof insertNotificationReminderStageChannelSchema>;
8
+ export type UpdateReminderStageChannelInput = z.infer<typeof updateNotificationReminderStageChannelSchema>;
9
+ export type ReorderReminderRuleStagesInput = z.infer<typeof reorderReminderRuleStagesSchema>;
10
+ export type UpdateNotificationSettingsInput = z.infer<typeof updateNotificationSettingsSchema>;
11
+ export declare function listReminderRuleStages(db: PostgresJsDatabase, reminderRuleId: string): Promise<NotificationReminderRuleStage[]>;
12
+ export declare function getReminderRuleStageById(db: PostgresJsDatabase, stageId: string): Promise<NotificationReminderRuleStage | null>;
13
+ export declare function createReminderRuleStage(db: PostgresJsDatabase, reminderRuleId: string, input: CreateReminderRuleStageInput): Promise<NotificationReminderRuleStage>;
14
+ export declare function updateReminderRuleStage(db: PostgresJsDatabase, stageId: string, input: UpdateReminderRuleStageInput): Promise<NotificationReminderRuleStage | null>;
15
+ export declare function deleteReminderRuleStage(db: PostgresJsDatabase, stageId: string): Promise<boolean>;
16
+ export declare function reorderReminderRuleStages(db: PostgresJsDatabase, reminderRuleId: string, input: ReorderReminderRuleStagesInput): Promise<NotificationReminderRuleStage[]>;
17
+ export declare function listStageChannels(db: PostgresJsDatabase, stageId: string): Promise<NotificationReminderStageChannel[]>;
18
+ export declare function createStageChannel(db: PostgresJsDatabase, stageId: string, input: CreateReminderStageChannelInput): Promise<NotificationReminderStageChannel>;
19
+ export declare function updateStageChannel(db: PostgresJsDatabase, channelId: string, input: UpdateReminderStageChannelInput): Promise<NotificationReminderStageChannel | null>;
20
+ export declare function deleteStageChannel(db: PostgresJsDatabase, channelId: string): Promise<boolean>;
21
+ export declare function getNotificationSettingsRecord(db: PostgresJsDatabase, scope?: string): Promise<NotificationSettings>;
22
+ export declare function upsertNotificationSettings(db: PostgresJsDatabase, input: UpdateNotificationSettingsInput): Promise<NotificationSettings>;
23
+ //# sourceMappingURL=service-stages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-stages.d.ts","sourceRoot":"","sources":["../src/service-stages.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ import { and, asc, eq } from "drizzle-orm";
2
+ import { notificationReminderRuleStages, notificationReminderStageChannels, notificationSettings, } from "./schema.js";
3
+ import { DEFAULT_NOTIFICATION_SETTINGS } from "./service-sequence.js";
4
+ export async function listReminderRuleStages(db, reminderRuleId) {
5
+ return db
6
+ .select()
7
+ .from(notificationReminderRuleStages)
8
+ .where(eq(notificationReminderRuleStages.reminderRuleId, reminderRuleId))
9
+ .orderBy(asc(notificationReminderRuleStages.orderIndex));
10
+ }
11
+ export async function getReminderRuleStageById(db, stageId) {
12
+ const [row] = await db
13
+ .select()
14
+ .from(notificationReminderRuleStages)
15
+ .where(eq(notificationReminderRuleStages.id, stageId))
16
+ .limit(1);
17
+ return row ?? null;
18
+ }
19
+ export async function createReminderRuleStage(db, reminderRuleId, input) {
20
+ const [row] = await db
21
+ .insert(notificationReminderRuleStages)
22
+ .values({
23
+ reminderRuleId,
24
+ orderIndex: input.orderIndex,
25
+ name: input.name ?? null,
26
+ anchor: input.anchor,
27
+ windowStartDays: input.windowStartDays,
28
+ windowEndDays: input.windowEndDays,
29
+ cadenceKind: input.cadenceKind,
30
+ cadenceEveryDays: input.cadenceEveryDays ?? null,
31
+ cadenceIntervals: input.cadenceIntervals ?? null,
32
+ maxSendsInStage: input.maxSendsInStage ?? null,
33
+ respectQuietHours: input.respectQuietHours,
34
+ metadata: input.metadata ?? null,
35
+ })
36
+ .returning();
37
+ if (!row)
38
+ throw new Error("Failed to create reminder stage");
39
+ return row;
40
+ }
41
+ export async function updateReminderRuleStage(db, stageId, input) {
42
+ const updates = { updatedAt: new Date() };
43
+ if (input.name !== undefined)
44
+ updates.name = input.name ?? null;
45
+ if (input.orderIndex !== undefined)
46
+ updates.orderIndex = input.orderIndex;
47
+ if (input.anchor !== undefined)
48
+ updates.anchor = input.anchor;
49
+ if (input.windowStartDays !== undefined)
50
+ updates.windowStartDays = input.windowStartDays;
51
+ if (input.windowEndDays !== undefined)
52
+ updates.windowEndDays = input.windowEndDays;
53
+ if (input.cadenceKind !== undefined)
54
+ updates.cadenceKind = input.cadenceKind;
55
+ if (input.cadenceEveryDays !== undefined)
56
+ updates.cadenceEveryDays = input.cadenceEveryDays ?? null;
57
+ if (input.cadenceIntervals !== undefined)
58
+ updates.cadenceIntervals = input.cadenceIntervals ?? null;
59
+ if (input.maxSendsInStage !== undefined)
60
+ updates.maxSendsInStage = input.maxSendsInStage ?? null;
61
+ if (input.respectQuietHours !== undefined)
62
+ updates.respectQuietHours = input.respectQuietHours;
63
+ if (input.metadata !== undefined)
64
+ updates.metadata = input.metadata ?? null;
65
+ const [row] = await db
66
+ .update(notificationReminderRuleStages)
67
+ .set(updates)
68
+ .where(eq(notificationReminderRuleStages.id, stageId))
69
+ .returning();
70
+ return row ?? null;
71
+ }
72
+ export async function deleteReminderRuleStage(db, stageId) {
73
+ const rows = await db
74
+ .delete(notificationReminderRuleStages)
75
+ .where(eq(notificationReminderRuleStages.id, stageId))
76
+ .returning({ id: notificationReminderRuleStages.id });
77
+ return rows.length > 0;
78
+ }
79
+ export async function reorderReminderRuleStages(db, reminderRuleId, input) {
80
+ const now = new Date();
81
+ await db.transaction(async (tx) => {
82
+ for (let i = 0; i < input.stageIds.length; i += 1) {
83
+ const stageId = input.stageIds[i];
84
+ await tx
85
+ .update(notificationReminderRuleStages)
86
+ .set({ orderIndex: i, updatedAt: now })
87
+ .where(and(eq(notificationReminderRuleStages.id, stageId), eq(notificationReminderRuleStages.reminderRuleId, reminderRuleId)));
88
+ }
89
+ });
90
+ return listReminderRuleStages(db, reminderRuleId);
91
+ }
92
+ export async function listStageChannels(db, stageId) {
93
+ return db
94
+ .select()
95
+ .from(notificationReminderStageChannels)
96
+ .where(eq(notificationReminderStageChannels.stageId, stageId))
97
+ .orderBy(asc(notificationReminderStageChannels.orderIndex), asc(notificationReminderStageChannels.createdAt));
98
+ }
99
+ export async function createStageChannel(db, stageId, input) {
100
+ const [row] = await db
101
+ .insert(notificationReminderStageChannels)
102
+ .values({
103
+ stageId,
104
+ orderIndex: input.orderIndex,
105
+ channel: input.channel,
106
+ provider: input.provider ?? null,
107
+ templateId: input.templateId ?? null,
108
+ templateSlug: input.templateSlug ?? null,
109
+ recipientKind: input.recipientKind,
110
+ recipientRole: input.recipientRole ?? null,
111
+ metadata: input.metadata ?? null,
112
+ })
113
+ .returning();
114
+ if (!row)
115
+ throw new Error("Failed to create stage channel");
116
+ return row;
117
+ }
118
+ export async function updateStageChannel(db, channelId, input) {
119
+ const updates = { updatedAt: new Date() };
120
+ if (input.orderIndex !== undefined)
121
+ updates.orderIndex = input.orderIndex;
122
+ if (input.channel !== undefined)
123
+ updates.channel = input.channel;
124
+ if (input.provider !== undefined)
125
+ updates.provider = input.provider ?? null;
126
+ if (input.templateId !== undefined)
127
+ updates.templateId = input.templateId ?? null;
128
+ if (input.templateSlug !== undefined)
129
+ updates.templateSlug = input.templateSlug ?? null;
130
+ if (input.recipientKind !== undefined)
131
+ updates.recipientKind = input.recipientKind;
132
+ if (input.recipientRole !== undefined)
133
+ updates.recipientRole = input.recipientRole ?? null;
134
+ if (input.metadata !== undefined)
135
+ updates.metadata = input.metadata ?? null;
136
+ const [row] = await db
137
+ .update(notificationReminderStageChannels)
138
+ .set(updates)
139
+ .where(eq(notificationReminderStageChannels.id, channelId))
140
+ .returning();
141
+ return row ?? null;
142
+ }
143
+ export async function deleteStageChannel(db, channelId) {
144
+ const rows = await db
145
+ .delete(notificationReminderStageChannels)
146
+ .where(eq(notificationReminderStageChannels.id, channelId))
147
+ .returning({ id: notificationReminderStageChannels.id });
148
+ return rows.length > 0;
149
+ }
150
+ export async function getNotificationSettingsRecord(db, scope = "default") {
151
+ const [row] = await db
152
+ .select()
153
+ .from(notificationSettings)
154
+ .where(eq(notificationSettings.scope, scope))
155
+ .limit(1);
156
+ return row ?? { ...DEFAULT_NOTIFICATION_SETTINGS, scope };
157
+ }
158
+ export async function upsertNotificationSettings(db, input) {
159
+ const scope = input.scope ?? "default";
160
+ const existing = await db
161
+ .select()
162
+ .from(notificationSettings)
163
+ .where(eq(notificationSettings.scope, scope))
164
+ .limit(1);
165
+ const updates = { updatedAt: new Date() };
166
+ if (input.quietHoursLocal !== undefined)
167
+ updates.quietHoursLocal = input.quietHoursLocal ?? null;
168
+ if (input.blackoutDates !== undefined)
169
+ updates.blackoutDates = input.blackoutDates ?? null;
170
+ if (input.skipWeekends !== undefined)
171
+ updates.skipWeekends = input.skipWeekends;
172
+ if (input.recipientRateLimitPerDay !== undefined)
173
+ updates.recipientRateLimitPerDay = input.recipientRateLimitPerDay ?? null;
174
+ if (input.suppressionWindowHours !== undefined)
175
+ updates.suppressionWindowHours = input.suppressionWindowHours;
176
+ if (input.metadata !== undefined)
177
+ updates.metadata = input.metadata ?? null;
178
+ if (existing[0]) {
179
+ const [row] = await db
180
+ .update(notificationSettings)
181
+ .set(updates)
182
+ .where(eq(notificationSettings.scope, scope))
183
+ .returning();
184
+ if (!row)
185
+ throw new Error("Failed to update notification settings");
186
+ return row;
187
+ }
188
+ const [row] = await db
189
+ .insert(notificationSettings)
190
+ .values({
191
+ scope,
192
+ quietHoursLocal: input.quietHoursLocal ?? null,
193
+ blackoutDates: input.blackoutDates ?? null,
194
+ skipWeekends: input.skipWeekends ?? false,
195
+ recipientRateLimitPerDay: input.recipientRateLimitPerDay ?? null,
196
+ suppressionWindowHours: input.suppressionWindowHours ?? 24,
197
+ metadata: input.metadata ?? null,
198
+ })
199
+ .returning();
200
+ if (!row)
201
+ throw new Error("Failed to create notification settings");
202
+ return row;
203
+ }
@@ -0,0 +1,19 @@
1
+ export declare function enrichBookingItem(value: unknown): unknown;
2
+ export declare function normalizeNotificationTemplateData(data: Record<string, unknown>): {
3
+ traveler: unknown;
4
+ travelers: unknown[];
5
+ billingPerson: unknown;
6
+ billing: unknown;
7
+ booking: unknown;
8
+ invoice: unknown;
9
+ paymentSession: unknown;
10
+ paymentSchedule: unknown;
11
+ payment: Record<string, unknown> | null;
12
+ documents: unknown[];
13
+ documentsCount: number;
14
+ items: unknown[];
15
+ product: {
16
+ title: {} | null;
17
+ } | null;
18
+ };
19
+ //# sourceMappingURL=service-template-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-template-data.d.ts","sourceRoot":"","sources":["../src/service-template-data.ts"],"names":[],"mappings":"AAiLA,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,WAwB/C;AAED,wBAAgB,iCAAiC,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;;EA2G9E"}