@voyantjs/notifications 0.13.0 → 0.14.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 CHANGED
@@ -3,7 +3,7 @@
3
3
  Notifications module for Voyant. It includes:
4
4
 
5
5
  - provider abstraction via `NotificationProvider`
6
- - first-party providers for local development and optional Resend (email)
6
+ - first-party providers for local development and Voyant Cloud (email + SMS)
7
7
  - database-backed notification templates
8
8
  - database-backed delivery logs
9
9
  - notification reminder rules and reminder runs
@@ -23,55 +23,55 @@ pnpm add @voyantjs/notifications
23
23
  ## Usage
24
24
 
25
25
  ```typescript
26
+ import { getVoyantCloudClient } from "@voyantjs/voyant-cloud"
26
27
  import { createNotificationService } from "@voyantjs/notifications"
27
28
  import { createLocalProvider } from "@voyantjs/notifications/providers/local"
28
- import { createResendProvider } from "@voyantjs/notifications/providers/resend"
29
+ import { createVoyantCloudEmailProvider } from "@voyantjs/notifications/providers/voyant-cloud-email"
30
+ import { createVoyantCloudSmsProvider } from "@voyantjs/notifications/providers/voyant-cloud-sms"
29
31
 
32
+ const cloud = getVoyantCloudClient(env)
30
33
  const notifications = createNotificationService([
31
- createLocalProvider(),
32
- createResendProvider({ apiKey: env.RESEND_API_KEY, from: "noreply@example.com" }),
34
+ createLocalProvider({ channels: ["email"] }),
35
+ createVoyantCloudEmailProvider({ client: cloud, from: "noreply@example.com" }),
36
+ createVoyantCloudSmsProvider({ client: cloud }),
33
37
  ])
34
38
 
35
- await notifications.sendWith("resend", {
39
+ await notifications.send({
36
40
  to: "user@example.com",
37
41
  channel: "email",
38
42
  template: "welcome",
39
43
  subject: "Hello",
40
44
  html: "<p>Welcome</p>",
41
- attachments: [
42
- {
43
- filename: "invoice.pdf",
44
- path: "https://cdn.example.com/invoices/invoice.pdf",
45
- contentType: "application/pdf",
46
- },
47
- ],
48
45
  })
49
46
  ```
50
47
 
51
48
  Later providers override earlier ones on channel conflict; `sendWith(name, payload)` dispatches by provider name.
52
49
 
53
- The bring-your-own path is first-class: any project can register its own `NotificationProvider`
54
- without using Resend at all.
50
+ The bring-your-own path is first-class: any project can implement
51
+ `NotificationProvider` against another transport (raw Resend, Twilio, SES, …)
52
+ and register it in place of the cloud adapters.
55
53
 
56
54
  For the Hono module:
57
55
 
58
56
  ```ts
57
+ import { getVoyantCloudClient } from "@voyantjs/voyant-cloud"
59
58
  import {
60
- createDefaultNotificationProviders,
61
59
  createNotificationsHonoModule,
60
+ createVoyantCloudEmailProvider,
61
+ createVoyantCloudSmsProvider,
62
62
  } from "@voyantjs/notifications"
63
63
 
64
64
  const notificationsModule = createNotificationsHonoModule({
65
- resolveProviders: (env) =>
66
- createDefaultNotificationProviders(env, {
67
- emailProvider: "resend",
68
- }),
65
+ resolveProviders: (env) => {
66
+ const cloud = getVoyantCloudClient(env as Record<string, unknown>)
67
+ return [
68
+ createVoyantCloudEmailProvider({ client: cloud, from: "noreply@example.com" }),
69
+ createVoyantCloudSmsProvider({ client: cloud }),
70
+ ]
71
+ },
69
72
  })
70
73
  ```
71
74
 
72
- `createDefaultNotificationProviders(env)` is intentionally local-only by default. Built-in
73
- email providers should be opted into explicitly at the app boundary.
74
-
75
75
  For scheduled reminder sweeps:
76
76
 
77
77
  ```ts
@@ -115,9 +115,9 @@ time from the current storage/runtime context.
115
115
  | `./routes` | Hono route factory |
116
116
  | `./service` | Dispatcher + database-backed notifications service |
117
117
  | `./tasks` | Reminder sweep task helpers |
118
- | `./provider-resolution` | Default local/Resend provider wiring |
119
118
  | `./providers/local` | Console sink for dev |
120
- | `./providers/resend` | Resend email provider |
119
+ | `./providers/voyant-cloud-email` | Voyant Cloud email provider |
120
+ | `./providers/voyant-cloud-sms` | Voyant Cloud SMS provider |
121
121
 
122
122
  ## License
123
123
 
package/dist/index.d.ts CHANGED
@@ -2,14 +2,12 @@ import type { HonoModule } from "@voyantjs/hono/module";
2
2
  import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
3
3
  import { type NotificationsRoutesOptions } from "./routes.js";
4
4
  export { notificationLiquidEngine, renderLiquidTemplate, } from "./liquid.js";
5
- export type { DefaultNotificationProviderOptions } from "./provider-resolution.js";
6
- export { createDefaultNotificationProviders, createResendProviderFromEnv, createTwilioProviderFromEnv, } from "./provider-resolution.js";
7
5
  export type { LocalProviderOptions } from "./providers/local.js";
8
6
  export { createLocalProvider } from "./providers/local.js";
9
- export type { ResendFetch, ResendProviderOptions, ResendRenderedEmail, } from "./providers/resend.js";
10
- export { createResendProvider } from "./providers/resend.js";
11
- export type { TwilioFetch, TwilioProviderOptions, TwilioRenderedSms } from "./providers/twilio.js";
12
- export { createTwilioProvider } from "./providers/twilio.js";
7
+ export type { VoyantCloudEmailProviderOptions, VoyantCloudEmailRendered, } from "./providers/voyant-cloud-email.js";
8
+ export { createVoyantCloudEmailProvider } from "./providers/voyant-cloud-email.js";
9
+ export type { VoyantCloudSmsProviderOptions, VoyantCloudSmsRendered, } from "./providers/voyant-cloud-sms.js";
10
+ export { createVoyantCloudSmsProvider } from "./providers/voyant-cloud-sms.js";
13
11
  export type { NotificationsRouteRuntime, NotificationsRoutesOptions } from "./routes.js";
14
12
  export { buildNotificationsRouteRuntime, createNotificationsRoutes, NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./routes.js";
15
13
  export type { NewNotificationDelivery, NewNotificationReminderRule, NewNotificationReminderRun, NewNotificationTemplate, NotificationDelivery, NotificationReminderRule, NotificationReminderRun, NotificationsHonoModule, NotificationTemplate, } from "./schema.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -3,10 +3,9 @@ import { notificationsModule } from "./schema.js";
3
3
  import { createNotificationService } from "./service.js";
4
4
  import { bookingDocumentNotificationsService } from "./service-booking-documents.js";
5
5
  export { notificationLiquidEngine, renderLiquidTemplate, } from "./liquid.js";
6
- export { createDefaultNotificationProviders, createResendProviderFromEnv, createTwilioProviderFromEnv, } from "./provider-resolution.js";
7
6
  export { createLocalProvider } from "./providers/local.js";
8
- export { createResendProvider } from "./providers/resend.js";
9
- export { createTwilioProvider } from "./providers/twilio.js";
7
+ export { createVoyantCloudEmailProvider } from "./providers/voyant-cloud-email.js";
8
+ export { createVoyantCloudSmsProvider } from "./providers/voyant-cloud-sms.js";
10
9
  export { buildNotificationsRouteRuntime, createNotificationsRoutes, NOTIFICATIONS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./routes.js";
11
10
  export { notificationChannelEnum, notificationDeliveries, notificationDeliveryStatusEnum, notificationReminderRules, notificationReminderRunStatusEnum, notificationReminderRuns, notificationReminderStatusEnum, notificationReminderTargetTypeEnum, notificationsModule, notificationTargetTypeEnum, notificationTemplateStatusEnum, notificationTemplates, } from "./schema.js";
12
11
  export { createDefaultBookingDocumentAttachment, createNotificationService, NotificationError, notificationsService, previewNotificationTemplate, renderNotificationTemplate, } from "./service.js";
@@ -0,0 +1,27 @@
1
+ import type { VoyantCloudClient } from "@voyantjs/voyant-cloud";
2
+ import type { NotificationProvider } from "../types.js";
3
+ export interface VoyantCloudEmailRendered {
4
+ subject: string;
5
+ html?: string;
6
+ text?: string;
7
+ }
8
+ export interface VoyantCloudEmailProviderOptions {
9
+ /** Cloud SDK client. Construct via `getVoyantCloudClient(env)`. */
10
+ client: VoyantCloudClient;
11
+ /** Default sender address. Payload `from` overrides. */
12
+ from: string;
13
+ /** Optional default reply-to addresses. Payload may override per-send. */
14
+ replyTo?: ReadonlyArray<string>;
15
+ /**
16
+ * Render a template id + data tuple into an email body. When omitted,
17
+ * the payload's `template` is used as the subject and `data` is
18
+ * JSON-stringified into the text body.
19
+ */
20
+ renderTemplate?: (template: string, data: unknown) => Promise<VoyantCloudEmailRendered> | VoyantCloudEmailRendered;
21
+ }
22
+ /**
23
+ * Notification provider that delivers email through the Voyant Cloud
24
+ * `/email/v1/messages` endpoint.
25
+ */
26
+ export declare function createVoyantCloudEmailProvider(options: VoyantCloudEmailProviderOptions): NotificationProvider;
27
+ //# sourceMappingURL=voyant-cloud-email.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voyant-cloud-email.d.ts","sourceRoot":"","sources":["../../src/providers/voyant-cloud-email.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAA;AAE3E,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,+BAA+B;IAC9C,mEAAmE;IACnE,MAAM,EAAE,iBAAiB,CAAA;IACzB,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,0EAA0E;IAC1E,OAAO,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC/B;;;;OAIG;IACH,cAAc,CAAC,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,KACV,OAAO,CAAC,wBAAwB,CAAC,GAAG,wBAAwB,CAAA;CAClE;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,oBAAoB,CA8BtB"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Notification provider that delivers email through the Voyant Cloud
3
+ * `/email/v1/messages` endpoint.
4
+ */
5
+ export function createVoyantCloudEmailProvider(options) {
6
+ return {
7
+ name: "voyant-cloud-email",
8
+ channels: ["email"],
9
+ async send(payload) {
10
+ if (payload.channel !== "email") {
11
+ throw new Error(`Voyant Cloud email provider only supports the "email" channel, got "${payload.channel}"`);
12
+ }
13
+ const rendered = options.renderTemplate
14
+ ? await options.renderTemplate(payload.template, payload.data)
15
+ : {
16
+ subject: payload.subject ?? payload.template,
17
+ text: JSON.stringify(payload.data ?? {}),
18
+ };
19
+ const message = await options.client.email.sendMessage({
20
+ from: payload.from ?? options.from,
21
+ to: [payload.to],
22
+ subject: payload.subject ?? rendered.subject,
23
+ html: payload.html ?? rendered.html ?? null,
24
+ text: payload.text ?? rendered.text ?? null,
25
+ replyTo: options.replyTo ? [...options.replyTo] : null,
26
+ });
27
+ return { id: message.id, provider: "voyant-cloud-email" };
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,26 @@
1
+ import type { VoyantCloudClient } from "@voyantjs/voyant-cloud";
2
+ import type { NotificationProvider } from "../types.js";
3
+ export interface VoyantCloudSmsRendered {
4
+ text: string;
5
+ }
6
+ export interface VoyantCloudSmsProviderOptions {
7
+ /** Cloud SDK client. Construct via `getVoyantCloudClient(env)`. */
8
+ client: VoyantCloudClient;
9
+ /**
10
+ * Default sender phone number. When omitted, the cloud account's default
11
+ * shared number is used (server-side selection).
12
+ */
13
+ from?: string;
14
+ /**
15
+ * Render a template id + data tuple into an SMS body. When omitted, the
16
+ * payload's `text` field is used directly, falling back to a JSON dump of
17
+ * `data`.
18
+ */
19
+ renderTemplate?: (template: string, data: unknown) => Promise<VoyantCloudSmsRendered> | VoyantCloudSmsRendered;
20
+ }
21
+ /**
22
+ * Notification provider that delivers SMS through the Voyant Cloud
23
+ * `/sms/v1/messages` endpoint.
24
+ */
25
+ export declare function createVoyantCloudSmsProvider(options: VoyantCloudSmsProviderOptions): NotificationProvider;
26
+ //# sourceMappingURL=voyant-cloud-sms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voyant-cloud-sms.d.ts","sourceRoot":"","sources":["../../src/providers/voyant-cloud-sms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAA;AAE3E,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,6BAA6B;IAC5C,mEAAmE;IACnE,MAAM,EAAE,iBAAiB,CAAA;IACzB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,KACV,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB,CAAA;CAC9D;AAED;;;GAGG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,oBAAoB,CAwBtB"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Notification provider that delivers SMS through the Voyant Cloud
3
+ * `/sms/v1/messages` endpoint.
4
+ */
5
+ export function createVoyantCloudSmsProvider(options) {
6
+ return {
7
+ name: "voyant-cloud-sms",
8
+ channels: ["sms"],
9
+ async send(payload) {
10
+ if (payload.channel !== "sms") {
11
+ throw new Error(`Voyant Cloud SMS provider only supports the "sms" channel, got "${payload.channel}"`);
12
+ }
13
+ const rendered = options.renderTemplate
14
+ ? await options.renderTemplate(payload.template, payload.data)
15
+ : { text: payload.text ?? JSON.stringify(payload.data ?? {}) };
16
+ const message = await options.client.sms.sendMessage({
17
+ to: payload.to,
18
+ from: payload.from ?? options.from ?? null,
19
+ body: payload.text ?? rendered.text,
20
+ });
21
+ return { id: message.id, provider: "voyant-cloud-sms" };
22
+ },
23
+ };
24
+ }
@@ -1,9 +1,6 @@
1
1
  import type { ExecutionLockManager } from "@voyantjs/core";
2
2
  import type { NotificationProvider } from "./types.js";
3
- export type NotificationTaskEnv = {
4
- RESEND_API_KEY?: unknown;
5
- EMAIL_FROM?: unknown;
6
- };
3
+ export type NotificationTaskEnv = Record<string, unknown>;
7
4
  export type ReminderDeliveryJob = {
8
5
  reminderRunId: string;
9
6
  };
@@ -1 +1 @@
1
- {"version":3,"file":"task-runtime.d.ts","sourceRoot":"","sources":["../src/task-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAG1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEtD,MAAM,MAAM,mBAAmB,GAAG;IAChC,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC9C,wBAAwB,CAAC,EAAE,oBAAoB,CAAA;IAC/C,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,SAAS,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC/C,wBAAwB,CAAC,EAAE,oBAAoB,CAAA;IAC/C,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,aAAa,CAAC,oBAAoB,CAAC,CAAA;CACrF,CAAA;AAED,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CASzB"}
1
+ {"version":3,"file":"task-runtime.d.ts","sourceRoot":"","sources":["../src/task-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAE1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEtD,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEzD,MAAM,MAAM,mBAAmB,GAAG;IAChC,aAAa,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC9C,wBAAwB,CAAC,EAAE,oBAAoB,CAAA;IAC/C,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,8BAA8B,GAAG;IAC3C,SAAS,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC/C,wBAAwB,CAAC,EAAE,oBAAoB,CAAA;IAC/C,uBAAuB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACrE,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,aAAa,CAAC,oBAAoB,CAAC,CAAA;CACrF,CAAA;AAED,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,8BAAmC,GAC3C,uBAAuB,CAazB"}
@@ -1,9 +1,10 @@
1
- import { createDefaultNotificationProviders } from "./provider-resolution.js";
2
1
  export function buildNotificationTaskRuntime(env, options = {}) {
2
+ const providers = options.resolveProviders?.(env) ?? options.providers;
3
+ if (!providers) {
4
+ throw new Error("buildNotificationTaskRuntime requires `providers` or `resolveProviders` — there are no default providers.");
5
+ }
3
6
  return {
4
- providers: options.resolveProviders?.(env) ??
5
- options.providers ??
6
- createDefaultNotificationProviders(env),
7
+ providers,
7
8
  reminderSweepLockManager: options.reminderSweepLockManager,
8
9
  enqueueReminderDelivery: options.enqueueReminderDelivery,
9
10
  };
package/dist/types.d.ts CHANGED
@@ -64,10 +64,12 @@ export interface NotificationResult {
64
64
  * channels and handle the actual delivery (HTTP call, SMTP, etc.).
65
65
  *
66
66
  * Built-in implementations:
67
- * - {@link createLocalProvider} — logs to console (dev)
68
- * - {@link createResendProvider} Resend email API
67
+ * - `createLocalProvider` — logs to console (dev/tests)
68
+ * - `createVoyantCloudEmailProvider`Voyant Cloud email API
69
+ * - `createVoyantCloudSmsProvider` — Voyant Cloud SMS API
69
70
  *
70
- * Additional providers can be added by implementing this interface.
71
+ * Self-hosters who want to deliver via a different provider (raw Resend,
72
+ * Twilio, SES, …) can implement this interface in their template.
71
73
  */
72
74
  export interface NotificationProvider {
73
75
  /** Unique provider name (e.g. "resend", "local", "twilio"). */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,WAAW,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAA;IACrC,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAA;IACV,yCAAyC;IACzC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,WAAW,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IACrD,mDAAmD;IACnD,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAChE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sBAAsB;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qCAAqC;IACrC,WAAW,CAAC,EAAE,YAAY,GAAG,QAAQ,CAAA;IACrC,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,EAAE,EAAE,MAAM,CAAA;IACV,yCAAyC;IACzC,OAAO,EAAE,mBAAmB,CAAA;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAA;IAChB,iDAAiD;IACjD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,WAAW,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;CACpD;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IACrD,mDAAmD;IACnD,IAAI,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CAChE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/notifications",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -36,13 +36,13 @@
36
36
  "types": "./dist/providers/local.d.ts",
37
37
  "import": "./dist/providers/local.js"
38
38
  },
39
- "./providers/resend": {
40
- "types": "./dist/providers/resend.d.ts",
41
- "import": "./dist/providers/resend.js"
39
+ "./providers/voyant-cloud-email": {
40
+ "types": "./dist/providers/voyant-cloud-email.d.ts",
41
+ "import": "./dist/providers/voyant-cloud-email.js"
42
42
  },
43
- "./provider-resolution": {
44
- "types": "./dist/provider-resolution.d.ts",
45
- "import": "./dist/provider-resolution.js"
43
+ "./providers/voyant-cloud-sms": {
44
+ "types": "./dist/providers/voyant-cloud-sms.d.ts",
45
+ "import": "./dist/providers/voyant-cloud-sms.js"
46
46
  }
47
47
  },
48
48
  "dependencies": {
@@ -50,12 +50,13 @@
50
50
  "hono": "^4.12.10",
51
51
  "liquidjs": "^10.24.0",
52
52
  "zod": "^4.3.6",
53
- "@voyantjs/bookings": "0.13.0",
54
- "@voyantjs/core": "0.13.0",
55
- "@voyantjs/db": "0.13.0",
56
- "@voyantjs/finance": "0.13.0",
57
- "@voyantjs/hono": "0.13.0",
58
- "@voyantjs/legal": "0.13.0"
53
+ "@voyantjs/bookings": "0.14.0",
54
+ "@voyantjs/core": "0.14.0",
55
+ "@voyantjs/db": "0.14.0",
56
+ "@voyantjs/finance": "0.14.0",
57
+ "@voyantjs/hono": "0.14.0",
58
+ "@voyantjs/legal": "0.14.0",
59
+ "@voyantjs/voyant-cloud": "0.14.0"
59
60
  },
60
61
  "devDependencies": {
61
62
  "typescript": "^6.0.2",
@@ -1,19 +0,0 @@
1
- import type { NotificationProvider } from "./types.js";
2
- type NotificationProviderEnv = {
3
- RESEND_API_KEY?: unknown;
4
- EMAIL_FROM?: unknown;
5
- TWILIO_ACCOUNT_SID?: unknown;
6
- TWILIO_AUTH_TOKEN?: unknown;
7
- TWILIO_SMS_FROM?: unknown;
8
- };
9
- export interface DefaultNotificationProviderOptions {
10
- includeLocal?: boolean;
11
- emailProvider?: "resend" | null;
12
- smsProvider?: "twilio" | null;
13
- customProviders?: ReadonlyArray<NotificationProvider>;
14
- }
15
- export declare function createResendProviderFromEnv(env: NotificationProviderEnv): NotificationProvider | null;
16
- export declare function createTwilioProviderFromEnv(env: NotificationProviderEnv): NotificationProvider | null;
17
- export declare function createDefaultNotificationProviders(env: NotificationProviderEnv, options?: DefaultNotificationProviderOptions): NotificationProvider[];
18
- export {};
19
- //# sourceMappingURL=provider-resolution.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"provider-resolution.d.ts","sourceRoot":"","sources":["../src/provider-resolution.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEtD,KAAK,uBAAuB,GAAG;IAC7B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED,MAAM,WAAW,kCAAkC;IACjD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,aAAa,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC/B,WAAW,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAA;IAC7B,eAAe,CAAC,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;CACtD;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,uBAAuB,+BAcvE;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,uBAAuB,+BAiBvE;AAED,wBAAgB,kCAAkC,CAChD,GAAG,EAAE,uBAAuB,EAC5B,OAAO,GAAE,kCAAuC,0BA2BjD"}
@@ -1,52 +0,0 @@
1
- import { createLocalProvider } from "./providers/local.js";
2
- import { createResendProvider } from "./providers/resend.js";
3
- import { createTwilioProvider } from "./providers/twilio.js";
4
- export function createResendProviderFromEnv(env) {
5
- if (typeof env.RESEND_API_KEY === "string" &&
6
- env.RESEND_API_KEY &&
7
- typeof env.EMAIL_FROM === "string" &&
8
- env.EMAIL_FROM) {
9
- return createResendProvider({
10
- apiKey: env.RESEND_API_KEY,
11
- from: env.EMAIL_FROM,
12
- });
13
- }
14
- return null;
15
- }
16
- export function createTwilioProviderFromEnv(env) {
17
- if (typeof env.TWILIO_ACCOUNT_SID === "string" &&
18
- env.TWILIO_ACCOUNT_SID &&
19
- typeof env.TWILIO_AUTH_TOKEN === "string" &&
20
- env.TWILIO_AUTH_TOKEN &&
21
- typeof env.TWILIO_SMS_FROM === "string" &&
22
- env.TWILIO_SMS_FROM) {
23
- return createTwilioProvider({
24
- accountSid: env.TWILIO_ACCOUNT_SID,
25
- authToken: env.TWILIO_AUTH_TOKEN,
26
- from: env.TWILIO_SMS_FROM,
27
- });
28
- }
29
- return null;
30
- }
31
- export function createDefaultNotificationProviders(env, options = {}) {
32
- const providers = [];
33
- if (options.includeLocal !== false) {
34
- providers.push(createLocalProvider());
35
- }
36
- if (options.emailProvider === "resend") {
37
- const resend = createResendProviderFromEnv(env);
38
- if (resend) {
39
- providers.push(resend);
40
- }
41
- }
42
- if (options.smsProvider === "twilio") {
43
- const twilio = createTwilioProviderFromEnv(env);
44
- if (twilio) {
45
- providers.push(twilio);
46
- }
47
- }
48
- if (options.customProviders?.length) {
49
- providers.push(...options.customProviders);
50
- }
51
- return providers;
52
- }
@@ -1,52 +0,0 @@
1
- import type { NotificationProvider } from "../types.js";
2
- /**
3
- * Minimal `fetch` shape the Resend provider depends on. Works with the
4
- * global `fetch` in Node 18+ / workers / browsers, and can be stubbed in
5
- * tests.
6
- */
7
- export type ResendFetch = (input: string, init: {
8
- method: string;
9
- headers: Record<string, string>;
10
- body: string;
11
- }) => Promise<{
12
- ok: boolean;
13
- status: number;
14
- json: () => Promise<unknown>;
15
- text: () => Promise<string>;
16
- }>;
17
- /**
18
- * Rendered email template. At least one of `html` or `text` should be set.
19
- */
20
- export interface ResendRenderedEmail {
21
- subject: string;
22
- html?: string;
23
- text?: string;
24
- }
25
- /**
26
- * Options for {@link createResendProvider}.
27
- */
28
- export interface ResendProviderOptions {
29
- /** Resend API key. */
30
- apiKey: string;
31
- /** Default sender address. Payload `from` overrides. */
32
- from: string;
33
- /** Override the Resend API base URL. Defaults to `https://api.resend.com`. */
34
- baseUrl?: string;
35
- /** Override `fetch` (e.g. in tests). Defaults to global `fetch`. */
36
- fetch?: ResendFetch;
37
- /**
38
- * Render a template id + data tuple into an email body. When omitted,
39
- * the payload's `template` is used as the subject and `data` is
40
- * JSON-stringified into the text body.
41
- */
42
- renderTemplate?: (template: string, data: unknown) => Promise<ResendRenderedEmail> | ResendRenderedEmail;
43
- }
44
- /**
45
- * Create a notification provider that delivers email through the Resend HTTP
46
- * API (https://resend.com/docs/api-reference/emails/send-email).
47
- *
48
- * Only the `"email"` channel is supported; attempting to send to any other
49
- * channel throws.
50
- */
51
- export declare function createResendProvider(options: ResendProviderOptions): NotificationProvider;
52
- //# sourceMappingURL=resend.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/providers/resend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAA;AAE3E;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;CACb,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5B,CAAC,CAAA;AAEF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oEAAoE;IACpE,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB;;;;OAIG;IACH,cAAc,CAAC,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,KACV,OAAO,CAAC,mBAAmB,CAAC,GAAG,mBAAmB,CAAA;CACxD;AAMD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAqDzF"}
@@ -1,58 +0,0 @@
1
- /**
2
- * Create a notification provider that delivers email through the Resend HTTP
3
- * API (https://resend.com/docs/api-reference/emails/send-email).
4
- *
5
- * Only the `"email"` channel is supported; attempting to send to any other
6
- * channel throws.
7
- */
8
- export function createResendProvider(options) {
9
- const baseUrl = options.baseUrl ?? "https://api.resend.com";
10
- const fetchImpl = options.fetch ?? globalThis.fetch;
11
- return {
12
- name: "resend",
13
- channels: ["email"],
14
- async send(payload) {
15
- if (payload.channel !== "email") {
16
- throw new Error(`Resend provider only supports the "email" channel, got "${payload.channel}"`);
17
- }
18
- if (!fetchImpl) {
19
- throw new Error("Resend provider requires a fetch implementation");
20
- }
21
- const rendered = options.renderTemplate
22
- ? await options.renderTemplate(payload.template, payload.data)
23
- : {
24
- subject: payload.subject ?? payload.template,
25
- text: JSON.stringify(payload.data ?? {}),
26
- };
27
- const body = {
28
- from: payload.from ?? options.from,
29
- to: payload.to,
30
- subject: payload.subject ?? rendered.subject,
31
- html: payload.html ?? rendered.html,
32
- text: payload.text ?? rendered.text,
33
- attachments: payload.attachments?.map((attachment) => ({
34
- filename: attachment.filename,
35
- content: attachment.contentBase64,
36
- path: attachment.path,
37
- content_type: attachment.contentType,
38
- disposition: attachment.disposition,
39
- content_id: attachment.contentId,
40
- })),
41
- };
42
- const response = await fetchImpl(`${baseUrl}/emails`, {
43
- method: "POST",
44
- headers: {
45
- Authorization: `Bearer ${options.apiKey}`,
46
- "Content-Type": "application/json",
47
- },
48
- body: JSON.stringify(body),
49
- });
50
- if (!response.ok) {
51
- const text = await response.text().catch(() => "");
52
- throw new Error(`Resend send failed (${response.status}): ${text}`);
53
- }
54
- const data = (await response.json());
55
- return { id: data.id, provider: "resend" };
56
- },
57
- };
58
- }
@@ -1,24 +0,0 @@
1
- import type { NotificationProvider } from "../types.js";
2
- export type TwilioFetch = (input: string, init: {
3
- method: string;
4
- headers: Record<string, string>;
5
- body: string;
6
- }) => Promise<{
7
- ok: boolean;
8
- status: number;
9
- json: () => Promise<unknown>;
10
- text: () => Promise<string>;
11
- }>;
12
- export interface TwilioRenderedSms {
13
- text: string;
14
- }
15
- export interface TwilioProviderOptions {
16
- accountSid: string;
17
- authToken: string;
18
- from: string;
19
- baseUrl?: string;
20
- fetch?: TwilioFetch;
21
- renderTemplate?: (template: string, data: unknown) => Promise<TwilioRenderedSms> | TwilioRenderedSms;
22
- }
23
- export declare function createTwilioProvider(options: TwilioProviderOptions): NotificationProvider;
24
- //# sourceMappingURL=twilio.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"twilio.d.ts","sourceRoot":"","sources":["../../src/providers/twilio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,aAAa,CAAA;AAE3E,MAAM,MAAM,WAAW,GAAG,CACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;CACb,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5B,CAAC,CAAA;AAEF,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,WAAW,CAAA;IACnB,cAAc,CAAC,EAAE,CACf,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,KACV,OAAO,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAAA;CACpD;AA0BD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CA4CzF"}
@@ -1,48 +0,0 @@
1
- function toBase64(value) {
2
- if (typeof btoa === "function") {
3
- return btoa(value);
4
- }
5
- const globals = globalThis;
6
- if (globals.Buffer) {
7
- return globals.Buffer.from(value).toString("base64");
8
- }
9
- throw new Error("Twilio provider requires a base64 encoder");
10
- }
11
- export function createTwilioProvider(options) {
12
- const baseUrl = options.baseUrl ?? "https://api.twilio.com/2010-04-01";
13
- const fetchImpl = options.fetch ?? globalThis.fetch;
14
- return {
15
- name: "twilio",
16
- channels: ["sms"],
17
- async send(payload) {
18
- if (payload.channel !== "sms") {
19
- throw new Error(`Twilio provider only supports the "sms" channel, got "${payload.channel}"`);
20
- }
21
- if (!fetchImpl) {
22
- throw new Error("Twilio provider requires a fetch implementation");
23
- }
24
- const rendered = options.renderTemplate
25
- ? await options.renderTemplate(payload.template, payload.data)
26
- : { text: payload.text ?? JSON.stringify(payload.data ?? {}) };
27
- const body = new URLSearchParams({
28
- To: payload.to,
29
- From: payload.from ?? options.from,
30
- Body: payload.text ?? rendered.text,
31
- });
32
- const response = await fetchImpl(`${baseUrl}/Accounts/${options.accountSid}/Messages.json`, {
33
- method: "POST",
34
- headers: {
35
- Authorization: `Basic ${toBase64(`${options.accountSid}:${options.authToken}`)}`,
36
- "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
37
- },
38
- body: body.toString(),
39
- });
40
- if (!response.ok) {
41
- const text = await response.text().catch(() => "");
42
- throw new Error(`Twilio send failed (${response.status}): ${text}`);
43
- }
44
- const data = (await response.json());
45
- return { id: data.sid, provider: "twilio" };
46
- },
47
- };
48
- }