n8n-nodes-befroosh 0.7.0 → 0.8.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
@@ -13,7 +13,8 @@ apps/n8n-nodes/
13
13
  │ ├── BatabjamSmsApi.credentials.ts
14
14
  │ ├── MeliPayamakSmsApi.credentials.ts
15
15
  │ ├── BatabjamAboardSmsApi.credentials.ts
16
- └── BefrooshAnalyticsApi.credentials.ts # baseUrl + signingSecret + apiKey
16
+ ├── BefrooshAnalyticsApi.credentials.ts # baseUrl + signingSecret + apiKey
17
+ │ └── BefrooshEmailApi.credentials.ts # SMTP host/port/user/pass/fromAddress (mirrors core)
17
18
  ├── lib/
18
19
  │ └── signature.ts # local HMAC verify (self-contained) + tests
19
20
  ├── nodes/
@@ -22,7 +23,8 @@ apps/n8n-nodes/
22
23
  │ ├── BefrooshReplay/ # schedule/cancel/status replay calls
23
24
  │ ├── BefrooshAssignAction/ # create + assign an admin task
24
25
  │ ├── BefrooshWait/ # pause on an offset schedule
25
- └── BefrooshStatus/ # route by user status (10 outputs)
26
+ ├── BefrooshStatus/ # route by user status (10 outputs)
27
+ │ └── BefEmailOrSms/ # subscription-alert via email or SMS
26
28
  ├── scripts/copy-icons.mjs # copies .svg/.png into dist after tsc
27
29
  ├── tsconfig.json
28
30
  └── package.json # the "n8n" field registers nodes + credentials
@@ -0,0 +1,7 @@
1
+ import { ICredentialType, INodeProperties } from 'n8n-workflow';
2
+ export declare class BefrooshEmailApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ properties: INodeProperties[];
7
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BefrooshEmailApi = void 0;
4
+ class BefrooshEmailApi {
5
+ constructor() {
6
+ this.name = 'befrooshEmailApi';
7
+ this.displayName = 'Befroosh Email API';
8
+ this.documentationUrl = 'https://befroosh.com';
9
+ // Pure-data credential (no test/authenticate/preSend/loadOptions) — matches the
10
+ // existing SMS/Analytics credentials and avoids the editor credential-save hang on
11
+ // the self-hosted box (import via `n8n import:credentials` CLI). Mirrors core's own
12
+ // SMTP setup exactly (apps/core/src/app.module.ts's MailerModule.forRootAsync):
13
+ // MAIL_HOST/MAIL_PORT/MAIL_USER/MAIL_PASS/MAIL_ADDRESS, secure:false + TLS with
14
+ // rejectUnauthorized:false (both hardcoded there, not env-driven — same here).
15
+ this.properties = [
16
+ {
17
+ displayName: 'SMTP Host',
18
+ name: 'host',
19
+ type: 'string',
20
+ default: '',
21
+ required: true,
22
+ description: 'Matches MAIL_HOST in core',
23
+ },
24
+ {
25
+ displayName: 'SMTP Port',
26
+ name: 'port',
27
+ type: 'number',
28
+ default: 587,
29
+ required: true,
30
+ description: 'Matches MAIL_PORT in core',
31
+ },
32
+ {
33
+ displayName: 'SMTP User',
34
+ name: 'user',
35
+ type: 'string',
36
+ default: '',
37
+ required: true,
38
+ description: 'Matches MAIL_USER in core',
39
+ },
40
+ {
41
+ displayName: 'SMTP Password',
42
+ name: 'password',
43
+ type: 'string',
44
+ typeOptions: { password: true },
45
+ default: '',
46
+ required: true,
47
+ description: 'Matches MAIL_PASS in core',
48
+ },
49
+ {
50
+ displayName: 'From Address',
51
+ name: 'fromAddress',
52
+ type: 'string',
53
+ default: '',
54
+ required: true,
55
+ description: 'Mailbox address mail is sent from — matches MAIL_ADDRESS in core',
56
+ },
57
+ {
58
+ displayName: 'From Name',
59
+ name: 'fromName',
60
+ type: 'string',
61
+ default: 'بفروش',
62
+ description: 'Display name on the From header — core hardcodes "بفروش"',
63
+ },
64
+ ];
65
+ }
66
+ }
67
+ exports.BefrooshEmailApi = BefrooshEmailApi;
68
+ //# sourceMappingURL=BefrooshEmailApi.credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BefrooshEmailApi.credentials.js","sourceRoot":"","sources":["../../credentials/BefrooshEmailApi.credentials.ts"],"names":[],"mappings":";;;AAEA,MAAa,gBAAgB;IAA7B;QACE,SAAI,GAAG,kBAAkB,CAAC;QAE1B,gBAAW,GAAG,oBAAoB,CAAC;QAEnC,qBAAgB,GAAG,sBAAsB,CAAC;QAE1C,gFAAgF;QAChF,mFAAmF;QACnF,oFAAoF;QACpF,gFAAgF;QAChF,gFAAgF;QAChF,+EAA+E;QAC/E,eAAU,GAAsB;YAC9B;gBACE,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2BAA2B;aACzC;YACD;gBACE,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,GAAG;gBACZ,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2BAA2B;aACzC;YACD;gBACE,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2BAA2B;aACzC;YACD;gBACE,WAAW,EAAE,eAAe;gBAC5B,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC/B,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,2BAA2B;aACzC;YACD;gBACE,WAAW,EAAE,cAAc;gBAC3B,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,kEAAkE;aAChF;YACD;gBACE,WAAW,EAAE,WAAW;gBACxB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,OAAO;gBAChB,WAAW,EAAE,0DAA0D;aACxE;SACF,CAAC;IACJ,CAAC;CAAA;AA/DD,4CA+DC"}
@@ -0,0 +1,4 @@
1
+ /** Split a recipient field that may hold several comma/newline separated numbers. */
2
+ export declare function toRecipients(raw: string): string[];
3
+ /** Render a provider response body for display without dumping megabytes. */
4
+ export declare function describeSmsBody(body: unknown): string;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ // Pure helpers with zero `n8n-workflow` import — kept separate from smsProviders.ts
3
+ // so they stay unit-testable with plain `node --test`. Importing `n8n-workflow`'s
4
+ // runtime values (NodeApiError/NodeOperationError, as smsProviders.ts does) breaks
5
+ // standalone `node --test` in this environment (its installed ESM build has an
6
+ // unresolvable internal import, `dist/esm/logger-proxy` — a bug in that package,
7
+ // not this one); every existing *.test.ts file in this package avoids the problem
8
+ // the same way, by testing only n8n-workflow-free logic.
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.toRecipients = toRecipients;
11
+ exports.describeSmsBody = describeSmsBody;
12
+ /** Split a recipient field that may hold several comma/newline separated numbers. */
13
+ function toRecipients(raw) {
14
+ return raw
15
+ .split(/[\n,]/)
16
+ .map((s) => s.trim())
17
+ .filter(Boolean);
18
+ }
19
+ /** Render a provider response body for display without dumping megabytes. */
20
+ function describeSmsBody(body) {
21
+ if (body === undefined || body === null || body === '')
22
+ return '(empty response body)';
23
+ const text = typeof body === 'string' ? body : JSON.stringify(body);
24
+ return text.length > 1500 ? `${text.slice(0, 1500)}…` : text;
25
+ }
26
+ //# sourceMappingURL=smsFormat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smsFormat.js","sourceRoot":"","sources":["../../lib/smsFormat.ts"],"names":[],"mappings":";AAAA,oFAAoF;AACpF,kFAAkF;AAClF,mFAAmF;AACnF,+EAA+E;AAC/E,iFAAiF;AACjF,kFAAkF;AAClF,yDAAyD;;AAGzD,oCAKC;AAGD,0CAIC;AAbD,qFAAqF;AACrF,SAAgB,YAAY,CAAC,GAAW;IACtC,OAAO,GAAG;SACP,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC;AAED,6EAA6E;AAC7E,SAAgB,eAAe,CAAC,IAAa;IAC3C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,uBAAuB,CAAC;IACvF,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACpE,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { IExecuteFunctions } from 'n8n-workflow';
2
+ import { toRecipients, describeSmsBody } from './smsFormat';
3
+ export type SmsProvider = 'notrika' | 'batabjam' | 'melipayamak' | 'batabjamAboard';
4
+ export interface SmsSendResult {
5
+ statusCode: number;
6
+ body: unknown;
7
+ }
8
+ export { toRecipients, describeSmsBody };
9
+ /**
10
+ * Sends a plain free-text message (not OTP) via the given provider, fetching that
11
+ * provider's own credential from the node's credential store. Mirrors
12
+ * `BefrooshSms.node.ts`'s `sendMessage` branch field-for-field (request shapes,
13
+ * headers, the Batabjam Aboard login→bearer→send handshake).
14
+ */
15
+ export declare function sendSmsMessage(ctx: IExecuteFunctions, provider: SmsProvider, to: string, message: string, itemIndex: number): Promise<SmsSendResult>;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.describeSmsBody = exports.toRecipients = void 0;
4
+ exports.sendSmsMessage = sendSmsMessage;
5
+ const n8n_workflow_1 = require("n8n-workflow");
6
+ const smsFormat_1 = require("./smsFormat");
7
+ Object.defineProperty(exports, "toRecipients", { enumerable: true, get: function () { return smsFormat_1.toRecipients; } });
8
+ Object.defineProperty(exports, "describeSmsBody", { enumerable: true, get: function () { return smsFormat_1.describeSmsBody; } });
9
+ async function sendRequest(ctx, provider, step, options, itemIndex) {
10
+ try {
11
+ const res = (await ctx.helpers.httpRequest({
12
+ ...options,
13
+ returnFullResponse: true,
14
+ ignoreHttpStatusErrors: true,
15
+ }));
16
+ return { statusCode: res.statusCode, body: res.body };
17
+ }
18
+ catch (error) {
19
+ throw new n8n_workflow_1.NodeApiError(ctx.getNode(), error, {
20
+ message: `${provider} · ${step}: request could not be sent`,
21
+ description: error.message,
22
+ itemIndex,
23
+ });
24
+ }
25
+ }
26
+ /**
27
+ * Sends a plain free-text message (not OTP) via the given provider, fetching that
28
+ * provider's own credential from the node's credential store. Mirrors
29
+ * `BefrooshSms.node.ts`'s `sendMessage` branch field-for-field (request shapes,
30
+ * headers, the Batabjam Aboard login→bearer→send handshake).
31
+ */
32
+ async function sendSmsMessage(ctx, provider, to, message, itemIndex) {
33
+ var _a;
34
+ if (provider === 'notrika') {
35
+ const c = await ctx.getCredentials('notrikaSmsApi', itemIndex);
36
+ return sendRequest(ctx, 'Notrika', 'send', {
37
+ method: 'POST',
38
+ url: 'https://api.notrikaco.ir/api/v1/messages/send/template',
39
+ headers: {
40
+ 'X-Api-Key': c.apiKey,
41
+ Accept: 'application/json',
42
+ 'Cache-Control': 'no-cache',
43
+ },
44
+ body: {
45
+ senderNumber: c.senderNumber,
46
+ recipientNumber: to,
47
+ templateId: c.messageTemplateId,
48
+ parameters: [{ name: 'message', value: message }],
49
+ },
50
+ json: true,
51
+ }, itemIndex);
52
+ }
53
+ if (provider === 'batabjam') {
54
+ const c = await ctx.getCredentials('batabjamSmsApi', itemIndex);
55
+ return sendRequest(ctx, 'Batabjam', 'send', {
56
+ method: 'POST',
57
+ url: 'https://smsapi.pishgamrayan.com/Messages/Send',
58
+ headers: { Authorization: c.token },
59
+ body: {
60
+ senderNumber: c.senderNumber,
61
+ recipientNumbers: (0, smsFormat_1.toRecipients)(to),
62
+ messageBodies: [message],
63
+ },
64
+ json: true,
65
+ }, itemIndex);
66
+ }
67
+ if (provider === 'melipayamak') {
68
+ const c = await ctx.getCredentials('meliPayamakSmsApi', itemIndex);
69
+ const enc = encodeURIComponent;
70
+ // Same GET-only legacy ASMX constraint as BefrooshSms.node.ts — see that
71
+ // file's comment on this exact call for the full rationale.
72
+ const url = `https://sms.toolzi.ir/post/Send.asmx/SendSimpleSMS2?username=${enc(c.username)}` +
73
+ `&password=${enc(c.password)}&to=${enc(to)}&from=${enc(c.senderNumber)}` +
74
+ `&text=${enc(message)}&isFlash=false`;
75
+ return sendRequest(ctx, 'MeliPayamak', 'send', { method: 'GET', url }, itemIndex);
76
+ }
77
+ // batabjamAboard: login → bearer token → bulk send
78
+ const c = await ctx.getCredentials('batabjamAboardSmsApi', itemIndex);
79
+ const login = await sendRequest(ctx, 'Batabjam Aboard', 'login', {
80
+ method: 'POST',
81
+ url: 'https://panel.batabjam.com/api/login.php',
82
+ body: { username: c.username, password: c.password },
83
+ json: true,
84
+ }, itemIndex);
85
+ if (login.statusCode >= 400)
86
+ return login;
87
+ const token = (_a = login.body) === null || _a === void 0 ? void 0 : _a.token;
88
+ if (!token) {
89
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Batabjam Aboard login did not return a token. Response: ${(0, smsFormat_1.describeSmsBody)(login.body)}`, { itemIndex });
90
+ }
91
+ return sendRequest(ctx, 'Batabjam Aboard', 'send', {
92
+ method: 'POST',
93
+ url: 'https://panel.batabjam.com/api/send-bulk-sms.php',
94
+ headers: { Authorization: `Bearer ${token}` },
95
+ body: { numbers: (0, smsFormat_1.toRecipients)(to), message },
96
+ json: true,
97
+ }, itemIndex);
98
+ }
99
+ //# sourceMappingURL=smsProviders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smsProviders.js","sourceRoot":"","sources":["../../lib/smsProviders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare const SUBSCRIPTION_ALERT_EMAIL_SUBJECT = "\u06CC\u0627\u062F\u0622\u0648\u0631\u06CC \u062A\u0645\u062F\u06CC\u062F \u0627\u0634\u062A\u0631\u0627\u06A9 \u0628\u0641\u0631\u0648\u0634";
2
+ /** Plain-text SMS body — verbatim copy of SmsHelper.subscriptionExpirationAlert. */
3
+ export declare function subscriptionAlertSmsText(firstname: string, instagramUsername: string, expireDate: Date): string;
4
+ /** HTML email body — verbatim copy of subscriptionExpirationEmailTemplate. */
5
+ export declare function subscriptionAlertEmailHtml(firstname: string, instagramUsername: string | undefined, expireDate: Date): string;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ // Intentional copy of the "subscription expiry" alert content — the same one core
3
+ // sends today via SmsHelper.subscriptionExpirationAlert (apps/core/src/providers/sms/
4
+ // helpers/sms.helper.ts) and subscriptionExpirationEmailTemplate (packages/common/src/
5
+ // utils/emailTemplates.ts, called from apps/core/src/notification/notification.templates.ts's
6
+ // SUBSCRIPTION_EXPIRY case). Not imported from either — this package is self-contained/
7
+ // published (CLAUDE.md §10) — so keep this in sync by hand if that copy changes.
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SUBSCRIPTION_ALERT_EMAIL_SUBJECT = void 0;
10
+ exports.subscriptionAlertSmsText = subscriptionAlertSmsText;
11
+ exports.subscriptionAlertEmailHtml = subscriptionAlertEmailHtml;
12
+ exports.SUBSCRIPTION_ALERT_EMAIL_SUBJECT = 'یادآوری تمدید اشتراک بفروش';
13
+ function escapeHtml(s) {
14
+ return String(s)
15
+ .replace(/&/g, '&amp;')
16
+ .replace(/</g, '&lt;')
17
+ .replace(/>/g, '&gt;')
18
+ .replace(/"/g, '&quot;')
19
+ .replace(/'/g, '&#39;');
20
+ }
21
+ function formatFaDate(date) {
22
+ return date.toLocaleDateString('fa-IR');
23
+ }
24
+ /** Plain-text SMS body — verbatim copy of SmsHelper.subscriptionExpirationAlert. */
25
+ function subscriptionAlertSmsText(firstname, instagramUsername, expireDate) {
26
+ const formattedDate = formatFaDate(expireDate);
27
+ return `${firstname} عزیز
28
+ اشتراک شما در بفروش برای پیج ${instagramUsername} تا ${formattedDate} فعال است.
29
+
30
+ برای ادامه استفاده از دایرکت هوشمند، اشتراک خود را تمدید کنید.
31
+
32
+ my.befroosh.app`;
33
+ }
34
+ /** HTML email body — verbatim copy of subscriptionExpirationEmailTemplate. */
35
+ function subscriptionAlertEmailHtml(firstname, instagramUsername, expireDate) {
36
+ const formattedDate = formatFaDate(expireDate);
37
+ const igLine = instagramUsername
38
+ ? `<p style="margin:0 0 8px;font-size:15px;color:#333333;">پیج: <strong>${escapeHtml(instagramUsername)}</strong></p>`
39
+ : '';
40
+ return `<!DOCTYPE html>
41
+ <html dir="rtl" lang="fa">
42
+ <head>
43
+ <meta charset="UTF-8">
44
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
45
+ </head>
46
+ <body style="margin:0;padding:0;background:#f5f5f5;font-family:Tahoma,Arial,sans-serif;">
47
+ <table width="100%" cellpadding="0" cellspacing="0" style="background:#f5f5f5;padding:32px 0;">
48
+ <tr>
49
+ <td align="center">
50
+ <table width="480" cellpadding="0" cellspacing="0" style="background:#ffffff;border-radius:8px;overflow:hidden;">
51
+ <tr>
52
+ <td style="background:#4f46e5;padding:20px;text-align:center;">
53
+ <span style="color:#ffffff;font-size:24px;font-weight:bold;">بفروش</span>
54
+ </td>
55
+ </tr>
56
+ <tr>
57
+ <td style="padding:32px;text-align:right;">
58
+ <p style="margin:0 0 16px;font-size:16px;color:#333333;font-weight:bold;">یادآوری تمدید اشتراک</p>
59
+ <p style="margin:0 0 16px;font-size:15px;color:#333333;line-height:1.8;">${escapeHtml(firstname)} عزیز،</p>
60
+ ${igLine}
61
+ <p style="margin:0 0 16px;font-size:15px;color:#333333;line-height:1.8;">
62
+ اشتراک شما در بفروش تا تاریخ <strong>${escapeHtml(formattedDate)}</strong> فعال است.
63
+ </p>
64
+ <p style="margin:0;font-size:14px;color:#666666;line-height:1.8;">
65
+ برای ادامه استفاده از دایرکت هوشمند، اشتراک خود را تمدید کنید.
66
+ </p>
67
+ </td>
68
+ </tr>
69
+ <tr>
70
+ <td style="padding:16px 32px;text-align:center;">
71
+ <a href="https://my.befroosh.app" style="display:inline-block;background:#4f46e5;color:#ffffff;text-decoration:none;padding:12px 28px;border-radius:6px;font-size:15px;">تمدید اشتراک</a>
72
+ </td>
73
+ </tr>
74
+ <tr>
75
+ <td style="background:#f9f9f9;padding:16px;text-align:center;border-top:1px solid #eeeeee;">
76
+ <span style="font-size:12px;color:#aaaaaa;">تیم پشتیبانی بفروش</span>
77
+ </td>
78
+ </tr>
79
+ </table>
80
+ </td>
81
+ </tr>
82
+ </table>
83
+ </body>
84
+ </html>`;
85
+ }
86
+ //# sourceMappingURL=subscriptionAlert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptionAlert.js","sourceRoot":"","sources":["../../lib/subscriptionAlert.ts"],"names":[],"mappings":";AAAA,kFAAkF;AAClF,sFAAsF;AACtF,uFAAuF;AACvF,8FAA8F;AAC9F,wFAAwF;AACxF,iFAAiF;;;AAkBjF,4DAYC;AAGD,gEAsDC;AArFY,QAAA,gCAAgC,GAAG,4BAA4B,CAAC;AAE7E,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,MAAM,CAAC,CAAC,CAAC;SACb,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,YAAY,CAAC,IAAU;IAC9B,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,oFAAoF;AACpF,SAAgB,wBAAwB,CACtC,SAAiB,EACjB,iBAAyB,EACzB,UAAgB;IAEhB,MAAM,aAAa,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC/C,OAAO,GAAG,SAAS;+BACU,iBAAiB,OAAO,aAAa;;;;gBAIpD,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,SAAgB,0BAA0B,CACxC,SAAiB,EACjB,iBAAqC,EACrC,UAAgB;IAEhB,MAAM,aAAa,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,iBAAiB;QAC9B,CAAC,CAAC,wEAAwE,UAAU,CAAC,iBAAiB,CAAC,eAAe;QACtH,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;;;;;;;;;;;;;;;;;;;yFAmBgF,UAAU,CAAC,SAAS,CAAC;gBAC9F,MAAM;;uDAEiC,UAAU,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;;;;;;;;QAsBxE,CAAC;AACT,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from 'n8n-workflow';
2
+ export declare class BefEmailOrSms implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BefEmailOrSms = void 0;
7
+ const n8n_workflow_1 = require("n8n-workflow");
8
+ const nodemailer_1 = __importDefault(require("nodemailer"));
9
+ const eventDefaults_1 = require("../../lib/eventDefaults");
10
+ const smsProviders_1 = require("../../lib/smsProviders");
11
+ const subscriptionAlert_1 = require("../../lib/subscriptionAlert");
12
+ class BefEmailOrSms {
13
+ constructor() {
14
+ this.description = {
15
+ displayName: 'Bef Email Or SMS',
16
+ name: 'befEmailOrSms',
17
+ icon: 'file:befroosh.svg',
18
+ group: ['output'],
19
+ version: 1,
20
+ subtitle: '={{ "prefer " + $parameter["preferChannel"] }}',
21
+ description: 'Send the subscription-renewal alert by email or SMS, whichever the user actually has ' +
22
+ "(falls back to the other channel if the preferred one's contact field is empty)",
23
+ defaults: { name: 'Bef Email Or SMS' },
24
+ inputs: [n8n_workflow_1.NodeConnectionTypes.Main],
25
+ outputs: [n8n_workflow_1.NodeConnectionTypes.Main],
26
+ credentials: [
27
+ { name: 'befrooshEmailApi', required: true },
28
+ {
29
+ name: 'notrikaSmsApi',
30
+ required: true,
31
+ displayOptions: { show: { smsProvider: ['notrika'] } },
32
+ },
33
+ {
34
+ name: 'batabjamSmsApi',
35
+ required: true,
36
+ displayOptions: { show: { smsProvider: ['batabjam'] } },
37
+ },
38
+ {
39
+ name: 'meliPayamakSmsApi',
40
+ required: true,
41
+ displayOptions: { show: { smsProvider: ['melipayamak'] } },
42
+ },
43
+ {
44
+ name: 'batabjamAboardSmsApi',
45
+ required: true,
46
+ displayOptions: { show: { smsProvider: ['batabjamAboard'] } },
47
+ },
48
+ ],
49
+ properties: [
50
+ {
51
+ displayName: 'Prefer Channel',
52
+ name: 'preferChannel',
53
+ type: 'options',
54
+ noDataExpression: true,
55
+ default: 'email',
56
+ options: [
57
+ { name: 'Email First', value: 'email' },
58
+ { name: 'SMS First', value: 'sms' },
59
+ ],
60
+ description: 'Which channel to try first when the user has both an email and a mobile number. ' +
61
+ "Falls back to the other channel when the preferred one's field is empty; fails when " +
62
+ 'neither is present.',
63
+ },
64
+ {
65
+ displayName: 'SMS Provider',
66
+ name: 'smsProvider',
67
+ type: 'options',
68
+ noDataExpression: true,
69
+ default: 'notrika',
70
+ options: [
71
+ { name: 'Notrika', value: 'notrika' },
72
+ { name: 'Batabjam', value: 'batabjam' },
73
+ { name: 'MeliPayamak', value: 'melipayamak' },
74
+ { name: 'Batabjam Aboard', value: 'batabjamAboard' },
75
+ ],
76
+ description: 'Which SMS provider to use if/when the SMS channel is chosen',
77
+ },
78
+ {
79
+ displayName: 'Email',
80
+ name: 'email',
81
+ type: 'string',
82
+ default: `={{ $json.context?.user?.email ?? ${eventDefaults_1.TRIGGER_ITEM_JSON}.context?.user?.email ?? '' }}`,
83
+ description: "Recipient email. Defaults to the acting user's email from the webhook context " +
84
+ '(empty when the user has none — the node then falls through to SMS).',
85
+ },
86
+ {
87
+ displayName: 'Mobile',
88
+ name: 'mobile',
89
+ type: 'string',
90
+ default: `={{ $json.context?.user?.mobile ?? ${eventDefaults_1.TRIGGER_ITEM_JSON}.context?.user?.mobile ?? '' }}`,
91
+ description: "Recipient phone number. Defaults to the acting user's mobile from the webhook context.",
92
+ },
93
+ {
94
+ displayName: 'First Name',
95
+ name: 'firstname',
96
+ type: 'string',
97
+ default: `={{ $json.context?.user?.firstname ?? ${eventDefaults_1.TRIGGER_ITEM_JSON}.context?.user?.firstname ?? '' }}`,
98
+ },
99
+ {
100
+ displayName: 'Instagram Username',
101
+ name: 'instagramUsername',
102
+ type: 'string',
103
+ default: `={{ $json.context?.eventInstagram?.username ?? ${eventDefaults_1.TRIGGER_ITEM_JSON}.context?.eventInstagram?.username ?? '' }}`,
104
+ description: 'Shown in the alert as the page the subscription covers',
105
+ },
106
+ {
107
+ displayName: 'Expire Date',
108
+ name: 'expireDate',
109
+ type: 'string',
110
+ default: `={{ $json.context?.eventInstagram?.subscription?.expire ?? ${eventDefaults_1.TRIGGER_ITEM_JSON}.context?.eventInstagram?.subscription?.expire ?? '' }}`,
111
+ description: 'ISO date string. Defaults to now if left empty.',
112
+ },
113
+ ],
114
+ };
115
+ }
116
+ async execute() {
117
+ const items = this.getInputData();
118
+ const returnData = [];
119
+ for (let i = 0; i < items.length; i++) {
120
+ let channel;
121
+ try {
122
+ const preferChannel = this.getNodeParameter('preferChannel', i);
123
+ const email = (this.getNodeParameter('email', i) || '').trim();
124
+ const mobile = (this.getNodeParameter('mobile', i) || '').trim();
125
+ const firstname = (this.getNodeParameter('firstname', i) || '').trim();
126
+ const instagramUsername = (this.getNodeParameter('instagramUsername', i) || '').trim();
127
+ const expireDateRaw = this.getNodeParameter('expireDate', i) || '';
128
+ const expireDate = expireDateRaw ? new Date(expireDateRaw) : new Date();
129
+ const order = preferChannel === 'sms' ? ['sms', 'email'] : ['email', 'sms'];
130
+ channel = order.find((c) => (c === 'email' ? !!email : !!mobile));
131
+ if (!channel) {
132
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'User has neither an email nor a mobile number to send the alert to', { itemIndex: i });
133
+ }
134
+ if (channel === 'email') {
135
+ const cred = await this.getCredentials('befrooshEmailApi', i);
136
+ if (!cred.host || !cred.user || !cred.password || !cred.fromAddress) {
137
+ throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Befroosh Email API credential is missing required fields (host/user/password/fromAddress)', { itemIndex: i });
138
+ }
139
+ const transporter = nodemailer_1.default.createTransport({
140
+ host: cred.host,
141
+ port: cred.port,
142
+ secure: false,
143
+ auth: { user: cred.user, pass: cred.password },
144
+ // Matches core's own mailer config exactly (apps/core/src/app.module.ts) —
145
+ // both flags are hardcoded there too, not env-driven.
146
+ tls: { rejectUnauthorized: false },
147
+ });
148
+ const html = (0, subscriptionAlert_1.subscriptionAlertEmailHtml)(firstname, instagramUsername || undefined, expireDate);
149
+ await transporter.sendMail({
150
+ to: email,
151
+ from: `"${cred.fromName || 'بفروش'}" <${cred.fromAddress}>`,
152
+ subject: subscriptionAlert_1.SUBSCRIPTION_ALERT_EMAIL_SUBJECT,
153
+ html,
154
+ });
155
+ returnData.push({
156
+ json: { success: true, channel: 'email', to: email },
157
+ pairedItem: { item: i },
158
+ });
159
+ continue;
160
+ }
161
+ const provider = this.getNodeParameter('smsProvider', i);
162
+ const text = (0, subscriptionAlert_1.subscriptionAlertSmsText)(firstname, instagramUsername, expireDate);
163
+ const result = await (0, smsProviders_1.sendSmsMessage)(this, provider, mobile, text, i);
164
+ if (result.statusCode >= 400) {
165
+ const detail = (0, smsProviders_1.describeSmsBody)(result.body);
166
+ if (this.continueOnFail()) {
167
+ returnData.push({
168
+ json: {
169
+ success: false,
170
+ channel: 'sms',
171
+ provider,
172
+ to: mobile,
173
+ statusCode: result.statusCode,
174
+ error: `${provider} returned HTTP ${result.statusCode}`,
175
+ response: result.body,
176
+ },
177
+ pairedItem: { item: i },
178
+ });
179
+ continue;
180
+ }
181
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), { provider, statusCode: result.statusCode, body: result.body }, {
182
+ httpCode: String(result.statusCode),
183
+ message: `${provider} rejected the request (HTTP ${result.statusCode})`,
184
+ description: detail,
185
+ itemIndex: i,
186
+ });
187
+ }
188
+ returnData.push({
189
+ json: {
190
+ success: true,
191
+ channel: 'sms',
192
+ provider,
193
+ to: mobile,
194
+ statusCode: result.statusCode,
195
+ },
196
+ pairedItem: { item: i },
197
+ });
198
+ }
199
+ catch (error) {
200
+ if (this.continueOnFail()) {
201
+ const e = error;
202
+ returnData.push({
203
+ json: {
204
+ success: false,
205
+ channel: channel !== null && channel !== void 0 ? channel : null,
206
+ error: e.message,
207
+ details: e.description,
208
+ },
209
+ pairedItem: { item: i },
210
+ });
211
+ continue;
212
+ }
213
+ throw error;
214
+ }
215
+ }
216
+ return [returnData];
217
+ }
218
+ }
219
+ exports.BefEmailOrSms = BefEmailOrSms;
220
+ //# sourceMappingURL=BefEmailOrSms.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BefEmailOrSms.node.js","sourceRoot":"","sources":["../../../nodes/BefEmailOrSms/BefEmailOrSms.node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><rect width="24" height="24" rx="5" fill="#6366f1"/><path d="M7 12a5 5 0 1 1 1.6 3.7" fill="none" stroke="#fff" stroke-width="2.1" stroke-linecap="round"/><path d="M7 8.5V12h3.5" fill="none" stroke="#fff" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-befroosh",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "private": false,
5
5
  "description": "Befroosh custom n8n nodes (SMS providers, analytics webhook trigger, event replay)",
6
6
  "license": "UNLICENSED",
@@ -24,7 +24,7 @@
24
24
  "dev": "tsc --watch",
25
25
  "check-types": "tsc --noEmit",
26
26
  "send-test": "node scripts/send-test-event.mjs",
27
- "test": "node --test lib/signature.test.ts lib/offsetParser.test.ts scripts/send-test-event.test.ts",
27
+ "test": "node --test lib/signature.test.ts lib/offsetParser.test.ts lib/smsFormat.test.ts lib/subscriptionAlert.test.ts scripts/send-test-event.test.ts",
28
28
  "lint": "eslint .",
29
29
  "lint:fix": "eslint . --fix",
30
30
  "prepublishOnly": "npm run build"
@@ -36,7 +36,8 @@
36
36
  "dist/credentials/BatabjamSmsApi.credentials.js",
37
37
  "dist/credentials/MeliPayamakSmsApi.credentials.js",
38
38
  "dist/credentials/BatabjamAboardSmsApi.credentials.js",
39
- "dist/credentials/BefrooshAnalyticsApi.credentials.js"
39
+ "dist/credentials/BefrooshAnalyticsApi.credentials.js",
40
+ "dist/credentials/BefrooshEmailApi.credentials.js"
40
41
  ],
41
42
  "nodes": [
42
43
  "dist/nodes/BefrooshSms/BefrooshSms.node.js",
@@ -44,15 +45,20 @@
44
45
  "dist/nodes/BefrooshReplay/BefrooshReplay.node.js",
45
46
  "dist/nodes/BefrooshAssignAction/BefrooshAssignAction.node.js",
46
47
  "dist/nodes/BefrooshWait/BefrooshWait.node.js",
47
- "dist/nodes/BefrooshStatus/BefrooshStatus.node.js"
48
+ "dist/nodes/BefrooshStatus/BefrooshStatus.node.js",
49
+ "dist/nodes/BefEmailOrSms/BefEmailOrSms.node.js"
48
50
  ]
49
51
  },
50
52
  "files": [
51
53
  "dist"
52
54
  ],
55
+ "dependencies": {
56
+ "nodemailer": "^7.0.4"
57
+ },
53
58
  "devDependencies": {
54
59
  "@eslint/js": "^9.31.0",
55
60
  "@types/node": "^20.11.0",
61
+ "@types/nodemailer": "^6.4.17",
56
62
  "eslint": "^9.31.0",
57
63
  "eslint-config-prettier": "^10.1.5",
58
64
  "globals": "^16.2.0",