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.
Files changed (50) hide show
  1. package/dungeons/adspend.js +35 -1
  2. package/dungeons/anon.js +25 -1
  3. package/dungeons/{array-of-object-loopup.js → array-of-object-lookup.js} +28 -8
  4. package/dungeons/benchmark-heavy.js +2 -2
  5. package/dungeons/benchmark-light.js +2 -2
  6. package/dungeons/big.js +2 -2
  7. package/dungeons/business.js +59 -12
  8. package/dungeons/complex.js +34 -1
  9. package/dungeons/copilot.js +1 -1
  10. package/dungeons/{harness/harness-education.js → education.js} +29 -12
  11. package/dungeons/experiments.js +15 -2
  12. package/dungeons/{harness/harness-fintech.js → fintech.js} +8 -8
  13. package/dungeons/foobar.js +33 -1
  14. package/dungeons/{harness/harness-food.js → food.js} +7 -4
  15. package/dungeons/funnels.js +38 -1
  16. package/dungeons/gaming.js +25 -5
  17. package/dungeons/media.js +861 -271
  18. package/dungeons/mil.js +29 -2
  19. package/dungeons/mirror.js +33 -1
  20. package/dungeons/{kurby.js → retention-cadence.js} +1 -1
  21. package/dungeons/{harness/harness-gaming.js → rpg.js} +5 -5
  22. package/dungeons/sanity.js +31 -2
  23. package/dungeons/{harness/harness-sass.js → sass.js} +2 -2
  24. package/dungeons/scd.js +46 -1
  25. package/dungeons/simple.js +1 -1
  26. package/dungeons/{harness/harness-social.js → social.js} +2 -2
  27. package/dungeons/streaming.js +373 -0
  28. package/dungeons/strict-event-test.js +1 -1
  29. package/dungeons/student-teacher.js +18 -5
  30. package/dungeons/text-generation.js +38 -1
  31. package/dungeons/too-big-events.js +38 -1
  32. package/dungeons/{userAgent.js → user-agent.js} +21 -1
  33. package/entry.js +5 -4
  34. package/lib/utils/logger.js +0 -4
  35. package/package.json +1 -4
  36. package/dungeons/ai-chat-analytics-ed.js +0 -275
  37. package/dungeons/clinch-agi.js +0 -632
  38. package/dungeons/ecommerce-store.js +0 -0
  39. package/dungeons/harness/harness-media.js +0 -961
  40. package/dungeons/money2020-ed-also.js +0 -277
  41. package/dungeons/money2020-ed.js +0 -580
  42. package/dungeons/uday-schema.json +0 -220
  43. package/lib/templates/funnels-instructions.txt +0 -272
  44. package/lib/templates/hook-examples.json +0 -187
  45. package/lib/templates/hooks-instructions.txt +0 -721
  46. package/lib/templates/refine-instructions.txt +0 -485
  47. package/lib/templates/schema-instructions.txt +0 -285
  48. package/lib/utils/ai.js +0 -896
  49. package/lib/utils/mixpanel.js +0 -101
  50. package/lib/utils/project.js +0 -167
@@ -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 };
@@ -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;