@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.
Files changed (66) hide show
  1. package/README.md +518 -0
  2. package/dungeons/array-of-object-lookup-schema.json +327 -0
  3. package/dungeons/array-of-object-lookup.js +220 -0
  4. package/dungeons/ecommerce-schema.json +462 -0
  5. package/dungeons/ecommerce.js +447 -0
  6. package/dungeons/education-schema.json +2409 -0
  7. package/dungeons/education.js +768 -0
  8. package/dungeons/fintech-schema.json +14034 -0
  9. package/dungeons/fintech.js +696 -0
  10. package/dungeons/foobar-schema.json +403 -0
  11. package/dungeons/foobar.js +296 -0
  12. package/dungeons/food-delivery-schema.json +192 -0
  13. package/dungeons/food-delivery.js +602 -0
  14. package/dungeons/food-schema.json +1152 -0
  15. package/dungeons/food.js +754 -0
  16. package/dungeons/gaming-schema.json +1270 -0
  17. package/dungeons/gaming.js +508 -0
  18. package/dungeons/insurance-application-schema.json +204 -0
  19. package/dungeons/insurance-application.js +605 -0
  20. package/dungeons/media-schema.json +906 -0
  21. package/dungeons/media.js +790 -0
  22. package/dungeons/retention-cadence-schema.json +78 -0
  23. package/dungeons/retention-cadence.js +244 -0
  24. package/dungeons/rpg-schema.json +4526 -0
  25. package/dungeons/rpg.js +919 -0
  26. package/dungeons/sanity-schema.json +255 -0
  27. package/dungeons/sanity.js +152 -0
  28. package/dungeons/sass-schema.json +1291 -0
  29. package/dungeons/sass.js +795 -0
  30. package/dungeons/scd-schema.json +919 -0
  31. package/dungeons/scd.js +277 -0
  32. package/dungeons/simple-schema.json +608 -0
  33. package/dungeons/simple.js +285 -0
  34. package/dungeons/simplest-schema.json +1418 -0
  35. package/dungeons/simplest.js +392 -0
  36. package/dungeons/social-schema.json +1118 -0
  37. package/dungeons/social.js +686 -0
  38. package/dungeons/text-generation-schema.json +3096 -0
  39. package/dungeons/text-generation.js +812 -0
  40. package/index.js +567 -0
  41. package/lib/core/config-validator.js +395 -0
  42. package/lib/core/context.js +204 -0
  43. package/lib/core/dungeon-loader.js +337 -0
  44. package/lib/core/storage.js +379 -0
  45. package/lib/generators/adspend.js +132 -0
  46. package/lib/generators/events.js +271 -0
  47. package/lib/generators/funnels.js +407 -0
  48. package/lib/generators/mirror.js +167 -0
  49. package/lib/generators/product-lookup.js +262 -0
  50. package/lib/generators/product-names.js +195 -0
  51. package/lib/generators/profiles.js +93 -0
  52. package/lib/generators/scd.js +124 -0
  53. package/lib/generators/text.js +1192 -0
  54. package/lib/orchestrators/mixpanel-sender.js +266 -0
  55. package/lib/orchestrators/user-loop.js +335 -0
  56. package/lib/templates/abbreviated.d.ts +169 -0
  57. package/lib/templates/defaults.js +1405 -0
  58. package/lib/templates/phrases.js +2526 -0
  59. package/lib/templates/schema.d.ts +173 -0
  60. package/lib/templates/soup-presets.js +188 -0
  61. package/lib/utils/function-registry.js +302 -0
  62. package/lib/utils/json-evaluator.js +172 -0
  63. package/lib/utils/logger.js +34 -0
  64. package/lib/utils/utils.js +1490 -0
  65. package/package.json +89 -0
  66. package/types.d.ts +865 -0
package/types.d.ts ADDED
@@ -0,0 +1,865 @@
1
+ /**
2
+ * most of the time, the value of a property is a primitive
3
+ */
4
+ type Primitives = string | number | boolean | Date | Record<string, any>;
5
+
6
+ /**
7
+ * a "validValue" can be a primitive, an array of primitives, or a function that returns a primitive
8
+ */
9
+ export type ValueValid = Primitives | ValueValid[] | (() => ValueValid);
10
+
11
+ /**
12
+ * main config object for the entire data generation
13
+ */
14
+ export interface Dungeon {
15
+ // ── Core Parameters ──
16
+ /** Mixpanel project token. If provided, data will be imported to Mixpanel after generation. */
17
+ token?: string;
18
+ /** RNG seed for reproducible output. Same seed + concurrency=1 = identical data. */
19
+ seed?: string;
20
+ /** Number of days the dataset spans (from "now" looking backward). Default: 30 */
21
+ numDays?: number;
22
+ /** Explicit start of dataset window (unix seconds). Alternative to numDays. */
23
+ epochStart?: number;
24
+ /** Explicit end of dataset window (unix seconds). Defaults to FIXED_NOW. */
25
+ epochEnd?: number;
26
+ /** Target total number of events to generate across all users. */
27
+ numEvents?: number;
28
+ /** Number of unique users to generate. */
29
+ numUsers?: number;
30
+ /** Output format for files written to disk. */
31
+ format?: "csv" | "json" | "parquet" | string;
32
+ /** Mixpanel data residency region. */
33
+ region?: "US" | "EU";
34
+ /** User generation concurrency. Default: 1. Values > 1 break seed reproducibility and provide no performance benefit (CPU-bound). */
35
+ concurrency?: number;
36
+ /** Number of records before auto-flushing to disk. Prevents OOM for large datasets. Default: 1,000,000 */
37
+ batchSize?: number;
38
+
39
+ // ── Mixpanel Import Credentials (for SCD import) ──
40
+ serviceAccount?: string;
41
+ serviceSecret?: string;
42
+ projectId?: string;
43
+
44
+ // ── Identifiers ──
45
+ /** Dataset name prefix for output files. Auto-generated if not set. */
46
+ name?: string;
47
+
48
+ // ── Feature Switches ──
49
+ /** If true, users have no distinct_id (anonymous-only tracking). */
50
+ isAnonymous?: boolean;
51
+ /** If true, user profiles include avatar URLs. */
52
+ hasAvatar?: boolean;
53
+ /** If true, events include geo properties (city, region, country, lat/lng). */
54
+ hasLocation?: boolean;
55
+ /** If true, events include UTM campaign properties. */
56
+ hasCampaigns?: boolean;
57
+ /** If true, generates ad spend data (impressions, clicks, cost). */
58
+ hasAdSpend?: boolean;
59
+ /** If true, device pool includes iOS devices. */
60
+ hasIOSDevices?: boolean;
61
+ /** If true, device pool includes Android devices. */
62
+ hasAndroidDevices?: boolean;
63
+ /** If true, device pool includes desktop devices. */
64
+ hasDesktopDevices?: boolean;
65
+ /** If true, events include browser properties. */
66
+ hasBrowser?: boolean;
67
+ /** If true (default), writes output files to ./data/. Can also be a directory path string. */
68
+ writeToDisk?: boolean | string;
69
+ /** If true, gzip-compresses output files. */
70
+ gzip?: boolean;
71
+ /** If true, prints progress to stdout during generation. */
72
+ verbose?: boolean;
73
+ /** If true, users get anonymous device IDs in addition to distinct_id. */
74
+ hasAnonIds?: boolean;
75
+ /** If true, users get session IDs attached to events. */
76
+ hasSessionIds?: boolean;
77
+ /** If true, auto-generates funnels from the events array in addition to any explicit funnels. */
78
+ alsoInferFunnels?: boolean;
79
+ /** Restrict all location data to a single country (e.g., "US", "GB"). */
80
+ singleCountry?: string;
81
+ /** If true, stops generation at exactly numEvents (forces concurrency=1). Without this, event count is approximate. */
82
+ strictEventCount?: boolean;
83
+ /** Internal flag for UI-triggered jobs (affects SCD credential handling). */
84
+ isUIJob?: boolean;
85
+
86
+ // ── Data Models ──
87
+ /** Event definitions: names, weights, properties, and behavioral flags. */
88
+ events?: EventConfig[];
89
+ /** Properties that appear on EVERY event (e.g., platform, app_version). */
90
+ superProps?: Record<string, ValueValid>;
91
+ /** Funnel definitions: conversion sequences, rates, ordering strategies. */
92
+ funnels?: Funnel[];
93
+ /** User profile properties set once per user. */
94
+ userProps?: Record<string, ValueValid>;
95
+ /** Slowly Changing Dimension properties: time-series mutations of user/group attributes. */
96
+ scdProps?: Record<string, SCDProp>;
97
+ /** Mirror dataset definitions: create transformed copies of event data. */
98
+ mirrorProps?: Record<string, MirrorProps>;
99
+ /** Group analytics keys. Format: [key, numGroups] or [key, numGroups, [associatedEvents]]. */
100
+ groupKeys?: [string, number][] | [string, number, string[]][];
101
+ /** Properties for each group key's entities. */
102
+ groupProps?: Record<string, Record<string, ValueValid>>;
103
+ /** Group-level events (stub — not yet implemented). */
104
+ groupEvents?: GroupEventConfig[];
105
+ /** Lookup table definitions for dimension tables. */
106
+ lookupTables?: LookupTableSchema[];
107
+ /** TimeSoup configuration: controls the temporal distribution of events (peaks, deviation, mean). */
108
+ soup?: soup;
109
+ /** Hook function called on every data point. The primary mechanism for engineering deliberate trends and patterns. */
110
+ hook?: Hook<any>;
111
+
112
+ /** Allow arbitrary additional properties on the config. */
113
+ [key: string]: any;
114
+
115
+ // ── Distribution Controls ──
116
+ /** Percentage of users whose account creation falls within the dataset window (vs. pre-existing). Default: 15 */
117
+ percentUsersBornInDataset?: number;
118
+ /** Bias toward recent birth dates for users born in dataset (0 = uniform, 1 = heavily recent). Default: 0.3 */
119
+ bornRecentBias?: number;
120
+ }
121
+
122
+ export type SCDProp = {
123
+ /** Entity type this SCD applies to. "user" for user profiles; use a group key (e.g., "company_id") for group SCDs. Default: "user" */
124
+ type?: string | "user" | "company_id" | "team_id" | "department_id";
125
+ /** How often the property mutates. Default: "day" */
126
+ frequency?: "day" | "week" | "month" | "year";
127
+ /** Array of possible values, or a function that returns values. */
128
+ values: ValueValid;
129
+ /** "fixed" = mutations at clean boundaries (start of day/week/month/year). "fuzzy" = mutations at any time. Default: "fuzzy" */
130
+ timing?: "fixed" | "fuzzy";
131
+ /** Maximum number of mutations per entity. Default: 10 */
132
+ max?: number;
133
+ };
134
+
135
+ /**
136
+ * Soup preset names for common time distribution patterns
137
+ */
138
+ export type SoupPreset = "steady" | "growth" | "spiky" | "seasonal" | "global" | "churny" | "chaotic";
139
+
140
+ /**
141
+ * Soup configuration object for fine-grained control
142
+ */
143
+ export type SoupConfig = {
144
+ /** Use a named preset as base, then override individual fields */
145
+ preset?: SoupPreset;
146
+ /** Controls clustering tightness. Higher = tighter peaks. Default: 2 */
147
+ deviation?: number;
148
+ /** Number of time clusters to distribute events across. Default: numDays*2 */
149
+ peaks?: number;
150
+ /** Offset for the normal distribution center within each peak. Default: 0 */
151
+ mean?: number;
152
+ /** Day-of-week weights (7 elements, index 0=Sunday). Normalized max=1.0. Set null to disable. */
153
+ dayOfWeekWeights?: number[] | null;
154
+ /** Hour-of-day weights (24 elements, index 0=midnight UTC). Normalized max=1.0. Set null to disable. */
155
+ hourOfDayWeights?: number[] | null;
156
+ };
157
+
158
+ /**
159
+ * the soup is a set of parameters that determine the distribution of events over time.
160
+ * Can be a preset name string, a config object, or a config object with a preset base.
161
+ */
162
+ type soup = SoupPreset | SoupConfig;
163
+
164
+ /**
165
+ * Hook types and when they fire (in order per user):
166
+ * - "user" — user profile object (mutate in-place, return ignored)
167
+ * - "scd-pre" — array of SCD entries (mutate in-place OR return new array to replace)
168
+ * - "funnel-pre" — funnel config object (mutate conversionRate, timeToConvert, etc. in-place)
169
+ * - "event" — single event with FLAT properties (return value replaces event)
170
+ * - "funnel-post" — array of generated funnel events (mutate in-place, splice to inject)
171
+ * - "everything" — array of ALL events for one user (return array to replace; meta.profile available)
172
+ *
173
+ * Storage-only hooks (fire during hookPush, not in generators):
174
+ * - "ad-spend", "group", "mirror", "lookup"
175
+ */
176
+ export type hookTypes =
177
+ | "event"
178
+ | "user"
179
+ | "group"
180
+ | "lookup"
181
+ | "scd"
182
+ | "scd-pre"
183
+ | "mirror"
184
+ | "funnel-pre"
185
+ | "funnel-post"
186
+ | "ad-spend"
187
+ | "churn"
188
+ | "group-event"
189
+ | "everything"
190
+ | "";
191
+
192
+ /**
193
+ * A hook function that receives every piece of data as it flows through the pipeline.
194
+ * @param record - The data being processed (event, profile, array of events, etc.)
195
+ * @param type - Which hook type is firing
196
+ * @param meta - Contextual metadata (varies by type; "everything" includes meta.profile and meta.scd)
197
+ */
198
+ export type Hook<T> = (record: any, type: hookTypes, meta: any) => T;
199
+
200
+ export interface hookArrayOptions<T> {
201
+ hook?: Hook<T>;
202
+ type?: hookTypes;
203
+ filename?: string;
204
+ format?: "csv" | "json" | "parquet" | string;
205
+ concurrency?: number;
206
+ context?: Context;
207
+ [key: string]: any;
208
+ }
209
+
210
+ /**
211
+ * an enriched array is an array that has a hookPush method that can be used to transform-then-push items into the array
212
+ */
213
+ export interface HookedArray<T> extends Array<T> {
214
+ hookPush: (item: T | T[], ...meta: any[]) => any;
215
+ flush: () => void;
216
+ getWriteDir: () => string;
217
+ getWritePath: () => string;
218
+ [key: string]: any;
219
+ }
220
+
221
+ export type AllData =
222
+ | HookedArray<EventSchema>
223
+ | HookedArray<UserProfile>
224
+ | HookedArray<GroupProfileSchema>
225
+ | HookedArray<LookupTableSchema>
226
+ | HookedArray<SCDSchema>
227
+ | any[];
228
+
229
+ /**
230
+ * the storage object is a key-value store that holds arrays of data
231
+ */
232
+ export interface Storage {
233
+ eventData?: HookedArray<EventSchema>;
234
+ mirrorEventData?: HookedArray<EventSchema>;
235
+ userProfilesData?: HookedArray<UserProfile>;
236
+ adSpendData?: HookedArray<EventSchema>;
237
+ groupProfilesData?: HookedArray<GroupProfileSchema>[];
238
+ lookupTableData?: HookedArray<LookupTableSchema>[];
239
+ scdTableData?: HookedArray<SCDSchema>[];
240
+ groupEventData?: HookedArray<EventSchema>;
241
+ }
242
+
243
+ /**
244
+ * Runtime state for tracking execution metrics and flags
245
+ */
246
+ export interface RuntimeState {
247
+ operations: number;
248
+ eventCount: number;
249
+ userCount: number;
250
+ isBatchMode: boolean;
251
+ verbose: boolean;
252
+ }
253
+
254
+ /**
255
+ * Default data factories for generating realistic test data
256
+ */
257
+ export interface Defaults {
258
+ locationsUsers: () => any[];
259
+ locationsEvents: () => any[];
260
+ iOSDevices: () => any[];
261
+ androidDevices: () => any[];
262
+ desktopDevices: () => any[];
263
+ browsers: () => any[];
264
+ campaigns: () => any[];
265
+ devicePools: { android: any[]; ios: any[]; desktop: any[] };
266
+ allDevices:any[];
267
+ }
268
+
269
+ /**
270
+ * Context object that replaces global variables with dependency injection
271
+ * Contains validated config, storage containers, defaults, and runtime state
272
+ */
273
+ export interface Context {
274
+ config: Dungeon;
275
+ storage: Storage | null;
276
+ defaults: Defaults;
277
+ campaigns: any[];
278
+ runtime: RuntimeState;
279
+ FIXED_NOW: number;
280
+ FIXED_BEGIN?: number;
281
+ TIME_SHIFT_SECONDS: number;
282
+ MAX_TIME: number;
283
+
284
+ // State update methods
285
+ incrementOperations(): void;
286
+ incrementEvents(): void;
287
+ incrementUsers(): void;
288
+ setStorage(storage: Storage): void;
289
+
290
+ // State getter methods
291
+ getOperations(): number;
292
+ getEventCount(): number;
293
+ getUserCount(): number;
294
+ incrementUserCount(): void;
295
+ incrementEventCount(): void;
296
+ isBatchMode(): boolean;
297
+
298
+ // Time helper methods
299
+ getTimeShift(): number;
300
+ getDaysShift(): number;
301
+ }
302
+
303
+ /**
304
+ * how we define events and their properties
305
+ */
306
+ export interface EventConfig {
307
+ /** The event name (e.g., "page viewed", "purchase completed"). */
308
+ event?: string;
309
+ /** Relative frequency weight (1-10). Higher = more likely to be selected. Used for both standalone event selection and funnel sequence building. Default: 1 */
310
+ weight?: number;
311
+ /** Properties to attach to this event type. Values can be arrays (random pick), functions, or primitives. */
312
+ properties?: Record<string, ValueValid>;
313
+ /** If true, this is the user's first-ever event (e.g., "sign up"). Used to create onboarding funnels. */
314
+ isFirstEvent?: boolean;
315
+ /** If true, generating this event signals the user has churned. The user stops producing further events unless returnLikelihood allows them to come back. */
316
+ isChurnEvent?: boolean;
317
+ /** Probability (0-1) that a churned user returns and continues generating events. 0 = permanent churn, 1 = always returns. Only used when isChurnEvent is true. Default: 0 */
318
+ returnLikelihood?: number;
319
+ /** If true, this event is automatically prepended 15 seconds before each funnel sequence (e.g., "$session_started"). */
320
+ isSessionStartEvent?: boolean;
321
+ /** Internal: timing offset in milliseconds (set by funnel system, not user-configured). */
322
+ relativeTimeMs?: number;
323
+ /** If true, this event is excluded from auto-generated funnels (inferFunnels and catch-all). Use for system events that shouldn't appear in conversion sequences. */
324
+ isStrictEvent?: boolean;
325
+ }
326
+
327
+ export interface GroupEventConfig extends EventConfig {
328
+ frequency: number; //how often the event occurs (in days)
329
+ group_key: string; //the key that the group is based on
330
+ attribute_to_user: boolean; //if true, the event also goes to a user
331
+ group_size: number; //the number of users in the group
332
+ }
333
+
334
+ /**
335
+ * the generated event data
336
+ */
337
+ export interface EventSchema {
338
+ event: string;
339
+ time: string;
340
+ source: string;
341
+ insert_id: string;
342
+ device_id?: string;
343
+ session_id?: string;
344
+ user_id?: string;
345
+ [key: string]: ValueValid;
346
+ }
347
+
348
+ /**
349
+ * how we define funnels and their properties
350
+ */
351
+ export interface Funnel {
352
+ /**
353
+ * the name of the funnel
354
+ */
355
+ name?: string;
356
+ /**
357
+ * the description of the funnel
358
+ */
359
+ description?: string;
360
+ /**
361
+ * the sequence of events that define the funnel
362
+ */
363
+ sequence: string[];
364
+ /**
365
+ * how likely the funnel is to be selected
366
+ */
367
+ weight?: number;
368
+ /**
369
+ * If true, the funnel will be the first thing the user does
370
+ */
371
+ isFirstFunnel?: boolean;
372
+ /**
373
+ * If true, the funnel will require the user to repeat the sequence of events in order to convert
374
+ * If false, the user does not need to repeat the sequence of events in order to convert
375
+ * ^ when false, users who repeat the repetitive steps are more likely to convert
376
+ */
377
+ requireRepeats?: boolean;
378
+ /**
379
+ * how the events in the funnel are ordered for each user
380
+ */
381
+ order?:
382
+ | "sequential"
383
+ | "first-fixed"
384
+ | "last-fixed"
385
+ | "random" //totally shuffled
386
+ | "first-and-last-fixed"
387
+ | "middle-fixed"
388
+ | "interrupted"
389
+ | string;
390
+
391
+ /**
392
+ * the likelihood that a user will convert (0-100%)
393
+ */
394
+ conversionRate?: number;
395
+ /**
396
+ * the time it takes (on average) to convert in hours
397
+ */
398
+ timeToConvert?: number;
399
+ /**
400
+ * funnel properties go onto each event in the funnel and are held constant
401
+ */
402
+ props?: Record<string, ValueValid>;
403
+ /**
404
+ * funnel conditions (user properties) are used to filter users who are eligible for the funnel
405
+ * these conditions must match the current user's profile for the user to be eligible for the funnel
406
+ */
407
+ conditions?: Record<string, ValueValid>;
408
+ /**
409
+ * If true, the funnel will be part of an experiment where we generate 3 variants of the funnel with different conversion rates
410
+ *
411
+ */
412
+ experiment?: boolean;
413
+ /**
414
+ * optional: if set, in sequential funnels, this will determine WHEN the property is bound to the rest of the events in the funnel
415
+ */
416
+ bindPropsIndex?: number;
417
+ }
418
+
419
+ /**
420
+ * mirror props are used to show mutations of event data over time
421
+ * there are different strategies for how to mutate the data
422
+ */
423
+ export interface MirrorProps {
424
+ /**
425
+ * the event that will be mutated in the new version
426
+ */
427
+ events?: string[] | "*";
428
+ /**
429
+ * "create" - create this key in the new version; value are chosen
430
+ * "update" - update this key in the new version; values are chosen
431
+ * "fill" - update this key in the new version, but only if the existing key is null or unset
432
+ * "delete" - delete this key in the new version; values are ignored
433
+ */
434
+ strategy?: "create" | "update" | "fill" | "delete" | "";
435
+ values?: ValueValid[];
436
+ /**
437
+ * optional: for 'fill' mode, daysUnfilled will dictate where the cutoff is in the unfilled data
438
+ */
439
+ daysUnfilled?: number;
440
+ }
441
+
442
+ export interface UserProfile {
443
+ name?: string;
444
+ email?: string;
445
+ avatar?: string;
446
+ created: string | undefined;
447
+ distinct_id: string;
448
+ [key: string]: ValueValid;
449
+ }
450
+
451
+ export interface Person {
452
+ name: string;
453
+ email?: string;
454
+ avatar?: string;
455
+ created: string | undefined;
456
+ anonymousIds: string[];
457
+ sessionIds: string[];
458
+ distinct_id?: string;
459
+ }
460
+
461
+ /**
462
+ * the generated user data
463
+ */
464
+ export interface LookupTableSchema {
465
+ key: string;
466
+ entries: number;
467
+ attributes: Record<string, ValueValid>;
468
+ }
469
+
470
+ export interface LookupTableData {
471
+ key: string;
472
+ data: any[];
473
+ }
474
+
475
+ export interface SCDSchema {
476
+ distinct_id: string;
477
+ insertTime: string;
478
+ startTime: string;
479
+ [key: string]: ValueValid;
480
+ }
481
+
482
+ export interface GroupProfileSchema {
483
+ key: string;
484
+ data: any[];
485
+ }
486
+
487
+ /**
488
+ * the end result of importing data into mixpanel
489
+ */
490
+ export interface ImportResults {
491
+ events: ImportResult;
492
+ users: ImportResult;
493
+ groups: ImportResult[];
494
+ }
495
+ type ImportResult = import("mixpanel-import").ImportResults;
496
+
497
+ /**
498
+ * the end result of the data generation
499
+ */
500
+ export type Result = {
501
+ eventData: EventSchema[];
502
+ mirrorEventData: EventSchema[];
503
+ userProfilesData: any[];
504
+ scdTableData: any[][];
505
+ adSpendData: EventSchema[];
506
+ groupProfilesData: GroupProfileSchema[][];
507
+ lookupTableData: LookupTableData[][];
508
+ importResults?: ImportResults;
509
+ files?: string[];
510
+ time?: {
511
+ start: number;
512
+ end: number;
513
+ delta: number;
514
+ human: string;
515
+ };
516
+ operations?: number;
517
+ eventCount?: number;
518
+ userCount?: number;
519
+ groupCount?: number;
520
+ avgEPS?: number;
521
+ };
522
+
523
+ /**
524
+ * dungeon-master: generate realistic Mixpanel data at scale
525
+ *
526
+ * accepts multiple input formats:
527
+ * - config object: `DUNGEON_MASTER({ numUsers: 100, events: [...] })`
528
+ * - file path (.js/.mjs): `DUNGEON_MASTER('./dungeons/simple.js')`
529
+ * - file path (.json): `DUNGEON_MASTER('./dungeons/simple-schema.json')`
530
+ * - array of file paths: `DUNGEON_MASTER(['./dungeons/a.js', './dungeons/b.js'])`
531
+ * - raw JS string: `DUNGEON_MASTER('export default { numUsers: 50, ... }')`
532
+ *
533
+ * @example
534
+ * import DUNGEON_MASTER from '@ak--47/dungeon-master';
535
+ * const data = await DUNGEON_MASTER({ numUsers: 100, numEvents: 10_000, numDays: 30 });
536
+ *
537
+ * @example
538
+ * const data = await DUNGEON_MASTER('./dungeons/simple.js', { writeToDisk: true });
539
+ *
540
+ * @example
541
+ * const results = await DUNGEON_MASTER(['./dungeons/gaming.js', './dungeons/media.js']);
542
+ */
543
+ declare function DUNGEON_MASTER(input: Dungeon, overrides?: Partial<Dungeon>): Promise<Result>;
544
+ declare function DUNGEON_MASTER(input: string, overrides?: Partial<Dungeon>): Promise<Result>;
545
+ declare function DUNGEON_MASTER(input: string[], overrides?: Partial<Dungeon>): Promise<Result[]>;
546
+
547
+ export default DUNGEON_MASTER;
548
+
549
+ /** Load and validate a dungeon from a file path */
550
+ export declare function loadFromFile(filePath: string): Promise<Dungeon>;
551
+ /** Load and validate a dungeon from raw JavaScript text */
552
+ export declare function loadFromText(code: string): Promise<Dungeon>;
553
+ /** Parse a JSON dungeon (UI schema format) into a runnable config */
554
+ export declare function parseJSONDungeon(json: object): Dungeon;
555
+ /** Validate that an object has the minimum shape of a dungeon config */
556
+ export declare function validateDungeonShape(config: any): void;
557
+
558
+ // ============= Text Generator Types =============
559
+
560
+ /**
561
+ * Sentiment tone of generated text
562
+ */
563
+ export type TextTone = "pos" | "neg" | "neu";
564
+
565
+ /**
566
+ * Style of text generation
567
+ *
568
+ * Supported styles:
569
+ * - "support": Customer support tickets and requests
570
+ * - "review": Product reviews and ratings
571
+ * - "search": Search queries and keywords
572
+ * - "feedback": User feedback and suggestions
573
+ * - "chat": Casual chat messages and conversations
574
+ * - "email": Formal email communications
575
+ * - "forum": Forum posts and discussions
576
+ * - "comments": Social media comments and reactions
577
+ * - "tweet": Twitter-style social media posts
578
+ */
579
+ export type TextStyle = "support" | "review" | "search" | "feedback" | "chat" | "email" | "forum" | "comments" | "tweet";
580
+
581
+ /**
582
+ * Emotional intensity level
583
+ */
584
+ export type TextIntensity = "low" | "medium" | "high";
585
+
586
+ /**
587
+ * Language formality level
588
+ */
589
+ export type TextFormality = "casual" | "business" | "technical";
590
+
591
+ /**
592
+ * Output format for batch generation
593
+ */
594
+ export type TextReturnType = "strings" | "objects";
595
+
596
+ /**
597
+ * Domain-specific keywords to inject into generated text
598
+ *
599
+ * Common predefined categories include:
600
+ * - features: Product features to mention
601
+ * - products: Product/company names
602
+ * - competitors: Competitor names for comparisons
603
+ * - technical: Technical terms and jargon
604
+ * - versions: Version numbers and releases
605
+ * - errors: Specific error messages or codes
606
+ * - metrics: Business metrics or KPIs
607
+ * - events: Event types (e.g., 'wedding', 'celebration', 'conference')
608
+ * - emotions: Emotional descriptors (e.g., 'inspiring', 'heartwarming')
609
+ * - issues: Common problems or issues
610
+ * - team: Team or role references
611
+ * - business_impact: Business impact phrases
612
+ * - comparisons: Comparison phrases
613
+ * - credibility: Credibility markers
614
+ * - user_actions: User action descriptions
615
+ * - specific_praise: Specific positive details
616
+ * - specific_issues: Specific negative details
617
+ * - error_messages: Error message text
618
+ * - categories: General categories
619
+ * - brands: Brand names
620
+ * - vendors: Vendor references
621
+ * - services: Service types
622
+ * - locations: Location references
623
+ *
624
+ * Custom categories can be added as needed.
625
+ */
626
+ export interface TextKeywordSet {
627
+ /** Product features to mention */
628
+ features?: string[];
629
+ /** Product/company names */
630
+ products?: string[];
631
+ /** Competitor names for comparisons */
632
+ competitors?: string[];
633
+ /** Technical terms and jargon */
634
+ technical?: string[];
635
+ /** Version numbers and releases */
636
+ versions?: string[];
637
+ /** Specific error messages or codes */
638
+ errors?: string[];
639
+ /** Business metrics or KPIs */
640
+ metrics?: string[];
641
+ /** Event types (e.g., 'wedding', 'celebration', 'conference') */
642
+ events?: string[];
643
+ /** Emotional descriptors (e.g., 'inspiring', 'heartwarming') */
644
+ emotions?: string[];
645
+ /** Common problems or issues */
646
+ issues?: string[];
647
+ /** Team or role references */
648
+ team?: string[];
649
+ /** Business impact phrases */
650
+ business_impact?: string[];
651
+ /** Comparison phrases */
652
+ comparisons?: string[];
653
+ /** Credibility markers */
654
+ credibility?: string[];
655
+ /** User action descriptions */
656
+ user_actions?: string[];
657
+ /** Specific positive details */
658
+ specific_praise?: string[];
659
+ /** Specific negative details */
660
+ specific_issues?: string[];
661
+ /** Error message text */
662
+ error_messages?: string[];
663
+ /** General categories */
664
+ categories?: string[];
665
+ /** Brand names */
666
+ brands?: string[];
667
+ /** Vendor references */
668
+ vendors?: string[];
669
+ /** Service types */
670
+ services?: string[];
671
+ /** Location references */
672
+ locations?: string[];
673
+ /** Allow any custom keyword category */
674
+ [key: string]: string[] | undefined;
675
+ }
676
+
677
+ /**
678
+ * Configuration for text generator instance
679
+ */
680
+ export interface TextGeneratorConfig {
681
+ /** Default sentiment tone */
682
+ tone?: TextTone;
683
+ /** Type of text to generate */
684
+ style?: TextStyle;
685
+ /** Emotional intensity */
686
+ intensity?: TextIntensity;
687
+ /** Language formality */
688
+ formality?: TextFormality;
689
+ /** Minimum text length in characters */
690
+ min?: number;
691
+ /** Maximum text length in characters */
692
+ max?: number;
693
+ /** RNG seed for reproducibility */
694
+ seed?: string;
695
+ /** Domain-specific keywords to inject */
696
+ keywords?: TextKeywordSet;
697
+ /** Probability of keyword injection (0-1) */
698
+ keywordDensity?: number;
699
+ /** Enable realistic typos */
700
+ typos?: boolean;
701
+ /** Base typo probability per word */
702
+ typoRate?: number;
703
+ /** Allow sentiment mixing for realism */
704
+ mixedSentiment?: boolean;
705
+ /** Amount of authentic markers (0-1) */
706
+ authenticityLevel?: number;
707
+ /** Add timestamps to some messages */
708
+ timestamps?: boolean;
709
+ /** Include user role/experience markers */
710
+ userPersona?: boolean;
711
+ /** Allow sentiment to drift during generation (0-1) */
712
+ sentimentDrift?: number;
713
+ /** Add metadata to generated text */
714
+ includeMetadata?: boolean;
715
+ /** How specific/detailed to make claims (0-1) */
716
+ specificityLevel?: number;
717
+ /** Filter near-duplicates */
718
+ enableDeduplication?: boolean;
719
+ /** Max generation attempts per item */
720
+ maxAttempts?: number;
721
+ // performanceMode removed - system is always optimized for speed + uniqueness
722
+ }
723
+
724
+ /**
725
+ * Metadata for generated text
726
+ */
727
+ export interface TextMetadata {
728
+ /** Timestamp if enabled */
729
+ timestamp?: string;
730
+ /** Sentiment analysis score */
731
+ sentimentScore?: number;
732
+ /** Keywords that were injected */
733
+ injectedKeywords?: string[];
734
+ /** User persona information */
735
+ persona?: Record<string, any>;
736
+ /** Flesch reading ease score */
737
+ readabilityScore?: number;
738
+ /** Text style used */
739
+ style?: TextStyle | string;
740
+ /** Intensity level used */
741
+ intensity?: TextIntensity | string;
742
+ /** Formality level used */
743
+ formality?: TextFormality | string;
744
+ }
745
+
746
+ /**
747
+ * Simple generated text object (without metadata)
748
+ */
749
+ export interface SimpleGeneratedText {
750
+ /** The generated text */
751
+ text: string;
752
+ /** Actual tone of generated text */
753
+ tone: TextTone | string;
754
+ }
755
+
756
+ /**
757
+ * Generated text with metadata
758
+ */
759
+ export interface GeneratedText {
760
+ /** The generated text */
761
+ text: string;
762
+ /** Actual tone of generated text */
763
+ tone: TextTone | string;
764
+ /** Additional metadata */
765
+ metadata?: TextMetadata;
766
+ }
767
+
768
+ /**
769
+ * Options for batch text generation
770
+ */
771
+ export interface TextBatchOptions {
772
+ /** Number of items to generate */
773
+ n: number;
774
+ /** Output format */
775
+ returnType?: TextReturnType;
776
+ /** Override tone for this batch */
777
+ tone?: TextTone;
778
+ /** Generate related/coherent items */
779
+ related?: boolean;
780
+ /** Shared context/topic for related items */
781
+ sharedContext?: string;
782
+ }
783
+
784
+ /**
785
+ * Statistics for text generator performance
786
+ */
787
+ export interface TextGeneratorStats {
788
+ /** Configuration used */
789
+ config: TextGeneratorConfig;
790
+ /** Total items generated */
791
+ generatedCount: number;
792
+ /** Items that were duplicates */
793
+ duplicateCount: number;
794
+ /** Items that failed generation */
795
+ failedCount: number;
796
+ /** Average generation time per item */
797
+ avgGenerationTime: number;
798
+ /** Total generation time */
799
+ totalGenerationTime: number;
800
+ }
801
+
802
+ /**
803
+ * Text generator instance interface
804
+ */
805
+ export interface TextGenerator {
806
+ /** Generate a single text item */
807
+ generateOne(): string | GeneratedText | null;
808
+ /** Generate multiple text items in batch */
809
+ generateBatch(options: TextBatchOptions): (string | GeneratedText | SimpleGeneratedText)[];
810
+ /** Get generation statistics */
811
+ getStats(): TextGeneratorStats;
812
+ }
813
+
814
+ /**
815
+ * Creates a new text generator instance
816
+ * @param config - Configuration options for the generator
817
+ * @returns Text generator instance
818
+ */
819
+ export declare function createTextGenerator(config?: TextGeneratorConfig): TextGenerator;
820
+
821
+ /**
822
+ * Generate a batch of text items directly (standalone function)
823
+ * @param options - Combined generator config and batch options
824
+ * @returns Array of generated text items
825
+ */
826
+ export declare function generateBatch(options: TextGeneratorConfig & TextBatchOptions): (string | GeneratedText | SimpleGeneratedText)[];
827
+
828
+ // ============= Additional Utility Types =============
829
+
830
+ /**
831
+ * File path configuration for data generation output
832
+ */
833
+ export interface WritePaths {
834
+ eventFiles: string[];
835
+ userFiles: string[];
836
+ adSpendFiles: string[];
837
+ scdFiles: string[];
838
+ mirrorFiles: string[];
839
+ groupFiles: string[];
840
+ lookupFiles: string[];
841
+ folder: string;
842
+ }
843
+
844
+ /**
845
+ * Configuration for TimeSoup time distribution function
846
+ */
847
+ export interface TimeSoupOptions {
848
+ earliestTime?: number;
849
+ latestTime?: number;
850
+ peaks?: number;
851
+ deviation?: number;
852
+ mean?: number;
853
+ }
854
+
855
+ /**
856
+ * Test context configuration for unit/integration tests
857
+ */
858
+ export interface TestContext {
859
+ config: Dungeon;
860
+ storage: Storage | null;
861
+ defaults: Defaults;
862
+ campaigns: any[];
863
+ runtime: RuntimeState;
864
+ [key: string]: any;
865
+ }