Skip to content

Commit 8506f1f

Browse files
author
Pavillion
committed
fix: Seeding script improvements and Storybook configuration cleanup
- Allowed dry-run validation in seed.ts without Supabase keys - Corrected formatting and column counts in lessons-template.csv - Broadened Storybook story discovery pattern - Updated seedLessons for null-safety during local validation
1 parent aa1f840 commit 8506f1f

4 files changed

Lines changed: 28 additions & 25 deletions

File tree

.storybook/main.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import type { StorybookConfig } from '@storybook/nextjs-vite'
22

33
const config: StorybookConfig = {
4-
stories: [
5-
'../src/components/**/*.mdx',
6-
'../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)',
7-
],
4+
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
85
addons: [
96
'@chromatic-com/storybook',
107
'@storybook/addon-vitest',

content/lessons-template.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
unit_id,lesson_order,lesson_title,intro_video_url,passing_score,exercise_id,exercise_type,prompt,audio_url,options,correct_option_index,explanation,sentence_parts,correct_order,distractors,correct_answer,acceptable_answers,pairs,correct_transcript
2-
UNIT_ID_HERE,1,Greetings,,0.8,,multiple_choice,Choose the correct article for Hund,,Der Hund|Die Hund|Das Hund,0,Use Der for masculine nouns.,,,,,,,
3-
UNIT_ID_HERE,1,Greetings,,0.8,,word_bank,Build the sentence,,,,Ich|trinke|Wasser,0|1|2,heute,,,,
2+
UNIT_ID_HERE,1,Greetings,,0.8,,multiple_choice,Choose the correct article for Hund,,Der Hund|Die Hund|Das Hund,0,Use Der for masculine nouns,,,,,,,
3+
UNIT_ID_HERE,1,Greetings,,0.8,,word_bank,Build the sentence,,,,,Ich|trinke|Wasser,0|1|2,heute,,,,

scripts/seed.ts

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,18 @@ async function main() {
254254
process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL
255255
const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY
256256

257-
if (!supabaseUrl || !serviceRoleKey) {
257+
if (!options.dryRun && (!supabaseUrl || !serviceRoleKey)) {
258258
throw new Error(
259-
'Missing SUPABASE_URL (or NEXT_PUBLIC_SUPABASE_URL) or SUPABASE_SERVICE_ROLE_KEY'
259+
'Missing SUPABASE_URL (or NEXT_PUBLIC_SUPABASE_URL) or SUPABASE_SERVICE_ROLE_KEY. Required for actual seeding.'
260260
)
261261
}
262262

263-
const client = createClient(supabaseUrl, serviceRoleKey, {
264-
auth: { persistSession: false },
265-
})
263+
const client =
264+
supabaseUrl && serviceRoleKey
265+
? createClient(supabaseUrl, serviceRoleKey, {
266+
auth: { persistSession: false },
267+
})
268+
: null
266269

267270
const resolvedPath = path.resolve(process.cwd(), options.filePath)
268271
const csv = await fs.readFile(resolvedPath, 'utf8')
@@ -273,14 +276,17 @@ async function main() {
273276
trim: true,
274277
}) as CsvRow[]
275278

276-
if (rows.length === 0) {
277-
throw new Error('CSV contains no rows')
279+
if (!Array.isArray(rows) || rows.length === 0) {
280+
throw new Error('CSV yielded no valid rows')
278281
}
279282

280283
const units = new Map<string, Map<number, LessonSeed>>()
281284

282-
rows.forEach((row, index) => {
285+
let index = 0
286+
for (const row of rows) {
283287
const line = index + 2
288+
index += 1
289+
284290
const unitId = normalize(row.unit_id) || options.unitId
285291
if (!unitId) {
286292
throw new Error(`Line ${line}: missing unit_id or --unit flag`)
@@ -352,7 +358,7 @@ async function main() {
352358

353359
const exercise = parseExercise(row, line)
354360
lesson.exercises.push(exercise)
355-
})
361+
}
356362

357363
for (const [unitId, lessonMap] of units) {
358364
const items = Array.from(lessonMap.values())
@@ -368,14 +374,10 @@ async function main() {
368374
try {
369375
content = LessonContentSchema.parse(input)
370376
} catch (error) {
371-
if (error instanceof ZodError) {
372-
const details = error.issues
373-
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
374-
.join(' | ')
375-
throw new Error(
376-
`Lesson ${lesson.orderIndex} (${lesson.title}) failed validation: ${details}`
377-
)
378-
}
377+
console.error(
378+
`Validation failed for Lesson ${lesson.orderIndex} (${lesson.title}):`
379+
)
380+
console.error(error)
379381
throw error
380382
}
381383

@@ -395,6 +397,6 @@ async function main() {
395397
}
396398

397399
main().catch((error) => {
398-
console.error(error instanceof Error ? error.message : error)
400+
console.error(error)
399401
process.exitCode = 1
400402
})

src/features/admin/seed.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ interface SeedParams {
1717
* NOTE: This should only be run by admin users or via a protected server script.
1818
*/
1919
export async function seedLessons(
20-
client: SupabaseClient,
20+
client: SupabaseClient | null,
2121
{ unitId, items, dryRun = false }: SeedParams
2222
) {
2323
console.log(
@@ -53,6 +53,10 @@ export async function seedLessons(
5353
content: item.content as unknown as Record<string, unknown>,
5454
}))
5555

56+
if (!client) {
57+
throw new Error('Database client is not initialized')
58+
}
59+
5660
const { error } = await client
5761
.from('lessons')
5862
.upsert(records, { onConflict: 'unit_id, order_index' })

0 commit comments

Comments
 (0)