create-better-t-stack 3.21.6 → 3.21.7

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/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { l as createBtsCli } from "./src-DS7GWAzq.mjs";
2
+ import { l as createBtsCli } from "./src-BEc5W50Y.mjs";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { _ as DatabaseSetupError, a as VirtualFileSystem, b as UserCancelledError, c as create, d as docs, f as generate, g as CompatibilityError, h as CLIError, i as TEMPLATE_COUNT, l as createBtsCli, m as sponsors, n as GeneratorError, o as add, p as router, r as Result, s as builder, t as EMBEDDED_TEMPLATES, u as createVirtual, v as DirectoryConflictError, x as ValidationError, y as ProjectCreationError } from "./src-DS7GWAzq.mjs";
2
+ import { _ as DatabaseSetupError, a as VirtualFileSystem, b as UserCancelledError, c as create, d as docs, f as generate, g as CompatibilityError, h as CLIError, i as TEMPLATE_COUNT, l as createBtsCli, m as sponsors, n as GeneratorError, o as add, p as router, r as Result, s as builder, t as EMBEDDED_TEMPLATES, u as createVirtual, v as DirectoryConflictError, x as ValidationError, y as ProjectCreationError } from "./src-BEc5W50Y.mjs";
3
3
 
4
4
  export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, Result, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, router, sponsors };
@@ -430,28 +430,65 @@ async function openUrl(url) {
430
430
  //#endregion
431
431
  //#region src/utils/sponsors.ts
432
432
  const SPONSORS_JSON_URL = "https://sponsors.better-t-stack.dev/sponsors.json";
433
+ const GITHUB_SPONSOR_URL = "https://github.com/sponsors/AmanVarshney01";
434
+ const nullableString = z.string().nullish().transform((value) => value ?? void 0);
435
+ const nullableNumber = z.number().nullish().transform((value) => value ?? void 0);
436
+ const sponsorSchema = z.object({
437
+ name: nullableString,
438
+ githubId: z.string(),
439
+ avatarUrl: z.string(),
440
+ websiteUrl: nullableString,
441
+ githubUrl: z.string(),
442
+ tierName: nullableString,
443
+ sinceWhen: z.string(),
444
+ transactionCount: z.number(),
445
+ totalProcessedAmount: nullableNumber,
446
+ formattedAmount: nullableString
447
+ });
448
+ const sponsorSummarySchema = z.object({
449
+ total_sponsors: z.number(),
450
+ total_lifetime_amount: z.number(),
451
+ total_current_monthly: z.number(),
452
+ special_sponsors: z.number(),
453
+ current_sponsors: z.number(),
454
+ past_sponsors: z.number(),
455
+ backers: z.number(),
456
+ top_sponsor: z.object({
457
+ name: z.string(),
458
+ amount: z.number()
459
+ }).nullish().transform((value) => value ?? void 0)
460
+ });
461
+ const sponsorEntrySchema = z.object({
462
+ generated_at: z.string(),
463
+ summary: sponsorSummarySchema,
464
+ specialSponsors: z.array(sponsorSchema),
465
+ sponsors: z.array(sponsorSchema),
466
+ pastSponsors: z.array(sponsorSchema),
467
+ backers: z.array(sponsorSchema)
468
+ });
433
469
  async function fetchSponsors(url = SPONSORS_JSON_URL) {
434
- const s = spinner();
435
- s.start("Fetching sponsors…");
436
- const response = await fetch(url);
437
- if (!response.ok) {
438
- s.stop(pc.red(`Failed to fetch sponsors: ${response.statusText}`));
439
- throw new Error(`Failed to fetch sponsors: ${response.statusText}`);
440
- }
441
- const sponsors = await response.json();
442
- s.stop("Sponsors fetched successfully!");
443
- return sponsors;
470
+ return fetchSponsorsData({
471
+ url,
472
+ withSpinner: true
473
+ });
474
+ }
475
+ async function fetchSponsorsQuietly({ url = SPONSORS_JSON_URL, timeoutMs = 1500 } = {}) {
476
+ return fetchSponsorsData({
477
+ url,
478
+ withSpinner: false,
479
+ timeoutMs
480
+ });
444
481
  }
445
482
  function displaySponsors(sponsors) {
446
483
  const { total_sponsors } = sponsors.summary;
447
484
  if (total_sponsors === 0) {
448
485
  log.info("No sponsors found. You can be the first one! ✨");
449
- outro(pc.cyan("Visit https://github.com/sponsors/AmanVarshney01 to become a sponsor."));
486
+ outro(pc.cyan(`Visit ${GITHUB_SPONSOR_URL} to become a sponsor.`));
450
487
  return;
451
488
  }
452
489
  displaySponsorsBox(sponsors);
453
490
  if (total_sponsors - sponsors.specialSponsors.length > 0) log.message(pc.blue(`+${total_sponsors - sponsors.specialSponsors.length} more amazing sponsors.\n`));
454
- outro(pc.magenta("Visit https://github.com/sponsors/AmanVarshney01 to become a sponsor."));
491
+ outro(pc.magenta(`Visit ${GITHUB_SPONSOR_URL} to become a sponsor.`));
455
492
  }
456
493
  function displaySponsorsBox(sponsors) {
457
494
  if (sponsors.specialSponsors.length === 0) return;
@@ -467,6 +504,92 @@ function displaySponsorsBox(sponsors) {
467
504
  });
468
505
  consola$1.box(output);
469
506
  }
507
+ function formatPostInstallSpecialSponsorsSection(sponsors) {
508
+ if (sponsors.specialSponsors.length === 0) return "";
509
+ const wrappedSponsorLines = wrapSponsorTokens(sponsors.specialSponsors.map((sponsor) => {
510
+ return `• ${sponsor.name ?? sponsor.githubId}`;
511
+ }), getPostInstallSponsorLineWidth());
512
+ let output = `${pc.bold("Special sponsors")}\n`;
513
+ wrappedSponsorLines.forEach((line) => {
514
+ output += `${line}\n`;
515
+ });
516
+ return output.trimEnd();
517
+ }
518
+ function getPostInstallSponsorLineWidth() {
519
+ const terminalWidth = process.stdout.columns;
520
+ if (!terminalWidth || terminalWidth <= 0) return 72;
521
+ const availableWidth = Math.max(8, terminalWidth - 24);
522
+ return Math.min(72, availableWidth);
523
+ }
524
+ function wrapSponsorTokens(tokens, maxLineWidth) {
525
+ const lines = [];
526
+ const separator = " ";
527
+ let currentLine = "";
528
+ tokens.forEach((token) => {
529
+ const candidateLine = currentLine ? `${currentLine}${separator}${token}` : token;
530
+ if (candidateLine.length <= maxLineWidth) {
531
+ currentLine = candidateLine;
532
+ return;
533
+ }
534
+ if (currentLine) {
535
+ lines.push(currentLine);
536
+ currentLine = token;
537
+ return;
538
+ }
539
+ lines.push(token);
540
+ });
541
+ if (currentLine) lines.push(currentLine);
542
+ return lines;
543
+ }
544
+ async function fetchSponsorsData({ url = SPONSORS_JSON_URL, withSpinner = false, timeoutMs }) {
545
+ const s = withSpinner ? spinner() : null;
546
+ if (s) s.start("Fetching sponsors…");
547
+ const controller = timeoutMs ? new AbortController() : null;
548
+ const timeout = timeoutMs ? setTimeout(() => {
549
+ controller?.abort();
550
+ }, timeoutMs) : null;
551
+ try {
552
+ const response = await fetch(url, controller ? { signal: controller.signal } : void 0);
553
+ if (!response.ok) {
554
+ const message = `Failed to fetch sponsors: ${response.statusText || String(response.status)}`;
555
+ if (s) s.stop(pc.red(message));
556
+ return Result.err(new CLIError({ message }));
557
+ }
558
+ const rawSponsors = await response.json();
559
+ const parseResult = sponsorEntrySchema.safeParse(rawSponsors);
560
+ if (!parseResult.success) {
561
+ const message = `Failed to fetch sponsors: invalid response format at "${parseResult.error.issues[0]?.path?.join(".") || "unknown"}"`;
562
+ if (s) s.stop(pc.red(message));
563
+ return Result.err(new CLIError({
564
+ message,
565
+ cause: parseResult.error
566
+ }));
567
+ }
568
+ if (s) s.stop("Sponsors fetched successfully!");
569
+ return Result.ok(parseResult.data);
570
+ } catch (error) {
571
+ const normalizedError = normalizeSponsorFetchError(error);
572
+ if (s) s.stop(pc.red(normalizedError.message));
573
+ return Result.err(normalizedError);
574
+ } finally {
575
+ if (timeout) clearTimeout(timeout);
576
+ }
577
+ }
578
+ function normalizeSponsorFetchError(error) {
579
+ if (error instanceof Error && error.name === "AbortError") return new CLIError({
580
+ message: "Failed to fetch sponsors: request timed out",
581
+ cause: error
582
+ });
583
+ if (CLIError.is(error)) return error;
584
+ if (error instanceof Error) return new CLIError({
585
+ message: error.message.startsWith("Failed to fetch sponsors:") ? error.message : `Failed to fetch sponsors: ${error.message}`,
586
+ cause: error
587
+ });
588
+ return new CLIError({
589
+ message: `Failed to fetch sponsors: ${String(error)}`,
590
+ cause: error
591
+ });
592
+ }
470
593
 
471
594
  //#endregion
472
595
  //#region src/commands/meta.ts
@@ -480,21 +603,15 @@ async function openExternalUrl(url, successMessage) {
480
603
  else log.message(`Please visit ${url}`);
481
604
  }
482
605
  async function showSponsorsCommand() {
483
- const result = await Result.tryPromise({
484
- try: async () => {
485
- renderTitle();
486
- intro(pc.magenta("Better-T-Stack Sponsors"));
487
- displaySponsors(await fetchSponsors());
488
- },
489
- catch: (error) => new CLIError({
490
- message: error instanceof Error ? error.message : "Failed to display sponsors",
491
- cause: error
492
- })
493
- });
494
- if (result.isErr()) {
495
- displayError(result.error);
606
+ renderTitle();
607
+ intro(pc.magenta("Better-T-Stack Sponsors"));
608
+ const sponsorsResult = await fetchSponsors();
609
+ if (sponsorsResult.isErr()) {
610
+ displayError(sponsorsResult.error);
496
611
  process.exit(1);
612
+ return;
497
613
  }
614
+ displaySponsors(sponsorsResult.value);
498
615
  }
499
616
  async function openDocsCommand() {
500
617
  await openExternalUrl(DOCS_URL, "Opened docs in your default browser.");
@@ -1804,6 +1921,7 @@ const SKILL_SOURCES = {
1804
1921
  "nuxt/ui": { label: "Nuxt UI" },
1805
1922
  "heroui-inc/heroui": { label: "HeroUI Native" },
1806
1923
  "better-auth/skills": { label: "Better Auth" },
1924
+ "clerk/skills": { label: "Clerk" },
1807
1925
  "neondatabase/agent-skills": { label: "Neon Database" },
1808
1926
  "supabase/agent-skills": { label: "Supabase" },
1809
1927
  "planetscale/database-skills": { label: "PlanetScale" },
@@ -1931,6 +2049,7 @@ function getRecommendedSourceKeys(config) {
1931
2049
  if (frontend.includes("native-uniwind")) sources.push("heroui-inc/heroui");
1932
2050
  if (hasNativeFrontend(frontend)) sources.push("expo/skills");
1933
2051
  if (auth === "better-auth") sources.push("better-auth/skills");
2052
+ if (auth === "clerk") sources.push("clerk/skills");
1934
2053
  if (dbSetup === "neon") sources.push("neondatabase/agent-skills");
1935
2054
  if (dbSetup === "supabase") sources.push("supabase/agent-skills");
1936
2055
  if (dbSetup === "planetscale") sources.push("planetscale/database-skills");
@@ -1961,6 +2080,18 @@ const CURATED_SKILLS_BY_SOURCE = {
1961
2080
  "nuxt/ui": () => ["nuxt-ui"],
1962
2081
  "heroui-inc/heroui": () => ["heroui-native"],
1963
2082
  "better-auth/skills": () => ["better-auth-best-practices"],
2083
+ "clerk/skills": (config) => {
2084
+ const skills = [
2085
+ "clerk",
2086
+ "clerk-setup",
2087
+ "clerk-custom-ui",
2088
+ "clerk-webhooks",
2089
+ "clerk-testing",
2090
+ "clerk-orgs"
2091
+ ];
2092
+ if (config.frontend.includes("next")) skills.push("clerk-nextjs-patterns");
2093
+ return skills;
2094
+ },
1964
2095
  "neondatabase/agent-skills": () => ["neon-postgres"],
1965
2096
  "supabase/agent-skills": () => ["supabase-postgres-best-practices"],
1966
2097
  "planetscale/database-skills": (config) => {
@@ -5554,6 +5685,9 @@ async function displayPostInstallInstructions(config) {
5554
5685
  if (polarInstructions) output += `\n${polarInstructions.trim()}\n`;
5555
5686
  if (noOrmWarning) output += `\n${noOrmWarning.trim()}\n`;
5556
5687
  if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
5688
+ const sponsorsResult = await fetchSponsorsQuietly();
5689
+ const specialSponsorsSection = sponsorsResult.isOk() ? formatPostInstallSpecialSponsorsSection(sponsorsResult.value) : "";
5690
+ if (specialSponsorsSection) output += `\n${specialSponsorsSection.trim()}\n`;
5557
5691
  output += `\n${pc.bold("Like Better-T-Stack?")} Please consider giving us a star\n on GitHub:\n`;
5558
5692
  output += pc.cyan("https://github.com/AmanVarshney01/create-better-t-stack");
5559
5693
  consola$1.box(output);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "3.21.6",
3
+ "version": "3.21.7",
4
4
  "description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
5
5
  "keywords": [
6
6
  "better-auth",
@@ -70,8 +70,8 @@
70
70
  "prepublishOnly": "npm run build"
71
71
  },
72
72
  "dependencies": {
73
- "@better-t-stack/template-generator": "^3.21.6",
74
- "@better-t-stack/types": "^3.21.6",
73
+ "@better-t-stack/template-generator": "^3.21.7",
74
+ "@better-t-stack/types": "^3.21.7",
75
75
  "@clack/core": "^1.0.0",
76
76
  "@clack/prompts": "^1.0.0",
77
77
  "@orpc/server": "^1.13.4",