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.
- package/.env.example +37 -0
- package/README.md +486 -0
- package/alchemy.run.ts +155 -0
- package/cli/bootstrap-admin.ts +284 -0
- package/cli/deploy-staging.ts +692 -0
- package/cli/import-events.ts +628 -0
- package/cli/import-sites.ts +518 -0
- package/cli/index.ts +609 -0
- package/cli/init-db.ts +269 -0
- package/cli/migrate-to-durable-objects.ts +564 -0
- package/cli/migration-worker.ts +300 -0
- package/cli/performance-test.ts +588 -0
- package/cli/pg/client.ts +4 -0
- package/cli/pg/new-site.ts +153 -0
- package/cli/rollback-durable-objects.ts +622 -0
- package/cli/seed-data.ts +459 -0
- package/cli/setup.js +18 -0
- package/cli/setup.ts +463 -0
- package/cli/validate-migration.ts +200 -0
- package/cli/wrangler-migration.jsonc +28 -0
- package/db/adapter.ts +166 -0
- package/db/analytics_engine/client.ts +0 -0
- package/db/analytics_engine/sites.ts +0 -0
- package/db/client.ts +16 -0
- package/db/d1/client.ts +8 -0
- package/db/d1/drizzle.config.ts +35 -0
- package/db/d1/migrations/0000_true_maelstrom.sql +165 -0
- package/db/d1/migrations/0001_wonderful_bloodaxe.sql +12 -0
- package/db/d1/migrations/0002_late_frightful_four.sql +1 -0
- package/db/d1/migrations/0003_cuddly_obadiah_stane.sql +16 -0
- package/db/d1/migrations/0004_mute_stardust.sql +1 -0
- package/db/d1/migrations/0005_awesome_silvermane.sql +3 -0
- package/db/d1/migrations/0006_volatile_shriek.sql +2 -0
- package/db/d1/migrations/0007_superb_lila_cheney.sql +1 -0
- package/db/d1/migrations/0008_bitter_longshot.sql +17 -0
- package/db/d1/migrations/0009_wonderful_madame_masque.sql +28 -0
- package/db/d1/migrations/meta/0000_snapshot.json +1112 -0
- package/db/d1/migrations/meta/0001_snapshot.json +1187 -0
- package/db/d1/migrations/meta/0002_snapshot.json +1194 -0
- package/db/d1/migrations/meta/0003_snapshot.json +1296 -0
- package/db/d1/migrations/meta/0004_snapshot.json +1303 -0
- package/db/d1/migrations/meta/0005_snapshot.json +1325 -0
- package/db/d1/migrations/meta/0006_snapshot.json +1339 -0
- package/db/d1/migrations/meta/0007_snapshot.json +1347 -0
- package/db/d1/migrations/meta/0008_snapshot.json +1464 -0
- package/db/d1/migrations/meta/0009_snapshot.json +1648 -0
- package/db/d1/migrations/meta/_journal.json +76 -0
- package/db/d1/schema.ts +407 -0
- package/db/d1/sites.ts +374 -0
- package/db/d1/teamAiUsage.ts +101 -0
- package/db/d1/teams.ts +127 -0
- package/db/durable/drizzle.config.ts +8 -0
- package/db/durable/durableObjectClient.ts +480 -0
- package/db/durable/events.ts +100 -0
- package/db/durable/migrations/0000_fair_bucky.sql +38 -0
- package/db/durable/migrations/meta/0000_snapshot.json +278 -0
- package/db/durable/migrations/meta/_journal.json +13 -0
- package/db/durable/migrations/migrations.js +10 -0
- package/db/durable/schema.ts +5 -0
- package/db/durable/siteDurableObject.ts +1352 -0
- package/db/durable/types.ts +53 -0
- package/db/postgres/client.ts +13 -0
- package/db/postgres/drizzle.config.ts +12 -0
- package/db/postgres/migrations/0000_brainy_sprite.sql +116 -0
- package/db/postgres/migrations/meta/0000_snapshot.json +681 -0
- package/db/postgres/migrations/meta/_journal.json +13 -0
- package/db/postgres/schema.ts +145 -0
- package/db/postgres/sites.ts +118 -0
- package/db/tranformReports.ts +595 -0
- package/db/types.ts +55 -0
- package/endpoints/api_worker.tsx +1854 -0
- package/endpoints/site_do_worker.ts +11 -0
- package/index.d.ts +63 -0
- package/index.ts +83 -0
- package/lib/auth.ts +279 -0
- package/lib/geojson/world_countries.json +45307 -0
- package/lib/random_name.ts +41 -0
- package/lib/sendMail.ts +252 -0
- package/package.json +142 -0
- package/public/favicon.ico +0 -0
- package/public/images/android-chrome-192x192.png +0 -0
- package/public/images/android-chrome-512x512.png +0 -0
- package/public/images/apple-touch-icon.png +0 -0
- package/public/images/favicon-16x16.png +0 -0
- package/public/images/favicon-32x32.png +0 -0
- package/public/images/lytx_dark_dashboard.png +0 -0
- package/public/images/lytx_light_dashboard.png +0 -0
- package/public/images/safari-pinned-tab.svg +4 -0
- package/public/logo.png +0 -0
- package/public/site.webmanifest +26 -0
- package/public/sw.js +107 -0
- package/src/Document.tsx +86 -0
- package/src/api/ai_api.ts +1156 -0
- package/src/api/authMiddleware.ts +45 -0
- package/src/api/auth_api.ts +465 -0
- package/src/api/event_labels_api.ts +193 -0
- package/src/api/events_api.ts +210 -0
- package/src/api/queueWorker.ts +303 -0
- package/src/api/reports_api.ts +278 -0
- package/src/api/seed_api.ts +288 -0
- package/src/api/sites_api.ts +904 -0
- package/src/api/tag_api.ts +458 -0
- package/src/api/tag_api_v2.ts +289 -0
- package/src/api/team_api.ts +456 -0
- package/src/app/Dashboard.tsx +1339 -0
- package/src/app/Events.tsx +974 -0
- package/src/app/Explore.tsx +312 -0
- package/src/app/Layout.tsx +58 -0
- package/src/app/Settings.tsx +1302 -0
- package/src/app/components/DashboardCard.tsx +118 -0
- package/src/app/components/EditableCell.tsx +123 -0
- package/src/app/components/EventForm.tsx +93 -0
- package/src/app/components/MarketingFooter.tsx +49 -0
- package/src/app/components/MarketingNav.tsx +150 -0
- package/src/app/components/Nav.tsx +755 -0
- package/src/app/components/NewSiteSetup.tsx +298 -0
- package/src/app/components/SQLEditor.tsx +740 -0
- package/src/app/components/SiteSelector.tsx +126 -0
- package/src/app/components/SiteTag.tsx +42 -0
- package/src/app/components/SiteTagInstallCard.tsx +241 -0
- package/src/app/components/WorldMapCard.tsx +337 -0
- package/src/app/components/charts/ChartComponents.tsx +1481 -0
- package/src/app/components/charts/EventFunnel.tsx +45 -0
- package/src/app/components/charts/EventSummary.tsx +194 -0
- package/src/app/components/charts/SankeyFlows.tsx +72 -0
- package/src/app/components/marketing/CheckIcon.tsx +16 -0
- package/src/app/components/marketing/MarketingLayout.tsx +23 -0
- package/src/app/components/marketing/SectionHeading.tsx +35 -0
- package/src/app/components/reports/AskAiWorkspace.tsx +371 -0
- package/src/app/components/reports/CreateReportStarter.tsx +74 -0
- package/src/app/components/reports/DashboardRouteFiltersContext.tsx +14 -0
- package/src/app/components/reports/DashboardToolbar.tsx +154 -0
- package/src/app/components/reports/DashboardWorkspaceLayout.tsx +63 -0
- package/src/app/components/reports/DashboardWorkspaceShell.tsx +118 -0
- package/src/app/components/reports/ReportBuilderWorkspace.tsx +76 -0
- package/src/app/components/reports/custom/CustomReportBuilderPage.tsx +1667 -0
- package/src/app/components/reports/custom/ReportWidgetChart.tsx +297 -0
- package/src/app/components/reports/custom/buildWidgetSql.ts +151 -0
- package/src/app/components/reports/custom/chartPalettes.ts +18 -0
- package/src/app/components/reports/custom/types.ts +50 -0
- package/src/app/components/reports/reportBuilderMenuItems.ts +17 -0
- package/src/app/components/reports/useDashboardToolbarControls.tsx +235 -0
- package/src/app/components/ui/AlertBanner.tsx +101 -0
- package/src/app/components/ui/Button.tsx +55 -0
- package/src/app/components/ui/Card.tsx +80 -0
- package/src/app/components/ui/Input.tsx +72 -0
- package/src/app/components/ui/Link.tsx +23 -0
- package/src/app/components/ui/ReportBuilderMenu.tsx +246 -0
- package/src/app/components/ui/ThemeToggle.tsx +54 -0
- package/src/app/constants.ts +6 -0
- package/src/app/headers.ts +33 -0
- package/src/app/providers/AuthProvider.tsx +189 -0
- package/src/app/providers/ClientProviders.tsx +18 -0
- package/src/app/providers/QueryProvider.tsx +23 -0
- package/src/app/providers/ThemeProvider.tsx +88 -0
- package/src/app/utils/chartThemes.ts +146 -0
- package/src/app/utils/keybinds.ts +96 -0
- package/src/app/utils/media.tsx +24 -0
- package/src/client.tsx +114 -0
- package/src/config/createLytxAppConfig.ts +252 -0
- package/src/config/resourceNames.ts +88 -0
- package/src/db/index.ts +67 -0
- package/src/index.css +285 -0
- package/src/lib/featureFlags.ts +69 -0
- package/src/pages/GetStarted.tsx +290 -0
- package/src/pages/Home.tsx +268 -0
- package/src/pages/Login.tsx +283 -0
- package/src/pages/PrivacyPolicy.tsx +120 -0
- package/src/pages/Signup.tsx +267 -0
- package/src/pages/TermsOfService.tsx +126 -0
- package/src/pages/VerifyEmail.tsx +56 -0
- package/src/session/durableObject.ts +7 -0
- package/src/session/siteSchema.ts +86 -0
- package/src/session/types.ts +36 -0
- package/src/templates/README.md +80 -0
- package/src/templates/cleanFunctions.js +44 -0
- package/src/templates/embedFunctions.js +52 -0
- package/src/templates/lytx-shared.ts +662 -0
- package/src/templates/lytxpixel-core.ts +144 -0
- package/src/templates/lytxpixel.ts +267 -0
- package/src/templates/lytxpixelBrowser.js +634 -0
- package/src/templates/lytxpixelBrowser.mjs +634 -0
- package/src/templates/parseData.js +12 -0
- package/src/templates/script.ts +31 -0
- package/src/templates/template.tsx +50 -0
- package/src/templates/test.js +3 -0
- package/src/templates/trackWebEvents.ts +177 -0
- package/src/templates/vendors/clickcease.ts +8 -0
- package/src/templates/vendors/google.ts +174 -0
- package/src/templates/vendors/linkedin.ts +23 -0
- package/src/templates/vendors/meta.ts +56 -0
- package/src/templates/vendors/quantcast.ts +22 -0
- package/src/templates/vendors/simplfi.ts +7 -0
- package/src/types/app-context.ts +16 -0
- package/src/utilities/dashboardParams.ts +188 -0
- package/src/utilities/dashboardQueries.ts +537 -0
- package/src/utilities/dashboardTransforms.ts +167 -0
- package/src/utilities/dataValidation.ts +414 -0
- package/src/utilities/detector.ts +73 -0
- package/src/utilities/encrypt.ts +103 -0
- package/src/utilities/index.ts +13 -0
- package/src/utilities/parser.ts +117 -0
- package/src/utilities/performanceMonitoring.ts +570 -0
- package/src/utilities/route_interuptors.ts +24 -0
- package/src/worker.tsx +675 -0
- package/tsconfig.json +78 -0
- package/types/env.d.ts +16 -0
- package/types/rw.d.ts +7 -0
- package/types/shims.d.ts +53 -0
- package/types/vite.d.ts +19 -0
- package/vite/vite-plugin-pixel-bundle.ts +126 -0
- package/vite.config.ts +53 -0
- package/worker-configuration.d.ts +8401 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Migration Worker Script
|
|
4
|
+
*
|
|
5
|
+
* This script runs inside the Cloudflare Workers environment to perform
|
|
6
|
+
* data migration from D1/Postgres to Durable Objects using the existing
|
|
7
|
+
* infrastructure (writeToDurableObject, insertSiteEvents, etc.)
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* 1. Deploy this as a temporary worker or run with wrangler dev
|
|
11
|
+
* 2. Call the migration endpoints to trigger migration
|
|
12
|
+
* 3. Remove after migration is complete
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { writeToDurableObject } from '@db/durable/durableObjectClient';
|
|
16
|
+
import { drizzle } from 'drizzle-orm/d1';
|
|
17
|
+
import { siteEvents as d1SiteEvents, sites as d1Sites } from '@db/d1/schema';
|
|
18
|
+
import { eq } from 'drizzle-orm';
|
|
19
|
+
import type { SiteEventInput } from '@/session/siteSchema';
|
|
20
|
+
|
|
21
|
+
interface MigrationRequest {
|
|
22
|
+
siteId: number;
|
|
23
|
+
batchSize?: number;
|
|
24
|
+
dryRun?: boolean;
|
|
25
|
+
verify?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface MigrationResponse {
|
|
29
|
+
success: boolean;
|
|
30
|
+
siteId: number;
|
|
31
|
+
totalEvents: number;
|
|
32
|
+
migratedEvents: number;
|
|
33
|
+
batches: number;
|
|
34
|
+
errors?: string[];
|
|
35
|
+
dryRun?: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Transform D1 events to durable object format
|
|
40
|
+
*/
|
|
41
|
+
function transformEventsForDurableObject(events: any[]): SiteEventInput[] {
|
|
42
|
+
return events.map(event => ({
|
|
43
|
+
bot_data: event.bot_data,
|
|
44
|
+
browser: event.browser,
|
|
45
|
+
city: event.city,
|
|
46
|
+
client_page_url: event.client_page_url,
|
|
47
|
+
country: event.country,
|
|
48
|
+
createdAt: event.createdAt ? new Date(event.createdAt) : new Date(),
|
|
49
|
+
updatedAt: event.updatedAt ? new Date(event.updatedAt) : new Date(),
|
|
50
|
+
custom_data: event.custom_data,
|
|
51
|
+
device_type: event.device_type,
|
|
52
|
+
event: event.event,
|
|
53
|
+
operating_system: event.operating_system,
|
|
54
|
+
page_url: event.page_url,
|
|
55
|
+
postal: event.postal,
|
|
56
|
+
query_params: event.query_params,
|
|
57
|
+
referer: event.referer,
|
|
58
|
+
region: event.region,
|
|
59
|
+
rid: event.rid,
|
|
60
|
+
screen_height: event.screen_height,
|
|
61
|
+
screen_width: event.screen_width,
|
|
62
|
+
tag_id: event.tag_id,
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Migrate a single site's events from D1 to Durable Object
|
|
68
|
+
*/
|
|
69
|
+
async function migrateSiteEvents(
|
|
70
|
+
siteId: number,
|
|
71
|
+
env: Env,
|
|
72
|
+
batchSize: number = 50,
|
|
73
|
+
dryRun: boolean = false
|
|
74
|
+
): Promise<MigrationResponse> {
|
|
75
|
+
const db = drizzle(env.lytx_core_db);
|
|
76
|
+
const errors: string[] = [];
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const siteRecord = await db
|
|
80
|
+
.select({ uuid: d1Sites.uuid })
|
|
81
|
+
.from(d1Sites)
|
|
82
|
+
.where(eq(d1Sites.site_id, siteId))
|
|
83
|
+
.limit(1);
|
|
84
|
+
|
|
85
|
+
const siteUuid = siteRecord[0]?.uuid;
|
|
86
|
+
if (!siteUuid) {
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
siteId,
|
|
90
|
+
totalEvents: 0,
|
|
91
|
+
migratedEvents: 0,
|
|
92
|
+
batches: 0,
|
|
93
|
+
errors: [`Site ${siteId} not found`],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Get all events for this site from D1
|
|
98
|
+
const events = await db
|
|
99
|
+
.select()
|
|
100
|
+
.from(d1SiteEvents)
|
|
101
|
+
.where(eq(d1SiteEvents.site_id, siteId))
|
|
102
|
+
.orderBy(d1SiteEvents.createdAt);
|
|
103
|
+
|
|
104
|
+
console.log(`Found ${events.length} events for site ${siteId}`);
|
|
105
|
+
|
|
106
|
+
if (events.length === 0) {
|
|
107
|
+
return {
|
|
108
|
+
success: true,
|
|
109
|
+
siteId,
|
|
110
|
+
totalEvents: 0,
|
|
111
|
+
migratedEvents: 0,
|
|
112
|
+
batches: 0,
|
|
113
|
+
dryRun
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Transform events for durable object
|
|
118
|
+
const transformedEvents = transformEventsForDurableObject(events);
|
|
119
|
+
|
|
120
|
+
if (dryRun) {
|
|
121
|
+
return {
|
|
122
|
+
success: true,
|
|
123
|
+
siteId,
|
|
124
|
+
totalEvents: events.length,
|
|
125
|
+
migratedEvents: 0,
|
|
126
|
+
batches: Math.ceil(events.length / batchSize),
|
|
127
|
+
dryRun: true
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Process in batches
|
|
132
|
+
let migratedCount = 0;
|
|
133
|
+
const totalBatches = Math.ceil(transformedEvents.length / batchSize);
|
|
134
|
+
|
|
135
|
+
for (let i = 0; i < transformedEvents.length; i += batchSize) {
|
|
136
|
+
const batch = transformedEvents.slice(i, i + batchSize);
|
|
137
|
+
const batchNumber = Math.floor(i / batchSize) + 1;
|
|
138
|
+
|
|
139
|
+
console.log(`Processing batch ${batchNumber}/${totalBatches} (${batch.length} events) for site ${siteId}`);
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const result = await writeToDurableObject(siteId, siteUuid, batch);
|
|
143
|
+
|
|
144
|
+
if (result.success) {
|
|
145
|
+
migratedCount += result.inserted || batch.length;
|
|
146
|
+
} else {
|
|
147
|
+
errors.push(`Batch ${batchNumber}: ${result.error}`);
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
const errorMsg = `Batch ${batchNumber} failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
151
|
+
errors.push(errorMsg);
|
|
152
|
+
console.error(errorMsg);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
success: errors.length === 0,
|
|
158
|
+
siteId,
|
|
159
|
+
totalEvents: events.length,
|
|
160
|
+
migratedEvents: migratedCount,
|
|
161
|
+
batches: totalBatches,
|
|
162
|
+
errors: errors.length > 0 ? errors : undefined
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const errorMsg = `Migration failed for site ${siteId}: ${error instanceof Error ? error.message : String(error)}`;
|
|
167
|
+
console.error(errorMsg);
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
success: false,
|
|
171
|
+
siteId,
|
|
172
|
+
totalEvents: 0,
|
|
173
|
+
migratedEvents: 0,
|
|
174
|
+
batches: 0,
|
|
175
|
+
errors: [errorMsg]
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Verify migration by checking durable object has events
|
|
182
|
+
*/
|
|
183
|
+
async function verifyMigration(siteId: number, expectedCount: number, env: Env): Promise<{ success: boolean; actualCount: number; expectedCount: number }> {
|
|
184
|
+
try {
|
|
185
|
+
// Get the durable object for this site
|
|
186
|
+
const durableObjectId = env.SITE_DURABLE_OBJECT.idFromName(`Site-${siteId}`);
|
|
187
|
+
const durableObject = env.SITE_DURABLE_OBJECT.get(durableObjectId);
|
|
188
|
+
|
|
189
|
+
// Get health check which includes total events
|
|
190
|
+
const response = await durableObject.fetch('https://durable-object/health');
|
|
191
|
+
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
throw new Error(`Health check failed: ${response.status}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const health = await response.json() as { totalEvents: number };
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
success: health.totalEvents === expectedCount,
|
|
200
|
+
actualCount: health.totalEvents,
|
|
201
|
+
expectedCount
|
|
202
|
+
};
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(`Verification failed for site ${siteId}:`, error);
|
|
205
|
+
return {
|
|
206
|
+
success: false,
|
|
207
|
+
actualCount: -1,
|
|
208
|
+
expectedCount
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Worker fetch handler for migration endpoints
|
|
215
|
+
*/
|
|
216
|
+
export default {
|
|
217
|
+
async fetch(request: Request, env: Env): Promise<Response> {
|
|
218
|
+
const url = new URL(request.url);
|
|
219
|
+
|
|
220
|
+
// CORS headers for development
|
|
221
|
+
const corsHeaders = {
|
|
222
|
+
'Access-Control-Allow-Origin': '*',
|
|
223
|
+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
|
|
224
|
+
'Access-Control-Allow-Headers': 'Content-Type',
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
if (request.method === 'OPTIONS') {
|
|
228
|
+
return new Response(null, { headers: corsHeaders });
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
// POST /migrate-site - Migrate a single site
|
|
233
|
+
if (url.pathname === '/migrate-site' && request.method === 'POST') {
|
|
234
|
+
const body = await request.json() as MigrationRequest;
|
|
235
|
+
const { siteId, batchSize = 50, dryRun = false, verify = false } = body;
|
|
236
|
+
|
|
237
|
+
if (!siteId) {
|
|
238
|
+
return new Response(JSON.stringify({ error: 'siteId is required' }), {
|
|
239
|
+
status: 400,
|
|
240
|
+
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Perform migration
|
|
245
|
+
const migrationResult = await migrateSiteEvents(siteId, env, batchSize, dryRun);
|
|
246
|
+
|
|
247
|
+
// Perform verification if requested and migration was successful
|
|
248
|
+
let verificationResult;
|
|
249
|
+
if (verify && migrationResult.success && !dryRun) {
|
|
250
|
+
verificationResult = await verifyMigration(siteId, migrationResult.totalEvents, env);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return new Response(JSON.stringify({
|
|
254
|
+
migration: migrationResult,
|
|
255
|
+
verification: verificationResult
|
|
256
|
+
}), {
|
|
257
|
+
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// GET /health - Health check
|
|
262
|
+
if (url.pathname === '/health' && request.method === 'GET') {
|
|
263
|
+
return new Response(JSON.stringify({
|
|
264
|
+
status: 'ok',
|
|
265
|
+
service: 'migration-worker',
|
|
266
|
+
timestamp: new Date().toISOString()
|
|
267
|
+
}), {
|
|
268
|
+
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// GET /verify-site/:siteId - Verify a site's migration
|
|
273
|
+
const verifyMatch = url.pathname.match(/^\/verify-site\/(\d+)$/);
|
|
274
|
+
if (verifyMatch && request.method === 'GET') {
|
|
275
|
+
const siteId = parseInt(verifyMatch[1]);
|
|
276
|
+
const expectedCount = parseInt(url.searchParams.get('expectedCount') || '0');
|
|
277
|
+
|
|
278
|
+
const verificationResult = await verifyMigration(siteId, expectedCount, env);
|
|
279
|
+
|
|
280
|
+
return new Response(JSON.stringify(verificationResult), {
|
|
281
|
+
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return new Response('Not Found', {
|
|
286
|
+
status: 404,
|
|
287
|
+
headers: corsHeaders
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error('Migration worker error:', error);
|
|
292
|
+
return new Response(JSON.stringify({
|
|
293
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
294
|
+
}), {
|
|
295
|
+
status: 500,
|
|
296
|
+
headers: { 'Content-Type': 'application/json', ...corsHeaders }
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
};
|