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,145 @@
1
+ import { pgTable, serial, integer, text, timestamp, boolean, jsonb } from 'drizzle-orm/pg-core'
2
+ import { relations, sql } from 'drizzle-orm'
3
+
4
+ export const accounts = pgTable('accounts', {
5
+ account_id: serial('account_id').primaryKey(),
6
+ api_key: text('api_key'),
7
+ created_at: timestamp('created_at'),
8
+ created_by: text('created_by'),
9
+ name: text('name'),
10
+ website: text('website'),
11
+ })
12
+
13
+ export const dataStore = pgTable('dataStore', {
14
+ id: serial('id').primaryKey(),
15
+ uuid: text('uuid').notNull(),
16
+ account: text('account'),
17
+ adServer: text('adServer'),
18
+ adServerData: jsonb('adServerData'),
19
+ adServerType: text('adServerType'),
20
+ city: text('city'),
21
+ client_ip: text('client_ip'),
22
+ country: text('country'),
23
+ created_at: timestamp('created_at'),
24
+ customData: jsonb('customData'),
25
+ customType: text('customType'),
26
+ data_event: text('data_event'),
27
+ data_passback: text('data_passback'),
28
+ host: text('host'),
29
+ labels: text('labels'),
30
+ lat: text('lat'),
31
+ long: text('long'),
32
+ message: text('message'),
33
+ method: text('method'),
34
+ path: text('path'),
35
+ referer: text('referer'),
36
+ referrer: text('referrer'),
37
+ region: text('region'),
38
+ screen_height: text('screen_height'),
39
+ screen_width: text('screen_width'),
40
+ thirdPartyId: text('thirdPartyId'),
41
+ user_agent: text('user_agent'),
42
+ zip: text('zip'),
43
+ })
44
+
45
+ export const sites = pgTable('sites', {
46
+ site_id: serial('site_id').primaryKey(),
47
+ tag_id: text('tag_id').default(sql`uuid_generate_v4()`),
48
+ track_web_events: boolean('track_web_events').notNull().default(false),
49
+ event_load_strategy: text('event_load_strategy').notNull().default('sdk'),
50
+ account_id: integer('account_id'),
51
+ client: text('client'),
52
+ created_at: timestamp('created_at'),
53
+ domain: text('domain'),
54
+ gdpr: boolean('gdpr'),
55
+ // Autocapture: automatically track clicks on links, buttons, and form submissions
56
+ autocapture: boolean('autocapture').default(true),
57
+ rid_salt: text('rid_salt'),
58
+ rid_salt_expire: timestamp('rid_salt_expire'),
59
+ tag_id_override: text('tag_id_override'),
60
+ })
61
+
62
+ export const events = pgTable('events', {
63
+ id: serial('id').primaryKey(),
64
+ account_id: integer('account_id'),
65
+ clickCease: jsonb('clickCease'),
66
+ condition: text('condition'),
67
+ created_at: timestamp('created_at'),
68
+ data_passback: text('data_passback'),
69
+ event_name: text('event_name'),
70
+ google_ads_conversion: jsonb('google_ads_conversion'),
71
+ google_ads_script: text('google_ads_script'),
72
+ google_analytics: text('google_analytics'),
73
+ notes: text('notes'),
74
+ param_config: jsonb('param_config'),
75
+ parameters: text('parameters'),
76
+ quantcast_pixel_id: text('quantcast_pixel_id'),
77
+ rules: text('rules'),
78
+ simplfi_pixel_id: text('simplfi_pixel_id'),
79
+ site_id: integer('site_id'),
80
+ })
81
+
82
+ export const siteEvents = pgTable('site_events', {
83
+ id: serial('id').primaryKey(),
84
+ account_id: integer('account_id'),
85
+ bot_data: jsonb('bot_data'),
86
+ browser: text('browser'),
87
+ city: text('city'),
88
+ client_page_url: text('client_page_url'),
89
+ country: text('country'),
90
+ created_at: timestamp('created_at'),
91
+ custom_data: jsonb('custom_data'),
92
+ device_type: text('device_type'),
93
+ event: text('event'),
94
+ operating_system: text('operating_system'),
95
+ page_url: text('page_url'),
96
+ postal: text('postal'),
97
+ query_params: jsonb('query_params'),
98
+ referer: text('referer'),
99
+ region: text('region'),
100
+ rid: text('rid'),
101
+ screen_height: integer('screen_height'),
102
+ screen_width: integer('screen_width'),
103
+ site_id: integer('site_id'),
104
+ tag_id: text('tag_id'),
105
+ })
106
+
107
+ export const sitePersonalization = pgTable('site_personalization', {
108
+ id: serial('id').primaryKey(),
109
+ created_at: timestamp('created_at').notNull(),
110
+ client_page_url: text('client_page_url'),
111
+ rid: text('rid'),
112
+ })
113
+
114
+ export const waitlist = pgTable('waitlist', {
115
+ id: serial('id').primaryKey(),
116
+ company: text('company'),
117
+ created_at: timestamp('created_at'),
118
+ email_address: text('email_address'),
119
+ name: text('name'),
120
+ website: text('website'),
121
+ })
122
+
123
+ export const accountsRelations = relations(accounts, ({ many }) => ({
124
+ sites: many(sites),
125
+ events: many(events),
126
+ }))
127
+
128
+ export const sitesRelations = relations(sites, ({ one, many }) => ({
129
+ account: one(accounts, {
130
+ fields: [sites.account_id],
131
+ references: [accounts.account_id],
132
+ }),
133
+ events: many(events),
134
+ }))
135
+
136
+ export const eventsRelations = relations(events, ({ one }) => ({
137
+ account: one(accounts, {
138
+ fields: [events.account_id],
139
+ references: [accounts.account_id],
140
+ }),
141
+ site: one(sites, {
142
+ fields: [events.site_id],
143
+ references: [sites.site_id],
144
+ }),
145
+ }))
@@ -0,0 +1,118 @@
1
+ import { pg_client } from "@db/postgres/client";
2
+ import { DashboardOptions } from "@db/types";
3
+ import { siteEvents, sites } from "@db/postgres/schema";
4
+ import { and, count, eq, gte, inArray, lte } from 'drizzle-orm';
5
+ import { WebEvent } from "@/templates/trackWebEvents";
6
+ import { IS_DEV } from "rwsdk/constants";
7
+
8
+
9
+ export function getDashboardData(options: DashboardOptions) {
10
+ const { date, site_id, team_id } = options;
11
+ const client = pg_client();
12
+ let parsedSiteId = site_id;
13
+ const query = client.select({
14
+ page_url: siteEvents.page_url,
15
+ client_page_url: siteEvents.client_page_url,
16
+ referer: siteEvents.referer,
17
+ event: siteEvents.event,
18
+ createdAt: siteEvents.created_at,
19
+ operating_system: siteEvents.operating_system,
20
+ browser: siteEvents.browser,
21
+ country: siteEvents.country,
22
+ region: siteEvents.region,
23
+ rid: siteEvents.rid,
24
+ city: siteEvents.city,
25
+ postal: siteEvents.postal,
26
+ screen_width: siteEvents.screen_width,
27
+ screen_height: siteEvents.screen_height,
28
+ device_type: siteEvents.device_type,
29
+ }).from(siteEvents);
30
+ const whereFilters = [eq(siteEvents.account_id, team_id)];
31
+ if (typeof site_id === 'string') {
32
+ whereFilters.push(eq(siteEvents.tag_id, site_id));
33
+ }
34
+ else {
35
+ whereFilters.push(eq(siteEvents.site_id, site_id));
36
+ }
37
+ if (date) {
38
+ if (date.start) {
39
+ whereFilters.push(gte(siteEvents.created_at, date.start));
40
+ }
41
+ if (date.end) {
42
+ // Set end date to end of day (23:59:59.999) to include the entire day
43
+ const endOfDay = new Date(date.end);
44
+ endOfDay.setHours(23, 59, 59, 999);
45
+ whereFilters.push(lte(siteEvents.created_at, endOfDay));
46
+ }
47
+ } else {
48
+ // Default to last 7 days
49
+ const sevenDaysAgo = new Date();
50
+ sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
51
+ whereFilters.push(gte(siteEvents.created_at, sevenDaysAgo));
52
+ }
53
+ const noSiteRecordsExist = checkIfSiteEventsHaveRows(site_id, client);
54
+
55
+ query.where(and(...whereFilters));
56
+ if (IS_DEV) console.log("🔥🔥🔥 getDashboardData", query.toSQL());
57
+ return { query, client, noSiteRecordsExist: noSiteRecordsExist };
58
+ }
59
+
60
+
61
+ //WARNING: THIS IS ONLY FOR LOADING INTO THE TAG DO NOT USE THIS FOR ANYTHING ELSE
62
+ export async function getSiteForTag(account: string) {
63
+ const client = pg_client();
64
+ const [site] = await client
65
+ .select()
66
+ .from(sites)
67
+ .where(eq(siteEvents.tag_id, account))
68
+ .limit(1);
69
+ return site;
70
+ }
71
+
72
+
73
+ export async function insertSiteEvent(event: WebEvent) {
74
+ const client = pg_client();
75
+
76
+ const [newEvent] = await client.insert(siteEvents).values({
77
+ event: event.event!,
78
+ tag_id: event.tag_id!,
79
+ client_page_url: event.client_page_url,
80
+ screen_height: event.screen_height,
81
+ screen_width: event.screen_width,
82
+ rid: event.rid,
83
+ browser: event.browser,
84
+ operating_system: event.operating_system,
85
+ device_type: event.device_type,
86
+ custom_data: event.custom_data,
87
+ country: event.country,
88
+ region: event.region,
89
+ city: event.city,
90
+ postal: event.postal,
91
+ site_id: event.site_id!,
92
+ page_url: event.page_url,
93
+ bot_data: event.bot_data,
94
+ query_params: event.query_params,
95
+ referer: event.referer,
96
+ //TODO:RENAME TEAM_ID TO ACCOUNT_ID
97
+ account_id: event.account_id,
98
+ }).returning();
99
+ return newEvent;
100
+
101
+ }
102
+
103
+ export async function checkIfSiteEventsHaveRows(site_id: number | string, client: ReturnType<typeof pg_client>) {
104
+ const whereFilters = [];
105
+ if (typeof site_id === 'string') {
106
+ whereFilters.push(eq(siteEvents.tag_id, site_id));
107
+ }
108
+ else {
109
+ whereFilters.push(eq(siteEvents.site_id, site_id));
110
+ }
111
+ const siteEv = await client
112
+ .select({ id: siteEvents.id })
113
+ .from(siteEvents)
114
+ .where(and(...whereFilters))
115
+ .limit(1);
116
+ if (siteEv.length == 0) return true;
117
+ return false;
118
+ }