@decocms/apps 0.25.2 → 0.26.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decocms/apps",
3
- "version": "0.25.2",
3
+ "version": "0.26.0",
4
4
  "type": "module",
5
5
  "description": "Deco commerce apps for TanStack Start - Shopify, VTEX, commerce types, analytics utils",
6
6
  "exports": {
@@ -37,7 +37,11 @@
37
37
  "./vtex/hooks/*": "./vtex/hooks/*.ts",
38
38
  "./vtex/inline-loaders/workflowProducts": "./vtex/inline-loaders/workflowProducts.ts",
39
39
  "./vtex/middleware": "./vtex/middleware.ts",
40
- "./vtex/invoke": "./vtex/invoke.ts"
40
+ "./vtex/invoke": "./vtex/invoke.ts",
41
+ "./resend": "./resend/index.ts",
42
+ "./resend/client": "./resend/client.ts",
43
+ "./resend/types": "./resend/types.ts",
44
+ "./resend/actions/send": "./resend/actions/send.ts"
41
45
  },
42
46
  "scripts": {
43
47
  "typecheck": "tsc --noEmit",
@@ -68,6 +72,7 @@
68
72
  "commerce/",
69
73
  "shopify/",
70
74
  "vtex/",
75
+ "resend/",
71
76
  "!**/__tests__/"
72
77
  ],
73
78
  "engines": {
@@ -0,0 +1,57 @@
1
+ import { getResendConfig } from "../client";
2
+ import type { CreateEmailOptions, CreateEmailResponse } from "../types";
3
+
4
+ /**
5
+ * Send an email via Resend API.
6
+ *
7
+ * ```ts
8
+ * import { sendEmail } from "@decocms/apps/resend/actions/send";
9
+ *
10
+ * const result = await sendEmail({
11
+ * subject: "Hello",
12
+ * html: "<p>World</p>",
13
+ * });
14
+ * ```
15
+ *
16
+ * Fields not provided fall back to the defaults set in `configureResend()`.
17
+ */
18
+ export async function sendEmail(
19
+ payload: Partial<CreateEmailOptions> & { subject?: string; html?: string },
20
+ ): Promise<CreateEmailResponse> {
21
+ const config = getResendConfig();
22
+
23
+ const body: CreateEmailOptions = {
24
+ from: payload.from ?? config.emailFrom ?? "Contact <onboarding@resend.dev>",
25
+ to: payload.to ?? config.emailTo ?? [],
26
+ subject: payload.subject ?? config.subject ?? "No subject",
27
+ ...(payload.bcc && { bcc: payload.bcc }),
28
+ ...(payload.cc && { cc: payload.cc }),
29
+ ...(payload.reply_to && { reply_to: payload.reply_to }),
30
+ ...(payload.html && { html: payload.html }),
31
+ ...(payload.text && { text: payload.text }),
32
+ ...(payload.headers && { headers: payload.headers }),
33
+ };
34
+
35
+ const response = await fetch("https://api.resend.com/emails", {
36
+ method: "POST",
37
+ headers: {
38
+ Authorization: `Bearer ${config.apiKey}`,
39
+ "Content-Type": "application/json",
40
+ },
41
+ body: JSON.stringify(body),
42
+ });
43
+
44
+ const data = await response.json();
45
+
46
+ if (!response.ok) {
47
+ return {
48
+ data: null,
49
+ error: data,
50
+ };
51
+ }
52
+
53
+ return {
54
+ data,
55
+ error: null,
56
+ };
57
+ }
@@ -0,0 +1,30 @@
1
+ import type { ResendConfig } from "./types";
2
+
3
+ let _config: ResendConfig | null = null;
4
+
5
+ /**
6
+ * Configure the Resend client. Call once in your site's setup.ts.
7
+ *
8
+ * ```ts
9
+ * import { configureResend } from "@decocms/apps/resend/client";
10
+ *
11
+ * configureResend({
12
+ * apiKey: process.env.RESEND_API_KEY!,
13
+ * emailFrom: "Contact <hello@example.com>",
14
+ * emailTo: ["team@example.com"],
15
+ * subject: "Contact form submission",
16
+ * });
17
+ * ```
18
+ */
19
+ export function configureResend(config: ResendConfig) {
20
+ _config = config;
21
+ }
22
+
23
+ export function getResendConfig(): ResendConfig {
24
+ if (!_config) {
25
+ throw new Error(
26
+ "Resend not configured. Call configureResend() in setup.ts before using Resend actions.",
27
+ );
28
+ }
29
+ return _config;
30
+ }
@@ -0,0 +1,10 @@
1
+ export { sendEmail } from "./actions/send";
2
+ export { configureResend, getResendConfig } from "./client";
3
+ export type {
4
+ CreateEmailOptions,
5
+ CreateEmailResponse,
6
+ CreateEmailResponseSuccess,
7
+ ErrorResponse,
8
+ ResendConfig,
9
+ ResendErrorCodeKey,
10
+ } from "./types";
@@ -0,0 +1,54 @@
1
+ export const RESEND_ERROR_CODES_BY_KEY = {
2
+ missing_required_field: 422,
3
+ invalid_access: 422,
4
+ invalid_parameter: 422,
5
+ invalid_region: 422,
6
+ rate_limit_exceeded: 429,
7
+ missing_api_key: 401,
8
+ invalid_api_Key: 403,
9
+ invalid_from_address: 403,
10
+ validation_error: 403,
11
+ not_found: 404,
12
+ method_not_allowed: 405,
13
+ application_error: 500,
14
+ internal_server_error: 500,
15
+ } as const;
16
+
17
+ export type ResendErrorCodeKey = keyof typeof RESEND_ERROR_CODES_BY_KEY;
18
+
19
+ export interface ErrorResponse {
20
+ message: string;
21
+ name: ResendErrorCodeKey;
22
+ }
23
+
24
+ export interface CreateEmailResponseSuccess {
25
+ /** The ID of the newly created email. */
26
+ id: string;
27
+ }
28
+
29
+ export interface CreateEmailResponse {
30
+ data: CreateEmailResponseSuccess | null;
31
+ error: ErrorResponse | null;
32
+ }
33
+
34
+ export interface CreateEmailOptions {
35
+ from?: string;
36
+ to: string | string[];
37
+ subject: string;
38
+ bcc?: string | string[];
39
+ cc?: string | string[];
40
+ reply_to?: string | string[];
41
+ html?: string;
42
+ text?: string;
43
+ headers?: Record<string, string>;
44
+ }
45
+
46
+ export interface ResendConfig {
47
+ apiKey: string;
48
+ /** Default sender — e.g. "Contact <onboarding@resend.dev>" */
49
+ emailFrom?: string;
50
+ /** Default recipients */
51
+ emailTo?: string[];
52
+ /** Default subject */
53
+ subject?: string;
54
+ }