From e04b7b6df58bf64e1fdc9e3874d10e8cdbd109ed Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 05:07:54 +0000 Subject: [PATCH 1/4] refactor(sets): share SET_TYPES between frontend and edge functions Pin the sets_set_type_check constraint to SET_TYPES with a unit test. Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01CMhMAja3g8dwyMnAjVCLN2 --- src/api/sets/types.ts | 16 +++++++-------- src/lib/setTypeConstraint.test.ts | 28 ++++++++++++++++++++++++++ supabase/functions/_shared/setTypes.ts | 6 ++++-- 3 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 src/lib/setTypeConstraint.test.ts diff --git a/src/api/sets/types.ts b/src/api/sets/types.ts index b29ba56b..2352dd11 100644 --- a/src/api/sets/types.ts +++ b/src/api/sets/types.ts @@ -1,14 +1,14 @@ import type { Database } from "@/integrations/supabase/types"; import type { Artist } from "@/api/artists/types"; import { asEnumValue } from "@/lib/enum"; - -export const SET_TYPES = ["music", "workshop", "performance", "other"] as const; - -export type SetType = (typeof SET_TYPES)[number]; - -export function asSetType(value: string | null): SetType | null { - return asEnumValue(SET_TYPES, value); -} +import { + SET_TYPES, + asSetType, + type SetType, +} from "../../../supabase/functions/_shared/setTypes.ts"; + +export { SET_TYPES, asSetType }; +export type { SetType }; export function isNonMusicSetType( setType: SetType | null, diff --git a/src/lib/setTypeConstraint.test.ts b/src/lib/setTypeConstraint.test.ts new file mode 100644 index 00000000..32ee82b0 --- /dev/null +++ b/src/lib/setTypeConstraint.test.ts @@ -0,0 +1,28 @@ +import { readFileSync, readdirSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { SET_TYPES } from "@/api/sets/types"; + +const MIGRATIONS_DIR = join(process.cwd(), "supabase/migrations"); + +describe("sets_set_type_check constraint", () => { + it("allows exactly the values in SET_TYPES", () => { + expect(latestConstraintValues()).toEqual([...SET_TYPES].sort()); + }); +}); + +function latestConstraintValues() { + const matches = readdirSync(MIGRATIONS_DIR) + .sort() + .flatMap((file) => { + const sql = readFileSync(join(MIGRATIONS_DIR, file), "utf8"); + return [ + ...sql.matchAll( + /ADD CONSTRAINT sets_set_type_check\s+CHECK \(set_type IN \(([^)]*)\)\)/gi, + ), + ]; + }); + const latest = matches.at(-1); + if (!latest) throw new Error("sets_set_type_check migration not found"); + return [...latest[1]!.matchAll(/'([^']+)'/g)].map((m) => m[1]!).sort(); +} diff --git a/supabase/functions/_shared/setTypes.ts b/supabase/functions/_shared/setTypes.ts index 15b4960c..3b99a4b8 100644 --- a/supabase/functions/_shared/setTypes.ts +++ b/supabase/functions/_shared/setTypes.ts @@ -1,6 +1,8 @@ /** - * Mirrors SET_TYPES in src/api/sets/types.ts and the sets_set_type_check - * constraint. Keep the three in sync when adding a type. + * Single TypeScript definition of set types: src/api/sets/types.ts re-exports + * it, so this file must stay dependency-free (Deno can't resolve `@/` aliases). + * The sets_set_type_check constraint is the other copy; src/lib/setTypeConstraint.test.ts fails + * when it drifts. */ export const SET_TYPES = ["music", "workshop", "performance", "other"] as const; From 4dc341c5bc6d4f543f5e8bf111279e4420855f97 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 16 Oct 2026 05:08:30 +0000 Subject: [PATCH 2/4] docs(sets): rewrap setTypes comment --- supabase/functions/_shared/setTypes.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supabase/functions/_shared/setTypes.ts b/supabase/functions/_shared/setTypes.ts index 3b99a4b8..4ec02b76 100644 --- a/supabase/functions/_shared/setTypes.ts +++ b/supabase/functions/_shared/setTypes.ts @@ -1,8 +1,8 @@ /** * Single TypeScript definition of set types: src/api/sets/types.ts re-exports * it, so this file must stay dependency-free (Deno can't resolve `@/` aliases). - * The sets_set_type_check constraint is the other copy; src/lib/setTypeConstraint.test.ts fails - * when it drifts. + * The sets_set_type_check constraint is the other copy; + * src/lib/setTypeConstraint.test.ts fails when it drifts. */ export const SET_TYPES = ["music", "workshop", "performance", "other"] as const; From de4490ae05fdec2c8b12b9dca5f308b7c5baabfb Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 05:07:53 +0000 Subject: [PATCH 3/4] refactor(sets): drop sync comment from setTypes Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_017Mb7n65Uv6JK1vgDFZCVPw --- supabase/functions/_shared/setTypes.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/supabase/functions/_shared/setTypes.ts b/supabase/functions/_shared/setTypes.ts index 4ec02b76..f0c6fb6b 100644 --- a/supabase/functions/_shared/setTypes.ts +++ b/supabase/functions/_shared/setTypes.ts @@ -1,8 +1,6 @@ /** * Single TypeScript definition of set types: src/api/sets/types.ts re-exports * it, so this file must stay dependency-free (Deno can't resolve `@/` aliases). - * The sets_set_type_check constraint is the other copy; - * src/lib/setTypeConstraint.test.ts fails when it drifts. */ export const SET_TYPES = ["music", "workshop", "performance", "other"] as const; From 82f6c0f8843b324d3b7caf116356176a04fe8e2d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 2 Nov 2026 19:55:30 +0000 Subject: [PATCH 4/4] refactor(sets): add @functions alias and drop set-type constraint test Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01TL8Yq3Q42iWAE8GCu58TTq --- src/api/sets/types.ts | 2 +- src/lib/setTypeConstraint.test.ts | 28 ---------------------------- tsconfig.app.json | 3 ++- tsconfig.json | 3 ++- vite.config.ts | 1 + vitest.config.ts | 1 + vitest.integration.config.ts | 1 + 7 files changed, 8 insertions(+), 31 deletions(-) delete mode 100644 src/lib/setTypeConstraint.test.ts diff --git a/src/api/sets/types.ts b/src/api/sets/types.ts index 2352dd11..bfe277fb 100644 --- a/src/api/sets/types.ts +++ b/src/api/sets/types.ts @@ -5,7 +5,7 @@ import { SET_TYPES, asSetType, type SetType, -} from "../../../supabase/functions/_shared/setTypes.ts"; +} from "@functions/_shared/setTypes.ts"; export { SET_TYPES, asSetType }; export type { SetType }; diff --git a/src/lib/setTypeConstraint.test.ts b/src/lib/setTypeConstraint.test.ts deleted file mode 100644 index 32ee82b0..00000000 --- a/src/lib/setTypeConstraint.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { readFileSync, readdirSync } from "node:fs"; -import { join } from "node:path"; -import { describe, expect, it } from "vitest"; -import { SET_TYPES } from "@/api/sets/types"; - -const MIGRATIONS_DIR = join(process.cwd(), "supabase/migrations"); - -describe("sets_set_type_check constraint", () => { - it("allows exactly the values in SET_TYPES", () => { - expect(latestConstraintValues()).toEqual([...SET_TYPES].sort()); - }); -}); - -function latestConstraintValues() { - const matches = readdirSync(MIGRATIONS_DIR) - .sort() - .flatMap((file) => { - const sql = readFileSync(join(MIGRATIONS_DIR, file), "utf8"); - return [ - ...sql.matchAll( - /ADD CONSTRAINT sets_set_type_check\s+CHECK \(set_type IN \(([^)]*)\)\)/gi, - ), - ]; - }); - const latest = matches.at(-1); - if (!latest) throw new Error("sets_set_type_check migration not found"); - return [...latest[1]!.matchAll(/'([^']+)'/g)].map((m) => m[1]!).sort(); -} diff --git a/tsconfig.app.json b/tsconfig.app.json index 6650053e..f8d6e487 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -23,7 +23,8 @@ "baseUrl": ".", "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@functions/*": ["./supabase/functions/*"] } }, "include": ["src"] diff --git a/tsconfig.json b/tsconfig.json index c04f96c2..cde71290 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,7 +7,8 @@ "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["./src/*"] + "@/*": ["./src/*"], + "@functions/*": ["./supabase/functions/*"] }, "skipLibCheck": true, "allowJs": true, diff --git a/vite.config.ts b/vite.config.ts index b878ca33..af51a426 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -90,6 +90,7 @@ export default defineConfig(({ mode }) => ({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), + "@functions": path.resolve(__dirname, "./supabase/functions"), }, }, })); diff --git a/vitest.config.ts b/vitest.config.ts index e95aa9b5..68d797ca 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -25,6 +25,7 @@ export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), + "@functions": path.resolve(__dirname, "./supabase/functions"), }, }, }); diff --git a/vitest.integration.config.ts b/vitest.integration.config.ts index 38cafb11..27f47af3 100644 --- a/vitest.integration.config.ts +++ b/vitest.integration.config.ts @@ -19,6 +19,7 @@ export default defineConfig({ resolve: { alias: { "@": path.resolve(__dirname, "./src"), + "@functions": path.resolve(__dirname, "./supabase/functions"), }, }, });