make-mp-data 1.3.4 → 1.4.1

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.
@@ -1,19 +1,58 @@
1
1
  const generate = require('../index.js');
2
2
  const dayjs = require("dayjs");
3
3
  const utc = require("dayjs/plugin/utc");
4
+ const fs = require('fs');
4
5
  const u = require('ak-tools');
5
6
  dayjs.extend(utc);
6
- const { timeSoup } = generate;
7
7
  require('dotenv').config();
8
8
 
9
-
10
-
11
- describe('timeSoup', () => {
12
- test('always positive dates', () => {
9
+ const { applySkew,
10
+ boxMullerRandom,
11
+ choose,
12
+ date,
13
+ dates,
14
+ day,
15
+ exhaust,
16
+ generateEmoji,
17
+ getUniqueKeys,
18
+ integer,
19
+ mapToRange,
20
+ person,
21
+ pick,
22
+ range,
23
+ pickAWinner,
24
+ weightedRange,
25
+ enrichArray,
26
+ fixFirstAndLast,
27
+ generateUser,
28
+ openFinder,
29
+ progress,
30
+ shuffleArray,
31
+ shuffleExceptFirst,
32
+ shuffleExceptLast,
33
+ shuffleMiddle,
34
+ shuffleOutside,
35
+ streamCSV,
36
+ streamJSON,
37
+ weighArray,
38
+ weighFunnels,
39
+ buildFileNames,
40
+ TimeSoup,
41
+ getChance,
42
+ initChance,
43
+ validateEventConfig,
44
+ validateTime,
45
+ interruptArray,
46
+ optimizedBoxMuller
47
+ } = require('../utils');
48
+
49
+
50
+ describe('timesoup', () => {
51
+ test('always valid times', () => {
13
52
  const dates = [];
14
- for (let i = 0; i < 20000; i++) {
15
- const earliest = dayjs().subtract(u.rand(2, 360), 'D');
16
- dates.push(timeSoup());
53
+ for (let i = 0; i < 10000; i++) {
54
+ const earliest = dayjs().subtract(u.rand(5, 50), 'D');
55
+ dates.push(TimeSoup());
17
56
  }
18
57
  const tooOld = dates.filter(d => dayjs(d).isBefore(dayjs.unix(0)));
19
58
  const badYear = dates.filter(d => !d.startsWith('202'));
@@ -24,10 +63,288 @@ describe('timeSoup', () => {
24
63
  });
25
64
 
26
65
 
66
+ describe('names', () => {
67
+
68
+ test('default config', () => {
69
+ const config = { simulationName: 'testSim' };
70
+ const result = buildFileNames(config);
71
+ expect(result.eventFiles).toEqual(['testSim-EVENTS.csv']);
72
+ expect(result.userFiles).toEqual(['testSim-USERS.csv']);
73
+ expect(result.scdFiles).toEqual([]);
74
+ expect(result.groupFiles).toEqual([]);
75
+ expect(result.lookupFiles).toEqual([]);
76
+ expect(result.mirrorFiles).toEqual([]);
77
+ expect(result.folder).toEqual('./');
78
+ });
79
+
80
+ test('json format', () => {
81
+ const config = { simulationName: 'testSim', format: 'json' };
82
+ const result = buildFileNames(config);
83
+ expect(result.eventFiles).toEqual(['testSim-EVENTS.json']);
84
+ expect(result.userFiles).toEqual(['testSim-USERS.json']);
85
+ });
86
+
87
+ test('with scdProps', () => {
88
+ const config = {
89
+ simulationName: 'testSim',
90
+ scdProps: { prop1: {}, prop2: {} }
91
+ };
92
+ const result = buildFileNames(config);
93
+ expect(result.scdFiles).toEqual([
94
+ 'testSim-prop1-SCD.csv',
95
+ 'testSim-prop2-SCD.csv'
96
+ ]);
97
+ });
98
+
99
+ test('with groupKeys', () => {
100
+ const config = {
101
+ simulationName: 'testSim',
102
+ groupKeys: [['group1'], ['group2']]
103
+ };
104
+ const result = buildFileNames(config);
105
+ expect(result.groupFiles).toEqual([
106
+ 'testSim-group1-GROUP.csv',
107
+ 'testSim-group2-GROUP.csv'
108
+ ]);
109
+ });
110
+
111
+ test('with lookupTables', () => {
112
+ const config = {
113
+ simulationName: 'testSim',
114
+ lookupTables: [{ key: 'lookup1' }, { key: 'lookup2' }]
115
+ };
116
+ const result = buildFileNames(config);
117
+ expect(result.lookupFiles).toEqual([
118
+ 'testSim-lookup1-LOOKUP.csv',
119
+ 'testSim-lookup2-LOOKUP.csv'
120
+ ]);
121
+ });
122
+
123
+ test('with mirrorProps', () => {
124
+ const config = {
125
+ simulationName: 'testSim',
126
+ mirrorProps: { prop1: {} }
127
+ };
128
+ const result = buildFileNames(config);
129
+ expect(result.mirrorFiles).toEqual(['testSim-MIRROR.csv']);
130
+ });
131
+
132
+ test('writeToDisk', async () => {
133
+ const config = { simulationName: 'testSim', writeToDisk: true };
134
+ const result = await buildFileNames(config);
135
+ expect(result.folder).toBeDefined();
136
+
137
+ });
138
+
139
+
140
+ test('invalid simName', () => {
141
+ const config = { simulationName: 123 };
142
+ expect(() => buildFileNames(config)).toThrow('simName must be a string');
143
+ });
144
+
145
+
146
+ test('streamJSON: writes to file', async () => {
147
+ const path = 'test.json';
148
+ const data = [{ a: 1, b: 2 }, { a: 3, b: 4 }];
149
+ await streamJSON(path, data);
150
+ const content = fs.readFileSync(path, 'utf8');
151
+ const lines = content.trim().split('\n').map(line => JSON.parse(line));
152
+ expect(lines).toEqual(data);
153
+ fs.unlinkSync(path);
154
+ });
155
+
156
+ test('streamCSV: writes to file', async () => {
157
+ const path = 'test.csv';
158
+ const data = [{ a: 1, b: 2 }, { a: 3, b: 4 }];
159
+ await streamCSV(path, data);
160
+ const content = fs.readFileSync(path, 'utf8');
161
+ const lines = content.trim().split('\n');
162
+ expect(lines.length).toBe(3); // Including header
163
+ fs.unlinkSync(path);
164
+ });
165
+
166
+
167
+ test('generateUser: works', () => {
168
+ const uuid = { guid: jest.fn().mockReturnValue('uuid-123') };
169
+ const numDays = 30;
170
+ const user = generateUser(numDays);
171
+ expect(user).toHaveProperty('distinct_id');
172
+ expect(user).toHaveProperty('name');
173
+ expect(user).toHaveProperty('email');
174
+ expect(user).toHaveProperty('avatar');
175
+ });
176
+
177
+ test('enrichArray: works', () => {
178
+ const arr = [];
179
+ const enrichedArray = enrichArray(arr);
180
+ enrichedArray.hookPush(1);
181
+ enrichedArray.hookPush(2);
182
+ const match = JSON.stringify(enrichedArray) === JSON.stringify([1, 2]);
183
+ expect(match).toEqual(true);
184
+ });
185
+
186
+ });
187
+
188
+
189
+ describe('determinism', () => {
190
+ test('initializes RNG with seed from environment variable', () => {
191
+ process.env.SEED = 'test-seed';
192
+ // @ts-ignore
193
+ initChance();
194
+ const chance = getChance();
195
+ expect(chance).toBeDefined();
196
+ expect(chance.random()).toBeGreaterThanOrEqual(0);
197
+ expect(chance.random()).toBeLessThanOrEqual(1);
198
+
199
+ });
200
+
201
+ test('initializes RNG only once', () => {
202
+ const seed = 'initial-seed';
203
+ initChance(seed);
204
+ const chance1 = getChance();
205
+ initChance('new-seed');
206
+ const chance2 = getChance();
207
+ expect(chance1).toBe(chance2);
208
+
209
+ });
210
+ });
211
+
212
+
213
+ describe('generation', () => {
214
+ test('users: can make', () => {
215
+ const numDays = 30;
216
+ const user = generateUser('uuid-123', numDays);
217
+ expect(user).toHaveProperty('distinct_id');
218
+ expect(user).toHaveProperty('name');
219
+ expect(user).toHaveProperty('email');
220
+ expect(user).toHaveProperty('avatar');
221
+ expect(user).toHaveProperty('created');
222
+ expect(user).toHaveProperty('anonymousIds');
223
+ expect(user).toHaveProperty('sessionIds');
224
+ });
225
+
226
+ test('user: in time range', () => {
227
+ const numDays = 30;
228
+ const user = generateUser('uuid-123', numDays);
229
+ const createdDate = dayjs(user.created, 'YYYY-MM-DD');
230
+ expect(createdDate.isValid()).toBeTruthy();
231
+ expect(createdDate.isBefore(dayjs.unix(global.NOW))).toBeTruthy();
232
+ });
233
+ });
234
+
235
+ describe('validation', () => {
236
+
237
+ beforeAll(() => {
238
+ global.NOW = 1672531200; // fixed point in time for testing
239
+ });
240
+
241
+ test('events: throws non array', () => {
242
+ // @ts-ignore
243
+ expect(() => validateEventConfig("not an array")).toThrow("events must be an array");
244
+ });
245
+
246
+ test('events: strings', () => {
247
+ const events = ["event1", "event2"];
248
+ const result = validateEventConfig(events);
249
+
250
+ expect(result).toEqual([
251
+ { event: "event1", isFirstEvent: false, properties: {}, weight: expect.any(Number) },
252
+ { event: "event2", isFirstEvent: false, properties: {}, weight: expect.any(Number) },
253
+ ]);
254
+
255
+ result.forEach(event => {
256
+ expect(event.weight).toBeGreaterThanOrEqual(1);
257
+ expect(event.weight).toBeLessThanOrEqual(5);
258
+ });
259
+ });
260
+
261
+ test('events: objects', () => {
262
+ const events = [{ event: "event1", properties: { a: 1 } }, { event: "event2", properties: { b: 2 } }];
263
+ const result = validateEventConfig(events);
264
+
265
+ expect(result).toEqual(events);
266
+ });
267
+
268
+ test('events: mix', () => {
269
+ const events = ["event1", { event: "event2", properties: { b: 2 } }];
270
+ // @ts-ignore
271
+ const result = validateEventConfig(events);
272
+
273
+ expect(result).toEqual([
274
+ { event: "event1", isFirstEvent: false, properties: {}, weight: expect.any(Number) },
275
+ { event: "event2", properties: { b: 2 } }
276
+ ]);
277
+
278
+ expect(result[0].weight).toBeGreaterThanOrEqual(1);
279
+ expect(result[0].weight).toBeLessThanOrEqual(5);
280
+ });
281
+
282
+ test('dates: between', () => {
283
+ const chosenTime = global.NOW - (60 * 60 * 24 * 15); // 15 days ago
284
+ const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
285
+ const latestTime = global.NOW;
286
+ expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(true);
287
+ });
288
+
289
+ test('dates: outside earliest', () => {
290
+ const chosenTime = global.NOW - (60 * 60 * 24 * 31); // 31 days ago
291
+ const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
292
+ const latestTime = global.NOW;
293
+ expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(false);
294
+ });
295
+
296
+ test('dates: outside latest', () => {
297
+ const chosenTime = -1;
298
+ const earliestTime = global.NOW - (60 * 60 * 24 * 30); // 30 days ago
299
+ const latestTime = global.NOW;
300
+ expect(validateTime(chosenTime, earliestTime, latestTime)).toBe(false);
301
+ });
302
+
303
+ test('dates: inference in', () => {
304
+ const chosenTime = global.NOW - (60 * 60 * 24 * 15); // 15 days ago
305
+ expect(validateTime(chosenTime)).toBe(true);
306
+ });
307
+
308
+ test('dates: inference out', () => {
309
+ const chosenTime = global.NOW - (60 * 60 * 24 * 31); // 31 days ago
310
+ expect(validateTime(chosenTime)).toBe(false);
311
+ });
312
+ });
313
+
314
+ describe('enrichment', () => {
315
+ test('hook works', () => {
316
+ const arr = [];
317
+ const hook = (item) => item * 2;
318
+ const enrichedArray = enrichArray(arr, { hook });
319
+ enrichedArray.hookPush(1);
320
+ enrichedArray.hookPush(2);
321
+ expect(enrichedArray.includes(2)).toBeTruthy();
322
+ expect(enrichedArray.includes(4)).toBeTruthy();
323
+ });
324
+
325
+ test('filter empties', () => {
326
+ const arr = [];
327
+ const hook = (item) => item ? item.toString() : item;
328
+ const enrichedArray = enrichArray(arr, { hook });
329
+ enrichedArray.hookPush(null);
330
+ enrichedArray.hookPush(undefined);
331
+ enrichedArray.hookPush({});
332
+ enrichedArray.hookPush({ a: 1 });
333
+ enrichedArray.hookPush([1, 2]);
334
+ expect(enrichedArray).toHaveLength(3);
335
+ expect(enrichedArray.includes('null')).toBeFalsy();
336
+ expect(enrichedArray.includes('undefined')).toBeFalsy();
337
+ expect(enrichedArray.includes('[object Object]')).toBeTruthy();
338
+ expect(enrichedArray.includes('1')).toBeTruthy();
339
+ expect(enrichedArray.includes('2')).toBeTruthy();
340
+
341
+ });
342
+
343
+
344
+ });
27
345
 
28
- const { applySkew, boxMullerRandom, choose, date, dates, day, exhaust, generateEmoji, getUniqueKeys, integer, mapToRange, person, pick, range, weighList, weightedRange } = require('../utils');
29
346
 
30
- describe('utils', () => {
347
+ describe('utilities', () => {
31
348
 
32
349
  test('pick: works', () => {
33
350
  const array = [1, 2, 3];
@@ -58,9 +375,9 @@ describe('utils', () => {
58
375
 
59
376
  test('person: fields', () => {
60
377
  const generatedPerson = person();
61
- expect(generatedPerson).toHaveProperty('$name');
62
- expect(generatedPerson).toHaveProperty('$email');
63
- expect(generatedPerson).toHaveProperty('$avatar');
378
+ expect(generatedPerson).toHaveProperty('name');
379
+ expect(generatedPerson).toHaveProperty('email');
380
+ expect(generatedPerson).toHaveProperty('avatar');
64
381
  });
65
382
 
66
383
 
@@ -73,7 +390,7 @@ describe('utils', () => {
73
390
  test('date: future', () => {
74
391
  const futureDate = date(10, false, 'YYYY-MM-DD')();
75
392
  expect(dayjs(futureDate, 'YYYY-MM-DD').isValid()).toBeTruthy();
76
- expect(dayjs(futureDate).isAfter(dayjs())).toBeTruthy();
393
+ expect(dayjs(futureDate).isAfter(dayjs.unix(global.NOW))).toBeTruthy();
77
394
  });
78
395
 
79
396
  test('dates: pairs', () => {
@@ -107,15 +424,15 @@ describe('utils', () => {
107
424
  });
108
425
 
109
426
  test('weightedRange: within range', () => {
110
- const values = weightedRange(5, 15, 100);
427
+ const values = weightedRange(5, 15);
111
428
  expect(values.every(v => v >= 5 && v <= 15)).toBe(true);
112
- expect(values.length).toBe(100);
429
+ expect(values.length).toBe(50);
113
430
  });
114
431
 
115
432
  test('applySkew: skews', () => {
116
433
  const value = boxMullerRandom();
117
434
  const skewedValue = applySkew(value, .25);
118
- expect(Math.abs(skewedValue)).toBeGreaterThanOrEqual(Math.abs(value));
435
+ expect(Math.abs(skewedValue)).toBeLessThanOrEqual(Math.abs(value));
119
436
  });
120
437
 
121
438
  test('mapToRange: works', () => {
@@ -146,6 +463,19 @@ describe('utils', () => {
146
463
  });
147
464
 
148
465
 
466
+ test('times', () => {
467
+ const dates = [];
468
+ for (let i = 0; i < 10000; i++) {
469
+ const earliest = dayjs().subtract(u.rand(5, 50), 'D');
470
+ dates.push(TimeSoup());
471
+ }
472
+ const tooOld = dates.filter(d => dayjs(d).isBefore(dayjs.unix(0)));
473
+ const badYear = dates.filter(d => !d.startsWith('202'));
474
+ expect(dates.every(d => dayjs(d).isAfter(dayjs.unix(0)))).toBe(true);
475
+ expect(dates.every(d => d.startsWith('202'))).toBe(true);
476
+
477
+ });
478
+
149
479
  test('date', () => {
150
480
  const result = date();
151
481
  expect(dayjs(result()).isValid()).toBe(true);
@@ -206,4 +536,101 @@ describe('utils', () => {
206
536
  });
207
537
 
208
538
 
539
+ test('weighArray: works', () => {
540
+ const arr = ['a', 'b', 'c'];
541
+ const weightedArr = weighArray(arr);
542
+ expect(weightedArr.length).toBeGreaterThanOrEqual(arr.length);
543
+ });
544
+
545
+ test('weighFunnels: works', () => {
546
+ const acc = [];
547
+ const funnel = { weight: 3 };
548
+ const result = weighFunnels(acc, funnel);
549
+ expect(result.length).toBe(3);
550
+ });
551
+
552
+ test('progress: outputs correctly', () => {
553
+ // @ts-ignore
554
+ const mockStdoutWrite = jest.spyOn(process.stdout, 'write').mockImplementation(() => { });
555
+ progress('test', 50);
556
+ expect(mockStdoutWrite).toHaveBeenCalled();
557
+ mockStdoutWrite.mockRestore();
558
+ });
559
+
560
+ test('range: works', () => {
561
+ const result = [];
562
+ range.call(result, 1, 5);
563
+ expect(result).toEqual([1, 2, 3, 4, 5]);
564
+ });
565
+
566
+
567
+
568
+ test('shuffleArray: works', () => {
569
+ const arr = [1, 2, 3, 4, 5];
570
+ const shuffled = shuffleArray([...arr]);
571
+ expect(shuffled).not.toEqual(arr);
572
+ expect(shuffled.sort()).toEqual(arr.sort());
573
+ });
574
+
575
+ test('shuffleExceptFirst: works', () => {
576
+ const arr = [1, 2, 3, 4, 5];
577
+ const shuffled = shuffleExceptFirst([...arr]);
578
+ expect(shuffled[0]).toBe(arr[0]);
579
+ expect(shuffled.slice(1).sort()).toEqual(arr.slice(1).sort());
580
+ });
581
+
582
+ test('shuffleExceptLast: works', () => {
583
+ const arr = [1, 2, 3, 4, 5];
584
+ const shuffled = shuffleExceptLast([...arr]);
585
+ expect(shuffled[shuffled.length - 1]).toBe(arr[arr.length - 1]);
586
+ expect(shuffled.slice(0, -1).sort()).toEqual(arr.slice(0, -1).sort());
587
+ });
588
+
589
+ test('fixFirstAndLast: works', () => {
590
+ const arr = [1, 2, 3, 4, 5];
591
+ const shuffled = fixFirstAndLast([...arr]);
592
+ expect(shuffled[0]).toBe(arr[0]);
593
+ expect(shuffled[shuffled.length - 1]).toBe(arr[arr.length - 1]);
594
+ expect(shuffled.slice(1, -1).sort()).toEqual(arr.slice(1, -1).sort());
595
+ });
596
+
597
+ test('shuffleMiddle: works', () => {
598
+ const arr = [1, 2, 3, 4, 5];
599
+ const shuffled = shuffleMiddle([...arr]);
600
+ expect(shuffled[0]).toBe(arr[0]);
601
+ expect(shuffled[shuffled.length - 1]).toBe(arr[arr.length - 1]);
602
+ expect(shuffled.slice(1, -1).sort()).toEqual(arr.slice(1, -1).sort());
603
+ });
604
+
605
+ test('shuffleOutside: works', () => {
606
+ const arr = [1, 2, 3, 4, 5];
607
+ const shuffled = shuffleOutside([...arr]);
608
+ expect(shuffled.slice(1, -1)).toEqual(arr.slice(1, -1));
609
+ });
610
+
611
+ test('box normal distribution', () => {
612
+ const values = [];
613
+ for (let i = 0; i < 10000; i++) {
614
+ values.push(boxMullerRandom());
615
+ }
616
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
617
+ const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
618
+ const stdDev = Math.sqrt(variance);
619
+ expect(mean).toBeCloseTo(0, 1);
620
+ expect(stdDev).toBeCloseTo(1, 1);
621
+ });
622
+
623
+ test('optimized box normal distribution', () => {
624
+ const values = [];
625
+ for (let i = 0; i < 10000; i++) {
626
+ values.push(optimizedBoxMuller());
627
+ }
628
+ const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
629
+ const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
630
+ const stdDev = Math.sqrt(variance);
631
+ expect(mean).toBeCloseTo(0, 1);
632
+ expect(stdDev).toBeCloseTo(1, 1);
633
+ });
634
+
635
+
209
636
  });
package/tmp/.gitkeep ADDED
File without changes
package/tsconfig.json CHANGED
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "include": [
13
13
  "**/*.js"
14
- ],
14
+ , "soupTemplates.mjs", "testSoup.mjs", "testCases.mjs" ],
15
15
  "exclude": [
16
16
  "node_modules"
17
17
  ]
package/types.d.ts CHANGED
@@ -9,16 +9,20 @@ declare namespace main {
9
9
  token?: string;
10
10
  seed?: string;
11
11
  numDays?: number;
12
+ epochStart?: number;
13
+ epochEnd?: number;
12
14
  numEvents?: number;
13
15
  numUsers?: number;
14
16
  format?: "csv" | "json";
15
17
  region?: "US" | "EU";
16
- events?: EventConfig[];
18
+ chance?: any;
19
+ events?: EventConfig[]; //can also be a array of strings
17
20
  superProps?: Record<string, ValueValid>;
21
+ funnels?: Funnel[];
18
22
  userProps?: Record<string, ValueValid>;
19
23
  scdProps?: Record<string, ValueValid>;
20
24
  mirrorProps?: Record<string, MirrorProps>;
21
- groupKeys?: [string, number][] | [string, number, string[]][];
25
+ groupKeys?: [string, number][] | [string, number, string[]][]; // [key, numGroups, [events]]
22
26
  groupProps?: Record<string, Record<string, ValueValid>>;
23
27
  lookupTables?: LookupTable[];
24
28
  writeToDisk?: boolean;
@@ -26,19 +30,37 @@ declare namespace main {
26
30
  verbose?: boolean;
27
31
  anonIds?: boolean;
28
32
  sessionIds?: boolean;
33
+ makeChart?: boolean | string;
34
+ soup?: soup;
29
35
  hook?: Hook<any>;
30
36
  }
31
37
 
32
- export type Hook<T> = (record: any, type: string, meta: any) => T;
38
+ type soup = {
39
+ deviation?: number;
40
+ peaks?: number;
41
+ mean?: number;
42
+ };
43
+
44
+ type hookTypes =
45
+ | "event"
46
+ | "user"
47
+ | "group"
48
+ | "lookup"
49
+ | "scd"
50
+ | "mirror"
51
+ | "funnel-pre"
52
+ | "funnel-post"
53
+ | "";
54
+ export type Hook<T> = (record: any, type: hookTypes, meta: any) => T;
33
55
 
34
56
  export interface EnrichArrayOptions<T> {
35
57
  hook?: Hook<T>;
36
- type?: string;
58
+ type?: hookTypes;
37
59
  [key: string]: any;
38
60
  }
39
61
 
40
62
  export interface EnrichedArray<T> extends Array<T> {
41
- hPush: (item: T) => number;
63
+ hookPush: (item: T) => boolean;
42
64
  }
43
65
 
44
66
  export interface EventConfig {
@@ -46,6 +68,40 @@ declare namespace main {
46
68
  weight?: number;
47
69
  properties?: Record<string, ValueValid>;
48
70
  isFirstEvent?: boolean;
71
+ relativeTimeMs?: number;
72
+ }
73
+
74
+ export interface EventSpec {
75
+ event: string;
76
+ time: string;
77
+ insert_id: string;
78
+ device_id?: string;
79
+ session_id?: string;
80
+ user_id?: string;
81
+ [key: string]: ValueValid;
82
+ }
83
+
84
+ export interface Funnel {
85
+ sequence: string[];
86
+ weight?: number;
87
+ isFirstFunnel?: boolean;
88
+ /**
89
+ * If true, the funnel will require the user to repeat the sequence of events in order to convert
90
+ * If false, the user does not need to repeat the sequence of events in order to convert
91
+ * ^ when false, users who repeat the repetitive steps are more likely to convert
92
+ */
93
+ requireRepeats?: boolean;
94
+ order?:
95
+ | "sequential"
96
+ | "first-fixed"
97
+ | "last-fixed"
98
+ | "random"
99
+ | "first-and-last-fixed"
100
+ | "middle-fixed"
101
+ | "interrupted";
102
+ conversionRate?: number;
103
+ timeToConvert?: number;
104
+ props?: Record<string, ValueValid>;
49
105
  }
50
106
 
51
107
  export interface MirrorProps {
@@ -59,7 +115,7 @@ declare namespace main {
59
115
  attributes: Record<string, ValueValid>;
60
116
  }
61
117
 
62
- export interface SCDTable {
118
+ export interface SCDTableRow {
63
119
  distinct_id: string;
64
120
  insertTime: string;
65
121
  startTime: string;
@@ -72,17 +128,17 @@ declare namespace main {
72
128
  scdTableData: any[];
73
129
  groupProfilesData: GroupProfilesData[];
74
130
  lookupTableData: LookupTableData[];
75
- import?: ImportResults;
131
+ importResults?: ImportResults;
76
132
  files?: string[];
77
133
  };
78
134
 
79
135
  export interface EventData {
80
136
  event: string;
81
- $source: string;
137
+ source: string;
82
138
  time: string;
83
- $device_id?: string;
84
- $session_id?: string;
85
- $user_id?: string;
139
+ device_id?: string;
140
+ session_id?: string;
141
+ user_id?: string;
86
142
  [key: string]: any;
87
143
  }
88
144
 
@@ -107,12 +163,22 @@ declare namespace main {
107
163
  bytes: number;
108
164
  }
109
165
  export interface Person {
110
- $name: string;
111
- $email: string;
112
- $avatar: string;
113
- $created: string | undefined;
166
+ name: string;
167
+ email: string;
168
+ avatar: string;
169
+ created: string | undefined;
114
170
  anonymousIds: string[];
115
171
  sessionIds: string[];
172
+ distinct_id?: string;
173
+ }
174
+
175
+ export interface UserProfile {
176
+ name?: string;
177
+ email?: string;
178
+ avatar?: string;
179
+ created: string | undefined;
180
+ distinct_id: string;
181
+ [key: string]: ValueValid;
116
182
  }
117
183
  }
118
184