@ak--47/dungeon-master 1.2.2 → 1.3.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/CHANGELOG.md +42 -0
- package/README.md +51 -13
- package/dungeons/technical/ad-spend.js +2 -2
- package/dungeons/technical/anonymous-users.js +2 -2
- package/dungeons/technical/array-of-object-lookup.js +2 -2
- package/dungeons/technical/experiments.js +2 -2
- package/dungeons/technical/foobar.js +2 -2
- package/dungeons/technical/group-analytics.js +2 -2
- package/dungeons/technical/mirror-strategies.js +2 -2
- package/dungeons/technical/nested-objects.js +2 -2
- package/dungeons/technical/retention-cadence.js +2 -3
- package/dungeons/technical/sanity.js +2 -2
- package/dungeons/technical/scale-test.js +2 -2
- package/dungeons/technical/scd.js +2 -2
- package/dungeons/technical/simple.js +2 -2
- package/dungeons/technical/simplest.js +2 -2
- package/dungeons/technical/text-generation.js +2 -2
- package/dungeons/vertical/ai-platform-schema.json +617 -0
- package/dungeons/vertical/ai-platform.js +799 -0
- package/dungeons/vertical/community.js +40 -26
- package/dungeons/vertical/crypto-schema.json +546 -0
- package/dungeons/vertical/crypto.js +721 -0
- package/dungeons/vertical/dating-schema.json +401 -0
- package/dungeons/vertical/dating.js +798 -0
- package/dungeons/vertical/devtools.js +13 -9
- package/dungeons/vertical/ecommerce.js +2 -3
- package/dungeons/vertical/education.js +4 -5
- package/dungeons/vertical/fintech.js +32 -29
- package/dungeons/vertical/fitness.js +2 -3
- package/dungeons/vertical/food-delivery.js +37 -43
- package/dungeons/vertical/gaming-schema.json +2495 -230
- package/dungeons/vertical/gaming.js +771 -388
- package/dungeons/vertical/healthcare.js +2 -3
- package/dungeons/vertical/insurance-application.js +2 -3
- package/dungeons/vertical/logistics.js +20 -14
- package/dungeons/vertical/marketplace.js +22 -14
- package/dungeons/vertical/media.js +39 -30
- package/dungeons/vertical/real-estate-schema.json +527 -0
- package/dungeons/vertical/real-estate.js +774 -0
- package/dungeons/vertical/sass.js +2 -3
- package/dungeons/vertical/social.js +15 -13
- package/dungeons/vertical/travel.js +59 -26
- package/lib/core/config-validator.js +71 -15
- package/lib/core/storage.js +14 -4
- package/lib/orchestrators/user-loop.js +39 -5
- package/lib/templates/macro-presets.js +111 -0
- package/lib/templates/soup-presets.js +19 -36
- package/package.json +8 -2
- package/types.d.ts +219 -42
- package/dungeons/user/.gitkeep +0 -0
- package/dungeons/vertical/rpg-schema.json +0 -2491
- package/dungeons/vertical/rpg.js +0 -976
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Soup preset configurations.
|
|
3
|
+
*
|
|
4
|
+
* Soup presets shape the INTRA-WEEK and INTRA-DAY rhythm: how many Gaussian
|
|
5
|
+
* peaks to sample from, how tightly each clusters, and how to weight each
|
|
6
|
+
* day-of-week and hour-of-day during accept/reject sampling.
|
|
7
|
+
*
|
|
8
|
+
* Soup is the orthogonal axis to macro presets (lib/templates/macro-presets.js).
|
|
9
|
+
* Macro shapes the big-picture trend (births, growth, decline). Soup shapes
|
|
10
|
+
* the texture inside that trend (weekly cycle, daily peak, burstiness).
|
|
4
11
|
*
|
|
5
12
|
* Parameters:
|
|
6
13
|
* - peaks(numDays): function returning number of Gaussian clusters
|
|
@@ -8,9 +15,6 @@
|
|
|
8
15
|
* - mean: offset from chunk center (0 = centered)
|
|
9
16
|
* - dayOfWeekWeights: 7-element array [Sun..Sat], max=1.0, null to disable
|
|
10
17
|
* - hourOfDayWeights: 24-element array [0h..23h UTC], max=1.0, null to disable
|
|
11
|
-
*
|
|
12
|
-
* Some presets also suggest bornRecentBias and percentUsersBornInDataset,
|
|
13
|
-
* but those are top-level dungeon config — presets only set them if not already specified.
|
|
14
18
|
*/
|
|
15
19
|
|
|
16
20
|
// Real-world Mixpanel DOW pattern: weekday-heavy, Saturday valley
|
|
@@ -27,11 +31,11 @@ export const REAL_HOD = [
|
|
|
27
31
|
export const FLAT_DOW = [1, 1, 1, 1, 1, 1, 1];
|
|
28
32
|
export const FLAT_HOD = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
|
|
29
33
|
|
|
30
|
-
/** @type {Record<string, {peaks: (numDays: number) => number, deviation: number, mean: number, dayOfWeekWeights: number[]|null, hourOfDayWeights: number[]|null
|
|
34
|
+
/** @type {Record<string, {peaks: (numDays: number) => number, deviation: number, mean: number, dayOfWeekWeights: number[]|null, hourOfDayWeights: number[]|null}>} */
|
|
31
35
|
export const SOUP_PRESETS = {
|
|
32
36
|
/**
|
|
33
37
|
* steady — Mature SaaS / Stable Product
|
|
34
|
-
*
|
|
38
|
+
* Tighter clusters, real-world DOW/HOD weights.
|
|
35
39
|
*/
|
|
36
40
|
steady: {
|
|
37
41
|
peaks: (numDays) => Math.max(5, numDays * 2),
|
|
@@ -39,13 +43,11 @@ export const SOUP_PRESETS = {
|
|
|
39
43
|
mean: 0,
|
|
40
44
|
dayOfWeekWeights: REAL_DOW,
|
|
41
45
|
hourOfDayWeights: REAL_HOD,
|
|
42
|
-
bornRecentBias: 0.1,
|
|
43
|
-
percentUsersBornInDataset: 10,
|
|
44
46
|
},
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* growth — Growing Startup (DEFAULT)
|
|
48
|
-
*
|
|
50
|
+
* Standard clustering with real-world weekly + daily rhythm.
|
|
49
51
|
*/
|
|
50
52
|
growth: {
|
|
51
53
|
peaks: (numDays) => Math.max(5, numDays * 2),
|
|
@@ -53,13 +55,11 @@ export const SOUP_PRESETS = {
|
|
|
53
55
|
mean: 0,
|
|
54
56
|
dayOfWeekWeights: REAL_DOW,
|
|
55
57
|
hourOfDayWeights: REAL_HOD,
|
|
56
|
-
bornRecentBias: 0.3,
|
|
57
|
-
percentUsersBornInDataset: 15,
|
|
58
58
|
},
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* spiky — Event-Driven / Bursty
|
|
62
|
-
*
|
|
62
|
+
* Fewer Gaussian clusters + tight deviation = visible peaks and valleys.
|
|
63
63
|
*/
|
|
64
64
|
spiky: {
|
|
65
65
|
peaks: (numDays) => Math.max(4, Math.ceil(numDays / 15)),
|
|
@@ -67,13 +67,11 @@ export const SOUP_PRESETS = {
|
|
|
67
67
|
mean: 0,
|
|
68
68
|
dayOfWeekWeights: REAL_DOW,
|
|
69
69
|
hourOfDayWeights: REAL_HOD,
|
|
70
|
-
bornRecentBias: 0.3,
|
|
71
|
-
percentUsersBornInDataset: 20,
|
|
72
70
|
},
|
|
73
71
|
|
|
74
72
|
/**
|
|
75
73
|
* seasonal — Strong Cyclical Patterns
|
|
76
|
-
*
|
|
74
|
+
* 4 major waves across the dataset for dramatic macro trends.
|
|
77
75
|
*/
|
|
78
76
|
seasonal: {
|
|
79
77
|
peaks: () => 4,
|
|
@@ -81,13 +79,11 @@ export const SOUP_PRESETS = {
|
|
|
81
79
|
mean: 0,
|
|
82
80
|
dayOfWeekWeights: REAL_DOW,
|
|
83
81
|
hourOfDayWeights: REAL_HOD,
|
|
84
|
-
bornRecentBias: 0.2,
|
|
85
|
-
percentUsersBornInDataset: 25,
|
|
86
82
|
},
|
|
87
83
|
|
|
88
84
|
/**
|
|
89
85
|
* global — Distributed Users Across Timezones
|
|
90
|
-
*
|
|
86
|
+
* Flat hourly + daily distribution. No cyclical patterns.
|
|
91
87
|
*/
|
|
92
88
|
global: {
|
|
93
89
|
peaks: (numDays) => Math.max(5, numDays * 2),
|
|
@@ -95,15 +91,12 @@ export const SOUP_PRESETS = {
|
|
|
95
91
|
mean: 0,
|
|
96
92
|
dayOfWeekWeights: FLAT_DOW,
|
|
97
93
|
hourOfDayWeights: FLAT_HOD,
|
|
98
|
-
bornRecentBias: 0,
|
|
99
|
-
percentUsersBornInDataset: 10,
|
|
100
94
|
},
|
|
101
95
|
|
|
102
96
|
/**
|
|
103
97
|
* churny — High Churn / Declining Product
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* filters late events to create a true declining shape.
|
|
98
|
+
* Standard intra-week rhythm. Combine with macro: "decline" and an
|
|
99
|
+
* "everything" hook that filters late events to create a true declining shape.
|
|
107
100
|
*/
|
|
108
101
|
churny: {
|
|
109
102
|
peaks: (numDays) => Math.max(5, numDays * 2),
|
|
@@ -111,8 +104,6 @@ export const SOUP_PRESETS = {
|
|
|
111
104
|
mean: 0,
|
|
112
105
|
dayOfWeekWeights: REAL_DOW,
|
|
113
106
|
hourOfDayWeights: REAL_HOD,
|
|
114
|
-
bornRecentBias: 0,
|
|
115
|
-
percentUsersBornInDataset: 5,
|
|
116
107
|
},
|
|
117
108
|
|
|
118
109
|
/**
|
|
@@ -125,8 +116,6 @@ export const SOUP_PRESETS = {
|
|
|
125
116
|
mean: 0,
|
|
126
117
|
dayOfWeekWeights: REAL_DOW,
|
|
127
118
|
hourOfDayWeights: REAL_HOD,
|
|
128
|
-
bornRecentBias: 0.5,
|
|
129
|
-
percentUsersBornInDataset: 40,
|
|
130
119
|
},
|
|
131
120
|
};
|
|
132
121
|
|
|
@@ -137,7 +126,7 @@ export const PRESET_NAMES = Object.keys(SOUP_PRESETS);
|
|
|
137
126
|
* Resolves a soup config — handles string presets, preset+overrides, and raw objects.
|
|
138
127
|
* @param {string | object} soup - Soup config from dungeon
|
|
139
128
|
* @param {number} numDays - Number of days in the dataset
|
|
140
|
-
* @returns {{ soup: object
|
|
129
|
+
* @returns {{ soup: object }}
|
|
141
130
|
*/
|
|
142
131
|
export function resolveSoup(soup, numDays) {
|
|
143
132
|
if (!soup) return { soup: {} };
|
|
@@ -156,8 +145,6 @@ export function resolveSoup(soup, numDays) {
|
|
|
156
145
|
dayOfWeekWeights: preset.dayOfWeekWeights,
|
|
157
146
|
hourOfDayWeights: preset.hourOfDayWeights,
|
|
158
147
|
},
|
|
159
|
-
suggestedBornRecentBias: preset.bornRecentBias,
|
|
160
|
-
suggestedPercentUsersBornInDataset: preset.percentUsersBornInDataset,
|
|
161
148
|
};
|
|
162
149
|
}
|
|
163
150
|
|
|
@@ -176,11 +163,7 @@ export function resolveSoup(soup, numDays) {
|
|
|
176
163
|
};
|
|
177
164
|
// Apply overrides (excluding the 'preset' key itself)
|
|
178
165
|
const { preset: _, ...overrides } = soup;
|
|
179
|
-
return {
|
|
180
|
-
soup: { ...base, ...overrides },
|
|
181
|
-
suggestedBornRecentBias: preset.bornRecentBias,
|
|
182
|
-
suggestedPercentUsersBornInDataset: preset.percentUsersBornInDataset,
|
|
183
|
-
};
|
|
166
|
+
return { soup: { ...base, ...overrides } };
|
|
184
167
|
}
|
|
185
168
|
|
|
186
169
|
// Raw object: { peaks: 10, deviation: 2 } — pass through unchanged
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ak--47/dungeon-master",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "generate fancy datasets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -19,10 +19,16 @@
|
|
|
19
19
|
"lib/",
|
|
20
20
|
"dungeons/",
|
|
21
21
|
"!dungeons/customers/",
|
|
22
|
+
"!dungeons/user/",
|
|
22
23
|
"scripts/",
|
|
24
|
+
"!scripts/experiments/",
|
|
23
25
|
"package.json",
|
|
24
|
-
"README.md"
|
|
26
|
+
"README.md",
|
|
27
|
+
"CHANGELOG.md"
|
|
25
28
|
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18.0.0"
|
|
31
|
+
},
|
|
26
32
|
"publishConfig": {
|
|
27
33
|
"access": "public"
|
|
28
34
|
},
|
package/types.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Primitive scalar types that property values resolve to. Property values may
|
|
3
|
+
* also be plain object literals (nested records) — `Record<string, any>` is the
|
|
4
|
+
* narrowest TS can express here without making `Primitives` self-recursive
|
|
5
|
+
* (which it can't be, because `ValueValid` is built on top of it).
|
|
3
6
|
*/
|
|
4
7
|
type Primitives = string | number | boolean | Date | Record<string, any>;
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
|
-
*
|
|
10
|
+
* A "validValue" can be a primitive, an array of valid values, or a thunk that
|
|
11
|
+
* returns one. Configs use this everywhere properties are user-defined.
|
|
8
12
|
*/
|
|
9
13
|
export type ValueValid = Primitives | ValueValid[] | (() => ValueValid);
|
|
10
14
|
|
|
@@ -23,10 +27,12 @@ export interface Dungeon {
|
|
|
23
27
|
epochStart?: number;
|
|
24
28
|
/** Explicit end of dataset window (unix seconds). Defaults to FIXED_NOW. */
|
|
25
29
|
epochEnd?: number;
|
|
26
|
-
/** Target total number of events to generate across all users. */
|
|
30
|
+
/** Target total number of events to generate across all users. Fallback when avgEventsPerUserPerDay is not set; otherwise derived from rate × numUsers × numDays. */
|
|
27
31
|
numEvents?: number;
|
|
28
32
|
/** Number of unique users to generate. */
|
|
29
33
|
numUsers?: number;
|
|
34
|
+
/** Average events per user per active day. The canonical event-volume primitive — born-late users get this rate × their remaining window, so per-day density stays constant. If both this and numEvents are set, this wins. */
|
|
35
|
+
avgEventsPerUserPerDay?: number;
|
|
30
36
|
/** Output format for files written to disk. */
|
|
31
37
|
format?: "csv" | "json" | "parquet" | string;
|
|
32
38
|
/** Mixpanel data residency region. */
|
|
@@ -106,9 +112,11 @@ export interface Dungeon {
|
|
|
106
112
|
groupEvents?: GroupEventConfig[];
|
|
107
113
|
/** Lookup table definitions for dimension tables. */
|
|
108
114
|
lookupTables?: LookupTableSchema[];
|
|
109
|
-
/** TimeSoup configuration:
|
|
115
|
+
/** TimeSoup configuration: shapes intra-week and intra-day rhythm (peaks, deviation, DOW/HOD weights). Pair with `macro` for big-picture trend control. */
|
|
110
116
|
soup?: soup;
|
|
111
|
-
/**
|
|
117
|
+
/** Macro trend shape across the full dataset window: birth distribution + per-user event allocation. Default: "flat". Use "growth"/"viral"/"steady"/"decline" or a custom object. */
|
|
118
|
+
macro?: macro;
|
|
119
|
+
/** Hook function called on every data point. The primary mechanism for engineering deliberate trends and patterns. The `any` is intentional — `record` and `meta` shapes vary by hook type; narrow inside the function (see `HookMeta*` types). */
|
|
112
120
|
hook?: Hook<any>;
|
|
113
121
|
|
|
114
122
|
// ── Advanced Features ──
|
|
@@ -135,10 +143,14 @@ export interface Dungeon {
|
|
|
135
143
|
[key: string]: any;
|
|
136
144
|
|
|
137
145
|
// ── Distribution Controls ──
|
|
138
|
-
|
|
146
|
+
// These three knobs are normally set by the `macro` preset (default "flat").
|
|
147
|
+
// Setting them on the dungeon config directly overrides the preset's value.
|
|
148
|
+
/** Percentage of users whose account creation falls within the dataset window (vs. pre-existing). Default (from macro: "flat"): 15 */
|
|
139
149
|
percentUsersBornInDataset?: number;
|
|
140
|
-
/** Bias
|
|
150
|
+
/** Bias for birth dates of users born in dataset. -1..1; negative = early skew, positive = recent skew, 0 = uniform. Default (from macro: "flat"): 0 */
|
|
141
151
|
bornRecentBias?: number;
|
|
152
|
+
/** How pre-existing users' first event time is placed. "pinned" stacks them all at FIXED_BEGIN; "uniform" spreads across [FIXED_BEGIN-30d, FIXED_BEGIN]. Default (from macro: "flat"): "uniform" */
|
|
153
|
+
preExistingSpread?: "pinned" | "uniform";
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
export type SCDProp = {
|
|
@@ -183,6 +195,43 @@ export type SoupConfig = {
|
|
|
183
195
|
*/
|
|
184
196
|
type soup = SoupPreset | SoupConfig;
|
|
185
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Macro preset names for big-picture trend shape across the dataset window.
|
|
200
|
+
* Macro is orthogonal to soup: macro shapes the whole-window trend (births,
|
|
201
|
+
* growth, decline); soup shapes the intra-week and intra-day rhythm.
|
|
202
|
+
*/
|
|
203
|
+
export type MacroPreset = "flat" | "steady" | "growth" | "viral" | "decline";
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Macro configuration object — fine-grained big-picture trend control.
|
|
207
|
+
*/
|
|
208
|
+
export type MacroConfig = {
|
|
209
|
+
/** Use a named macro preset as the base, then override individual fields. */
|
|
210
|
+
preset?: MacroPreset;
|
|
211
|
+
/** Bias for birth dates. -1..1; negative = early skew, positive = recent skew, 0 = uniform. */
|
|
212
|
+
bornRecentBias?: number;
|
|
213
|
+
/** Percentage of users born in dataset window (0..100). */
|
|
214
|
+
percentUsersBornInDataset?: number;
|
|
215
|
+
/** "pinned" = pre-existing users stack at FIXED_BEGIN; "uniform" = spread across [FIXED_BEGIN-30d, FIXED_BEGIN]. */
|
|
216
|
+
preExistingSpread?: "pinned" | "uniform";
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/** Big-picture trend shape: preset string, config object, or preset+overrides. */
|
|
220
|
+
type macro = MacroPreset | MacroConfig;
|
|
221
|
+
|
|
222
|
+
/** Public alias for the `soup` config union (preset string or config object). */
|
|
223
|
+
export type Soup = soup;
|
|
224
|
+
|
|
225
|
+
/** Public alias for the `macro` config union (preset string or config object). */
|
|
226
|
+
export type Macro = macro;
|
|
227
|
+
|
|
228
|
+
/** Resolved macro values after preset + override resolution. Used internally. */
|
|
229
|
+
export interface ResolvedMacro {
|
|
230
|
+
bornRecentBias: number;
|
|
231
|
+
percentUsersBornInDataset: number;
|
|
232
|
+
preExistingSpread: "pinned" | "uniform";
|
|
233
|
+
}
|
|
234
|
+
|
|
186
235
|
/**
|
|
187
236
|
* Hook types and when they fire (in order per user):
|
|
188
237
|
* - "user" — user profile object (mutate in-place, return ignored)
|
|
@@ -213,31 +262,129 @@ export type hookTypes =
|
|
|
213
262
|
|
|
214
263
|
/**
|
|
215
264
|
* A hook function that receives every piece of data as it flows through the pipeline.
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
265
|
+
*
|
|
266
|
+
* The runtime signature is intentionally permissive (`any`) because `record` and `meta`
|
|
267
|
+
* vary by `type`. Use the `HookMeta*` interfaces below as convenience types when narrowing
|
|
268
|
+
* inside your hook (e.g. `if (type === "event") { const m = meta as HookMetaEvent; ... }`).
|
|
269
|
+
*
|
|
270
|
+
* Return-value semantics:
|
|
271
|
+
* - "event": return value REPLACES the event (must be the event object).
|
|
272
|
+
* - "everything": return an array to REPLACE the user's event list (filter/inject/dedupe).
|
|
273
|
+
* - "user", "scd-pre", "funnel-pre", "funnel-post": return value is IGNORED — mutate in place.
|
|
274
|
+
* - storage-only ("ad-spend", "group", "mirror", "lookup"): return value is IGNORED.
|
|
275
|
+
*
|
|
276
|
+
* @param record - The data being processed (event, profile, array of events, funnel config, etc.).
|
|
277
|
+
* @param type - Which hook type is firing — see `hookTypes`.
|
|
278
|
+
* @param meta - Contextual metadata. Shape depends on `type` — see `HookMeta*` interfaces.
|
|
219
279
|
*/
|
|
220
280
|
export type Hook<T> = (record: any, type: hookTypes, meta: any) => T;
|
|
221
281
|
|
|
282
|
+
/** Meta passed to the "event" hook. */
|
|
283
|
+
export interface HookMetaEvent {
|
|
284
|
+
/** The user this event belongs to (only `distinct_id` is guaranteed). */
|
|
285
|
+
user: { distinct_id: string };
|
|
286
|
+
/** The fully-resolved dungeon config. */
|
|
287
|
+
config: Dungeon;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Meta passed to the "user" hook (fires when a user profile is created). */
|
|
291
|
+
export interface HookMetaUser {
|
|
292
|
+
/** The user object being constructed (mutate in place). */
|
|
293
|
+
user: UserProfile;
|
|
294
|
+
/** The fully-resolved dungeon config. */
|
|
295
|
+
config: Dungeon;
|
|
296
|
+
/** True if the user's account creation falls inside the dataset window. */
|
|
297
|
+
userIsBornInDataset: boolean;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Meta passed to the "scd-pre" hook (fires per SCD prop, before insertion). */
|
|
301
|
+
export interface HookMetaScdPre {
|
|
302
|
+
/** The user profile that owns these SCD entries. */
|
|
303
|
+
profile: UserProfile;
|
|
304
|
+
/** The SCD prop key being generated (e.g. "plan", "tier"). */
|
|
305
|
+
type: string;
|
|
306
|
+
/** The full SCD entry list for this prop (mutate in place). */
|
|
307
|
+
scd: SCDSchema[];
|
|
308
|
+
/** The fully-resolved dungeon config. */
|
|
309
|
+
config: Dungeon;
|
|
310
|
+
/** All SCD prop arrays generated so far for this user, keyed by prop name. */
|
|
311
|
+
allSCDs: Record<string, SCDSchema[]>;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/** Meta passed to the "funnel-pre" hook (mutate funnel before generating events). */
|
|
315
|
+
export interface HookMetaFunnelPre {
|
|
316
|
+
user: { distinct_id: string };
|
|
317
|
+
profile: UserProfile;
|
|
318
|
+
scd: Record<string, SCDSchema[]>;
|
|
319
|
+
funnel: Funnel;
|
|
320
|
+
config: Dungeon;
|
|
321
|
+
/** Unix seconds — earliest possible event time for this funnel's first step. */
|
|
322
|
+
firstEventTime: number;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/** Meta passed to the "funnel-post" hook (mutate generated funnel events in place). */
|
|
326
|
+
export interface HookMetaFunnelPost {
|
|
327
|
+
user: { distinct_id: string };
|
|
328
|
+
profile: UserProfile;
|
|
329
|
+
scd: Record<string, SCDSchema[]>;
|
|
330
|
+
funnel: Funnel;
|
|
331
|
+
config: Dungeon;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** Meta passed to the "everything" hook — most powerful hook (sees all events for one user). */
|
|
335
|
+
export interface HookMetaEverything {
|
|
336
|
+
/** The user's profile, including merged persona/region/attribution properties. */
|
|
337
|
+
profile: UserProfile;
|
|
338
|
+
/** All SCD entries for this user, keyed by prop name. */
|
|
339
|
+
scd: Record<string, SCDSchema[]>;
|
|
340
|
+
/** The fully-resolved dungeon config. */
|
|
341
|
+
config: Dungeon;
|
|
342
|
+
/** True if the user's account creation falls inside the dataset window. */
|
|
343
|
+
userIsBornInDataset: boolean;
|
|
344
|
+
}
|
|
345
|
+
|
|
222
346
|
export interface hookArrayOptions<T> {
|
|
347
|
+
/** Transform/validate function applied to every record on push. */
|
|
223
348
|
hook?: Hook<T>;
|
|
349
|
+
/** What this array stores — controls hook-firing semantics in the storage layer. */
|
|
224
350
|
type?: hookTypes;
|
|
351
|
+
/** Output filename (no extension; format adds it). Used by storage's batch writer. */
|
|
225
352
|
filename?: string;
|
|
353
|
+
/** Output filepath used when writing batches to disk. */
|
|
354
|
+
filepath?: string;
|
|
355
|
+
/** Output serialization format. */
|
|
226
356
|
format?: "csv" | "json" | "parquet" | string;
|
|
357
|
+
/** Max parallel disk writes. */
|
|
227
358
|
concurrency?: number;
|
|
359
|
+
/** Generation context (config, runtime, defaults). */
|
|
228
360
|
context?: Context;
|
|
229
|
-
[key: string]: any;
|
|
230
361
|
}
|
|
231
362
|
|
|
232
363
|
/**
|
|
233
|
-
* an enriched array is an array that has a hookPush method that can be used to transform-then-push items into the array
|
|
364
|
+
* an enriched array is an array that has a hookPush method that can be used to transform-then-push items into the array.
|
|
365
|
+
*
|
|
366
|
+
* Storage callers also tag the array with a key identifying what it stores
|
|
367
|
+
* (e.g. SCD prop name, group key, lookup table key). The fields are optional
|
|
368
|
+
* because not every HookedArray needs them; mixpanel-sender / user-loop read
|
|
369
|
+
* them when present to route uploads correctly.
|
|
234
370
|
*/
|
|
235
371
|
export interface HookedArray<T> extends Array<T> {
|
|
236
|
-
|
|
372
|
+
/** Transform-then-push. Resolves once the item (and any auto-flushed batch) is persisted. */
|
|
373
|
+
hookPush: (item: T | T[], ...meta: unknown[]) => Promise<void>;
|
|
374
|
+
/** Force-flush any pending batch to disk. */
|
|
237
375
|
flush: () => Promise<void>;
|
|
376
|
+
/** Absolute path of the directory batches will be written to. */
|
|
238
377
|
getWriteDir: () => string;
|
|
378
|
+
/** Absolute path (with extension) of the next batch file. */
|
|
239
379
|
getWritePath: () => string;
|
|
240
|
-
|
|
380
|
+
/** SCD prop name this array carries (only set on SCD HookedArrays). */
|
|
381
|
+
scdKey?: string;
|
|
382
|
+
/** Entity type for SCDs ("user" or a group key). */
|
|
383
|
+
entityType?: string;
|
|
384
|
+
/** Group key this array carries (only set on group profile HookedArrays). */
|
|
385
|
+
groupKey?: string;
|
|
386
|
+
/** Lookup table key this array carries (only set on lookup table HookedArrays). */
|
|
387
|
+
lookupKey?: string;
|
|
241
388
|
}
|
|
242
389
|
|
|
243
390
|
export type AllData =
|
|
@@ -245,8 +392,7 @@ export type AllData =
|
|
|
245
392
|
| HookedArray<UserProfile>
|
|
246
393
|
| HookedArray<GroupProfileSchema>
|
|
247
394
|
| HookedArray<LookupTableSchema>
|
|
248
|
-
| HookedArray<SCDSchema
|
|
249
|
-
| any[];
|
|
395
|
+
| HookedArray<SCDSchema>;
|
|
250
396
|
|
|
251
397
|
/**
|
|
252
398
|
* the storage object is a key-value store that holds arrays of data
|
|
@@ -277,16 +423,33 @@ export interface RuntimeState {
|
|
|
277
423
|
/**
|
|
278
424
|
* Default data factories for generating realistic test data
|
|
279
425
|
*/
|
|
426
|
+
/**
|
|
427
|
+
* Default data factories — pre-resolved at context creation time so user-loop
|
|
428
|
+
* doesn't re-evaluate weighted picker arrays on every iteration.
|
|
429
|
+
*/
|
|
280
430
|
export interface Defaults {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
431
|
+
/** Location pools applied to user profiles (city, region, country, lat/lng). */
|
|
432
|
+
locationsUsers: () => Record<string, ValueValid>[];
|
|
433
|
+
/** Location pools applied to events. */
|
|
434
|
+
locationsEvents: () => Record<string, ValueValid>[];
|
|
435
|
+
/** iOS device pool (model, os version, etc.). */
|
|
436
|
+
iOSDevices: () => Record<string, ValueValid>[];
|
|
437
|
+
/** Android device pool. */
|
|
438
|
+
androidDevices: () => Record<string, ValueValid>[];
|
|
439
|
+
/** Desktop device pool (browser, screen resolution, etc.). */
|
|
440
|
+
desktopDevices: () => Record<string, ValueValid>[];
|
|
441
|
+
/** Browser/UA pool. */
|
|
442
|
+
browsers: () => Record<string, ValueValid>[];
|
|
443
|
+
/** UTM campaign pool used when `hasCampaigns: true`. */
|
|
444
|
+
campaigns: () => Record<string, ValueValid>[];
|
|
445
|
+
/** Pre-built per-platform device arrays selected once at context creation. */
|
|
446
|
+
devicePools: {
|
|
447
|
+
android: Record<string, ValueValid>[];
|
|
448
|
+
ios: Record<string, ValueValid>[];
|
|
449
|
+
desktop: Record<string, ValueValid>[];
|
|
450
|
+
};
|
|
451
|
+
/** Flat union of every device in `devicePools` — used when no platform filter applies. */
|
|
452
|
+
allDevices: Record<string, ValueValid>[];
|
|
290
453
|
}
|
|
291
454
|
|
|
292
455
|
/**
|
|
@@ -297,7 +460,8 @@ export interface Context {
|
|
|
297
460
|
config: Dungeon;
|
|
298
461
|
storage: Storage | null;
|
|
299
462
|
defaults: Defaults;
|
|
300
|
-
|
|
463
|
+
/** Pre-built UTM campaign pool (used when `hasCampaigns: true`). */
|
|
464
|
+
campaigns: Record<string, ValueValid>[];
|
|
301
465
|
runtime: RuntimeState;
|
|
302
466
|
FIXED_NOW: number;
|
|
303
467
|
FIXED_BEGIN?: number;
|
|
@@ -494,7 +658,8 @@ export interface LookupTableSchema {
|
|
|
494
658
|
|
|
495
659
|
export interface LookupTableData {
|
|
496
660
|
key: string;
|
|
497
|
-
|
|
661
|
+
/** Generated rows for this lookup table. Each row is a flat record keyed by attribute name. */
|
|
662
|
+
data: Record<string, ValueValid>[];
|
|
498
663
|
}
|
|
499
664
|
|
|
500
665
|
export interface SCDSchema {
|
|
@@ -506,7 +671,8 @@ export interface SCDSchema {
|
|
|
506
671
|
|
|
507
672
|
export interface GroupProfileSchema {
|
|
508
673
|
key: string;
|
|
509
|
-
|
|
674
|
+
/** Generated group profile rows. Each row is a flat record keyed by group property name. */
|
|
675
|
+
data: Record<string, ValueValid>[];
|
|
510
676
|
}
|
|
511
677
|
|
|
512
678
|
/**
|
|
@@ -523,15 +689,25 @@ type ImportResult = import("mixpanel-import").ImportResults;
|
|
|
523
689
|
* the end result of the data generation
|
|
524
690
|
*/
|
|
525
691
|
export type Result = {
|
|
692
|
+
/** Generated events. */
|
|
526
693
|
eventData: EventSchema[];
|
|
694
|
+
/** Mirror datasets (transformed copies of `eventData`). */
|
|
527
695
|
mirrorEventData: EventSchema[];
|
|
528
|
-
|
|
529
|
-
|
|
696
|
+
/** User profiles. */
|
|
697
|
+
userProfilesData: UserProfile[];
|
|
698
|
+
/** SCD entries — one inner array per SCD prop. */
|
|
699
|
+
scdTableData: SCDSchema[][];
|
|
700
|
+
/** Ad-spend events (only populated when `hasAdSpend: true`). */
|
|
530
701
|
adSpendData: EventSchema[];
|
|
702
|
+
/** Group profiles — one inner array per group key. */
|
|
531
703
|
groupProfilesData: GroupProfileSchema[][];
|
|
704
|
+
/** Lookup tables — one inner array per table. */
|
|
532
705
|
lookupTableData: LookupTableData[][];
|
|
706
|
+
/** Mixpanel import results (only populated when a token was provided). */
|
|
533
707
|
importResults?: ImportResults;
|
|
708
|
+
/** Absolute paths of all files written to disk. */
|
|
534
709
|
files?: string[];
|
|
710
|
+
/** Timing information. */
|
|
535
711
|
time?: {
|
|
536
712
|
start: number;
|
|
537
713
|
end: number;
|
|
@@ -589,7 +765,7 @@ export interface WorldEvent {
|
|
|
589
765
|
/** Conversion rate modifier during this event. */
|
|
590
766
|
conversionModifier?: number;
|
|
591
767
|
/** Properties injected into affected events. */
|
|
592
|
-
injectProps?: Record<string,
|
|
768
|
+
injectProps?: Record<string, ValueValid>;
|
|
593
769
|
/** Which events are affected ("*" for all, or array of event names). */
|
|
594
770
|
affectsEvents?: string[] | "*";
|
|
595
771
|
/** Aftermath period after the event ends. */
|
|
@@ -752,7 +928,7 @@ export interface GeoRegion {
|
|
|
752
928
|
/** UTC timezone offset for this region (e.g., -5 for EST). */
|
|
753
929
|
timezoneOffset: number;
|
|
754
930
|
/** Properties injected for users in this region. */
|
|
755
|
-
properties?: Record<string,
|
|
931
|
+
properties?: Record<string, ValueValid>;
|
|
756
932
|
}
|
|
757
933
|
|
|
758
934
|
/**
|
|
@@ -792,9 +968,9 @@ export interface FeatureConfig {
|
|
|
792
968
|
/** Property name to inject on events. */
|
|
793
969
|
property: string;
|
|
794
970
|
/** Possible values for the property. First value is the "before" default if defaultBefore not set. */
|
|
795
|
-
values:
|
|
971
|
+
values: ValueValid[];
|
|
796
972
|
/** Default value before the feature launches. If not set, property doesn't exist before launch. */
|
|
797
|
-
defaultBefore?:
|
|
973
|
+
defaultBefore?: ValueValid;
|
|
798
974
|
/** Which events are affected ("*" for all, or array of event names). */
|
|
799
975
|
affectsEvents?: string[] | "*";
|
|
800
976
|
/** Conversion rate lift for users who adopted the feature. */
|
|
@@ -802,7 +978,7 @@ export interface FeatureConfig {
|
|
|
802
978
|
/** Resolved logistic curve params (set by config-validator). */
|
|
803
979
|
_resolvedCurve?: { k: number; midpoint: number };
|
|
804
980
|
/** Pre-computed adopted values (set by config-validator). */
|
|
805
|
-
_adoptedValues?:
|
|
981
|
+
_adoptedValues?: ValueValid[];
|
|
806
982
|
}
|
|
807
983
|
|
|
808
984
|
/**
|
|
@@ -830,7 +1006,7 @@ export interface AnomalyConfig {
|
|
|
830
1006
|
/** For burst/coordinated: number of events to inject. */
|
|
831
1007
|
count?: number;
|
|
832
1008
|
/** Properties injected on anomalous events. */
|
|
833
|
-
properties?: Record<string,
|
|
1009
|
+
properties?: Record<string, ValueValid>;
|
|
834
1010
|
/** Resolved absolute start time in unix seconds (set by config-validator). */
|
|
835
1011
|
_startUnix?: number;
|
|
836
1012
|
/** Resolved absolute end time in unix seconds (set by config-validator). */
|
|
@@ -869,8 +1045,8 @@ export declare function loadFromFile(filePath: string): Promise<Dungeon>;
|
|
|
869
1045
|
export declare function loadFromText(code: string): Promise<Dungeon>;
|
|
870
1046
|
/** Parse a JSON dungeon (UI schema format) into a runnable config */
|
|
871
1047
|
export declare function parseJSONDungeon(json: object): Dungeon;
|
|
872
|
-
/** Validate that an object has the minimum shape of a dungeon config */
|
|
873
|
-
export declare function validateDungeonShape(config:
|
|
1048
|
+
/** Validate that an object has the minimum shape of a dungeon config. Throws on shape violations. */
|
|
1049
|
+
export declare function validateDungeonShape(config: unknown): void;
|
|
874
1050
|
|
|
875
1051
|
// ============= Text Generator Types =============
|
|
876
1052
|
|
|
@@ -1049,7 +1225,7 @@ export interface TextMetadata {
|
|
|
1049
1225
|
/** Keywords that were injected */
|
|
1050
1226
|
injectedKeywords?: string[];
|
|
1051
1227
|
/** User persona information */
|
|
1052
|
-
persona?: Record<string,
|
|
1228
|
+
persona?: Record<string, ValueValid>;
|
|
1053
1229
|
/** Flesch reading ease score */
|
|
1054
1230
|
readabilityScore?: number;
|
|
1055
1231
|
/** Text style used */
|
|
@@ -1170,13 +1346,14 @@ export interface TimeSoupOptions {
|
|
|
1170
1346
|
}
|
|
1171
1347
|
|
|
1172
1348
|
/**
|
|
1173
|
-
* Test context configuration for unit/integration tests
|
|
1349
|
+
* Test context configuration for unit/integration tests. Looser than `Context`
|
|
1350
|
+
* by design — tests routinely attach ad-hoc fixtures, so the index signature stays.
|
|
1174
1351
|
*/
|
|
1175
1352
|
export interface TestContext {
|
|
1176
1353
|
config: Dungeon;
|
|
1177
1354
|
storage: Storage | null;
|
|
1178
1355
|
defaults: Defaults;
|
|
1179
|
-
campaigns:
|
|
1356
|
+
campaigns: Record<string, ValueValid>[];
|
|
1180
1357
|
runtime: RuntimeState;
|
|
1181
|
-
[key: string]:
|
|
1358
|
+
[key: string]: unknown;
|
|
1182
1359
|
}
|
package/dungeons/user/.gitkeep
DELETED
|
File without changes
|