n8n-nodes-sendzen 1.0.0 → 1.0.1

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.
Files changed (38) hide show
  1. package/LICENSE.md +21 -21
  2. package/README.md +193 -280
  3. package/dist/credentials/SendZenApi.credentials.js +0 -1
  4. package/dist/credentials/SendZenWebhookApi.credentials.d.ts +7 -0
  5. package/dist/credentials/SendZenWebhookApi.credentials.js +21 -0
  6. package/dist/nodes/SendZen/SendZen.node.js +0 -1
  7. package/dist/nodes/SendZen/SendZen.node.json +3 -3
  8. package/dist/nodes/SendZen/SendZenTrigger.node.js +44 -2
  9. package/dist/nodes/SendZen/SendZenTrigger.node.json +20 -0
  10. package/dist/shared/constants.js +0 -1
  11. package/dist/shared/nodeProperties.js +0 -1
  12. package/dist/shared/template/template.api.types.d.ts +2 -2
  13. package/dist/shared/template/template.api.types.js +0 -1
  14. package/dist/shared/template/template.builder.js +1 -2
  15. package/dist/shared/type.js +0 -1
  16. package/dist/shared/utils.js +0 -1
  17. package/index.js +1 -10
  18. package/package.json +32 -25
  19. package/dist/credentials/SendZenApi.credentials.js.map +0 -1
  20. package/dist/nodes/SendZen/SendZen.node.js.map +0 -1
  21. package/dist/nodes/SendZen/SendZenTrigger.node.js.map +0 -1
  22. package/dist/package.json +0 -76
  23. package/dist/shared/constants.js.map +0 -1
  24. package/dist/shared/nodeProperties.js.map +0 -1
  25. package/dist/shared/template/template.api.types.js.map +0 -1
  26. package/dist/shared/template/template.builder.js.map +0 -1
  27. package/dist/shared/type.js.map +0 -1
  28. package/dist/shared/utils.js.map +0 -1
  29. package/jest.config.js +0 -22
  30. package/n8n-nodes-sendzen-1.0.0.tgz +0 -0
  31. package/nodes/SendZen/SendZen.node.json +0 -20
  32. package/nodes/SendZen/sendzen.svg +0 -1
  33. package/shared/constants.ts +0 -1
  34. package/shared/nodeProperties.ts +0 -197
  35. package/shared/template/template.api.types.ts +0 -435
  36. package/shared/template/template.builder.ts +0 -223
  37. package/shared/type.ts +0 -40
  38. package/shared/utils.ts +0 -16
@@ -1,223 +0,0 @@
1
- import { MessageTemplate, ResponseBodyComponent, ResponseHeaderComponent, ResponseButtonsComponent, ResponseCarouselComponent } from './template.api.types';
2
-
3
- export interface TemplatePayloadParams {
4
- from: string;
5
- to: string;
6
- template: MessageTemplate;
7
- variables: Record<string, string>;
8
- }
9
-
10
- /**
11
- * Builds the SendZen/WhatsApp template payload based on the selected template structure
12
- * and the variables provided by the user in the n8n Resource Mapper.
13
- */
14
- export function buildTemplatePayload(params: TemplatePayloadParams) {
15
- const { template, variables, from, to } = params;
16
- const templateComponents: any[] = [];
17
-
18
- if (!template.components) {
19
- return {
20
- from,
21
- to,
22
- type: 'template',
23
- template: {
24
- name: template.name,
25
- lang_code: template.language,
26
- components: [],
27
- },
28
- };
29
- }
30
-
31
- const processComponent = (component: any, prefix = '') => {
32
- switch (component.type) {
33
- case 'HEADER': {
34
- const header = component as ResponseHeaderComponent;
35
- if (header.format === 'TEXT' && header.text) {
36
- const tokens = header.text.match(/\{\{([^}]+)\}\}/g);
37
- if (tokens && tokens.length > 0) {
38
- const parameters = tokens.map((match) => {
39
- const inner = match.replace(/[{}]/g, '');
40
- const isNumber = /^\d+$/.test(inner);
41
- const fieldId = `header_param_${inner}`;
42
- const value = variables[fieldId] || match;
43
-
44
- return {
45
- type: 'text',
46
- text: value,
47
- ...(isNumber ? {} : { parameter_name: inner }),
48
- };
49
- });
50
-
51
- templateComponents.push({
52
- type: 'header',
53
- parameters: parameters,
54
- });
55
- }
56
- } else if (header.format && ['IMAGE', 'VIDEO', 'DOCUMENT'].includes(header.format)) {
57
- const mediaType = header.format.toLowerCase();
58
- const mediaUrl = variables['header_media_url'] || '';
59
-
60
- if (mediaUrl) {
61
- templateComponents.push({
62
- type: 'header',
63
- parameters: [
64
- {
65
- type: mediaType,
66
- [mediaType]: {
67
- link: mediaUrl,
68
- },
69
- },
70
- ],
71
- });
72
- }
73
- }
74
- break;
75
- }
76
-
77
- case 'BODY': {
78
- const body = component as ResponseBodyComponent;
79
- if (body.text) {
80
- const tokens = body.text.match(/\{\{([^}]+)\}\}/g);
81
- if (tokens && tokens.length > 0) {
82
- const parameters = tokens.map((match) => {
83
- const inner = match.replace(/[{}]/g, '');
84
- const isNumber = /^\d+$/.test(inner);
85
- const fieldId = `body_param_${inner}`;
86
- const value = variables[fieldId] || match;
87
-
88
- return {
89
- type: 'text',
90
- text: value,
91
- ...(isNumber ? {} : { parameter_name: inner }),
92
- };
93
- });
94
-
95
- templateComponents.push({
96
- type: 'body',
97
- parameters: parameters,
98
- });
99
- }
100
- }
101
- break;
102
- }
103
-
104
- case 'BUTTONS': {
105
- const buttonsComp = component as ResponseButtonsComponent;
106
- if (buttonsComp.buttons && buttonsComp.buttons.length > 0) {
107
- buttonsComp.buttons.forEach((button, buttonIndex) => {
108
- if (button.type === 'URL' && button.url) {
109
- const urlToken = button.url.match(/\{\{([^}]+)\}\}/);
110
- if (urlToken && urlToken[1]) {
111
- const inner = urlToken[1];
112
- const isNumber = /^\d+$/.test(inner);
113
- const fieldId = `button_${buttonIndex}_param_${inner}`;
114
- const value = variables[fieldId] || '123456';
115
-
116
- templateComponents.push({
117
- type: 'button',
118
- sub_type: 'url',
119
- index: buttonIndex,
120
- parameters: [
121
- {
122
- type: 'text',
123
- text: value,
124
- ...(isNumber ? {} : { parameter_name: inner }),
125
- },
126
- ],
127
- });
128
- }
129
- } else if ((button.type as any) === 'COPY_CODE') {
130
- const searchableText = (button as any).text || (button as any).url || '';
131
- const codeToken = searchableText.match(/\{\{([^}]+)\}\}/);
132
- if (codeToken && codeToken[1]) {
133
- const inner = codeToken[1];
134
- const isNumber = /^\d+$/.test(inner);
135
- const fieldId = `button_${buttonIndex}_param_${inner}`;
136
- const value = variables[fieldId] || '123456';
137
-
138
- templateComponents.push({
139
- type: 'button',
140
- sub_type: 'copy_code',
141
- index: buttonIndex,
142
- parameters: [
143
- {
144
- type: 'text',
145
- text: value,
146
- ...(isNumber ? {} : { parameter_name: inner }),
147
- },
148
- ],
149
- });
150
- }
151
- } else if (button.type === 'FLOW') {
152
- const flowButton = button as any;
153
- const flowAction: {
154
- flow_token?: string;
155
- flow_action_data?: any;
156
- } = {};
157
-
158
- const flowToken = variables[`button_${buttonIndex}_flow_token`];
159
- flowAction.flow_token = flowToken || 'unused';
160
-
161
- const customFlowActionData = variables[`button_${buttonIndex}_flow_action_data`];
162
- if (customFlowActionData) {
163
- try {
164
- flowAction.flow_action_data =
165
- typeof customFlowActionData === 'string'
166
- ? JSON.parse(customFlowActionData)
167
- : customFlowActionData;
168
- } catch (e) {
169
- flowAction.flow_action_data = {};
170
- }
171
- } else if (flowButton.flow_id || flowButton.flow_action || flowButton.navigate_screen) {
172
- flowAction.flow_action_data = {};
173
- if (flowButton.flow_id) flowAction.flow_action_data.flow_id = flowButton.flow_id;
174
- if (flowButton.flow_action)
175
- flowAction.flow_action_data.flow_action = flowButton.flow_action;
176
- if (flowButton.navigate_screen)
177
- flowAction.flow_action_data.navigate_screen = flowButton.navigate_screen;
178
- }
179
-
180
- templateComponents.push({
181
- type: 'button',
182
- sub_type: 'flow',
183
- index: buttonIndex,
184
- parameters: [
185
- {
186
- type: 'action',
187
- action: flowAction,
188
- },
189
- ],
190
- });
191
- }
192
- });
193
- }
194
- break;
195
- }
196
-
197
- case 'CAROUSEL': {
198
- const carousel = component as ResponseCarouselComponent;
199
- if (carousel.cards) {
200
- carousel.cards.forEach((card, i) => {
201
- card.components.forEach((cardComp) => {
202
- processComponent(cardComp, `card_${i + 1}_`);
203
- });
204
- });
205
- }
206
- break;
207
- }
208
- }
209
- };
210
-
211
- template.components.forEach((comp) => processComponent(comp));
212
-
213
- return {
214
- from,
215
- to,
216
- type: 'template',
217
- template: {
218
- name: template.name,
219
- lang_code: template.language,
220
- components: templateComponents,
221
- },
222
- };
223
- }
package/shared/type.ts DELETED
@@ -1,40 +0,0 @@
1
- export interface WABAResponseList {
2
- message: string;
3
- data: {
4
- projects: {
5
- id: number;
6
- project_name: string;
7
- client_identifier: string;
8
- wabas: {
9
- id: number;
10
- waba_id: string;
11
- waba_business_name: string;
12
- phone_number_id: string;
13
- phone_number: string;
14
- number_status: string;
15
- setup_mode: string;
16
- mm_lite_api_status: string;
17
- phone_number_type: string;
18
- waba_onboard_stage: string;
19
- }[];
20
- }[];
21
- };
22
- }
23
-
24
- export interface SendTextMessageRequest {
25
- from: string;
26
- to: string;
27
- type: 'text';
28
- text: {
29
- body: string;
30
- preview_url?: boolean;
31
- };
32
- }
33
-
34
- export type SendzenAPIErroResponse = {
35
- message: string;
36
- error: {
37
- code: string;
38
- details: string;
39
- };
40
- };
package/shared/utils.ts DELETED
@@ -1,16 +0,0 @@
1
- import { SendzenAPIErroResponse } from "./type";
2
-
3
- export function isSendzenAPIErroResponse(
4
- value: unknown
5
- ): value is SendzenAPIErroResponse {
6
- return (
7
- typeof value === 'object' &&
8
- value !== null &&
9
- 'message' in value &&
10
- typeof (value as any).message === 'string' &&
11
- 'error' in value &&
12
- typeof (value as any).error === 'object' &&
13
- typeof (value as any).error?.code === 'string' &&
14
- typeof (value as any).error?.details === 'string'
15
- );
16
- }