@ak--47/dungeon-master 1.2.0 → 1.2.2
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/dungeons/technical/ad-spend.js +15 -4
- package/dungeons/technical/anonymous-users.js +15 -5
- package/dungeons/technical/array-of-object-lookup.js +21 -5
- package/dungeons/technical/experiments.js +23 -5
- package/dungeons/technical/foobar.js +28 -12
- package/dungeons/technical/group-analytics.js +15 -5
- package/dungeons/technical/mirror-strategies.js +15 -5
- package/dungeons/technical/nested-objects.js +15 -4
- package/dungeons/technical/retention-cadence.js +13 -7
- package/dungeons/technical/sanity.js +25 -6
- package/dungeons/technical/scale-test.js +15 -4
- package/dungeons/technical/scd.js +24 -5
- package/dungeons/technical/simple.js +20 -5
- package/dungeons/technical/simplest.js +23 -6
- package/dungeons/technical/text-generation.js +22 -6
- package/dungeons/user/.gitkeep +0 -0
- package/dungeons/vertical/community-schema.json +1 -1
- package/dungeons/vertical/community.js +49 -28
- package/dungeons/vertical/devtools-schema.json +1 -1
- package/dungeons/vertical/devtools.js +50 -29
- package/dungeons/vertical/ecommerce.js +23 -6
- package/dungeons/vertical/education-schema.json +1 -1
- package/dungeons/vertical/education.js +29 -19
- package/dungeons/vertical/fintech-schema.json +1 -1
- package/dungeons/vertical/fintech.js +27 -8
- package/dungeons/vertical/fitness-schema.json +1 -1
- package/dungeons/vertical/fitness.js +48 -22
- package/dungeons/vertical/food-delivery-schema.json +1 -1
- package/dungeons/vertical/food-delivery.js +51 -12
- package/dungeons/vertical/gaming-schema.json +1 -1
- package/dungeons/vertical/gaming.js +41 -7
- package/dungeons/vertical/healthcare-schema.json +1 -1
- package/dungeons/vertical/healthcare.js +69 -40
- package/dungeons/vertical/insurance-application-schema.json +1 -1
- package/dungeons/vertical/insurance-application.js +26 -8
- package/dungeons/vertical/logistics-schema.json +1 -1
- package/dungeons/vertical/logistics.js +69 -41
- package/dungeons/vertical/marketplace-schema.json +1 -1
- package/dungeons/vertical/marketplace.js +44 -19
- package/dungeons/vertical/media.js +56 -15
- package/dungeons/vertical/rpg-schema.json +1 -1
- package/dungeons/vertical/rpg.js +38 -8
- package/dungeons/vertical/sass.js +24 -7
- package/dungeons/vertical/social.js +23 -7
- package/dungeons/vertical/travel-schema.json +1 -1
- package/dungeons/vertical/travel.js +50 -19
- package/index.js +3 -0
- package/lib/core/config-validator.js +13 -2
- package/lib/generators/events.js +3 -5
- package/lib/orchestrators/mixpanel-sender.js +64 -3
- package/lib/orchestrators/user-loop.js +20 -0
- package/lib/utils/utils.js +129 -9
- package/package.json +2 -2
- package/types.d.ts +5 -3
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "ad spend test";
|
|
3
|
+
const num_days = 90;
|
|
4
|
+
const num_users = 1_000;
|
|
5
|
+
const avg_events_per_user = 50;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -25,11 +35,12 @@ import { weighNumRange, date, integer, weighChoices } from "../../lib/utils/util
|
|
|
25
35
|
|
|
26
36
|
/** @type {import('../../types').Dungeon} */
|
|
27
37
|
const config = {
|
|
28
|
-
|
|
38
|
+
token,
|
|
39
|
+
seed: SEED,
|
|
29
40
|
name: "ad-spend",
|
|
30
|
-
numDays:
|
|
31
|
-
numEvents:
|
|
32
|
-
numUsers:
|
|
41
|
+
numDays: num_days,
|
|
42
|
+
numEvents: num_users * avg_events_per_user,
|
|
43
|
+
numUsers: num_users,
|
|
33
44
|
format: 'json',
|
|
34
45
|
region: "US",
|
|
35
46
|
hasAnonIds: true,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "anonymous-users";
|
|
3
|
+
const num_days = 180;
|
|
4
|
+
const num_users = 1_000;
|
|
5
|
+
const avg_events_per_user = 50;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Anonymous Users — tests anonymous user mode, anonIds, and identity merge.
|
|
3
13
|
*
|
|
@@ -17,11 +27,11 @@ import { weighNumRange, weighChoices } from "../../lib/utils/utils.js";
|
|
|
17
27
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
18
28
|
/** @type {import('../../types').Dungeon} */
|
|
19
29
|
const config = {
|
|
20
|
-
token
|
|
21
|
-
seed:
|
|
22
|
-
numDays:
|
|
23
|
-
numEvents:
|
|
24
|
-
numUsers:
|
|
30
|
+
token,
|
|
31
|
+
seed: SEED,
|
|
32
|
+
numDays: num_days,
|
|
33
|
+
numEvents: num_users * avg_events_per_user,
|
|
34
|
+
numUsers: num_users,
|
|
25
35
|
format: "json",
|
|
26
36
|
region: "US",
|
|
27
37
|
isAnonymous: true,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "dm4-array-of-object-lookup";
|
|
3
|
+
const num_days = 60;
|
|
4
|
+
const num_users = 1_000;
|
|
5
|
+
const avg_events_per_user = 100;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -40,12 +50,12 @@ const spiritAnimals = ["duck", "dog", "otter", "penguin", "cat", "elephant", "li
|
|
|
40
50
|
|
|
41
51
|
/** @type {import('../types.js').Dungeon} */
|
|
42
52
|
const config = {
|
|
43
|
-
|
|
44
|
-
seed:
|
|
53
|
+
token,
|
|
54
|
+
seed: SEED,
|
|
45
55
|
name: "array-of-object-lookup",
|
|
46
|
-
numDays:
|
|
47
|
-
numEvents:
|
|
48
|
-
numUsers:
|
|
56
|
+
numDays: num_days,
|
|
57
|
+
numEvents: num_users * avg_events_per_user,
|
|
58
|
+
numUsers: num_users,
|
|
49
59
|
format: 'json', //csv or json
|
|
50
60
|
region: "US",
|
|
51
61
|
hasAnonIds: true, //if true, anonymousIds are created for each user
|
|
@@ -109,6 +119,7 @@ const config = {
|
|
|
109
119
|
each key should be an array or function reference
|
|
110
120
|
*/
|
|
111
121
|
userProps: {
|
|
122
|
+
theme: ["light", "dark", "custom", "light", "dark"],
|
|
112
123
|
// title: chance.profession.bind(chance),
|
|
113
124
|
// luckyNumber: weighNumRange(1, 500, .3),
|
|
114
125
|
spiritAnimal: spiritAnimals
|
|
@@ -160,6 +171,11 @@ const config = {
|
|
|
160
171
|
}
|
|
161
172
|
|
|
162
173
|
if (type === "everything") {
|
|
174
|
+
const profile = meta.profile;
|
|
175
|
+
record.forEach(e => {
|
|
176
|
+
e.theme = profile.theme;
|
|
177
|
+
});
|
|
178
|
+
|
|
163
179
|
// Pattern 3: Users who view 5+ items but never checkout are tagged as window shoppers
|
|
164
180
|
const views = record.filter(e => e.event === "view item").length;
|
|
165
181
|
const checkouts = record.filter(e => e.event === "checkout").length;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "experiments";
|
|
3
|
+
const num_days = 60;
|
|
4
|
+
const num_users = 2_000;
|
|
5
|
+
const avg_events_per_user = 50;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Experiments — tests funnel experiments with A/B/C variants.
|
|
3
13
|
*
|
|
@@ -17,11 +27,11 @@ import { weighNumRange, weighChoices } from "../../lib/utils/utils.js";
|
|
|
17
27
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
18
28
|
/** @type {import('../../types').Dungeon} */
|
|
19
29
|
const config = {
|
|
20
|
-
token
|
|
21
|
-
seed:
|
|
22
|
-
numDays:
|
|
23
|
-
numEvents:
|
|
24
|
-
numUsers:
|
|
30
|
+
token,
|
|
31
|
+
seed: SEED,
|
|
32
|
+
numDays: num_days,
|
|
33
|
+
numEvents: num_users * avg_events_per_user,
|
|
34
|
+
numUsers: num_users,
|
|
25
35
|
format: "json",
|
|
26
36
|
region: "US",
|
|
27
37
|
hasAnonIds: false,
|
|
@@ -152,6 +162,7 @@ const config = {
|
|
|
152
162
|
|
|
153
163
|
userProps: {
|
|
154
164
|
plan: weighChoices(["free", "free", "free", "starter", "growth", "enterprise"]),
|
|
165
|
+
platform: ["web", "web", "ios", "android"],
|
|
155
166
|
},
|
|
156
167
|
|
|
157
168
|
scdProps: {},
|
|
@@ -161,6 +172,13 @@ const config = {
|
|
|
161
172
|
lookupTables: [],
|
|
162
173
|
|
|
163
174
|
hook: function (record, type, meta) {
|
|
175
|
+
if (type === "everything") {
|
|
176
|
+
const profile = meta.profile;
|
|
177
|
+
record.forEach(e => {
|
|
178
|
+
e.platform = profile.platform;
|
|
179
|
+
});
|
|
180
|
+
return record;
|
|
181
|
+
}
|
|
164
182
|
return record;
|
|
165
183
|
}
|
|
166
184
|
};
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "dm4-foobar";
|
|
3
|
+
const num_days = 30;
|
|
4
|
+
const num_users = 4_000_000;
|
|
5
|
+
const avg_events_per_user = 500;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* ═══════════════════════════════════════════════════════════════
|
|
3
13
|
* DATASET OVERVIEW
|
|
@@ -151,20 +161,13 @@ const dates = [
|
|
|
151
161
|
"2024-06-03T06:52:21.652Z"
|
|
152
162
|
];
|
|
153
163
|
|
|
154
|
-
const billionsOfEvents = 2
|
|
155
|
-
|
|
156
|
-
const numEvents = billionsOfEvents * 1_000_000_000;
|
|
157
|
-
const eventPerUser = 1_000;
|
|
158
|
-
const numUsers = Math.floor(numEvents / eventPerUser);
|
|
159
|
-
const seed = Math.random().toString()
|
|
160
|
-
|
|
161
164
|
/** @type {import('../../types').Dungeon} */
|
|
162
165
|
const config = {
|
|
163
|
-
token
|
|
164
|
-
seed:
|
|
165
|
-
numDays:
|
|
166
|
-
numEvents:
|
|
167
|
-
numUsers:
|
|
166
|
+
token,
|
|
167
|
+
seed: SEED,
|
|
168
|
+
numDays: num_days,
|
|
169
|
+
numEvents: num_users * avg_events_per_user,
|
|
170
|
+
numUsers: num_users,
|
|
168
171
|
format: 'json', //csv or json
|
|
169
172
|
region: "US",
|
|
170
173
|
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
@@ -244,6 +247,11 @@ const config = {
|
|
|
244
247
|
luckyNumber: integer,
|
|
245
248
|
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"],
|
|
246
249
|
created: dates,
|
|
250
|
+
string: ["red", "orange", "yellow", "green", "blue", "indigo", "violet"],
|
|
251
|
+
number: integer,
|
|
252
|
+
boolean: [true, false],
|
|
253
|
+
date: dates,
|
|
254
|
+
temperature: ["warm"],
|
|
247
255
|
},
|
|
248
256
|
|
|
249
257
|
scdProps: {},
|
|
@@ -270,6 +278,14 @@ const config = {
|
|
|
270
278
|
|
|
271
279
|
// everything hook: hash-based cohort — 10% of users (by distinct_id) get doubled events
|
|
272
280
|
if (type === "everything") {
|
|
281
|
+
const profile = meta.profile;
|
|
282
|
+
record.forEach(e => {
|
|
283
|
+
e.string = profile.string;
|
|
284
|
+
e.number = profile.number;
|
|
285
|
+
e.boolean = profile.boolean;
|
|
286
|
+
e.date = profile.date;
|
|
287
|
+
e.temperature = profile.temperature;
|
|
288
|
+
});
|
|
273
289
|
if (record.length > 0) {
|
|
274
290
|
const userId = record[0].user_id || record[0].distinct_id || "";
|
|
275
291
|
if (userId && userId.charCodeAt(0) % 10 === 0) {
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "group-analytics";
|
|
3
|
+
const num_days = 60;
|
|
4
|
+
const num_users = 500;
|
|
5
|
+
const avg_events_per_user = 60;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Group Analytics — tests multiple group keys with varied entity counts.
|
|
3
13
|
*
|
|
@@ -17,11 +27,11 @@ import { weighNumRange, weighChoices } from "../../lib/utils/utils.js";
|
|
|
17
27
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
18
28
|
/** @type {import('../../types').Dungeon} */
|
|
19
29
|
const config = {
|
|
20
|
-
token
|
|
21
|
-
seed:
|
|
22
|
-
numDays:
|
|
23
|
-
numEvents:
|
|
24
|
-
numUsers:
|
|
30
|
+
token,
|
|
31
|
+
seed: SEED,
|
|
32
|
+
numDays: num_days,
|
|
33
|
+
numEvents: num_users * avg_events_per_user,
|
|
34
|
+
numUsers: num_users,
|
|
25
35
|
format: "json",
|
|
26
36
|
region: "US",
|
|
27
37
|
hasAnonIds: false,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "mirror-strategies";
|
|
3
|
+
const num_days = 30;
|
|
4
|
+
const num_users = 500;
|
|
5
|
+
const avg_events_per_user = 60;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
/**
|
|
2
12
|
* Mirror Strategies — tests all 4 mirror data strategies.
|
|
3
13
|
*
|
|
@@ -16,11 +26,11 @@ import { weighNumRange, weighChoices } from "../../lib/utils/utils.js";
|
|
|
16
26
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
17
27
|
/** @type {import('../../types').Dungeon} */
|
|
18
28
|
const config = {
|
|
19
|
-
token
|
|
20
|
-
seed:
|
|
21
|
-
numDays:
|
|
22
|
-
numEvents:
|
|
23
|
-
numUsers:
|
|
29
|
+
token,
|
|
30
|
+
seed: SEED,
|
|
31
|
+
numDays: num_days,
|
|
32
|
+
numEvents: num_users * avg_events_per_user,
|
|
33
|
+
numUsers: num_users,
|
|
24
34
|
format: "json",
|
|
25
35
|
region: "US",
|
|
26
36
|
hasAnonIds: false,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "dm4-nested-objects";
|
|
3
|
+
const num_days = 30;
|
|
4
|
+
const num_users = 500;
|
|
5
|
+
const avg_events_per_user = 60;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -30,11 +40,12 @@ const countries = ["US", "UK", "JP", "DE", "AU", "CA", "FR", "IN", "KR", "MX", "
|
|
|
30
40
|
|
|
31
41
|
/** @type {import('../../types').Dungeon} */
|
|
32
42
|
const config = {
|
|
33
|
-
|
|
43
|
+
token,
|
|
44
|
+
seed: SEED,
|
|
34
45
|
name: "nested-objects",
|
|
35
|
-
numDays:
|
|
36
|
-
numEvents:
|
|
37
|
-
numUsers:
|
|
46
|
+
numDays: num_days,
|
|
47
|
+
numEvents: num_users * avg_events_per_user,
|
|
48
|
+
numUsers: num_users,
|
|
38
49
|
format: 'json',
|
|
39
50
|
region: "US",
|
|
40
51
|
hasAnonIds: false,
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
1
2
|
const SEED = "kurby-retention";
|
|
3
|
+
const num_days = 360;
|
|
4
|
+
const num_users = 100;
|
|
5
|
+
const avg_events_per_user = 50;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
2
11
|
import dayjs from 'dayjs';
|
|
3
12
|
import utc from 'dayjs/plugin/utc.js';
|
|
4
13
|
dayjs.extend(utc);
|
|
@@ -6,9 +15,6 @@ import * as u from "../../lib/utils/utils.js";
|
|
|
6
15
|
import * as v from 'ak-tools';
|
|
7
16
|
const chance = u.initChance(SEED);
|
|
8
17
|
|
|
9
|
-
const num_users = 100;
|
|
10
|
-
const days = 360;
|
|
11
|
-
|
|
12
18
|
/** @typedef {import("../../types").Dungeon} Config */
|
|
13
19
|
|
|
14
20
|
/**
|
|
@@ -101,10 +107,10 @@ function generateCadencedEvents(behaviorName, cadence, startTime, endTime, churn
|
|
|
101
107
|
|
|
102
108
|
/** @type {Config} */
|
|
103
109
|
const config = {
|
|
104
|
-
token
|
|
105
|
-
seed:
|
|
106
|
-
numDays:
|
|
107
|
-
numEvents: num_users *
|
|
110
|
+
token,
|
|
111
|
+
seed: SEED,
|
|
112
|
+
numDays: num_days,
|
|
113
|
+
numEvents: num_users * avg_events_per_user,
|
|
108
114
|
numUsers: num_users,
|
|
109
115
|
hasAnonIds: false,
|
|
110
116
|
hasSessionIds: false,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "foo bar";
|
|
3
|
+
const num_days = 90;
|
|
4
|
+
const num_users = 500;
|
|
5
|
+
const avg_events_per_user = 100;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
const chance = new Chance();
|
|
3
13
|
import dayjs from 'dayjs';
|
|
@@ -30,11 +40,11 @@ import { weighNumRange, integer } from "../../lib/utils/utils.js";
|
|
|
30
40
|
|
|
31
41
|
/** @type {import('../types.js').Dungeon} */
|
|
32
42
|
const config = {
|
|
33
|
-
token
|
|
34
|
-
seed:
|
|
35
|
-
numDays:
|
|
36
|
-
numEvents:
|
|
37
|
-
numUsers:
|
|
43
|
+
token,
|
|
44
|
+
seed: SEED,
|
|
45
|
+
numDays: num_days,
|
|
46
|
+
numEvents: num_users * avg_events_per_user,
|
|
47
|
+
numUsers: num_users,
|
|
38
48
|
format: 'json', //csv or json
|
|
39
49
|
region: "US",
|
|
40
50
|
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
@@ -113,7 +123,10 @@ const config = {
|
|
|
113
123
|
title: chance.profession.bind(chance),
|
|
114
124
|
luckyNumber: weighNumRange(42, 420),
|
|
115
125
|
userTier: ["regular"],
|
|
116
|
-
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"]
|
|
126
|
+
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"],
|
|
127
|
+
color: ["red", "orange", "yellow", "green", "blue", "indigo", "violet"],
|
|
128
|
+
number: integer,
|
|
129
|
+
engagement_score: [0],
|
|
117
130
|
},
|
|
118
131
|
hook: function (record, type, meta) {
|
|
119
132
|
// --- user hook: tag power users based on luckyNumber ---
|
|
@@ -138,6 +151,12 @@ const config = {
|
|
|
138
151
|
|
|
139
152
|
// --- everything hook: low-activity users lose their last few events (churn simulation) ---
|
|
140
153
|
if (type === "everything") {
|
|
154
|
+
const profile = meta.profile;
|
|
155
|
+
record.forEach(e => {
|
|
156
|
+
e.color = profile.color;
|
|
157
|
+
e.number = profile.number;
|
|
158
|
+
// engagement_score intentionally varies per event (set by event hook)
|
|
159
|
+
});
|
|
141
160
|
if (record.length > 3 && record.length < 8) {
|
|
142
161
|
// users with few events lose the tail end — simulates churn
|
|
143
162
|
return record.slice(0, Math.ceil(record.length * 0.6));
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "scale test";
|
|
3
|
+
const num_days = 365;
|
|
4
|
+
const num_users = 10_000;
|
|
5
|
+
const avg_events_per_user = 50;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -24,11 +34,12 @@ import { weighNumRange, date, integer, weighChoices } from "../../lib/utils/util
|
|
|
24
34
|
|
|
25
35
|
/** @type {import('../../types').Dungeon} */
|
|
26
36
|
const config = {
|
|
27
|
-
|
|
37
|
+
token,
|
|
38
|
+
seed: SEED,
|
|
28
39
|
name: "scale-test",
|
|
29
|
-
numDays:
|
|
30
|
-
numEvents:
|
|
31
|
-
numUsers:
|
|
40
|
+
numDays: num_days,
|
|
41
|
+
numEvents: num_users * avg_events_per_user,
|
|
42
|
+
numUsers: num_users,
|
|
32
43
|
format: 'json',
|
|
33
44
|
gzip: true,
|
|
34
45
|
concurrency: 1,
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "simple is best";
|
|
3
|
+
const num_days = 30;
|
|
4
|
+
const num_users = 500;
|
|
5
|
+
const avg_events_per_user = 100;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
const chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -51,11 +61,11 @@ const videoCategories = ["funny", "educational", "inspirational", "music", "news
|
|
|
51
61
|
|
|
52
62
|
/** @type {import('../../types').Dungeon} */
|
|
53
63
|
const config = {
|
|
54
|
-
token
|
|
55
|
-
seed:
|
|
56
|
-
numDays:
|
|
57
|
-
numEvents:
|
|
58
|
-
numUsers:
|
|
64
|
+
token,
|
|
65
|
+
seed: SEED,
|
|
66
|
+
numDays: num_days,
|
|
67
|
+
numEvents: num_users * avg_events_per_user,
|
|
68
|
+
numUsers: num_users,
|
|
59
69
|
format: 'csv', //csv or json
|
|
60
70
|
region: "US",
|
|
61
71
|
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
@@ -167,6 +177,8 @@ const config = {
|
|
|
167
177
|
luckyNumber: weighNumRange(42, 420, .3),
|
|
168
178
|
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"],
|
|
169
179
|
spendTier: ["budget"],
|
|
180
|
+
platform: ["web", "mobile", "web", "mobile", "web", "web", "kiosk", "smartTV"],
|
|
181
|
+
currentTheme: weighChoices(["light", "dark", "custom", "light", "dark"]),
|
|
170
182
|
},
|
|
171
183
|
scdProps: {
|
|
172
184
|
role: {
|
|
@@ -259,6 +271,13 @@ const config = {
|
|
|
259
271
|
|
|
260
272
|
// --- everything hook: simulate cart abandonment ---
|
|
261
273
|
if (type === "everything") {
|
|
274
|
+
// stamp superProps from profile for consistency
|
|
275
|
+
const profile = meta.profile;
|
|
276
|
+
record.forEach(e => {
|
|
277
|
+
e.platform = profile.platform;
|
|
278
|
+
e.currentTheme = profile.currentTheme;
|
|
279
|
+
});
|
|
280
|
+
|
|
262
281
|
const hasAddToCart = record.some(e => e.event === "add to cart");
|
|
263
282
|
const hasCheckout = record.some(e => e.event === "checkout");
|
|
264
283
|
// users who added to cart but never checked out: remove checkout events (if any slipped through)
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "simple is best";
|
|
3
|
+
const num_days = 100;
|
|
4
|
+
const num_users = 5_000;
|
|
5
|
+
const avg_events_per_user = 100;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -60,11 +70,11 @@ const videoCategories = ["funny", "educational", "inspirational", "music", "news
|
|
|
60
70
|
|
|
61
71
|
/** @type {import('../../types').Dungeon} */
|
|
62
72
|
const config = {
|
|
63
|
-
token
|
|
64
|
-
seed:
|
|
65
|
-
numDays:
|
|
66
|
-
numEvents:
|
|
67
|
-
numUsers:
|
|
73
|
+
token,
|
|
74
|
+
seed: SEED,
|
|
75
|
+
numDays: num_days,
|
|
76
|
+
numEvents: num_users * avg_events_per_user,
|
|
77
|
+
numUsers: num_users,
|
|
68
78
|
format: 'json', //csv or json
|
|
69
79
|
region: "US",
|
|
70
80
|
hasAnonIds: true, //if true, anonymousIds are created for each user
|
|
@@ -191,6 +201,7 @@ const config = {
|
|
|
191
201
|
each key should be an array or function reference
|
|
192
202
|
*/
|
|
193
203
|
userProps: {
|
|
204
|
+
theme: ["light", "dark", "custom", "light", "dark"],
|
|
194
205
|
title: chance.profession.bind(chance),
|
|
195
206
|
luckyNumber: weighNumRange(42, 420, .3),
|
|
196
207
|
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"]
|
|
@@ -234,6 +245,10 @@ const config = {
|
|
|
234
245
|
}
|
|
235
246
|
|
|
236
247
|
if (type === "everything") {
|
|
248
|
+
const profile = meta.profile;
|
|
249
|
+
record.forEach(e => {
|
|
250
|
+
e.theme = profile.theme;
|
|
251
|
+
});
|
|
237
252
|
|
|
238
253
|
//custom themes purchase more:
|
|
239
254
|
const numCustomMode = record.filter(a => a.theme === 'custom').length;
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// ── TWEAK THESE ──
|
|
2
|
+
const SEED = "simple is best";
|
|
3
|
+
const num_days = 100;
|
|
4
|
+
const num_users = 2_500;
|
|
5
|
+
const avg_events_per_user = 100;
|
|
6
|
+
let token = "your-mixpanel-token";
|
|
7
|
+
|
|
8
|
+
// ── env overrides ──
|
|
9
|
+
if (process.env.MP_TOKEN) token = process.env.MP_TOKEN;
|
|
10
|
+
|
|
1
11
|
import Chance from 'chance';
|
|
2
12
|
let chance = new Chance();
|
|
3
13
|
import dayjs from "dayjs";
|
|
@@ -34,11 +44,11 @@ const videoCategories = ["funny", "educational", "inspirational", "music", "news
|
|
|
34
44
|
|
|
35
45
|
/** @type {import('../types.js').Dungeon} */
|
|
36
46
|
const config = {
|
|
37
|
-
token
|
|
38
|
-
seed:
|
|
39
|
-
numDays:
|
|
40
|
-
numEvents:
|
|
41
|
-
numUsers:
|
|
47
|
+
token,
|
|
48
|
+
seed: SEED,
|
|
49
|
+
numDays: num_days,
|
|
50
|
+
numEvents: num_users * avg_events_per_user,
|
|
51
|
+
numUsers: num_users,
|
|
42
52
|
format: 'json', //csv or json
|
|
43
53
|
region: "US",
|
|
44
54
|
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
@@ -365,6 +375,7 @@ const config = {
|
|
|
365
375
|
each key should be an array or function reference
|
|
366
376
|
*/
|
|
367
377
|
userProps: {
|
|
378
|
+
theme: ["light", "dark", "custom", "light", "dark"],
|
|
368
379
|
title: chance.profession.bind(chance),
|
|
369
380
|
luckyNumber: weighNumRange(42, 420, .3),
|
|
370
381
|
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"]
|
|
@@ -381,7 +392,13 @@ const config = {
|
|
|
381
392
|
lookupTables: [],
|
|
382
393
|
hook: function (record, type, meta) {
|
|
383
394
|
|
|
384
|
-
|
|
395
|
+
if (type === "everything") {
|
|
396
|
+
const profile = meta.profile;
|
|
397
|
+
record.forEach(e => {
|
|
398
|
+
e.theme = profile.theme;
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
|
|
385
402
|
return record;
|
|
386
403
|
}
|
|
387
404
|
};
|