@suprsend/node-sdk 1.9.1 → 1.10.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 +1 -1
- package/dist/constants.js +2 -4
- package/dist/index.js +12 -5
- package/dist/request_json/workflow.json +4 -0
- package/dist/request_json/workflow_trigger.json +360 -0
- package/dist/subscriber.js +7 -0
- package/dist/subscriber_helper.js +7 -1
- package/dist/utils.js +20 -0
- package/dist/workflow.js +1 -1
- package/dist/workflow_api.js +108 -0
- package/dist/workflow_request.js +93 -0
- package/dist/workflow_trigger_bulk.js +316 -0
- package/package.json +1 -1
- package/src/constants.js +0 -2
- package/src/index.js +16 -7
- package/src/request_json/workflow.json +4 -0
- package/src/request_json/workflow_trigger.json +360 -0
- package/src/subscriber.js +6 -0
- package/src/subscriber_helper.js +6 -0
- package/src/utils.js +20 -0
- package/src/workflow.js +1 -1
- package/src/workflow_api.js +71 -0
- package/src/workflow_request.js +92 -0
- package/src/workflow_trigger_bulk.js +218 -0
- package/types/index.d.ts +33 -1
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { cloneDeep } from "lodash";
|
|
3
|
+
import get_request_signature from "./signature";
|
|
4
|
+
import BulkResponse from "./bulk_response";
|
|
5
|
+
import { invalid_record_json, InputValueError } from "./utils";
|
|
6
|
+
import WorkflowTriggerRequest from "./workflow_request";
|
|
7
|
+
import {
|
|
8
|
+
SINGLE_EVENT_MAX_APPARENT_SIZE_IN_BYTES,
|
|
9
|
+
SINGLE_EVENT_MAX_APPARENT_SIZE_IN_BYTES_READABLE,
|
|
10
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES,
|
|
11
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE,
|
|
12
|
+
MAX_WORKFLOWS_IN_BULK_API,
|
|
13
|
+
ALLOW_ATTACHMENTS_IN_BULK_API,
|
|
14
|
+
} from "./constants";
|
|
15
|
+
|
|
16
|
+
export class _BulkWorkflowTriggerChunk {
|
|
17
|
+
static _chunk_apparent_size_in_bytes = BODY_MAX_APPARENT_SIZE_IN_BYTES;
|
|
18
|
+
static _chunk_apparent_size_in_bytes_readable =
|
|
19
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE;
|
|
20
|
+
static _max_records_in_chunk = MAX_WORKFLOWS_IN_BULK_API;
|
|
21
|
+
|
|
22
|
+
constructor(config) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
this.url = this.__url = `${this.config.base_url}trigger/`;
|
|
25
|
+
this.__chunk = [];
|
|
26
|
+
this.__running_size = 0;
|
|
27
|
+
this.__running_length = 0;
|
|
28
|
+
this.response = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
_get_headers() {
|
|
32
|
+
return {
|
|
33
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
34
|
+
"User-Agent": this.config.user_agent,
|
|
35
|
+
Date: new Date().toUTCString(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
__add_body_to_chunk(body, body_size) {
|
|
40
|
+
this.__running_size += body_size;
|
|
41
|
+
this.__chunk.push(body);
|
|
42
|
+
this.__running_length++;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
_check_limit_reached() {
|
|
46
|
+
return (
|
|
47
|
+
this.__running_length >=
|
|
48
|
+
_BulkWorkflowTriggerChunk._max_records_in_chunk ||
|
|
49
|
+
this.__running_size >=
|
|
50
|
+
_BulkWorkflowTriggerChunk._chunk_apparent_size_in_bytes
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try_to_add_into_chunk(body, body_size) {
|
|
55
|
+
if (!body) {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
if (this._check_limit_reached()) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (body_size > SINGLE_EVENT_MAX_APPARENT_SIZE_IN_BYTES) {
|
|
62
|
+
throw new InputValueError(
|
|
63
|
+
`workflow body too big - ${body_size} Bytes, must not exceed ${SINGLE_EVENT_MAX_APPARENT_SIZE_IN_BYTES_READABLE}`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
this.__running_size + body_size >
|
|
68
|
+
_BulkWorkflowTriggerChunk._chunk_apparent_size_in_bytes
|
|
69
|
+
) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!ALLOW_ATTACHMENTS_IN_BULK_API) {
|
|
74
|
+
delete body.data["$attachments"];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.__add_body_to_chunk(body, body_size);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async trigger() {
|
|
82
|
+
const headers = this._get_headers();
|
|
83
|
+
const content_text = JSON.stringify(this.__chunk);
|
|
84
|
+
|
|
85
|
+
const signature = get_request_signature(
|
|
86
|
+
this.__url,
|
|
87
|
+
"POST",
|
|
88
|
+
content_text,
|
|
89
|
+
headers,
|
|
90
|
+
this.config.workspace_secret
|
|
91
|
+
);
|
|
92
|
+
headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
|
|
93
|
+
try {
|
|
94
|
+
const resp = await axios.post(this.__url, content_text, {
|
|
95
|
+
headers,
|
|
96
|
+
transformResponse: [(data) => data], // dont assume type of response
|
|
97
|
+
});
|
|
98
|
+
this.response = {
|
|
99
|
+
status: "success",
|
|
100
|
+
status_code: resp.status,
|
|
101
|
+
total: this.__chunk.length,
|
|
102
|
+
success: this.__chunk.length,
|
|
103
|
+
failure: 0,
|
|
104
|
+
failed_records: [],
|
|
105
|
+
};
|
|
106
|
+
} catch (err) {
|
|
107
|
+
if (err?.response) {
|
|
108
|
+
const resp_data = err.response;
|
|
109
|
+
this.response = {
|
|
110
|
+
status: "fail",
|
|
111
|
+
status_code: resp_data.status,
|
|
112
|
+
total: this.__chunk.length,
|
|
113
|
+
success: 0,
|
|
114
|
+
failure: this.__chunk.length,
|
|
115
|
+
failed_records: this.__chunk.map((record) => ({
|
|
116
|
+
record: record,
|
|
117
|
+
error: resp_data.data,
|
|
118
|
+
code: resp_data.status,
|
|
119
|
+
})),
|
|
120
|
+
};
|
|
121
|
+
} else {
|
|
122
|
+
this.response = {
|
|
123
|
+
status: "fail",
|
|
124
|
+
status_code: 500,
|
|
125
|
+
total: this.__chunk.length,
|
|
126
|
+
success: 0,
|
|
127
|
+
failure: this.__chunk.length,
|
|
128
|
+
failed_records: this.__chunk.map((record) => ({
|
|
129
|
+
record: record,
|
|
130
|
+
error: err.message,
|
|
131
|
+
code: 500,
|
|
132
|
+
})),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export class BulkWorkflowTrigger {
|
|
140
|
+
constructor(config) {
|
|
141
|
+
this.config = config;
|
|
142
|
+
this.__workflows = [];
|
|
143
|
+
this.__pending_records = [];
|
|
144
|
+
this.chunks = [];
|
|
145
|
+
this.response = new BulkResponse();
|
|
146
|
+
// invalid_record json: {"record": workflow-json, "error": error_str, "code": 500}
|
|
147
|
+
this.__invalid_records = [];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
__validate_workflows() {
|
|
151
|
+
for (const wf of this.__workflows) {
|
|
152
|
+
try {
|
|
153
|
+
const is_part_of_bulk = true;
|
|
154
|
+
const [wf_body, body_size] = wf.get_final_json(
|
|
155
|
+
this.config,
|
|
156
|
+
is_part_of_bulk
|
|
157
|
+
);
|
|
158
|
+
this.__pending_records.push([wf_body, body_size]);
|
|
159
|
+
} catch (ex) {
|
|
160
|
+
const inv_rec = invalid_record_json(wf.as_json(), ex);
|
|
161
|
+
this.__invalid_records.push(inv_rec);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
__chunkify(start_idx = 0) {
|
|
167
|
+
const curr_chunk = new _BulkWorkflowTriggerChunk(this.config);
|
|
168
|
+
this.chunks.push(curr_chunk);
|
|
169
|
+
const entries = this.__pending_records.slice(start_idx).entries();
|
|
170
|
+
for (const [rel_idx, rec] of entries) {
|
|
171
|
+
const is_added = curr_chunk.try_to_add_into_chunk(rec[0], rec[1]);
|
|
172
|
+
if (!is_added) {
|
|
173
|
+
// create chunks from remaining records
|
|
174
|
+
this.__chunkify(start_idx + rel_idx);
|
|
175
|
+
// Don't forget to break. As current loop must not continue further
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
append(...workflows) {
|
|
182
|
+
if (!workflows.length) return;
|
|
183
|
+
for (const wf of workflows) {
|
|
184
|
+
if (wf instanceof WorkflowTriggerRequest) {
|
|
185
|
+
const wf_copy = cloneDeep(wf);
|
|
186
|
+
this.__workflows.push(wf_copy);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async trigger() {
|
|
192
|
+
this.__validate_workflows();
|
|
193
|
+
if (this.__invalid_records.length > 0) {
|
|
194
|
+
const ch_response = BulkResponse.invalid_records_chunk_response(
|
|
195
|
+
this.__invalid_records
|
|
196
|
+
);
|
|
197
|
+
this.response.merge_chunk_response(ch_response);
|
|
198
|
+
}
|
|
199
|
+
if (this.__pending_records.length) {
|
|
200
|
+
this.__chunkify();
|
|
201
|
+
for (const [c_idx, ch] of this.chunks.entries()) {
|
|
202
|
+
if (this.config.req_log_level > 0) {
|
|
203
|
+
console.log(`DEBUG: triggering api call for chunk: ${cIdx}`);
|
|
204
|
+
}
|
|
205
|
+
// do api call
|
|
206
|
+
await ch.trigger();
|
|
207
|
+
// merge response
|
|
208
|
+
this.response.merge_chunk_response(ch.response);
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
if (this.__invalid_records.length === 0)
|
|
212
|
+
this.response.merge_chunk_response(
|
|
213
|
+
BulkResponse.empty_chunk_success_response()
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return this.response;
|
|
217
|
+
}
|
|
218
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -86,6 +86,7 @@ declare namespace suprsend {
|
|
|
86
86
|
unset(keys: string | string[]): void;
|
|
87
87
|
|
|
88
88
|
set_preferred_language(lang_code: string): void;
|
|
89
|
+
set_timezone(timezone: string): void;
|
|
89
90
|
|
|
90
91
|
add_email(email: string): void;
|
|
91
92
|
remove_email(email: string): void;
|
|
@@ -207,11 +208,39 @@ declare namespace suprsend {
|
|
|
207
208
|
delete_version(list_id: string, version_id: string): Promise<Dictionary>;
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
interface WorkflowTriggerRequest {
|
|
212
|
+
new (
|
|
213
|
+
body: Dictionary,
|
|
214
|
+
kwargs?: {
|
|
215
|
+
idempotency_key?: string;
|
|
216
|
+
tenant_id?: string;
|
|
217
|
+
cancellation_id?: string;
|
|
218
|
+
}
|
|
219
|
+
): WorkflowTriggerRequest;
|
|
220
|
+
|
|
221
|
+
add_attachment(
|
|
222
|
+
file_path: string,
|
|
223
|
+
kwargs?: { file_name?: string; ignore_if_error?: boolean }
|
|
224
|
+
): void;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
interface WorkflowsApi {
|
|
228
|
+
trigger(workflow: WorkflowTriggerRequest): Promise<SBulkResponse>;
|
|
229
|
+
|
|
230
|
+
bulk_trigger_instance(): BulkWorkflowTrigger;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
interface BulkWorkflowTrigger {
|
|
234
|
+
append(...workflows: WorkflowTriggerRequest[]): void;
|
|
235
|
+
|
|
236
|
+
trigger(): Promise<SBulkResponse>;
|
|
237
|
+
}
|
|
238
|
+
|
|
210
239
|
interface Suprsend {
|
|
211
240
|
new (
|
|
212
241
|
workspace_env: string,
|
|
213
242
|
workspace_secret: string,
|
|
214
|
-
config?: {
|
|
243
|
+
config?: { base_url?: string }
|
|
215
244
|
): Suprsend;
|
|
216
245
|
|
|
217
246
|
get bulk_workflows(): BulkWorkflowsFactory;
|
|
@@ -228,6 +257,8 @@ declare namespace suprsend {
|
|
|
228
257
|
|
|
229
258
|
subscriber_lists: SubscriberListsApi;
|
|
230
259
|
|
|
260
|
+
workflows: WorkflowsApi;
|
|
261
|
+
|
|
231
262
|
add_attachment(
|
|
232
263
|
body: Dictionary,
|
|
233
264
|
file_path: string,
|
|
@@ -255,3 +286,4 @@ export const Suprsend: suprsend.Suprsend;
|
|
|
255
286
|
export const Event: suprsend.Event;
|
|
256
287
|
export const Workflow: suprsend.Workflow;
|
|
257
288
|
export const SubscriberListBroadcast: suprsend.SubscriberListBroadcast;
|
|
289
|
+
export const WorkflowTriggerRequest: suprsend.WorkflowTriggerRequest;
|