make-mp-data 2.0.19 → 2.0.22
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/dungeons/big.js +7 -6
- package/dungeons/business.js +21 -3
- package/dungeons/experiments.js +8 -7
- package/dungeons/media.js +7 -7
- package/dungeons/sanity.js +8 -14
- package/dungeons/simple.js +1 -0
- package/dungeons/student-teacher.js +426 -0
- package/dungeons/userAgent.js +7 -7
- package/entry.js +19 -3
- package/index.js +107 -7
- package/lib/cli/cli.js +8 -0
- package/lib/core/config-validator.js +244 -218
- package/lib/core/context.js +31 -16
- package/lib/core/storage.js +61 -27
- package/lib/generators/events.js +41 -18
- package/lib/orchestrators/mixpanel-sender.js +5 -2
- package/lib/orchestrators/user-loop.js +212 -181
- package/lib/orchestrators/worker-manager.js +5 -2
- package/lib/templates/abbreviated.d.ts +159 -0
- package/lib/{data → templates}/defaults.js +2 -2
- package/lib/templates/instructions.txt +78 -0
- package/lib/templates/scratch-dungeon-template.js +116 -0
- package/lib/templates/verbose-schema.js +338 -0
- package/lib/utils/ai.js +42 -64
- package/lib/utils/chart.js +5 -0
- package/lib/utils/utils.js +116 -55
- package/package.json +9 -10
- package/types.d.ts +138 -125
- package/lib/cloud-function.js +0 -20
- /package/lib/{utils/prompt.txt → templates/prompt (old).txt} +0 -0
package/lib/utils/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import Chance from 'chance';
|
|
3
3
|
import readline from 'readline';
|
|
4
|
-
import { comma, uid} from 'ak-tools';
|
|
4
|
+
import { comma, uid } from 'ak-tools';
|
|
5
5
|
import { spawn } from 'child_process';
|
|
6
6
|
import dayjs from 'dayjs';
|
|
7
7
|
import utc from 'dayjs/plugin/utc.js';
|
|
@@ -10,7 +10,8 @@ import { mkdir, parseGCSUri } from 'ak-tools';
|
|
|
10
10
|
import { existsSync } from 'fs';
|
|
11
11
|
dayjs.extend(utc);
|
|
12
12
|
import 'dotenv/config';
|
|
13
|
-
import { domainSuffix, domainPrefix } from '../
|
|
13
|
+
import { domainSuffix, domainPrefix } from '../templates/defaults.js';
|
|
14
|
+
const {NODE_ENV = "unknown"} = process.env;
|
|
14
15
|
|
|
15
16
|
/** @typedef {import('../../types').Dungeon} Config */
|
|
16
17
|
/** @typedef {import('../../types').EventConfig} EventConfig */
|
|
@@ -186,6 +187,27 @@ function day(start, end) {
|
|
|
186
187
|
function choose(value) {
|
|
187
188
|
const chance = getChance();
|
|
188
189
|
|
|
190
|
+
// most of the time this will receive a list of strings;
|
|
191
|
+
// when that is the case, we need to ensure some 'keywords' like 'variant' or 'test' aren't in the array
|
|
192
|
+
// next we want to see if the array is unweighted ... i.e. no dupe strings and each string only occurs once ['a', 'b', 'c', 'd']
|
|
193
|
+
// if all these are true we will pickAWinner(value)()
|
|
194
|
+
if (Array.isArray(value) && value.length > 2 && value.length < 20 && value.every(item => typeof item === 'string')) {
|
|
195
|
+
// ensure terms 'variant' 'group' 'experiment' or 'population' are NOT in any of the items
|
|
196
|
+
if (!value.some(item => item.includes('variant') || item.includes('group') || item.includes('experiment') || item.includes('population'))) {
|
|
197
|
+
// check to make sure that each element in the array only occurs once...
|
|
198
|
+
const uniqueItems = new Set(value);
|
|
199
|
+
if (uniqueItems.size === value.length) {
|
|
200
|
+
// Array has no duplicates, use pickAWinner
|
|
201
|
+
const quickList = pickAWinner(value, 0)();
|
|
202
|
+
const theChosenOne = chance.pickone(quickList);
|
|
203
|
+
return theChosenOne;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
189
211
|
try {
|
|
190
212
|
// Keep resolving the value if it's a function (with caching)
|
|
191
213
|
while (typeof value === 'function') {
|
|
@@ -218,13 +240,12 @@ function choose(value) {
|
|
|
218
240
|
return chance.pickone(value);
|
|
219
241
|
}
|
|
220
242
|
|
|
221
|
-
//
|
|
222
|
-
if (Array.isArray(value) && value.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
return chance.pickone(value);
|
|
243
|
+
// PERFORMANCE: Optimized array handling - check first item type instead of every()
|
|
244
|
+
if (Array.isArray(value) && value.length > 0) {
|
|
245
|
+
const firstType = typeof value[0];
|
|
246
|
+
if (firstType === 'string' || firstType === 'number') {
|
|
247
|
+
return chance.pickone(value);
|
|
248
|
+
}
|
|
228
249
|
}
|
|
229
250
|
|
|
230
251
|
if (Array.isArray(value) && value.every(item => typeof item === 'object')) {
|
|
@@ -331,7 +352,10 @@ function integer(min = 1, max = 100) {
|
|
|
331
352
|
};
|
|
332
353
|
|
|
333
354
|
|
|
334
|
-
|
|
355
|
+
function decimal(min = 0, max = 1, fixed = 2) {
|
|
356
|
+
const chance = getChance();
|
|
357
|
+
return chance.floating({ min, max, fixed });
|
|
358
|
+
}
|
|
335
359
|
|
|
336
360
|
|
|
337
361
|
/*
|
|
@@ -522,13 +546,7 @@ WEIGHERS
|
|
|
522
546
|
----
|
|
523
547
|
*/
|
|
524
548
|
|
|
525
|
-
|
|
526
|
-
const weight = funnel?.weight || 1;
|
|
527
|
-
for (let i = 0; i < weight; i++) {
|
|
528
|
-
acc.push(funnel);
|
|
529
|
-
}
|
|
530
|
-
return acc;
|
|
531
|
-
}
|
|
549
|
+
|
|
532
550
|
|
|
533
551
|
/**
|
|
534
552
|
* a utility function to generate a range of numbers within a given skew
|
|
@@ -684,18 +702,18 @@ function pickAWinner(items, mostChosenIndex) {
|
|
|
684
702
|
}
|
|
685
703
|
|
|
686
704
|
function quickHash(str, seed = 0) {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
705
|
+
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
|
706
|
+
for (let i = 0, ch; i < str.length; i++) {
|
|
707
|
+
ch = str.charCodeAt(i);
|
|
708
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
709
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
710
|
+
}
|
|
711
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
|
|
712
|
+
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
713
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
|
|
714
|
+
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
715
|
+
|
|
716
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString();
|
|
699
717
|
};
|
|
700
718
|
|
|
701
719
|
/*
|
|
@@ -717,10 +735,10 @@ function shuffleArray(array) {
|
|
|
717
735
|
}
|
|
718
736
|
|
|
719
737
|
function pickRandom(array) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
738
|
+
if (!array || array.length === 0) return undefined;
|
|
739
|
+
// PERFORMANCE: Use Math.random() instead of chance.integer() for simple cases
|
|
740
|
+
const randomIndex = Math.floor(Math.random() * array.length);
|
|
741
|
+
return array[randomIndex];
|
|
724
742
|
}
|
|
725
743
|
|
|
726
744
|
function shuffleExceptFirst(array) {
|
|
@@ -918,25 +936,25 @@ function buildFileNames(config) {
|
|
|
918
936
|
* @param {[string, number][]} arrayOfArrays
|
|
919
937
|
*/
|
|
920
938
|
function progress(arrayOfArrays) {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
939
|
+
const terminalWidth = process.stdout.columns || 120;
|
|
940
|
+
|
|
941
|
+
// Clear the entire line
|
|
942
|
+
readline.cursorTo(process.stdout, 0);
|
|
943
|
+
readline.clearLine(process.stdout, 0);
|
|
944
|
+
|
|
945
|
+
// Build message with better formatting
|
|
946
|
+
const items = arrayOfArrays.map(([thing, p]) => {
|
|
947
|
+
return `${thing}: ${comma(p)}`;
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
const message = items.join(' │ ');
|
|
951
|
+
|
|
952
|
+
// Ensure we don't exceed terminal width
|
|
953
|
+
const finalMessage = message.length > terminalWidth
|
|
954
|
+
? message.substring(0, terminalWidth - 3) + '...'
|
|
955
|
+
: message.padEnd(terminalWidth, ' ');
|
|
956
|
+
|
|
957
|
+
process.stdout.write(finalMessage);
|
|
940
958
|
}
|
|
941
959
|
|
|
942
960
|
function openFinder(path, callback) {
|
|
@@ -997,6 +1015,46 @@ let soupHits = 0;
|
|
|
997
1015
|
* @param {number} [peaks=5]
|
|
998
1016
|
*/
|
|
999
1017
|
function TimeSoup(earliestTime, latestTime, peaks = 5, deviation = 2, mean = 0) {
|
|
1018
|
+
if (!earliestTime) earliestTime = global.FIXED_BEGIN ? global.FIXED_BEGIN : dayjs().subtract(30, 'd').unix(); // 30 days ago
|
|
1019
|
+
if (!latestTime) latestTime = global.FIXED_NOW ? global.FIXED_NOW : dayjs().unix();
|
|
1020
|
+
const chance = getChance();
|
|
1021
|
+
const totalRange = latestTime - earliestTime;
|
|
1022
|
+
const chunkSize = totalRange / peaks;
|
|
1023
|
+
|
|
1024
|
+
// Select a random chunk based on the number of peaks
|
|
1025
|
+
const peakIndex = integer(0, peaks - 1);
|
|
1026
|
+
const chunkStart = earliestTime + peakIndex * chunkSize;
|
|
1027
|
+
const chunkEnd = chunkStart + chunkSize;
|
|
1028
|
+
const chunkMid = (chunkStart + chunkEnd) / 2;
|
|
1029
|
+
|
|
1030
|
+
// Generate a single timestamp within this chunk using a normal distribution centered at chunkMid
|
|
1031
|
+
let offset;
|
|
1032
|
+
let iterations = 0;
|
|
1033
|
+
let isValidTime = false;
|
|
1034
|
+
do {
|
|
1035
|
+
iterations++;
|
|
1036
|
+
soupHits++;
|
|
1037
|
+
offset = chance.normal({ mean: mean, dev: chunkSize / deviation });
|
|
1038
|
+
isValidTime = validTime(chunkMid + offset, earliestTime, latestTime);
|
|
1039
|
+
if (iterations > 25000) {
|
|
1040
|
+
throw `${iterations} iterations... exceeded`;
|
|
1041
|
+
}
|
|
1042
|
+
} while (chunkMid + offset < chunkStart || chunkMid + offset > chunkEnd);
|
|
1043
|
+
|
|
1044
|
+
try {
|
|
1045
|
+
return dayjs.unix(chunkMid + offset).toISOString();
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
catch (e) {
|
|
1049
|
+
//escape hatch
|
|
1050
|
+
// console.log('BAD TIME', e?.message);
|
|
1051
|
+
if (NODE_ENV === 'dev') debugger;
|
|
1052
|
+
return dayjs.unix(integer(earliestTime, latestTime)).toISOString();
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
function NewTimeSoup(earliestTime, latestTime, peaks = 5, deviation = 2, mean = 0) {
|
|
1000
1058
|
if (!earliestTime) earliestTime = global.FIXED_BEGIN ? global.FIXED_BEGIN : dayjs().subtract(30, 'd').unix(); // 30 days ago
|
|
1001
1059
|
if (!latestTime) latestTime = global.FIXED_NOW ? global.FIXED_NOW : dayjs().unix();
|
|
1002
1060
|
const chance = getChance();
|
|
@@ -1176,7 +1234,10 @@ function wrapFunc(obj, func, recursion = 0, parentKey = null, grandParentKey = n
|
|
|
1176
1234
|
|
|
1177
1235
|
// }
|
|
1178
1236
|
|
|
1179
|
-
|
|
1237
|
+
const chance = getChance();
|
|
1238
|
+
function odds(num) {
|
|
1239
|
+
return chance.bool({ likelihood: num });
|
|
1240
|
+
}
|
|
1180
1241
|
|
|
1181
1242
|
/**
|
|
1182
1243
|
* makes a random-sized array of emojis
|
|
@@ -1271,7 +1332,8 @@ export {
|
|
|
1271
1332
|
deepClone,
|
|
1272
1333
|
initChance,
|
|
1273
1334
|
getChance,
|
|
1274
|
-
|
|
1335
|
+
decimal,
|
|
1336
|
+
odds,
|
|
1275
1337
|
validTime,
|
|
1276
1338
|
validEvent,
|
|
1277
1339
|
|
|
@@ -1287,7 +1349,6 @@ export {
|
|
|
1287
1349
|
pickAWinner,
|
|
1288
1350
|
quickHash,
|
|
1289
1351
|
weighArray,
|
|
1290
|
-
weighFunnels,
|
|
1291
1352
|
validateEventConfig,
|
|
1292
1353
|
shuffleArray,
|
|
1293
1354
|
shuffleExceptFirst,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "make-mp-data",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.22",
|
|
4
4
|
"description": "builds all mixpanel primitives for a given project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"README.md"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
+
"new:dungeon": "node ./scripts/create-dungeon.mjs",
|
|
19
20
|
"start": "node ./index.js",
|
|
20
21
|
"dev": "nodemon scratch.mjs --ignore ./data/*",
|
|
21
22
|
"prune": "rm -f ./data/* && rm -f ./tmp/* && rm -f vscode-profile-*",
|
|
@@ -24,10 +25,9 @@
|
|
|
24
25
|
"test": "NODE_ENV=test vitest run",
|
|
25
26
|
"coverage": "vitest run --coverage && open ./coverage/index.html",
|
|
26
27
|
"typecheck": "tsc --noEmit",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"benchmark:phase1": "node ./tests/benchmark/phase1-performance.mjs",
|
|
28
|
+
"typecheck:build": "tsc --noEmit --project tsconfig.build.json",
|
|
29
|
+
"typecheck:strict": "echo '⚠️ Running pedantic strict checks (many false positives expected)...' && tsc --noEmit --project tsconfig.build.json --strict",
|
|
30
|
+
"typecheck:summary": "echo '🔍 Type-checking all shipped files...' && npm run typecheck:build && echo '✅ All TypeScript checks passed!'",
|
|
31
31
|
"test:quick": "node ./tests/benchmark/quick-test.mjs",
|
|
32
32
|
"exp:soup": "node ./tests/testSoup.mjs",
|
|
33
33
|
"func:local": "functions-framework --target=entry",
|
|
@@ -61,17 +61,16 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@google-cloud/functions-framework": "^3.4.2",
|
|
63
63
|
"@google-cloud/storage": "^7.14.0",
|
|
64
|
-
"
|
|
65
|
-
"ak-
|
|
66
|
-
"ak-
|
|
67
|
-
"ak-tools": "^1.1.0",
|
|
64
|
+
"ak-fetch": "^2.0.12",
|
|
65
|
+
"ak-gemini": "^1.0.59",
|
|
66
|
+
"ak-tools": "^1.1.12",
|
|
68
67
|
"chance": "^1.1.11",
|
|
69
68
|
"chart.js": "^3.9.1",
|
|
70
69
|
"chartjs-node-canvas": "^4.1.6",
|
|
71
70
|
"dayjs": "^1.11.11",
|
|
72
71
|
"dotenv": "^16.4.5",
|
|
73
72
|
"google-auth-library": "^9.15.0",
|
|
74
|
-
"mixpanel-import": "^2.8.
|
|
73
|
+
"mixpanel-import": "^2.8.162",
|
|
75
74
|
"p-limit": "^3.1.0",
|
|
76
75
|
"yargs": "^17.7.2"
|
|
77
76
|
},
|