make-mp-data 3.0.1 → 3.0.2
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/adspend.js +35 -1
- package/dungeons/anon.js +25 -1
- package/dungeons/{array-of-object-loopup.js → array-of-object-lookup.js} +28 -8
- package/dungeons/benchmark-heavy.js +2 -2
- package/dungeons/benchmark-light.js +2 -2
- package/dungeons/big.js +2 -2
- package/dungeons/business.js +59 -12
- package/dungeons/complex.js +34 -1
- package/dungeons/copilot.js +1 -1
- package/dungeons/{harness/harness-education.js → education.js} +29 -12
- package/dungeons/experiments.js +15 -2
- package/dungeons/{harness/harness-fintech.js → fintech.js} +8 -8
- package/dungeons/foobar.js +33 -1
- package/dungeons/{harness/harness-food.js → food.js} +7 -4
- package/dungeons/funnels.js +38 -1
- package/dungeons/gaming.js +25 -5
- package/dungeons/media.js +861 -271
- package/dungeons/mil.js +29 -2
- package/dungeons/mirror.js +33 -1
- package/dungeons/{kurby.js → retention-cadence.js} +1 -1
- package/dungeons/{harness/harness-gaming.js → rpg.js} +5 -5
- package/dungeons/sanity.js +31 -2
- package/dungeons/{harness/harness-sass.js → sass.js} +2 -2
- package/dungeons/scd.js +46 -1
- package/dungeons/simple.js +1 -1
- package/dungeons/{harness/harness-social.js → social.js} +2 -2
- package/dungeons/streaming.js +373 -0
- package/dungeons/strict-event-test.js +1 -1
- package/dungeons/student-teacher.js +18 -5
- package/dungeons/text-generation.js +38 -1
- package/dungeons/too-big-events.js +38 -1
- package/dungeons/{userAgent.js → user-agent.js} +21 -1
- package/entry.js +5 -4
- package/lib/utils/logger.js +0 -4
- package/package.json +1 -4
- package/dungeons/ai-chat-analytics-ed.js +0 -275
- package/dungeons/clinch-agi.js +0 -632
- package/dungeons/ecommerce-store.js +0 -0
- package/dungeons/harness/harness-media.js +0 -961
- package/dungeons/money2020-ed-also.js +0 -277
- package/dungeons/money2020-ed.js +0 -580
- package/dungeons/uday-schema.json +0 -220
- package/lib/templates/funnels-instructions.txt +0 -272
- package/lib/templates/hook-examples.json +0 -187
- package/lib/templates/hooks-instructions.txt +0 -721
- package/lib/templates/refine-instructions.txt +0 -485
- package/lib/templates/schema-instructions.txt +0 -285
- package/lib/utils/ai.js +0 -896
- package/lib/utils/mixpanel.js +0 -101
- package/lib/utils/project.js +0 -167
package/lib/utils/mixpanel.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Server-side Mixpanel wrapper for AI observability
|
|
3
|
-
*
|
|
4
|
-
* Provides a clean interface for tracking AI job events and usage metrics.
|
|
5
|
-
* Non-blocking - tracking failures are logged but don't affect application flow.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import Mixpanel from 'mixpanel';
|
|
9
|
-
import { serverLogger as logger } from './logger.js';
|
|
10
|
-
|
|
11
|
-
const MIXPANEL_TOKEN = '7608bedf7495b09ac092209387facb52';
|
|
12
|
-
const { NODE_ENV = 'unknown' } = process.env;
|
|
13
|
-
|
|
14
|
-
// Initialize Mixpanel
|
|
15
|
-
let mixpanel = null;
|
|
16
|
-
try {
|
|
17
|
-
mixpanel = Mixpanel.init(MIXPANEL_TOKEN);
|
|
18
|
-
logger.debug('Mixpanel initialized for server-side tracking');
|
|
19
|
-
} catch (error) {
|
|
20
|
-
logger.error({ err: error }, 'Failed to initialize Mixpanel');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Track an event to Mixpanel (server-side)
|
|
25
|
-
* @param {string} eventName - Event name
|
|
26
|
-
* @param {object} properties - Event properties
|
|
27
|
-
* @param {string} [userId] - Optional user ID for distinct_id
|
|
28
|
-
*/
|
|
29
|
-
export function track(eventName, properties = {}, userId = null) {
|
|
30
|
-
if (!mixpanel) {
|
|
31
|
-
logger.warn({ eventName }, 'Mixpanel not initialized, skipping track');
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const trackProps = {
|
|
37
|
-
...properties,
|
|
38
|
-
distinct_id: userId || 'anonymous',
|
|
39
|
-
source: 'dm4-server',
|
|
40
|
-
$insert_id: `${eventName}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
mixpanel.track(eventName, trackProps);
|
|
44
|
-
} catch (error) {
|
|
45
|
-
// Non-blocking - log but don't throw
|
|
46
|
-
logger.error({ err: error, eventName }, 'Failed to track Mixpanel event');
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Track an AI job completion event with structured metadata
|
|
52
|
-
* @param {object} params - AI job parameters
|
|
53
|
-
* @param {string} params.component - AI component (schema, hooks, refine, funnels, generic)
|
|
54
|
-
* @param {string} params.prompt - The prompt sent to the AI
|
|
55
|
-
* @param {object|string} params.response - The AI response
|
|
56
|
-
* @param {number} params.duration_ms - Duration in milliseconds
|
|
57
|
-
* @param {boolean} params.success - Whether the job succeeded
|
|
58
|
-
* @param {string} [params.error] - Error message if failed
|
|
59
|
-
* @param {object} [params.usage] - Token usage from ai.getLastUsage()
|
|
60
|
-
* @param {string} [params.user_id] - User ID for distinct_id
|
|
61
|
-
*/
|
|
62
|
-
export function trackAIJob(params) {
|
|
63
|
-
const {
|
|
64
|
-
component,
|
|
65
|
-
prompt,
|
|
66
|
-
response,
|
|
67
|
-
duration_ms,
|
|
68
|
-
success,
|
|
69
|
-
error = null,
|
|
70
|
-
usage = null,
|
|
71
|
-
user_id = null
|
|
72
|
-
} = params;
|
|
73
|
-
|
|
74
|
-
const responseStr = typeof response === 'string' ? response : JSON.stringify(response);
|
|
75
|
-
|
|
76
|
-
const eventProps = {
|
|
77
|
-
component: `ai-${component}`,
|
|
78
|
-
prompt_preview: prompt?.substring(0, 200) || '',
|
|
79
|
-
prompt_length: prompt?.length || 0,
|
|
80
|
-
output_length: responseStr?.length || 0,
|
|
81
|
-
duration_ms,
|
|
82
|
-
duration_human: `${(duration_ms / 1000).toFixed(2)} seconds`,
|
|
83
|
-
runtime: process.env.RUNTIME_CONTEXT || 'dm4',
|
|
84
|
-
environment: NODE_ENV,
|
|
85
|
-
success,
|
|
86
|
-
error,
|
|
87
|
-
// Token usage (all fields from getLastUsage)
|
|
88
|
-
...(usage && {
|
|
89
|
-
promptTokens: usage.promptTokens,
|
|
90
|
-
responseTokens: usage.responseTokens,
|
|
91
|
-
totalTokens: usage.totalTokens,
|
|
92
|
-
attempts: usage.attempts,
|
|
93
|
-
modelVersion: usage.modelVersion,
|
|
94
|
-
requestedModel: usage.requestedModel,
|
|
95
|
-
}),
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
track('AI Job', eventProps, user_id);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export default { track, trackAIJob };
|
package/lib/utils/project.js
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import 'dotenv/config';
|
|
2
|
-
import * as akTools from 'ak-tools';
|
|
3
|
-
import { dataLogger as logger } from './logger.js';
|
|
4
|
-
const { rand, makeName } = akTools;
|
|
5
|
-
let { OAUTH_TOKEN = "" } = process.env;
|
|
6
|
-
const { NODE_ENV = "unknown" } = process.env;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Main function to create a project and add group keys to it.
|
|
10
|
-
*
|
|
11
|
-
* @param {Object} params - Parameters for the function.
|
|
12
|
-
* @param {string} [params.oauth=""] - OAuth token for authentication.
|
|
13
|
-
* @param {string} [params.orgId=""] - Organization ID.
|
|
14
|
-
* @param {Array<Object>} [params.groups=[]] - List of groups to add to the project.
|
|
15
|
-
* @param {string} [params.name=""] - Name of the user.
|
|
16
|
-
* @param {string} [params.email=""] - Email of the user.
|
|
17
|
-
* @param {string} [params.projectName=""] - Name of the project.
|
|
18
|
-
* @returns {Promise<Object>} The created project with additional group keys.
|
|
19
|
-
* @throws Will throw an error if OAUTH_TOKEN is not set.
|
|
20
|
-
* @throws Will throw an error if orgId is not found.
|
|
21
|
-
*/
|
|
22
|
-
async function main(params = {}) {
|
|
23
|
-
let { oauth = "", orgId = "", groups = [], name = "", email = "", projectName } = params;
|
|
24
|
-
if (oauth) OAUTH_TOKEN = oauth;
|
|
25
|
-
if (!OAUTH_TOKEN) throw new Error('No OAUTH_TOKEN in .env');
|
|
26
|
-
if (!orgId) {
|
|
27
|
-
({ orgId, name, email } = await getUser());
|
|
28
|
-
}
|
|
29
|
-
if (!orgId) throw new Error('No orgId found');
|
|
30
|
-
if (!projectName) projectName = makeName();
|
|
31
|
-
const project = await makeProject(orgId);
|
|
32
|
-
project.user = name;
|
|
33
|
-
project.email = email;
|
|
34
|
-
project.groups = groups;
|
|
35
|
-
project.orgId = orgId;
|
|
36
|
-
const groupKeys = [
|
|
37
|
-
// { display_name: 'Account', property_name: 'account_id' },
|
|
38
|
-
];
|
|
39
|
-
groupKeys.push(...groups);
|
|
40
|
-
const addedGroupKeys = await addGroupKeys(groupKeys, project.id);
|
|
41
|
-
project.groupsAdded = addedGroupKeys;
|
|
42
|
-
|
|
43
|
-
return project;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
async function makeProject(orgId, oauthToken = OAUTH_TOKEN) {
|
|
48
|
-
const excludedOrgs = [
|
|
49
|
-
1, // Mixpanel
|
|
50
|
-
328203, // Mixpanel Demo
|
|
51
|
-
1673847, // SE Demo
|
|
52
|
-
1866253 // Demo Projects
|
|
53
|
-
];
|
|
54
|
-
if (!orgId || !oauthToken) throw new Error('Missing orgId or oauthToken');
|
|
55
|
-
const url = `https://mixpanel.com/api/app/organizations/${orgId}/create-project`;
|
|
56
|
-
const projectPayload = {
|
|
57
|
-
"cluster_id": 1,
|
|
58
|
-
"project_name": `GTM Metrics: Test Env ${rand(1000, 9999)}`,
|
|
59
|
-
"timezone_id": 404
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const payload = {
|
|
63
|
-
method: 'POST',
|
|
64
|
-
|
|
65
|
-
headers: {
|
|
66
|
-
Authorization: `Bearer ${oauthToken}`,
|
|
67
|
-
},
|
|
68
|
-
body: JSON.stringify(projectPayload)
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
const projectsReq = await fetch(url, payload);
|
|
73
|
-
const projectsRes = await projectsReq.json();
|
|
74
|
-
const { api_secret, id, name, token } = projectsRes.results;
|
|
75
|
-
|
|
76
|
-
const data = {
|
|
77
|
-
api_secret,
|
|
78
|
-
id,
|
|
79
|
-
name,
|
|
80
|
-
token,
|
|
81
|
-
url: `https://mixpanel.com/project/${id}/app/settings#project/${id}`
|
|
82
|
-
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
return data;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function getUser(oauthToken = OAUTH_TOKEN) {
|
|
89
|
-
const user = {};
|
|
90
|
-
try {
|
|
91
|
-
if (oauthToken) {
|
|
92
|
-
const info = await fetch(`https://mixpanel.com/api/app/me/?include_workspace_users=false`, { headers: { Authorization: `Bearer ${oauthToken}` } });
|
|
93
|
-
const data = await info.json();
|
|
94
|
-
if (data?.results) {
|
|
95
|
-
const { user_name = "", user_email = "" } = data.results;
|
|
96
|
-
if (user_name) user.name = user_name;
|
|
97
|
-
if (user_email) user.email = user_email;
|
|
98
|
-
const foundOrg = Object.values(data.results.organizations).filter(o => o.name.includes(user_name))?.pop();
|
|
99
|
-
if (foundOrg) {
|
|
100
|
-
user.orgId = foundOrg.id?.toString();
|
|
101
|
-
user.orgName = foundOrg.name;
|
|
102
|
-
}
|
|
103
|
-
if (!foundOrg) {
|
|
104
|
-
// the name is not in the orgs, so we need to find the org in which the user is the owner
|
|
105
|
-
const ignoreProjects = [1673847, 1866253, 328203];
|
|
106
|
-
const possibleOrg = Object.values(data.results.organizations)
|
|
107
|
-
.filter(o => o.role === 'owner')
|
|
108
|
-
.filter(o => !ignoreProjects.includes(o.id))?.pop();
|
|
109
|
-
if (possibleOrg) {
|
|
110
|
-
user.orgId = possibleOrg?.id?.toString();
|
|
111
|
-
user.orgName = possibleOrg.name;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
catch (err) {
|
|
118
|
-
logger.error({ err }, 'Error getting user information');
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return user;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
async function addGroupKeys(groupKeyDfns = [], projectId, oauthToken = OAUTH_TOKEN) {
|
|
126
|
-
const url = `https://mixpanel.com/api/app/projects/${projectId}/data-groups/`;
|
|
127
|
-
const results = [];
|
|
128
|
-
loopKeys: for (const { display_name, property_name } of groupKeyDfns) {
|
|
129
|
-
const body = {
|
|
130
|
-
display_name,
|
|
131
|
-
property_name
|
|
132
|
-
};
|
|
133
|
-
const payload = {
|
|
134
|
-
method: 'POST',
|
|
135
|
-
headers: {
|
|
136
|
-
Authorization: `Bearer ${oauthToken}`,
|
|
137
|
-
'Content-Type': 'application/json'
|
|
138
|
-
},
|
|
139
|
-
body: JSON.stringify(body)
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
const res = await fetch(url, payload);
|
|
144
|
-
const data = await res.json();
|
|
145
|
-
results.push(data?.results);
|
|
146
|
-
}
|
|
147
|
-
catch (err) {
|
|
148
|
-
logger.error({ err, property_name }, 'Error adding group key');
|
|
149
|
-
continue loopKeys;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
return results;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
158
|
-
main()
|
|
159
|
-
.then((result)=>{
|
|
160
|
-
if (NODE_ENV === "dev") debugger;
|
|
161
|
-
})
|
|
162
|
-
.catch((error)=>{
|
|
163
|
-
if (NODE_ENV === "dev") debugger;
|
|
164
|
-
})
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export default main;
|