@dartix-software-solutions/create-fullstack-app 2.0.13 → 2.0.15

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "../chunk-Z7MIDMEN.js";
4
+ } from "../chunk-B3RRUSWS.js";
5
5
 
6
6
  // src/bin/create-fullstack-app.ts
7
7
  main().catch((error) => {
@@ -1970,9 +1970,12 @@ var SingleAppLayout = class {
1970
1970
  if (isFullstack) {
1971
1971
  const feDir = context.hasMobile ? "mobile" : "client";
1972
1972
  const scripts = {
1973
- dev: "npm run dev --workspaces --if-present --parallel",
1974
- build: "npm run build --workspaces --if-present",
1975
- lint: "npm run lint --workspaces --if-present"
1973
+ "dev:client": `npm run dev --prefix ${feDir}`,
1974
+ "dev:server": "npm run dev --prefix server",
1975
+ "build:client": `npm run build --prefix ${feDir}`,
1976
+ "build:server": "npm run build --prefix server",
1977
+ "lint:client": `npm run lint --prefix ${feDir}`,
1978
+ "lint:server": "npm run lint --prefix server"
1976
1979
  };
1977
1980
  if (context.hasHusky) {
1978
1981
  scripts.prepare = "husky";
@@ -1984,7 +1987,6 @@ var SingleAppLayout = class {
1984
1987
  name: context.projectName,
1985
1988
  version: "0.1.0",
1986
1989
  private: true,
1987
- workspaces: [feDir, "server"],
1988
1990
  scripts
1989
1991
  },
1990
1992
  null,
@@ -2001,7 +2003,6 @@ var SingleAppLayout = class {
2001
2003
  const isFullstack = hasFE && hasBE;
2002
2004
  if (isFullstack) {
2003
2005
  const feDir = context.hasMobile ? "mobile" : "client";
2004
- targets.push({ path: "package.json", target: TARGETS.ROOT, name: context.projectName });
2005
2006
  targets.push({
2006
2007
  path: `${feDir}/package.json`,
2007
2008
  target: TARGETS.FRONTEND,
@@ -3021,37 +3022,44 @@ function inferTargetFromPluginOutputs(plugin, context) {
3021
3022
  }
3022
3023
 
3023
3024
  // src/generator/script-builder.ts
3024
- function buildScripts2(plugins, packageJsonTargets, _context) {
3025
+ function buildScripts2(plugins, packageJsonTargets, context) {
3025
3026
  const result = /* @__PURE__ */ new Map();
3026
3027
  for (const target of packageJsonTargets) {
3027
3028
  result.set(target.path, {});
3028
3029
  }
3029
3030
  for (const plugin of plugins) {
3030
3031
  for (const scriptEntry of plugin.meta.scripts) {
3031
- const targetPath = findTargetPath(scriptEntry.target, packageJsonTargets);
3032
- if (!targetPath) {
3032
+ const targetPaths = findTargetPaths(scriptEntry.target, packageJsonTargets, context);
3033
+ if (targetPaths.length === 0) {
3033
3034
  logger.warn(
3034
3035
  `Could not resolve target for script "${scriptEntry.name}" from plugin "${plugin.meta.id}" (target: ${scriptEntry.target})`
3035
3036
  );
3036
3037
  continue;
3037
3038
  }
3038
- const scripts = result.get(targetPath);
3039
- if (!scripts) continue;
3040
- if (scripts[scriptEntry.name]) {
3041
- logger.warn(
3042
- `Script name collision: "${scriptEntry.name}" in ${targetPath} (existing from another plugin, overwriting with ${plugin.meta.id})`
3043
- );
3039
+ for (const targetPath of targetPaths) {
3040
+ const scripts = result.get(targetPath);
3041
+ if (!scripts) continue;
3042
+ if (scripts[scriptEntry.name]) {
3043
+ logger.warn(
3044
+ `Script name collision: "${scriptEntry.name}" in ${targetPath} (existing from another plugin, overwriting with ${plugin.meta.id})`
3045
+ );
3046
+ }
3047
+ scripts[scriptEntry.name] = scriptEntry.command;
3044
3048
  }
3045
- scripts[scriptEntry.name] = scriptEntry.command;
3046
3049
  }
3047
3050
  }
3048
3051
  return result;
3049
3052
  }
3050
- function findTargetPath(target, packageJsonTargets) {
3053
+ function findTargetPaths(target, packageJsonTargets, context) {
3051
3054
  const match = packageJsonTargets.find((t) => t.target === target);
3052
- if (match) return match.path;
3055
+ if (match) return [match.path];
3056
+ if (target === TARGETS.ROOT && context.isSingleApp && context.isFullstack) {
3057
+ const frontend = packageJsonTargets.find((t) => t.target === TARGETS.FRONTEND)?.path;
3058
+ const backend = packageJsonTargets.find((t) => t.target === TARGETS.BACKEND)?.path;
3059
+ return [frontend, backend].filter((p) => Boolean(p));
3060
+ }
3053
3061
  const root = packageJsonTargets.find((t) => t.target === TARGETS.ROOT);
3054
- return root?.path || null;
3062
+ return root ? [root.path] : [];
3055
3063
  }
3056
3064
 
3057
3065
  // src/generator/env-builder.ts
@@ -3720,6 +3728,7 @@ async function runPostGenerate(outputDir, context, options) {
3720
3728
  const [cmd, ...args] = installCmd.split(" ");
3721
3729
  const installTargets = await getInstallTargets(outputDir, context);
3722
3730
  try {
3731
+ let installCount = 0;
3723
3732
  for (const target of installTargets) {
3724
3733
  await withSpinner(
3725
3734
  `Installing ${target.label} dependencies with ${context.packageManager}...`,
@@ -3731,8 +3740,9 @@ async function runPostGenerate(outputDir, context, options) {
3731
3740
  },
3732
3741
  `${target.label} dependencies installed`
3733
3742
  );
3743
+ installCount += 1;
3734
3744
  }
3735
- installed = true;
3745
+ installed = installCount > 0;
3736
3746
  } catch (error) {
3737
3747
  logger.warn(`Failed to install dependencies: ${error.message}`);
3738
3748
  logger.info(`You can run "${installCmd}" manually`);
@@ -3765,7 +3775,13 @@ function buildNextSteps(context, installed) {
3765
3775
  steps.push(`Set up database: ${pm} run db:migrate && ${pm} run db:seed`);
3766
3776
  }
3767
3777
  }
3768
- steps.push(`Start development: ${pm} run dev`);
3778
+ if (context.isFullstack) {
3779
+ const feDir = context.hasMobile ? "mobile" : "client";
3780
+ steps.push(`Start frontend: ${pm} run dev --prefix ${feDir}`);
3781
+ steps.push(`Start backend: ${pm} run dev --prefix server`);
3782
+ } else {
3783
+ steps.push(`Start development: ${pm} run dev`);
3784
+ }
3769
3785
  if (context.hasMobile) {
3770
3786
  steps.push("Run on device: Press 'i' for iOS, 'a' for Android, or scan QR code");
3771
3787
  }
@@ -3781,9 +3797,6 @@ async function getInstallTargets(outputDir, context) {
3781
3797
  cwd: dir
3782
3798
  });
3783
3799
  }
3784
- if (targets.length === 0) {
3785
- targets.push({ label: "project", cwd: outputDir });
3786
- }
3787
3800
  return targets;
3788
3801
  }
3789
3802
  async function runBootstrapScripts(outputDir, context) {
@@ -1,8 +1,42 @@
1
1
  // src/plugins/devtools/eslint/file-map.ts
2
2
  var fileMap = {
3
3
  files: [
4
- { template: "eslint.config.js.hbs", outputPath: "eslint.config.js", target: "root" },
5
- { template: ".eslintignore.hbs", outputPath: ".eslintignore", target: "root" }
4
+ {
5
+ template: "eslint.config.js.hbs",
6
+ outputPath: "eslint.config.js",
7
+ target: "root",
8
+ when: (ctx) => !(ctx.isSingleApp && ctx.isFullstack)
9
+ },
10
+ {
11
+ template: ".eslintignore.hbs",
12
+ outputPath: ".eslintignore",
13
+ target: "root",
14
+ when: (ctx) => !(ctx.isSingleApp && ctx.isFullstack)
15
+ },
16
+ {
17
+ template: "eslint.config.js.hbs",
18
+ outputPath: "eslint.config.js",
19
+ target: "frontend",
20
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
21
+ },
22
+ {
23
+ template: ".eslintignore.hbs",
24
+ outputPath: ".eslintignore",
25
+ target: "frontend",
26
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
27
+ },
28
+ {
29
+ template: "eslint.config.js.hbs",
30
+ outputPath: "eslint.config.js",
31
+ target: "backend",
32
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
33
+ },
34
+ {
35
+ template: ".eslintignore.hbs",
36
+ outputPath: ".eslintignore",
37
+ target: "backend",
38
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
39
+ }
6
40
  ],
7
41
  injections: []
8
42
  };
@@ -1,8 +1,42 @@
1
1
  // src/plugins/devtools/prettier/file-map.ts
2
2
  var fileMap = {
3
3
  files: [
4
- { template: ".prettierrc.hbs", outputPath: ".prettierrc", target: "root" },
5
- { template: ".prettierignore.hbs", outputPath: ".prettierignore", target: "root" }
4
+ {
5
+ template: ".prettierrc.hbs",
6
+ outputPath: ".prettierrc",
7
+ target: "root",
8
+ when: (ctx) => !(ctx.isSingleApp && ctx.isFullstack)
9
+ },
10
+ {
11
+ template: ".prettierignore.hbs",
12
+ outputPath: ".prettierignore",
13
+ target: "root",
14
+ when: (ctx) => !(ctx.isSingleApp && ctx.isFullstack)
15
+ },
16
+ {
17
+ template: ".prettierrc.hbs",
18
+ outputPath: ".prettierrc",
19
+ target: "frontend",
20
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
21
+ },
22
+ {
23
+ template: ".prettierignore.hbs",
24
+ outputPath: ".prettierignore",
25
+ target: "frontend",
26
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
27
+ },
28
+ {
29
+ template: ".prettierrc.hbs",
30
+ outputPath: ".prettierrc",
31
+ target: "backend",
32
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
33
+ },
34
+ {
35
+ template: ".prettierignore.hbs",
36
+ outputPath: ".prettierignore",
37
+ target: "backend",
38
+ when: (ctx) => ctx.isSingleApp && ctx.isFullstack
39
+ }
6
40
  ],
7
41
  injections: []
8
42
  };
@@ -15,16 +15,24 @@ export function SampleForm(): JSX.Element {
15
15
  }}
16
16
  >
17
17
  {({ isSubmitting }) => (
18
- <Form style={{ display: 'grid', gap: 12, maxWidth: 360 }}>
19
- <label htmlFor="email">Email</label>
20
- <Field id="email" name="email" type="email" />
21
- <ErrorMessage name="email" component="small" />
18
+ <Form className="grid max-w-sm gap-3">
19
+ <label htmlFor="email" className="text-sm font-medium">
20
+ Email
21
+ </label>
22
+ <Field id="email" name="email" type="email" className="rounded border px-3 py-2" />
23
+ <ErrorMessage name="email" component="small" className="text-sm text-red-600" />
22
24
 
23
- <label htmlFor="password">Password</label>
24
- <Field id="password" name="password" type="password" />
25
- <ErrorMessage name="password" component="small" />
25
+ <label htmlFor="password" className="text-sm font-medium">
26
+ Password
27
+ </label>
28
+ <Field id="password" name="password" type="password" className="rounded border px-3 py-2" />
29
+ <ErrorMessage name="password" component="small" className="text-sm text-red-600" />
26
30
 
27
- <button type="submit" disabled={isSubmitting}>
31
+ <button
32
+ type="submit"
33
+ disabled={isSubmitting}
34
+ className="rounded bg-black px-4 py-2 text-white disabled:opacity-60"
35
+ >
28
36
  {isSubmitting ? 'Submitting...' : 'Submit'}
29
37
  </button>
30
38
  </Form>
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  main
3
- } from "./chunk-Z7MIDMEN.js";
3
+ } from "./chunk-B3RRUSWS.js";
4
4
  export {
5
5
  main
6
6
  };
@@ -2,6 +2,7 @@
2
2
  var fileMap = {
3
3
  files: [
4
4
  { template: "schema.prisma.hbs", outputPath: "prisma/schema.prisma", target: "backend" },
5
+ { template: "prisma.config.ts.hbs", outputPath: "prisma.config.ts", target: "backend" },
5
6
  { template: "seed.ts.hbs", outputPath: "prisma/seed.ts", target: "backend" },
6
7
  { template: "db-client.ts.hbs", outputPath: "src/lib/db.ts", target: "backend" },
7
8
  { template: "models/user.ts.hbs", outputPath: "src/models/user.ts", target: "backend" },
@@ -5,9 +5,12 @@ var meta = {
5
5
  description: "Type-safe ORM with auto-generated client, migrations, and studio",
6
6
  category: "orm",
7
7
  platformSupport: "backend-only",
8
- deps: [{ name: "@prisma/client", version: "^6.1.0" }],
8
+ deps: [
9
+ { name: "@prisma/client", version: "^7.7.0" },
10
+ { name: "@prisma/adapter-pg", version: "^7.7.0" }
11
+ ],
9
12
  devDeps: [
10
- { name: "prisma", version: "^6.1.0" },
13
+ { name: "prisma", version: "^7.7.0" },
11
14
  { name: "tsx", version: "^4.19.0" }
12
15
  ],
13
16
  envVars: [],
@@ -1,8 +1,17 @@
1
1
  import { PrismaClient } from '@prisma/client';
2
+ {{#if hasPostgres}}
3
+ import { PrismaPg } from '@prisma/adapter-pg';
4
+ {{/if}}
2
5
 
3
6
  const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined };
4
7
 
5
- export const prisma = globalForPrisma.prisma ?? new PrismaClient();
8
+ export const prisma =
9
+ globalForPrisma.prisma ??
10
+ new PrismaClient({
11
+ {{#if hasPostgres}}
12
+ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL ?? '' }),
13
+ {{/if}}
14
+ });
6
15
 
7
16
  if (process.env.NODE_ENV !== 'production') {
8
17
  globalForPrisma.prisma = prisma;
@@ -0,0 +1,12 @@
1
+ import { defineConfig, env } from 'prisma/config';
2
+
3
+ export default defineConfig({
4
+ schema: 'prisma/schema.prisma',
5
+ migrations: {
6
+ path: 'prisma/migrations',
7
+ },
8
+ seed: 'tsx prisma/seed.ts',
9
+ datasource: {
10
+ url: env('DATABASE_URL'),
11
+ },
12
+ });
@@ -1,8 +1,19 @@
1
1
  import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
2
  import { PrismaClient } from '@prisma/client';
3
+ {{#if hasPostgres}}
4
+ import { PrismaPg } from '@prisma/adapter-pg';
5
+ {{/if}}
3
6
 
4
7
  @Injectable()
5
8
  export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
9
+ constructor() {
10
+ super({
11
+ {{#if hasPostgres}}
12
+ adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL ?? '' }),
13
+ {{/if}}
14
+ });
15
+ }
16
+
6
17
  async onModuleInit(): Promise<void> {
7
18
  await this.$connect();
8
19
  }
@@ -10,7 +10,6 @@ datasource db {
10
10
  {{else}}
11
11
  provider = "sqlite"
12
12
  {{/if}}
13
- url = env("DATABASE_URL")
14
13
  }
15
14
 
16
15
  model User {
@@ -11,9 +11,9 @@ var meta = {
11
11
  platformSupport: "web-only",
12
12
  deps: [],
13
13
  devDeps: [
14
- { name: "tailwindcss", version: "^3.4.16" },
15
- { name: "postcss", version: "^8.4.49" },
16
- { name: "autoprefixer", version: "^10.4.20" }
14
+ { name: "tailwindcss", version: "^4.1.0" },
15
+ { name: "@tailwindcss/postcss", version: "^4.1.0" },
16
+ { name: "postcss", version: "^8.4.49" }
17
17
  ],
18
18
  envVars: [],
19
19
  scripts: [],
@@ -1,3 +1 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
1
+ @import "tailwindcss";
@@ -1,6 +1,5 @@
1
- export default {
1
+ module.exports = {
2
2
  plugins: {
3
- tailwindcss: {},
4
- autoprefixer: {},
3
+ '@tailwindcss/postcss': {},
5
4
  },
6
5
  };
@@ -1,7 +1,7 @@
1
1
  import type { Config } from 'tailwindcss';
2
2
 
3
3
  const config: Config = {
4
- content: ['./src/**/*.{js,ts,jsx,tsx}'],
4
+ content: ['./src/**/*.{js,ts,jsx,tsx,mdx,html,vue,svelte}'],
5
5
  theme: {
6
6
  extend: {},
7
7
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dartix-software-solutions/create-fullstack-app",
3
- "version": "2.0.13",
3
+ "version": "2.0.15",
4
4
  "description": "CLI tool to scaffold full-stack applications with pluggable architecture",
5
5
  "type": "module",
6
6
  "bin": {