@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 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"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"}
package/dist/routes.js ADDED
@@ -0,0 +1,337 @@
1
+ import { parseJsonBody, parseOptionalJsonBody, parseQuery } from "@voyant-travel/hono";
2
+ import { Hono } from "hono";
3
+ import { createNotificationService, notificationsService } from "./service.js";
4
+ import { bookingDocumentBundleSchema, composeNotificationReminderRuleSchema, confirmAndDispatchBookingResultSchema, confirmAndDispatchBookingSchema, insertNotificationReminderRuleSchema, insertNotificationReminderRuleStageSchema, insertNotificationReminderStageChannelSchema, insertNotificationTemplateSchema, notificationDeliveryListQuerySchema, notificationReminderRuleListQuerySchema, notificationReminderRunListQuerySchema, notificationTemplateListQuerySchema, previewNotificationTemplateResultSchema, previewNotificationTemplateSchema, previewRemindersQuerySchema, reorderReminderRuleStagesSchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationReminderRuleStageSchema, updateNotificationReminderStageChannelSchema, updateNotificationSettingsSchema, updateNotificationTemplateSchema, } from "./validation.js";
5
+ export const NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY = "providers.notifications.runtime";
6
+ export function buildNotificationsRouteRuntime(bindings, options) {
7
+ return {
8
+ providers: options?.resolveProviders?.(bindings) ?? options?.providers ?? [],
9
+ publicCheckoutBaseUrl: options?.resolvePublicCheckoutBaseUrl?.(bindings) ?? options?.publicCheckoutBaseUrl ?? null,
10
+ documentAttachmentResolver: options?.resolveDocumentAttachmentResolver?.(bindings) ?? options?.documentAttachmentResolver,
11
+ eventBus: options?.resolveEventBus?.(bindings) ?? options?.eventBus,
12
+ };
13
+ }
14
+ function getRuntime(bindings, options, resolveFromContainer) {
15
+ try {
16
+ return resolveFromContainer(NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY);
17
+ }
18
+ catch {
19
+ return buildNotificationsRouteRuntime(bindings, options);
20
+ }
21
+ }
22
+ function idempotencyKey(c, bodyKey) {
23
+ return c.req.header("Idempotency-Key") ?? bodyKey;
24
+ }
25
+ export function createNotificationsRoutes(options) {
26
+ return new Hono()
27
+ .get("/templates", async (c) => {
28
+ const query = parseQuery(c, notificationTemplateListQuerySchema);
29
+ return c.json(await notificationsService.listTemplates(c.get("db"), query));
30
+ })
31
+ .post("/templates", async (c) => {
32
+ const row = await notificationsService.createTemplate(c.get("db"), await parseJsonBody(c, insertNotificationTemplateSchema));
33
+ return c.json({ data: row }, 201);
34
+ })
35
+ .get("/templates/:id", async (c) => {
36
+ const row = await notificationsService.getTemplateById(c.get("db"), c.req.param("id"));
37
+ if (!row)
38
+ return c.json({ error: "Notification template not found" }, 404);
39
+ return c.json({ data: row });
40
+ })
41
+ .patch("/templates/:id", async (c) => {
42
+ const row = await notificationsService.updateTemplate(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateNotificationTemplateSchema));
43
+ if (!row)
44
+ return c.json({ error: "Notification template not found" }, 404);
45
+ return c.json({ data: row });
46
+ })
47
+ .delete("/templates/:id", async (c) => {
48
+ const ok = await notificationsService.deleteTemplate(c.get("db"), c.req.param("id"));
49
+ if (!ok)
50
+ return c.json({ error: "Notification template not found" }, 404);
51
+ return c.body(null, 204);
52
+ })
53
+ .post("/preview", async (c) => {
54
+ const rendered = notificationsService.previewNotificationTemplate(await parseJsonBody(c, previewNotificationTemplateSchema));
55
+ return c.json({ data: previewNotificationTemplateResultSchema.parse(rendered) });
56
+ })
57
+ .get("/deliveries", async (c) => {
58
+ const query = parseQuery(c, notificationDeliveryListQuerySchema);
59
+ return c.json(await notificationsService.listDeliveries(c.get("db"), query));
60
+ })
61
+ .get("/deliveries/:id", async (c) => {
62
+ const row = await notificationsService.getDeliveryById(c.get("db"), c.req.param("id"));
63
+ if (!row)
64
+ return c.json({ error: "Notification delivery not found" }, 404);
65
+ return c.json({ data: row });
66
+ })
67
+ .post("/deliveries/:id/resend", async (c) => {
68
+ try {
69
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
70
+ const dispatcher = createNotificationService(runtime.providers);
71
+ const row = await notificationsService.resendDelivery(c.get("db"), dispatcher, c.req.param("id"));
72
+ if (!row)
73
+ return c.json({ error: "Notification delivery not found" }, 404);
74
+ return c.json({ data: row }, 201);
75
+ }
76
+ catch (error) {
77
+ const message = error instanceof Error ? error.message : "Notification resend failed";
78
+ return c.json({ error: message }, 400);
79
+ }
80
+ })
81
+ .get("/reminder-rules", async (c) => {
82
+ const query = parseQuery(c, notificationReminderRuleListQuerySchema);
83
+ return c.json(await notificationsService.listReminderRules(c.get("db"), query));
84
+ })
85
+ .post("/reminder-rules", async (c) => {
86
+ const row = await notificationsService.createReminderRule(c.get("db"), await parseJsonBody(c, insertNotificationReminderRuleSchema));
87
+ return c.json({ data: row }, 201);
88
+ })
89
+ .post("/reminder-rules/compose", async (c) => {
90
+ const body = await parseJsonBody(c, composeNotificationReminderRuleSchema);
91
+ const outcome = await notificationsService.composeNotificationReminderRule(c.get("db"), body, {
92
+ idempotencyKey: idempotencyKey(c, body.idempotencyKey),
93
+ });
94
+ if (outcome.status === "invalid") {
95
+ return c.json({ error: "invalid_reminder_rule_graph", issues: outcome.issues }, 422);
96
+ }
97
+ return c.json({ data: outcome.result }, outcome.reused ? 200 : 201);
98
+ })
99
+ .get("/reminder-rules/:id", async (c) => {
100
+ const row = await notificationsService.getReminderRuleById(c.get("db"), c.req.param("id"));
101
+ if (!row)
102
+ return c.json({ error: "Notification reminder rule not found" }, 404);
103
+ return c.json({ data: row });
104
+ })
105
+ .patch("/reminder-rules/:id", async (c) => {
106
+ const row = await notificationsService.updateReminderRule(c.get("db"), c.req.param("id"), await parseJsonBody(c, updateNotificationReminderRuleSchema));
107
+ if (!row)
108
+ return c.json({ error: "Notification reminder rule not found" }, 404);
109
+ return c.json({ data: row });
110
+ })
111
+ .delete("/reminder-rules/:id", async (c) => {
112
+ const ok = await notificationsService.deleteReminderRule(c.get("db"), c.req.param("id"));
113
+ if (!ok)
114
+ return c.json({ error: "Notification reminder rule not found" }, 404);
115
+ return c.body(null, 204);
116
+ })
117
+ .get("/reminder-rules/:id/stages", async (c) => {
118
+ const stages = await notificationsService.listReminderRuleStages(c.get("db"), c.req.param("id"));
119
+ return c.json({ data: stages });
120
+ })
121
+ .post("/reminder-rules/:id/stages", async (c) => {
122
+ const stage = await notificationsService.createReminderRuleStage(c.get("db"), c.req.param("id"), await parseJsonBody(c, insertNotificationReminderRuleStageSchema));
123
+ return c.json({ data: stage }, 201);
124
+ })
125
+ .post("/reminder-rules/:id/stages/reorder", async (c) => {
126
+ const stages = await notificationsService.reorderReminderRuleStages(c.get("db"), c.req.param("id"), await parseJsonBody(c, reorderReminderRuleStagesSchema));
127
+ return c.json({ data: stages });
128
+ })
129
+ .patch("/reminder-rules/:id/stages/:stageId", async (c) => {
130
+ const stage = await notificationsService.updateReminderRuleStage(c.get("db"), c.req.param("stageId"), await parseJsonBody(c, updateNotificationReminderRuleStageSchema));
131
+ if (!stage)
132
+ return c.json({ error: "Reminder stage not found" }, 404);
133
+ return c.json({ data: stage });
134
+ })
135
+ .delete("/reminder-rules/:id/stages/:stageId", async (c) => {
136
+ const ok = await notificationsService.deleteReminderRuleStage(c.get("db"), c.req.param("stageId"));
137
+ if (!ok)
138
+ return c.json({ error: "Reminder stage not found" }, 404);
139
+ return c.body(null, 204);
140
+ })
141
+ .get("/reminder-rules/:id/stages/:stageId/channels", async (c) => {
142
+ const channels = await notificationsService.listStageChannels(c.get("db"), c.req.param("stageId"));
143
+ return c.json({ data: channels });
144
+ })
145
+ .post("/reminder-rules/:id/stages/:stageId/channels", async (c) => {
146
+ const row = await notificationsService.createStageChannel(c.get("db"), c.req.param("stageId"), await parseJsonBody(c, insertNotificationReminderStageChannelSchema));
147
+ return c.json({ data: row }, 201);
148
+ })
149
+ .patch("/reminder-rules/:id/stages/:stageId/channels/:channelId", async (c) => {
150
+ const row = await notificationsService.updateStageChannel(c.get("db"), c.req.param("channelId"), await parseJsonBody(c, updateNotificationReminderStageChannelSchema));
151
+ if (!row)
152
+ return c.json({ error: "Stage channel not found" }, 404);
153
+ return c.json({ data: row });
154
+ })
155
+ .delete("/reminder-rules/:id/stages/:stageId/channels/:channelId", async (c) => {
156
+ const ok = await notificationsService.deleteStageChannel(c.get("db"), c.req.param("channelId"));
157
+ if (!ok)
158
+ return c.json({ error: "Stage channel not found" }, 404);
159
+ return c.body(null, 204);
160
+ })
161
+ .get("/notification-settings", async (c) => {
162
+ const row = await notificationsService.getNotificationSettings(c.get("db"));
163
+ return c.json({ data: row });
164
+ })
165
+ .patch("/notification-settings", async (c) => {
166
+ const row = await notificationsService.upsertNotificationSettings(c.get("db"), await parseJsonBody(c, updateNotificationSettingsSchema));
167
+ return c.json({ data: row });
168
+ })
169
+ .get("/reminders/preview", async (c) => {
170
+ const query = parseQuery(c, previewRemindersQuerySchema);
171
+ const now = query.date ? new Date(`${query.date}T00:00:00Z`) : new Date();
172
+ const rows = await notificationsService.previewReminders(c.get("db"), {
173
+ now,
174
+ ruleId: query.ruleId,
175
+ targetId: query.targetId,
176
+ });
177
+ return c.json({ data: rows });
178
+ })
179
+ .get("/reminder-runs", async (c) => {
180
+ const query = parseQuery(c, notificationReminderRunListQuerySchema);
181
+ return c.json(await notificationsService.listReminderRuns(c.get("db"), query));
182
+ })
183
+ .get("/reminder-runs/:id", async (c) => {
184
+ const row = await notificationsService.getReminderRunById(c.get("db"), c.req.param("id"));
185
+ if (!row)
186
+ return c.json({ error: "Notification reminder run not found" }, 404);
187
+ return c.json({ data: row });
188
+ })
189
+ .post("/reminders/run-due", async (c) => {
190
+ try {
191
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
192
+ const dispatcher = createNotificationService(runtime.providers);
193
+ const result = await notificationsService.runDueReminders(c.get("db"), dispatcher, await parseOptionalJsonBody(c, runDueRemindersSchema));
194
+ return c.json({ data: result });
195
+ }
196
+ catch (error) {
197
+ const message = error instanceof Error ? error.message : "Reminder sweep failed";
198
+ return c.json({ error: message }, 400);
199
+ }
200
+ })
201
+ .post("/payment-sessions/:id/send", async (c) => {
202
+ try {
203
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
204
+ const dispatcher = createNotificationService(runtime.providers);
205
+ const row = await notificationsService.sendPaymentSessionNotification(c.get("db"), dispatcher, c.req.param("id"), withPaymentLinkBaseUrl(await parseJsonBody(c, sendPaymentSessionNotificationSchema), runtime.publicCheckoutBaseUrl));
206
+ if (!row)
207
+ return c.json({ error: "Payment session not found" }, 404);
208
+ return c.json({ data: row }, 201);
209
+ }
210
+ catch (error) {
211
+ const message = error instanceof Error ? error.message : "Payment session notification failed";
212
+ return c.json({ error: message }, 400);
213
+ }
214
+ })
215
+ .post("/invoices/:id/send", async (c) => {
216
+ try {
217
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
218
+ const dispatcher = createNotificationService(runtime.providers);
219
+ const row = await notificationsService.sendInvoiceNotification(c.get("db"), dispatcher, c.req.param("id"), withPaymentLinkBaseUrl(await parseJsonBody(c, sendInvoiceNotificationSchema), runtime.publicCheckoutBaseUrl));
220
+ if (!row)
221
+ return c.json({ error: "Invoice not found" }, 404);
222
+ return c.json({ data: row }, 201);
223
+ }
224
+ catch (error) {
225
+ const message = error instanceof Error ? error.message : "Invoice notification failed";
226
+ return c.json({ error: message }, 400);
227
+ }
228
+ })
229
+ .get("/bookings/:id/document-bundle", async (c) => {
230
+ const bundle = await notificationsService.listBookingDocumentBundle(c.get("db"), c.req.param("id"));
231
+ if (!bundle)
232
+ return c.json({ error: "Booking not found" }, 404);
233
+ return c.json({ data: bookingDocumentBundleSchema.parse(bundle) });
234
+ })
235
+ .post("/bookings/:id/confirm-and-dispatch", async (c) => {
236
+ try {
237
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
238
+ const dispatcher = createNotificationService(runtime.providers);
239
+ const result = await notificationsService.confirmAndDispatchBooking(c.get("db"), dispatcher, c.req.param("id"), await parseOptionalJsonBody(c, confirmAndDispatchBookingSchema), {
240
+ attachmentResolver: runtime.documentAttachmentResolver,
241
+ eventBus: runtime.eventBus,
242
+ });
243
+ if (result.status === "not_found")
244
+ return c.json({ error: "Booking not found" }, 404);
245
+ if (result.status === "preview") {
246
+ return c.json({
247
+ data: confirmAndDispatchBookingResultSchema.parse({
248
+ bookingId: result.bookingId,
249
+ documents: result.documents,
250
+ notification: null,
251
+ skipReason: "preview_only",
252
+ }),
253
+ });
254
+ }
255
+ if (result.status === "skipped") {
256
+ return c.json({
257
+ data: confirmAndDispatchBookingResultSchema.parse({
258
+ bookingId: result.bookingId,
259
+ documents: result.documents,
260
+ notification: null,
261
+ skipReason: result.skipReason,
262
+ }),
263
+ });
264
+ }
265
+ return c.json({
266
+ data: confirmAndDispatchBookingResultSchema.parse({
267
+ bookingId: result.bookingId,
268
+ documents: result.documents,
269
+ notification: {
270
+ recipient: result.recipient,
271
+ deliveryId: result.delivery.id,
272
+ provider: result.delivery.provider,
273
+ status: result.delivery.status,
274
+ },
275
+ skipReason: null,
276
+ }),
277
+ }, 201);
278
+ }
279
+ catch (error) {
280
+ const message = error instanceof Error ? error.message : "Confirm-and-dispatch failed";
281
+ return c.json({ error: message }, 400);
282
+ }
283
+ })
284
+ .post("/bookings/:id/send-documents", async (c) => {
285
+ try {
286
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
287
+ const dispatcher = createNotificationService(runtime.providers);
288
+ const result = await notificationsService.sendBookingDocumentsNotification(c.get("db"), dispatcher, c.req.param("id"), await parseOptionalJsonBody(c, sendBookingDocumentsNotificationSchema), {
289
+ attachmentResolver: runtime.documentAttachmentResolver,
290
+ eventBus: runtime.eventBus,
291
+ });
292
+ if (result.status === "not_found")
293
+ return c.json({ error: "Booking not found" }, 404);
294
+ if (result.status === "no_documents")
295
+ return c.json({ error: "No booking documents" }, 400);
296
+ if (result.status === "no_recipient")
297
+ return c.json({ error: "No recipient available" }, 400);
298
+ if (result.status === "no_attachments") {
299
+ return c.json({ error: "No deliverable document attachments available" }, 400);
300
+ }
301
+ if (result.status === "send_failed") {
302
+ return c.json({ error: "Booking document notification failed" }, 400);
303
+ }
304
+ return c.json({
305
+ data: sendBookingDocumentsNotificationResultSchema.parse({
306
+ bookingId: result.bookingId,
307
+ recipient: result.recipient,
308
+ documents: result.documents,
309
+ deliveryId: result.delivery.id,
310
+ provider: result.delivery.provider,
311
+ status: result.delivery.status,
312
+ }),
313
+ }, 201);
314
+ }
315
+ catch (error) {
316
+ const message = error instanceof Error ? error.message : "Booking document notification failed";
317
+ return c.json({ error: message }, 400);
318
+ }
319
+ })
320
+ .post("/send", async (c) => {
321
+ try {
322
+ const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
323
+ const dispatcher = createNotificationService(runtime.providers);
324
+ const row = await notificationsService.sendNotification(c.get("db"), dispatcher, await parseJsonBody(c, sendNotificationSchema));
325
+ return c.json({ data: row }, 201);
326
+ }
327
+ catch (error) {
328
+ const message = error instanceof Error ? error.message : "Notification send failed";
329
+ return c.json({ error: message }, 400);
330
+ }
331
+ });
332
+ }
333
+ function withPaymentLinkBaseUrl(input, publicCheckoutBaseUrl) {
334
+ if (input.paymentLinkBaseUrl || !publicCheckoutBaseUrl)
335
+ return input;
336
+ return { ...input, paymentLinkBaseUrl: publicCheckoutBaseUrl };
337
+ }