@engine9-io/input-tools 1.9.11 → 2.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.
- package/ForEachEntry.js +18 -45
- package/ValidatingReadable.js +3 -6
- package/buildSamplePackets.js +11 -16
- package/eslint.config.mjs +15 -11
- package/file/FileUtilities.js +29 -153
- package/file/GoogleDrive.js +32 -38
- package/file/Parquet.js +112 -124
- package/file/R2.js +27 -32
- package/file/S3.js +259 -293
- package/file/tools.js +33 -54
- package/index.js +59 -74
- package/package.json +2 -1
- package/test/cli.js +3 -4
- package/test/file.js +6 -7
- package/test/processing/bigDataMessage.js +8 -10
- package/test/processing/forEach.js +6 -8
- package/test/processing/forEachResume.js +6 -8
- package/test/processing/message.js +31 -39
- package/test/processing/zip.js +6 -7
- package/test/uuid.js +6 -11
- package/timelineTypes.js +2 -24
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug$0 from 'debug';
|
|
4
|
+
import promises from 'node:timers/promises';
|
|
5
|
+
import { ForEachEntry } from '../../index.js';
|
|
6
|
+
const { describe, it } = nodetest;
|
|
7
|
+
const debug = debug$0('test:big-data');
|
|
8
|
+
const { setTimeout } = promises;
|
|
9
9
|
describe('big-data message: forEachPerson', async () => {
|
|
10
10
|
it('message: forEachPerson should loop through 1000000 sample people', async () => {
|
|
11
11
|
const messageContent = [];
|
|
12
12
|
let counter = 0;
|
|
13
13
|
const forEach = new ForEachEntry();
|
|
14
|
-
|
|
15
14
|
const output = await forEach.process({
|
|
16
15
|
// packet: '../1000000_person_message.packet.zip',
|
|
17
16
|
filename: '../1000000_person_message.packet/person/1000000_fake_people.csv',
|
|
@@ -47,7 +46,6 @@ describe('big-data message: forEachPerson', async () => {
|
|
|
47
46
|
}
|
|
48
47
|
});
|
|
49
48
|
debug(output);
|
|
50
|
-
|
|
51
49
|
assert.equal(counter, 1000000, `Expected to loop through 1000000 people, actual:${counter}`);
|
|
52
50
|
});
|
|
53
51
|
debug('Completed all tests');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const {
|
|
6
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug$0 from 'debug';
|
|
4
|
+
import { ForEachEntry } from '../../index.js';
|
|
5
|
+
const { describe, it } = nodetest;
|
|
6
|
+
const debug = debug$0('test/forEach');
|
|
7
7
|
describe('Test Person File For Each', async () => {
|
|
8
8
|
it('forEachPerson Should loop through 1000 sample people', async () => {
|
|
9
9
|
let counter = 0;
|
|
@@ -24,7 +24,6 @@ describe('Test Person File For Each', async () => {
|
|
|
24
24
|
},
|
|
25
25
|
async transform(props) {
|
|
26
26
|
const { batch, timelineOutputFileStream, sampleOutputFileStream } = props;
|
|
27
|
-
|
|
28
27
|
batch.forEach((p) => {
|
|
29
28
|
if (Math.random() > 0.9) {
|
|
30
29
|
sampleOutputFileStream.push({
|
|
@@ -41,7 +40,6 @@ describe('Test Person File For Each', async () => {
|
|
|
41
40
|
entry_type: 'EMAIL_DELIVERED'
|
|
42
41
|
});
|
|
43
42
|
});
|
|
44
|
-
|
|
45
43
|
batch.forEach(() => {
|
|
46
44
|
counter += 1;
|
|
47
45
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const {
|
|
6
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug$0 from 'debug';
|
|
4
|
+
import { ForEachEntry } from '../../index.js';
|
|
5
|
+
const { describe, it } = nodetest;
|
|
6
|
+
const debug = debug$0('test/forEach');
|
|
7
7
|
describe('Test Person File For Each', async () => {
|
|
8
8
|
it('forEachPerson Should loop through 1000 sample people', async () => {
|
|
9
9
|
let counter = 0;
|
|
@@ -24,7 +24,6 @@ describe('Test Person File For Each', async () => {
|
|
|
24
24
|
},
|
|
25
25
|
async transform(props) {
|
|
26
26
|
const { batch, timelineOutputFileStream, sampleOutputFileStream } = props;
|
|
27
|
-
|
|
28
27
|
batch.forEach((p) => {
|
|
29
28
|
if (Math.random() > 0.9) {
|
|
30
29
|
sampleOutputFileStream.push({
|
|
@@ -41,7 +40,6 @@ describe('Test Person File For Each', async () => {
|
|
|
41
40
|
entry_type: 'EMAIL_DELIVERED'
|
|
42
41
|
});
|
|
43
42
|
});
|
|
44
|
-
|
|
45
43
|
batch.forEach(() => {
|
|
46
44
|
counter += 1;
|
|
47
45
|
});
|
|
@@ -1,47 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const { forEachPerson } =
|
|
8
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug$0 from 'debug';
|
|
4
|
+
import index from '../../index.js';
|
|
5
|
+
const { describe, it } = nodetest;
|
|
6
|
+
const debug = debug$0('message');
|
|
7
|
+
const { forEachPerson } = index;
|
|
9
8
|
describe('Test Person Packet Message For Each', async () => {
|
|
10
9
|
it('message: forEachPerson should loop through 1000 sample people', async () => {
|
|
11
10
|
const messageContent = [];
|
|
12
11
|
let counter = 0;
|
|
13
|
-
const results = await forEachPerson(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
handlebars: { type: 'handlebars' },
|
|
21
|
-
},
|
|
22
|
-
async transform({
|
|
23
|
-
batch,
|
|
24
|
-
message,
|
|
25
|
-
handlebars,
|
|
26
|
-
timelineOutputStream,
|
|
27
|
-
}) {
|
|
28
|
-
const template = handlebars.compile(message.content.text);
|
|
29
|
-
batch.forEach((person) => {
|
|
30
|
-
messageContent.push(template(person));
|
|
31
|
-
});
|
|
32
|
-
batch.forEach(() => { counter += 1; });
|
|
33
|
-
batch.forEach((p) => {
|
|
34
|
-
timelineOutputStream.push(
|
|
35
|
-
{
|
|
36
|
-
person_id: p.person_id,
|
|
37
|
-
email: p.email,
|
|
38
|
-
entry_type: 'EMAIL_DELIVERED',
|
|
39
|
-
},
|
|
40
|
-
);
|
|
41
|
-
});
|
|
42
|
-
},
|
|
12
|
+
const results = await forEachPerson({
|
|
13
|
+
packet: 'test/sample/1000_message.packet.zip',
|
|
14
|
+
batchSize: 50,
|
|
15
|
+
bindings: {
|
|
16
|
+
timelineOutputStream: { type: 'output.timeline' },
|
|
17
|
+
message: { type: 'packet.message' },
|
|
18
|
+
handlebars: { type: 'handlebars' }
|
|
43
19
|
},
|
|
44
|
-
|
|
20
|
+
async transform({ batch, message, handlebars, timelineOutputStream }) {
|
|
21
|
+
const template = handlebars.compile(message.content.text);
|
|
22
|
+
batch.forEach((person) => {
|
|
23
|
+
messageContent.push(template(person));
|
|
24
|
+
});
|
|
25
|
+
batch.forEach(() => {
|
|
26
|
+
counter += 1;
|
|
27
|
+
});
|
|
28
|
+
batch.forEach((p) => {
|
|
29
|
+
timelineOutputStream.push({
|
|
30
|
+
person_id: p.person_id,
|
|
31
|
+
email: p.email,
|
|
32
|
+
entry_type: 'EMAIL_DELIVERED'
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
45
37
|
debug(results);
|
|
46
38
|
assert.equal(counter, 1000, `Expected to loop through 1000 people, actual:${counter}`);
|
|
47
39
|
});
|
package/test/processing/zip.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const {
|
|
6
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug from 'debug';
|
|
4
|
+
import { create, getManifest } from '../../index.js';
|
|
5
|
+
const { describe, it } = nodetest;
|
|
7
6
|
describe('Test Person Packet Creator', async () => {
|
|
8
7
|
const pfile = './test/sample/message/5_fake_people.csv';
|
|
9
8
|
it(`should create a zip file from directory ${process.cwd()} with path ${pfile}`, async () => {
|
|
10
9
|
const out = await create({
|
|
11
10
|
personFiles: [pfile],
|
|
12
|
-
messageFiles: 'test/sample/message/message.json5'
|
|
11
|
+
messageFiles: 'test/sample/message/message.json5'
|
|
13
12
|
});
|
|
14
13
|
debug('Successfully created:', out);
|
|
15
14
|
return out;
|
package/test/uuid.js
CHANGED
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const { getUUIDv7, getUUIDTimestamp } = require('../index');
|
|
8
|
-
|
|
1
|
+
import nodetest from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import * as debug$0 from 'debug';
|
|
4
|
+
import { getUUIDv7, getUUIDTimestamp } from '../index.js';
|
|
5
|
+
const { it } = nodetest;
|
|
6
|
+
const debug = debug$0('message');
|
|
9
7
|
it('Should correctly calculate UUIDS given various inputs', async () => {
|
|
10
8
|
const now = new Date();
|
|
11
|
-
|
|
12
9
|
const uuid = getUUIDv7();
|
|
13
10
|
const ts = getUUIDTimestamp(uuid);
|
|
14
11
|
debug(uuid, ts, now);
|
|
15
12
|
const diff = now.getTime() - ts.getTime();
|
|
16
13
|
assert(diff < 1000 && diff >= 0, 'More than a second between newly created');
|
|
17
|
-
|
|
18
14
|
const uuid2 = getUUIDv7(now);
|
|
19
15
|
const ts2 = getUUIDTimestamp(uuid2);
|
|
20
16
|
const diff2 = now.getTime() - ts2.getTime();
|
|
21
17
|
assert(diff2 === 0, 'Timestamps should match');
|
|
22
|
-
|
|
23
18
|
const uuid3 = getUUIDv7(now);
|
|
24
19
|
assert(uuid2 !== uuid3, 'UUIDs should be unique match');
|
|
25
20
|
});
|
package/timelineTypes.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
const SOURCE_CODE_OVERRIDE = 0;
|
|
2
2
|
const CRM_ORIGIN = 1;
|
|
3
3
|
const ACQUISITION = 2;
|
|
4
|
-
|
|
5
4
|
// Generic signup
|
|
6
5
|
const SIGNUP = 3;
|
|
7
6
|
// Known first time signup
|
|
@@ -9,7 +8,6 @@ const SIGNUP_INITIAL = 4;
|
|
|
9
8
|
// Known subsequent signup
|
|
10
9
|
const SIGNUP_SUBSEQUENT = 5;
|
|
11
10
|
const UNSUBSCRIBE = 6;
|
|
12
|
-
|
|
13
11
|
// Generic monetary transaction
|
|
14
12
|
const TRANSACTION = 10;
|
|
15
13
|
// known one-time transaction
|
|
@@ -22,20 +20,16 @@ const TRANSACTION_SUBSEQUENT = 13;
|
|
|
22
20
|
const TRANSACTION_RECURRING = 14;
|
|
23
21
|
// refunded transaction, first instance
|
|
24
22
|
const TRANSACTION_REFUND = 15;
|
|
25
|
-
|
|
26
23
|
const SEGMENT_PERSON_ADD = 16;
|
|
27
24
|
const SEGMENT_PERSON_REMOVE = 17;
|
|
28
|
-
|
|
29
25
|
// unknown generic conversion on a message
|
|
30
26
|
const MESSAGE_CONVERSION = 20;
|
|
31
27
|
// advocacy conversion on a message
|
|
32
28
|
const MESSAGE_CONVERSION_ADVOCACY = 21;
|
|
33
29
|
// unknown transaction conversion on a message
|
|
34
30
|
const MESSAGE_CONVERSION_TRANSACTION = 22;
|
|
35
|
-
|
|
36
31
|
const MESSAGE_DELIVERY_FAILURE_SHOULD_RETRY = 25;
|
|
37
32
|
const MESSAGE_DELIVERY_FAILURE_SHOULD_NOT_RETRY = 26;
|
|
38
|
-
|
|
39
33
|
const SMS_SEND = 30;
|
|
40
34
|
const SMS_DELIVERED = 31;
|
|
41
35
|
const SMS_CLICK = 33;
|
|
@@ -43,7 +37,6 @@ const SMS_UNSUBSCRIBE = 34;
|
|
|
43
37
|
const SMS_BOUNCE = 37;
|
|
44
38
|
const SMS_SPAM = 38;
|
|
45
39
|
const SMS_REPLY = 39;
|
|
46
|
-
|
|
47
40
|
const EMAIL_SEND = 40;
|
|
48
41
|
const EMAIL_DELIVERED = 41;
|
|
49
42
|
const EMAIL_OPEN = 42;
|
|
@@ -54,37 +47,28 @@ const EMAIL_HARD_BOUNCE = 46;
|
|
|
54
47
|
const EMAIL_BOUNCE = 47;
|
|
55
48
|
const EMAIL_SPAM = 48;
|
|
56
49
|
const EMAIL_REPLY = 49;
|
|
57
|
-
|
|
58
50
|
const PHONE_CALL_ATTEMPT = 50;
|
|
59
51
|
const PHONE_CALL_SUCCESS = 51;
|
|
60
52
|
const PHONE_CALL_FAIL = 52;
|
|
61
|
-
|
|
62
53
|
// Generic action
|
|
63
54
|
const FORM_SUBMIT = 60;
|
|
64
55
|
const FORM_PETITION = 61;
|
|
65
56
|
const FORM_PETITION_CONTACT_TARGET = 62;
|
|
66
|
-
|
|
67
57
|
const FORM_ADVOCACY = 66;
|
|
68
58
|
const FORM_SURVEY = 67;
|
|
69
|
-
|
|
70
59
|
const FILE_IMPORT = 70;
|
|
71
|
-
|
|
72
60
|
// For tracking exports or data pushes
|
|
73
61
|
// Generic export of data
|
|
74
62
|
const EXPORT = 80;
|
|
75
|
-
|
|
76
63
|
// Export specifically for pushing data to remote systems
|
|
77
64
|
const EXPORT_FOR_REMOTE = 81;
|
|
78
|
-
|
|
79
65
|
// Export specifically for sending out messages
|
|
80
66
|
const EXPORT_FOR_MESSAGING = 82;
|
|
81
|
-
|
|
82
67
|
//These are for actions we may not have exact
|
|
83
68
|
// details on, but are useful for modeling, etc
|
|
84
69
|
const INFERRED_ENTRY = 91;
|
|
85
70
|
const INFERRED_MESSAGE = 92;
|
|
86
71
|
const INFERRED_FORM = 93;
|
|
87
|
-
|
|
88
72
|
// DO. NOT. CHANGE. (once finalized)
|
|
89
73
|
// should probably have offsets between types
|
|
90
74
|
// ie email, transaction, etc.
|
|
@@ -104,10 +88,8 @@ const TIMELINE_ENTRY_TYPES = {
|
|
|
104
88
|
TRANSACTION_ONE_TIME,
|
|
105
89
|
TRANSACTION_RECURRING,
|
|
106
90
|
TRANSACTION_REFUND,
|
|
107
|
-
|
|
108
91
|
SEGMENT_PERSON_ADD,
|
|
109
92
|
SEGMENT_PERSON_REMOVE,
|
|
110
|
-
|
|
111
93
|
SMS_SEND,
|
|
112
94
|
SMS_DELIVERED,
|
|
113
95
|
SMS_CLICK,
|
|
@@ -115,7 +97,6 @@ const TIMELINE_ENTRY_TYPES = {
|
|
|
115
97
|
SMS_BOUNCE,
|
|
116
98
|
SMS_SPAM,
|
|
117
99
|
SMS_REPLY,
|
|
118
|
-
|
|
119
100
|
// email interactions
|
|
120
101
|
EMAIL_SEND,
|
|
121
102
|
EMAIL_DELIVERED,
|
|
@@ -127,24 +108,20 @@ const TIMELINE_ENTRY_TYPES = {
|
|
|
127
108
|
EMAIL_BOUNCE,
|
|
128
109
|
EMAIL_REPLY,
|
|
129
110
|
EMAIL_SPAM,
|
|
130
|
-
|
|
131
111
|
PHONE_CALL_ATTEMPT,
|
|
132
112
|
PHONE_CALL_SUCCESS,
|
|
133
113
|
PHONE_CALL_FAIL,
|
|
134
|
-
|
|
135
114
|
// forms
|
|
136
115
|
FORM_SUBMIT,
|
|
137
116
|
FORM_PETITION,
|
|
138
117
|
FORM_PETITION_CONTACT_TARGET,
|
|
139
118
|
FORM_ADVOCACY,
|
|
140
119
|
FORM_SURVEY,
|
|
141
|
-
|
|
142
120
|
MESSAGE_CONVERSION,
|
|
143
121
|
MESSAGE_CONVERSION_ADVOCACY,
|
|
144
122
|
MESSAGE_CONVERSION_TRANSACTION,
|
|
145
123
|
MESSAGE_DELIVERY_FAILURE_SHOULD_RETRY,
|
|
146
124
|
MESSAGE_DELIVERY_FAILURE_SHOULD_NOT_RETRY,
|
|
147
|
-
|
|
148
125
|
FILE_IMPORT,
|
|
149
126
|
EXPORT,
|
|
150
127
|
EXPORT_FOR_REMOTE,
|
|
@@ -156,6 +133,7 @@ const TIMELINE_ENTRY_TYPES = {
|
|
|
156
133
|
Object.entries(TIMELINE_ENTRY_TYPES).forEach(([k, v]) => {
|
|
157
134
|
TIMELINE_ENTRY_TYPES[v] = k;
|
|
158
135
|
});
|
|
159
|
-
|
|
136
|
+
export { TIMELINE_ENTRY_TYPES };
|
|
137
|
+
export default {
|
|
160
138
|
TIMELINE_ENTRY_TYPES
|
|
161
139
|
};
|