@ak--47/dungeon-master 1.2.0 → 1.2.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.
Files changed (54) hide show
  1. package/dungeons/technical/ad-spend.js +15 -4
  2. package/dungeons/technical/anonymous-users.js +15 -5
  3. package/dungeons/technical/array-of-object-lookup.js +21 -5
  4. package/dungeons/technical/experiments.js +23 -5
  5. package/dungeons/technical/foobar.js +28 -12
  6. package/dungeons/technical/group-analytics.js +15 -5
  7. package/dungeons/technical/mirror-strategies.js +15 -5
  8. package/dungeons/technical/nested-objects.js +15 -4
  9. package/dungeons/technical/retention-cadence.js +13 -7
  10. package/dungeons/technical/sanity.js +25 -6
  11. package/dungeons/technical/scale-test.js +15 -4
  12. package/dungeons/technical/scd.js +24 -5
  13. package/dungeons/technical/simple.js +20 -5
  14. package/dungeons/technical/simplest.js +23 -6
  15. package/dungeons/technical/text-generation.js +22 -6
  16. package/dungeons/user/.gitkeep +0 -0
  17. package/dungeons/user/shalini.js +847 -0
  18. package/dungeons/vertical/community-schema.json +1 -1
  19. package/dungeons/vertical/community.js +49 -28
  20. package/dungeons/vertical/devtools-schema.json +1 -1
  21. package/dungeons/vertical/devtools.js +50 -29
  22. package/dungeons/vertical/ecommerce.js +23 -6
  23. package/dungeons/vertical/education-schema.json +1 -1
  24. package/dungeons/vertical/education.js +29 -19
  25. package/dungeons/vertical/fintech-schema.json +1 -1
  26. package/dungeons/vertical/fintech.js +27 -8
  27. package/dungeons/vertical/fitness-schema.json +1 -1
  28. package/dungeons/vertical/fitness.js +48 -22
  29. package/dungeons/vertical/food-delivery-schema.json +1 -1
  30. package/dungeons/vertical/food-delivery.js +51 -12
  31. package/dungeons/vertical/gaming-schema.json +1 -1
  32. package/dungeons/vertical/gaming.js +41 -7
  33. package/dungeons/vertical/healthcare-schema.json +1 -1
  34. package/dungeons/vertical/healthcare.js +69 -40
  35. package/dungeons/vertical/insurance-application-schema.json +1 -1
  36. package/dungeons/vertical/insurance-application.js +26 -8
  37. package/dungeons/vertical/logistics-schema.json +1 -1
  38. package/dungeons/vertical/logistics.js +69 -41
  39. package/dungeons/vertical/marketplace-schema.json +1 -1
  40. package/dungeons/vertical/marketplace.js +44 -19
  41. package/dungeons/vertical/media.js +56 -15
  42. package/dungeons/vertical/rpg-schema.json +1 -1
  43. package/dungeons/vertical/rpg.js +38 -8
  44. package/dungeons/vertical/sass.js +24 -7
  45. package/dungeons/vertical/social.js +23 -7
  46. package/dungeons/vertical/travel-schema.json +1 -1
  47. package/dungeons/vertical/travel.js +50 -19
  48. package/index.js +3 -0
  49. package/lib/core/config-validator.js +13 -2
  50. package/lib/generators/events.js +3 -5
  51. package/lib/orchestrators/user-loop.js +20 -0
  52. package/lib/utils/utils.js +129 -9
  53. package/package.json +1 -1
  54. 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
- seed: "ad spend test",
38
+ token,
39
+ seed: SEED,
29
40
  name: "ad-spend",
30
- numDays: 90,
31
- numEvents: 50_000,
32
- numUsers: 1_000,
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: "anonymous-users",
22
- numDays: 180,
23
- numEvents: 50_000,
24
- numUsers: 1_000,
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
- // token: "",
44
- seed: "test array of objects lookup",
53
+ token,
54
+ seed: SEED,
45
55
  name: "array-of-object-lookup",
46
- numDays: 60, //how many days worth1 of data
47
- numEvents: 100_000, //how many events
48
- numUsers: 1_000, //how many users
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: "experiments",
22
- numDays: 60,
23
- numEvents: 100_000,
24
- numUsers: 2_000,
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: seed,
165
- numDays: 30, //how many days worth of data
166
- numEvents: numEvents, //how many events
167
- numUsers: numUsers, //how many users
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: "group-analytics",
22
- numDays: 60,
23
- numEvents: 30_000,
24
- numUsers: 500,
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: "mirror-strategies",
21
- numDays: 30,
22
- numEvents: 30_000,
23
- numUsers: 500,
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
- seed: "nested objects test",
43
+ token,
44
+ seed: SEED,
34
45
  name: "nested-objects",
35
- numDays: 30,
36
- numEvents: 30_000,
37
- numUsers: 500,
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: "lets go",
106
- numDays: days,
107
- numEvents: num_users * 50,
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: "foo bar",
35
- numDays: 90, //how many days worth of data
36
- numEvents: 50_000, //how many events
37
- numUsers: 500, //how many users
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
- seed: "scale test",
37
+ token,
38
+ seed: SEED,
28
39
  name: "scale-test",
29
- numDays: 365,
30
- numEvents: 500_000,
31
- numUsers: 10_000,
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: "simple is best",
56
- numDays: 30, //how many days worth1 of data
57
- numEvents: 50000, //how many events
58
- numUsers: 500, //how many users
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: "simple is best",
65
- numDays: 100, //how many days worth1 of data
66
- numEvents: 500_000, //how many events
67
- numUsers: 5_000, //how many users
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: "simple is best",
39
- numDays: 100, //how many days worth1 of data
40
- numEvents: 250_000, //how many events
41
- numUsers: 2_500, //how many users
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
- // no hooks!
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
  };