lytx 0.3.0

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 (213) hide show
  1. package/.env.example +37 -0
  2. package/README.md +486 -0
  3. package/alchemy.run.ts +155 -0
  4. package/cli/bootstrap-admin.ts +284 -0
  5. package/cli/deploy-staging.ts +692 -0
  6. package/cli/import-events.ts +628 -0
  7. package/cli/import-sites.ts +518 -0
  8. package/cli/index.ts +609 -0
  9. package/cli/init-db.ts +269 -0
  10. package/cli/migrate-to-durable-objects.ts +564 -0
  11. package/cli/migration-worker.ts +300 -0
  12. package/cli/performance-test.ts +588 -0
  13. package/cli/pg/client.ts +4 -0
  14. package/cli/pg/new-site.ts +153 -0
  15. package/cli/rollback-durable-objects.ts +622 -0
  16. package/cli/seed-data.ts +459 -0
  17. package/cli/setup.js +18 -0
  18. package/cli/setup.ts +463 -0
  19. package/cli/validate-migration.ts +200 -0
  20. package/cli/wrangler-migration.jsonc +28 -0
  21. package/db/adapter.ts +166 -0
  22. package/db/analytics_engine/client.ts +0 -0
  23. package/db/analytics_engine/sites.ts +0 -0
  24. package/db/client.ts +16 -0
  25. package/db/d1/client.ts +8 -0
  26. package/db/d1/drizzle.config.ts +35 -0
  27. package/db/d1/migrations/0000_true_maelstrom.sql +165 -0
  28. package/db/d1/migrations/0001_wonderful_bloodaxe.sql +12 -0
  29. package/db/d1/migrations/0002_late_frightful_four.sql +1 -0
  30. package/db/d1/migrations/0003_cuddly_obadiah_stane.sql +16 -0
  31. package/db/d1/migrations/0004_mute_stardust.sql +1 -0
  32. package/db/d1/migrations/0005_awesome_silvermane.sql +3 -0
  33. package/db/d1/migrations/0006_volatile_shriek.sql +2 -0
  34. package/db/d1/migrations/0007_superb_lila_cheney.sql +1 -0
  35. package/db/d1/migrations/0008_bitter_longshot.sql +17 -0
  36. package/db/d1/migrations/0009_wonderful_madame_masque.sql +28 -0
  37. package/db/d1/migrations/meta/0000_snapshot.json +1112 -0
  38. package/db/d1/migrations/meta/0001_snapshot.json +1187 -0
  39. package/db/d1/migrations/meta/0002_snapshot.json +1194 -0
  40. package/db/d1/migrations/meta/0003_snapshot.json +1296 -0
  41. package/db/d1/migrations/meta/0004_snapshot.json +1303 -0
  42. package/db/d1/migrations/meta/0005_snapshot.json +1325 -0
  43. package/db/d1/migrations/meta/0006_snapshot.json +1339 -0
  44. package/db/d1/migrations/meta/0007_snapshot.json +1347 -0
  45. package/db/d1/migrations/meta/0008_snapshot.json +1464 -0
  46. package/db/d1/migrations/meta/0009_snapshot.json +1648 -0
  47. package/db/d1/migrations/meta/_journal.json +76 -0
  48. package/db/d1/schema.ts +407 -0
  49. package/db/d1/sites.ts +374 -0
  50. package/db/d1/teamAiUsage.ts +101 -0
  51. package/db/d1/teams.ts +127 -0
  52. package/db/durable/drizzle.config.ts +8 -0
  53. package/db/durable/durableObjectClient.ts +480 -0
  54. package/db/durable/events.ts +100 -0
  55. package/db/durable/migrations/0000_fair_bucky.sql +38 -0
  56. package/db/durable/migrations/meta/0000_snapshot.json +278 -0
  57. package/db/durable/migrations/meta/_journal.json +13 -0
  58. package/db/durable/migrations/migrations.js +10 -0
  59. package/db/durable/schema.ts +5 -0
  60. package/db/durable/siteDurableObject.ts +1352 -0
  61. package/db/durable/types.ts +53 -0
  62. package/db/postgres/client.ts +13 -0
  63. package/db/postgres/drizzle.config.ts +12 -0
  64. package/db/postgres/migrations/0000_brainy_sprite.sql +116 -0
  65. package/db/postgres/migrations/meta/0000_snapshot.json +681 -0
  66. package/db/postgres/migrations/meta/_journal.json +13 -0
  67. package/db/postgres/schema.ts +145 -0
  68. package/db/postgres/sites.ts +118 -0
  69. package/db/tranformReports.ts +595 -0
  70. package/db/types.ts +55 -0
  71. package/endpoints/api_worker.tsx +1854 -0
  72. package/endpoints/site_do_worker.ts +11 -0
  73. package/index.d.ts +63 -0
  74. package/index.ts +83 -0
  75. package/lib/auth.ts +279 -0
  76. package/lib/geojson/world_countries.json +45307 -0
  77. package/lib/random_name.ts +41 -0
  78. package/lib/sendMail.ts +252 -0
  79. package/package.json +142 -0
  80. package/public/favicon.ico +0 -0
  81. package/public/images/android-chrome-192x192.png +0 -0
  82. package/public/images/android-chrome-512x512.png +0 -0
  83. package/public/images/apple-touch-icon.png +0 -0
  84. package/public/images/favicon-16x16.png +0 -0
  85. package/public/images/favicon-32x32.png +0 -0
  86. package/public/images/lytx_dark_dashboard.png +0 -0
  87. package/public/images/lytx_light_dashboard.png +0 -0
  88. package/public/images/safari-pinned-tab.svg +4 -0
  89. package/public/logo.png +0 -0
  90. package/public/site.webmanifest +26 -0
  91. package/public/sw.js +107 -0
  92. package/src/Document.tsx +86 -0
  93. package/src/api/ai_api.ts +1156 -0
  94. package/src/api/authMiddleware.ts +45 -0
  95. package/src/api/auth_api.ts +465 -0
  96. package/src/api/event_labels_api.ts +193 -0
  97. package/src/api/events_api.ts +210 -0
  98. package/src/api/queueWorker.ts +303 -0
  99. package/src/api/reports_api.ts +278 -0
  100. package/src/api/seed_api.ts +288 -0
  101. package/src/api/sites_api.ts +904 -0
  102. package/src/api/tag_api.ts +458 -0
  103. package/src/api/tag_api_v2.ts +289 -0
  104. package/src/api/team_api.ts +456 -0
  105. package/src/app/Dashboard.tsx +1339 -0
  106. package/src/app/Events.tsx +974 -0
  107. package/src/app/Explore.tsx +312 -0
  108. package/src/app/Layout.tsx +58 -0
  109. package/src/app/Settings.tsx +1302 -0
  110. package/src/app/components/DashboardCard.tsx +118 -0
  111. package/src/app/components/EditableCell.tsx +123 -0
  112. package/src/app/components/EventForm.tsx +93 -0
  113. package/src/app/components/MarketingFooter.tsx +49 -0
  114. package/src/app/components/MarketingNav.tsx +150 -0
  115. package/src/app/components/Nav.tsx +755 -0
  116. package/src/app/components/NewSiteSetup.tsx +298 -0
  117. package/src/app/components/SQLEditor.tsx +740 -0
  118. package/src/app/components/SiteSelector.tsx +126 -0
  119. package/src/app/components/SiteTag.tsx +42 -0
  120. package/src/app/components/SiteTagInstallCard.tsx +241 -0
  121. package/src/app/components/WorldMapCard.tsx +337 -0
  122. package/src/app/components/charts/ChartComponents.tsx +1481 -0
  123. package/src/app/components/charts/EventFunnel.tsx +45 -0
  124. package/src/app/components/charts/EventSummary.tsx +194 -0
  125. package/src/app/components/charts/SankeyFlows.tsx +72 -0
  126. package/src/app/components/marketing/CheckIcon.tsx +16 -0
  127. package/src/app/components/marketing/MarketingLayout.tsx +23 -0
  128. package/src/app/components/marketing/SectionHeading.tsx +35 -0
  129. package/src/app/components/reports/AskAiWorkspace.tsx +371 -0
  130. package/src/app/components/reports/CreateReportStarter.tsx +74 -0
  131. package/src/app/components/reports/DashboardRouteFiltersContext.tsx +14 -0
  132. package/src/app/components/reports/DashboardToolbar.tsx +154 -0
  133. package/src/app/components/reports/DashboardWorkspaceLayout.tsx +63 -0
  134. package/src/app/components/reports/DashboardWorkspaceShell.tsx +118 -0
  135. package/src/app/components/reports/ReportBuilderWorkspace.tsx +76 -0
  136. package/src/app/components/reports/custom/CustomReportBuilderPage.tsx +1667 -0
  137. package/src/app/components/reports/custom/ReportWidgetChart.tsx +297 -0
  138. package/src/app/components/reports/custom/buildWidgetSql.ts +151 -0
  139. package/src/app/components/reports/custom/chartPalettes.ts +18 -0
  140. package/src/app/components/reports/custom/types.ts +50 -0
  141. package/src/app/components/reports/reportBuilderMenuItems.ts +17 -0
  142. package/src/app/components/reports/useDashboardToolbarControls.tsx +235 -0
  143. package/src/app/components/ui/AlertBanner.tsx +101 -0
  144. package/src/app/components/ui/Button.tsx +55 -0
  145. package/src/app/components/ui/Card.tsx +80 -0
  146. package/src/app/components/ui/Input.tsx +72 -0
  147. package/src/app/components/ui/Link.tsx +23 -0
  148. package/src/app/components/ui/ReportBuilderMenu.tsx +246 -0
  149. package/src/app/components/ui/ThemeToggle.tsx +54 -0
  150. package/src/app/constants.ts +6 -0
  151. package/src/app/headers.ts +33 -0
  152. package/src/app/providers/AuthProvider.tsx +189 -0
  153. package/src/app/providers/ClientProviders.tsx +18 -0
  154. package/src/app/providers/QueryProvider.tsx +23 -0
  155. package/src/app/providers/ThemeProvider.tsx +88 -0
  156. package/src/app/utils/chartThemes.ts +146 -0
  157. package/src/app/utils/keybinds.ts +96 -0
  158. package/src/app/utils/media.tsx +24 -0
  159. package/src/client.tsx +114 -0
  160. package/src/config/createLytxAppConfig.ts +252 -0
  161. package/src/config/resourceNames.ts +88 -0
  162. package/src/db/index.ts +67 -0
  163. package/src/index.css +285 -0
  164. package/src/lib/featureFlags.ts +69 -0
  165. package/src/pages/GetStarted.tsx +290 -0
  166. package/src/pages/Home.tsx +268 -0
  167. package/src/pages/Login.tsx +283 -0
  168. package/src/pages/PrivacyPolicy.tsx +120 -0
  169. package/src/pages/Signup.tsx +267 -0
  170. package/src/pages/TermsOfService.tsx +126 -0
  171. package/src/pages/VerifyEmail.tsx +56 -0
  172. package/src/session/durableObject.ts +7 -0
  173. package/src/session/siteSchema.ts +86 -0
  174. package/src/session/types.ts +36 -0
  175. package/src/templates/README.md +80 -0
  176. package/src/templates/cleanFunctions.js +44 -0
  177. package/src/templates/embedFunctions.js +52 -0
  178. package/src/templates/lytx-shared.ts +662 -0
  179. package/src/templates/lytxpixel-core.ts +144 -0
  180. package/src/templates/lytxpixel.ts +267 -0
  181. package/src/templates/lytxpixelBrowser.js +634 -0
  182. package/src/templates/lytxpixelBrowser.mjs +634 -0
  183. package/src/templates/parseData.js +12 -0
  184. package/src/templates/script.ts +31 -0
  185. package/src/templates/template.tsx +50 -0
  186. package/src/templates/test.js +3 -0
  187. package/src/templates/trackWebEvents.ts +177 -0
  188. package/src/templates/vendors/clickcease.ts +8 -0
  189. package/src/templates/vendors/google.ts +174 -0
  190. package/src/templates/vendors/linkedin.ts +23 -0
  191. package/src/templates/vendors/meta.ts +56 -0
  192. package/src/templates/vendors/quantcast.ts +22 -0
  193. package/src/templates/vendors/simplfi.ts +7 -0
  194. package/src/types/app-context.ts +16 -0
  195. package/src/utilities/dashboardParams.ts +188 -0
  196. package/src/utilities/dashboardQueries.ts +537 -0
  197. package/src/utilities/dashboardTransforms.ts +167 -0
  198. package/src/utilities/dataValidation.ts +414 -0
  199. package/src/utilities/detector.ts +73 -0
  200. package/src/utilities/encrypt.ts +103 -0
  201. package/src/utilities/index.ts +13 -0
  202. package/src/utilities/parser.ts +117 -0
  203. package/src/utilities/performanceMonitoring.ts +570 -0
  204. package/src/utilities/route_interuptors.ts +24 -0
  205. package/src/worker.tsx +675 -0
  206. package/tsconfig.json +78 -0
  207. package/types/env.d.ts +16 -0
  208. package/types/rw.d.ts +7 -0
  209. package/types/shims.d.ts +53 -0
  210. package/types/vite.d.ts +19 -0
  211. package/vite/vite-plugin-pixel-bundle.ts +126 -0
  212. package/vite.config.ts +53 -0
  213. package/worker-configuration.d.ts +8401 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Generate a new encryption key (run this locally once, not in production)
3
+ * @returns Base64 encoded encryption key
4
+ */
5
+ export async function generateEncryptionKey(): Promise<string> {
6
+ const key = await crypto.subtle.generateKey(
7
+ { name: "AES-GCM", length: 256 },
8
+ true,
9
+ ["encrypt", "decrypt"]
10
+ );
11
+
12
+ const exportedKey = await crypto.subtle.exportKey("raw", key);
13
+ return btoa(String.fromCharCode(...new Uint8Array(exportedKey)));
14
+ }
15
+
16
+
17
+ /**
18
+ * Import an encryption key from base64 format
19
+ * @param keyBase64 Base64 encoded encryption key
20
+ * @returns CryptoKey object for encryption/decryption
21
+ */
22
+ export async function getEncryptionKey(keyBase64: string): Promise<CryptoKey> {
23
+ const keyBytes = Uint8Array.from(atob(keyBase64), c => c.charCodeAt(0));
24
+ return await crypto.subtle.importKey(
25
+ "raw",
26
+ keyBytes,
27
+ { name: "AES-GCM", length: 256 },
28
+ false,
29
+ ["encrypt", "decrypt"]
30
+ );
31
+ }
32
+
33
+
34
+ /**
35
+ * Encrypt a string value
36
+ * @param value The string to encrypt
37
+ * @param keyBase64 Base64 encoded encryption key
38
+ * @returns Object containing encrypted value and initialization vector
39
+ */
40
+ export async function encrypt(value: string, keyBase64: string): Promise<{
41
+ encryptedValue: string;
42
+ iv: string;
43
+ }> {
44
+ // Create a random initialization vector
45
+ const iv = crypto.getRandomValues(new Uint8Array(12));
46
+
47
+ // Get the key
48
+ const key = await getEncryptionKey(keyBase64);
49
+
50
+ // Encode the string as bytes
51
+ const encoder = new TextEncoder();
52
+ const valueBytes = encoder.encode(value);
53
+
54
+ // Encrypt the value
55
+ const encryptedBytes = await crypto.subtle.encrypt(
56
+ { name: "AES-GCM", iv },
57
+ key,
58
+ valueBytes
59
+ );
60
+
61
+ // Convert to base64 for storage
62
+ const encryptedValue = btoa(String.fromCharCode(...new Uint8Array(encryptedBytes)));
63
+ const ivBase64 = btoa(String.fromCharCode(...iv));
64
+
65
+ return { encryptedValue, iv: ivBase64 };
66
+ }
67
+
68
+
69
+ /**
70
+ * Decrypt an encrypted string value
71
+ * @param encryptedValue Base64 encoded encrypted value
72
+ * @param ivBase64 Base64 encoded initialization vector
73
+ * @param keyBase64 Base64 encoded encryption key
74
+ * @returns The decrypted string
75
+ */
76
+ export async function decrypt(
77
+ encryptedValue: string,
78
+ ivBase64: string,
79
+ keyBase64: string
80
+ ): Promise<string> {
81
+ try {
82
+ // Convert from base64
83
+ const encryptedBytes = Uint8Array.from(atob(encryptedValue), c => c.charCodeAt(0));
84
+ const iv = Uint8Array.from(atob(ivBase64), c => c.charCodeAt(0));
85
+
86
+ // Get the key
87
+ const key = await getEncryptionKey(keyBase64);
88
+
89
+ // Decrypt
90
+ const decryptedBytes = await crypto.subtle.decrypt(
91
+ { name: "AES-GCM", iv },
92
+ key,
93
+ encryptedBytes
94
+ );
95
+
96
+ // Convert back to string
97
+ const decoder = new TextDecoder();
98
+ return decoder.decode(decryptedBytes);
99
+ } catch (error) {
100
+ console.error("Decryption failed:", error);
101
+ throw new Error("Failed to decrypt value. The data may be corrupted or the key is incorrect.", { cause: error });
102
+ }
103
+ }
@@ -0,0 +1,13 @@
1
+ //import { crypto } from "@cloudflare/workers-types";
2
+
3
+ export async function hashIpAddress(ipAddress:string, salt:string) {
4
+ const encoder = new TextEncoder();
5
+ const data = encoder.encode(ipAddress + salt); // Combine IP address and salt
6
+ const hashBuffer = await crypto.subtle.digest('SHA-256', data);
7
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
8
+ const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
9
+ return hashHex;
10
+ }
11
+
12
+ //crypto
13
+
@@ -0,0 +1,117 @@
1
+ import { PageEvent, parseData } from "@/templates/lytxpixel";
2
+ import { trackEvents } from "@/templates/trackWebEvents";
3
+ const dataVariableName = "lytxDataLayer" as const;
4
+
5
+ // Comprehensive function cleaner for build artifacts
6
+ function cleanFunctionForEmbedding(func: Function): string {
7
+ let source = func.toString();
8
+
9
+ // Remove all variations of __name and @__PURE__ annotations
10
+ source = source
11
+ // Remove standalone @__PURE__ comments
12
+ .replace(/\/\*\s*@__PURE__\s*\*\/\s*/g, '')
13
+ // Remove __name calls with various patterns
14
+ .replace(/__name\s*\([^)]*\)\s*[,;]?\s*/g, '')
15
+ // Remove combined patterns like "= /* @__PURE__ */ __name("
16
+ .replace(/=\s*\/\*\s*@__PURE__\s*\*\/\s*__name\s*\([^,)]*,\s*[^)]*\)/g, '= ')
17
+ // Remove const declarations with __name
18
+ .replace(/const\s+(\w+)\s*=\s*\/\*\s*@__PURE__\s*\*\/\s*__name\s*\([^,)]*,\s*[^)]*\)/g, 'const $1 = ')
19
+ // Clean up function expressions
20
+ .replace(/function\s*\(\)\s*\{\s*return\s*([^}]+)\s*\}\s*\(\)/g, '$1')
21
+ // Remove any remaining __name references
22
+ .replace(/__name/g, '')
23
+ // Clean up extra commas and semicolons
24
+ .replace(/,\s*[,;]/g, ',')
25
+ .replace(/;\s*;/g, ';')
26
+ // Normalize whitespace
27
+ .replace(/\s+/g, ' ')
28
+ .trim();
29
+
30
+ return source;
31
+ }
32
+ type TagConfig = { site: string, tag: string, track_web_events: boolean, gdpr: boolean };
33
+ type QueryParams = {
34
+ [key: string]: string[];
35
+ };
36
+ type DataVariableName = typeof dataVariableName;
37
+
38
+ type ScriptConfig = { config: TagConfig, queryParamsStr?: string, data: PageEvent[], dataVariableName: DataVariableName };
39
+ //TODO fix types for config and queryParamsStr
40
+ export function generateScript(conf: ScriptConfig) {
41
+ const { config, queryParamsStr, data, dataVariableName } = conf;
42
+
43
+
44
+ //TODO check these
45
+ const dataObjects = data.map(item => {
46
+ return `
47
+ {
48
+ event_name: ${JSON.stringify(item.event_name)},
49
+ condition: ${JSON.stringify(item.condition)},
50
+ data_passback: ${JSON.stringify(item.data_passback)},
51
+ parameters: ${JSON.stringify(item.parameters)},
52
+ paramConfig: ${JSON.stringify(item.paramConfig)},
53
+ query_parameters: ${JSON.stringify(item.query_parameters)},
54
+ customScript: ${JSON.stringify(item.customScript)},
55
+ rules: ${JSON.stringify(item.rules)},
56
+ Notes: ${JSON.stringify(item.Notes)}
57
+ }
58
+ `;
59
+ }).join(',');
60
+
61
+ //part to impor
62
+
63
+ //!dont forget to check for config gdp and change data
64
+
65
+ //var config = ${JSON.stringify(config)};
66
+ //var queryParamsStr = "${queryParamsStr}";
67
+ const jsTemplate = `
68
+ (function() {
69
+ const dataVariableName = [${dataObjects}];
70
+
71
+
72
+ if(window.${dataVariableName}){
73
+ window.${dataVariableName}.push(
74
+ {site:"${config.site}",tag:"${config.tag}",events:${dataVariableName},tracked:[]}
75
+ )
76
+ }else{
77
+ window.${dataVariableName} = [
78
+ {site:"${config.site}",tag:"${config.tag}",events:${dataVariableName},tracked:[]}
79
+ ]
80
+ }
81
+
82
+ //parseData
83
+ //trackEvents
84
+ ${cleanFunctionForEmbedding(parseData)}
85
+ ${cleanFunctionForEmbedding(trackEvents)}
86
+ parseData(${dataVariableName},{site:"${config.site}",tag:"${config.tag}"},trackEvents,${config.track_web_events},'{{platform}}');
87
+ //replace handlebars
88
+
89
+ parseData(${dataVariableName},{site:"${config.site}",tag:"${config.tag}"},trackEvents,${config.track_web_events},'{{platform}}');
90
+ ${config.track_web_events
91
+ ? `trackEvents("${config.tag}",'{{platform}}',null,'{{{macros}}}');`
92
+ : ``
93
+ }
94
+ window.lytxApi.event = trackEvents;
95
+ window.lytxApi.capture = function(eventName, customData) {
96
+ window.lytxApi.event("${config.tag}", "{{platform}}", { custom: eventName }, "", customData || undefined);
97
+ };
98
+ })();
99
+ `;
100
+
101
+ return jsTemplate;
102
+ }
103
+
104
+
105
+
106
+
107
+ function buildQueryString(queryParams: QueryParams): string {
108
+ // Filter out unwanted keys
109
+ const filteredParams = Object.entries(queryParams).filter(([key]) => key !== 'account' && key !== 'platform');
110
+
111
+ // Convert the object to a query string
112
+ const queryString = filteredParams.map(([key, value]) => {
113
+ return encodeURIComponent(key) + '=' + encodeURIComponent(value.join('&'));
114
+ }).join('&');
115
+
116
+ return queryString ? `&${queryString}` : '';
117
+ }