make-mp-data 2.1.11 → 3.0.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.
Files changed (71) hide show
  1. package/README.md +31 -0
  2. package/dungeons/adspend.js +35 -1
  3. package/dungeons/anon.js +25 -1
  4. package/dungeons/array-of-object-lookup.js +201 -0
  5. package/dungeons/benchmark-heavy.js +241 -0
  6. package/dungeons/benchmark-light.js +141 -0
  7. package/dungeons/big.js +10 -9
  8. package/dungeons/business.js +60 -12
  9. package/dungeons/complex.js +35 -1
  10. package/dungeons/copilot.js +383 -0
  11. package/dungeons/education.js +1005 -0
  12. package/dungeons/experiments.js +18 -4
  13. package/dungeons/fintech.js +976 -0
  14. package/dungeons/foobar.js +32 -0
  15. package/dungeons/food.js +988 -0
  16. package/dungeons/funnels.js +38 -1
  17. package/dungeons/gaming.js +26 -5
  18. package/dungeons/media.js +861 -270
  19. package/dungeons/mil.js +31 -3
  20. package/dungeons/mirror.js +33 -1
  21. package/dungeons/retention-cadence.js +211 -0
  22. package/dungeons/rpg.js +1178 -0
  23. package/dungeons/sanity.js +32 -2
  24. package/dungeons/sass.js +923 -0
  25. package/dungeons/scd.js +47 -1
  26. package/dungeons/simple.js +29 -14
  27. package/dungeons/social.js +928 -0
  28. package/dungeons/streaming.js +373 -0
  29. package/dungeons/strict-event-test.js +30 -0
  30. package/dungeons/student-teacher.js +19 -5
  31. package/dungeons/text-generation.js +120 -84
  32. package/dungeons/too-big-events.js +203 -0
  33. package/dungeons/{userAgent.js → user-agent.js} +23 -2
  34. package/entry.js +5 -4
  35. package/index.js +41 -54
  36. package/lib/core/config-validator.js +122 -7
  37. package/lib/core/context.js +7 -14
  38. package/lib/core/storage.js +57 -25
  39. package/lib/generators/adspend.js +12 -12
  40. package/lib/generators/events.js +6 -5
  41. package/lib/generators/funnels.js +32 -10
  42. package/lib/generators/product-lookup.js +262 -0
  43. package/lib/generators/product-names.js +195 -0
  44. package/lib/generators/profiles.js +3 -3
  45. package/lib/generators/scd.js +13 -3
  46. package/lib/generators/text.js +17 -4
  47. package/lib/orchestrators/mixpanel-sender.js +244 -204
  48. package/lib/orchestrators/user-loop.js +54 -16
  49. package/lib/templates/phrases.js +473 -16
  50. package/lib/templates/schema.d.ts +173 -0
  51. package/lib/templates/verbose-schema.js +140 -206
  52. package/lib/utils/chart.js +210 -0
  53. package/lib/utils/function-registry.js +285 -0
  54. package/lib/utils/json-evaluator.js +172 -0
  55. package/lib/utils/logger.js +34 -0
  56. package/lib/utils/utils.js +41 -4
  57. package/package.json +12 -21
  58. package/types.d.ts +15 -5
  59. package/dungeons/ai-chat-analytics-ed.js +0 -274
  60. package/dungeons/money2020-ed-also.js +0 -277
  61. package/dungeons/money2020-ed.js +0 -579
  62. package/lib/generators/text-bak-old.js +0 -1121
  63. package/lib/orchestrators/worker-manager.js +0 -203
  64. package/lib/templates/hooks-instructions.txt +0 -434
  65. package/lib/templates/phrases-bak.js +0 -925
  66. package/lib/templates/prompt (old).txt +0 -98
  67. package/lib/templates/schema-instructions.txt +0 -155
  68. package/lib/templates/scratch-dungeon-template.js +0 -116
  69. package/lib/templates/textQuickTest.js +0 -172
  70. package/lib/utils/ai.js +0 -120
  71. package/lib/utils/project.js +0 -166
package/dungeons/mil.js CHANGED
@@ -4,7 +4,7 @@ import dayjs from 'dayjs';
4
4
  import utc from 'dayjs/plugin/utc.js';
5
5
  dayjs.extend(utc);
6
6
  import 'dotenv/config';
7
- import * as u from '../lib/utils/utils.js';
7
+ import * as u from "../lib/utils/utils.js";
8
8
  import * as v from 'ak-tools';
9
9
  const chance = u.initChance(SEED);
10
10
  const num_users = 10_000;
@@ -44,10 +44,11 @@ const config = {
44
44
  hasAdSpend: false,
45
45
 
46
46
  hasAvatar: false,
47
+ makeChart: false,
47
48
 
48
- batchSize: 1_500_000,
49
+ batchSize: 2_500_000,
49
50
  concurrency: 10,
50
- writeToDisk: true,
51
+ writeToDisk: false,
51
52
 
52
53
  funnels: [],
53
54
 
@@ -289,6 +290,33 @@ const config = {
289
290
  groupProps: {},
290
291
  lookupTables: [],
291
292
  hook: function (record, type, meta) {
293
+ // event hook: tag events by frequency tier and enrich booleans
294
+ if (type === "event") {
295
+ const highFreq = ["foo", "bar", "baz"];
296
+ const lowFreq = ["crumn", "yak"];
297
+ if (highFreq.includes(record.event)) {
298
+ record.frequency_tier = "high";
299
+ } else if (lowFreq.includes(record.event)) {
300
+ record.frequency_tier = "low";
301
+ } else {
302
+ record.frequency_tier = "medium";
303
+ }
304
+ // boolean super prop drives a derived field
305
+ if (record.boolean === true) {
306
+ record.flag_status = "active";
307
+ }
308
+ }
309
+
310
+ // everything hook: users with very few events are marked as churned
311
+ if (type === "everything") {
312
+ if (record.length <= 3) {
313
+ for (const e of record) {
314
+ e.is_churned_user = true;
315
+ }
316
+ }
317
+ return record;
318
+ }
319
+
292
320
  return record;
293
321
  }
294
322
  };
@@ -14,7 +14,7 @@ import dayjs from "dayjs";
14
14
  import utc from "dayjs/plugin/utc.js";
15
15
  dayjs.extend(utc);
16
16
  import { uid, comma } from 'ak-tools';
17
- import { pickAWinner, weighNumRange, date, integer } from '../lib/utils/utils.js';
17
+ import { pickAWinner, weighNumRange, date, integer } from "../lib/utils/utils.js";
18
18
 
19
19
 
20
20
  /** @type {import('../types').Dungeon} */
@@ -120,6 +120,38 @@ const config = {
120
120
  groupProps: {},
121
121
  lookupTables: [],
122
122
  hook: function (record, type, meta) {
123
+ // --- user hook: segment users by spirit animal ---
124
+ if (type === "user") {
125
+ const aquatic = ["whale", "dolphin", "shark", "octopus", "squid", "jellyfish", "seahorse", "crab", "lobster", "shrimp"];
126
+ record.segment = aquatic.includes(record.spiritAnimal) ? "aquatic" : "terrestrial";
127
+ return record;
128
+ }
129
+
130
+ // --- event hook: color-based property boost ---
131
+ if (type === "event") {
132
+ // warm-colored events get a higher updateMe value
133
+ const warmColors = ["red", "orange", "yellow"];
134
+ if (warmColors.includes(record.color)) {
135
+ record.updateMe = (record.updateMe || 5) + 10;
136
+ }
137
+ return record;
138
+ }
139
+
140
+ // --- everything hook: inject a "milestone" event for users with 8+ events ---
141
+ if (type === "everything") {
142
+ if (record.length >= 8) {
143
+ const lastEvent = record[record.length - 1];
144
+ record.push({
145
+ event: "milestone_reached",
146
+ time: lastEvent.time,
147
+ user_id: lastEvent.user_id,
148
+ color: lastEvent.color,
149
+ milestone: record.length
150
+ });
151
+ }
152
+ return record;
153
+ }
154
+
123
155
  return record;
124
156
  }
125
157
  };
@@ -0,0 +1,211 @@
1
+
2
+ const SEED = "kurby-retention";
3
+ import dayjs from 'dayjs';
4
+ import utc from 'dayjs/plugin/utc.js';
5
+ dayjs.extend(utc);
6
+ import * as u from "../lib/utils/utils.js";
7
+ import * as v from 'ak-tools';
8
+ const chance = u.initChance(SEED);
9
+
10
+ const num_users = 100;
11
+ const days = 360;
12
+
13
+ /** @typedef {import("../types.js").Dungeon} Config */
14
+
15
+ // Churn rates by favorite color per behavior type (percentage likelihood)
16
+ const CHURN_RATES = {
17
+ red: { hourly: 15, daily: 40, weekly: 15, monthly: 10 },
18
+ blue: { hourly: 15, daily: 15, weekly: 40, monthly: 10 },
19
+ green: { hourly: 5, daily: 5, weekly: 5, monthly: 5 },
20
+ yellow: { hourly: 15, daily: 15, weekly: 15, monthly: 40 },
21
+ purple: { hourly: 40, daily: 15, weekly: 15, monthly: 10 },
22
+ };
23
+
24
+ // Behavior cadence definitions: [intervalAmount, intervalUnit, jitterMax, jitterUnit]
25
+ const BEHAVIORS = {
26
+ hourly: { interval: 1, unit: 'hour', jitterMax: 10, jitterUnit: 'minute' },
27
+ daily: { interval: 1, unit: 'day', jitterMax: 2, jitterUnit: 'hour' },
28
+ weekly: { interval: 7, unit: 'day', jitterMax: 12, jitterUnit: 'hour' },
29
+ monthly: { interval: 30, unit: 'day', jitterMax: 2, jitterUnit: 'day' },
30
+ };
31
+
32
+ function generateCadencedEvents(behaviorName, cadence, startTime, endTime, churnTime, userId) {
33
+ const events = [];
34
+ let cursor = dayjs(startTime);
35
+ const end = dayjs(endTime);
36
+
37
+ while (cursor.isBefore(end)) {
38
+ if (churnTime && cursor.isAfter(churnTime)) break;
39
+
40
+ const jitter = chance.integer({ min: -cadence.jitterMax, max: cadence.jitterMax });
41
+ const eventTime = cursor.add(jitter, cadence.jitterUnit);
42
+
43
+ if (eventTime.isBefore(end) && eventTime.isAfter(startTime)) {
44
+ events.push({
45
+ event: `${behaviorName} behavior`,
46
+ time: eventTime.toISOString(),
47
+ user_id: userId,
48
+ insert_id: v.uid(12),
49
+ });
50
+ }
51
+
52
+ cursor = cursor.add(cadence.interval, cadence.unit);
53
+ }
54
+
55
+ // Insert churn event if user churns on this behavior
56
+ if (churnTime && dayjs(churnTime).isBefore(end)) {
57
+ events.push({
58
+ event: `churn - ${behaviorName} behavior`,
59
+ time: dayjs(churnTime).toISOString(),
60
+ user_id: userId,
61
+ insert_id: v.uid(12),
62
+ });
63
+ }
64
+
65
+ return events;
66
+ }
67
+
68
+ /** @type {Config} */
69
+ const config = {
70
+ token: "",
71
+ seed: "lets go",
72
+ numDays: days,
73
+ numEvents: num_users * 50,
74
+ numUsers: num_users,
75
+ hasAnonIds: false,
76
+ hasSessionIds: false,
77
+ format: "json",
78
+ alsoInferFunnels: false,
79
+ hasLocation: false,
80
+ hasAndroidDevices: false,
81
+ hasIOSDevices: false,
82
+ hasDesktopDevices: false,
83
+ hasBrowser: false,
84
+ hasCampaigns: false,
85
+ isAnonymous: false,
86
+ hasAdSpend: false,
87
+ hasAvatar: false,
88
+ makeChart: false,
89
+ batchSize: 5_500_000,
90
+ concurrency: 10,
91
+ writeToDisk: false,
92
+ percentUsersBornInDataset: 100,
93
+
94
+ funnels: [],
95
+
96
+ events: [
97
+ {
98
+ event: "first behavior",
99
+ weight: 1,
100
+ isFirstEvent: true,
101
+ properties: {},
102
+ },
103
+ {
104
+ event: "hourly behavior",
105
+ weight: 40,
106
+ properties: {},
107
+ },
108
+ {
109
+ event: "daily behavior",
110
+ weight: 30,
111
+ properties: {},
112
+ },
113
+ {
114
+ event: "weekly behavior",
115
+ weight: 15,
116
+ properties: {},
117
+ },
118
+ {
119
+ event: "monthly behavior",
120
+ weight: 10,
121
+ properties: {},
122
+ },
123
+ {
124
+ event: "placeholder",
125
+ weight: 50,
126
+ properties: {},
127
+ },
128
+ ],
129
+
130
+ superProps: {},
131
+
132
+ userProps: {
133
+ "favorite color": ["red", "blue", "green", "yellow", "purple"],
134
+ },
135
+
136
+ scdProps: {},
137
+ mirrorProps: {},
138
+ groupKeys: [],
139
+ groupProps: {},
140
+ lookupTables: [],
141
+
142
+ hook: function (record, type, meta) {
143
+ if (type === "everything") {
144
+ if (!record.length) return record;
145
+
146
+ const userId = record[0].user_id || record[0].device_id;
147
+ if (!userId) return record;
148
+
149
+ const favoriteColor = meta.profile?.["favorite color"] || "green";
150
+ const colorChurnRates = CHURN_RATES[favoriteColor] || CHURN_RATES.green;
151
+
152
+ // Find the time range from the raw events
153
+ const times = record.map(e => new Date(e.time).getTime()).filter(t => !isNaN(t));
154
+ if (!times.length) return record;
155
+ const startTime = dayjs(Math.min(...times));
156
+ const endTime = dayjs(Math.max(...times));
157
+ const totalSpanHours = endTime.diff(startTime, 'hour');
158
+
159
+ if (totalSpanHours < 1) return record;
160
+
161
+ // Keep the "first behavior" event from the original stream
162
+ const firstBehavior = record.find(e => e.event === "first behavior");
163
+ const newEvents = [];
164
+
165
+ if (firstBehavior) {
166
+ newEvents.push(firstBehavior);
167
+ } else {
168
+ // Create a first behavior event at the start
169
+ newEvents.push({
170
+ event: "first behavior",
171
+ time: startTime.toISOString(),
172
+ user_id: userId,
173
+ insert_id: v.uid(12),
174
+ });
175
+ }
176
+
177
+ // For each behavior type, determine churn and generate cadenced events
178
+ for (const [behaviorKey, cadence] of Object.entries(BEHAVIORS)) {
179
+ const churnRate = colorChurnRates[behaviorKey];
180
+ let churnTime = null;
181
+
182
+ if (chance.bool({ likelihood: churnRate })) {
183
+ // Pick churn time between 20% and 80% into the active period
184
+ const churnOffsetHours = chance.integer({
185
+ min: Math.floor(totalSpanHours * 0.2),
186
+ max: Math.floor(totalSpanHours * 0.8),
187
+ });
188
+ churnTime = startTime.add(churnOffsetHours, 'hour');
189
+ }
190
+
191
+ const behaviorEvents = generateCadencedEvents(
192
+ behaviorKey,
193
+ cadence,
194
+ startTime,
195
+ endTime,
196
+ churnTime,
197
+ userId
198
+ );
199
+ newEvents.push(...behaviorEvents);
200
+ }
201
+
202
+ // Sort all events by time
203
+ newEvents.sort((a, b) => new Date(a.time) - new Date(b.time));
204
+ return newEvents;
205
+ }
206
+
207
+ return record;
208
+ },
209
+ };
210
+
211
+ export default config;