create-tigra 2.6.8 → 2.7.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.
Files changed (27) hide show
  1. package/bin/create-tigra.js +144 -0
  2. package/lib/patchers/email-verification.patcher.js +576 -0
  3. package/modules/email-verification/client/hooks/useVerification.ts +70 -0
  4. package/modules/email-verification/client/services/verification.service.ts +25 -0
  5. package/modules/email-verification/server/verification.controller.ts +28 -0
  6. package/modules/email-verification/server/verification.service.ts +190 -0
  7. package/package.json +5 -2
  8. package/template/client/src/features/auth/components/AuthInitializer.tsx +7 -1
  9. package/template/client/src/features/auth/hooks/useAuth.ts +10 -1
  10. package/template/client/src/features/auth/hooks/usePasswordReset.ts +57 -0
  11. package/template/client/src/features/auth/services/auth.service.ts +2 -2
  12. package/template/client/src/lib/constants/api-endpoints.ts +1 -1
  13. package/template/client/src/lib/constants/routes.ts +1 -1
  14. package/template/client/src/lib/utils/error.ts +4 -0
  15. package/template/server/.env.example +29 -0
  16. package/template/server/.env.example.production +22 -0
  17. package/template/server/package-lock.json +6823 -0
  18. package/template/server/package.json +1 -0
  19. package/template/server/src/config/env.ts +18 -1
  20. package/template/server/src/config/rate-limit.config.ts +8 -0
  21. package/template/server/src/libs/auth.ts +4 -1
  22. package/template/server/src/libs/email.ts +40 -0
  23. package/template/server/src/modules/auth/auth.controller.ts +27 -1
  24. package/template/server/src/modules/auth/auth.repo.ts +1 -0
  25. package/template/server/src/modules/auth/auth.routes.ts +24 -0
  26. package/template/server/src/modules/auth/auth.schemas.ts +18 -0
  27. package/template/server/src/modules/auth/auth.service.ts +136 -4
@@ -176,6 +176,25 @@ async function main() {
176
176
  }
177
177
  }
178
178
 
179
+ // Ask about email verification
180
+ const { enableVerification } = await prompts(
181
+ {
182
+ type: 'toggle',
183
+ name: 'enableVerification',
184
+ message: 'Enable email verification for new users?',
185
+ initial: false,
186
+ active: 'Yes',
187
+ inactive: 'No',
188
+ hint: 'Users must verify email before accessing the app',
189
+ },
190
+ {
191
+ onCancel: () => {
192
+ console.log(chalk.red('\n Cancelled.\n'));
193
+ process.exit(1);
194
+ },
195
+ }
196
+ );
197
+
179
198
  // Generate random port offset (1-200) so multiple projects don't conflict
180
199
  const portOffset = crypto.randomInt(1, 201);
181
200
 
@@ -218,6 +237,25 @@ async function main() {
218
237
  }
219
238
  }
220
239
 
240
+ // Apply email verification module if selected
241
+ if (enableVerification) {
242
+ const { applyEmailVerificationModule } = await import('../lib/patchers/email-verification.patcher.js');
243
+ await applyEmailVerificationModule(targetDir);
244
+ } else {
245
+ // Disable verification requirement in .env files
246
+ for (const envFile of ['server/.env.example', 'server/.env']) {
247
+ const envPath = path.join(targetDir, envFile);
248
+ if (await fs.pathExists(envPath)) {
249
+ const content = await fs.readFile(envPath, 'utf-8');
250
+ await fs.writeFile(
251
+ envPath,
252
+ content.replace('REQUIRE_USER_VERIFICATION=true', 'REQUIRE_USER_VERIFICATION=false'),
253
+ 'utf-8',
254
+ );
255
+ }
256
+ }
257
+ }
258
+
221
259
  // Create .developer-role file (default: fullstack = no restrictions)
222
260
  const developerRoleContent = [
223
261
  'fullstack',
@@ -281,12 +319,118 @@ async function main() {
281
319
  console.log();
282
320
  console.log(line);
283
321
  console.log();
322
+ if (enableVerification) {
323
+ console.log(dim(' Email verification: ') + green('enabled'));
324
+ console.log(dim(' Set RESEND_API_KEY in server/.env to send emails'));
325
+ console.log();
326
+ }
284
327
  console.log(dim(' Tip: ') + 'npm run docker:down' + dim(' to stop infrastructure'));
285
328
  console.log();
286
329
  console.log(dim(' Happy coding! 🚀'));
287
330
  console.log();
288
331
  });
289
332
 
333
+ // ─── Add module to existing project ───────────────────────────
334
+ program
335
+ .command('add <module>')
336
+ .description('Add a module to an existing Tigra project')
337
+ .action(async (moduleName) => {
338
+ console.log();
339
+ console.log(chalk.bold(' Create Tigra') + chalk.dim(` v${VERSION}`) + chalk.dim(' — add module'));
340
+ console.log();
341
+
342
+ const projectDir = process.cwd();
343
+
344
+ // Detect if we're inside a Tigra project
345
+ const hasServer = await fs.pathExists(path.join(projectDir, 'server', 'src', 'modules', 'auth'));
346
+ const hasClient = await fs.pathExists(path.join(projectDir, 'client', 'src', 'features', 'auth'));
347
+
348
+ if (!hasServer || !hasClient) {
349
+ console.error(chalk.red(' This does not appear to be a Tigra project.'));
350
+ console.error(chalk.dim(' Run this command from the root of your project (the folder containing server/ and client/).'));
351
+ console.log();
352
+ process.exit(1);
353
+ }
354
+
355
+ const availableModules = ['email-verification'];
356
+
357
+ if (!availableModules.includes(moduleName)) {
358
+ console.error(chalk.red(` Unknown module: "${moduleName}"`));
359
+ console.log();
360
+ console.log(chalk.dim(' Available modules:'));
361
+ for (const m of availableModules) {
362
+ console.log(chalk.cyan(` - ${m}`));
363
+ }
364
+ console.log();
365
+ process.exit(1);
366
+ }
367
+
368
+ if (moduleName === 'email-verification') {
369
+ // Check if already applied
370
+ const alreadyApplied = await fs.pathExists(
371
+ path.join(projectDir, 'server', 'src', 'modules', 'auth', 'verification.service.ts'),
372
+ );
373
+ if (alreadyApplied) {
374
+ console.log(chalk.yellow(' Email verification is already installed in this project.'));
375
+ console.log();
376
+ process.exit(0);
377
+ }
378
+
379
+ const spinner = ora('Adding email verification module...').start();
380
+
381
+ try {
382
+ const { applyEmailVerificationModule } = await import(
383
+ '../lib/patchers/email-verification.patcher.js'
384
+ );
385
+ await applyEmailVerificationModule(projectDir);
386
+
387
+ // Set REQUIRE_USER_VERIFICATION=true in .env if it's currently false
388
+ for (const envFile of ['server/.env.example', 'server/.env']) {
389
+ const envPath = path.join(projectDir, envFile);
390
+ if (await fs.pathExists(envPath)) {
391
+ const content = await fs.readFile(envPath, 'utf-8');
392
+ if (content.includes('REQUIRE_USER_VERIFICATION=false')) {
393
+ await fs.writeFile(
394
+ envPath,
395
+ content.replace('REQUIRE_USER_VERIFICATION=false', 'REQUIRE_USER_VERIFICATION=true'),
396
+ 'utf-8',
397
+ );
398
+ }
399
+ }
400
+ }
401
+
402
+ spinner.succeed('Email verification module added!');
403
+ } catch (error) {
404
+ spinner.fail('Failed to add email verification module');
405
+ console.error(chalk.red(`\n ${error.message}\n`));
406
+ process.exit(1);
407
+ }
408
+
409
+ const dim = chalk.dim;
410
+ const cyan = chalk.cyan;
411
+ const green = chalk.green;
412
+
413
+ console.log();
414
+ console.log(green(' ✓ ') + 'Files added:');
415
+ console.log(dim(' server/src/modules/auth/verification.service.ts'));
416
+ console.log(dim(' server/src/modules/auth/verification.controller.ts'));
417
+ console.log(dim(' client/src/features/auth/services/verification.service.ts'));
418
+ console.log(dim(' client/src/features/auth/hooks/useVerification.ts'));
419
+ console.log();
420
+ console.log(green(' ✓ ') + 'Files patched:');
421
+ console.log(dim(' auth.routes.ts, auth.schemas.ts, auth.service.ts, auth.repo.ts'));
422
+ console.log(dim(' rate-limit.config.ts, api-endpoints.ts, error.ts, useAuth.ts'));
423
+ console.log(dim(' postman/collection.json'));
424
+ console.log();
425
+ console.log(green(' ✓ ') + 'REQUIRE_USER_VERIFICATION=true in server/.env');
426
+ console.log();
427
+ console.log(dim(' Next steps:'));
428
+ console.log(cyan(' 1 ') + 'Set ' + chalk.bold('RESEND_API_KEY') + ' in server/.env');
429
+ console.log(cyan(' 2 ') + 'Restart the server');
430
+ console.log();
431
+ }
432
+ });
433
+
290
434
  program.parse();
291
435
  }
292
436