From f8c4d3fa6d052dd916a9b0d4f4fe4739b00f2710 Mon Sep 17 00:00:00 2001 From: Erik Thorelli Date: Tue, 15 Sep 2026 19:12:58 -0700 Subject: [PATCH] Preserve venue details when Luma supplies a placeholder URL --- app/src/components/event-details.tsx | 2 +- app/src/lib/luma/public-calendar.ts | 8 +- app/src/lib/luma/sync.ts | 13 +++- app/src/lib/luma/venue-archive.json | 26 +++++++ app/src/lib/luma/venue-recovery.ts | 22 ++++++ app/tests/luma-sync.test.ts | 109 +++++++++++++++++++++++++++ 6 files changed, 175 insertions(+), 5 deletions(-) create mode 100644 app/src/lib/luma/venue-archive.json create mode 100644 app/src/lib/luma/venue-recovery.ts diff --git a/app/src/components/event-details.tsx b/app/src/components/event-details.tsx index e3c0783..4826144 100644 --- a/app/src/components/event-details.tsx +++ b/app/src/components/event-details.tsx @@ -240,7 +240,7 @@ export function AllYouNeedToKnowSection({

- {event.shortLocation} + {event.shortLocation || "Location details on Luma"}

{event.streetAddress || event.shortLocation} diff --git a/app/src/lib/luma/public-calendar.ts b/app/src/lib/luma/public-calendar.ts index 019d75a..d2182f5 100644 --- a/app/src/lib/luma/public-calendar.ts +++ b/app/src/lib/luma/public-calendar.ts @@ -3,6 +3,9 @@ import { TZDate } from "@date-fns/tz"; export const ALL_THINGS_WEB_CALENDAR_ID = "cal-3AAimKnRVQEId4r"; const CALENDAR_TIMEZONE = "America/Los_Angeles"; +export const LUMA_LOCATION_PLACEHOLDER_PATTERN = + "^https?://(www[.])?(luma[.]com|lu[.]ma)/event/evt-[A-Za-z0-9]+/?([?#].*)?$"; +const locationPlaceholder = new RegExp(LUMA_LOCATION_PLACEHOLDER_PATTERN, "i"); export type PublicLumaEvent = { lumaEventId: string; @@ -89,7 +92,10 @@ export function parsePublicLumaCalendar(text: string): PublicLumaEvent[] { name: event.summary.trim(), startDate, endDate, - location: event.location?.trim() || null, + location: + event.location && !locationPlaceholder.test(event.location.trim()) + ? event.location.trim() || null + : null, isDraft, }, sequence: event.sequence, diff --git a/app/src/lib/luma/sync.ts b/app/src/lib/luma/sync.ts index 5e55a32..7b7e8ca 100644 --- a/app/src/lib/luma/sync.ts +++ b/app/src/lib/luma/sync.ts @@ -3,6 +3,7 @@ import { sql } from "drizzle-orm"; import type { PgDatabase, PgQueryResultHKT } from "drizzle-orm/pg-core"; import { eventsTable } from "@/lib/schema"; import { fetchPublicLumaEvents, type PublicLumaEvent } from "./public-calendar"; +import { mergeVenueField } from "./venue-recovery"; function eventSlug(event: PublicLumaEvent): string { const date = new TZDate(event.startDate, "America/Los_Angeles"); @@ -52,9 +53,15 @@ export async function syncPublicLumaEvents( startDate: sql`excluded.start_date`, endDate: sql`excluded.end_date`, isDraft: sql`excluded.is_draft`, - streetAddress: sql`coalesce(excluded.street_address, ${eventsTable.streetAddress})`, - shortLocation: sql`coalesce(excluded.short_location, ${eventsTable.shortLocation})`, - fullAddress: sql`coalesce(excluded.full_address, ${eventsTable.fullAddress})`, + streetAddress: mergeVenueField( + "streetAddress", + sql`excluded.street_address`, + ), + shortLocation: mergeVenueField( + "shortLocation", + sql`excluded.short_location`, + ), + fullAddress: mergeVenueField("fullAddress", sql`excluded.full_address`), }, }) .returning({ slug: eventsTable.slug, isDraft: eventsTable.isDraft }); diff --git a/app/src/lib/luma/venue-archive.json b/app/src/lib/luma/venue-archive.json new file mode 100644 index 0000000..8ca01d9 --- /dev/null +++ b/app/src/lib/luma/venue-archive.json @@ -0,0 +1,26 @@ +[ + { + "lumaEventId": "evt-deGtRGSvYsWMqAc", + "streetAddress": "444 De Haro St #218", + "shortLocation": "Convex HQ", + "fullAddress": "444 De Haro St #218, San Francisco, CA 94107, USA" + }, + { + "lumaEventId": "evt-7CaqG4UZsbIQb6s", + "streetAddress": "100 1st St #2400", + "shortLocation": "Vercel HQ", + "fullAddress": "100 First Plaza, 100 1st St #2400, San Francisco, CA 94105" + }, + { + "lumaEventId": "evt-dbF3WPClKyxWQ7n", + "streetAddress": "45 Fremont St", + "shortLocation": "Sentry, SF", + "fullAddress": "45 Fremont St, San Francisco, CA 94105" + }, + { + "lumaEventId": "evt-HtDmTqndK1vA1Z4", + "streetAddress": "500 Terry A Francois Blvd", + "shortLocation": "Meraki HQ", + "fullAddress": "Cisco Meraki, 500 Terry A Francois Blvd, San Francisco, CA 94158" + } +] diff --git a/app/src/lib/luma/venue-recovery.ts b/app/src/lib/luma/venue-recovery.ts new file mode 100644 index 0000000..b816c17 --- /dev/null +++ b/app/src/lib/luma/venue-recovery.ts @@ -0,0 +1,22 @@ +import { sql, type SQL } from "drizzle-orm"; +import { eventsTable } from "@/lib/schema"; +import { LUMA_LOCATION_PLACEHOLDER_PATTERN } from "./public-calendar"; +import archivedVenues from "./venue-archive.json"; + +type VenueField = "streetAddress" | "shortLocation" | "fullAddress"; + +// Recover only placeholder values overwritten by the first public-feed sync. +// The archive contains public venue data captured before that sync on 2026-09-16. +export function mergeVenueField(field: VenueField, incoming: SQL): SQL { + const archivedValue = sql`case ${eventsTable.lumaEventId} ${sql.join( + archivedVenues.map( + (venue) => sql`when ${venue.lumaEventId} then ${venue[field]}`, + ), + sql` `, + )} else null end`; + return sql`coalesce(${incoming}, case + when ${eventsTable[field]} ~* ${LUMA_LOCATION_PLACEHOLDER_PATTERN} + then ${archivedValue} + else ${eventsTable[field]} + end)`; +} diff --git a/app/tests/luma-sync.test.ts b/app/tests/luma-sync.test.ts index df7ce68..cb6bd45 100644 --- a/app/tests/luma-sync.test.ts +++ b/app/tests/luma-sync.test.ts @@ -92,6 +92,24 @@ describe("public Luma calendar", () => { expect(rows[0].name).toBe("Updated title"); }); + test("ignores Luma event-page location placeholders but keeps online venues", () => { + for (const location of [ + "https://luma.com/event/evt-test", + "https://lu.ma/event/evt-test/", + "HTTPS://WWW.LUMA.COM/event/evt-test?ref=calendar", + ]) { + const input = event().replace("Sentry\\, San Francisco", location); + expect(parsePublicLumaCalendar(calendar(input))[0].location).toBeNull(); + } + const online = event().replace( + "Sentry\\, San Francisco", + "https://zoom.us/j/123", + ); + expect(parsePublicLumaCalendar(calendar(online))[0].location).toBe( + "https://zoom.us/j/123", + ); + }); + test("withholds private and cancelled entries regardless of value casing", () => { for (const property of [ "STATUS:cancelled", @@ -342,4 +360,95 @@ describe("Luma synchronization against Postgres", () => { expect(updated.isDraft).toBe(true); expect(updated.recordingUrl).toBe(original.recordingUrl); }); + + test("missing public venue details preserve a useful stored venue", async () => { + const [original] = await db + .insert(eventsTable) + .values({ + ...seed, + streetAddress: "500 Terry A Francois Blvd", + shortLocation: "Meraki HQ", + fullAddress: "Cisco Meraki, San Francisco", + }) + .returning(); + respond( + calendar( + event().replace( + "Sentry\\, San Francisco", + "https://luma.com/event/evt-test", + ), + ), + ); + await syncPublicLumaEvents(db); + const [updated] = await db.select().from(eventsTable); + expect(updated.streetAddress).toBe(original.streetAddress); + expect(updated.shortLocation).toBe(original.shortLocation); + expect(updated.fullAddress).toBe(original.fullAddress); + }); + + test("recovers archived venue fields once, preserves later edits, and accepts genuine Luma venue updates", async () => { + const id = "evt-HtDmTqndK1vA1Z4"; + const placeholder = `https://luma.com/event/${id}`; + const [original] = await db + .insert(eventsTable) + .values({ + ...seed, + lumaEventId: id, + streetAddress: placeholder, + shortLocation: placeholder, + fullAddress: placeholder, + }) + .returning(); + respond( + calendar(event(id).replace("Sentry\\, San Francisco", placeholder)), + ); + await syncPublicLumaEvents(db); + const [recovered] = await db.select().from(eventsTable); + expect(recovered.id).toBe(original.id); + expect(recovered.streetAddress).toBe("500 Terry A Francois Blvd"); + expect(recovered.shortLocation).toBe("Meraki HQ"); + expect(recovered.fullAddress).toBe( + "Cisco Meraki, 500 Terry A Francois Blvd, San Francisco, CA 94158", + ); + await syncPublicLumaEvents(db); + const [repeated] = await db.select().from(eventsTable); + expect(repeated.streetAddress).toBe(recovered.streetAddress); + await db.update(eventsTable).set({ shortLocation: "Edited venue label" }); + await syncPublicLumaEvents(db); + expect((await db.select().from(eventsTable))[0].shortLocation).toBe( + "Edited venue label", + ); + respond(calendar(event(id))); + await syncPublicLumaEvents(db); + expect((await db.select().from(eventsTable))[0].fullAddress).toBe( + "Sentry, San Francisco", + ); + }); + + test("clears unrecoverable placeholders and imports unknown venues without inventing an address", async () => { + await db.insert(eventsTable).values({ + ...seed, + streetAddress: "https://lu.ma/event/evt-test", + shortLocation: "https://lu.ma/event/evt-test", + fullAddress: "https://lu.ma/event/evt-test", + }); + respond( + calendar( + ...["evt-test", "evt-new"].map((id) => + event(id).replace( + "Sentry\\, San Francisco", + `https://luma.com/event/${id}`, + ), + ), + ), + ); + await syncPublicLumaEvents(db); + const rows = await db.select().from(eventsTable); + expect(rows).toHaveLength(2); + for (const row of rows) { + expect(row.streetAddress).toBeNull(); + expect(row.shortLocation).toBeNull(); + expect(row.fullAddress).toBeNull(); + } + }); });