@voyantjs/notifications 0.6.8 → 0.7.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.
- package/README.md +1 -1
- package/dist/index.d.ts +27 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -4
- package/dist/liquid.d.ts +5 -0
- package/dist/liquid.d.ts.map +1 -0
- package/dist/liquid.js +156 -0
- package/dist/routes.d.ts +88 -2
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +54 -1
- package/dist/schema.d.ts +1 -1
- package/dist/service-booking-documents.d.ts +128 -0
- package/dist/service-booking-documents.d.ts.map +1 -1
- package/dist/service-booking-documents.js +56 -4
- package/dist/service-deliveries.d.ts.map +1 -1
- package/dist/service-deliveries.js +25 -7
- package/dist/service-reminders.d.ts +1 -1
- package/dist/service-reminders.d.ts.map +1 -1
- package/dist/service-reminders.js +98 -78
- package/dist/service-shared.d.ts +48 -3
- package/dist/service-shared.d.ts.map +1 -1
- package/dist/service-shared.js +300 -40
- package/dist/service-templates.d.ts +2 -2
- package/dist/service.d.ts +119 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +4 -1
- package/dist/tasks/deliver-reminder.d.ts +1 -1
- package/dist/template-authoring.d.ts +23 -0
- package/dist/template-authoring.d.ts.map +1 -0
- package/dist/template-authoring.js +386 -0
- package/dist/validation.d.ts +102 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +57 -0
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -94,7 +94,7 @@ For finance-aware collection sends, the routes also support:
|
|
|
94
94
|
- `GET /bookings/:id/document-bundle`
|
|
95
95
|
- `POST /bookings/:id/send-documents`
|
|
96
96
|
|
|
97
|
-
Those routes resolve recipients from the payment session, invoice, and linked booking
|
|
97
|
+
Those routes resolve recipients from the payment session, invoice, and linked booking travelers, then render the selected notification template with finance context such as payment links, invoice balances, and booking references.
|
|
98
98
|
|
|
99
99
|
Booking document sends bundle the latest customer-facing contract attachment and
|
|
100
100
|
ready invoice/proforma rendition for a booking. By default they use the stored
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { HonoModule } from "@voyantjs/hono/module";
|
|
2
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
3
|
import { type NotificationsRoutesOptions } from "./routes.js";
|
|
4
|
+
export { notificationLiquidEngine, renderLiquidTemplate, } from "./liquid.js";
|
|
3
5
|
export type { DefaultNotificationProviderOptions } from "./provider-resolution.js";
|
|
4
6
|
export { createDefaultNotificationProviders, createResendProviderFromEnv, createTwilioProviderFromEnv, } from "./provider-resolution.js";
|
|
5
7
|
export type { LocalProviderOptions } from "./providers/local.js";
|
|
@@ -13,13 +15,35 @@ export { buildNotificationsRouteRuntime, createNotificationsRoutes, NOTIFICATION
|
|
|
13
15
|
export type { NewNotificationDelivery, NewNotificationReminderRule, NewNotificationReminderRun, NewNotificationTemplate, NotificationDelivery, NotificationReminderRule, NotificationReminderRun, NotificationsHonoModule, NotificationTemplate, } from "./schema.js";
|
|
14
16
|
export { notificationChannelEnum, notificationDeliveries, notificationDeliveryStatusEnum, notificationReminderRules, notificationReminderRunStatusEnum, notificationReminderRuns, notificationReminderStatusEnum, notificationReminderTargetTypeEnum, notificationsModule, notificationTargetTypeEnum, notificationTemplateStatusEnum, notificationTemplates, } from "./schema.js";
|
|
15
17
|
export type { NotificationService } from "./service.js";
|
|
16
|
-
export { createDefaultBookingDocumentAttachment, createNotificationService, NotificationError, notificationsService, renderNotificationTemplate, } from "./service.js";
|
|
18
|
+
export { createDefaultBookingDocumentAttachment, createNotificationService, NotificationError, notificationsService, previewNotificationTemplate, renderNotificationTemplate, } from "./service.js";
|
|
17
19
|
export type { BookingDocumentAttachmentResolver, BookingDocumentsSentEvent, SendBookingDocumentsRuntimeOptions, } from "./service-booking-documents.js";
|
|
18
20
|
export { bookingDocumentNotificationsService } from "./service-booking-documents.js";
|
|
19
21
|
export type { NotificationTaskEnv, NotificationTaskRuntime, NotificationTaskRuntimeOptions, ReminderDeliveryJob, } from "./task-runtime.js";
|
|
20
22
|
export { buildNotificationTaskRuntime } from "./task-runtime.js";
|
|
21
23
|
export { deliverQueuedNotificationReminder, sendDueNotificationReminders } from "./tasks/index.js";
|
|
24
|
+
export type { NotificationLiquidSnippet, NotificationTemplateVariableCategory, NotificationTemplateVariableDefinition, NotificationTemplateVariableType, } from "./template-authoring.js";
|
|
25
|
+
export { notificationLiquidSnippets, notificationTemplateVariableCatalog, } from "./template-authoring.js";
|
|
22
26
|
export type { NotificationAttachment, NotificationChannel, NotificationPayload, NotificationProvider, NotificationResult, } from "./types.js";
|
|
23
|
-
export { bookingDocumentBundleItemSchema, bookingDocumentBundleSchema, insertNotificationReminderRuleSchema, insertNotificationTemplateSchema, notificationAttachmentSchema, notificationChannelSchema, notificationDeliveryListQuerySchema, notificationDeliveryStatusSchema, notificationDocumentSourceSchema, notificationDocumentTypeSchema, notificationReminderRuleListQuerySchema, notificationReminderRunDeliverySummarySchema, notificationReminderRunLinksSchema, notificationReminderRunListQuerySchema, notificationReminderRunListResponseSchema, notificationReminderRunRecordSchema, notificationReminderRunRuleSummarySchema, notificationReminderRunStatusSchema, notificationReminderStatusSchema, notificationReminderTargetTypeSchema, notificationTargetTypeSchema, notificationTemplateListQuerySchema, notificationTemplateStatusSchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationTemplateSchema, } from "./validation.js";
|
|
24
|
-
|
|
27
|
+
export { bookingDocumentBundleItemSchema, bookingDocumentBundleSchema, insertNotificationReminderRuleSchema, insertNotificationTemplateSchema, notificationAttachmentSchema, notificationChannelSchema, notificationDeliveryListQuerySchema, notificationDeliveryStatusSchema, notificationDocumentSourceSchema, notificationDocumentTypeSchema, notificationReminderRuleListQuerySchema, notificationReminderRunDeliverySummarySchema, notificationReminderRunLinksSchema, notificationReminderRunListQuerySchema, notificationReminderRunListResponseSchema, notificationReminderRunRecordSchema, notificationReminderRunRuleSummarySchema, notificationReminderRunStatusSchema, notificationReminderStatusSchema, notificationReminderTargetTypeSchema, notificationTargetTypeSchema, notificationTemplateListQuerySchema, notificationTemplateStatusSchema, previewNotificationTemplateResultSchema, previewNotificationTemplateSchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationTemplateSchema, } from "./validation.js";
|
|
28
|
+
/**
|
|
29
|
+
* Auto-dispatch policy for the `booking.confirmed` subscriber. Set `enabled:
|
|
30
|
+
* false` (or leave the option off entirely) to opt out.
|
|
31
|
+
*/
|
|
32
|
+
export interface NotificationsAutoConfirmAndDispatchOptions {
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
/** Notification template slug used when the handler fires. */
|
|
35
|
+
templateSlug?: string;
|
|
36
|
+
/** Optional allowlist of document types to attach; defaults to all. */
|
|
37
|
+
documentTypes?: Array<"contract" | "invoice" | "proforma">;
|
|
38
|
+
}
|
|
39
|
+
export interface CreateNotificationsHonoModuleOptions extends NotificationsRoutesOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Resolves a database from runtime bindings. Required for
|
|
42
|
+
* `autoConfirmAndDispatch` — the `booking.confirmed` subscriber fires
|
|
43
|
+
* outside a request scope and needs its own db handle.
|
|
44
|
+
*/
|
|
45
|
+
resolveDb?: (bindings: Record<string, unknown>) => PostgresJsDatabase;
|
|
46
|
+
autoConfirmAndDispatch?: NotificationsAutoConfirmAndDispatchOptions;
|
|
47
|
+
}
|
|
48
|
+
export declare function createNotificationsHonoModule(options?: CreateNotificationsHonoModuleOptions): HonoModule;
|
|
25
49
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,25 +1,61 @@
|
|
|
1
1
|
import { buildNotificationsRouteRuntime, createNotificationsRoutes, NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./routes.js";
|
|
2
2
|
import { notificationsModule } from "./schema.js";
|
|
3
|
+
import { createNotificationService } from "./service.js";
|
|
4
|
+
import { bookingDocumentNotificationsService } from "./service-booking-documents.js";
|
|
5
|
+
export { notificationLiquidEngine, renderLiquidTemplate, } from "./liquid.js";
|
|
3
6
|
export { createDefaultNotificationProviders, createResendProviderFromEnv, createTwilioProviderFromEnv, } from "./provider-resolution.js";
|
|
4
7
|
export { createLocalProvider } from "./providers/local.js";
|
|
5
8
|
export { createResendProvider } from "./providers/resend.js";
|
|
6
9
|
export { createTwilioProvider } from "./providers/twilio.js";
|
|
7
10
|
export { buildNotificationsRouteRuntime, createNotificationsRoutes, NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./routes.js";
|
|
8
11
|
export { notificationChannelEnum, notificationDeliveries, notificationDeliveryStatusEnum, notificationReminderRules, notificationReminderRunStatusEnum, notificationReminderRuns, notificationReminderStatusEnum, notificationReminderTargetTypeEnum, notificationsModule, notificationTargetTypeEnum, notificationTemplateStatusEnum, notificationTemplates, } from "./schema.js";
|
|
9
|
-
export { createDefaultBookingDocumentAttachment, createNotificationService, NotificationError, notificationsService, renderNotificationTemplate, } from "./service.js";
|
|
12
|
+
export { createDefaultBookingDocumentAttachment, createNotificationService, NotificationError, notificationsService, previewNotificationTemplate, renderNotificationTemplate, } from "./service.js";
|
|
10
13
|
export { bookingDocumentNotificationsService } from "./service-booking-documents.js";
|
|
11
14
|
export { buildNotificationTaskRuntime } from "./task-runtime.js";
|
|
12
15
|
export { deliverQueuedNotificationReminder, sendDueNotificationReminders } from "./tasks/index.js";
|
|
13
|
-
export {
|
|
16
|
+
export { notificationLiquidSnippets, notificationTemplateVariableCatalog, } from "./template-authoring.js";
|
|
17
|
+
export { bookingDocumentBundleItemSchema, bookingDocumentBundleSchema, insertNotificationReminderRuleSchema, insertNotificationTemplateSchema, notificationAttachmentSchema, notificationChannelSchema, notificationDeliveryListQuerySchema, notificationDeliveryStatusSchema, notificationDocumentSourceSchema, notificationDocumentTypeSchema, notificationReminderRuleListQuerySchema, notificationReminderRunDeliverySummarySchema, notificationReminderRunLinksSchema, notificationReminderRunListQuerySchema, notificationReminderRunListResponseSchema, notificationReminderRunRecordSchema, notificationReminderRunRuleSummarySchema, notificationReminderRunStatusSchema, notificationReminderStatusSchema, notificationReminderTargetTypeSchema, notificationTargetTypeSchema, notificationTemplateListQuerySchema, notificationTemplateStatusSchema, previewNotificationTemplateResultSchema, previewNotificationTemplateSchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationTemplateSchema, } from "./validation.js";
|
|
14
18
|
export function createNotificationsHonoModule(options) {
|
|
19
|
+
const routes = createNotificationsRoutes(options);
|
|
15
20
|
const module = {
|
|
16
21
|
...notificationsModule,
|
|
17
|
-
bootstrap: ({ bindings, container }) => {
|
|
22
|
+
bootstrap: ({ bindings, container, eventBus }) => {
|
|
18
23
|
container.register(NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY, buildNotificationsRouteRuntime(bindings, options));
|
|
24
|
+
// Auto-dispatch wiring — opt-in. When enabled, every `booking.confirmed`
|
|
25
|
+
// event triggers a `confirmAndDispatchBooking` call so the operator
|
|
26
|
+
// doesn't have to click a second button. The handler runs in the same
|
|
27
|
+
// process as the emitter (the in-process event bus) but outside the
|
|
28
|
+
// request scope, so we resolve our own db handle from bindings.
|
|
29
|
+
if (options?.autoConfirmAndDispatch?.enabled && options.resolveDb) {
|
|
30
|
+
const resolveDb = options.resolveDb;
|
|
31
|
+
const autoOptions = options.autoConfirmAndDispatch;
|
|
32
|
+
const runtime = buildNotificationsRouteRuntime(bindings, options);
|
|
33
|
+
const dispatcher = createNotificationService(runtime.providers);
|
|
34
|
+
eventBus.subscribe("booking.confirmed", async (event) => {
|
|
35
|
+
try {
|
|
36
|
+
const db = resolveDb(bindings);
|
|
37
|
+
await bookingDocumentNotificationsService.confirmAndDispatchBooking(db, dispatcher, event.data.bookingId, {
|
|
38
|
+
templateSlug: autoOptions.templateSlug ?? null,
|
|
39
|
+
documentTypes: autoOptions.documentTypes ?? null,
|
|
40
|
+
}, {
|
|
41
|
+
attachmentResolver: runtime.documentAttachmentResolver,
|
|
42
|
+
eventBus,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
// Per the EventBus contract, handler failures are logged, not
|
|
47
|
+
// rethrown. We surface the context so ops can diagnose without
|
|
48
|
+
// digging through stack traces.
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
console.error(`[notifications] auto-dispatch failed for booking ${event.data.bookingId}: ${message}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
19
54
|
},
|
|
20
55
|
};
|
|
21
56
|
return {
|
|
22
57
|
module,
|
|
23
|
-
|
|
58
|
+
adminRoutes: routes,
|
|
59
|
+
routes,
|
|
24
60
|
};
|
|
25
61
|
}
|
package/dist/liquid.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Liquid } from "liquidjs";
|
|
2
|
+
declare const engine: Liquid;
|
|
3
|
+
export declare function renderLiquidTemplate(template: string | null | undefined, data: Record<string, unknown>): string | null;
|
|
4
|
+
export { engine as notificationLiquidEngine };
|
|
5
|
+
//# sourceMappingURL=liquid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquid.d.ts","sourceRoot":"","sources":["../src/liquid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,QAAA,MAAM,MAAM,QAOV,CAAA;AAqIF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,IAAI,CAiBf;AAED,OAAO,EAAE,MAAM,IAAI,wBAAwB,EAAE,CAAA"}
|
package/dist/liquid.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Liquid } from "liquidjs";
|
|
2
|
+
const engine = new Liquid({
|
|
3
|
+
strictFilters: false,
|
|
4
|
+
strictVariables: false,
|
|
5
|
+
trimTagLeft: false,
|
|
6
|
+
trimTagRight: false,
|
|
7
|
+
greedy: false,
|
|
8
|
+
jsTruthy: true,
|
|
9
|
+
});
|
|
10
|
+
engine.registerFilter("json", (value) => JSON.stringify(value ?? null));
|
|
11
|
+
engine.registerFilter("currency", (value, currency = "EUR", locale = "en-US") => {
|
|
12
|
+
const num = typeof value === "number" ? value : Number.parseFloat(String(value));
|
|
13
|
+
if (Number.isNaN(num))
|
|
14
|
+
return String(value ?? "");
|
|
15
|
+
return new Intl.NumberFormat(String(locale), {
|
|
16
|
+
style: "currency",
|
|
17
|
+
currency: String(currency || "EUR"),
|
|
18
|
+
}).format(num);
|
|
19
|
+
});
|
|
20
|
+
engine.registerFilter("date_format", (value, _format, locale = "en-US") => {
|
|
21
|
+
if (!value)
|
|
22
|
+
return "";
|
|
23
|
+
const date = value instanceof Date ? value : new Date(String(value));
|
|
24
|
+
if (Number.isNaN(date.getTime()))
|
|
25
|
+
return String(value);
|
|
26
|
+
return date.toLocaleDateString(String(locale), {
|
|
27
|
+
year: "numeric",
|
|
28
|
+
month: "long",
|
|
29
|
+
day: "numeric",
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
engine.registerFilter("phone", (value) => {
|
|
33
|
+
if (!value)
|
|
34
|
+
return "";
|
|
35
|
+
const phone = String(value).replace(/\D/g, "");
|
|
36
|
+
if (phone.length === 10) {
|
|
37
|
+
return `(${phone.slice(0, 3)}) ${phone.slice(3, 6)}-${phone.slice(6)}`;
|
|
38
|
+
}
|
|
39
|
+
if (phone.length === 11 && phone.startsWith("1")) {
|
|
40
|
+
return `+1 (${phone.slice(1, 4)}) ${phone.slice(4, 7)}-${phone.slice(7)}`;
|
|
41
|
+
}
|
|
42
|
+
if (phone.length > 10) {
|
|
43
|
+
return `+${phone.slice(0, -9)} ${phone.slice(-9, -6)} ${phone.slice(-6, -3)} ${phone.slice(-3)}`;
|
|
44
|
+
}
|
|
45
|
+
return String(value);
|
|
46
|
+
});
|
|
47
|
+
engine.registerFilter("default", (value, defaultValue) => {
|
|
48
|
+
if (value === null || value === undefined || value === "")
|
|
49
|
+
return defaultValue;
|
|
50
|
+
return value;
|
|
51
|
+
});
|
|
52
|
+
engine.registerFilter("pluralize", (count, singular, plural) => {
|
|
53
|
+
const num = typeof count === "number" ? count : Number.parseInt(String(count), 10);
|
|
54
|
+
return num === 1 ? singular : plural;
|
|
55
|
+
});
|
|
56
|
+
function toSnakeCase(str) {
|
|
57
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
58
|
+
}
|
|
59
|
+
function normalizeKeys(obj) {
|
|
60
|
+
const result = {};
|
|
61
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
62
|
+
result[key] =
|
|
63
|
+
value && typeof value === "object" && !Array.isArray(value)
|
|
64
|
+
? normalizeKeys(value)
|
|
65
|
+
: value;
|
|
66
|
+
const snakeKey = toSnakeCase(key);
|
|
67
|
+
if (snakeKey !== key) {
|
|
68
|
+
result[snakeKey] = result[key];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
function decodeHtmlEntities(str) {
|
|
74
|
+
return str
|
|
75
|
+
.replace(/"/g, '"')
|
|
76
|
+
.replace(/'/g, "'")
|
|
77
|
+
.replace(/&/g, "&")
|
|
78
|
+
.replace(/</g, "<")
|
|
79
|
+
.replace(/>/g, ">");
|
|
80
|
+
}
|
|
81
|
+
function healBrokenTags(html) {
|
|
82
|
+
html = html.replace(/\{\{([\s\S]{1,300}?)\}\}/g, (match) => {
|
|
83
|
+
let healed = match;
|
|
84
|
+
if (/</.test(healed))
|
|
85
|
+
healed = healed.replace(/<[^>]+>/g, "").replace(/\s+/g, " ");
|
|
86
|
+
if (/&\w+;/.test(healed))
|
|
87
|
+
healed = decodeHtmlEntities(healed);
|
|
88
|
+
return healed;
|
|
89
|
+
});
|
|
90
|
+
html = html.replace(/\{%([\s\S]{1,300}?)%\}/g, (match) => {
|
|
91
|
+
let healed = match;
|
|
92
|
+
if (/</.test(healed))
|
|
93
|
+
healed = healed.replace(/<[^>]+>/g, "").replace(/\s+/g, " ");
|
|
94
|
+
if (/&\w+;/.test(healed))
|
|
95
|
+
healed = decodeHtmlEntities(healed);
|
|
96
|
+
return healed;
|
|
97
|
+
});
|
|
98
|
+
return html;
|
|
99
|
+
}
|
|
100
|
+
function healSyntax(template) {
|
|
101
|
+
let result = healBrokenTags(template);
|
|
102
|
+
result = result.replace(/\{%[-\s]*for\s+(\w+)\s*[-]?%\}/gi, (match, collection) => {
|
|
103
|
+
if (/\bfor\s+\w+\s+in\s+/i.test(match))
|
|
104
|
+
return match;
|
|
105
|
+
const singular = collection.endsWith("ies")
|
|
106
|
+
? `${collection.slice(0, -3)}y`
|
|
107
|
+
: collection.endsWith("s")
|
|
108
|
+
? collection.slice(0, -1)
|
|
109
|
+
: `${collection}_item`;
|
|
110
|
+
return `{% for ${singular} in ${collection} %}`;
|
|
111
|
+
});
|
|
112
|
+
result = result.replace(/\{%[-\s]*(endfor|endif|else|endunless|endcase|endcapture|endraw)\s*[-]?%\}/gi, (_match, tag) => `{% ${tag.toLowerCase()} %}`);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
function regexFallback(template, data) {
|
|
116
|
+
function resolve(obj, path) {
|
|
117
|
+
const parts = path.split(".");
|
|
118
|
+
let cur = obj;
|
|
119
|
+
for (const p of parts) {
|
|
120
|
+
if (cur == null || typeof cur !== "object")
|
|
121
|
+
return undefined;
|
|
122
|
+
cur = cur[p];
|
|
123
|
+
}
|
|
124
|
+
return cur;
|
|
125
|
+
}
|
|
126
|
+
let result = template;
|
|
127
|
+
result = result.replace(/\{\{\s*([^}|]+?)(?:\s*\|[^}]*)?\s*\}\}/g, (_match, rawPath) => {
|
|
128
|
+
const path = rawPath.trim();
|
|
129
|
+
const value = resolve(data, path);
|
|
130
|
+
if (value !== undefined && value !== null)
|
|
131
|
+
return String(value);
|
|
132
|
+
return _match;
|
|
133
|
+
});
|
|
134
|
+
result = result.replace(/\{%[\s\S]*?%\}/g, "");
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
export function renderLiquidTemplate(template, data) {
|
|
138
|
+
if (!template)
|
|
139
|
+
return null;
|
|
140
|
+
const normalized = normalizeKeys(data);
|
|
141
|
+
const healed = healSyntax(template);
|
|
142
|
+
try {
|
|
143
|
+
return engine.parseAndRenderSync(healed, normalized);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
console.error("[notifications:liquid] template parsing failed, falling back to regex", error);
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
return regexFallback(healed, normalized);
|
|
150
|
+
}
|
|
151
|
+
catch (fallbackError) {
|
|
152
|
+
console.error("[notifications:liquid] regex fallback failed", fallbackError);
|
|
153
|
+
return template;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export { engine as notificationLiquidEngine };
|
package/dist/routes.d.ts
CHANGED
|
@@ -170,6 +170,24 @@ export declare function createNotificationsRoutes(options?: NotificationsRoutesO
|
|
|
170
170
|
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
171
171
|
};
|
|
172
172
|
};
|
|
173
|
+
} & {
|
|
174
|
+
"/preview": {
|
|
175
|
+
$post: {
|
|
176
|
+
input: {};
|
|
177
|
+
output: {
|
|
178
|
+
data: {
|
|
179
|
+
channel: "email" | "sms";
|
|
180
|
+
provider: string | null;
|
|
181
|
+
fromAddress: string | null;
|
|
182
|
+
subject: string | null;
|
|
183
|
+
html: string | null;
|
|
184
|
+
text: string | null;
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
outputFormat: "json";
|
|
188
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
189
|
+
};
|
|
190
|
+
};
|
|
173
191
|
} & {
|
|
174
192
|
"/deliveries": {
|
|
175
193
|
$get: {
|
|
@@ -430,7 +448,7 @@ export declare function createNotificationsRoutes(options?: NotificationsRoutesO
|
|
|
430
448
|
targetType: "invoice" | "booking_payment_schedule";
|
|
431
449
|
targetId: string;
|
|
432
450
|
dedupeKey: string;
|
|
433
|
-
status: "failed" | "sent" | "processing" | "
|
|
451
|
+
status: "failed" | "sent" | "processing" | "skipped" | "queued";
|
|
434
452
|
recipient: string | null;
|
|
435
453
|
scheduledFor: string;
|
|
436
454
|
processedAt: string;
|
|
@@ -507,7 +525,7 @@ export declare function createNotificationsRoutes(options?: NotificationsRoutesO
|
|
|
507
525
|
targetType: "invoice" | "booking_payment_schedule";
|
|
508
526
|
targetId: string;
|
|
509
527
|
dedupeKey: string;
|
|
510
|
-
status: "failed" | "sent" | "processing" | "
|
|
528
|
+
status: "failed" | "sent" | "processing" | "skipped" | "queued";
|
|
511
529
|
recipient: string | null;
|
|
512
530
|
scheduledFor: string;
|
|
513
531
|
processedAt: string;
|
|
@@ -766,6 +784,74 @@ export declare function createNotificationsRoutes(options?: NotificationsRoutesO
|
|
|
766
784
|
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
767
785
|
};
|
|
768
786
|
};
|
|
787
|
+
} & {
|
|
788
|
+
"/bookings/:id/confirm-and-dispatch": {
|
|
789
|
+
$post: {
|
|
790
|
+
input: {
|
|
791
|
+
param: {
|
|
792
|
+
id: string;
|
|
793
|
+
};
|
|
794
|
+
};
|
|
795
|
+
output: {
|
|
796
|
+
error: string;
|
|
797
|
+
};
|
|
798
|
+
outputFormat: "json";
|
|
799
|
+
status: 404;
|
|
800
|
+
} | {
|
|
801
|
+
input: {
|
|
802
|
+
param: {
|
|
803
|
+
id: string;
|
|
804
|
+
};
|
|
805
|
+
};
|
|
806
|
+
output: {
|
|
807
|
+
data: {
|
|
808
|
+
bookingId: string;
|
|
809
|
+
documents: {
|
|
810
|
+
key: string;
|
|
811
|
+
source: "finance" | "legal";
|
|
812
|
+
documentType: "invoice" | "proforma" | "contract";
|
|
813
|
+
bookingId: string;
|
|
814
|
+
name: string;
|
|
815
|
+
createdAt: string;
|
|
816
|
+
contractId?: string | null | undefined;
|
|
817
|
+
invoiceId?: string | null | undefined;
|
|
818
|
+
attachmentId?: string | null | undefined;
|
|
819
|
+
renditionId?: string | null | undefined;
|
|
820
|
+
contractStatus?: string | null | undefined;
|
|
821
|
+
invoiceStatus?: string | null | undefined;
|
|
822
|
+
format?: string | null | undefined;
|
|
823
|
+
mimeType?: string | null | undefined;
|
|
824
|
+
storageKey?: string | null | undefined;
|
|
825
|
+
downloadUrl?: string | null | undefined;
|
|
826
|
+
language?: string | null | undefined;
|
|
827
|
+
metadata?: {
|
|
828
|
+
[x: string]: import("hono/utils/types").JSONValue;
|
|
829
|
+
} | null | undefined;
|
|
830
|
+
}[];
|
|
831
|
+
notification: {
|
|
832
|
+
recipient: string;
|
|
833
|
+
deliveryId: string;
|
|
834
|
+
status: "pending" | "cancelled" | "failed" | "sent";
|
|
835
|
+
provider?: string | null | undefined;
|
|
836
|
+
} | null;
|
|
837
|
+
skipReason: "preview_only" | "no_documents" | "no_recipient" | "no_attachments" | "send_failed" | null;
|
|
838
|
+
};
|
|
839
|
+
};
|
|
840
|
+
outputFormat: "json";
|
|
841
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
842
|
+
} | {
|
|
843
|
+
input: {
|
|
844
|
+
param: {
|
|
845
|
+
id: string;
|
|
846
|
+
};
|
|
847
|
+
};
|
|
848
|
+
output: {
|
|
849
|
+
error: string;
|
|
850
|
+
};
|
|
851
|
+
outputFormat: "json";
|
|
852
|
+
status: 400;
|
|
853
|
+
};
|
|
854
|
+
};
|
|
769
855
|
} & {
|
|
770
856
|
"/bookings/:id/send-documents": {
|
|
771
857
|
$post: {
|
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAIjE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAA;AACvF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAE/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAIjE,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,gCAAgC,CAAA;AACvF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAuBtD,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE;QACT,SAAS,EAAE,eAAe,CAAA;QAC1B,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,SAAS,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC/C,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC7F,0BAA0B,CAAC,EAAE,iCAAiC,CAAA;IAC9D,iCAAiC,CAAC,EAAE,CAClC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,iCAAiC,GAAG,SAAS,CAAA;IAClD,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,QAAQ,GAAG,SAAS,CAAA;CAC9E,CAAA;AAED,MAAM,MAAM,yBAAyB,GAAG;IACtC,SAAS,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC9C,0BAA0B,CAAC,EAAE,iCAAiC,CAAA;IAC9D,QAAQ,CAAC,EAAE,QAAQ,CAAA;CACpB,CAAA;AAED,eAAO,MAAM,yCAAyC,oCAAoC,CAAA;AAE1F,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,OAAO,CAAC,EAAE,0BAA0B,GACnC,yBAAyB,CAO3B;AAcD,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwP7E"}
|
package/dist/routes.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseJsonBody, parseOptionalJsonBody, parseQuery } from "@voyantjs/hono";
|
|
2
2
|
import { Hono } from "hono";
|
|
3
3
|
import { createNotificationService, notificationsService } from "./service.js";
|
|
4
|
-
import { bookingDocumentBundleSchema, insertNotificationReminderRuleSchema, insertNotificationTemplateSchema, notificationDeliveryListQuerySchema, notificationReminderRuleListQuerySchema, notificationReminderRunListQuerySchema, notificationTemplateListQuerySchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationTemplateSchema, } from "./validation.js";
|
|
4
|
+
import { bookingDocumentBundleSchema, confirmAndDispatchBookingResultSchema, confirmAndDispatchBookingSchema, insertNotificationReminderRuleSchema, insertNotificationTemplateSchema, notificationDeliveryListQuerySchema, notificationReminderRuleListQuerySchema, notificationReminderRunListQuerySchema, notificationTemplateListQuerySchema, previewNotificationTemplateResultSchema, previewNotificationTemplateSchema, runDueRemindersSchema, sendBookingDocumentsNotificationResultSchema, sendBookingDocumentsNotificationSchema, sendInvoiceNotificationSchema, sendNotificationSchema, sendPaymentSessionNotificationSchema, updateNotificationReminderRuleSchema, updateNotificationTemplateSchema, } from "./validation.js";
|
|
5
5
|
export const NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY = "providers.notifications.runtime";
|
|
6
6
|
export function buildNotificationsRouteRuntime(bindings, options) {
|
|
7
7
|
return {
|
|
@@ -39,6 +39,10 @@ export function createNotificationsRoutes(options) {
|
|
|
39
39
|
if (!row)
|
|
40
40
|
return c.json({ error: "Notification template not found" }, 404);
|
|
41
41
|
return c.json({ data: row });
|
|
42
|
+
})
|
|
43
|
+
.post("/preview", async (c) => {
|
|
44
|
+
const rendered = notificationsService.previewNotificationTemplate(await parseJsonBody(c, previewNotificationTemplateSchema));
|
|
45
|
+
return c.json({ data: previewNotificationTemplateResultSchema.parse(rendered) });
|
|
42
46
|
})
|
|
43
47
|
.get("/deliveries", async (c) => {
|
|
44
48
|
const query = parseQuery(c, notificationDeliveryListQuerySchema);
|
|
@@ -125,6 +129,55 @@ export function createNotificationsRoutes(options) {
|
|
|
125
129
|
if (!bundle)
|
|
126
130
|
return c.json({ error: "Booking not found" }, 404);
|
|
127
131
|
return c.json({ data: bookingDocumentBundleSchema.parse(bundle) });
|
|
132
|
+
})
|
|
133
|
+
.post("/bookings/:id/confirm-and-dispatch", async (c) => {
|
|
134
|
+
try {
|
|
135
|
+
const runtime = getRuntime(c.env, options, (key) => c.var.container.resolve(key));
|
|
136
|
+
const dispatcher = createNotificationService(runtime.providers);
|
|
137
|
+
const result = await notificationsService.confirmAndDispatchBooking(c.get("db"), dispatcher, c.req.param("id"), await parseOptionalJsonBody(c, confirmAndDispatchBookingSchema), {
|
|
138
|
+
attachmentResolver: runtime.documentAttachmentResolver,
|
|
139
|
+
eventBus: runtime.eventBus,
|
|
140
|
+
});
|
|
141
|
+
if (result.status === "not_found")
|
|
142
|
+
return c.json({ error: "Booking not found" }, 404);
|
|
143
|
+
if (result.status === "preview") {
|
|
144
|
+
return c.json({
|
|
145
|
+
data: confirmAndDispatchBookingResultSchema.parse({
|
|
146
|
+
bookingId: result.bookingId,
|
|
147
|
+
documents: result.documents,
|
|
148
|
+
notification: null,
|
|
149
|
+
skipReason: "preview_only",
|
|
150
|
+
}),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (result.status === "skipped") {
|
|
154
|
+
return c.json({
|
|
155
|
+
data: confirmAndDispatchBookingResultSchema.parse({
|
|
156
|
+
bookingId: result.bookingId,
|
|
157
|
+
documents: result.documents,
|
|
158
|
+
notification: null,
|
|
159
|
+
skipReason: result.skipReason,
|
|
160
|
+
}),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return c.json({
|
|
164
|
+
data: confirmAndDispatchBookingResultSchema.parse({
|
|
165
|
+
bookingId: result.bookingId,
|
|
166
|
+
documents: result.documents,
|
|
167
|
+
notification: {
|
|
168
|
+
recipient: result.recipient,
|
|
169
|
+
deliveryId: result.delivery.id,
|
|
170
|
+
provider: result.delivery.provider,
|
|
171
|
+
status: result.delivery.status,
|
|
172
|
+
},
|
|
173
|
+
skipReason: null,
|
|
174
|
+
}),
|
|
175
|
+
}, 201);
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
const message = error instanceof Error ? error.message : "Confirm-and-dispatch failed";
|
|
179
|
+
return c.json({ error: message }, 400);
|
|
180
|
+
}
|
|
128
181
|
})
|
|
129
182
|
.post("/bookings/:id/send-documents", async (c) => {
|
|
130
183
|
try {
|
package/dist/schema.d.ts
CHANGED
|
@@ -1156,7 +1156,7 @@ export declare const notificationReminderRuns: import("drizzle-orm/pg-core").PgT
|
|
|
1156
1156
|
tableName: "notification_reminder_runs";
|
|
1157
1157
|
dataType: "string";
|
|
1158
1158
|
columnType: "PgEnumColumn";
|
|
1159
|
-
data: "failed" | "sent" | "processing" | "
|
|
1159
|
+
data: "failed" | "sent" | "processing" | "skipped" | "queued";
|
|
1160
1160
|
driverParam: string;
|
|
1161
1161
|
notNull: true;
|
|
1162
1162
|
hasDefault: false;
|