@ak--47/dungeon-master 1.6.2 → 1.6.4

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.
@@ -37,15 +37,16 @@ export interface Dungeon {
37
37
  /** Properties that change for users or groups over time (Slowly Changing Dimensions). */
38
38
  scdProps?: Record<string, SCDProp>;
39
39
 
40
- /** Defines group entities, like companies or teams, and how many of each to create. */
41
- groupKeys?: [string, number, string[]?][]; // [key, numGroups, optional_events_for_group]
42
-
40
+ /**
41
+ * Defines group entities, like companies or teams, and how many of each to create.
42
+ * Tuple form: `[key, numGroups]` or `[key, numGroups, [events]]`.
43
+ * Named form: `{ key, cardinality, events? }`. Both are accepted.
44
+ */
45
+ groupKeys?: ([string, number, string[]?] | { key: string; cardinality: number; events?: string[] })[];
46
+
43
47
  /** Properties that define the characteristics of the groups defined in groupKeys. */
44
48
  groupProps?: Record<string, Record<string, ValueValid>>;
45
49
 
46
- /** Events that are attributed to a group entity rather than an individual user. */
47
- groupEvents?: GroupEventConfig[];
48
-
49
50
  /** Static data tables (e.g., product catalogs) that can be referenced in events. */
50
51
  lookupTables?: LookupTableSchema[];
51
52
 
@@ -134,25 +135,6 @@ interface SCDProp {
134
135
  }
135
136
 
136
137
 
137
- /**
138
- * Defines an event that is attributed to a group and occurs on a regular schedule.
139
- * (e.g., a monthly subscription charge for a company).
140
- */
141
- interface GroupEventConfig extends EventConfig {
142
- /** How often the event occurs (in days). */
143
- frequency: number;
144
-
145
- /** The group key this event is associated with (e.g., "company_id"). */
146
- group_key: string;
147
-
148
- /** If true, a random user within the group is also associated with the event. */
149
- attribute_to_user: boolean;
150
-
151
- /** The number of entities in this group. */
152
- group_size: number;
153
- }
154
-
155
-
156
138
  /**
157
139
  * Defines the schema for a static lookup table, which can be used to enrich event data.
158
140
  * For example, a "products" table could hold details about product IDs.
@@ -17,7 +17,7 @@ type ValueValid = Primitives | Primitives[] | FunctionCall;
17
17
  * This is the high-level object you will be constructing.
18
18
  *
19
19
  * REQUIRED fields: events, funnels, superProps, userProps
20
- * OPTIONAL fields: scdProps, groupKeys, groupProps, groupEvents
20
+ * OPTIONAL fields: scdProps, groupKeys, groupProps
21
21
  */
22
22
  export interface Dungeon {
23
23
  /** REQUIRED: A list of all possible events that can occur in the simulation. */
@@ -35,14 +35,15 @@ export interface Dungeon {
35
35
  /** OPTIONAL: Properties that change for users or groups over time (Slowly Changing Dimensions). Only include when properties explicitly change over time. */
36
36
  scdProps?: Record<string, SCDProp>;
37
37
 
38
- /** OPTIONAL: Defines group entities (companies, teams). Format: [["group_key", count], ...]. ONLY for B2B/SaaS scenarios. */
39
- groupKeys?: [string, number][];
38
+ /**
39
+ * OPTIONAL: Defines group entities (companies, teams). ONLY for B2B/SaaS scenarios.
40
+ * Tuple form: `[["group_key", count], ...]`.
41
+ * Named form: `[{ key: "group_key", cardinality: count, events: [...] }, ...]`.
42
+ */
43
+ groupKeys?: ([string, number] | { key: string; cardinality: number; events?: string[] })[];
40
44
 
41
45
  /** OPTIONAL: Properties for groups defined in groupKeys. ONLY include if groupKeys is defined. */
42
46
  groupProps?: Record<string, Record<string, ValueValid>>;
43
-
44
- /** OPTIONAL: Events attributed to groups on a schedule (e.g., monthly billing). Rarely needed. */
45
- groupEvents?: GroupEventConfig[];
46
47
  }
47
48
 
48
49
 
@@ -146,28 +147,6 @@ interface SCDProp {
146
147
  }
147
148
 
148
149
 
149
- /**
150
- * Defines an event attributed to a group on a regular schedule.
151
- * Example: monthly subscription charges, weekly reports, etc.
152
- *
153
- * This is rarely needed - only use for B2B scenarios with recurring group-level events.
154
- */
155
- interface GroupEventConfig {
156
- /** REQUIRED: The name of the event. */
157
- event: string;
158
-
159
- /** REQUIRED: How often the event occurs (in days). e.g., 30 for monthly. */
160
- frequency: number;
161
-
162
- /** REQUIRED: The group key this event belongs to (e.g., "company_id"). */
163
- group_key: string;
164
-
165
- /** OPTIONAL: If true, a random user in the group is also attributed to the event. */
166
- attribute_to_user?: boolean;
167
-
168
- /** OPTIONAL: Properties for this event. */
169
- properties?: Record<string, ValueValid>;
170
-
171
- /** OPTIONAL: Relative frequency of this event. */
172
- weight?: number;
173
- }
150
+ // v1.6.4 — `GroupEventConfig` removed. It was a declared-only stub that nothing in
151
+ // `lib/` ever read. To scope an event to a group, list its name in that group key's
152
+ // `events` array instead.
@@ -1649,7 +1649,6 @@ function wrapFunc(obj, func, recursion = 0, parentKey = null, grandParentKey = n
1649
1649
  "userProps",
1650
1650
  "scdProps",
1651
1651
  "mirrorProps",
1652
- "groupEvents",
1653
1652
  "groupProps"
1654
1653
  ]) {
1655
1654
  if (recursion === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ak--47/dungeon-master",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
4
  "description": "generate fancy datasets",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -87,7 +87,7 @@
87
87
  "dotenv": "^16.4.5",
88
88
  "hyparquet-writer": "^0.6.1",
89
89
  "mixpanel": "^0.18.0",
90
- "mixpanel-import": "^3.5.1",
90
+ "mixpanel-import": "^3.6.1",
91
91
  "p-limit": "^3.1.0",
92
92
  "pino": "^9.0.0",
93
93
  "pino-pretty": "^11.0.0",
package/types.d.ts CHANGED
@@ -13,22 +13,56 @@ type Primitives = string | number | boolean | Date | Record<string, any>;
13
13
  export type ValueValid = Primitives | ValueValid[] | (() => ValueValid);
14
14
 
15
15
  /**
16
- * v1.5.1 credentials sub-object. Groups Mixpanel project credentials. Top-level
17
- * `token` / `region` / etc. remain functional as a back-compat alias; when both
18
- * are set, the top-level value wins with a verbose warning.
16
+ * Mixpanel data residency region. Matches the set `mixpanel-import` accepts.
17
+ */
18
+ export type Region = 'US' | 'EU' | 'IN';
19
+
20
+ /**
21
+ * v1.6.4 — named-object form of a group key. Equivalent to the positional tuple
22
+ * `[key, cardinality]` / `[key, cardinality, events]`, which stays supported.
23
+ * The validator normalizes this to the tuple form.
24
+ */
25
+ export interface GroupKeyObject {
26
+ /** The group key property name (e.g. `"company_id"`). */
27
+ key: string;
28
+ /** How many distinct group entities to generate. */
29
+ cardinality: number;
30
+ /** Event names that carry this group key. Omit or leave empty for all events. */
31
+ events?: string[];
32
+ }
33
+
34
+ /**
35
+ * The normalized positional form of a group key. Everything downstream of
36
+ * `validateDungeonConfig` sees this shape — the validator converts
37
+ * `GroupKeyObject` entries for you.
38
+ */
39
+ export type GroupKeyTuple = [string, number] | [string, number, string[]];
40
+
41
+ /**
42
+ * A group analytics key as an author may write it: either the legacy tuple form
43
+ * or the named-object form. `result.validatedConfig.groupKeys` is always
44
+ * `GroupKeyTuple[]`.
45
+ */
46
+ export type GroupKey = GroupKeyTuple | GroupKeyObject;
47
+
48
+ /**
49
+ * v1.5.1 — credentials sub-object. **This is the canonical form.** Groups Mixpanel
50
+ * project credentials. Top-level `token` / `region` / etc. remain functional as a
51
+ * back-compat alias; when both are set, the top-level value wins with a verbose
52
+ * warning. Emit one form or the other, never both.
19
53
  */
20
54
  export interface DungeonCredentials {
21
55
  token?: string;
22
- region?: 'US' | 'EU' | 'IN';
56
+ region?: Region;
23
57
  serviceAccount?: string;
24
58
  serviceSecret?: string;
25
59
  projectId?: string;
26
60
  }
27
61
 
28
62
  /**
29
- * v1.5.1 — switches sub-object. Groups data-shape booleans. Top-level keys
30
- * remain functional as a back-compat alias; same precedence rules as
31
- * `DungeonCredentials`.
63
+ * v1.5.1 — switches sub-object. **This is the canonical form.** Groups data-shape
64
+ * booleans. Top-level keys remain functional as a back-compat alias; same
65
+ * precedence rules as `DungeonCredentials`. Emit one form or the other, never both.
32
66
  */
33
67
  export interface DungeonSwitches {
34
68
  hasLocation?: boolean;
@@ -42,13 +76,13 @@ export interface DungeonSwitches {
42
76
  hasBrowser?: boolean;
43
77
  isAnonymous?: boolean;
44
78
  alsoInferFunnels?: boolean;
45
- hasAttributionFlags?: boolean;
46
79
  }
47
80
 
48
81
  /**
49
- * v1.5.1 — identity sub-object. Groups identity-model knobs. Top-level
50
- * `avgDevicePerUser` / `sessionTimeout` remain functional as a back-compat
51
- * alias.
82
+ * v1.5.1 — identity sub-object. **This is the canonical form.** Groups
83
+ * identity-model knobs. Top-level `avgDevicePerUser` / `sessionTimeout` remain
84
+ * functional as a back-compat alias; when both are set, the top-level value wins
85
+ * with a verbose warning. Emit one form or the other, never both.
52
86
  *
53
87
  * `hasAnonIds` is DEPRECATED — when present here, it maps to
54
88
  * `avgDevicePerUser: 1` with a verbose warning. Use `avgDevicePerUser` instead.
@@ -143,8 +177,8 @@ export interface Dungeon {
143
177
  avgEventsPerUserPerDay?: number;
144
178
  /** Output format for files written to disk. */
145
179
  format?: "csv" | "json" | "parquet" | string;
146
- /** Mixpanel data residency region. */
147
- region?: "US" | "EU";
180
+ /** Mixpanel data residency region. Back-compat alias for `credentials.region`. */
181
+ region?: Region;
148
182
  /** User generation concurrency. Default: 1. Values > 1 break seed reproducibility and provide no performance benefit (CPU-bound). */
149
183
  concurrency?: number;
150
184
  /**
@@ -186,6 +220,12 @@ export interface Dungeon {
186
220
  * @see EventConfig.isAttributionEvent
187
221
  */
188
222
  hasCampaigns?: boolean;
223
+ /**
224
+ * @internal Derived, not settable. The validator unconditionally sets this to
225
+ * `events.some(e => e.isAttributionEvent)`. Read it off `result.validatedConfig`;
226
+ * setting it on an input config has no effect.
227
+ */
228
+ hasAttributionFlags?: boolean;
189
229
  /** If true, generates ad spend data (impressions, clicks, cost). */
190
230
  hasAdSpend?: boolean;
191
231
  /** If true, device pool includes iOS devices. */
@@ -196,7 +236,7 @@ export interface Dungeon {
196
236
  hasDesktopDevices?: boolean;
197
237
  /** If true, events include browser properties. */
198
238
  hasBrowser?: boolean;
199
- /** If true (default), writes output files to ./data/. Can also be a directory path string or gs:// URI. */
239
+ /** If true, writes output files to ./data/. Can also be a directory path string or gs:// URI. Default: `false` — data is returned in memory only. */
200
240
  writeToDisk?: boolean | string;
201
241
  /** If true, deletes all written files (local and GCS) at end of run regardless of import success/failure. Default: false. */
202
242
  cleanup?: boolean;
@@ -289,12 +329,19 @@ export interface Dungeon {
289
329
  scdProps?: Record<string, SCDProp>;
290
330
  /** Mirror dataset definitions: create transformed copies of event data. */
291
331
  mirrorProps?: Record<string, MirrorProps>;
292
- /** Group analytics keys. Format: [key, numGroups] or [key, numGroups, [associatedEvents]]. */
293
- groupKeys?: [string, number][] | [string, number, string[]][];
332
+ /**
333
+ * Group analytics keys. Two interchangeable forms:
334
+ *
335
+ * - Tuple (legacy): `[key, numGroups]` or `[key, numGroups, [associatedEvents]]`
336
+ * - Named object (v1.6.4, preferred): `{ key, cardinality, events? }`
337
+ *
338
+ * The validator normalizes the named form to the tuple form, so hooks and the
339
+ * verifier always see tuples. Mixing both forms in one array is allowed.
340
+ * An empty or omitted `events` list means every event carries the group key.
341
+ */
342
+ groupKeys?: GroupKey[];
294
343
  /** Properties for each group key's entities. */
295
344
  groupProps?: Record<string, Record<string, ValueValid>>;
296
- /** Group-level events (stub — not yet implemented). */
297
- groupEvents?: GroupEventConfig[];
298
345
  /** Lookup table definitions for dimension tables. */
299
346
  lookupTables?: LookupTableSchema[];
300
347
  /** TimeSoup configuration: shapes intra-week and intra-day rhythm (peaks, deviation, DOW/HOD weights). Pair with `macro` for big-picture trend control. */
@@ -370,7 +417,11 @@ export interface Dungeon {
370
417
  * **Incompatibility with `engagementDecay`:** decay drops events from late picked days,
371
418
  * eroding the effective active-day count below the configured target. Use one or the
372
419
  * other; if you need both, write decay logic in an `everything` hook scoped to specific
373
- * cohorts. See HOOKS.md §2.5.
420
+ * cohorts. See HOOKS.md §2.5. v1.6.4: the validator warns unconditionally (not gated
421
+ * behind `verbose`) when both are set.
422
+ *
423
+ * **Precedence with `retentionCurve`:** the curve WINS. When `retentionCurve` is set,
424
+ * the active-day plan is built from the curve and this value is ignored entirely.
374
425
  *
375
426
  * Safe range: `[1, numDays * 0.5]`. Above 50% of `numDays` defeats the concentrator
376
427
  * purpose; the v1.5 validator strict-clamps to `floor(numDays * 0.5)` with a warning.
@@ -928,12 +979,10 @@ export interface EventConfig {
928
979
  isAttributionEvent?: boolean;
929
980
  }
930
981
 
931
- export interface GroupEventConfig extends EventConfig {
932
- frequency: number; //how often the event occurs (in days)
933
- group_key: string; //the key that the group is based on
934
- attribute_to_user: boolean; //if true, the event also goes to a user
935
- group_size: number; //the number of users in the group
936
- }
982
+ // v1.6.4 — `GroupEventConfig` and `Dungeon.groupEvents` were removed from the
983
+ // public types. They were a declared-only stub: nothing in `lib/` ever read them,
984
+ // and no shipped dungeon set them. Group-scoped events are modeled today by
985
+ // listing the event name in a `groupKeys` entry's `events` array.
937
986
 
938
987
  /**
939
988
  * the generated event data