bunkit-cli 1.2.1 → 1.3.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 (2) hide show
  1. package/dist/index.js +1499 -67
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14851,7 +14851,396 @@ var init_monorepo = __esm(() => {
14851
14851
  init_fs();
14852
14852
  });
14853
14853
 
14854
- // ../core/src/presets.ts
14854
+ // ../core/src/presets/registry.ts
14855
+ class PresetRegistry {
14856
+ static aliasMap = null;
14857
+ static getAliasMap() {
14858
+ if (!this.aliasMap) {
14859
+ this.aliasMap = new Map;
14860
+ for (const [name, definition] of Object.entries(PRESET_DEFINITIONS)) {
14861
+ this.aliasMap.set(name, name);
14862
+ for (const alias of definition.aliases) {
14863
+ this.aliasMap.set(alias, name);
14864
+ }
14865
+ }
14866
+ }
14867
+ return this.aliasMap;
14868
+ }
14869
+ static normalize(input) {
14870
+ const map = this.getAliasMap();
14871
+ return map.get(input) || null;
14872
+ }
14873
+ static get(input) {
14874
+ const normalized = this.normalize(input);
14875
+ if (!normalized)
14876
+ return null;
14877
+ return PRESET_DEFINITIONS[normalized];
14878
+ }
14879
+ static hasCapability(input, capability) {
14880
+ const preset = this.get(input);
14881
+ if (!preset)
14882
+ return false;
14883
+ return preset.capabilities[capability];
14884
+ }
14885
+ static isMonorepo(input) {
14886
+ return this.hasCapability(input, "isMonorepo");
14887
+ }
14888
+ static getSelectOptions() {
14889
+ return Object.values(PRESET_DEFINITIONS).map((preset) => ({
14890
+ value: preset.name,
14891
+ label: `${preset.emoji} ${preset.displayName}`,
14892
+ hint: preset.hint
14893
+ }));
14894
+ }
14895
+ static getPresetsWithCapability(capability) {
14896
+ return Object.values(PRESET_DEFINITIONS).filter((preset) => preset.capabilities[capability]);
14897
+ }
14898
+ static isValid(input) {
14899
+ return this.normalize(input) !== null;
14900
+ }
14901
+ static getAllValidNames() {
14902
+ return Array.from(this.getAliasMap().keys());
14903
+ }
14904
+ }
14905
+ var PRESET_DEFINITIONS;
14906
+ var init_registry = __esm(() => {
14907
+ PRESET_DEFINITIONS = {
14908
+ minimal: {
14909
+ name: "minimal",
14910
+ displayName: "Minimal",
14911
+ description: "Single-file Bun project",
14912
+ hint: "Single-file Bun project - perfect for CLIs and scripts",
14913
+ emoji: "\u26A1",
14914
+ aliases: [],
14915
+ capabilities: {
14916
+ database: false,
14917
+ cssFramework: false,
14918
+ uiLibrary: false,
14919
+ auth: false,
14920
+ redis: false,
14921
+ docker: true,
14922
+ cicd: true,
14923
+ isMonorepo: false,
14924
+ hasApi: false,
14925
+ hasWeb: false
14926
+ },
14927
+ devCommand: "bun run dev",
14928
+ rootDependencies: {},
14929
+ rootDevDependencies: {
14930
+ "@types/bun": "latest",
14931
+ typescript: "^5.9.3"
14932
+ }
14933
+ },
14934
+ nextjs: {
14935
+ name: "nextjs",
14936
+ displayName: "Next.js Application",
14937
+ description: "Next.js 16 + React 19 + Tailwind CSS 4",
14938
+ hint: "Next.js 16 + React 19 + Tailwind CSS 4 - production-ready web app (single repo)",
14939
+ emoji: "\uD83C\uDF10",
14940
+ aliases: ["web"],
14941
+ capabilities: {
14942
+ database: true,
14943
+ cssFramework: true,
14944
+ uiLibrary: true,
14945
+ auth: true,
14946
+ redis: false,
14947
+ docker: true,
14948
+ cicd: true,
14949
+ isMonorepo: false,
14950
+ hasApi: false,
14951
+ hasWeb: true
14952
+ },
14953
+ devCommand: "bun dev",
14954
+ rootDependencies: {
14955
+ react: "^19.2.3",
14956
+ "react-dom": "^19.2.3",
14957
+ next: "^16.0.10"
14958
+ },
14959
+ rootDevDependencies: {
14960
+ "@types/bun": "latest",
14961
+ "@types/react": "^19.2.7",
14962
+ "@types/react-dom": "^19.2.3",
14963
+ "@types/node": "^25.0.3",
14964
+ typescript: "^5.9.3",
14965
+ tailwindcss: "^4.1.18",
14966
+ "@tailwindcss/postcss": "^4.1.18",
14967
+ postcss: "^8.5.6"
14968
+ }
14969
+ },
14970
+ "hono-api": {
14971
+ name: "hono-api",
14972
+ displayName: "Hono API Server",
14973
+ description: "Hono 4 + Bun.serve()",
14974
+ hint: "Hono 4 + Bun.serve() - full-featured API with middleware ecosystem (single repo)",
14975
+ emoji: "\uD83D\uDE80",
14976
+ aliases: ["api"],
14977
+ capabilities: {
14978
+ database: true,
14979
+ cssFramework: false,
14980
+ uiLibrary: false,
14981
+ auth: true,
14982
+ redis: true,
14983
+ docker: true,
14984
+ cicd: true,
14985
+ isMonorepo: false,
14986
+ hasApi: true,
14987
+ hasWeb: false
14988
+ },
14989
+ devCommand: "bun run dev",
14990
+ rootDependencies: {
14991
+ hono: "^4.11.1"
14992
+ },
14993
+ rootDevDependencies: {
14994
+ "@types/bun": "latest",
14995
+ typescript: "^5.9.3"
14996
+ }
14997
+ },
14998
+ "bun-api": {
14999
+ name: "bun-api",
15000
+ displayName: "Bun Native API",
15001
+ description: "Bun.serve() native routing",
15002
+ hint: "Bun.serve() native routing - ultra-fast API with zero dependencies (single repo)",
15003
+ emoji: "\u26A1",
15004
+ aliases: [],
15005
+ capabilities: {
15006
+ database: true,
15007
+ cssFramework: false,
15008
+ uiLibrary: false,
15009
+ auth: true,
15010
+ redis: true,
15011
+ docker: true,
15012
+ cicd: true,
15013
+ isMonorepo: false,
15014
+ hasApi: true,
15015
+ hasWeb: false
15016
+ },
15017
+ devCommand: "bun run dev",
15018
+ rootDependencies: {},
15019
+ rootDevDependencies: {
15020
+ "@types/bun": "latest",
15021
+ typescript: "^5.9.3"
15022
+ }
15023
+ },
15024
+ "bun-fullstack": {
15025
+ name: "bun-fullstack",
15026
+ displayName: "Bun Full-Stack",
15027
+ description: "Bun.serve() + HTML imports",
15028
+ hint: "Bun.serve() + HTML imports - full-stack app without Next.js (single repo)",
15029
+ emoji: "\uD83D\uDD25",
15030
+ aliases: [],
15031
+ capabilities: {
15032
+ database: true,
15033
+ cssFramework: true,
15034
+ uiLibrary: true,
15035
+ auth: true,
15036
+ redis: true,
15037
+ docker: true,
15038
+ cicd: true,
15039
+ isMonorepo: false,
15040
+ hasApi: true,
15041
+ hasWeb: true
15042
+ },
15043
+ devCommand: "bun run dev",
15044
+ rootDependencies: {},
15045
+ rootDevDependencies: {
15046
+ "@types/bun": "latest",
15047
+ typescript: "^5.9.3",
15048
+ tailwindcss: "^4.1.18",
15049
+ "@tailwindcss/postcss": "^4.1.18",
15050
+ postcss: "^8.5.6"
15051
+ }
15052
+ },
15053
+ "nextjs-monorepo": {
15054
+ name: "nextjs-monorepo",
15055
+ displayName: "Next.js Monorepo",
15056
+ description: "Next.js + Hono + shared packages",
15057
+ hint: "Next.js + Hono + shared packages - enterprise SaaS architecture",
15058
+ emoji: "\uD83D\uDCE6",
15059
+ aliases: ["full", "monorepo-nextjs"],
15060
+ capabilities: {
15061
+ database: true,
15062
+ cssFramework: true,
15063
+ uiLibrary: true,
15064
+ auth: true,
15065
+ redis: true,
15066
+ docker: true,
15067
+ cicd: true,
15068
+ isMonorepo: true,
15069
+ hasApi: true,
15070
+ hasWeb: true
15071
+ },
15072
+ workspaceStructure: {
15073
+ apps: ["web", "platform", "api"],
15074
+ packages: ["ui", "types", "utils"],
15075
+ tooling: ["typescript"]
15076
+ },
15077
+ devCommand: "bun dev",
15078
+ rootDependencies: {},
15079
+ rootDevDependencies: {
15080
+ "@types/bun": "latest",
15081
+ typescript: "catalog:"
15082
+ },
15083
+ catalogEntries: {
15084
+ react: "^19.2.3",
15085
+ "react-dom": "^19.2.3",
15086
+ next: "^16.0.10",
15087
+ "@types/react": "^19.2.7",
15088
+ "@types/react-dom": "^19.2.3",
15089
+ hono: "^4.11.1",
15090
+ "drizzle-orm": "^0.45.1",
15091
+ "drizzle-kit": "^0.31.8",
15092
+ postgres: "^3.4.7",
15093
+ "@supabase/supabase-js": "^2.88.0",
15094
+ tailwindcss: "^4.1.18",
15095
+ "@tailwindcss/postcss": "^4.1.18",
15096
+ postcss: "^8.5.6",
15097
+ autoprefixer: "^10.4.23",
15098
+ "radix-ui": "^1.4.3",
15099
+ "@radix-ui/react-slot": "^1.2.4",
15100
+ "@base-ui/react": "^1.0.0",
15101
+ shadcn: "^3.6.2",
15102
+ "class-variance-authority": "^0.7.1",
15103
+ clsx: "^2.1.1",
15104
+ "tailwind-merge": "^3.4.0",
15105
+ "tw-animate-css": "^1.4.0",
15106
+ "@phosphor-icons/react": "^2.1.10",
15107
+ "iconoir-react": "^7.11.0",
15108
+ ultracite: "^6.4.2",
15109
+ "@biomejs/biome": "^2.3.10",
15110
+ vitest: "^4.0.16",
15111
+ "@vitest/ui": "^4.0.16",
15112
+ "@types/node": "^25.0.3",
15113
+ typescript: "^5.9.3"
15114
+ }
15115
+ },
15116
+ "bun-monorepo": {
15117
+ name: "bun-monorepo",
15118
+ displayName: "Bun Monorepo",
15119
+ description: "Full-stack monorepo with Bun.serve()",
15120
+ hint: "Full-stack monorepo with Bun.serve() - no Next.js",
15121
+ emoji: "\uD83D\uDD25",
15122
+ aliases: ["monorepo-bun"],
15123
+ capabilities: {
15124
+ database: true,
15125
+ cssFramework: true,
15126
+ uiLibrary: true,
15127
+ auth: true,
15128
+ redis: true,
15129
+ docker: true,
15130
+ cicd: true,
15131
+ isMonorepo: true,
15132
+ hasApi: true,
15133
+ hasWeb: true
15134
+ },
15135
+ workspaceStructure: {
15136
+ apps: ["web", "api"],
15137
+ packages: ["ui", "types", "utils"],
15138
+ tooling: ["typescript"]
15139
+ },
15140
+ devCommand: "bun dev",
15141
+ rootDependencies: {},
15142
+ rootDevDependencies: {
15143
+ "@types/bun": "latest",
15144
+ typescript: "catalog:"
15145
+ },
15146
+ catalogEntries: {
15147
+ react: "^19.2.3",
15148
+ "react-dom": "^19.2.3",
15149
+ "@types/react": "^19.2.7",
15150
+ "@types/react-dom": "^19.2.3",
15151
+ "drizzle-orm": "^0.45.1",
15152
+ "drizzle-kit": "^0.31.8",
15153
+ postgres: "^3.4.7",
15154
+ "@supabase/supabase-js": "^2.88.0",
15155
+ tailwindcss: "^4.1.18",
15156
+ "@tailwindcss/postcss": "^4.1.18",
15157
+ postcss: "^8.5.6",
15158
+ autoprefixer: "^10.4.23",
15159
+ "radix-ui": "^1.4.3",
15160
+ "@radix-ui/react-slot": "^1.2.4",
15161
+ "@base-ui/react": "^1.0.0",
15162
+ shadcn: "^3.6.2",
15163
+ "class-variance-authority": "^0.7.1",
15164
+ clsx: "^2.1.1",
15165
+ "tailwind-merge": "^3.4.0",
15166
+ "tw-animate-css": "^1.4.0",
15167
+ "@phosphor-icons/react": "^2.1.10",
15168
+ "iconoir-react": "^7.11.0",
15169
+ ultracite: "^6.4.2",
15170
+ "@biomejs/biome": "^2.3.10",
15171
+ vitest: "^4.0.16",
15172
+ "@vitest/ui": "^4.0.16",
15173
+ "@types/node": "^25.0.3",
15174
+ typescript: "^5.9.3"
15175
+ }
15176
+ },
15177
+ "enterprise-monorepo": {
15178
+ name: "enterprise-monorepo",
15179
+ displayName: "Enterprise Monorepo",
15180
+ description: "Multiple Next.js apps + services",
15181
+ hint: "Multiple Next.js apps + services - platform, app, service-identity",
15182
+ emoji: "\uD83C\uDFE2",
15183
+ aliases: [],
15184
+ capabilities: {
15185
+ database: true,
15186
+ cssFramework: true,
15187
+ uiLibrary: true,
15188
+ auth: true,
15189
+ redis: true,
15190
+ docker: true,
15191
+ cicd: true,
15192
+ isMonorepo: true,
15193
+ hasApi: true,
15194
+ hasWeb: true
15195
+ },
15196
+ workspaceStructure: {
15197
+ apps: ["web", "platform", "admin", "api", "service-identity"],
15198
+ packages: ["ui", "types", "utils", "db", "auth"],
15199
+ tooling: ["typescript", "testing"]
15200
+ },
15201
+ devCommand: "bun dev",
15202
+ rootDependencies: {},
15203
+ rootDevDependencies: {
15204
+ "@types/bun": "latest",
15205
+ typescript: "catalog:"
15206
+ },
15207
+ catalogEntries: {
15208
+ react: "^19.2.3",
15209
+ "react-dom": "^19.2.3",
15210
+ next: "^16.0.10",
15211
+ "@types/react": "^19.2.7",
15212
+ "@types/react-dom": "^19.2.3",
15213
+ hono: "^4.11.1",
15214
+ "drizzle-orm": "^0.45.1",
15215
+ "drizzle-kit": "^0.31.8",
15216
+ postgres: "^3.4.7",
15217
+ "@supabase/supabase-js": "^2.88.0",
15218
+ tailwindcss: "^4.1.18",
15219
+ "@tailwindcss/postcss": "^4.1.18",
15220
+ postcss: "^8.5.6",
15221
+ autoprefixer: "^10.4.23",
15222
+ "radix-ui": "^1.4.3",
15223
+ "@radix-ui/react-slot": "^1.2.4",
15224
+ "@base-ui/react": "^1.0.0",
15225
+ shadcn: "^3.6.2",
15226
+ "class-variance-authority": "^0.7.1",
15227
+ clsx: "^2.1.1",
15228
+ "tailwind-merge": "^3.4.0",
15229
+ "tw-animate-css": "^1.4.0",
15230
+ "@phosphor-icons/react": "^2.1.10",
15231
+ "iconoir-react": "^7.11.0",
15232
+ ultracite: "^6.4.2",
15233
+ "@biomejs/biome": "^2.3.10",
15234
+ vitest: "^4.0.16",
15235
+ "@vitest/ui": "^4.0.16",
15236
+ "@types/node": "^25.0.3",
15237
+ typescript: "^5.9.3"
15238
+ }
15239
+ }
15240
+ };
15241
+ });
15242
+
15243
+ // ../core/src/presets/custom.ts
14855
15244
  function getPresetsDir() {
14856
15245
  return join(process.env.HOME || process.env.USERPROFILE || ".", ".bunkit");
14857
15246
  }
@@ -14896,11 +15285,17 @@ async function listCustomPresets() {
14896
15285
  const presets = await loadCustomPresets();
14897
15286
  return Object.values(presets);
14898
15287
  }
14899
- var init_presets = __esm(() => {
15288
+ var init_custom2 = __esm(() => {
14900
15289
  init_dist();
14901
15290
  init_fs();
14902
15291
  });
14903
15292
 
15293
+ // ../core/src/presets/index.ts
15294
+ var init_presets = __esm(() => {
15295
+ init_registry();
15296
+ init_custom2();
15297
+ });
15298
+
14904
15299
  // ../core/src/project.ts
14905
15300
  async function createProject(config) {
14906
15301
  const projectPath = join(process.cwd(), config.path);
@@ -19091,8 +19486,12 @@ var init_types2 = __esm(() => {
19091
19486
  tsStrictness: exports_external.enum(["strict", "moderate", "loose"]).default("strict"),
19092
19487
  uiLibrary: exports_external.enum(["shadcn", "none"]).optional(),
19093
19488
  cssFramework: exports_external.enum(["tailwind", "vanilla", "css-modules"]).optional(),
19094
- shadcnStyle: exports_external.enum(["new-york", "default"]).optional(),
19489
+ shadcnStyle: exports_external.enum(["radix-maia", "radix-vega", "radix-nova", "radix-lyra", "radix-mira", "new-york", "default"]).optional(),
19490
+ shadcnBase: exports_external.enum(["radix", "base-ui"]).optional(),
19095
19491
  shadcnBaseColor: exports_external.enum(["neutral", "gray", "zinc", "stone", "slate"]).optional(),
19492
+ shadcnIconLibrary: exports_external.enum(["phosphor", "lucide", "iconoir"]).optional(),
19493
+ shadcnMenuAccent: exports_external.enum(["subtle", "bold"]).optional(),
19494
+ shadcnMenuColor: exports_external.enum(["default", "muted"]).optional(),
19096
19495
  shadcnRadius: exports_external.string().optional(),
19097
19496
  testing: exports_external.enum(["bun-test", "vitest", "none"]).default("bun-test"),
19098
19497
  docker: exports_external.boolean().default(false),
@@ -19195,6 +19594,8 @@ __export(exports_src, {
19195
19594
  addWorkspaceToRoot: () => addWorkspaceToRoot,
19196
19595
  addToCatalog: () => addToCatalog,
19197
19596
  ProjectConfigSchema: () => ProjectConfigSchema,
19597
+ PresetRegistry: () => PresetRegistry,
19598
+ PRESET_DEFINITIONS: () => PRESET_DEFINITIONS,
19198
19599
  FeatureConfigSchema: () => FeatureConfigSchema
19199
19600
  });
19200
19601
  var init_src = __esm(() => {
@@ -21360,6 +21761,240 @@ var require_commander = __commonJS((exports) => {
21360
21761
  exports.InvalidOptionArgumentError = InvalidArgumentError;
21361
21762
  });
21362
21763
 
21764
+ // ../templates/src/shared/package-json.ts
21765
+ var exports_package_json = {};
21766
+ __export(exports_package_json, {
21767
+ writeUtilsPackageJson: () => writeUtilsPackageJson,
21768
+ writeUiPackageJson: () => writeUiPackageJson,
21769
+ writeTypesPackageJson: () => writeTypesPackageJson,
21770
+ writePackageJson: () => writePackageJson,
21771
+ writeNextjsAppPackageJson: () => writeNextjsAppPackageJson,
21772
+ writeMonorepoRootPackageJson: () => writeMonorepoRootPackageJson,
21773
+ writeHonoApiPackageJson: () => writeHonoApiPackageJson
21774
+ });
21775
+ async function writePackageJson(directory, options) {
21776
+ const packageJson = {
21777
+ name: options.name,
21778
+ version: options.version ?? "0.0.0"
21779
+ };
21780
+ if (options.private !== undefined) {
21781
+ packageJson.private = options.private;
21782
+ }
21783
+ if (options.description) {
21784
+ packageJson.description = options.description;
21785
+ }
21786
+ if (options.main) {
21787
+ packageJson.main = options.main;
21788
+ }
21789
+ if (options.types) {
21790
+ packageJson.types = options.types;
21791
+ }
21792
+ if (options.exports) {
21793
+ packageJson.exports = options.exports;
21794
+ }
21795
+ if (options.workspaces) {
21796
+ packageJson.workspaces = options.workspaces;
21797
+ }
21798
+ if (options.scripts && Object.keys(options.scripts).length > 0) {
21799
+ packageJson.scripts = options.scripts;
21800
+ }
21801
+ if (options.dependencies && Object.keys(options.dependencies).length > 0) {
21802
+ packageJson.dependencies = options.dependencies;
21803
+ }
21804
+ if (options.devDependencies && Object.keys(options.devDependencies).length > 0) {
21805
+ packageJson.devDependencies = options.devDependencies;
21806
+ }
21807
+ if (options.peerDependencies && Object.keys(options.peerDependencies).length > 0) {
21808
+ packageJson.peerDependencies = options.peerDependencies;
21809
+ }
21810
+ if (options.catalog && Object.keys(options.catalog).length > 0) {
21811
+ packageJson.catalog = options.catalog;
21812
+ }
21813
+ await writeFile(join(directory, "package.json"), JSON.stringify(packageJson, null, 2));
21814
+ }
21815
+ async function writeMonorepoRootPackageJson(projectPath, projectName, catalog, options = {}) {
21816
+ const scripts = {
21817
+ dev: 'bun run --filter "*" dev',
21818
+ build: 'bun run --filter "*" build',
21819
+ lint: options.codeQuality === "ultracite" ? "ultracite check ." : "biome check .",
21820
+ format: options.codeQuality === "ultracite" ? "ultracite fix ." : "biome format --write .",
21821
+ test: "bun test"
21822
+ };
21823
+ if (options.hasWeb) {
21824
+ scripts["dev:web"] = 'bun run --filter "@*/web" dev';
21825
+ }
21826
+ if (options.hasPlatform) {
21827
+ scripts["dev:platform"] = 'bun run --filter "@*/platform" dev';
21828
+ }
21829
+ if (options.hasApi) {
21830
+ scripts["dev:api"] = 'bun run --filter "@*/api" dev';
21831
+ scripts.debug = "bun --inspect apps/api/src/index.ts";
21832
+ scripts["debug:brk"] = "bun --inspect-brk apps/api/src/index.ts";
21833
+ scripts["debug:wait"] = "bun --inspect-wait apps/api/src/index.ts";
21834
+ }
21835
+ await writePackageJson(projectPath, {
21836
+ name: `${projectName}-monorepo`,
21837
+ version: "0.0.0",
21838
+ private: true,
21839
+ workspaces: ["apps/*", "packages/*"],
21840
+ scripts,
21841
+ devDependencies: {
21842
+ "@types/bun": "latest",
21843
+ typescript: "catalog:"
21844
+ },
21845
+ catalog
21846
+ });
21847
+ }
21848
+ async function writeNextjsAppPackageJson(appPath, scopeName, appName, options = {}) {
21849
+ const dependencies = {
21850
+ react: "catalog:",
21851
+ "react-dom": "catalog:",
21852
+ next: "catalog:",
21853
+ "iconoir-react": "catalog:"
21854
+ };
21855
+ if (options.usesTypes) {
21856
+ dependencies[`@${scopeName}/types`] = "workspace:*";
21857
+ }
21858
+ if (options.usesUi) {
21859
+ dependencies[`@${scopeName}/ui`] = "workspace:*";
21860
+ }
21861
+ const devDependencies = {
21862
+ "@types/react": "catalog:",
21863
+ "@types/react-dom": "catalog:",
21864
+ "@types/node": "catalog:",
21865
+ typescript: "catalog:",
21866
+ tailwindcss: "catalog:",
21867
+ "@tailwindcss/postcss": "catalog:",
21868
+ postcss: "catalog:"
21869
+ };
21870
+ await writePackageJson(appPath, {
21871
+ name: `@${scopeName}/${appName}`,
21872
+ version: "0.0.0",
21873
+ private: true,
21874
+ scripts: {
21875
+ dev: "next dev",
21876
+ build: "next build",
21877
+ start: "next start",
21878
+ debug: "bun --inspect node_modules/.bin/next dev",
21879
+ "debug:brk": "bun --inspect-brk node_modules/.bin/next dev",
21880
+ "debug:wait": "bun --inspect-wait node_modules/.bin/next dev"
21881
+ },
21882
+ dependencies,
21883
+ devDependencies
21884
+ });
21885
+ }
21886
+ async function writeHonoApiPackageJson(appPath, scopeName, options = {}) {
21887
+ const dependencies = {
21888
+ hono: "catalog:"
21889
+ };
21890
+ if (options.usesTypes) {
21891
+ dependencies[`@${scopeName}/types`] = "workspace:*";
21892
+ }
21893
+ if (options.usesDb) {
21894
+ dependencies[`@${scopeName}/db`] = "workspace:*";
21895
+ }
21896
+ await writePackageJson(appPath, {
21897
+ name: `@${scopeName}/api`,
21898
+ version: "0.0.0",
21899
+ private: true,
21900
+ scripts: {
21901
+ dev: "bun --hot src/index.ts",
21902
+ build: "bun build src/index.ts --outdir dist --target bun",
21903
+ start: "bun dist/index.js",
21904
+ debug: "bun --inspect src/index.ts",
21905
+ "debug:brk": "bun --inspect-brk src/index.ts",
21906
+ "debug:wait": "bun --inspect-wait src/index.ts"
21907
+ },
21908
+ dependencies,
21909
+ devDependencies: {
21910
+ "@types/bun": "latest",
21911
+ typescript: "catalog:"
21912
+ }
21913
+ });
21914
+ }
21915
+ async function writeUiPackageJson(packagePath, scopeName) {
21916
+ await writePackageJson(packagePath, {
21917
+ name: `@${scopeName}/ui`,
21918
+ version: "0.0.0",
21919
+ private: true,
21920
+ main: "./src/index.ts",
21921
+ types: "./src/index.ts",
21922
+ exports: {
21923
+ ".": "./src/index.ts",
21924
+ "./components": "./src/components/index.ts",
21925
+ "./lib/utils": "./src/lib/utils.ts",
21926
+ "./hooks": "./src/hooks/index.ts",
21927
+ "./globals.css": "./src/styles/globals.css",
21928
+ "./postcss.config": "./postcss.config.mjs"
21929
+ },
21930
+ scripts: {
21931
+ build: "tsc --noEmit",
21932
+ lint: "tsc --noEmit"
21933
+ },
21934
+ dependencies: {
21935
+ "@radix-ui/react-slot": "catalog:",
21936
+ "class-variance-authority": "catalog:",
21937
+ clsx: "catalog:",
21938
+ "tailwind-merge": "catalog:",
21939
+ "iconoir-react": "catalog:",
21940
+ tailwindcss: "catalog:",
21941
+ "@tailwindcss/postcss": "catalog:",
21942
+ postcss: "catalog:"
21943
+ },
21944
+ devDependencies: {
21945
+ "@types/react": "catalog:",
21946
+ "@types/react-dom": "catalog:",
21947
+ typescript: "catalog:"
21948
+ },
21949
+ peerDependencies: {
21950
+ react: "^19.0.0",
21951
+ "react-dom": "^19.0.0"
21952
+ }
21953
+ });
21954
+ }
21955
+ async function writeTypesPackageJson(packagePath, scopeName) {
21956
+ await writePackageJson(packagePath, {
21957
+ name: `@${scopeName}/types`,
21958
+ version: "0.0.0",
21959
+ private: true,
21960
+ main: "./src/index.ts",
21961
+ types: "./src/index.ts",
21962
+ exports: {
21963
+ ".": "./src/index.ts"
21964
+ },
21965
+ scripts: {
21966
+ build: "tsc --noEmit",
21967
+ lint: "tsc --noEmit"
21968
+ },
21969
+ devDependencies: {
21970
+ typescript: "catalog:"
21971
+ }
21972
+ });
21973
+ }
21974
+ async function writeUtilsPackageJson(packagePath, scopeName) {
21975
+ await writePackageJson(packagePath, {
21976
+ name: `@${scopeName}/utils`,
21977
+ version: "0.0.0",
21978
+ private: true,
21979
+ main: "./src/index.ts",
21980
+ types: "./src/index.ts",
21981
+ exports: {
21982
+ ".": "./src/index.ts"
21983
+ },
21984
+ scripts: {
21985
+ build: "tsc --noEmit",
21986
+ lint: "tsc --noEmit"
21987
+ },
21988
+ devDependencies: {
21989
+ typescript: "catalog:"
21990
+ }
21991
+ });
21992
+ }
21993
+ var init_package_json = __esm(() => {
21994
+ init_src();
21995
+ init_dist();
21996
+ });
21997
+
21363
21998
  // ../../node_modules/.bun/ejs@3.1.10/node_modules/ejs/lib/utils.js
21364
21999
  var require_utils5 = __commonJS((exports) => {
21365
22000
  var regExpChars = /[|\\{}()[\]^$+*?.]/g;
@@ -27823,12 +28458,7 @@ var themes = {
27823
28458
  };
27824
28459
  function generateThemeCSS(theme, customRadius) {
27825
28460
  const radius = customRadius || theme.light.radius;
27826
- return `@import "tailwindcss";
27827
- @source "../../../apps/**/*.{ts,tsx}";
27828
- @source "../../../components/**/*.{ts,tsx}";
27829
- @source "../**/*.{ts,tsx}";
27830
-
27831
- :root {
28461
+ return `:root {
27832
28462
  --radius: ${radius};
27833
28463
  --background: ${theme.light.background};
27834
28464
  --foreground: ${theme.light.foreground};
@@ -27947,58 +28577,183 @@ function generateThemeCSS(theme, customRadius) {
27947
28577
  }
27948
28578
  `;
27949
28579
  }
27950
-
27951
- // ../templates/src/generators/shadcn.ts
27952
- async function setupShadcnWeb(projectPath, context) {
27953
- await ensureDirectory(join(projectPath, "src/components/ui"));
27954
- await ensureDirectory(join(projectPath, "src/lib"));
27955
- const style = context.shadcnStyle || "new-york";
27956
- const baseColor = context.shadcnBaseColor || "zinc";
27957
- const radius = context.shadcnRadius || "0.625rem";
27958
- const componentsJson = {
27959
- $schema: "https://ui.shadcn.com/schema.json",
27960
- style,
27961
- rsc: true,
27962
- tsx: true,
27963
- tailwind: {
27964
- config: "",
27965
- css: "src/app/globals.css",
27966
- baseColor,
27967
- cssVariables: true
27968
- },
27969
- iconLibrary: "lucide",
27970
- aliases: {
27971
- components: "@/components",
27972
- utils: "@/lib/utils",
27973
- ui: "@/components/ui",
27974
- lib: "@/lib",
27975
- hooks: "@/hooks"
27976
- }
27977
- };
27978
- await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
27979
- const utilsContent = `import { clsx, type ClassValue } from 'clsx';
27980
- import { twMerge } from 'tailwind-merge';
27981
-
27982
- export function cn(...inputs: ClassValue[]) {
27983
- return twMerge(clsx(inputs));
28580
+ function generateModernThemeCSS(baseColor, customRadius) {
28581
+ const theme = themes[baseColor] || themes.zinc;
28582
+ const radius = customRadius || "0.625rem";
28583
+ return `@theme inline {
28584
+ --color-background: var(--background);
28585
+ --color-foreground: var(--foreground);
28586
+ --font-sans: var(--font-sans);
28587
+ --font-mono: var(--font-geist-mono);
28588
+ --color-sidebar-ring: var(--sidebar-ring);
28589
+ --color-sidebar-border: var(--sidebar-border);
28590
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
28591
+ --color-sidebar-accent: var(--sidebar-accent);
28592
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
28593
+ --color-sidebar-primary: var(--sidebar-primary);
28594
+ --color-sidebar-foreground: var(--sidebar-foreground);
28595
+ --color-sidebar: var(--sidebar);
28596
+ --color-chart-5: var(--chart-5);
28597
+ --color-chart-4: var(--chart-4);
28598
+ --color-chart-3: var(--chart-3);
28599
+ --color-chart-2: var(--chart-2);
28600
+ --color-chart-1: var(--chart-1);
28601
+ --color-ring: var(--ring);
28602
+ --color-input: var(--input);
28603
+ --color-border: var(--border);
28604
+ --color-destructive: var(--destructive);
28605
+ --color-accent-foreground: var(--accent-foreground);
28606
+ --color-accent: var(--accent);
28607
+ --color-muted-foreground: var(--muted-foreground);
28608
+ --color-muted: var(--muted);
28609
+ --color-secondary-foreground: var(--secondary-foreground);
28610
+ --color-secondary: var(--secondary);
28611
+ --color-primary-foreground: var(--primary-foreground);
28612
+ --color-primary: var(--primary);
28613
+ --color-popover-foreground: var(--popover-foreground);
28614
+ --color-popover: var(--popover);
28615
+ --color-card-foreground: var(--card-foreground);
28616
+ --color-card: var(--card);
28617
+ --radius-sm: calc(var(--radius) - 4px);
28618
+ --radius-md: calc(var(--radius) - 2px);
28619
+ --radius-lg: var(--radius);
28620
+ --radius-xl: calc(var(--radius) + 4px);
28621
+ --radius-2xl: calc(var(--radius) + 8px);
28622
+ --radius-3xl: calc(var(--radius) + 12px);
28623
+ --radius-4xl: calc(var(--radius) + 16px);
27984
28624
  }
27985
- `;
27986
- await writeFile(join(projectPath, "src/lib/utils.ts"), utilsContent);
27987
- const packageJsonPath = join(projectPath, "package.json");
27988
- let packageJson = {};
27989
- try {
27990
- packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
27991
- } catch {}
27992
- if (!packageJson.dependencies) {
27993
- packageJson.dependencies = {};
27994
- }
27995
- packageJson.dependencies["@radix-ui/react-slot"] = "catalog:";
27996
- packageJson.dependencies["class-variance-authority"] = "catalog:";
27997
- packageJson.dependencies.clsx = "catalog:";
27998
- packageJson.dependencies["tailwind-merge"] = "catalog:";
27999
- packageJson.dependencies["lucide-react"] = "catalog:";
28000
- if (!packageJson.catalog) {
28001
- packageJson.catalog = {};
28625
+
28626
+ :root {
28627
+ --background: ${theme.light.background};
28628
+ --foreground: ${theme.light.foreground};
28629
+ --card: ${theme.light.card};
28630
+ --card-foreground: ${theme.light.cardForeground};
28631
+ --popover: ${theme.light.popover};
28632
+ --popover-foreground: ${theme.light.popoverForeground};
28633
+ --primary: ${theme.light.primary};
28634
+ --primary-foreground: ${theme.light.primaryForeground};
28635
+ --secondary: ${theme.light.secondary};
28636
+ --secondary-foreground: ${theme.light.secondaryForeground};
28637
+ --muted: ${theme.light.muted};
28638
+ --muted-foreground: ${theme.light.mutedForeground};
28639
+ --accent: ${theme.light.accent};
28640
+ --accent-foreground: ${theme.light.accentForeground};
28641
+ --destructive: ${theme.light.destructive};
28642
+ --border: ${theme.light.border};
28643
+ --input: ${theme.light.input};
28644
+ --ring: ${theme.light.ring};
28645
+ --chart-1: ${theme.light.chart1};
28646
+ --chart-2: ${theme.light.chart2};
28647
+ --chart-3: ${theme.light.chart3};
28648
+ --chart-4: ${theme.light.chart4};
28649
+ --chart-5: ${theme.light.chart5};
28650
+ --radius: ${radius};
28651
+ --sidebar: ${theme.light.sidebar};
28652
+ --sidebar-foreground: ${theme.light.sidebarForeground};
28653
+ --sidebar-primary: ${theme.light.sidebarPrimary};
28654
+ --sidebar-primary-foreground: ${theme.light.sidebarPrimaryForeground};
28655
+ --sidebar-accent: ${theme.light.sidebarAccent};
28656
+ --sidebar-accent-foreground: ${theme.light.sidebarAccentForeground};
28657
+ --sidebar-border: ${theme.light.sidebarBorder};
28658
+ --sidebar-ring: ${theme.light.sidebarRing};
28659
+ }
28660
+
28661
+ .dark {
28662
+ --background: ${theme.dark.background};
28663
+ --foreground: ${theme.dark.foreground};
28664
+ --card: ${theme.dark.card};
28665
+ --card-foreground: ${theme.dark.cardForeground};
28666
+ --popover: ${theme.dark.popover};
28667
+ --popover-foreground: ${theme.dark.popoverForeground};
28668
+ --primary: ${theme.dark.primary};
28669
+ --primary-foreground: ${theme.dark.primaryForeground};
28670
+ --secondary: ${theme.dark.secondary};
28671
+ --secondary-foreground: ${theme.dark.secondaryForeground};
28672
+ --muted: ${theme.dark.muted};
28673
+ --muted-foreground: ${theme.dark.mutedForeground};
28674
+ --accent: ${theme.dark.accent};
28675
+ --accent-foreground: ${theme.dark.accentForeground};
28676
+ --destructive: ${theme.dark.destructive};
28677
+ --border: ${theme.dark.border};
28678
+ --input: ${theme.dark.input};
28679
+ --ring: ${theme.dark.ring};
28680
+ --chart-1: ${theme.dark.chart1};
28681
+ --chart-2: ${theme.dark.chart2};
28682
+ --chart-3: ${theme.dark.chart3};
28683
+ --chart-4: ${theme.dark.chart4};
28684
+ --chart-5: ${theme.dark.chart5};
28685
+ --sidebar: ${theme.dark.sidebar};
28686
+ --sidebar-foreground: ${theme.dark.sidebarForeground};
28687
+ --sidebar-primary: ${theme.dark.sidebarPrimary};
28688
+ --sidebar-primary-foreground: ${theme.dark.sidebarPrimaryForeground};
28689
+ --sidebar-accent: ${theme.dark.sidebarAccent};
28690
+ --sidebar-accent-foreground: ${theme.dark.sidebarAccentForeground};
28691
+ --sidebar-border: ${theme.dark.sidebarBorder};
28692
+ --sidebar-ring: ${theme.dark.sidebarRing};
28693
+ }
28694
+
28695
+ @layer base {
28696
+ * {
28697
+ @apply border-border outline-ring/50;
28698
+ }
28699
+ body {
28700
+ @apply bg-background text-foreground;
28701
+ }
28702
+ }
28703
+ `;
28704
+ }
28705
+
28706
+ // ../templates/src/generators/shadcn.ts
28707
+ async function setupShadcnWeb(projectPath, context) {
28708
+ await ensureDirectory(join(projectPath, "src/components/ui"));
28709
+ await ensureDirectory(join(projectPath, "src/lib"));
28710
+ const style = context.shadcnStyle || "new-york";
28711
+ const baseColor = context.shadcnBaseColor || "zinc";
28712
+ const radius = context.shadcnRadius || "0.625rem";
28713
+ const componentsJson = {
28714
+ $schema: "https://ui.shadcn.com/schema.json",
28715
+ style,
28716
+ rsc: true,
28717
+ tsx: true,
28718
+ tailwind: {
28719
+ config: "",
28720
+ css: "src/app/globals.css",
28721
+ baseColor,
28722
+ cssVariables: true
28723
+ },
28724
+ iconLibrary: "lucide",
28725
+ aliases: {
28726
+ components: "@/components",
28727
+ utils: "@/lib/utils",
28728
+ ui: "@/components/ui",
28729
+ lib: "@/lib",
28730
+ hooks: "@/hooks"
28731
+ }
28732
+ };
28733
+ await writeFile(join(projectPath, "components.json"), JSON.stringify(componentsJson, null, 2));
28734
+ const utilsContent = `import { clsx, type ClassValue } from 'clsx';
28735
+ import { twMerge } from 'tailwind-merge';
28736
+
28737
+ export function cn(...inputs: ClassValue[]) {
28738
+ return twMerge(clsx(inputs));
28739
+ }
28740
+ `;
28741
+ await writeFile(join(projectPath, "src/lib/utils.ts"), utilsContent);
28742
+ const packageJsonPath = join(projectPath, "package.json");
28743
+ let packageJson = {};
28744
+ try {
28745
+ packageJson = JSON.parse(await Bun.file(packageJsonPath).text());
28746
+ } catch {}
28747
+ if (!packageJson.dependencies) {
28748
+ packageJson.dependencies = {};
28749
+ }
28750
+ packageJson.dependencies["@radix-ui/react-slot"] = "catalog:";
28751
+ packageJson.dependencies["class-variance-authority"] = "catalog:";
28752
+ packageJson.dependencies.clsx = "catalog:";
28753
+ packageJson.dependencies["tailwind-merge"] = "catalog:";
28754
+ packageJson.dependencies["lucide-react"] = "catalog:";
28755
+ if (!packageJson.catalog) {
28756
+ packageJson.catalog = {};
28002
28757
  }
28003
28758
  packageJson.catalog["@radix-ui/react-slot"] = "^1.2.4";
28004
28759
  packageJson.catalog["class-variance-authority"] = "^0.7.1";
@@ -30266,6 +31021,622 @@ export default config;
30266
31021
  await writeFile(packageJsonPath, JSON.stringify(existingPackageJson, null, 2));
30267
31022
  await generateNextjsReadme(projectPath, context);
30268
31023
  }
31024
+ // ../templates/src/builders/full-v2.ts
31025
+ init_src();
31026
+ init_dist();
31027
+ init_package_json();
31028
+
31029
+ // ../templates/src/shared/ui-package.ts
31030
+ init_src();
31031
+ init_dist();
31032
+ init_package_json();
31033
+ function isModernStyle(style) {
31034
+ return style === "radix-maia" || style === "radix-vega" || style === "radix-nova" || style === "radix-lyra" || style === "radix-mira";
31035
+ }
31036
+ async function buildUiPackage(packagesPath, options) {
31037
+ const uiPath = join(packagesPath, "ui");
31038
+ await ensureDirectory(join(uiPath, "src/components"));
31039
+ await ensureDirectory(join(uiPath, "src/hooks"));
31040
+ await ensureDirectory(join(uiPath, "src/lib"));
31041
+ await ensureDirectory(join(uiPath, "src/styles"));
31042
+ await writeUiPackageJson(uiPath, options.scopeName);
31043
+ await writeFile(join(uiPath, "tsconfig.json"), JSON.stringify({
31044
+ extends: "../../tooling/typescript/library.json",
31045
+ compilerOptions: {
31046
+ jsx: "react-jsx",
31047
+ rootDir: "./src",
31048
+ outDir: "./dist",
31049
+ baseUrl: ".",
31050
+ paths: {
31051
+ "@/*": ["./src/*"]
31052
+ }
31053
+ },
31054
+ include: ["src/**/*"],
31055
+ exclude: ["node_modules"]
31056
+ }, null, 2));
31057
+ const style = options.shadcnStyle || "radix-maia";
31058
+ const useModernStyle = isModernStyle(style);
31059
+ const iconLibrary = options.shadcnIconLibrary || (useModernStyle ? "phosphor" : "iconoir");
31060
+ const componentsJson = {
31061
+ $schema: "https://ui.shadcn.com/schema.json",
31062
+ style,
31063
+ rsc: true,
31064
+ tsx: true,
31065
+ tailwind: {
31066
+ config: "",
31067
+ css: "./src/styles/globals.css",
31068
+ baseColor: options.shadcnBaseColor || "zinc",
31069
+ cssVariables: true,
31070
+ prefix: ""
31071
+ },
31072
+ iconLibrary,
31073
+ aliases: {
31074
+ components: "./src/components",
31075
+ utils: "./src/lib/utils",
31076
+ ui: "./src/components/ui",
31077
+ lib: "./src/lib",
31078
+ hooks: "./src/hooks"
31079
+ }
31080
+ };
31081
+ if (useModernStyle) {
31082
+ componentsJson.menuColor = options.shadcnMenuColor || "default";
31083
+ componentsJson.menuAccent = options.shadcnMenuAccent || "subtle";
31084
+ componentsJson.registries = {};
31085
+ }
31086
+ await writeFile(join(uiPath, "components.json"), JSON.stringify(componentsJson, null, 2));
31087
+ await writeFile(join(uiPath, "postcss.config.mjs"), `export default {
31088
+ plugins: {
31089
+ '@tailwindcss/postcss': {},
31090
+ },
31091
+ };
31092
+ `);
31093
+ const appsToScan = options.appsToScan || ["web", "platform"];
31094
+ const appSourcePaths = appsToScan.map((app) => `@source "../../../apps/${app}/src/**/*.{ts,tsx}";`);
31095
+ const baseColor = options.shadcnBaseColor || "zinc";
31096
+ const customRadius = options.shadcnRadius || "0.625rem";
31097
+ let globalsCss;
31098
+ if (useModernStyle) {
31099
+ const modernThemeCSS = generateModernThemeCSS(baseColor, customRadius);
31100
+ globalsCss = `@import "tailwindcss";
31101
+ @import "tw-animate-css";
31102
+ @import "shadcn/tailwind.css";
31103
+ ${appSourcePaths.join(`
31104
+ `)}
31105
+ @source "../**/*.{ts,tsx}";
31106
+
31107
+ @custom-variant dark (&:is(.dark *));
31108
+
31109
+ ${modernThemeCSS}
31110
+ `;
31111
+ } else {
31112
+ const theme = themes[baseColor] || themes.zinc;
31113
+ const themeCSS = generateThemeCSS(theme, customRadius);
31114
+ globalsCss = `@import "tailwindcss";
31115
+ ${appSourcePaths.join(`
31116
+ `)}
31117
+ @source "../**/*.{ts,tsx}";
31118
+
31119
+ ${themeCSS}
31120
+ `;
31121
+ }
31122
+ await writeFile(join(uiPath, "src/styles/globals.css"), globalsCss);
31123
+ await writeFile(join(uiPath, "src/lib/utils.ts"), `import { clsx, type ClassValue } from 'clsx';
31124
+ import { twMerge } from 'tailwind-merge';
31125
+
31126
+ export function cn(...inputs: ClassValue[]) {
31127
+ return twMerge(clsx(inputs));
31128
+ }
31129
+ `);
31130
+ await writeFile(join(uiPath, "src/components/index.ts"), `/**
31131
+ * UI Components
31132
+ *
31133
+ * Add shadcn/ui components using:
31134
+ * bunx shadcn@latest add button card dialog ...
31135
+ *
31136
+ * Then export them here for use across apps.
31137
+ */
31138
+
31139
+ // Export components as they are added
31140
+ // Example: export { Button } from './ui/button';
31141
+
31142
+ // Empty export to make this a valid ES module
31143
+ export {};
31144
+ `);
31145
+ await writeFile(join(uiPath, "src/hooks/index.ts"), `/**
31146
+ * Shared Hooks
31147
+ *
31148
+ * Custom React hooks shared across apps.
31149
+ */
31150
+
31151
+ // Export hooks as they are added
31152
+ // Example: export { useMediaQuery } from './use-media-query';
31153
+
31154
+ // Empty export to make this a valid ES module
31155
+ export {};
31156
+ `);
31157
+ await writeFile(join(uiPath, "src/index.ts"), `/**
31158
+ * @${options.scopeName}/ui - Shared UI Components
31159
+ *
31160
+ * This package provides:
31161
+ * - shadcn/ui components (add with: bunx shadcn@latest add <component>)
31162
+ * - Tailwind CSS v4 configuration
31163
+ * - Shared hooks and utilities
31164
+ *
31165
+ * Usage in apps:
31166
+ * - Import globals.css: import '@${options.scopeName}/ui/globals.css';
31167
+ * - Import components: import { Button } from '@${options.scopeName}/ui/components';
31168
+ * - Import utils: import { cn } from '@${options.scopeName}/ui/lib/utils';
31169
+ */
31170
+
31171
+ export * from './lib/utils';
31172
+ export * from './hooks';
31173
+ export * from './components';
31174
+ `);
31175
+ }
31176
+ async function buildTypesPackage(packagesPath, scopeName) {
31177
+ const typesPath = join(packagesPath, "types");
31178
+ await ensureDirectory(join(typesPath, "src"));
31179
+ const { writeTypesPackageJson: writeTypesPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
31180
+ await writeTypesPackageJson2(typesPath, scopeName);
31181
+ await writeFile(join(typesPath, "tsconfig.json"), JSON.stringify({
31182
+ extends: "../../tooling/typescript/library.json",
31183
+ compilerOptions: {
31184
+ rootDir: "./src",
31185
+ outDir: "./dist"
31186
+ },
31187
+ include: ["src/**/*"],
31188
+ exclude: ["node_modules"]
31189
+ }, null, 2));
31190
+ await writeFile(join(typesPath, "src/index.ts"), `/**
31191
+ * @${scopeName}/types - Shared TypeScript Types
31192
+ *
31193
+ * Define types that are shared across multiple packages/apps here.
31194
+ */
31195
+
31196
+ // Example types - replace with your actual types
31197
+
31198
+ export interface User {
31199
+ id: string;
31200
+ email: string;
31201
+ name?: string;
31202
+ createdAt: Date;
31203
+ updatedAt: Date;
31204
+ }
31205
+
31206
+ export interface ApiResponse<T> {
31207
+ success: boolean;
31208
+ data?: T;
31209
+ error?: {
31210
+ code: string;
31211
+ message: string;
31212
+ };
31213
+ }
31214
+
31215
+ export interface PaginatedResponse<T> extends ApiResponse<T[]> {
31216
+ pagination: {
31217
+ page: number;
31218
+ perPage: number;
31219
+ total: number;
31220
+ totalPages: number;
31221
+ };
31222
+ }
31223
+ `);
31224
+ }
31225
+ async function buildUtilsPackage(packagesPath, scopeName) {
31226
+ const utilsPath = join(packagesPath, "utils");
31227
+ await ensureDirectory(join(utilsPath, "src"));
31228
+ const { writeUtilsPackageJson: writeUtilsPackageJson2 } = await Promise.resolve().then(() => (init_package_json(), exports_package_json));
31229
+ await writeUtilsPackageJson2(utilsPath, scopeName);
31230
+ await writeFile(join(utilsPath, "tsconfig.json"), JSON.stringify({
31231
+ extends: "../../tooling/typescript/library.json",
31232
+ compilerOptions: {
31233
+ rootDir: "./src",
31234
+ outDir: "./dist"
31235
+ },
31236
+ include: ["src/**/*"],
31237
+ exclude: ["node_modules"]
31238
+ }, null, 2));
31239
+ await writeFile(join(utilsPath, "src/index.ts"), `/**
31240
+ * @${scopeName}/utils - Shared Utilities
31241
+ *
31242
+ * Utility functions shared across packages and apps.
31243
+ */
31244
+
31245
+ /**
31246
+ * Format a date to a human-readable string
31247
+ */
31248
+ export function formatDate(date: Date | string, locale = 'en-US'): string {
31249
+ const d = typeof date === 'string' ? new Date(date) : date;
31250
+ return d.toLocaleDateString(locale, {
31251
+ year: 'numeric',
31252
+ month: 'long',
31253
+ day: 'numeric',
31254
+ });
31255
+ }
31256
+
31257
+ /**
31258
+ * Format a number as currency
31259
+ */
31260
+ export function formatCurrency(
31261
+ amount: number,
31262
+ currency = 'USD',
31263
+ locale = 'en-US'
31264
+ ): string {
31265
+ return new Intl.NumberFormat(locale, {
31266
+ style: 'currency',
31267
+ currency,
31268
+ }).format(amount);
31269
+ }
31270
+
31271
+ /**
31272
+ * Sleep for a specified number of milliseconds
31273
+ */
31274
+ export function sleep(ms: number): Promise<void> {
31275
+ return new Promise((resolve) => setTimeout(resolve, ms));
31276
+ }
31277
+
31278
+ /**
31279
+ * Safely parse JSON with a fallback value
31280
+ */
31281
+ export function safeJsonParse<T>(json: string, fallback: T): T {
31282
+ try {
31283
+ return JSON.parse(json) as T;
31284
+ } catch {
31285
+ return fallback;
31286
+ }
31287
+ }
31288
+
31289
+ /**
31290
+ * Generate a random ID
31291
+ */
31292
+ export function generateId(length = 12): string {
31293
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
31294
+ let result = '';
31295
+ for (let i = 0; i < length; i++) {
31296
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
31297
+ }
31298
+ return result;
31299
+ }
31300
+
31301
+ /**
31302
+ * Debounce a function
31303
+ */
31304
+ export function debounce<T extends (...args: unknown[]) => unknown>(
31305
+ func: T,
31306
+ wait: number
31307
+ ): (...args: Parameters<T>) => void {
31308
+ let timeout: ReturnType<typeof setTimeout> | null = null;
31309
+ return (...args: Parameters<T>) => {
31310
+ if (timeout) clearTimeout(timeout);
31311
+ timeout = setTimeout(() => func(...args), wait);
31312
+ };
31313
+ }
31314
+
31315
+ /**
31316
+ * Check if running on server
31317
+ * Uses a type-safe approach that works without DOM types
31318
+ */
31319
+ export function isServer(): boolean {
31320
+ return !(typeof window !== 'undefined' && window.document);
31321
+ }
31322
+
31323
+ /**
31324
+ * Check if running on client
31325
+ * Uses a type-safe approach that works without DOM types
31326
+ */
31327
+ export function isClient(): boolean {
31328
+ return typeof window !== 'undefined' && !!window.document;
31329
+ }
31330
+
31331
+ // Declare window for environments without DOM types
31332
+ declare const window: { document?: unknown } | undefined;
31333
+ `);
31334
+ }
31335
+
31336
+ // ../templates/src/builders/full-v2.ts
31337
+ async function buildFullPresetV2(projectPath, context) {
31338
+ const preset = PresetRegistry.get("nextjs-monorepo");
31339
+ if (!preset) {
31340
+ throw new Error("nextjs-monorepo preset not found in registry");
31341
+ }
31342
+ const scopeName = context.packageName;
31343
+ const directories = [
31344
+ "apps/web/src/app",
31345
+ "apps/web/src/components",
31346
+ "apps/web/src/lib",
31347
+ "apps/platform/src/app",
31348
+ "apps/platform/src/components",
31349
+ "apps/platform/src/lib",
31350
+ "apps/api/src/routes",
31351
+ "apps/api/src/middleware",
31352
+ "packages/ui",
31353
+ "packages/types",
31354
+ "packages/utils",
31355
+ "tooling/typescript"
31356
+ ];
31357
+ for (const dir of directories) {
31358
+ await ensureDirectory(join(projectPath, dir));
31359
+ }
31360
+ const catalog = preset.catalogEntries || {};
31361
+ await writeMonorepoRootPackageJson(projectPath, scopeName, catalog, {
31362
+ hasWeb: true,
31363
+ hasPlatform: true,
31364
+ hasApi: true,
31365
+ codeQuality: context.codeQuality === "biome" ? "biome" : "ultracite"
31366
+ });
31367
+ await writeFile(join(projectPath, "bunfig.toml"), generateBunfigContent(context));
31368
+ await writeNextjsAppPackageJson(join(projectPath, "apps/web"), scopeName, "web", { usesUi: true, usesTypes: true });
31369
+ await writeFile(join(projectPath, "apps/web/src/app/layout.tsx"), `import type { Metadata } from 'next';
31370
+ import '@${scopeName}/ui/globals.css';
31371
+
31372
+ export const metadata: Metadata = {
31373
+ title: '${context.projectName}',
31374
+ description: 'Enterprise SaaS built with bunkit',
31375
+ };
31376
+
31377
+ export default function RootLayout({
31378
+ children,
31379
+ }: {
31380
+ children: React.ReactNode;
31381
+ }) {
31382
+ return (
31383
+ <html lang="en">
31384
+ <body className="antialiased">{children}</body>
31385
+ </html>
31386
+ );
31387
+ }
31388
+ `);
31389
+ await writeFile(join(projectPath, "apps/web/src/app/page.tsx"), `import { Home, Rocket, Book } from 'iconoir-react';
31390
+
31391
+ export default function HomePage() {
31392
+ return (
31393
+ <main className="min-h-screen flex items-center justify-center bg-gradient-to-br from-background to-muted">
31394
+ <div className="text-center space-y-8 p-8 max-w-3xl">
31395
+ <div className="flex justify-center">
31396
+ <Home className="w-16 h-16 text-primary" />
31397
+ </div>
31398
+ <h1 className="text-5xl font-bold tracking-tight">
31399
+ Welcome to ${context.projectName}
31400
+ </h1>
31401
+ <p className="text-xl text-muted-foreground">
31402
+ Enterprise-grade SaaS built with Next.js 16, React 19, Hono, and Bun
31403
+ </p>
31404
+ <div className="flex gap-4 justify-center pt-4">
31405
+ <a
31406
+ href="/dashboard"
31407
+ className="inline-flex items-center gap-2 px-6 py-3 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition font-medium"
31408
+ >
31409
+ <Rocket className="w-5 h-5" />
31410
+ Get Started
31411
+ </a>
31412
+ <a
31413
+ href="/docs"
31414
+ className="inline-flex items-center gap-2 px-6 py-3 bg-secondary text-secondary-foreground rounded-lg hover:bg-secondary/90 transition font-medium"
31415
+ >
31416
+ <Book className="w-5 h-5" />
31417
+ Documentation
31418
+ </a>
31419
+ </div>
31420
+ </div>
31421
+ </main>
31422
+ );
31423
+ }
31424
+ `);
31425
+ await writeFile(join(projectPath, "apps/web/next.config.ts"), `import type { NextConfig } from 'next';
31426
+
31427
+ const nextConfig: NextConfig = {
31428
+ transpilePackages: ['@${scopeName}/ui'],
31429
+ };
31430
+
31431
+ export default nextConfig;
31432
+ `);
31433
+ await writeFile(join(projectPath, "apps/web/tsconfig.json"), JSON.stringify({
31434
+ extends: "../../tooling/typescript/nextjs.json",
31435
+ compilerOptions: {
31436
+ paths: {
31437
+ "@/*": ["./src/*"]
31438
+ }
31439
+ },
31440
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
31441
+ exclude: ["node_modules"]
31442
+ }, null, 2));
31443
+ await writeFile(join(projectPath, "apps/web/postcss.config.mjs"), `export default {
31444
+ plugins: {
31445
+ '@tailwindcss/postcss': {},
31446
+ },
31447
+ };
31448
+ `);
31449
+ await writeNextjsAppPackageJson(join(projectPath, "apps/platform"), scopeName, "platform", { usesUi: true, usesTypes: true });
31450
+ await writeFile(join(projectPath, "apps/platform/src/app/layout.tsx"), `import type { Metadata } from 'next';
31451
+ import '@${scopeName}/ui/globals.css';
31452
+
31453
+ export const metadata: Metadata = {
31454
+ title: '${context.projectName} - Admin',
31455
+ description: 'Admin dashboard for ${context.projectName}',
31456
+ };
31457
+
31458
+ export default function RootLayout({
31459
+ children,
31460
+ }: {
31461
+ children: React.ReactNode;
31462
+ }) {
31463
+ return (
31464
+ <html lang="en">
31465
+ <body className="antialiased">{children}</body>
31466
+ </html>
31467
+ );
31468
+ }
31469
+ `);
31470
+ await writeFile(join(projectPath, "apps/platform/src/app/page.tsx"), `import { ViewGrid, User, Dollar, GraphUp } from 'iconoir-react';
31471
+
31472
+ export default function DashboardPage() {
31473
+ return (
31474
+ <main className="min-h-screen bg-background">
31475
+ <div className="max-w-7xl mx-auto py-12 px-4">
31476
+ <header className="mb-8 flex items-center gap-3">
31477
+ <ViewGrid className="w-8 h-8 text-primary" />
31478
+ <div>
31479
+ <h1 className="text-3xl font-bold">Admin Dashboard</h1>
31480
+ <p className="text-muted-foreground">
31481
+ Manage your ${context.projectName} platform
31482
+ </p>
31483
+ </div>
31484
+ </header>
31485
+
31486
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
31487
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31488
+ <div className="flex items-center gap-3 mb-2">
31489
+ <User className="w-5 h-5 text-blue-500" />
31490
+ <h2 className="text-lg font-semibold">Users</h2>
31491
+ </div>
31492
+ <p className="text-3xl font-bold">1,234</p>
31493
+ </div>
31494
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31495
+ <div className="flex items-center gap-3 mb-2">
31496
+ <Dollar className="w-5 h-5 text-green-500" />
31497
+ <h2 className="text-lg font-semibold">Revenue</h2>
31498
+ </div>
31499
+ <p className="text-3xl font-bold">$12,345</p>
31500
+ </div>
31501
+ <div className="bg-card p-6 rounded-lg border shadow-sm">
31502
+ <div className="flex items-center gap-3 mb-2">
31503
+ <GraphUp className="w-5 h-5 text-purple-500" />
31504
+ <h2 className="text-lg font-semibold">Active</h2>
31505
+ </div>
31506
+ <p className="text-3xl font-bold">567</p>
31507
+ </div>
31508
+ </div>
31509
+ </div>
31510
+ </main>
31511
+ );
31512
+ }
31513
+ `);
31514
+ await writeFile(join(projectPath, "apps/platform/next.config.ts"), `import type { NextConfig } from 'next';
31515
+
31516
+ const nextConfig: NextConfig = {
31517
+ transpilePackages: ['@${scopeName}/ui'],
31518
+ };
31519
+
31520
+ export default nextConfig;
31521
+ `);
31522
+ await writeFile(join(projectPath, "apps/platform/tsconfig.json"), JSON.stringify({
31523
+ extends: "../../tooling/typescript/nextjs.json",
31524
+ compilerOptions: {
31525
+ paths: {
31526
+ "@/*": ["./src/*"]
31527
+ }
31528
+ },
31529
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
31530
+ exclude: ["node_modules"]
31531
+ }, null, 2));
31532
+ await writeFile(join(projectPath, "apps/platform/postcss.config.mjs"), `export default {
31533
+ plugins: {
31534
+ '@tailwindcss/postcss': {},
31535
+ },
31536
+ };
31537
+ `);
31538
+ await writeHonoApiPackageJson(join(projectPath, "apps/api"), scopeName, {
31539
+ usesTypes: true
31540
+ });
31541
+ await writeFile(join(projectPath, "apps/api/src/index.ts"), `import { Hono } from 'hono';
31542
+ import { logger } from 'hono/logger';
31543
+ import { cors } from 'hono/cors';
31544
+
31545
+ const app = new Hono();
31546
+
31547
+ // Middleware
31548
+ app.use('*', logger());
31549
+ app.use('*', cors());
31550
+
31551
+ // Routes
31552
+ app.get('/', (context) => {
31553
+ return context.json({
31554
+ name: '${context.projectName} API',
31555
+ version: '1.0.0',
31556
+ timestamp: new Date().toISOString(),
31557
+ });
31558
+ });
31559
+
31560
+ app.get('/health', (context) => {
31561
+ return context.json({ status: 'ok' });
31562
+ });
31563
+
31564
+ app.get('/api/users', (context) => {
31565
+ return context.json({
31566
+ users: [
31567
+ { id: '1', email: 'john@example.com', name: 'John Doe' },
31568
+ { id: '2', email: 'jane@example.com', name: 'Jane Smith' },
31569
+ ],
31570
+ });
31571
+ });
31572
+
31573
+ // 404 handler
31574
+ app.notFound((context) => {
31575
+ return context.json({ error: 'Not found' }, 404);
31576
+ });
31577
+
31578
+ // Error handler
31579
+ app.onError((error, context) => {
31580
+ console.error('Error:', error);
31581
+ return context.json({ error: 'Internal server error' }, 500);
31582
+ });
31583
+
31584
+ // Start server with HMR
31585
+ const server = Bun.serve({
31586
+ fetch: app.fetch,
31587
+ port: 3002,
31588
+ development: {
31589
+ hmr: true,
31590
+ },
31591
+ });
31592
+
31593
+ console.log(\`\uD83D\uDE80 ${context.projectName} API running on \${server.url}\`);
31594
+
31595
+ export default app;
31596
+ `);
31597
+ await writeFile(join(projectPath, "apps/api/tsconfig.json"), JSON.stringify({
31598
+ extends: "../../tooling/typescript/api.json",
31599
+ compilerOptions: {
31600
+ types: ["bun-types"]
31601
+ },
31602
+ include: ["src/**/*"],
31603
+ exclude: ["node_modules"]
31604
+ }, null, 2));
31605
+ await buildUiPackage(join(projectPath, "packages"), {
31606
+ scopeName,
31607
+ shadcnStyle: context.shadcnStyle || "radix-maia",
31608
+ shadcnBase: context.shadcnBase || "radix",
31609
+ shadcnBaseColor: context.shadcnBaseColor || "zinc",
31610
+ shadcnIconLibrary: context.shadcnIconLibrary || "phosphor",
31611
+ shadcnMenuAccent: context.shadcnMenuAccent || "subtle",
31612
+ shadcnMenuColor: context.shadcnMenuColor || "default",
31613
+ shadcnRadius: context.shadcnRadius || "0.625rem",
31614
+ appsToScan: ["web", "platform"]
31615
+ });
31616
+ await buildTypesPackage(join(projectPath, "packages"), scopeName);
31617
+ await buildUtilsPackage(join(projectPath, "packages"), scopeName);
31618
+ await setupTooling(projectPath, context);
31619
+ await writeFile(join(projectPath, "tsconfig.json"), JSON.stringify({
31620
+ extends: "./tooling/typescript/base.json",
31621
+ include: ["apps/*/src/**/*", "packages/*/src/**/*"],
31622
+ exclude: ["node_modules", "**/node_modules", "**/.next"]
31623
+ }, null, 2));
31624
+ if (context.codeQuality === "ultracite") {
31625
+ await setupUltracite(projectPath, context);
31626
+ } else {
31627
+ await setupBiome(projectPath, context);
31628
+ }
31629
+ if (context.docker) {
31630
+ await setupDocker(projectPath, context);
31631
+ }
31632
+ if (context.cicd) {
31633
+ await setupGitHubActions(projectPath, context);
31634
+ }
31635
+ await setupVSCodeDebug(projectPath, context, "full");
31636
+ await generateMonorepoReadme(projectPath, context, "nextjs");
31637
+ }
31638
+ // ../templates/src/shared/index.ts
31639
+ init_package_json();
30269
31640
  // ../templates/src/render.ts
30270
31641
  var import_ejs = __toESM(require_ejs(), 1);
30271
31642
  // src/commands/add/component.ts
@@ -31734,17 +33105,42 @@ async function enhancedInitCommand(options = {}) {
31734
33105
  if (!shadcnStyle && uiLibrary === "shadcn") {
31735
33106
  if (!isNonInteractive) {
31736
33107
  shadcnStyle = await ve({
31737
- message: "\uD83C\uDFA8 shadcn/ui component style",
33108
+ message: "\uD83C\uDFA8 shadcn/ui visual style",
31738
33109
  options: [
33110
+ {
33111
+ value: "radix-maia",
33112
+ label: "Maia (Recommended)",
33113
+ hint: "Modern, clean design with soft shadows and refined aesthetics"
33114
+ },
33115
+ {
33116
+ value: "radix-vega",
33117
+ label: "Vega",
33118
+ hint: "Bold, vibrant design with stronger colors and contrast"
33119
+ },
33120
+ {
33121
+ value: "radix-nova",
33122
+ label: "Nova",
33123
+ hint: "Minimalist design with subtle accents and clean lines"
33124
+ },
33125
+ {
33126
+ value: "radix-lyra",
33127
+ label: "Lyra",
33128
+ hint: "Elegant design with refined typography and spacing"
33129
+ },
33130
+ {
33131
+ value: "radix-mira",
33132
+ label: "Mira",
33133
+ hint: "Playful design with rounded elements and soft colors"
33134
+ },
31739
33135
  {
31740
33136
  value: "new-york",
31741
- label: "New York (Recommended)",
31742
- hint: "Modern design aesthetic - rounded corners, subtle shadows, clean look"
33137
+ label: "New York (Legacy)",
33138
+ hint: "Classic modern aesthetic - rounded corners, subtle shadows"
31743
33139
  },
31744
33140
  {
31745
33141
  value: "default",
31746
- label: "Default",
31747
- hint: "Classic design aesthetic - sharper edges, higher contrast, traditional look"
33142
+ label: "Default (Legacy)",
33143
+ hint: "Classic design - sharper edges, higher contrast"
31748
33144
  }
31749
33145
  ]
31750
33146
  });
@@ -31753,7 +33149,7 @@ async function enhancedInitCommand(options = {}) {
31753
33149
  process.exit(0);
31754
33150
  }
31755
33151
  } else {
31756
- shadcnStyle = "new-york";
33152
+ shadcnStyle = "radix-maia";
31757
33153
  }
31758
33154
  }
31759
33155
  let shadcnBaseColor = getOptionValue("BUNKIT_SHADCN_BASE_COLOR", options.shadcnBaseColor);
@@ -31822,6 +33218,38 @@ async function enhancedInitCommand(options = {}) {
31822
33218
  shadcnRadius = "0.625rem";
31823
33219
  }
31824
33220
  }
33221
+ let shadcnIconLibrary = getOptionValue("BUNKIT_SHADCN_ICON_LIBRARY", options.shadcnIconLibrary);
33222
+ const isModernShadcnStyle = shadcnStyle === "radix-maia" || shadcnStyle === "radix-vega" || shadcnStyle === "radix-nova" || shadcnStyle === "radix-lyra" || shadcnStyle === "radix-mira";
33223
+ if (!shadcnIconLibrary && uiLibrary === "shadcn") {
33224
+ if (!isNonInteractive) {
33225
+ shadcnIconLibrary = await ve({
33226
+ message: "\uD83D\uDD23 Icon library",
33227
+ options: [
33228
+ {
33229
+ value: "phosphor",
33230
+ label: isModernShadcnStyle ? "Phosphor Icons (Recommended)" : "Phosphor Icons",
33231
+ hint: "Modern icon library with consistent design - default for new shadcn/ui styles"
33232
+ },
33233
+ {
33234
+ value: "iconoir",
33235
+ label: !isModernShadcnStyle ? "Iconoir (Recommended)" : "Iconoir",
33236
+ hint: "Lightweight icons with great variety - alternative choice"
33237
+ },
33238
+ {
33239
+ value: "lucide",
33240
+ label: "Lucide",
33241
+ hint: "Classic choice - based on Feather icons, widely used"
33242
+ }
33243
+ ]
33244
+ });
33245
+ if (pD(shadcnIconLibrary)) {
33246
+ xe("Operation cancelled.");
33247
+ process.exit(0);
33248
+ }
33249
+ } else {
33250
+ shadcnIconLibrary = isModernShadcnStyle ? "phosphor" : "iconoir";
33251
+ }
33252
+ }
31825
33253
  let testing = getOptionValue("BUNKIT_TESTING", options.testing, "bun-test");
31826
33254
  if (!testing) {
31827
33255
  if (!isNonInteractive) {
@@ -32062,7 +33490,11 @@ async function enhancedInitCommand(options = {}) {
32062
33490
  envExample: true,
32063
33491
  pathAliases: true,
32064
33492
  shadcnStyle,
33493
+ shadcnBase: "radix",
32065
33494
  shadcnBaseColor,
33495
+ shadcnIconLibrary,
33496
+ shadcnMenuAccent: "subtle",
33497
+ shadcnMenuColor: "default",
32066
33498
  shadcnRadius,
32067
33499
  supabasePreset,
32068
33500
  supabaseFeatures,
@@ -32093,7 +33525,7 @@ async function enhancedInitCommand(options = {}) {
32093
33525
  case "full":
32094
33526
  case "monorepo-nextjs":
32095
33527
  case "nextjs-monorepo":
32096
- await buildFullPreset(projectPath, context);
33528
+ await buildFullPresetV2(projectPath, context);
32097
33529
  break;
32098
33530
  case "monorepo-bun":
32099
33531
  case "bun-monorepo":