@suprsend/node-sdk 0.1.0 → 1.0.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/dist/attachment.js +26 -0
- package/dist/bulk_response.js +60 -0
- package/dist/constants.js +40 -0
- package/dist/event.js +154 -85
- package/dist/events_bulk.js +424 -0
- package/dist/index.js +89 -39
- package/dist/request_json/event.json +5 -0
- package/dist/request_json/workflow.json +116 -9
- package/dist/{identity.js → subscriber.js} +195 -50
- package/dist/{identity_helper.js → subscriber_helper.js} +191 -59
- package/dist/subscribers_bulk.js +447 -0
- package/dist/utils.js +210 -1
- package/dist/workflow.js +124 -59
- package/dist/workflows_bulk.js +424 -0
- package/package.json +7 -4
- package/src/attachment.js +12 -0
- package/src/bulk_response.js +35 -0
- package/src/constants.js +28 -0
- package/src/event.js +118 -75
- package/src/events_bulk.js +234 -0
- package/src/index.js +67 -33
- package/src/request_json/event.json +5 -0
- package/src/request_json/workflow.json +116 -9
- package/src/{identity.js → subscriber.js} +118 -34
- package/src/{identity_helper.js → subscriber_helper.js} +196 -53
- package/src/subscribers_bulk.js +235 -0
- package/src/utils.js +136 -0
- package/src/workflow.js +94 -45
- package/src/workflows_bulk.js +234 -0
- package/dist/config.js +0 -13
- package/src/config.js +0 -6
package/src/utils.js
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import os from "os";
|
|
2
2
|
import fs from "fs";
|
|
3
|
+
import { Validator } from "jsonschema";
|
|
3
4
|
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
import {
|
|
6
|
+
WORKFLOW_RUNTIME_KEYS_POTENTIAL_SIZE_IN_BYTES,
|
|
7
|
+
ATTACHMENT_URL_POTENTIAL_SIZE_IN_BYTES,
|
|
8
|
+
ATTACHMENT_UPLOAD_ENABLED,
|
|
9
|
+
ALLOW_ATTACHMENTS_IN_BULK_API,
|
|
10
|
+
} from "./constants";
|
|
11
|
+
import { cloneDeep } from "lodash";
|
|
12
|
+
|
|
13
|
+
const workflow_schema = require("./request_json/workflow.json");
|
|
14
|
+
const event_schema = require("./request_json/event.json");
|
|
4
15
|
|
|
5
16
|
export function base64Encode(file) {
|
|
6
17
|
var body = fs.readFileSync(file);
|
|
@@ -26,6 +37,13 @@ export class SuprsendError extends Error {
|
|
|
26
37
|
}
|
|
27
38
|
}
|
|
28
39
|
|
|
40
|
+
export class SuprsendConfigError extends Error {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "SuprsendConfigError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
29
47
|
export function is_string(value) {
|
|
30
48
|
return typeof value === "string";
|
|
31
49
|
}
|
|
@@ -39,6 +57,8 @@ export function is_empty(value) {
|
|
|
39
57
|
return Object.keys(value) <= 0;
|
|
40
58
|
} else if (Array.isArray(value)) {
|
|
41
59
|
return value.length <= 0;
|
|
60
|
+
} else {
|
|
61
|
+
return !value;
|
|
42
62
|
}
|
|
43
63
|
}
|
|
44
64
|
|
|
@@ -53,3 +73,119 @@ export function uuid() {
|
|
|
53
73
|
export function epoch_milliseconds() {
|
|
54
74
|
return Math.round(Date.now());
|
|
55
75
|
}
|
|
76
|
+
|
|
77
|
+
export function validate_workflow_body_schema(body) {
|
|
78
|
+
if (!body?.data) {
|
|
79
|
+
body.data = {};
|
|
80
|
+
}
|
|
81
|
+
if (!(body.data instanceof Object)) {
|
|
82
|
+
throw new SuprsendError("data must be a object");
|
|
83
|
+
}
|
|
84
|
+
const schema = workflow_schema;
|
|
85
|
+
var v = new Validator();
|
|
86
|
+
const validated_data = v.validate(body, schema);
|
|
87
|
+
if (validated_data.valid) {
|
|
88
|
+
return body;
|
|
89
|
+
} else {
|
|
90
|
+
const error_obj = validated_data.errors[0];
|
|
91
|
+
const error_msg = `${error_obj.property} ${error_obj.message}`;
|
|
92
|
+
throw new SuprsendError(error_msg);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function validate_track_event_schema(body) {
|
|
97
|
+
if (!body?.properties) {
|
|
98
|
+
body.properties = {};
|
|
99
|
+
}
|
|
100
|
+
const schema = event_schema;
|
|
101
|
+
var v = new Validator();
|
|
102
|
+
const validated_data = v.validate(body, schema);
|
|
103
|
+
if (validated_data.valid) {
|
|
104
|
+
return body;
|
|
105
|
+
} else {
|
|
106
|
+
const error_obj = validated_data.errors[0];
|
|
107
|
+
const error_msg = `${error_obj.property} ${error_obj.message}`;
|
|
108
|
+
throw new SuprsendError(error_msg);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function get_apparent_workflow_body_size(body, is_part_of_bulk) {
|
|
113
|
+
let extra_bytes = WORKFLOW_RUNTIME_KEYS_POTENTIAL_SIZE_IN_BYTES;
|
|
114
|
+
let apparent_body = body;
|
|
115
|
+
if (body?.data["$attachments"]) {
|
|
116
|
+
const num_attachments = body.data["$attachments"].length;
|
|
117
|
+
if (is_part_of_bulk) {
|
|
118
|
+
if (ALLOW_ATTACHMENTS_IN_BULK_API) {
|
|
119
|
+
if (ATTACHMENT_UPLOAD_ENABLED) {
|
|
120
|
+
extra_bytes +=
|
|
121
|
+
num_attachments * ATTACHMENT_URL_POTENTIAL_SIZE_IN_BYTES;
|
|
122
|
+
apparent_body = cloneDeep(body);
|
|
123
|
+
for (let attach_data of apparent_body["data"]["$attachments"]) {
|
|
124
|
+
delete attach_data["data"];
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
// pass
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
apparent_body = cloneDeep(body);
|
|
131
|
+
delete apparent_body["data"]["$attachments"];
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
if (ATTACHMENT_UPLOAD_ENABLED) {
|
|
135
|
+
extra_bytes += num_attachments * ATTACHMENT_URL_POTENTIAL_SIZE_IN_BYTES;
|
|
136
|
+
apparent_body = cloneDeep(body);
|
|
137
|
+
for (let attach_data of apparent_body["data"]["$attachments"]) {
|
|
138
|
+
delete attach_data["data"];
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
// pass
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const body_size = JSON.stringify(apparent_body).length;
|
|
146
|
+
const apparent_body_size = body_size + extra_bytes;
|
|
147
|
+
return apparent_body_size;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function get_apparent_event_size(event, is_part_of_bulk) {
|
|
151
|
+
let extra_bytes = 0;
|
|
152
|
+
let apparent_body = event;
|
|
153
|
+
if (event?.properties?.["$attachments"]) {
|
|
154
|
+
const num_attachments = event.properties["$attachments"].length;
|
|
155
|
+
if (is_part_of_bulk) {
|
|
156
|
+
if (ALLOW_ATTACHMENTS_IN_BULK_API) {
|
|
157
|
+
if (ATTACHMENT_UPLOAD_ENABLED) {
|
|
158
|
+
extra_bytes +=
|
|
159
|
+
num_attachments * ATTACHMENT_URL_POTENTIAL_SIZE_IN_BYTES;
|
|
160
|
+
apparent_body = cloneDeep(event);
|
|
161
|
+
for (let attach_data of apparent_body["properties"]["$attachments"]) {
|
|
162
|
+
delete attach_data["data"];
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
// pass
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
apparent_body = cloneDeep(body);
|
|
169
|
+
delete apparent_body["properties"]["$attachments"];
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
if (ATTACHMENT_UPLOAD_ENABLED) {
|
|
173
|
+
extra_bytes += num_attachments * ATTACHMENT_URL_POTENTIAL_SIZE_IN_BYTES;
|
|
174
|
+
apparent_body = cloneDeep(body);
|
|
175
|
+
for (let attach_data of apparent_body["properties"]["$attachments"]) {
|
|
176
|
+
delete attach_data["data"];
|
|
177
|
+
}
|
|
178
|
+
} else {
|
|
179
|
+
// pass
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const body_size = JSON.stringify(apparent_body).length;
|
|
184
|
+
const apparent_size = body_size + extra_bytes;
|
|
185
|
+
return apparent_size;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function get_apparent_identity_event_size(event) {
|
|
189
|
+
const body_size = JSON.stringify(event);
|
|
190
|
+
return body_size;
|
|
191
|
+
}
|
package/src/workflow.js
CHANGED
|
@@ -1,85 +1,134 @@
|
|
|
1
|
-
import get_request_signature from "./signature";
|
|
2
|
-
import { Validator } from "jsonschema";
|
|
3
|
-
import { SuprsendError } from "./utils";
|
|
4
1
|
import axios from "axios";
|
|
2
|
+
import get_request_signature from "./signature";
|
|
3
|
+
import {
|
|
4
|
+
SuprsendError,
|
|
5
|
+
validate_workflow_body_schema,
|
|
6
|
+
get_apparent_workflow_body_size,
|
|
7
|
+
} from "./utils";
|
|
8
|
+
import get_attachment_json_for_file from "./attachment";
|
|
9
|
+
import {
|
|
10
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES,
|
|
11
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE,
|
|
12
|
+
} from "./constants";
|
|
13
|
+
|
|
14
|
+
export default class Workflow {
|
|
15
|
+
constructor(body, idempotency_key) {
|
|
16
|
+
if (!(body instanceof Object)) {
|
|
17
|
+
throw new SuprsendError("workflow body must be a json/dictionary");
|
|
18
|
+
}
|
|
19
|
+
this.body = body;
|
|
20
|
+
this.idempotency_key = idempotency_key;
|
|
21
|
+
}
|
|
5
22
|
|
|
6
|
-
|
|
23
|
+
add_attachment(file_path = "") {
|
|
24
|
+
if (!this.body.data) {
|
|
25
|
+
this.body.data = {};
|
|
26
|
+
}
|
|
27
|
+
if (!(this.body instanceof Object)) {
|
|
28
|
+
throw new SuprsendError("data must be a dictionary");
|
|
29
|
+
}
|
|
30
|
+
const attachment = get_attachment_json_for_file(file_path);
|
|
7
31
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
this.data
|
|
32
|
+
if (!this.body.data["$attachments"]) {
|
|
33
|
+
this.body["data"]["$attachments"] = [];
|
|
34
|
+
}
|
|
35
|
+
this.body["data"]["$attachments"].push(attachment);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get_final_json(config, is_part_of_bulk = false) {
|
|
39
|
+
// add idempotency key in body if present
|
|
40
|
+
if (this.idempotency_key) {
|
|
41
|
+
this.body["$idempotency_key"] = this.idempotency_key;
|
|
42
|
+
}
|
|
43
|
+
this.body = validate_workflow_body_schema(this.body);
|
|
44
|
+
const apparent_size = get_apparent_workflow_body_size(
|
|
45
|
+
this.body,
|
|
46
|
+
is_part_of_bulk
|
|
47
|
+
); // review
|
|
48
|
+
if (apparent_size > BODY_MAX_APPARENT_SIZE_IN_BYTES) {
|
|
49
|
+
throw new SuprsendError(
|
|
50
|
+
`workflow body (discounting attachment if any) too big - ${apparent_size} Bytes, must not cross ${BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE}`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
return [this.body, apparent_size];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class _WorkflowTrigger {
|
|
58
|
+
constructor(config) {
|
|
59
|
+
this.config = config;
|
|
12
60
|
this.url = this._get_url();
|
|
13
61
|
}
|
|
14
62
|
|
|
15
63
|
_get_url() {
|
|
16
64
|
let url_template = "/trigger/";
|
|
17
|
-
if (this.
|
|
18
|
-
if (this.
|
|
65
|
+
if (this.config.include_signature_param) {
|
|
66
|
+
if (this.config.auth_enabled) {
|
|
19
67
|
url_template = url_template + "?verify=true";
|
|
20
68
|
} else {
|
|
21
69
|
url_template = url_template + "?verify=false";
|
|
22
70
|
}
|
|
23
71
|
}
|
|
24
|
-
const url_formatted = `${this.
|
|
72
|
+
const url_formatted = `${this.config.base_url}${this.config.workspace_key}${url_template}`;
|
|
25
73
|
return url_formatted;
|
|
26
74
|
}
|
|
27
75
|
|
|
28
76
|
_get_headers() {
|
|
29
77
|
return {
|
|
30
|
-
"Content-Type": "application/json",
|
|
78
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
31
79
|
Date: new Date().toUTCString(),
|
|
32
|
-
"User-Agent": this.
|
|
80
|
+
"User-Agent": this.config.user_agent,
|
|
33
81
|
};
|
|
34
82
|
}
|
|
35
83
|
|
|
36
|
-
|
|
84
|
+
trigger(workflow) {
|
|
85
|
+
const is_part_of_bulk = false;
|
|
86
|
+
const [workflow_body, body_size] = workflow.get_final_json(
|
|
87
|
+
this.config,
|
|
88
|
+
is_part_of_bulk
|
|
89
|
+
);
|
|
90
|
+
return this.send(workflow_body);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async send(workflow_body) {
|
|
37
94
|
const headers = this._get_headers();
|
|
38
|
-
const content_text = JSON.stringify(
|
|
39
|
-
if (this.
|
|
95
|
+
const content_text = JSON.stringify(workflow_body);
|
|
96
|
+
if (this.config.auth_enabled) {
|
|
40
97
|
const signature = get_request_signature(
|
|
41
98
|
this.url,
|
|
42
99
|
"POST",
|
|
43
100
|
content_text,
|
|
44
101
|
headers,
|
|
45
|
-
this.
|
|
102
|
+
this.config.workspace_secret
|
|
46
103
|
);
|
|
47
|
-
headers["Authorization"] = `${this.
|
|
104
|
+
headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
|
|
48
105
|
}
|
|
106
|
+
|
|
49
107
|
try {
|
|
50
108
|
const response = await axios.post(this.url, content_text, { headers });
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
109
|
+
const ok_response = Math.floor(response.status / 100) == 2;
|
|
110
|
+
if (ok_response) {
|
|
111
|
+
return {
|
|
112
|
+
success: true,
|
|
113
|
+
status: "success",
|
|
114
|
+
status_code: response.status,
|
|
115
|
+
message: response.statusText,
|
|
116
|
+
};
|
|
117
|
+
} else {
|
|
118
|
+
return {
|
|
119
|
+
success: false,
|
|
120
|
+
status: "fail",
|
|
121
|
+
status_code: response.status,
|
|
122
|
+
message: response.statusText,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
56
125
|
} catch (err) {
|
|
57
126
|
return {
|
|
58
|
-
status_code: 400,
|
|
59
127
|
success: false,
|
|
128
|
+
status: "fail",
|
|
129
|
+
status_code: err.status || 500,
|
|
60
130
|
message: err.message,
|
|
61
131
|
};
|
|
62
132
|
}
|
|
63
133
|
}
|
|
64
|
-
|
|
65
|
-
validate_data() {
|
|
66
|
-
if (!this.data?.data) {
|
|
67
|
-
this.data.data = {};
|
|
68
|
-
}
|
|
69
|
-
if (!(this.data.data instanceof Object)) {
|
|
70
|
-
throw new SuprsendError("data must be a object");
|
|
71
|
-
}
|
|
72
|
-
const schema = workflow_schema;
|
|
73
|
-
var v = new Validator();
|
|
74
|
-
const validated_data = v.validate(this.data, schema);
|
|
75
|
-
if (validated_data.valid) {
|
|
76
|
-
return this.data;
|
|
77
|
-
} else {
|
|
78
|
-
const error_obj = validated_data.errors[0];
|
|
79
|
-
const error_msg = `${error_obj.property} ${error_obj.message}`;
|
|
80
|
-
throw new SuprsendError(error_msg);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
134
|
}
|
|
84
|
-
|
|
85
|
-
export default Workflow;
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES,
|
|
3
|
+
BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE,
|
|
4
|
+
MAX_WORKFLOWS_IN_BULK_API,
|
|
5
|
+
ALLOW_ATTACHMENTS_IN_BULK_API,
|
|
6
|
+
} from "./constants";
|
|
7
|
+
import { SuprsendError } from "./utils";
|
|
8
|
+
import Workflow from "./workflow";
|
|
9
|
+
import { cloneDeep } from "lodash";
|
|
10
|
+
import axios from "axios";
|
|
11
|
+
import BulkResponse from "./bulk_response";
|
|
12
|
+
import get_request_signature from "./signature";
|
|
13
|
+
|
|
14
|
+
export class BulkWorkflowsFactory {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
new_instance() {
|
|
20
|
+
return new BulkWorkflows(this.config);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class _BulkWorkflowsChunk {
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.__chunk = [];
|
|
28
|
+
this.__url = this.__get_url();
|
|
29
|
+
this.__headers = this.__common_headers();
|
|
30
|
+
|
|
31
|
+
this.__running_size = 0;
|
|
32
|
+
this.__running_length = 0;
|
|
33
|
+
this.response;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
__get_url() {
|
|
37
|
+
let url_template = "/trigger/";
|
|
38
|
+
if (this.config.include_signature_param) {
|
|
39
|
+
if (this.config.auth_enabled) {
|
|
40
|
+
url_template = url_template + "?verify=true";
|
|
41
|
+
} else {
|
|
42
|
+
url_template = url_template + "?verify=false";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const url_formatted = `${this.config.base_url}${this.config.workspace_key}${url_template}`;
|
|
46
|
+
return url_formatted;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
__common_headers() {
|
|
50
|
+
return {
|
|
51
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
52
|
+
"User-Agent": this.config.user_agent,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
__dynamic_headers() {
|
|
57
|
+
return {
|
|
58
|
+
Date: new Date().toUTCString(),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
__add_body_to_chunk(body, body_size) {
|
|
63
|
+
// First add size, then body to reduce effects of race condition
|
|
64
|
+
this.__running_size += body_size;
|
|
65
|
+
this.__chunk.push(body);
|
|
66
|
+
this.__running_length += 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
__check_limit_reached() {
|
|
70
|
+
if (
|
|
71
|
+
this.__running_length >= MAX_WORKFLOWS_IN_BULK_API ||
|
|
72
|
+
this.__running_size >= BODY_MAX_APPARENT_SIZE_IN_BYTES
|
|
73
|
+
) {
|
|
74
|
+
return true;
|
|
75
|
+
} else {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
try_to_add_into_chunk(body, body_size) {
|
|
81
|
+
if (!body) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
if (this.__check_limit_reached()) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
if (body_size > BODY_MAX_APPARENT_SIZE_IN_BYTES) {
|
|
88
|
+
throw new SuprsendError(
|
|
89
|
+
`workflow body (discounting attachment if any) too big - ${body_size} Bytes, must not cross ${BODY_MAX_APPARENT_SIZE_IN_BYTES_READABLE}`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (this.__running_size + body_size > BODY_MAX_APPARENT_SIZE_IN_BYTES) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
if (!ALLOW_ATTACHMENTS_IN_BULK_API) {
|
|
96
|
+
delete body.data["$attachments"];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.__add_body_to_chunk(body, body_size);
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async trigger() {
|
|
104
|
+
const headers = { ...this.__headers, ...this.__dynamic_headers() };
|
|
105
|
+
const content_text = JSON.stringify(this.__chunk);
|
|
106
|
+
// Based on whether signature is required or not, add Authorization header
|
|
107
|
+
if (this.config.auth_enabled) {
|
|
108
|
+
const signature = get_request_signature(
|
|
109
|
+
this.__url,
|
|
110
|
+
"POST",
|
|
111
|
+
content_text,
|
|
112
|
+
headers,
|
|
113
|
+
this.config.workspace_secret
|
|
114
|
+
);
|
|
115
|
+
headers["Authorization"] = `${this.config.workspace_key}:${signature}`;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const response = await axios.post(this.__url, content_text, { headers });
|
|
119
|
+
const ok_response = Math.floor(response.status / 100) == 2;
|
|
120
|
+
if (ok_response) {
|
|
121
|
+
this.response = {
|
|
122
|
+
status: "success",
|
|
123
|
+
status_code: response.status,
|
|
124
|
+
total: this.__chunk.length,
|
|
125
|
+
success: this.__chunk.length,
|
|
126
|
+
failure: 0,
|
|
127
|
+
failed_records: [],
|
|
128
|
+
};
|
|
129
|
+
} else {
|
|
130
|
+
this.response = {
|
|
131
|
+
status: "fail",
|
|
132
|
+
status_code: response.status,
|
|
133
|
+
total: this.__chunk.length,
|
|
134
|
+
success: 0,
|
|
135
|
+
failure: this.__chunk.length,
|
|
136
|
+
failed_records: this.__chunk.map((item) => ({
|
|
137
|
+
record: item,
|
|
138
|
+
error: response.statusText,
|
|
139
|
+
code: response.status,
|
|
140
|
+
})),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
const error_status = err.status || 500;
|
|
145
|
+
return {
|
|
146
|
+
status: "fail",
|
|
147
|
+
status_code: error_status,
|
|
148
|
+
message: err.message,
|
|
149
|
+
total: this.__chunk.length,
|
|
150
|
+
success: 0,
|
|
151
|
+
failure: this.__chunk.length,
|
|
152
|
+
failed_records: this.__chunk.map((item) => ({
|
|
153
|
+
record: item,
|
|
154
|
+
error: err.message,
|
|
155
|
+
code: error_status,
|
|
156
|
+
})),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
class BulkWorkflows {
|
|
163
|
+
constructor(config) {
|
|
164
|
+
this.config = config;
|
|
165
|
+
this.__workflows = [];
|
|
166
|
+
this.__pending_records = [];
|
|
167
|
+
this.chunks = [];
|
|
168
|
+
this.response = new BulkResponse();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
__validate_workflows() {
|
|
172
|
+
if (!this.__workflows) {
|
|
173
|
+
throw new SuprsendError("workflow list is empty in bulk request");
|
|
174
|
+
}
|
|
175
|
+
for (let wf of this.__workflows) {
|
|
176
|
+
const is_part_of_bulk = true;
|
|
177
|
+
const [wf_body, body_size] = wf.get_final_json(
|
|
178
|
+
this.config,
|
|
179
|
+
is_part_of_bulk
|
|
180
|
+
);
|
|
181
|
+
this.__pending_records.push([wf_body, body_size]);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
__chunkify(start_idx = 0) {
|
|
186
|
+
const curr_chunk = new _BulkWorkflowsChunk(this.config);
|
|
187
|
+
this.chunks.push(curr_chunk);
|
|
188
|
+
const entries = this.__pending_records.slice(start_idx).entries();
|
|
189
|
+
for (const [rel_idx, rec] of entries) {
|
|
190
|
+
const is_added = curr_chunk.try_to_add_into_chunk(rec[0], rec[1]);
|
|
191
|
+
if (!is_added) {
|
|
192
|
+
// create chunks from remaining records
|
|
193
|
+
this.__chunkify(start_idx + rel_idx);
|
|
194
|
+
// Don't forget to break. As current loop must not continue further
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
append(...workflows) {
|
|
201
|
+
if (!workflows) {
|
|
202
|
+
throw new SuprsendError(
|
|
203
|
+
"workflow list empty. must pass one or more valid workflow instances"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
for (let wf of workflows) {
|
|
207
|
+
if (!wf) {
|
|
208
|
+
throw new SuprsendError("null/empty element found in bulk instance");
|
|
209
|
+
}
|
|
210
|
+
if (!(wf instanceof Workflow)) {
|
|
211
|
+
throw new SuprsendError(
|
|
212
|
+
"element must be an instance of suprsend.Workflow"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
const wf_copy = cloneDeep(wf);
|
|
216
|
+
this.__workflows.push(wf_copy);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async trigger() {
|
|
221
|
+
this.__validate_workflows();
|
|
222
|
+
this.__chunkify();
|
|
223
|
+
for (const [c_idx, ch] of this.chunks.entries()) {
|
|
224
|
+
if (this.config.req_log_level > 0) {
|
|
225
|
+
console.log(`DEBUG: triggering api call for chunk: ${c_idx}`);
|
|
226
|
+
}
|
|
227
|
+
// do api call
|
|
228
|
+
await ch.trigger();
|
|
229
|
+
// merge response
|
|
230
|
+
this.response.merge_chunk_response(ch.response);
|
|
231
|
+
}
|
|
232
|
+
return this.response;
|
|
233
|
+
}
|
|
234
|
+
}
|
package/dist/config.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports["default"] = void 0;
|
|
7
|
-
var config = {
|
|
8
|
-
staging: "https://collector-staging.suprsend.workers.dev/",
|
|
9
|
-
prod: "https://hub.suprsend.com/"
|
|
10
|
-
};
|
|
11
|
-
var _default = config;
|
|
12
|
-
exports["default"] = _default;
|
|
13
|
-
module.exports = exports.default;
|