make-mp-data 1.4.2 → 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/{defaults.js → core/defaults.js} +48 -62
- package/{index.js → core/index.js} +113 -89
- package/{utils.js → core/utils.js} +139 -69
- package/package.json +7 -8
- 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 +1 -1
- package/scratch.mjs +18 -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 +153 -6
- package/tsconfig.json +1 -1
- package/types.d.ts +2 -1
- /package/{chart.js → core/chart.js} +0 -0
- /package/{testCases.mjs → tests/testCases.mjs} +0 -0
|
@@ -7,20 +7,24 @@ 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,77 +242,66 @@ 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
|
-
|
|
229
|
-
|
|
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
|
|
230
267
|
return function () {
|
|
231
268
|
const weighted = [];
|
|
232
269
|
for (let i = 0; i < 10; i++) {
|
|
233
|
-
|
|
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
|
|
234
275
|
if (chance.bool({ likelihood: 50 })) {
|
|
235
276
|
weighted.push(items[mostChosenIndex]);
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
const rand = chance.d10();
|
|
277
|
+
} else {
|
|
239
278
|
const addOrSubtract = chance.bool({ likelihood: 50 }) ? -rand : rand;
|
|
240
279
|
let newIndex = mostChosenIndex + addOrSubtract;
|
|
280
|
+
|
|
281
|
+
// Ensure newIndex is within bounds
|
|
241
282
|
if (newIndex < 0) newIndex = 0;
|
|
242
|
-
if (newIndex
|
|
283
|
+
if (newIndex >= items.length) newIndex = items.length - 1;
|
|
243
284
|
weighted.push(items[newIndex]);
|
|
244
285
|
}
|
|
245
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
|
|
246
296
|
else {
|
|
247
297
|
weighted.push(chance.pickone(items));
|
|
248
298
|
}
|
|
249
299
|
}
|
|
250
300
|
return weighted;
|
|
251
|
-
|
|
252
301
|
};
|
|
253
302
|
}
|
|
254
303
|
|
|
255
304
|
|
|
256
|
-
function inferFunnels(events) {
|
|
257
|
-
const createdFunnels = [];
|
|
258
|
-
const firstEvents = events.filter((e) => e.isFirstEvent).map((e) => e.event);
|
|
259
|
-
const usageEvents = events.filter((e) => !e.isFirstEvent).map((e) => e.event);
|
|
260
|
-
const numFunnelsToCreate = Math.ceil(usageEvents.length);
|
|
261
|
-
/** @type {Funnel} */
|
|
262
|
-
const funnelTemplate = {
|
|
263
|
-
sequence: [],
|
|
264
|
-
conversionRate: 50,
|
|
265
|
-
order: 'sequential',
|
|
266
|
-
requireRepeats: false,
|
|
267
|
-
props: {},
|
|
268
|
-
timeToConvert: 1,
|
|
269
|
-
isFirstFunnel: false,
|
|
270
|
-
weight: 1
|
|
271
|
-
};
|
|
272
|
-
if (firstEvents.length) {
|
|
273
|
-
for (const event of firstEvents) {
|
|
274
|
-
createdFunnels.push({ ...clone(funnelTemplate), sequence: [event], isFirstFunnel: true, conversionRate: 100 });
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
//at least one funnel with all usage events
|
|
279
|
-
createdFunnels.push({ ...clone(funnelTemplate), sequence: usageEvents });
|
|
280
|
-
|
|
281
|
-
//for the rest, make random funnels
|
|
282
|
-
followUpFunnels: for (let i = 1; i < numFunnelsToCreate; i++) {
|
|
283
|
-
/** @type {Funnel} */
|
|
284
|
-
const funnel = { ...clone(funnelTemplate) };
|
|
285
|
-
funnel.conversionRate = integer(25, 75);
|
|
286
|
-
funnel.timeToConvert = integer(1, 10);
|
|
287
|
-
funnel.weight = integer(1, 10);
|
|
288
|
-
const sequence = shuffleArray(usageEvents).slice(0, integer(2, usageEvents.length));
|
|
289
|
-
funnel.sequence = sequence;
|
|
290
|
-
funnel.order = 'random';
|
|
291
|
-
createdFunnels.push(funnel);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
return createdFunnels;
|
|
295
|
-
|
|
296
|
-
}
|
|
297
305
|
|
|
298
306
|
/*
|
|
299
307
|
----
|
|
@@ -360,6 +368,53 @@ function range(a, b, step = 1) {
|
|
|
360
368
|
};
|
|
361
369
|
|
|
362
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
|
+
|
|
363
418
|
/*
|
|
364
419
|
----
|
|
365
420
|
STREAMERS
|
|
@@ -425,8 +480,11 @@ function weighFunnels(acc, funnel) {
|
|
|
425
480
|
/**
|
|
426
481
|
* a utility function to generate a range of numbers within a given skew
|
|
427
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
|
+
*
|
|
428
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
|
+
*
|
|
429
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
|
+
*
|
|
430
488
|
* Size represents the size of the pool to choose from; Larger sizes result in smoother distributions but maintain the overall shape.
|
|
431
489
|
* @param {number} min
|
|
432
490
|
* @param {number} max
|
|
@@ -517,6 +575,7 @@ function shuffleOutside(array) {
|
|
|
517
575
|
}
|
|
518
576
|
|
|
519
577
|
/**
|
|
578
|
+
* given a funnel, shuffle the events in the sequence with random events
|
|
520
579
|
* @param {EventConfig[]} funnel
|
|
521
580
|
* @param {EventConfig[]} possibles
|
|
522
581
|
*/
|
|
@@ -662,13 +721,18 @@ function buildFileNames(config) {
|
|
|
662
721
|
// const current = dayjs.utc().format("MM-DD-HH");
|
|
663
722
|
const simName = config.simulationName;
|
|
664
723
|
let writeDir = "./";
|
|
665
|
-
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
|
+
}
|
|
666
729
|
if (typeof writeDir !== "string") throw new Error("writeDir must be a string");
|
|
667
730
|
if (typeof simName !== "string") throw new Error("simName must be a string");
|
|
668
731
|
|
|
669
732
|
const writePaths = {
|
|
670
733
|
eventFiles: [path.join(writeDir, `${simName}-EVENTS.${extension}`)],
|
|
671
734
|
userFiles: [path.join(writeDir, `${simName}-USERS.${extension}`)],
|
|
735
|
+
adSpendFiles: [path.join(writeDir, `${simName}-AD-SPEND.${extension}`)],
|
|
672
736
|
scdFiles: [],
|
|
673
737
|
mirrorFiles: [],
|
|
674
738
|
groupFiles: [],
|
|
@@ -713,11 +777,19 @@ function buildFileNames(config) {
|
|
|
713
777
|
return writePaths;
|
|
714
778
|
}
|
|
715
779
|
|
|
716
|
-
|
|
717
|
-
|
|
780
|
+
/**
|
|
781
|
+
* @param {[string, number][]} arrayOfArrays
|
|
782
|
+
*/
|
|
783
|
+
function progress(arrayOfArrays) {
|
|
718
784
|
// @ts-ignore
|
|
719
785
|
readline.cursorTo(process.stdout, 0);
|
|
720
|
-
|
|
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);
|
|
721
793
|
};
|
|
722
794
|
|
|
723
795
|
|
|
@@ -823,19 +895,16 @@ function TimeSoup(earliestTime, latestTime, peaks = 5, deviation = 2, mean = 0)
|
|
|
823
895
|
function person(userId, bornDaysAgo = 30, isAnonymous = false) {
|
|
824
896
|
const chance = getChance();
|
|
825
897
|
//names and photos
|
|
826
|
-
const l = chance.letter;
|
|
898
|
+
const l = chance.letter.bind(chance);
|
|
827
899
|
let gender = chance.pickone(['male', 'female']);
|
|
828
900
|
if (!gender) gender = "female";
|
|
829
901
|
// @ts-ignore
|
|
830
902
|
let first = chance.first({ gender });
|
|
831
903
|
let last = chance.last();
|
|
832
904
|
let name = `${first} ${last}`;
|
|
833
|
-
let email = `${first[0]}.${last}@${
|
|
905
|
+
let email = `${first[0]}.${last}@${choose(domainPrefix)}.${choose(domainSuffix)}`;
|
|
834
906
|
let avatarPrefix = `https://randomuser.me/api/portraits`;
|
|
835
|
-
let randomAvatarNumber =
|
|
836
|
-
min: 1,
|
|
837
|
-
max: 99
|
|
838
|
-
});
|
|
907
|
+
let randomAvatarNumber = integer(1, 99);
|
|
839
908
|
let avPath = gender === 'male' ? `/men/${randomAvatarNumber}.jpg` : `/women/${randomAvatarNumber}.jpg`;
|
|
840
909
|
let avatar = avatarPrefix + avPath;
|
|
841
910
|
let created = dayjs.unix(global.NOW).subtract(bornDaysAgo, 'day').format('YYYY-MM-DD');
|
|
@@ -855,8 +924,8 @@ function person(userId, bornDaysAgo = 30, isAnonymous = false) {
|
|
|
855
924
|
|
|
856
925
|
if (isAnonymous) {
|
|
857
926
|
user.name = "Anonymous User";
|
|
858
|
-
user.email =
|
|
859
|
-
delete user.avatar;
|
|
927
|
+
user.email = l() + l() + `*`.repeat(integer(3, 6)) + l() + `@` + l() + `*`.repeat(integer(3, 6)) + l() + `.` + choose(domainSuffix);
|
|
928
|
+
delete user.avatar;
|
|
860
929
|
|
|
861
930
|
}
|
|
862
931
|
|
|
@@ -980,5 +1049,6 @@ module.exports = {
|
|
|
980
1049
|
buildFileNames,
|
|
981
1050
|
streamJSON,
|
|
982
1051
|
streamCSV,
|
|
983
|
-
inferFunnels
|
|
1052
|
+
inferFunnels,
|
|
1053
|
+
datesBetween
|
|
984
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": {
|
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
|
|
package/scratch.mjs
CHANGED
|
@@ -1,23 +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
17
|
makeChart: false,
|
|
17
|
-
|
|
18
|
+
numUsers: 100,
|
|
19
|
+
numEvents: 10000,
|
|
20
|
+
numDays: 90,
|
|
21
|
+
token: ""
|
|
18
22
|
};
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
execSync.execSync('npm run prune');
|
|
22
|
-
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);
|
|
23
36
|
debugger;
|
package/scripts/jsdoctest.js
CHANGED