create-sonicjs 2.0.0 → 2.0.6

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/README.md CHANGED
@@ -1,21 +1,21 @@
1
- # create-sonicjs-app
1
+ # create-sonicjs
2
2
 
3
3
  > The easiest way to create a new SonicJS application
4
4
 
5
- [![Version](https://img.shields.io/npm/v/create-sonicjs-app)](https://www.npmjs.com/package/create-sonicjs-app)
6
- [![License](https://img.shields.io/npm/l/create-sonicjs-app)](./LICENSE)
5
+ [![Version](https://img.shields.io/npm/v/create-sonicjs)](https://www.npmjs.com/package/create-sonicjs)
6
+ [![License](https://img.shields.io/npm/l/create-sonicjs)](./LICENSE)
7
7
 
8
8
  ## Quick Start
9
9
 
10
10
  ```bash
11
- npx create-sonicjs-app my-app
11
+ npx create-sonicjs my-app
12
12
  ```
13
13
 
14
14
  That's it! Follow the interactive prompts and you'll have a running SonicJS application in minutes.
15
15
 
16
16
  ## What It Does
17
17
 
18
- `create-sonicjs-app` sets up everything you need for a modern headless CMS on Cloudflare's edge:
18
+ `create-sonicjs` sets up everything you need for a modern headless CMS on Cloudflare's edge:
19
19
 
20
20
  - ✅ **Project scaffolding** - Complete project structure
21
21
  - ✅ **Template selection** - Choose from pre-built templates
@@ -30,7 +30,7 @@ That's it! Follow the interactive prompts and you'll have a running SonicJS appl
30
30
  ### Interactive Mode (Recommended)
31
31
 
32
32
  ```bash
33
- npx create-sonicjs-app
33
+ npx create-sonicjs
34
34
  ```
35
35
 
36
36
  You'll be prompted for:
@@ -45,13 +45,13 @@ You'll be prompted for:
45
45
  ### With Project Name
46
46
 
47
47
  ```bash
48
- npx create-sonicjs-app my-blog
48
+ npx create-sonicjs my-blog
49
49
  ```
50
50
 
51
51
  ### Command Line Options
52
52
 
53
53
  ```bash
54
- npx create-sonicjs-app my-app --template=starter --skip-install
54
+ npx create-sonicjs my-app --template=starter --skip-install
55
55
  ```
56
56
 
57
57
  **Available flags:**
@@ -144,13 +144,13 @@ Works with all major package managers:
144
144
 
145
145
  ```bash
146
146
  # npm
147
- npx create-sonicjs-app my-app
147
+ npx create-sonicjs my-app
148
148
 
149
149
  # yarn
150
- yarn create sonicjs-app my-app
150
+ yarn create sonicjs my-app
151
151
 
152
152
  # pnpm
153
- pnpm create sonicjs-app my-app
153
+ pnpm create sonicjs my-app
154
154
  ```
155
155
 
156
156
  The CLI automatically detects your package manager from lock files.
@@ -217,7 +217,7 @@ You can create resources manually after project creation. See the [After Creatio
217
217
  ### Skip All Prompts (Non-Interactive Mode)
218
218
 
219
219
  ```bash
220
- npx create-sonicjs-app my-app \
220
+ npx create-sonicjs my-app \
221
221
  --template=starter \
222
222
  --database=my-app-db \
223
223
  --bucket=my-app-media \
@@ -230,7 +230,7 @@ npx create-sonicjs-app my-app \
230
230
  ### Use in CI/CD
231
231
 
232
232
  ```bash
233
- npx create-sonicjs-app test-app \
233
+ npx create-sonicjs test-app \
234
234
  --template=starter \
235
235
  --database=test-db \
236
236
  --bucket=test-bucket \
@@ -254,7 +254,7 @@ npx create-sonicjs-app test-app \
254
254
  ### Create a blog
255
255
 
256
256
  ```bash
257
- npx create-sonicjs-app my-blog
257
+ npx create-sonicjs my-blog
258
258
  # Select "Starter" template
259
259
  # Include example collection: Yes
260
260
  ```
@@ -262,7 +262,7 @@ npx create-sonicjs-app my-blog
262
262
  ### Create without examples
263
263
 
264
264
  ```bash
265
- npx create-sonicjs-app my-app
265
+ npx create-sonicjs my-app
266
266
  # Include example collection: No
267
267
  ```
268
268
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-sonicjs",
3
- "version": "2.0.0",
3
+ "version": "2.0.6",
4
4
  "description": "Create a new SonicJS application with zero configuration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,10 +40,10 @@
40
40
  "dependencies": {
41
41
  "prompts": "^2.4.2",
42
42
  "kleur": "^4.1.5",
43
- "ora": "^8.0.1",
44
- "execa": "^9.5.2",
43
+ "ora": "^8.1.3",
44
+ "execa": "^10.0.0",
45
45
  "fs-extra": "^11.2.0",
46
- "validate-npm-package-name": "^6.0.0"
46
+ "validate-npm-package-name": "^7.0.0"
47
47
  },
48
48
  "engines": {
49
49
  "node": ">=18.0.0"
package/src/cli.js CHANGED
@@ -12,7 +12,7 @@ import validatePackageName from 'validate-npm-package-name'
12
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
13
13
 
14
14
  // Version
15
- const VERSION = '2.0.0'
15
+ const VERSION = '2.0.0-beta.9'
16
16
 
17
17
  // Templates available
18
18
  const TEMPLATES = {
@@ -135,6 +135,40 @@ async function getProjectDetails(initialName) {
135
135
  })
136
136
  }
137
137
 
138
+ // Seed admin user
139
+ questions.push({
140
+ type: 'confirm',
141
+ name: 'seedAdmin',
142
+ message: 'Create admin user?',
143
+ initial: true
144
+ })
145
+
146
+ // Admin email (only if seeding)
147
+ questions.push({
148
+ type: (prev, values) => values.seedAdmin ? 'text' : null,
149
+ name: 'adminEmail',
150
+ message: 'Admin email:',
151
+ validate: (value) => {
152
+ if (!value) return 'Admin email is required'
153
+ // Basic email validation
154
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
155
+ if (!emailRegex.test(value)) return 'Please enter a valid email address'
156
+ return true
157
+ }
158
+ })
159
+
160
+ // Admin password (only if seeding)
161
+ questions.push({
162
+ type: (prev, values) => values.seedAdmin ? 'password' : null,
163
+ name: 'adminPassword',
164
+ message: 'Admin password:',
165
+ validate: (value) => {
166
+ if (!value) return 'Admin password is required'
167
+ if (value.length < 8) return 'Password must be at least 8 characters'
168
+ return true
169
+ }
170
+ })
171
+
138
172
  // Include example collection (only ask if neither flag is set)
139
173
  if (!flags.skipExample && !flags.includeExample) {
140
174
  questions.push({
@@ -176,8 +210,12 @@ async function getProjectDetails(initialName) {
176
210
  template: flags.template || answers.template,
177
211
  databaseName: flags.databaseName || answers.databaseName || `${initialName || answers.projectName}-db`,
178
212
  bucketName: flags.bucketName || answers.bucketName || `${initialName || answers.projectName}-media`,
213
+ seedAdmin: answers.seedAdmin !== undefined ? answers.seedAdmin : true,
214
+ adminEmail: answers.adminEmail,
215
+ adminPassword: answers.adminPassword,
179
216
  includeExample: flags.skipExample ? false : (flags.includeExample ? true : (answers.includeExample !== undefined ? answers.includeExample : true)),
180
217
  createResources: flags.skipCloudflare ? false : answers.createResources,
218
+ runMigrations: true, // Always run migrations automatically
181
219
  initGit: flags.skipGit ? false : answers.initGit,
182
220
  skipInstall: flags.skipInstall
183
221
  }
@@ -189,8 +227,12 @@ async function createProject(answers, flags) {
189
227
  template,
190
228
  databaseName,
191
229
  bucketName,
230
+ adminEmail,
231
+ adminPassword,
192
232
  includeExample,
193
233
  createResources,
234
+ runMigrations,
235
+ seedAdmin,
194
236
  initGit,
195
237
  skipInstall
196
238
  } = answers
@@ -207,23 +249,37 @@ async function createProject(answers, flags) {
207
249
  projectName,
208
250
  databaseName,
209
251
  bucketName,
252
+ seedAdmin,
253
+ adminEmail,
254
+ adminPassword,
210
255
  includeExample
211
256
  })
212
257
  spinner.succeed('Copied template files')
213
258
 
214
259
  // 2. Create Cloudflare resources
215
260
  let databaseId = 'YOUR_DATABASE_ID'
261
+ let resourcesCreated = false
216
262
  if (createResources) {
217
263
  spinner.start('Creating Cloudflare resources...')
218
264
  try {
219
- databaseId = await createCloudflareResources(databaseName, bucketName, targetDir)
220
- spinner.succeed('Created Cloudflare resources')
265
+ const result = await createCloudflareResources(databaseName, bucketName, targetDir)
266
+ databaseId = result.databaseId || 'YOUR_DATABASE_ID'
267
+ resourcesCreated = result.success
268
+ if (resourcesCreated) {
269
+ spinner.succeed('Created Cloudflare resources')
270
+ } else {
271
+ spinner.warn('Cloudflare resources partially created - see details above')
272
+ }
221
273
  } catch (error) {
222
274
  spinner.warn('Failed to create Cloudflare resources')
223
275
  console.log(kleur.dim(' You can create them manually later'))
224
276
  }
225
277
  }
226
278
 
279
+ // Store resources status for success message
280
+ answers.resourcesCreated = resourcesCreated
281
+ answers.databaseIdSet = databaseId !== 'YOUR_DATABASE_ID'
282
+
227
283
  // 3. Update wrangler.toml with database ID
228
284
  spinner.start('Updating configuration...')
229
285
  await updateWranglerConfig(targetDir, { databaseName, databaseId, bucketName })
@@ -234,6 +290,11 @@ async function createProject(answers, flags) {
234
290
  spinner.start('Installing dependencies...')
235
291
  await installDependencies(targetDir)
236
292
  spinner.succeed('Installed dependencies')
293
+
294
+ // Copy migrations after install
295
+ spinner.start('Copying database migrations...')
296
+ await copyMigrationsFromCore(targetDir)
297
+ spinner.succeed('Copied database migrations')
237
298
  }
238
299
 
239
300
  // 5. Initialize git
@@ -243,6 +304,45 @@ async function createProject(answers, flags) {
243
304
  spinner.succeed('Initialized git repository')
244
305
  }
245
306
 
307
+ // 6. Run migrations
308
+ if (runMigrations && !skipInstall && resourcesCreated) {
309
+ spinner.start('Running database migrations...')
310
+ try {
311
+ await runDatabaseMigrations(targetDir)
312
+ spinner.succeed('Database migrations completed')
313
+ answers.migrationsRan = true
314
+ } catch (error) {
315
+ spinner.warn('Failed to run migrations')
316
+ console.log(kleur.dim(` ${error.message}`))
317
+ console.log(kleur.dim(' You can run them manually with: npm run db:migrate:local'))
318
+ answers.migrationsRan = false
319
+ }
320
+ } else if (runMigrations && skipInstall) {
321
+ spinner.info('Skipping migrations - run after npm install')
322
+ answers.migrationsRan = false
323
+ } else if (runMigrations && !resourcesCreated) {
324
+ spinner.info('Skipping migrations - database not created yet')
325
+ answers.migrationsRan = false
326
+ }
327
+
328
+ // 7. Seed admin user
329
+ if (seedAdmin && !skipInstall && answers.migrationsRan) {
330
+ spinner.start('Seeding admin user...')
331
+ try {
332
+ await seedAdminUser(targetDir)
333
+ spinner.succeed('Admin user created')
334
+ answers.adminSeeded = true
335
+ } catch (error) {
336
+ spinner.warn('Failed to seed admin user')
337
+ console.log(kleur.dim(` ${error.message}`))
338
+ console.log(kleur.dim(' You can run it manually with: npm run seed'))
339
+ answers.adminSeeded = false
340
+ }
341
+ } else if (seedAdmin && !answers.migrationsRan) {
342
+ spinner.info('Skipping seed - migrations not completed')
343
+ answers.adminSeeded = false
344
+ }
345
+
246
346
  spinner.succeed(kleur.bold().green('✓ Project created successfully!'))
247
347
 
248
348
  } catch (error) {
@@ -282,7 +382,7 @@ async function copyTemplate(templateName, targetDir, options) {
282
382
 
283
383
  // Add @sonicjs-cms/core dependency
284
384
  packageJson.dependencies = {
285
- '@sonicjs-cms/core': '^2.0.0',
385
+ '@sonicjs-cms/core': '^2.0.5',
286
386
  ...packageJson.dependencies
287
387
  }
288
388
 
@@ -302,6 +402,159 @@ async function copyTemplate(templateName, targetDir, options) {
302
402
  await fs.remove(examplePath)
303
403
  }
304
404
  }
405
+
406
+ // Create admin seed script with provided credentials (only if creating admin user)
407
+ if (options.seedAdmin && options.adminEmail && options.adminPassword) {
408
+ await createAdminSeedScript(targetDir, {
409
+ email: options.adminEmail,
410
+ password: options.adminPassword
411
+ })
412
+ }
413
+ }
414
+
415
+ async function createAdminSeedScript(targetDir, { email, password }) {
416
+ const seedScriptContent = `import { createDb, users } from '@sonicjs-cms/core'
417
+ import { eq } from 'drizzle-orm'
418
+ import bcrypt from 'bcryptjs'
419
+
420
+ /**
421
+ * Seed script to create initial admin user
422
+ *
423
+ * Run this script after migrations:
424
+ * npm run db:migrate:local
425
+ * npm run seed
426
+ *
427
+ * Admin credentials:
428
+ * Email: ${email}
429
+ * Password: [as entered during setup]
430
+ */
431
+
432
+ interface Env {
433
+ DB: D1Database
434
+ }
435
+
436
+ async function seed() {
437
+ // Get D1 database from Cloudflare environment
438
+ // @ts-ignore - getPlatformProxy is available in wrangler
439
+ const { env } = await import('@cloudflare/workers-types/experimental')
440
+ const platform = (env as any).getPlatformProxy?.() || { env: {} }
441
+
442
+ if (!platform.env?.DB) {
443
+ console.error('❌ Error: DB binding not found')
444
+ console.error('')
445
+ console.error('Make sure you have:')
446
+ console.error('1. Created your D1 database: wrangler d1 create <database-name>')
447
+ console.error('2. Updated wrangler.toml with the database_id')
448
+ console.error('3. Run migrations: npm run db:migrate:local')
449
+ console.error('')
450
+ process.exit(1)
451
+ }
452
+
453
+ const db = createDb(platform.env.DB)
454
+
455
+ try {
456
+ // Check if admin user already exists
457
+ const existingUser = await db
458
+ .select()
459
+ .from(users)
460
+ .where(eq(users.email, '${email}'))
461
+ .get()
462
+
463
+ if (existingUser) {
464
+ console.log('✓ Admin user already exists')
465
+ console.log(\` Email: ${email}\`)
466
+ console.log(\` Role: \${existingUser.role}\`)
467
+ return
468
+ }
469
+
470
+ // Hash password using bcrypt
471
+ const passwordHash = await bcrypt.hash('${password}', 10)
472
+
473
+ // Create admin user
474
+ await db
475
+ .insert(users)
476
+ .values({
477
+ email: '${email}',
478
+ username: '${email.split('@')[0]}',
479
+ password: passwordHash,
480
+ role: 'admin',
481
+ isActive: 1,
482
+ createdAt: new Date().toISOString(),
483
+ updatedAt: new Date().toISOString()
484
+ })
485
+ .run()
486
+
487
+ console.log('✓ Admin user created successfully')
488
+ console.log(\` Email: ${email}\`)
489
+ console.log(\` Role: admin\`)
490
+ console.log('')
491
+ console.log('You can now login at: http://localhost:8787/auth/login')
492
+ } catch (error) {
493
+ console.error('❌ Error creating admin user:', error)
494
+ process.exit(1)
495
+ }
496
+ }
497
+
498
+ // Run seed
499
+ seed()
500
+ .then(() => {
501
+ console.log('')
502
+ console.log('✓ Seeding complete')
503
+ process.exit(0)
504
+ })
505
+ .catch((error) => {
506
+ console.error('❌ Seeding failed:', error)
507
+ process.exit(1)
508
+ })
509
+ `
510
+
511
+ // Create scripts directory
512
+ const scriptsDir = path.join(targetDir, 'scripts')
513
+ await fs.ensureDir(scriptsDir)
514
+
515
+ // Write seed script
516
+ const seedScriptPath = path.join(scriptsDir, 'seed-admin.ts')
517
+ await fs.writeFile(seedScriptPath, seedScriptContent)
518
+
519
+ // Add seed script to package.json
520
+ const packageJsonPath = path.join(targetDir, 'package.json')
521
+ const packageJson = await fs.readJson(packageJsonPath)
522
+
523
+ if (!packageJson.scripts) {
524
+ packageJson.scripts = {}
525
+ }
526
+
527
+ packageJson.scripts.seed = 'tsx scripts/seed-admin.ts'
528
+
529
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 })
530
+ }
531
+
532
+ async function copyMigrationsFromCore(targetDir) {
533
+ // The migrations are in @sonicjs-cms/core/migrations
534
+ // After npm install, they'll be in node_modules/@sonicjs-cms/core/migrations
535
+ const coreMigrationsPath = path.join(targetDir, 'node_modules', '@sonicjs-cms', 'core', 'migrations')
536
+ const projectMigrationsPath = path.join(targetDir, 'migrations')
537
+
538
+ // Check if core migrations exist (they should after npm install)
539
+ if (fs.existsSync(coreMigrationsPath)) {
540
+ // Copy migrations to project directory
541
+ await fs.copy(coreMigrationsPath, projectMigrationsPath)
542
+ } else {
543
+ // If migrations don't exist yet (npm install hasn't run), create a note file
544
+ await fs.ensureDir(projectMigrationsPath)
545
+ const noteContent = `# Migrations
546
+
547
+ Migrations will be copied from @sonicjs-cms/core after running npm install.
548
+
549
+ To manually copy migrations:
550
+ 1. Install dependencies: npm install
551
+ 2. Copy from: node_modules/@sonicjs-cms/core/migrations/
552
+ 3. Copy to: migrations/
553
+
554
+ Or they should be automatically available after installation.
555
+ `
556
+ await fs.writeFile(path.join(projectMigrationsPath, 'README.md'), noteContent)
557
+ }
305
558
  }
306
559
 
307
560
  async function createCloudflareResources(databaseName, bucketName, targetDir) {
@@ -312,10 +565,13 @@ async function createCloudflareResources(databaseName, bucketName, targetDir) {
312
565
  throw new Error('wrangler is not installed. Install with: npm install -g wrangler')
313
566
  }
314
567
 
315
- // Create D1 database
316
568
  let databaseId
569
+ let dbCreated = false
570
+ let bucketCreated = false
571
+
572
+ // Create D1 database
317
573
  try {
318
- const { stdout } = await execa('wrangler', ['d1', 'create', databaseName], {
574
+ const { stdout, stderr } = await execa('wrangler', ['d1', 'create', databaseName], {
319
575
  cwd: targetDir
320
576
  })
321
577
 
@@ -323,9 +579,22 @@ async function createCloudflareResources(databaseName, bucketName, targetDir) {
323
579
  const match = stdout.match(/database_id\s*=\s*["']([^"']+)["']/)
324
580
  if (match) {
325
581
  databaseId = match[1]
582
+ dbCreated = true
583
+ } else {
584
+ console.log('')
585
+ console.log(kleur.yellow('⚠ Warning: Could not parse database_id from wrangler output'))
586
+ console.log(kleur.dim(' You may need to manually update wrangler.toml'))
326
587
  }
327
588
  } catch (error) {
328
- console.log(kleur.yellow(' D1 database creation failed'))
589
+ console.log('')
590
+ console.log(kleur.yellow('⚠ D1 database creation failed:'))
591
+ console.log(kleur.dim(` ${error.message}`))
592
+ if (error.stderr) {
593
+ console.log(kleur.dim(` ${error.stderr}`))
594
+ }
595
+ console.log('')
596
+ console.log(kleur.dim(' Create manually with:'))
597
+ console.log(kleur.dim(` wrangler d1 create ${databaseName}`))
329
598
  }
330
599
 
331
600
  // Create R2 bucket
@@ -333,11 +602,23 @@ async function createCloudflareResources(databaseName, bucketName, targetDir) {
333
602
  await execa('wrangler', ['r2', 'bucket', 'create', bucketName], {
334
603
  cwd: targetDir
335
604
  })
605
+ bucketCreated = true
336
606
  } catch (error) {
337
- console.log(kleur.yellow(' R2 bucket creation failed'))
607
+ console.log('')
608
+ console.log(kleur.yellow('⚠ R2 bucket creation failed:'))
609
+ console.log(kleur.dim(` ${error.message}`))
610
+ if (error.stderr) {
611
+ console.log(kleur.dim(` ${error.stderr}`))
612
+ }
613
+ console.log('')
614
+ console.log(kleur.dim(' Create manually with:'))
615
+ console.log(kleur.dim(` wrangler r2 bucket create ${bucketName}`))
338
616
  }
339
617
 
340
- return databaseId
618
+ return {
619
+ databaseId,
620
+ success: dbCreated && bucketCreated
621
+ }
341
622
  }
342
623
 
343
624
  async function updateWranglerConfig(targetDir, { databaseName, databaseId, bucketName }) {
@@ -396,8 +677,50 @@ async function initializeGit(targetDir) {
396
677
  }
397
678
  }
398
679
 
680
+ async function runDatabaseMigrations(targetDir) {
681
+ try {
682
+ const { stdout, stderr } = await execa('npm', ['run', 'db:migrate:local'], {
683
+ cwd: targetDir,
684
+ reject: false // Don't reject on non-zero exit code - check manually
685
+ })
686
+
687
+ // Check if migrations were successful - look for actual errors, not warnings
688
+ if (stderr && (stderr.toLowerCase().includes('error:') || stderr.toLowerCase().includes('failed'))) {
689
+ // Filter out wrangler version warnings
690
+ if (!stderr.includes('Migrations were successfully applied')) {
691
+ throw new Error(stderr)
692
+ }
693
+ }
694
+
695
+ return stdout
696
+ } catch (error) {
697
+ throw new Error(`Migration failed: ${error.message}`)
698
+ }
699
+ }
700
+
701
+ async function seedAdminUser(targetDir) {
702
+ try {
703
+ const { stdout, stderr } = await execa('npm', ['run', 'seed'], {
704
+ cwd: targetDir,
705
+ reject: false // Don't reject on non-zero exit code - check manually
706
+ })
707
+
708
+ // Check if seeding was successful - look for actual errors, not warnings
709
+ if (stderr && (stderr.toLowerCase().includes('error:') || stderr.toLowerCase().includes('failed'))) {
710
+ // Filter out wrangler version warnings
711
+ if (!stdout.includes('Admin user created') && !stdout.includes('Admin user already exists')) {
712
+ throw new Error(stderr)
713
+ }
714
+ }
715
+
716
+ return stdout
717
+ } catch (error) {
718
+ throw new Error(`Seeding failed: ${error.message}`)
719
+ }
720
+ }
721
+
399
722
  function printSuccessMessage(answers) {
400
- const { projectName, createResources, skipInstall } = answers
723
+ const { projectName, createResources, skipInstall, resourcesCreated, databaseIdSet, migrationsRan, adminSeeded, seedAdmin } = answers
401
724
 
402
725
  console.log()
403
726
  console.log(kleur.bold().green('🎉 Success!'))
@@ -408,24 +731,57 @@ function printSuccessMessage(answers) {
408
731
 
409
732
  if (skipInstall) {
410
733
  console.log(kleur.cyan(' npm install'))
734
+ console.log()
735
+ console.log(kleur.yellow('⚠ Important: After npm install, copy migrations:'))
736
+ console.log(kleur.dim(' cp -r node_modules/@sonicjs-cms/core/migrations ./'))
411
737
  }
412
738
 
413
- if (!createResources) {
739
+ // Show resource creation steps if they weren't created or failed
740
+ if (!createResources || !resourcesCreated) {
414
741
  console.log()
415
742
  console.log(kleur.bold('Create Cloudflare resources:'))
416
- console.log(kleur.cyan(` wrangler d1 create ${answers.databaseName}`))
417
- console.log(kleur.dim(' # Copy database_id to wrangler.toml'))
743
+ if (!databaseIdSet) {
744
+ console.log(kleur.cyan(` wrangler d1 create ${answers.databaseName}`))
745
+ console.log(kleur.dim(' # Copy database_id to wrangler.toml'))
746
+ }
418
747
  console.log(kleur.cyan(` wrangler r2 bucket create ${answers.bucketName}`))
419
748
  }
420
749
 
421
- console.log()
422
- console.log(kleur.bold('Run migrations:'))
423
- console.log(kleur.cyan(' npm run db:migrate:local'))
750
+ // Only show migration/seed steps if they weren't completed (shouldn't normally happen)
751
+ const needsMigrations = !migrationsRan
752
+ const needsSeeding = seedAdmin && !adminSeeded
753
+
754
+ if (needsMigrations || needsSeeding) {
755
+ console.log()
756
+ console.log(kleur.bold('Complete setup:'))
757
+ if (needsMigrations) {
758
+ console.log(kleur.cyan(' npm run db:migrate:local'))
759
+ }
760
+ if (needsSeeding) {
761
+ console.log(kleur.cyan(' npm run seed'))
762
+ }
763
+ }
424
764
 
425
765
  console.log()
426
- console.log(kleur.bold('Start development:'))
766
+ if (migrationsRan && (!seedAdmin || adminSeeded)) {
767
+ console.log(kleur.bold().green('✓ Database is ready! Start development:'))
768
+ } else {
769
+ console.log(kleur.bold('Start development:'))
770
+ }
427
771
  console.log(kleur.cyan(' npm run dev'))
428
772
 
773
+ if (seedAdmin && answers.adminEmail) {
774
+ console.log()
775
+ console.log(kleur.bold('Login credentials:'))
776
+ console.log(kleur.cyan(` Email: ${answers.adminEmail}`))
777
+ console.log(kleur.dim(` Password: [as entered]`))
778
+ }
779
+
780
+ if (migrationsRan && (!seedAdmin || adminSeeded)) {
781
+ console.log()
782
+ console.log(kleur.green('✓ Everything is set up! Just run npm run dev and login.'))
783
+ }
784
+
429
785
  console.log()
430
786
  console.log(kleur.bold('Visit:'))
431
787
  console.log(kleur.cyan(' http://localhost:8787/admin'))
@@ -12,20 +12,21 @@
12
12
  "db:studio": "drizzle-kit studio",
13
13
  "type-check": "tsc --noEmit",
14
14
  "test": "vitest --run",
15
- "test:watch": "vitest"
16
- },
17
- "dependencies": {
15
+ "test:watch": "vitest",
16
+ "update": "npm install @sonicjs-cms/core@latest --save",
17
+ "update:beta": "npm install @sonicjs-cms/core@beta --save"
18
18
  },
19
+ "dependencies": {},
19
20
  "devDependencies": {
20
- "@cloudflare/workers-types": "^4.20250620.0",
21
- "@types/node": "^20.19.1",
22
- "drizzle-kit": "^0.30.0",
23
- "drizzle-orm": "^0.44.2",
24
- "hono": "^4.7.3",
25
- "typescript": "^5.8.3",
26
- "vitest": "^2.1.8",
27
- "wrangler": "^3.110.0",
28
- "zod": "^3.25.67"
21
+ "@cloudflare/workers-types": "^4.20251014.0",
22
+ "@types/node": "^24.9.2",
23
+ "drizzle-kit": "^0.30.3",
24
+ "drizzle-orm": "^0.44.7",
25
+ "hono": "^4.10.4",
26
+ "typescript": "^5.9.3",
27
+ "vitest": "^4.0.5",
28
+ "wrangler": "^3.110.4",
29
+ "zod": "^4.1.12"
29
30
  },
30
31
  "engines": {
31
32
  "node": ">=18.0.0"