n8n-nodes-resend 2.6.2 → 2.6.3

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.
@@ -5,8 +5,8 @@ declare class ResendApi implements ICredentialType {
5
5
  displayName: string;
6
6
  documentationUrl: string;
7
7
  icon: {
8
- readonly light: 'file:resend-icon-black.svg';
9
- readonly dark: 'file:resend-icon-white.svg';
8
+ readonly light: "file:resend-icon-black.svg";
9
+ readonly dark: "file:resend-icon-white.svg";
10
10
  };
11
11
  properties: INodeProperties[];
12
12
  authenticate: IAuthenticateGeneric;
@@ -6,8 +6,8 @@ declare class ResendOAuth2Api implements ICredentialType {
6
6
  displayName: string;
7
7
  documentationUrl: string;
8
8
  icon: {
9
- readonly light: 'file:resend-icon-black.svg';
10
- readonly dark: 'file:resend-icon-white.svg';
9
+ readonly light: "file:resend-icon-black.svg";
10
+ readonly dark: "file:resend-icon-white.svg";
11
11
  };
12
12
  properties: INodeProperties[];
13
13
  }
@@ -4,7 +4,7 @@ declare class ResendWebhookSigningSecretApi implements ICredentialType {
4
4
  name: string;
5
5
  displayName: string;
6
6
  documentationUrl: string;
7
- icon: 'file:resend.svg';
7
+ icon: "file:resend.svg";
8
8
  properties: INodeProperties[];
9
9
  }
10
10
  //#endregion
@@ -37,7 +37,6 @@ declare class Resend implements INodeType {
37
37
  webhookResponse?: undefined;
38
38
  workflowData?: undefined;
39
39
  } | {
40
- noWebhookResponse?: undefined;
41
40
  webhookResponse: undefined;
42
41
  workflowData: {
43
42
  json: {
@@ -46,8 +45,8 @@ declare class Resend implements INodeType {
46
45
  };
47
46
  };
48
47
  }[][];
49
- } | {
50
48
  noWebhookResponse?: undefined;
49
+ } | {
51
50
  webhookResponse: undefined;
52
51
  workflowData: {
53
52
  json: {
@@ -56,6 +55,7 @@ declare class Resend implements INodeType {
56
55
  };
57
56
  };
58
57
  }[][];
58
+ noWebhookResponse?: undefined;
59
59
  }>;
60
60
  execute: typeof router;
61
61
  }
@@ -54,13 +54,13 @@ var Resend = class {
54
54
  name: "authentication",
55
55
  type: "options",
56
56
  options: [{
57
- name: "OAuth2 (Recommended)",
58
- value: "oAuth2",
59
- description: "Sign in with your Resend account — n8n registers itself as an OAuth client automatically, no API key needed"
60
- }, {
61
57
  name: "API Key",
62
58
  value: "apiKey",
63
59
  description: "Manually paste a Resend API key"
60
+ }, {
61
+ name: "OAuth2 (Recommended)",
62
+ value: "oAuth2",
63
+ description: "Sign in with your Resend account — n8n registers itself as an OAuth client automatically, no API key needed"
64
64
  }],
65
65
  default: "oAuth2"
66
66
  },
@@ -1,7 +1,19 @@
1
- import { INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from "n8n-workflow";
1
+ import { ICredentialTestFunctions, ICredentialsDecrypted, IHookFunctions, INodeCredentialTestResult, INodeType, INodeTypeDescription, IWebhookFunctions, IWebhookResponseData } from "n8n-workflow";
2
2
  //#region nodes/Resend/ResendTrigger.node.d.ts
3
3
  declare class ResendTrigger implements INodeType {
4
4
  description: INodeTypeDescription;
5
+ methods: {
6
+ credentialTest: {
7
+ resendWebhookSigningSecretTest(this: ICredentialTestFunctions, credential: ICredentialsDecrypted): Promise<INodeCredentialTestResult>;
8
+ };
9
+ };
10
+ webhookMethods: {
11
+ default: {
12
+ checkExists(this: IHookFunctions): Promise<boolean>;
13
+ create(this: IHookFunctions): Promise<boolean>;
14
+ delete(this: IHookFunctions): Promise<boolean>;
15
+ };
16
+ };
5
17
  webhook(this: IWebhookFunctions): Promise<IWebhookResponseData>;
6
18
  }
7
19
  //#endregion
@@ -32,6 +32,31 @@ async function verifySvixSignature(payload, svixId, svixTimestamp, svixSignature
32
32
  }
33
33
  throw new n8n_workflow.NodeOperationError(node, "Invalid webhook signature");
34
34
  }
35
+ async function resendApiRequest(method, endpoint, body) {
36
+ return await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
37
+ url: `https://api.resend.com${endpoint}`,
38
+ method,
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ "User-Agent": "n8n-nodes-resend"
42
+ },
43
+ json: true,
44
+ ...body ? { body } : {}
45
+ });
46
+ }
47
+ function isNotFoundError(error) {
48
+ var _ref, _e$httpCode, _e$response;
49
+ const e = error;
50
+ const code = (_ref = (_e$httpCode = e === null || e === void 0 ? void 0 : e.httpCode) !== null && _e$httpCode !== void 0 ? _e$httpCode : e === null || e === void 0 ? void 0 : e.statusCode) !== null && _ref !== void 0 ? _ref : e === null || e === void 0 || (_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.status;
51
+ return String(code) === "404";
52
+ }
53
+ async function hasResendApiCredential(context) {
54
+ try {
55
+ return Boolean(await context.getCredentials("resendApi"));
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
35
60
  var ResendTrigger = class {
36
61
  constructor() {
37
62
  this.description = {
@@ -48,10 +73,14 @@ var ResendTrigger = class {
48
73
  defaults: { name: "Resend Trigger" },
49
74
  credentials: [{
50
75
  name: "resendWebhookSigningSecretApi",
51
- required: true
76
+ required: false,
77
+ testedBy: "resendWebhookSigningSecretTest"
78
+ }, {
79
+ name: "resendApi",
80
+ required: false
52
81
  }],
53
82
  triggerPanel: {
54
- header: "Copy the webhook URL below and paste it into your Resend dashboard webhook configuration.",
83
+ header: "Add a Resend API credential to register this webhook automatically, or copy the webhook URL below and paste it into your Resend dashboard webhook configuration.",
55
84
  executionsHelp: {
56
85
  inactive: "Webhooks have two modes: test and production.<br><br><b>Use test mode while you build your workflow</b>. Click the \"Listen for test event\" button, then paste the test URL into your Resend webhook configuration. The webhook executions will show up in the editor.<br><br><b>Use production mode to run your workflow automatically</b>. Activate the workflow, then paste the production URL into your Resend webhook configuration. These executions will show up in the executions list, but not in the editor.",
57
86
  active: "Webhooks have two modes: test and production.<br><br><b>Use test mode while you build your workflow</b>. Click the \"Listen for test event\" button, then paste the test URL into your Resend webhook configuration. The webhook executions will show up in the editor.<br><br><b>Use production mode to run your workflow automatically</b>. Since the workflow is activated, you can paste the production URL into your Resend webhook configuration. These executions will show up in the executions list, but not in the editor."
@@ -152,16 +181,92 @@ var ResendTrigger = class {
152
181
  }
153
182
  ],
154
183
  description: "Select the Resend event types to listen for"
155
- }]
184
+ }],
185
+ usableAsTool: true
156
186
  };
187
+ this.methods = { credentialTest: { async resendWebhookSigningSecretTest(credential) {
188
+ var _credential$data;
189
+ const secret = typeof ((_credential$data = credential.data) === null || _credential$data === void 0 ? void 0 : _credential$data.webhookSigningSecret) === "string" ? credential.data.webhookSigningSecret.trim() : "";
190
+ if (!secret.startsWith("whsec_")) return {
191
+ status: "Error",
192
+ message: "Signing secret must start with \"whsec_\". Copy it from the webhook settings page in your Resend dashboard."
193
+ };
194
+ const encoded = secret.slice(6);
195
+ if (!encoded || Buffer.from(encoded, "base64").length === 0) return {
196
+ status: "Error",
197
+ message: "Signing secret is not valid base64"
198
+ };
199
+ return {
200
+ status: "OK",
201
+ message: "Signing secret format is valid"
202
+ };
203
+ } } };
204
+ this.webhookMethods = { default: {
205
+ async checkExists() {
206
+ if (!await hasResendApiCredential(this)) return true;
207
+ const webhookData = this.getWorkflowStaticData("node");
208
+ if (!webhookData.webhookId) return false;
209
+ try {
210
+ await resendApiRequest.call(this, "GET", `/webhooks/${webhookData.webhookId}`);
211
+ return true;
212
+ } catch (error) {
213
+ if (isNotFoundError(error)) {
214
+ delete webhookData.webhookId;
215
+ delete webhookData.webhookSigningSecret;
216
+ return false;
217
+ }
218
+ throw new n8n_workflow.NodeApiError(this.getNode(), error);
219
+ }
220
+ },
221
+ async create() {
222
+ var _ref2, _response$data, _ref3, _response$data2;
223
+ if (!await hasResendApiCredential(this)) return true;
224
+ const webhookUrl = this.getNodeWebhookUrl("default");
225
+ const events = this.getNodeParameter("events");
226
+ const response = await resendApiRequest.call(this, "POST", "/webhooks", {
227
+ endpoint: webhookUrl,
228
+ events
229
+ });
230
+ const webhookId = (_ref2 = response.id) !== null && _ref2 !== void 0 ? _ref2 : (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.id;
231
+ if (!webhookId) throw new n8n_workflow.NodeOperationError(this.getNode(), "Resend did not return a webhook ID when creating the webhook");
232
+ const signingSecret = (_ref3 = response.signing_secret) !== null && _ref3 !== void 0 ? _ref3 : (_response$data2 = response.data) === null || _response$data2 === void 0 ? void 0 : _response$data2.signing_secret;
233
+ const webhookData = this.getWorkflowStaticData("node");
234
+ webhookData.webhookId = webhookId;
235
+ if (signingSecret) webhookData.webhookSigningSecret = signingSecret;
236
+ return true;
237
+ },
238
+ async delete() {
239
+ const webhookData = this.getWorkflowStaticData("node");
240
+ if (!webhookData.webhookId) return true;
241
+ if (await hasResendApiCredential(this)) try {
242
+ await resendApiRequest.call(this, "DELETE", `/webhooks/${webhookData.webhookId}`);
243
+ } catch (error) {
244
+ if (!isNotFoundError(error)) throw new n8n_workflow.NodeApiError(this.getNode(), error);
245
+ }
246
+ delete webhookData.webhookId;
247
+ delete webhookData.webhookSigningSecret;
248
+ return true;
249
+ }
250
+ } };
157
251
  }
158
252
  async webhook() {
159
253
  const bodyData = this.getBodyData();
160
254
  const headers = this.getHeaderData();
161
255
  const request = this.getRequestObject();
162
256
  const subscribedEvents = this.getNodeParameter("events");
163
- const webhookSigningSecret = (await this.getCredentials("resendWebhookSigningSecretApi")).webhookSigningSecret;
164
- if (webhookSigningSecret && webhookSigningSecret.trim() !== "") try {
257
+ const webhookData = this.getWorkflowStaticData("node");
258
+ let webhookSigningSecret = typeof webhookData.webhookSigningSecret === "string" ? webhookData.webhookSigningSecret : "";
259
+ if (!webhookSigningSecret) try {
260
+ var _ref4;
261
+ webhookSigningSecret = (_ref4 = (await this.getCredentials("resendWebhookSigningSecretApi")).webhookSigningSecret) !== null && _ref4 !== void 0 ? _ref4 : "";
262
+ } catch {
263
+ webhookSigningSecret = "";
264
+ }
265
+ if (!webhookSigningSecret || webhookSigningSecret.trim() === "") {
266
+ this.getResponseObject().status(401).json({ error: "Webhook signing secret is not configured" });
267
+ return { noWebhookResponse: true };
268
+ }
269
+ try {
165
270
  var _rawBody;
166
271
  const rawBody = (_rawBody = request.rawBody) !== null && _rawBody !== void 0 ? _rawBody : request.body;
167
272
  const payload = typeof rawBody === "string" ? rawBody : Buffer.isBuffer(rawBody) ? rawBody.toString("utf8") : JSON.stringify(bodyData !== null && bodyData !== void 0 ? bodyData : {});
@@ -173,7 +278,7 @@ var ResendTrigger = class {
173
278
  return { noWebhookResponse: true };
174
279
  }
175
280
  await verifySvixSignature(payload, svixId, svixTimestamp, svixSignature, webhookSigningSecret, this.getNode());
176
- } catch (_error) {
281
+ } catch {
177
282
  this.getResponseObject().status(401).json({ error: "Invalid webhook signature" });
178
283
  return { noWebhookResponse: true };
179
284
  }
@@ -19,7 +19,7 @@ const operations = [{
19
19
  name: "Disconnect",
20
20
  value: "disconnect",
21
21
  description: "Revoke the connected Resend OAuth2 grant, ending the connection to your Resend account",
22
- action: "Disconnect the Resend account"
22
+ action: "Disconnect the resend account"
23
23
  }],
24
24
  default: "disconnect"
25
25
  }];
@@ -20,10 +20,10 @@ const description = [require_nodes_Resend_utils_dynamicFields.createDynamicIdFie
20
20
  } }
21
21
  })];
22
22
  async function execute(index) {
23
- var _data;
23
+ var _ref;
24
24
  const domainId = require_nodes_Resend_utils_dynamicFields.resolveDynamicIdValue(this, "domainId", index);
25
25
  const response = await require_nodes_Resend_transport_index.apiRequest.call(this, "GET", `/domains/${encodeURIComponent(domainId)}/tracking-domains`);
26
- const executionData = ((_data = response === null || response === void 0 ? void 0 : response.data) !== null && _data !== void 0 ? _data : []).map((item, _i) => ({
26
+ const executionData = ((_ref = response.data) !== null && _ref !== void 0 ? _ref : []).map((item) => ({
27
27
  json: item,
28
28
  pairedItem: { item: index }
29
29
  }));
@@ -461,7 +461,7 @@ async function execute(index) {
461
461
  if (additionalOptions.idempotencyKey) requestHeaders["Idempotency-Key"] = additionalOptions.idempotencyKey;
462
462
  let response;
463
463
  try {
464
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
464
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
465
465
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails`,
466
466
  method: "POST",
467
467
  headers: requestHeaders,
@@ -3,6 +3,6 @@ declare namespace sendAndWait_operation_d_exports {
3
3
  export { SEND_AND_WAIT_OPERATION, description, execute };
4
4
  }
5
5
  declare const description: INodeProperties[];
6
- declare function execute(this: IExecuteFunctions, _index: number): Promise<INodeExecutionData[]>;
6
+ declare function execute(this: IExecuteFunctions): Promise<INodeExecutionData[]>;
7
7
  //#endregion
8
8
  export { SEND_AND_WAIT_OPERATION, description, execute, sendAndWait_operation_d_exports };
@@ -29,7 +29,7 @@ const description = require_nodes_Resend_utils_sendAndWait_utils.getSendAndWaitP
29
29
  defaultApproveLabel: "Approve",
30
30
  defaultDisapproveLabel: "Decline"
31
31
  });
32
- async function execute(_index) {
32
+ async function execute() {
33
33
  const email = require_nodes_Resend_utils_sendAndWait_utils.createEmail(this);
34
34
  await require_nodes_Resend_utils_sendAndWait_utils.sendResendEmail(this, email);
35
35
  const waitTill = require_nodes_Resend_utils_sendAndWait_utils.configureWaitTillDate(this);
@@ -48,7 +48,8 @@ const description = [{
48
48
  displayName: "Headers",
49
49
  name: "headers",
50
50
  type: "fixedCollection",
51
- default: {},
51
+ default: { headers: [] },
52
+ typeOptions: { multipleValues: true },
52
53
  options: [{
53
54
  name: "headers",
54
55
  displayName: "Header",
@@ -74,11 +75,20 @@ const description = [{
74
75
  default: "",
75
76
  description: "Email address where replies should be sent. Can be different from the sender address."
76
77
  },
78
+ {
79
+ displayName: "Scheduled At",
80
+ name: "scheduledAt",
81
+ type: "string",
82
+ default: "",
83
+ placeholder: "in 1 hour",
84
+ description: "Schedule this email to be sent at a future time. Accepts natural language like \"in 1 hour\" or ISO 8601 format \"2024-12-25T09:00:00Z\". Each email in the batch can be scheduled independently."
85
+ },
77
86
  {
78
87
  displayName: "Tags",
79
88
  name: "tags",
80
89
  type: "fixedCollection",
81
- default: {},
90
+ default: { tags: [] },
91
+ typeOptions: { multipleValues: true },
82
92
  options: [{
83
93
  name: "tags",
84
94
  displayName: "Tag",
@@ -170,7 +180,8 @@ const description = [{
170
180
  displayName: "Template Variables",
171
181
  name: "templateVariables",
172
182
  type: "fixedCollection",
173
- default: {},
183
+ default: { variables: [] },
184
+ typeOptions: { multipleValues: true },
174
185
  description: "Key-value pairs to replace template placeholders. Keys must match the template variable names.",
175
186
  options: [{
176
187
  name: "variables",
@@ -298,6 +309,8 @@ async function execute(index) {
298
309
  });
299
310
  const topicId = additionalOptions.topicId;
300
311
  if (topicId) emailObj.topic_id = topicId;
312
+ const scheduledAt = additionalOptions.scheduledAt;
313
+ if (scheduledAt) emailObj.scheduled_at = scheduledAt;
301
314
  if (contentType === "template") {
302
315
  if (!email.templateId) throw new n8n_workflow.NodeOperationError(this.getNode(), "Template Name or ID is required for batch emails when using templates.", { itemIndex: index });
303
316
  if (email.html || email.text) throw new n8n_workflow.NodeOperationError(this.getNode(), "HTML/Text Content cannot be used when sending batch emails with templates.", { itemIndex: index });
@@ -322,7 +335,7 @@ async function execute(index) {
322
335
  if (batchOptions.idempotency_key) headers["Idempotency-Key"] = batchOptions.idempotency_key;
323
336
  let response;
324
337
  try {
325
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
338
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
326
339
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails/batch`,
327
340
  method: "POST",
328
341
  headers,
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_nodes_Resend_transport_index = require("../transport/index.js");
2
3
  const require_nodes_Resend_actions_account_index = require("./account/index.js");
3
4
  const require_nodes_Resend_actions_broadcast_index = require("./broadcast/index.js");
4
5
  const require_nodes_Resend_actions_contact_index = require("./contact/index.js");
@@ -54,7 +55,7 @@ async function router() {
54
55
  });
55
56
  continue;
56
57
  }
57
- throw error;
58
+ require_nodes_Resend_transport_index.handleResendApiError(this.getNode(), error, i);
58
59
  }
59
60
  return [returnData];
60
61
  }
@@ -32,11 +32,11 @@ const description = [{
32
32
  description: "The unique identifier of the workflow run"
33
33
  }];
34
34
  async function execute(index) {
35
- var _data;
35
+ var _ref;
36
36
  const workflowId = this.getNodeParameter("workflowId", index);
37
37
  const runId = this.getNodeParameter("runId", index);
38
38
  const response = await require_nodes_Resend_transport_index.apiRequest.call(this, "GET", `/workflows/${encodeURIComponent(workflowId)}/runs/${encodeURIComponent(runId)}/steps`);
39
- const executionData = ((_data = response === null || response === void 0 ? void 0 : response.data) !== null && _data !== void 0 ? _data : []).map((item) => ({
39
+ const executionData = ((_ref = response.data) !== null && _ref !== void 0 ? _ref : []).map((item) => ({
40
40
  json: item,
41
41
  pairedItem: { item: index }
42
42
  }));
@@ -20,10 +20,10 @@ const description = [{
20
20
  description: "The unique identifier of the workflow to list runs for"
21
21
  }];
22
22
  async function execute(index) {
23
- var _data;
23
+ var _ref;
24
24
  const workflowId = this.getNodeParameter("workflowId", index);
25
25
  const response = await require_nodes_Resend_transport_index.apiRequest.call(this, "GET", `/workflows/${encodeURIComponent(workflowId)}/runs`);
26
- const executionData = ((_data = response === null || response === void 0 ? void 0 : response.data) !== null && _data !== void 0 ? _data : []).map((item) => ({
26
+ const executionData = ((_ref = response.data) !== null && _ref !== void 0 ? _ref : []).map((item) => ({
27
27
  json: item,
28
28
  pairedItem: { item: index }
29
29
  }));
@@ -9,7 +9,7 @@ async function loadDropdownOptions(loadOptionsFunctions, endpoint) {
9
9
  var _response$data;
10
10
  let response;
11
11
  try {
12
- response = await loadOptionsFunctions.helpers.httpRequestWithAuthentication.call(loadOptionsFunctions, "resendApi", {
12
+ response = await loadOptionsFunctions.helpers.httpRequestWithAuthentication.call(loadOptionsFunctions, require_nodes_Resend_transport_index.getCredentialType(loadOptionsFunctions), {
13
13
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}${endpoint}`,
14
14
  method: "GET",
15
15
  qs: { limit: 100 },
@@ -50,7 +50,7 @@ async function getTemplateVariables() {
50
50
  if (normalizedTemplateId.startsWith("={{") || normalizedTemplateId.includes("{{")) return [];
51
51
  let response;
52
52
  try {
53
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
53
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
54
54
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/templates/${encodeURIComponent(normalizedTemplateId)}`,
55
55
  method: "GET",
56
56
  json: true
@@ -85,7 +85,7 @@ async function getContacts() {
85
85
  var _response$data2;
86
86
  let response;
87
87
  try {
88
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
88
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
89
89
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/contacts`,
90
90
  method: "GET",
91
91
  qs: { limit: 100 },
@@ -114,7 +114,7 @@ async function getWebhooks() {
114
114
  var _response$data3;
115
115
  let response;
116
116
  try {
117
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
117
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
118
118
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/webhooks`,
119
119
  method: "GET",
120
120
  qs: { limit: 100 },
@@ -142,7 +142,7 @@ async function getEmails() {
142
142
  var _response$data4;
143
143
  let response;
144
144
  try {
145
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
145
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
146
146
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails`,
147
147
  method: "GET",
148
148
  qs: { limit: 100 },
@@ -174,7 +174,7 @@ async function getReceivedEmails() {
174
174
  var _response$data5;
175
175
  let response;
176
176
  try {
177
- response = await this.helpers.httpRequestWithAuthentication.call(this, "resendApi", {
177
+ response = await this.helpers.httpRequestWithAuthentication.call(this, require_nodes_Resend_transport_index.getCredentialType(this), {
178
178
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails/receiving`,
179
179
  method: "GET",
180
180
  qs: { limit: 100 },
@@ -1,7 +1,8 @@
1
- import { IDataObject, IExecuteFunctions, IHttpRequestMethods, INode, INodeExecutionData } from "n8n-workflow";
1
+ import { IDataObject, IExecuteFunctions, IHttpRequestMethods, ILoadOptionsFunctions, INode, INodeExecutionData } from "n8n-workflow";
2
2
  //#region nodes/Resend/transport/index.d.ts
3
3
  declare function handleResendApiError(node: INode, error: unknown, itemIndex?: number): never;
4
4
  declare const RESEND_API_BASE = "https://api.resend.com";
5
+ declare function getCredentialType(context: IExecuteFunctions | ILoadOptionsFunctions): string;
5
6
  declare function apiRequest(this: IExecuteFunctions, method: IHttpRequestMethods, endpoint: string, body?: IDataObject | IDataObject[], qs?: IDataObject): Promise<IDataObject>;
6
7
  declare function requestList(this: IExecuteFunctions, endpoint: string, extraQs?: IDataObject): Promise<IDataObject[]>;
7
8
  declare function normalizeEmailList(value: string | string[] | undefined): string[];
@@ -31,4 +32,4 @@ interface ListOperation {
31
32
  }
32
33
  declare function createOperationRouter(itemOps: Record<string, ItemOperation>, listOps?: Record<string, ListOperation>): (this: IExecuteFunctions, index: number, operation: string) => Promise<INodeExecutionData[]>;
33
34
  //#endregion
34
- export { RESEND_API_BASE, apiRequest, assertHttpsEndpoint, buildTemplateSendVariables, createListExecutionData, createOperationRouter, handleResendApiError, normalizeEmailList, parseTemplateVariables, requestList };
35
+ export { RESEND_API_BASE, apiRequest, assertHttpsEndpoint, buildTemplateSendVariables, createListExecutionData, createOperationRouter, getCredentialType, handleResendApiError, normalizeEmailList, parseTemplateVariables, requestList };
@@ -133,7 +133,10 @@ function handleResendApiError(node, error, itemIndex) {
133
133
  }
134
134
  const RESEND_API_BASE = "https://api.resend.com";
135
135
  function getCredentialType(context) {
136
- return context.getNodeParameter("authentication", 0, "apiKey") === "oAuth2" ? "resendOAuth2Api" : "resendApi";
136
+ let authentication;
137
+ if ("getInputData" in context) authentication = context.getNodeParameter("authentication", 0, "apiKey");
138
+ else authentication = context.getNodeParameter("authentication", "apiKey");
139
+ return authentication === "oAuth2" ? "resendOAuth2Api" : "resendApi";
137
140
  }
138
141
  async function apiRequest(method, endpoint, body, qs) {
139
142
  const options = {
@@ -265,6 +268,7 @@ exports.assertHttpsEndpoint = assertHttpsEndpoint;
265
268
  exports.buildTemplateSendVariables = buildTemplateSendVariables;
266
269
  exports.createListExecutionData = createListExecutionData;
267
270
  exports.createOperationRouter = createOperationRouter;
271
+ exports.getCredentialType = getCredentialType;
268
272
  exports.handleResendApiError = handleResendApiError;
269
273
  exports.normalizeEmailList = normalizeEmailList;
270
274
  exports.parseTemplateVariables = parseTemplateVariables;
@@ -1,28 +1,28 @@
1
1
  import { IExecuteFunctions, INodeProperties } from "n8n-workflow";
2
2
  //#region nodes/Resend/utils/dynamicFields.d.ts
3
3
  declare const RESOURCE_METHOD_MAP: {
4
- readonly broadcast: 'getBroadcasts';
5
- readonly contact: 'getContacts';
6
- readonly domain: 'getDomains';
7
- readonly webhook: 'getWebhooks';
8
- readonly contactProperty: 'getContactProperties';
9
- readonly email: 'getEmails';
10
- readonly receivedEmail: 'getReceivedEmails';
11
- readonly segment: 'getSegments';
12
- readonly template: 'getTemplates';
13
- readonly topic: 'getTopics';
4
+ readonly broadcast: "getBroadcasts";
5
+ readonly contact: "getContacts";
6
+ readonly domain: "getDomains";
7
+ readonly webhook: "getWebhooks";
8
+ readonly contactProperty: "getContactProperties";
9
+ readonly email: "getEmails";
10
+ readonly receivedEmail: "getReceivedEmails";
11
+ readonly segment: "getSegments";
12
+ readonly template: "getTemplates";
13
+ readonly topic: "getTopics";
14
14
  };
15
15
  declare const RESOURCE_DISPLAY_MAP: {
16
- readonly broadcast: 'Broadcast';
17
- readonly contact: 'Contact';
18
- readonly domain: 'Domain';
19
- readonly webhook: 'Webhook';
20
- readonly contactProperty: 'Contact Property';
21
- readonly email: 'Email';
22
- readonly receivedEmail: 'Received Email';
23
- readonly segment: 'Segment';
24
- readonly template: 'Template';
25
- readonly topic: 'Topic';
16
+ readonly broadcast: "Broadcast";
17
+ readonly contact: "Contact";
18
+ readonly domain: "Domain";
19
+ readonly webhook: "Webhook";
20
+ readonly contactProperty: "Contact Property";
21
+ readonly email: "Email";
22
+ readonly receivedEmail: "Received Email";
23
+ readonly segment: "Segment";
24
+ readonly template: "Template";
25
+ readonly topic: "Topic";
26
26
  };
27
27
  interface DynamicIdFieldOptions {
28
28
  fieldName: string;
@@ -12,7 +12,6 @@ declare function sendAndWaitWebhook(this: IWebhookFunctions): Promise<{
12
12
  webhookResponse?: undefined;
13
13
  workflowData?: undefined;
14
14
  } | {
15
- noWebhookResponse?: undefined;
16
15
  webhookResponse: undefined;
17
16
  workflowData: {
18
17
  json: {
@@ -21,8 +20,8 @@ declare function sendAndWaitWebhook(this: IWebhookFunctions): Promise<{
21
20
  };
22
21
  };
23
22
  }[][];
24
- } | {
25
23
  noWebhookResponse?: undefined;
24
+ } | {
26
25
  webhookResponse: undefined;
27
26
  workflowData: {
28
27
  json: {
@@ -31,6 +30,7 @@ declare function sendAndWaitWebhook(this: IWebhookFunctions): Promise<{
31
30
  };
32
31
  };
33
32
  }[][];
33
+ noWebhookResponse?: undefined;
34
34
  }>;
35
35
  declare function getSendAndWaitConfig(context: IExecuteFunctions): SendAndWaitConfig;
36
36
  declare function createButton(url: string, label: string, style: string): string;
@@ -36,6 +36,22 @@ function getSendAndWaitProperties(targetProperties, resource = "email", addition
36
36
  value: "secondary"
37
37
  }]
38
38
  };
39
+ const approveLabelProperty = {
40
+ displayName: "Approve Button Label",
41
+ name: "approveLabel",
42
+ type: "string",
43
+ default: "Approve",
44
+ displayOptions: { show: { approvalType: ["single", "double"] } }
45
+ };
46
+ if (options === null || options === void 0 ? void 0 : options.defaultApproveLabel) approveLabelProperty.default = options.defaultApproveLabel;
47
+ const disapproveLabelProperty = {
48
+ displayName: "Disapprove Button Label",
49
+ name: "disapproveLabel",
50
+ type: "string",
51
+ default: "Decline",
52
+ displayOptions: { show: { approvalType: ["double"] } }
53
+ };
54
+ if (options === null || options === void 0 ? void 0 : options.defaultDisapproveLabel) disapproveLabelProperty.default = options.defaultDisapproveLabel;
39
55
  const approvalOptionsValues = [
40
56
  {
41
57
  displayName: "Type of Approval",
@@ -51,26 +67,14 @@ function getSendAndWaitProperties(targetProperties, resource = "email", addition
51
67
  value: "double"
52
68
  }]
53
69
  },
54
- {
55
- displayName: "Approve Button Label",
56
- name: "approveLabel",
57
- type: "string",
58
- default: (options === null || options === void 0 ? void 0 : options.defaultApproveLabel) || "Approve",
59
- displayOptions: { show: { approvalType: ["single", "double"] } }
60
- },
70
+ approveLabelProperty,
61
71
  ...[(options === null || options === void 0 ? void 0 : options.noButtonStyle) ? {} : {
62
72
  ...buttonStyle,
63
73
  displayName: "Approve Button Style",
64
74
  name: "buttonApprovalStyle",
65
75
  displayOptions: { show: { approvalType: ["single", "double"] } }
66
76
  }],
67
- {
68
- displayName: "Disapprove Button Label",
69
- name: "disapproveLabel",
70
- type: "string",
71
- default: (options === null || options === void 0 ? void 0 : options.defaultDisapproveLabel) || "Decline",
72
- displayOptions: { show: { approvalType: ["double"] } }
73
- },
77
+ disapproveLabelProperty,
74
78
  ...[(options === null || options === void 0 ? void 0 : options.noButtonStyle) ? {} : {
75
79
  ...buttonStyle,
76
80
  displayName: "Disapprove Button Style",
@@ -456,7 +460,7 @@ async function sendResendEmail(context, email) {
456
460
  if (email.bcc) requestBody.bcc = email.bcc;
457
461
  if (email.replyTo) requestBody.reply_to = email.replyTo;
458
462
  try {
459
- await context.helpers.httpRequestWithAuthentication.call(context, "resendApi", {
463
+ await context.helpers.httpRequestWithAuthentication.call(context, require_nodes_Resend_transport_index.getCredentialType(context), {
460
464
  url: `${require_nodes_Resend_transport_index.RESEND_API_BASE}/emails`,
461
465
  method: "POST",
462
466
  headers: { "Content-Type": "application/json" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-resend",
3
- "version": "2.6.2",
3
+ "version": "2.6.3",
4
4
  "description": "Resend integration for n8n: Email, Broadcasts, Templates, Domains, Contacts, Segments, Topics, Webhooks, Workflows, Events, and more",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",
@@ -48,12 +48,14 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@biomejs/biome": "~2.5.3",
51
+ "@n8n/node-cli": "^0.39.3",
51
52
  "@types/jest": "^30.0.0",
52
53
  "@types/node": "^26.1.1",
53
54
  "auto-changelog": "^2.6.0",
55
+ "eslint": "9.29.0",
54
56
  "rimraf": "^6.1.3",
55
57
  "tsdown": "^0.22.4",
56
- "typescript": "^7.0.2",
58
+ "typescript": "~5.9.3",
57
59
  "unrun": "^0.3.1"
58
60
  },
59
61
  "peerDependencies": {
@@ -66,6 +68,7 @@
66
68
  "format": "biome format --write nodes credentials",
67
69
  "lint": "biome check",
68
70
  "lint:fix": "biome check --write",
71
+ "lint:n8n": "n8n-node lint",
69
72
  "typecheck": "tsc --noEmit"
70
73
  }
71
74
  }