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
package/cli/init-db.ts ADDED
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env bun
2
+ import { createId } from "@paralleldrive/cuid2";
3
+ // Import schemas for reference (not directly used but good for type checking)
4
+ // import { user, account, team, team_member } from "@db/d1/schema";
5
+ import { randomName } from "@lib/random_name";
6
+ import { execSync } from "child_process";
7
+ import { writeFileSync, unlinkSync } from "fs";
8
+ import { join } from "path";
9
+ import { scrypt, randomBytes } from "crypto";
10
+
11
+ // Hash password using scrypt with better-auth compatible parameters
12
+ async function hashPassword(password: string): Promise<string> {
13
+ const salt = randomBytes(16);
14
+ const saltHex = salt.toString("hex");
15
+
16
+ // Use better-auth compatible scrypt parameters
17
+ const config = {
18
+ N: 16384,
19
+ r: 16,
20
+ p: 1,
21
+ dkLen: 64,
22
+ maxmem: 128 * 16384 * 16 * 2, // 128 * N * r * 2
23
+ };
24
+
25
+ return new Promise((resolve, reject) => {
26
+ scrypt(
27
+ password.normalize("NFKC"),
28
+ saltHex,
29
+ config.dkLen,
30
+ {
31
+ N: config.N,
32
+ r: config.r,
33
+ p: config.p,
34
+ maxmem: config.maxmem,
35
+ },
36
+ (err, derivedKey) => {
37
+ if (err) reject(err);
38
+ else resolve(`${saltHex}:${derivedKey.toString("hex")}`);
39
+ },
40
+ );
41
+ });
42
+ }
43
+
44
+ // Parse CLI arguments
45
+ const args = process.argv.slice(2);
46
+ const getArg = (flag: string, defaultValue?: string): string => {
47
+ const index = args.indexOf(flag);
48
+ if (index === -1) {
49
+ if (defaultValue !== undefined) return defaultValue;
50
+ throw new Error(`Missing required argument: ${flag}`);
51
+ }
52
+ const value = args[index + 1];
53
+ if (!value || value.startsWith("-")) {
54
+ throw new Error(`Invalid value for ${flag}`);
55
+ }
56
+ return value;
57
+ };
58
+
59
+ const hasFlag = (flag: string): boolean => args.includes(flag);
60
+
61
+ // Check for help flag first
62
+ if (hasFlag("--help") || hasFlag("-h")) {
63
+ console.log(`
64
+ Usage: bun run db/init-db.ts [options]
65
+
66
+ Options:
67
+ -e, --email <email> User email (required)
68
+ -p, --password <password> User password (required)
69
+ -n, --name <name> User name (default: "Admin User")
70
+ -d, --database <name> Database name (default: "lytx_core_db")
71
+ --local Use local database (default: true)
72
+ --remote Use remote database (default: false)
73
+ -h, --help Show this help message
74
+
75
+ Example:
76
+ bun run db/init-db.ts --email admin@example.com --password mypassword --name "John Doe"
77
+ bun run db/init-db.ts --email admin@example.com --password mypassword --remote
78
+ `);
79
+ process.exit(0);
80
+ }
81
+
82
+ // CLI argument parsing
83
+ const getEmailArg = () => {
84
+ try {
85
+ return getArg("--email");
86
+ } catch {
87
+ return getArg("-e");
88
+ }
89
+ };
90
+
91
+ const getPasswordArg = () => {
92
+ try {
93
+ return getArg("--password");
94
+ } catch {
95
+ return getArg("-p");
96
+ }
97
+ };
98
+
99
+ const getNameArg = () => {
100
+ try {
101
+ return getArg("--name");
102
+ } catch {
103
+ try {
104
+ return getArg("-n");
105
+ } catch {
106
+ return "Admin User";
107
+ }
108
+ }
109
+ };
110
+
111
+ const getDatabaseArg = () => {
112
+ try {
113
+ return getArg("--database");
114
+ } catch {
115
+ try {
116
+ return getArg("-d");
117
+ } catch {
118
+ return "lytx_core_db";
119
+ }
120
+ }
121
+ };
122
+
123
+ const email = getEmailArg();
124
+ const password = getPasswordArg();
125
+ const name = getNameArg();
126
+ const database = getDatabaseArg();
127
+ const isRemote = hasFlag("--remote");
128
+ const isLocal = hasFlag("--local") || !isRemote; // Default to local
129
+
130
+ // Helper function to execute SQL via wrangler
131
+ function executeSQL(sql: string, description: string) {
132
+ console.log(`📝 ${description}...`);
133
+
134
+ // Create temporary SQL file
135
+ const tempFile = join(process.cwd(), `temp_${Date.now()}.sql`);
136
+ writeFileSync(tempFile, sql);
137
+
138
+ try {
139
+ const command = `bunx wrangler d1 execute ${database} --file ${tempFile} ${isLocal ? "--local" : "--remote"} --yes`;
140
+ const result = execSync(command, { encoding: "utf8", stdio: "pipe" });
141
+ console.log(`✅ ${description} completed`);
142
+ return result;
143
+ } catch (error: any) {
144
+ console.error(`❌ Error during ${description}:`, error.message);
145
+ throw error;
146
+ } finally {
147
+ // Clean up temp file
148
+ try {
149
+ unlinkSync(tempFile);
150
+ } catch (e) {
151
+ // Ignore cleanup errors
152
+ }
153
+ }
154
+ }
155
+
156
+ async function initDatabase() {
157
+ try {
158
+ console.log("🚀 Initializing database with default user...");
159
+ console.log(`📊 Target: ${database} (${isLocal ? "local" : "remote"})`);
160
+
161
+ // Generate IDs and timestamp
162
+ const userId = createId();
163
+ const teamUuid = createId();
164
+ const accountId = createId();
165
+ const now = new Date();
166
+ const timestamp = Math.floor(now.getTime() / 1000); // Convert to Unix timestamp (seconds)
167
+
168
+ // Hash the password using scrypt (same as better-auth)
169
+ console.log("🔐 Hashing password...");
170
+ const hashedPassword = await hashPassword(password);
171
+
172
+ // 1. Create user
173
+ const userSQL = `
174
+ INSERT INTO user (id, name, email, email_verified, created_at, updated_at)
175
+ VALUES ('${userId}', '${name.replace(/'/g, "''")}', '${email}', 1, ${timestamp}, ${timestamp});
176
+ `;
177
+ executeSQL(userSQL, "Creating user");
178
+
179
+ // 2. Create account with hashed password (for better-auth email/password provider)
180
+ const accountSQL = `
181
+ INSERT INTO account (id, account_id, provider_id, user_id, password, created_at, updated_at)
182
+ VALUES ('${accountId}', '${userId}', 'credential', '${userId}', '${hashedPassword}', ${timestamp}, ${timestamp});
183
+ `;
184
+ executeSQL(accountSQL, "Creating account with hashed password");
185
+
186
+ // 3. Create team for the user
187
+ const teamName = randomName();
188
+ const teamSQL = `
189
+ INSERT INTO team (created_by, name, uuid, db_adapter, created_at, updated_at)
190
+ VALUES ('${userId}', '${teamName}', '${teamUuid}', 'sqlite', ${timestamp}, ${timestamp});
191
+ `;
192
+ executeSQL(teamSQL, "Creating default team");
193
+
194
+ // 4. Get the team ID (we need to query it since it's auto-increment)
195
+ const getTeamIdSQL = `SELECT id FROM team WHERE uuid = '${teamUuid}';`;
196
+ const tempFile = join(process.cwd(), `temp_query_${Date.now()}.sql`);
197
+ writeFileSync(tempFile, getTeamIdSQL);
198
+
199
+ let teamId: number;
200
+ try {
201
+ const command = `bunx wrangler d1 execute ${database} --file ${tempFile} ${isLocal ? "--local" : "--remote"} --json --yes`;
202
+ const result = execSync(command, { encoding: "utf8", stdio: "pipe" });
203
+ const jsonResult = JSON.parse(result);
204
+ teamId = jsonResult[0].results[0].id;
205
+ console.log(`🔍 Found team ID: ${teamId}`);
206
+ } catch (error: any) {
207
+ console.error("❌ Error getting team ID:", error.message);
208
+ throw error;
209
+ } finally {
210
+ try {
211
+ unlinkSync(tempFile);
212
+ } catch (e) {
213
+ // Ignore cleanup errors
214
+ }
215
+ }
216
+
217
+ // 5. Add user to team
218
+ const teamMemberSQL = `
219
+ INSERT INTO team_member (team_id, user_id, created_at, updated_at)
220
+ VALUES (${teamId}, '${userId}', ${timestamp}, ${timestamp});
221
+ `;
222
+ executeSQL(teamMemberSQL, "Adding user to team");
223
+
224
+ console.log("✅ Database initialization complete!");
225
+ console.log(`
226
+ 📊 Summary:
227
+ User ID: ${userId}
228
+ Email: ${email}
229
+ Name: ${name}
230
+ Team ID: ${teamId}
231
+ Team Name: ${teamName}
232
+ Team UUID: ${teamUuid}
233
+ Database: ${database} (${isLocal ? "local" : "remote"})
234
+ `);
235
+
236
+ console.log(`
237
+ 🔑 Login credentials:
238
+ Email: ${email}
239
+ Password: ${password}
240
+ `);
241
+
242
+ console.log(`
243
+ 🚀 Next steps:
244
+ 1. Start the dev server: bun run dev
245
+ 2. Visit the login page and use the credentials above
246
+ 3. The user will automatically have a team and can create sites
247
+ `);
248
+ } catch (error) {
249
+ console.error("❌ Error initializing database:", error);
250
+ process.exit(1);
251
+ }
252
+ }
253
+
254
+ // Validate required arguments
255
+ if (!email || !password) {
256
+ console.error("❌ Error: --email and --password are required");
257
+ console.log("Use --help for usage information");
258
+ process.exit(1);
259
+ }
260
+
261
+ // Validate email format
262
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
263
+ if (!emailRegex.test(email)) {
264
+ console.error("❌ Error: Invalid email format");
265
+ process.exit(1);
266
+ }
267
+
268
+ // Run the initialization
269
+ initDatabase();