make-mp-data 1.4.1 → 1.4.3
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 +3 -2
- package/{cli.js → core/cli.js} +1 -1
- package/core/defaults.js +960 -0
- package/{index.js → core/index.js} +217 -87
- package/{utils.js → core/utils.js} +163 -34
- package/package.json +8 -9
- package/schemas/anon.js +104 -0
- package/schemas/complex.js +11 -2
- package/schemas/deepNest.js +5 -1
- package/schemas/foobar.js +2 -2
- package/schemas/funnels.js +1 -1
- package/schemas/simple.js +11 -1
- package/scratch.mjs +19 -5
- package/scripts/jsdoctest.js +1 -1
- package/tests/e2e.test.js +25 -7
- package/{testSoup.mjs → tests/testSoup.mjs} +2 -2
- package/tests/unit.test.js +157 -9
- package/tsconfig.json +1 -1
- package/types.d.ts +17 -3
- package/defaults.js +0 -11662
- /package/{chart.js → core/chart.js} +0 -0
- /package/{testCases.mjs → tests/testCases.mjs} +0 -0
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const Chance = require('chance');
|
|
3
3
|
const readline = require('readline');
|
|
4
|
-
const { comma, uid } = require('ak-tools');
|
|
4
|
+
const { comma, uid, clone } = require('ak-tools');
|
|
5
5
|
const { spawn } = require('child_process');
|
|
6
6
|
const dayjs = require('dayjs');
|
|
7
7
|
const utc = require('dayjs/plugin/utc');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const { mkdir } = require('ak-tools');
|
|
10
|
+
const { existsSync } = require('fs');
|
|
10
11
|
dayjs.extend(utc);
|
|
11
12
|
require('dotenv').config();
|
|
13
|
+
const { domainSuffix, domainPrefix } = require('./defaults');
|
|
12
14
|
|
|
13
|
-
/** @typedef {import('
|
|
14
|
-
/** @typedef {import('
|
|
15
|
-
/** @typedef {import('
|
|
16
|
-
/** @typedef {import('
|
|
17
|
-
/** @typedef {import('
|
|
18
|
-
/** @typedef {import('
|
|
19
|
-
/** @typedef {import('
|
|
15
|
+
/** @typedef {import('../types').Config} Config */
|
|
16
|
+
/** @typedef {import('../types').EventConfig} EventConfig */
|
|
17
|
+
/** @typedef {import('../types').ValueValid} ValueValid */
|
|
18
|
+
/** @typedef {import('../types').EnrichedArray} EnrichArray */
|
|
19
|
+
/** @typedef {import('../types').EnrichArrayOptions} EnrichArrayOptions */
|
|
20
|
+
/** @typedef {import('../types').Person} Person */
|
|
21
|
+
/** @typedef {import('../types').Funnel} Funnel */
|
|
20
22
|
|
|
21
23
|
let globalChance;
|
|
22
24
|
let chanceInitialized = false;
|
|
23
25
|
|
|
26
|
+
|
|
27
|
+
|
|
24
28
|
/*
|
|
25
29
|
----
|
|
26
30
|
RNG
|
|
@@ -127,6 +131,21 @@ function dates(inTheLast = 30, numPairs = 5, format = 'YYYY-MM-DD') {
|
|
|
127
131
|
return pairs;
|
|
128
132
|
};
|
|
129
133
|
|
|
134
|
+
function datesBetween(start, end) {
|
|
135
|
+
const result = [];
|
|
136
|
+
if (typeof start === 'number') start = dayjs.unix(start).utc();
|
|
137
|
+
if (typeof start !== 'number') start = dayjs(start).utc();
|
|
138
|
+
if (typeof end === 'number') end = dayjs.unix(end).utc();
|
|
139
|
+
if (typeof end !== 'number') end = dayjs(end).utc();
|
|
140
|
+
const diff = end.diff(start, 'day');
|
|
141
|
+
for (let i = 0; i < diff; i++) {
|
|
142
|
+
const day = start.add(i, 'day').startOf('day').add(12, 'hour');
|
|
143
|
+
result.push(day.toISOString());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
/**
|
|
131
150
|
* returns a random date
|
|
132
151
|
* @param {any} start
|
|
@@ -223,35 +242,67 @@ function integer(min = 1, max = 100) {
|
|
|
223
242
|
};
|
|
224
243
|
|
|
225
244
|
|
|
245
|
+
/**
|
|
246
|
+
* Creates a function that generates a weighted list of items
|
|
247
|
+
* with a higher likelihood of picking a specified index and clear second and third place indices.
|
|
248
|
+
*
|
|
249
|
+
* @param {Array} items - The list of items to pick from.
|
|
250
|
+
* @param {number} [mostChosenIndex] - The index of the item to be most favored.
|
|
251
|
+
* @returns {function} - A function that returns a weighted list of items.
|
|
252
|
+
*/
|
|
226
253
|
function pickAWinner(items, mostChosenIndex) {
|
|
227
254
|
const chance = getChance();
|
|
228
|
-
|
|
255
|
+
|
|
256
|
+
// Ensure mostChosenIndex is within the bounds of the items array
|
|
257
|
+
if (!items) return () => { return ""; };
|
|
258
|
+
if (!items.length) return () => { return ""; };
|
|
259
|
+
if (!mostChosenIndex) mostChosenIndex = chance.integer({ min: 0, max: items.length - 1 });
|
|
260
|
+
if (mostChosenIndex >= items.length) mostChosenIndex = items.length - 1;
|
|
261
|
+
|
|
262
|
+
// Calculate second and third most chosen indices
|
|
263
|
+
const secondMostChosenIndex = (mostChosenIndex + 1) % items.length;
|
|
264
|
+
const thirdMostChosenIndex = (mostChosenIndex + 2) % items.length;
|
|
265
|
+
|
|
266
|
+
// Return a function that generates a weighted list
|
|
229
267
|
return function () {
|
|
230
268
|
const weighted = [];
|
|
231
269
|
for (let i = 0; i < 10; i++) {
|
|
232
|
-
|
|
270
|
+
const rand = chance.d10(); // Random number between 1 and 10
|
|
271
|
+
|
|
272
|
+
// 35% chance to favor the most chosen index
|
|
273
|
+
if (chance.bool({ likelihood: 35 })) {
|
|
274
|
+
// 50% chance to slightly alter the index
|
|
233
275
|
if (chance.bool({ likelihood: 50 })) {
|
|
234
276
|
weighted.push(items[mostChosenIndex]);
|
|
235
|
-
}
|
|
236
|
-
else {
|
|
237
|
-
const rand = chance.d10();
|
|
277
|
+
} else {
|
|
238
278
|
const addOrSubtract = chance.bool({ likelihood: 50 }) ? -rand : rand;
|
|
239
279
|
let newIndex = mostChosenIndex + addOrSubtract;
|
|
280
|
+
|
|
281
|
+
// Ensure newIndex is within bounds
|
|
240
282
|
if (newIndex < 0) newIndex = 0;
|
|
241
|
-
if (newIndex
|
|
283
|
+
if (newIndex >= items.length) newIndex = items.length - 1;
|
|
242
284
|
weighted.push(items[newIndex]);
|
|
243
285
|
}
|
|
244
286
|
}
|
|
287
|
+
// 25% chance to favor the second most chosen index
|
|
288
|
+
else if (chance.bool({ likelihood: 25 })) {
|
|
289
|
+
weighted.push(items[secondMostChosenIndex]);
|
|
290
|
+
}
|
|
291
|
+
// 15% chance to favor the third most chosen index
|
|
292
|
+
else if (chance.bool({ likelihood: 15 })) {
|
|
293
|
+
weighted.push(items[thirdMostChosenIndex]);
|
|
294
|
+
}
|
|
295
|
+
// Otherwise, pick a random item from the list
|
|
245
296
|
else {
|
|
246
297
|
weighted.push(chance.pickone(items));
|
|
247
298
|
}
|
|
248
299
|
}
|
|
249
300
|
return weighted;
|
|
250
|
-
|
|
251
301
|
};
|
|
252
302
|
}
|
|
253
303
|
|
|
254
304
|
|
|
305
|
+
|
|
255
306
|
/*
|
|
256
307
|
----
|
|
257
308
|
GENERATORS
|
|
@@ -274,7 +325,10 @@ function optimizedBoxMuller() {
|
|
|
274
325
|
const chance = getChance();
|
|
275
326
|
const u = Math.max(Math.min(chance.normal({ mean: .5, dev: .25 }), 1), 0);
|
|
276
327
|
const v = Math.max(Math.min(chance.normal({ mean: .5, dev: .25 }), 1), 0);
|
|
277
|
-
|
|
328
|
+
const result = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
|
|
329
|
+
//ensure we didn't get infinity
|
|
330
|
+
if (result === Infinity || result === -Infinity) return chance.floating({ min: 0, max: 1 });
|
|
331
|
+
return result;
|
|
278
332
|
|
|
279
333
|
}
|
|
280
334
|
|
|
@@ -314,6 +368,53 @@ function range(a, b, step = 1) {
|
|
|
314
368
|
};
|
|
315
369
|
|
|
316
370
|
|
|
371
|
+
/**
|
|
372
|
+
* create funnels out of random events
|
|
373
|
+
* @param {EventConfig[]} events
|
|
374
|
+
*/
|
|
375
|
+
function inferFunnels(events) {
|
|
376
|
+
const createdFunnels = [];
|
|
377
|
+
const firstEvents = events.filter((e) => e.isFirstEvent).map((e) => e.event);
|
|
378
|
+
const usageEvents = events.filter((e) => !e.isFirstEvent).map((e) => e.event);
|
|
379
|
+
const numFunnelsToCreate = Math.ceil(usageEvents.length);
|
|
380
|
+
/** @type {Funnel} */
|
|
381
|
+
const funnelTemplate = {
|
|
382
|
+
sequence: [],
|
|
383
|
+
conversionRate: 50,
|
|
384
|
+
order: 'sequential',
|
|
385
|
+
requireRepeats: false,
|
|
386
|
+
props: {},
|
|
387
|
+
timeToConvert: 1,
|
|
388
|
+
isFirstFunnel: false,
|
|
389
|
+
weight: 1
|
|
390
|
+
};
|
|
391
|
+
if (firstEvents.length) {
|
|
392
|
+
for (const event of firstEvents) {
|
|
393
|
+
createdFunnels.push({ ...clone(funnelTemplate), sequence: [event], isFirstFunnel: true, conversionRate: 100 });
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
//at least one funnel with all usage events
|
|
398
|
+
createdFunnels.push({ ...clone(funnelTemplate), sequence: usageEvents });
|
|
399
|
+
|
|
400
|
+
//for the rest, make random funnels
|
|
401
|
+
followUpFunnels: for (let i = 1; i < numFunnelsToCreate; i++) {
|
|
402
|
+
/** @type {Funnel} */
|
|
403
|
+
const funnel = { ...clone(funnelTemplate) };
|
|
404
|
+
funnel.conversionRate = integer(25, 75);
|
|
405
|
+
funnel.timeToConvert = integer(1, 10);
|
|
406
|
+
funnel.weight = integer(1, 10);
|
|
407
|
+
const sequence = shuffleArray(usageEvents).slice(0, integer(2, usageEvents.length));
|
|
408
|
+
funnel.sequence = sequence;
|
|
409
|
+
funnel.order = 'random';
|
|
410
|
+
createdFunnels.push(funnel);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return createdFunnels;
|
|
414
|
+
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
|
|
317
418
|
/*
|
|
318
419
|
----
|
|
319
420
|
STREAMERS
|
|
@@ -379,8 +480,11 @@ function weighFunnels(acc, funnel) {
|
|
|
379
480
|
/**
|
|
380
481
|
* a utility function to generate a range of numbers within a given skew
|
|
381
482
|
* Skew = 0.5: The values are more concentrated towards the extremes (both ends of the range) with a noticeable dip in the middle. The distribution appears more "U" shaped. Larger sizes result in smoother distributions but maintain the overall shape.
|
|
483
|
+
*
|
|
382
484
|
* Skew = 1: This represents the default normal distribution without skew. The values are normally distributed around the mean. Larger sizes create a clearer bell-shaped curve.
|
|
485
|
+
*
|
|
383
486
|
* Skew = 2: The values are more concentrated towards the mean, with a steeper drop-off towards the extremes. The distribution appears more peaked, resembling a "sharper" bell curve. Larger sizes enhance the clarity of this peaked distribution.
|
|
487
|
+
*
|
|
384
488
|
* Size represents the size of the pool to choose from; Larger sizes result in smoother distributions but maintain the overall shape.
|
|
385
489
|
* @param {number} min
|
|
386
490
|
* @param {number} max
|
|
@@ -471,6 +575,7 @@ function shuffleOutside(array) {
|
|
|
471
575
|
}
|
|
472
576
|
|
|
473
577
|
/**
|
|
578
|
+
* given a funnel, shuffle the events in the sequence with random events
|
|
474
579
|
* @param {EventConfig[]} funnel
|
|
475
580
|
* @param {EventConfig[]} possibles
|
|
476
581
|
*/
|
|
@@ -616,13 +721,18 @@ function buildFileNames(config) {
|
|
|
616
721
|
// const current = dayjs.utc().format("MM-DD-HH");
|
|
617
722
|
const simName = config.simulationName;
|
|
618
723
|
let writeDir = "./";
|
|
619
|
-
if (config.writeToDisk)
|
|
724
|
+
if (config.writeToDisk) {
|
|
725
|
+
const dataFolder = path.resolve("./data");
|
|
726
|
+
if (existsSync(dataFolder)) writeDir = dataFolder;
|
|
727
|
+
else writeDir = path.resolve("./");
|
|
728
|
+
}
|
|
620
729
|
if (typeof writeDir !== "string") throw new Error("writeDir must be a string");
|
|
621
730
|
if (typeof simName !== "string") throw new Error("simName must be a string");
|
|
622
731
|
|
|
623
732
|
const writePaths = {
|
|
624
733
|
eventFiles: [path.join(writeDir, `${simName}-EVENTS.${extension}`)],
|
|
625
734
|
userFiles: [path.join(writeDir, `${simName}-USERS.${extension}`)],
|
|
735
|
+
adSpendFiles: [path.join(writeDir, `${simName}-AD-SPEND.${extension}`)],
|
|
626
736
|
scdFiles: [],
|
|
627
737
|
mirrorFiles: [],
|
|
628
738
|
groupFiles: [],
|
|
@@ -667,11 +777,19 @@ function buildFileNames(config) {
|
|
|
667
777
|
return writePaths;
|
|
668
778
|
}
|
|
669
779
|
|
|
670
|
-
|
|
671
|
-
|
|
780
|
+
/**
|
|
781
|
+
* @param {[string, number][]} arrayOfArrays
|
|
782
|
+
*/
|
|
783
|
+
function progress(arrayOfArrays) {
|
|
672
784
|
// @ts-ignore
|
|
673
785
|
readline.cursorTo(process.stdout, 0);
|
|
674
|
-
|
|
786
|
+
let message = "";
|
|
787
|
+
for (const status of arrayOfArrays) {
|
|
788
|
+
const [thing, p] = status;
|
|
789
|
+
message += `${thing} processed: ${comma(p)}\t\t`;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
process.stdout.write(message);
|
|
675
793
|
};
|
|
676
794
|
|
|
677
795
|
|
|
@@ -769,31 +887,33 @@ function TimeSoup(earliestTime, latestTime, peaks = 5, deviation = 2, mean = 0)
|
|
|
769
887
|
|
|
770
888
|
|
|
771
889
|
/**
|
|
890
|
+
* @param {string} userId
|
|
772
891
|
* @param {number} bornDaysAgo=30
|
|
892
|
+
* @param {boolean} isAnonymous
|
|
773
893
|
* @return {Person}
|
|
774
894
|
*/
|
|
775
|
-
function person(bornDaysAgo = 30) {
|
|
895
|
+
function person(userId, bornDaysAgo = 30, isAnonymous = false) {
|
|
776
896
|
const chance = getChance();
|
|
777
897
|
//names and photos
|
|
898
|
+
const l = chance.letter.bind(chance);
|
|
778
899
|
let gender = chance.pickone(['male', 'female']);
|
|
779
900
|
if (!gender) gender = "female";
|
|
780
901
|
// @ts-ignore
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
const avPath = gender === 'male' ? `/men/${randomAvatarNumber}.jpg` : `/women/${randomAvatarNumber}.jpg`;
|
|
791
|
-
const avatar = avatarPrefix + avPath;
|
|
792
|
-
const created = dayjs.unix(global.NOW).subtract(bornDaysAgo, 'day').format('YYYY-MM-DD');
|
|
902
|
+
let first = chance.first({ gender });
|
|
903
|
+
let last = chance.last();
|
|
904
|
+
let name = `${first} ${last}`;
|
|
905
|
+
let email = `${first[0]}.${last}@${choose(domainPrefix)}.${choose(domainSuffix)}`;
|
|
906
|
+
let avatarPrefix = `https://randomuser.me/api/portraits`;
|
|
907
|
+
let randomAvatarNumber = integer(1, 99);
|
|
908
|
+
let avPath = gender === 'male' ? `/men/${randomAvatarNumber}.jpg` : `/women/${randomAvatarNumber}.jpg`;
|
|
909
|
+
let avatar = avatarPrefix + avPath;
|
|
910
|
+
let created = dayjs.unix(global.NOW).subtract(bornDaysAgo, 'day').format('YYYY-MM-DD');
|
|
793
911
|
// const created = date(bornDaysAgo, true)();
|
|
794
912
|
|
|
913
|
+
|
|
795
914
|
/** @type {Person} */
|
|
796
915
|
const user = {
|
|
916
|
+
distinct_id: userId,
|
|
797
917
|
name,
|
|
798
918
|
email,
|
|
799
919
|
avatar,
|
|
@@ -802,6 +922,13 @@ function person(bornDaysAgo = 30) {
|
|
|
802
922
|
sessionIds: []
|
|
803
923
|
};
|
|
804
924
|
|
|
925
|
+
if (isAnonymous) {
|
|
926
|
+
user.name = "Anonymous User";
|
|
927
|
+
user.email = l() + l() + `*`.repeat(integer(3, 6)) + l() + `@` + l() + `*`.repeat(integer(3, 6)) + l() + `.` + choose(domainSuffix);
|
|
928
|
+
delete user.avatar;
|
|
929
|
+
|
|
930
|
+
}
|
|
931
|
+
|
|
805
932
|
//anon Ids
|
|
806
933
|
if (global.MP_SIMULATION_CONFIG?.anonIds) {
|
|
807
934
|
const clusterSize = integer(2, 10);
|
|
@@ -921,5 +1048,7 @@ module.exports = {
|
|
|
921
1048
|
optimizedBoxMuller,
|
|
922
1049
|
buildFileNames,
|
|
923
1050
|
streamJSON,
|
|
924
|
-
streamCSV
|
|
1051
|
+
streamCSV,
|
|
1052
|
+
inferFunnels,
|
|
1053
|
+
datesBetween
|
|
925
1054
|
};
|
package/package.json
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-mp-data",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.03",
|
|
4
4
|
"description": "builds all mixpanel primitives for a given project",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"start": "node index.js",
|
|
8
|
+
"start": "node ./core/index.js",
|
|
9
9
|
"dev": "nodemon scratch.mjs --ignore /data",
|
|
10
|
-
"complex": "nodemon index.js --complex --e 10000 --u 100",
|
|
11
|
-
"simple": "nodemon index.js --simple --e 10000 --u 100",
|
|
10
|
+
"complex": "nodemon ./core/index.js --complex --e 10000 --u 100",
|
|
11
|
+
"simple": "nodemon ./core/index.js --simple --e 10000 --u 100",
|
|
12
12
|
"prune": "rm -f ./data/* && rm -f ./tmp/*",
|
|
13
13
|
"post": "npm publish",
|
|
14
14
|
"test": "NODE_ENV=test jest --runInBand",
|
|
15
|
-
"deps": "sh ./scripts/deps.sh"
|
|
16
|
-
"udacity": "nodemon index.js ./customers/udacity.js"
|
|
15
|
+
"deps": "sh ./scripts/deps.sh"
|
|
17
16
|
},
|
|
18
17
|
"repository": {
|
|
19
18
|
"type": "git",
|
|
20
19
|
"url": "git+https://github.com/ak--47/make-mp-data.git"
|
|
21
20
|
},
|
|
22
21
|
"bin": {
|
|
23
|
-
"make-mp-data": "./index.js"
|
|
22
|
+
"make-mp-data": "./core/index.js"
|
|
24
23
|
},
|
|
25
24
|
"keywords": [
|
|
26
25
|
"mixpanel",
|
|
@@ -47,7 +46,7 @@
|
|
|
47
46
|
"chartjs-node-canvas": "^4.1.6",
|
|
48
47
|
"dayjs": "^1.11.11",
|
|
49
48
|
"dotenv": "^16.4.5",
|
|
50
|
-
"mixpanel-import": "^2.5.
|
|
49
|
+
"mixpanel-import": "^2.5.552",
|
|
51
50
|
"yargs": "^17.7.2"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
@@ -57,4 +56,4 @@
|
|
|
57
56
|
"jest": {
|
|
58
57
|
"preset": "./tests/jest.config.js"
|
|
59
58
|
}
|
|
60
|
-
}
|
|
59
|
+
}
|
package/schemas/anon.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the default configuration file for the data generator in SIMPLE mode
|
|
3
|
+
* notice how the config object is structured, and see it's type definition in ./types.d.ts
|
|
4
|
+
* feel free to modify this file to customize the data you generate
|
|
5
|
+
* see helper functions in utils.js for more ways to generate data
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const Chance = require('chance');
|
|
12
|
+
const chance = new Chance();
|
|
13
|
+
const dayjs = require("dayjs");
|
|
14
|
+
const utc = require("dayjs/plugin/utc");
|
|
15
|
+
dayjs.extend(utc);
|
|
16
|
+
const { uid, comma } = require('ak-tools');
|
|
17
|
+
const { pickAWinner, weightedRange, date, integer } = require('../core/utils');
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
/** @type {import('../types').Config} */
|
|
22
|
+
const config = {
|
|
23
|
+
token: "",
|
|
24
|
+
seed: "foo bar",
|
|
25
|
+
numDays: 365, //how many days worth of data
|
|
26
|
+
numEvents: 100000, //how many events
|
|
27
|
+
numUsers: 10000, //how many users
|
|
28
|
+
format: 'json', //csv or json
|
|
29
|
+
region: "US",
|
|
30
|
+
anonIds: true, //if true, anonymousIds are created for each user
|
|
31
|
+
sessionIds: false, //if true, sessionIds are created for each user
|
|
32
|
+
isAnonymous: true,
|
|
33
|
+
hasLocation: true,
|
|
34
|
+
events: [
|
|
35
|
+
{
|
|
36
|
+
event: "foo",
|
|
37
|
+
weight: 10,
|
|
38
|
+
properties: {}
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
event: "bar",
|
|
42
|
+
weight: 9,
|
|
43
|
+
properties: {}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
event: "baz",
|
|
47
|
+
weight: 8,
|
|
48
|
+
properties: {}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
event: "qux",
|
|
52
|
+
weight: 7,
|
|
53
|
+
properties: {}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
event: "garply",
|
|
57
|
+
weight: 6,
|
|
58
|
+
properties: {}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
event: "durtle",
|
|
62
|
+
weight: 5,
|
|
63
|
+
properties: {}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
event: "linny",
|
|
67
|
+
weight: 4,
|
|
68
|
+
properties: {}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
event: "fonk",
|
|
72
|
+
weight: 3,
|
|
73
|
+
properties: {}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
event: "crumn",
|
|
77
|
+
weight: 2,
|
|
78
|
+
properties: {}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
event: "yak",
|
|
82
|
+
weight: 1,
|
|
83
|
+
properties: {}
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
superProps: {},
|
|
87
|
+
userProps: {
|
|
88
|
+
title: chance.profession.bind(chance),
|
|
89
|
+
luckyNumber: weightedRange(42, 420),
|
|
90
|
+
spiritAnimal: ["duck", "dog", "otter", "penguin", "cat", "elephant", "lion", "cheetah", "giraffe", "zebra", "rhino", "hippo", "whale", "dolphin", "shark", "octopus", "squid", "jellyfish", "starfish", "seahorse", "crab", "lobster", "shrimp", "clam", "snail", "slug", "butterfly", "moth", "bee", "wasp", "ant", "beetle", "ladybug", "caterpillar", "centipede", "millipede", "scorpion", "spider", "tarantula", "tick", "mite", "mosquito", "fly", "dragonfly", "damselfly", "grasshopper", "cricket", "locust", "mantis", "cockroach", "termite", "praying mantis", "walking stick", "stick bug", "leaf insect", "lacewing", "aphid", "cicada", "thrips", "psyllid", "scale insect", "whitefly", "mealybug", "planthopper", "leafhopper", "treehopper", "flea", "louse", "bedbug", "flea beetle", "weevil", "longhorn beetle", "leaf beetle", "tiger beetle", "ground beetle", "lady beetle", "firefly", "click beetle", "rove beetle", "scarab beetle", "dung beetle", "stag beetle", "rhinoceros beetle", "hercules beetle", "goliath beetle", "jewel beetle", "tortoise beetle"]
|
|
91
|
+
},
|
|
92
|
+
scdProps: {},
|
|
93
|
+
mirrorProps: {},
|
|
94
|
+
groupKeys: [],
|
|
95
|
+
groupProps: {},
|
|
96
|
+
lookupTables: [],
|
|
97
|
+
hook: function (record, type, meta) {
|
|
98
|
+
return record;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
module.exports = config;
|
package/schemas/complex.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const Chance = require('chance');
|
|
10
10
|
const chance = new Chance();
|
|
11
|
-
const { weightedRange, date, integer } = require('../utils.js');
|
|
11
|
+
const { weightedRange, date, integer } = require('../core/utils.js');
|
|
12
12
|
const u = require('ak-tools');
|
|
13
13
|
|
|
14
14
|
/** @type {import('../types.js').Config} */
|
|
@@ -23,6 +23,15 @@ const config = {
|
|
|
23
23
|
anonIds: true, //if true, anonymousIds are created for each user
|
|
24
24
|
sessionIds: true, //if true, sessionIds are created for each user
|
|
25
25
|
|
|
26
|
+
hasLocation: true,
|
|
27
|
+
hasAndroidDevices: true,
|
|
28
|
+
hasIOSDevices: true,
|
|
29
|
+
hasDesktopDevices: true,
|
|
30
|
+
hasBrowser: true,
|
|
31
|
+
hasCampaigns: true,
|
|
32
|
+
isAnonymous: false,
|
|
33
|
+
hasAdSpend: true,
|
|
34
|
+
|
|
26
35
|
events: [
|
|
27
36
|
{
|
|
28
37
|
"event": "checkout",
|
|
@@ -122,7 +131,7 @@ const config = {
|
|
|
122
131
|
}
|
|
123
132
|
],
|
|
124
133
|
superProps: {
|
|
125
|
-
|
|
134
|
+
linked_device: deviceAttributes()
|
|
126
135
|
// emotions: generateEmoji(),
|
|
127
136
|
|
|
128
137
|
},
|
package/schemas/deepNest.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const Chance = require('chance');
|
|
2
2
|
const chance = new Chance();
|
|
3
|
+
const u = require('../core/utils');
|
|
4
|
+
|
|
5
|
+
const plans = ['free', 'premium', 'casual', 'influencer'];
|
|
6
|
+
const marketingChannels = ["Organic", "Organic", "Organic", "Organic", "Instagram Ads", "Facebook Ads", "Google Ads", "Youtube Ads", "Instagram Post", "Instagram Post", "Facebook Post"];
|
|
3
7
|
|
|
4
8
|
const config = {
|
|
5
9
|
token: "",
|
|
@@ -35,7 +39,7 @@ function generateVideoMeta() {
|
|
|
35
39
|
availableFormats: chance.pickset(formats, int(1, formats.length)),
|
|
36
40
|
availableAspectRatios: chance.pickset(ratios, int(1, ratios.length)),
|
|
37
41
|
availableContainerFormats: chance.pickset(containers, int(1, containers.length)),
|
|
38
|
-
observedLatencyTimestamps: chance.pickset(
|
|
42
|
+
observedLatencyTimestamps: chance.pickset(u.range(1, 300000), int(1, 40))
|
|
39
43
|
},
|
|
40
44
|
videoStats: {
|
|
41
45
|
numberOfPlays: int(10, 10000000),
|
package/schemas/foobar.js
CHANGED
|
@@ -14,7 +14,7 @@ const dayjs = require("dayjs");
|
|
|
14
14
|
const utc = require("dayjs/plugin/utc");
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
const { uid, comma } = require('ak-tools');
|
|
17
|
-
const { pickAWinner, weightedRange, date, integer } = require('../utils');
|
|
17
|
+
const { pickAWinner, weightedRange, date, integer } = require('../core/utils');
|
|
18
18
|
|
|
19
19
|
const itemCategories = ["Books", "Movies", "Music", "Games", "Electronics", "Computers", "Smart Home", "Home", "Garden", "Pet", "Beauty", "Health", "Toys", "Kids", "Baby", "Handmade", "Sports", "Outdoors", "Automotive", "Industrial", "Entertainment", "Art", "Food", "Appliances", "Office", "Wedding", "Software"];
|
|
20
20
|
|
|
@@ -31,7 +31,7 @@ const config = {
|
|
|
31
31
|
region: "US",
|
|
32
32
|
anonIds: true, //if true, anonymousIds are created for each user
|
|
33
33
|
sessionIds: false, //if true, sessionIds are created for each user
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
events: [
|
|
36
36
|
{
|
|
37
37
|
event: "foo",
|
package/schemas/funnels.js
CHANGED
|
@@ -14,7 +14,7 @@ const dayjs = require("dayjs");
|
|
|
14
14
|
const utc = require("dayjs/plugin/utc");
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
const { uid, comma } = require('ak-tools');
|
|
17
|
-
const { pickAWinner, weightedRange, date, integer } = require('../utils');
|
|
17
|
+
const { pickAWinner, weightedRange, date, integer } = require('../core/utils');
|
|
18
18
|
|
|
19
19
|
const itemCategories = ["Books", "Movies", "Music", "Games", "Electronics", "Computers", "Smart Home", "Home", "Garden", "Pet", "Beauty", "Health", "Toys", "Kids", "Baby", "Handmade", "Sports", "Outdoors", "Automotive", "Industrial", "Entertainment", "Art", "Food", "Appliances", "Office", "Wedding", "Software"];
|
|
20
20
|
|
package/schemas/simple.js
CHANGED
|
@@ -14,7 +14,7 @@ const dayjs = require("dayjs");
|
|
|
14
14
|
const utc = require("dayjs/plugin/utc");
|
|
15
15
|
dayjs.extend(utc);
|
|
16
16
|
const { uid, comma } = require('ak-tools');
|
|
17
|
-
const { pickAWinner, weightedRange, date, integer } = require('../utils');
|
|
17
|
+
const { pickAWinner, weightedRange, date, integer } = require('../core/utils');
|
|
18
18
|
|
|
19
19
|
const itemCategories = ["Books", "Movies", "Music", "Games", "Electronics", "Computers", "Smart Home", "Home", "Garden", "Pet", "Beauty", "Health", "Toys", "Kids", "Baby", "Handmade", "Sports", "Outdoors", "Automotive", "Industrial", "Entertainment", "Art", "Food", "Appliances", "Office", "Wedding", "Software"];
|
|
20
20
|
|
|
@@ -31,6 +31,16 @@ const config = {
|
|
|
31
31
|
region: "US",
|
|
32
32
|
anonIds: false, //if true, anonymousIds are created for each user
|
|
33
33
|
sessionIds: false, //if true, sessionIds are created for each user
|
|
34
|
+
hasAdSpend: false,
|
|
35
|
+
|
|
36
|
+
hasLocation: true,
|
|
37
|
+
hasAndroidDevices: true,
|
|
38
|
+
hasIOSDevices: true,
|
|
39
|
+
hasDesktopDevices: true,
|
|
40
|
+
hasBrowser: true,
|
|
41
|
+
hasCampaigns: true,
|
|
42
|
+
isAnonymous: false,
|
|
43
|
+
|
|
34
44
|
|
|
35
45
|
events: [
|
|
36
46
|
{
|
package/scratch.mjs
CHANGED
|
@@ -1,22 +1,36 @@
|
|
|
1
|
-
import main from "./index.js";
|
|
1
|
+
import main from "./core/index.js";
|
|
2
2
|
import amir from './customers/amir.js';
|
|
3
3
|
import simple from './schemas/simple.js';
|
|
4
4
|
import funnels from './schemas/funnels.js';
|
|
5
5
|
import foobar from './schemas/foobar.js';
|
|
6
6
|
import complex from './schemas/complex.js';
|
|
7
7
|
import deepNest from './schemas/deepNest.js';
|
|
8
|
+
import anon from './schemas/anon.js';
|
|
8
9
|
import execSync from 'child_process';
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
/** @type {main.Config} */
|
|
12
|
-
const spec = {
|
|
13
|
-
...
|
|
13
|
+
const spec = {
|
|
14
|
+
...complex,
|
|
14
15
|
writeToDisk: false,
|
|
15
16
|
verbose: true,
|
|
16
|
-
makeChart: false,
|
|
17
|
+
makeChart: false,
|
|
18
|
+
numUsers: 100,
|
|
19
|
+
numEvents: 10000,
|
|
20
|
+
numDays: 90,
|
|
21
|
+
token: ""
|
|
17
22
|
};
|
|
18
23
|
|
|
19
24
|
|
|
20
25
|
execSync.execSync('npm run prune');
|
|
21
|
-
const { eventData,
|
|
26
|
+
const { eventData,
|
|
27
|
+
groupProfilesData,
|
|
28
|
+
lookupTableData,
|
|
29
|
+
mirrorEventData,
|
|
30
|
+
scdTableData,
|
|
31
|
+
userProfilesData,
|
|
32
|
+
importResults,
|
|
33
|
+
files,
|
|
34
|
+
adSpendData
|
|
35
|
+
} = await main(spec);
|
|
22
36
|
debugger;
|
package/scripts/jsdoctest.js
CHANGED