@ak--47/dungeon-master 1.0.0
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 +518 -0
- package/dungeons/array-of-object-lookup-schema.json +327 -0
- package/dungeons/array-of-object-lookup.js +220 -0
- package/dungeons/ecommerce-schema.json +462 -0
- package/dungeons/ecommerce.js +447 -0
- package/dungeons/education-schema.json +2409 -0
- package/dungeons/education.js +768 -0
- package/dungeons/fintech-schema.json +14034 -0
- package/dungeons/fintech.js +696 -0
- package/dungeons/foobar-schema.json +403 -0
- package/dungeons/foobar.js +296 -0
- package/dungeons/food-delivery-schema.json +192 -0
- package/dungeons/food-delivery.js +602 -0
- package/dungeons/food-schema.json +1152 -0
- package/dungeons/food.js +754 -0
- package/dungeons/gaming-schema.json +1270 -0
- package/dungeons/gaming.js +508 -0
- package/dungeons/insurance-application-schema.json +204 -0
- package/dungeons/insurance-application.js +605 -0
- package/dungeons/media-schema.json +906 -0
- package/dungeons/media.js +790 -0
- package/dungeons/retention-cadence-schema.json +78 -0
- package/dungeons/retention-cadence.js +244 -0
- package/dungeons/rpg-schema.json +4526 -0
- package/dungeons/rpg.js +919 -0
- package/dungeons/sanity-schema.json +255 -0
- package/dungeons/sanity.js +152 -0
- package/dungeons/sass-schema.json +1291 -0
- package/dungeons/sass.js +795 -0
- package/dungeons/scd-schema.json +919 -0
- package/dungeons/scd.js +277 -0
- package/dungeons/simple-schema.json +608 -0
- package/dungeons/simple.js +285 -0
- package/dungeons/simplest-schema.json +1418 -0
- package/dungeons/simplest.js +392 -0
- package/dungeons/social-schema.json +1118 -0
- package/dungeons/social.js +686 -0
- package/dungeons/text-generation-schema.json +3096 -0
- package/dungeons/text-generation.js +812 -0
- package/index.js +567 -0
- package/lib/core/config-validator.js +395 -0
- package/lib/core/context.js +204 -0
- package/lib/core/dungeon-loader.js +337 -0
- package/lib/core/storage.js +379 -0
- package/lib/generators/adspend.js +132 -0
- package/lib/generators/events.js +271 -0
- package/lib/generators/funnels.js +407 -0
- package/lib/generators/mirror.js +167 -0
- package/lib/generators/product-lookup.js +262 -0
- package/lib/generators/product-names.js +195 -0
- package/lib/generators/profiles.js +93 -0
- package/lib/generators/scd.js +124 -0
- package/lib/generators/text.js +1192 -0
- package/lib/orchestrators/mixpanel-sender.js +266 -0
- package/lib/orchestrators/user-loop.js +335 -0
- package/lib/templates/abbreviated.d.ts +169 -0
- package/lib/templates/defaults.js +1405 -0
- package/lib/templates/phrases.js +2526 -0
- package/lib/templates/schema.d.ts +173 -0
- package/lib/templates/soup-presets.js +188 -0
- package/lib/utils/function-registry.js +302 -0
- package/lib/utils/json-evaluator.js +172 -0
- package/lib/utils/logger.js +34 -0
- package/lib/utils/utils.js +1490 -0
- package/package.json +89 -0
- package/types.d.ts +865 -0
package/dungeons/scd.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import Chance from 'chance';
|
|
2
|
+
const chance = new Chance();
|
|
3
|
+
import dayjs from "dayjs";
|
|
4
|
+
import utc from "dayjs/plugin/utc.js";
|
|
5
|
+
dayjs.extend(utc);
|
|
6
|
+
import { uid, comma } from 'ak-tools';
|
|
7
|
+
import { pickAWinner, weighNumRange, date, integer, weighChoices } from "../lib/utils/utils.js";
|
|
8
|
+
|
|
9
|
+
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"];
|
|
10
|
+
|
|
11
|
+
const videoCategories = ["funny", "educational", "inspirational", "music", "news", "sports", "cooking", "DIY", "travel", "gaming"];
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* ═══════════════════════════════════════════════════════════════
|
|
15
|
+
* DATASET OVERVIEW
|
|
16
|
+
* ═══════════════════════════════════════════════════════════════
|
|
17
|
+
*
|
|
18
|
+
* SCD Test — dungeon focused on Slowly Changing Dimensions.
|
|
19
|
+
* - 500 users over 30 days, ~50K events (CSV format)
|
|
20
|
+
* - E-commerce events: checkout, add to cart, page view, watch video, view/save item
|
|
21
|
+
* - User SCDs: role (weekly), NPS (daily)
|
|
22
|
+
* - Group SCDs: MRR (monthly), AccountHealthScore (weekly), plan (monthly)
|
|
23
|
+
* - 1,000 company groups with industry, segment, CSM assignments
|
|
24
|
+
*
|
|
25
|
+
* ═══════════════════════════════════════════════════════════════
|
|
26
|
+
* ANALYTICS HOOKS (3 patterns)
|
|
27
|
+
* ═══════════════════════════════════════════════════════════════
|
|
28
|
+
*
|
|
29
|
+
* 1. SPEND TIERS (user hook)
|
|
30
|
+
* Users with luckyNumber > 250 = "high_spender", else "budget".
|
|
31
|
+
*
|
|
32
|
+
* 2. COUPON DISCOUNTS + WEEKEND VIEWING (event hook)
|
|
33
|
+
* Checkouts with coupons get discounted amounts. Weekend video
|
|
34
|
+
* watchers get 1.5x watch time with is_weekend: true.
|
|
35
|
+
*
|
|
36
|
+
* Mixpanel Report:
|
|
37
|
+
* - Insights: "checkout", AVG(amount), breakdown by discount_applied
|
|
38
|
+
* Expected: discount_applied=true shows lower amounts
|
|
39
|
+
* - Insights: "watch video", AVG(watchTimeSec), breakdown by is_weekend
|
|
40
|
+
* Expected: weekend watch times ~1.5x higher
|
|
41
|
+
*
|
|
42
|
+
* 3. CART ABANDONMENT (everything hook)
|
|
43
|
+
* Users who add to cart but never checkout get a synthetic
|
|
44
|
+
* "cart_abandoned" event 30 min after last add-to-cart.
|
|
45
|
+
*
|
|
46
|
+
* Mixpanel Report:
|
|
47
|
+
* - Insights: "cart_abandoned" total events
|
|
48
|
+
* Expected: visible volume of abandoned cart events
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/** @type {import('../types').Dungeon} */
|
|
52
|
+
const config = {
|
|
53
|
+
token: "",
|
|
54
|
+
seed: "simple is best",
|
|
55
|
+
numDays: 30, //how many days worth1 of data
|
|
56
|
+
numEvents: 50000, //how many events
|
|
57
|
+
numUsers: 500, //how many users
|
|
58
|
+
format: 'csv', //csv or json
|
|
59
|
+
region: "US",
|
|
60
|
+
hasAnonIds: false, //if true, anonymousIds are created for each user
|
|
61
|
+
hasSessionIds: false, //if true, hasSessionIds are created for each user
|
|
62
|
+
hasAdSpend: false,
|
|
63
|
+
hasLocation: true,
|
|
64
|
+
hasAndroidDevices: true,
|
|
65
|
+
hasIOSDevices: true,
|
|
66
|
+
hasDesktopDevices: true,
|
|
67
|
+
hasBrowser: true,
|
|
68
|
+
hasCampaigns: true,
|
|
69
|
+
isAnonymous: false,
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
events: [
|
|
73
|
+
{
|
|
74
|
+
event: "checkout",
|
|
75
|
+
weight: 2,
|
|
76
|
+
properties: {
|
|
77
|
+
amount: weighNumRange(5, 500, .25),
|
|
78
|
+
currency: ["USD", "CAD", "EUR", "BTC", "ETH", "JPY"],
|
|
79
|
+
coupon: weighChoices(["none", "none", "none", "none", "10%OFF", "20%OFF", "10%OFF", "20%OFF", "30%OFF", "40%OFF", "50%OFF"]),
|
|
80
|
+
numItems: weighNumRange(1, 10),
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
event: "add to cart",
|
|
86
|
+
weight: 4,
|
|
87
|
+
properties: {
|
|
88
|
+
amount: weighNumRange(5, 500, .25),
|
|
89
|
+
rating: weighNumRange(1, 5),
|
|
90
|
+
reviews: weighNumRange(0, 35),
|
|
91
|
+
isFeaturedItem: [true, false, false],
|
|
92
|
+
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
93
|
+
dateItemListed: date(30, true, 'YYYY-MM-DD'),
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
event: "page view",
|
|
98
|
+
weight: 10,
|
|
99
|
+
properties: {
|
|
100
|
+
page: pickAWinner(["/", "/", "/help", "/account", "/watch", "/listen", "/product", "/people", "/peace"]),
|
|
101
|
+
utm_source: pickAWinner(["$organic", "$organic", "$organic", "$organic", "google", "google", "google", "facebook", "facebook", "twitter", "linkedin"]),
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
event: "watch video",
|
|
106
|
+
weight: 8,
|
|
107
|
+
properties: {
|
|
108
|
+
videoCategory: pickAWinner(videoCategories, integer(0, 9)),
|
|
109
|
+
isFeaturedItem: [true, false, false],
|
|
110
|
+
watchTimeSec: weighNumRange(10, 600, .25),
|
|
111
|
+
quality: ["2160p", "1440p", "1080p", "720p", "480p", "360p", "240p"],
|
|
112
|
+
format: ["mp4", "avi", "mov", "mpg"],
|
|
113
|
+
uploader_id: chance.guid.bind(chance)
|
|
114
|
+
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
event: "view item",
|
|
119
|
+
weight: 8,
|
|
120
|
+
properties: {
|
|
121
|
+
isFeaturedItem: [true, false, false],
|
|
122
|
+
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
123
|
+
dateItemListed: date(30, true, 'YYYY-MM-DD'),
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
event: "save item",
|
|
128
|
+
weight: 5,
|
|
129
|
+
properties: {
|
|
130
|
+
isFeaturedItem: [true, false, false],
|
|
131
|
+
itemCategory: pickAWinner(itemCategories, integer(0, 27)),
|
|
132
|
+
dateItemListed: date(30, true, 'YYYY-MM-DD'),
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
event: "sign up",
|
|
137
|
+
isFirstEvent: true,
|
|
138
|
+
weight: 0,
|
|
139
|
+
properties: {
|
|
140
|
+
variants: ["A", "B", "C", "Control"],
|
|
141
|
+
flows: ["new", "existing", "loyal", "churned"],
|
|
142
|
+
flags: ["on", "off"],
|
|
143
|
+
experiment_ids: ["1234", "5678", "9012", "3456", "7890"],
|
|
144
|
+
multiVariate: [true, false]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
],
|
|
148
|
+
superProps: {
|
|
149
|
+
platform: ["web", "mobile", "web", "mobile", "web", "web", "kiosk", "smartTV"],
|
|
150
|
+
currentTheme: weighChoices(["light", "dark", "custom", "light", "dark"]),
|
|
151
|
+
},
|
|
152
|
+
/*
|
|
153
|
+
user properties work the same as event properties
|
|
154
|
+
each key should be an array or function reference
|
|
155
|
+
*/
|
|
156
|
+
userProps: {
|
|
157
|
+
title: chance.profession.bind(chance),
|
|
158
|
+
luckyNumber: weighNumRange(42, 420, .3),
|
|
159
|
+
spiritAnimal: pickAWinner(["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"])
|
|
160
|
+
},
|
|
161
|
+
scdProps: {
|
|
162
|
+
role: {
|
|
163
|
+
type: "user",
|
|
164
|
+
frequency: "week",
|
|
165
|
+
values: ["admin", "collaborator", "user", "view only", "no access"],
|
|
166
|
+
timing: 'fuzzy',
|
|
167
|
+
max: 10
|
|
168
|
+
},
|
|
169
|
+
NPS: {
|
|
170
|
+
type: "user",
|
|
171
|
+
frequency: "day",
|
|
172
|
+
values: weighNumRange(1, 10, 2, 150),
|
|
173
|
+
timing: 'fuzzy',
|
|
174
|
+
max: 10
|
|
175
|
+
},
|
|
176
|
+
MRR: {
|
|
177
|
+
type: "company_id",
|
|
178
|
+
frequency: "month",
|
|
179
|
+
values: weighNumRange(0, 10000, .15),
|
|
180
|
+
timing: 'fixed',
|
|
181
|
+
max: 10
|
|
182
|
+
},
|
|
183
|
+
AccountHealthScore: {
|
|
184
|
+
type: "company_id",
|
|
185
|
+
frequency: "week",
|
|
186
|
+
values: weighNumRange(1, 10, .15),
|
|
187
|
+
timing: 'fixed',
|
|
188
|
+
max: 40
|
|
189
|
+
},
|
|
190
|
+
plan: {
|
|
191
|
+
type: "company_id",
|
|
192
|
+
frequency: "month",
|
|
193
|
+
values: ["free", "basic", "premium", "enterprise"],
|
|
194
|
+
timing: 'fixed',
|
|
195
|
+
max: 10
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
groupKeys: [["company_id", 1_000]],
|
|
199
|
+
groupProps: {
|
|
200
|
+
company_id: {
|
|
201
|
+
name: () => { return chance.name(); },
|
|
202
|
+
email: () => { return `CSM: ${chance.pickone(["AK", "Neha", "Rajiv", "Deepak", "Justin", "Hans", "Katie", "Somya", "Tony", "Kaan"])}`; },
|
|
203
|
+
industry: [
|
|
204
|
+
"technology",
|
|
205
|
+
"education",
|
|
206
|
+
"finance",
|
|
207
|
+
"healthcare",
|
|
208
|
+
"retail",
|
|
209
|
+
"manufacturing",
|
|
210
|
+
"transportation",
|
|
211
|
+
"entertainment",
|
|
212
|
+
"media",
|
|
213
|
+
"real estate",
|
|
214
|
+
"construction",
|
|
215
|
+
"hospitality",
|
|
216
|
+
"energy",
|
|
217
|
+
"utilities",
|
|
218
|
+
"agriculture",
|
|
219
|
+
"other",
|
|
220
|
+
],
|
|
221
|
+
segment: ["SMB", "SMB", "SMB", "Mid Market", "Mid Market", "Enterprise"],
|
|
222
|
+
"# active users": chance.integer({ min: 2, max: 20 })
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
hook: function (record, type, meta) {
|
|
226
|
+
// --- user hook: classify users into spending tiers ---
|
|
227
|
+
if (type === "user") {
|
|
228
|
+
record.spendTier = record.luckyNumber > 250 ? "high_spender" : "budget";
|
|
229
|
+
return record;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// --- event hook: coupon users get discounted checkout amounts ---
|
|
233
|
+
if (type === "event") {
|
|
234
|
+
if (record.event === "checkout" && record.coupon && record.coupon !== "none") {
|
|
235
|
+
const discountPct = parseInt(record.coupon) || 10;
|
|
236
|
+
record.amount = Math.round(record.amount * (1 - discountPct / 100));
|
|
237
|
+
record.discount_applied = true;
|
|
238
|
+
}
|
|
239
|
+
// weekend watchers get longer watch times
|
|
240
|
+
if (record.event === "watch video" && record.time) {
|
|
241
|
+
const day = dayjs(record.time).day();
|
|
242
|
+
if (day === 0 || day === 6) {
|
|
243
|
+
record.watchTimeSec = Math.round((record.watchTimeSec || 60) * 1.5);
|
|
244
|
+
record.is_weekend = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return record;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --- everything hook: simulate cart abandonment ---
|
|
251
|
+
if (type === "everything") {
|
|
252
|
+
const hasAddToCart = record.some(e => e.event === "add to cart");
|
|
253
|
+
const hasCheckout = record.some(e => e.event === "checkout");
|
|
254
|
+
// users who added to cart but never checked out: remove checkout events (if any slipped through)
|
|
255
|
+
// and mark them as abandoned
|
|
256
|
+
if (hasAddToCart && !hasCheckout && record.length > 2) {
|
|
257
|
+
const lastAdd = record.filter(e => e.event === "add to cart").pop();
|
|
258
|
+
if (lastAdd) {
|
|
259
|
+
record.push({
|
|
260
|
+
event: "cart_abandoned",
|
|
261
|
+
time: dayjs(lastAdd.time).add(30, "minute").toISOString(),
|
|
262
|
+
user_id: lastAdd.user_id,
|
|
263
|
+
platform: lastAdd.platform,
|
|
264
|
+
amount: lastAdd.amount
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return record;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return record;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
export default config;
|