@nexusts/cli 0.9.4 → 0.9.5

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/index.js CHANGED
@@ -168,14 +168,14 @@ async function loadConfig(cwd = process.cwd()) {
168
168
  const mod = await import(path);
169
169
  config = mod.default ?? mod;
170
170
  } catch (importErr) {
171
- console.warn(`[nx] Could not dynamically import ${candidate}: ${importErr.message ?? importErr}. Falling back to defaults.`);
171
+ console.warn(`[nx] Could not dynamically import ${candidate}: ${importErr instanceof Error ? importErr.message : String(importErr)}. Falling back to defaults.`);
172
172
  config = {};
173
173
  }
174
174
  }
175
175
  configSource = candidate;
176
176
  break;
177
177
  } catch (err) {
178
- throw new Error(`Failed to load ${candidate}: ${err.message ?? String(err)}`);
178
+ throw new Error(`Failed to load ${candidate}: ${err instanceof Error ? err.message : String(err)}`);
179
179
  }
180
180
  }
181
181
  const merged = mergeWithEnv(DEFAULT_CONFIG, config);
@@ -186,7 +186,7 @@ async function loadConfig(cwd = process.cwd()) {
186
186
  "mixed"
187
187
  ]);
188
188
  assertEnum("view", merged.view, ["rendu", "edge", "inertia", "none"]);
189
- assertEnum("orm", merged.orm, ["drizzle", "prisma", "kysely", "none"]);
189
+ assertEnum("orm", merged.orm, ["drizzle", "kysely", "none"]);
190
190
  assertEnum("database.driver", merged.database.driver, [
191
191
  "bun-sqlite",
192
192
  "node-sqlite",
@@ -201,7 +201,7 @@ async function loadConfig(cwd = process.cwd()) {
201
201
  "svelte",
202
202
  "solid"
203
203
  ]);
204
- if (process.env["NX_DEBUG"] === "1") {
204
+ if (process.env.NX_DEBUG === "1") {
205
205
  console.log(`[nx] config source: ${configSource}`);
206
206
  }
207
207
  return merged;
@@ -215,22 +215,22 @@ function mergeWithEnv(base, override) {
215
215
  inertia: { ...base.inertia, ...override.inertia ?? {} },
216
216
  paths: { ...base.paths, ...override.paths ?? {} }
217
217
  };
218
- if (env["NX_ROUTING"])
219
- merged.routing = env["NX_ROUTING"];
220
- if (env["NX_VIEW"])
221
- merged.view = env["NX_VIEW"];
222
- if (env["NX_ORM"])
223
- merged.orm = env["NX_ORM"];
224
- if (env["NX_DATABASE_DRIVER"])
225
- merged.database.driver = env["NX_DATABASE_DRIVER"];
226
- if (env["NX_DATABASE_URL"])
227
- merged.database.url = env["NX_DATABASE_URL"];
228
- if (env["NX_INERTIA_FRONTEND"])
229
- merged.inertia.frontend = env["NX_INERTIA_FRONTEND"];
230
- if (env["NX_INERTIA_SSR"])
231
- merged.inertia.ssr = env["NX_INERTIA_SSR"] !== "false" && env["NX_INERTIA_SSR"] !== "0";
232
- if (env["NX_INERTIA_VERSION"])
233
- merged.inertia.version = env["NX_INERTIA_VERSION"];
218
+ if (env.NX_ROUTING)
219
+ merged.routing = env.NX_ROUTING;
220
+ if (env.NX_VIEW)
221
+ merged.view = env.NX_VIEW;
222
+ if (env.NX_ORM)
223
+ merged.orm = env.NX_ORM;
224
+ if (env.NX_DATABASE_DRIVER)
225
+ merged.database.driver = env.NX_DATABASE_DRIVER;
226
+ if (env.NX_DATABASE_URL)
227
+ merged.database.url = env.NX_DATABASE_URL;
228
+ if (env.NX_INERTIA_FRONTEND)
229
+ merged.inertia.frontend = env.NX_INERTIA_FRONTEND;
230
+ if (env.NX_INERTIA_SSR)
231
+ merged.inertia.ssr = env.NX_INERTIA_SSR !== "false" && env.NX_INERTIA_SSR !== "0";
232
+ if (env.NX_INERTIA_VERSION)
233
+ merged.inertia.version = env.NX_INERTIA_VERSION;
234
234
  return merged;
235
235
  }
236
236
  function assertEnum(key, value, allowed) {
@@ -285,7 +285,7 @@ function pluralize(s) {
285
285
  return `${s}s`;
286
286
  }
287
287
  // packages/cli/src/core/logger.ts
288
- var USE_COLOR = process.env["NO_COLOR"] === undefined && process.env["FORCE_COLOR"] !== "0" && process.stdout.isTTY === true;
288
+ var USE_COLOR = process.env.NO_COLOR === undefined && process.env.FORCE_COLOR !== "0" && process.stdout.isTTY === true;
289
289
  var wrap = (open, close) => (s) => USE_COLOR ? `\x1B[${open}m${s}\x1B[${close}m` : s;
290
290
  var c = {
291
291
  reset: wrap(0, 0),
@@ -780,6 +780,30 @@ export const {{ snake }} = sqliteTable('{{ tableName }}', {
780
780
  });
781
781
  `.trimStart();
782
782
 
783
+ // packages/cli/src/templates/migration/kysely.ts
784
+ var kysely_default = `
785
+ import type { Kysely } from 'kysely';
786
+
787
+ /**
788
+ * Migration: {{ name }}
789
+ *
790
+ * Run with \`nx db:migrate\` or via Kysely's Migrator.
791
+ */
792
+ export async function up(db: Kysely<any>): Promise<void> {
793
+ await db.schema
794
+ .createTable('{{ tableName }}')
795
+ .addColumn('id', 'integer', (col) => col.primaryKey().autoIncrement())
796
+ {{ columns }}
797
+ .addColumn('created_at', 'integer', (col) => col.notNull().defaultTo(0))
798
+ .addColumn('updated_at', 'integer', (col) => col.notNull().defaultTo(0))
799
+ .execute();
800
+ }
801
+
802
+ export async function down(db: Kysely<any>): Promise<void> {
803
+ await db.schema.dropTable('{{ tableName }}').execute();
804
+ }
805
+ `.trimStart();
806
+
783
807
  // packages/cli/src/templates/migration/sql.ts
784
808
  var sql_default = `
785
809
  -- {{ timestamp }}_create_{{ snake }}.sql
@@ -812,93 +836,33 @@ export type New{{ name }} = typeof {{ snake }}.$inferInsert;
812
836
  `.trimStart();
813
837
 
814
838
  // packages/cli/src/templates/model/kysely.ts
815
- var kysely_default = `
839
+ var kysely_default2 = `
816
840
  import type { Generated, Insertable, Selectable, Updateable } from 'kysely';
817
- import { Kysely } from 'kysely';
818
841
  import { Inject, Injectable } from '@nexusts/core';
842
+ import { KyselyService, KyselyRepository } from '@nexusts/kysely';
819
843
 
844
+ /**
845
+ * Table interface for {{ tableName }}.
846
+ */
820
847
  export interface {{ name }}Table {
821
848
  id: Generated<number>;
822
849
  {{ columns }}
823
- created_at: Generated<Date>;
824
- updated_at: Generated<Date>;
850
+ created_at: Generated<string>;
851
+ updated_at: Generated<string>;
825
852
  }
826
853
 
854
+ /** Row types derived from the table interface. */
827
855
  export type {{ name }} = Selectable<{{ name }}Table>;
828
856
  export type New{{ name }} = Insertable<{{ name }}Table>;
829
857
  export type {{ name }}Update = Updateable<{{ name }}Table>;
830
858
 
831
- @Injectable()
832
- export class {{ name }}Repository {
833
- constructor(@Inject('DB') private readonly db: Kysely<any>) {}
834
-
835
- findAll() {
836
- return this.db.selectFrom('{{ tableName }}').selectAll().execute();
837
- }
838
-
839
- findOne(id: number) {
840
- return this.db
841
- .selectFrom('{{ tableName }}')
842
- .selectAll()
843
- .where('id', '=', id)
844
- .executeTakeFirst();
845
- }
846
-
847
- create(data: New{{ name }}) {
848
- return this.db.insertInto('{{ tableName }}').values(data).returningAll().executeTakeFirst();
849
- }
850
-
851
- update(id: number, data: {{ name }}Update) {
852
- return this.db
853
- .updateTable('{{ tableName }}')
854
- .set(data)
855
- .where('id', '=', id)
856
- .returningAll()
857
- .executeTakeFirst();
858
- }
859
-
860
- delete(id: number) {
861
- return this.db.deleteFrom('{{ tableName }}').where('id', '=', id).execute();
862
- }
863
- }
864
- `.trimStart();
865
-
866
- // packages/cli/src/templates/model/prisma.ts
867
- var prisma_default = `
868
859
  /**
869
- * {{ name }} \u2014 generated by \`nx make:model {{ name }}\`.
870
- *
871
- * Add this block to your schema.prisma file:
872
- *
873
- {{ prismaBlock }}
860
+ * Repository for {{ tableName }} \u2014 Lucid-style CRUD via KyselyRepository.
874
861
  */
875
-
876
- import { PrismaClient } from '@prisma/client';
877
- import { Inject, Injectable } from '@nexusts/core';
878
-
879
862
  @Injectable()
880
- export class {{ name }}Repository {
881
- constructor(@Inject('PRISMA') private readonly prisma: PrismaClient) {}
882
-
883
- findAll() {
884
- return this.prisma.{{ camel }}.findMany();
885
- }
886
-
887
- findOne(id: number) {
888
- return this.prisma.{{ camel }}.findUnique({ where: { id } });
889
- }
890
-
891
- create(data: any) {
892
- return this.prisma.{{ camel }}.create({ data });
893
- }
894
-
895
- update(id: number, data: any) {
896
- return this.prisma.{{ camel }}.update({ where: { id }, data });
897
- }
898
-
899
- delete(id: number) {
900
- return this.prisma.{{ camel }}.delete({ where: { id } });
901
- }
863
+ export class {{ name }}Repository extends KyselyRepository<any, '{{ tableName }}'> {
864
+ @Inject(KyselyService.TOKEN) declare db: KyselyService<any>;
865
+ protected readonly tableName = '{{ tableName }}' as const;
902
866
  }
903
867
  `.trimStart();
904
868
 
@@ -947,7 +911,7 @@ export default {
947
911
  */
948
912
  viewPaths: '{{ viewPaths }}',
949
913
 
950
- /** ORM driver \u2014 \`drizzle\`, \`prisma\`, \`kysely\`, or \`none\`. */
914
+ /** ORM driver \u2014 \`drizzle\`, \`kysely\`, or \`none\`. */
951
915
  orm: '{{ orm }}',
952
916
 
953
917
  // ---------------------------------------------------------------------------
@@ -1017,12 +981,22 @@ export class {{ repository }} extends DrizzleRepository<typeof {{ snake }}, {{ n
1017
981
  }
1018
982
  `.trimStart();
1019
983
 
984
+ // packages/cli/src/templates/repository/kysely-repository.ts
985
+ var kysely_repository_default = `
986
+ import { Injectable, Inject } from '@nexusts/core';
987
+ import { KyselyService, KyselyRepository } from '@nexusts/kysely';
988
+
989
+ @Injectable()
990
+ export class {{ repository }} extends KyselyRepository<any, '{{ tableName }}'> {
991
+ @Inject(KyselyService.TOKEN) declare db: KyselyService<any>;
992
+ protected readonly tableName = '{{ tableName }}' as const;
993
+ }
994
+ `.trimStart();
995
+
1020
996
  // packages/cli/src/templates/service/service.ts
1021
997
  var service_default = `
1022
998
  import { Injectable, Inject } from '@nexusts/core';
1023
- {{#hasRepo}}import { eq } from '@nexusts/drizzle';
1024
- import { {{ repository }} } from '../repositories/{{ kebab }}.repository.js';
1025
- import { {{ snake }} } from '../models/{{ kebab }}.model.js';{{/hasRepo}}
999
+ {{#hasRepo}}import { {{ repository }} } from '../repositories/{{ kebab }}.repository.js';{{/hasRepo}}
1026
1000
 
1027
1001
  @Injectable()
1028
1002
  export class {{ name }}Service {
@@ -1034,7 +1008,7 @@ export class {{ name }}Service {
1034
1008
  }
1035
1009
 
1036
1010
  async findOne(id: number) {
1037
- {{#hasRepo}}return this.{{ repositoryCamel }}.findOne(eq({{ snake }}.id, id));{{/hasRepo}}
1011
+ {{#hasRepo}}return this.{{ repositoryCamel }}.findById(id);{{/hasRepo}}
1038
1012
  {{^hasRepo}}return { id }; // TODO: implement{{/hasRepo}}
1039
1013
  }
1040
1014
 
@@ -1044,12 +1018,12 @@ export class {{ name }}Service {
1044
1018
  }
1045
1019
 
1046
1020
  async update(id: number, data: any) {
1047
- {{#hasRepo}}return this.{{ repositoryCamel }}.update(eq({{ snake }}.id, id), data);{{/hasRepo}}
1021
+ {{#hasRepo}}return this.{{ repositoryCamel }}.updateById(id, data);{{/hasRepo}}
1048
1022
  {{^hasRepo}}return { id, ...data }; // TODO: implement{{/hasRepo}}
1049
1023
  }
1050
1024
 
1051
1025
  async delete(id: number) {
1052
- {{#hasRepo}}return this.{{ repositoryCamel }}.delete(eq({{ snake }}.id, id));{{/hasRepo}}
1026
+ {{#hasRepo}}return this.{{ repositoryCamel }}.deleteById(id);{{/hasRepo}}
1053
1027
  {{^hasRepo}}return { removed: id }; // TODO: implement{{/hasRepo}}
1054
1028
  }
1055
1029
  }
@@ -1080,17 +1054,20 @@ var templates = {
1080
1054
  functional: functional_default
1081
1055
  },
1082
1056
  service: service_default,
1083
- repository: repository_default,
1057
+ repository: {
1058
+ drizzle: repository_default,
1059
+ kysely: kysely_repository_default
1060
+ },
1084
1061
  module: module_default2,
1085
1062
  validator: validator_default,
1086
1063
  middleware: middleware_default,
1087
1064
  model: {
1088
1065
  drizzle: drizzle_default2,
1089
- prisma: prisma_default,
1090
- kysely: kysely_default
1066
+ kysely: kysely_default2
1091
1067
  },
1092
1068
  migration: {
1093
1069
  drizzle: drizzle_default,
1070
+ kysely: kysely_default,
1094
1071
  sql: sql_default
1095
1072
  },
1096
1073
  crud: {
@@ -1131,13 +1108,17 @@ function computeDeps(view, orm, db, frontend) {
1131
1108
  deps["@nexusts/drizzle"] = "*";
1132
1109
  deps["drizzle-orm"] = "^0.45.0";
1133
1110
  if (db === "postgres")
1134
- deps["pg"] = "^8.13.0";
1111
+ deps.pg = "^8.13.0";
1135
1112
  if (db === "mysql")
1136
- deps["mysql2"] = "^3.11.0";
1113
+ deps.mysql2 = "^3.11.0";
1137
1114
  if (db === "sqlite" || db === "node-sqlite" || db === "bun-sqlite")
1138
1115
  deps["better-sqlite3"] = "^12.0.0";
1139
1116
  devDeps["drizzle-kit"] = "^0.31.0";
1140
1117
  }
1118
+ if (orm === "kysely") {
1119
+ deps["@nexusts/kysely"] = "*";
1120
+ deps["kysely"] = "^0.27.0";
1121
+ }
1141
1122
  if (view !== "none") {
1142
1123
  deps["@nexusts/static"] = "*";
1143
1124
  }
@@ -1145,10 +1126,10 @@ function computeDeps(view, orm, db, frontend) {
1145
1126
  if (view === "inertia") {
1146
1127
  if (frontend === "vue") {
1147
1128
  deps["@inertiajs/vue3"] = "^3.0.0";
1148
- deps["vue"] = "^3.5.0";
1129
+ deps.vue = "^3.5.0";
1149
1130
  } else {
1150
1131
  deps["@inertiajs/react"] = "^3.0.0";
1151
- deps["react"] = "^19.0.0";
1132
+ deps.react = "^19.0.0";
1152
1133
  deps["react-dom"] = "^19.0.0";
1153
1134
  }
1154
1135
  }
@@ -1165,7 +1146,7 @@ function buildPackageJson(name, deps, devDeps, view, frontend) {
1165
1146
  if (view === "inertia") {
1166
1147
  const ext = frontend === "vue" ? "ts" : "tsx";
1167
1148
  scripts["build:frontend"] = `bun build ./resources/js/app.${ext} --outdir=./public --target=browser --format=esm --minify`;
1168
- scripts["dev"] = `bun run build:frontend && bun --hot app/main.ts`;
1149
+ scripts.dev = `bun run build:frontend && bun --hot app/main.ts`;
1169
1150
  }
1170
1151
  const pkg = {
1171
1152
  name,
@@ -1205,7 +1186,7 @@ function generateDrizzleConfig(target, db, dbUrl) {
1205
1186
  writeFileSync2(resolve4(target, "drizzle.config.ts"), code);
1206
1187
  }
1207
1188
  function generateEnvFile() {
1208
- return [
1189
+ return `${[
1209
1190
  "# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1210
1191
  "# NexusTS \u2014 Environment Variables (committed to git)",
1211
1192
  "#",
@@ -1235,11 +1216,11 @@ function generateEnvFile() {
1235
1216
  "# BETTER_AUTH_SECRET=",
1236
1217
  "# BETTER_AUTH_URL=http://localhost:3000"
1237
1218
  ].join(`
1238
- `) + `
1219
+ `)}
1239
1220
  `;
1240
1221
  }
1241
1222
  function generateEnvLocalFile() {
1242
- return [
1223
+ return `${[
1243
1224
  "# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
1244
1225
  "# NexusTS \u2014 Local Overrides (DO NOT COMMIT to git)",
1245
1226
  "#",
@@ -1251,7 +1232,7 @@ function generateEnvLocalFile() {
1251
1232
  "# DATABASE_URL=postgres://user:password@localhost:5432/myapp",
1252
1233
  "# SESSION_SECRET=my-local-secret"
1253
1234
  ].join(`
1254
- `) + `
1235
+ `)}
1255
1236
  `;
1256
1237
  }
1257
1238
  function generateGitIgnore() {
@@ -1357,15 +1338,34 @@ console.log('[nexus] Listening on http://localhost:' + (process.env['PORT'] ?? 3
1357
1338
  `);
1358
1339
  }
1359
1340
  {
1360
- const hasOrm = opts.orm === "drizzle";
1361
- const ormImport = hasOrm ? `import { DrizzleModule } from '@nexusts/drizzle';
1362
- ` : "";
1363
- const forRootDialect = opts.db === "bun-sqlite" ? "bun-sqlite" : "sqlite";
1364
- const ormBlock = hasOrm ? ` DrizzleModule.forRoot({
1365
- dialect: '${forRootDialect}',
1366
- connection: { filename: '${opts.dbUrl || "app.db"}' },
1341
+ const isDrizzle = opts.orm === "drizzle";
1342
+ const isKysely = opts.orm === "kysely";
1343
+ const hasOrm = isDrizzle || isKysely;
1344
+ let ormImport = "";
1345
+ let ormBlock = "";
1346
+ if (isDrizzle) {
1347
+ ormImport = `import { DrizzleModule } from '@nexusts/drizzle';
1348
+ `;
1349
+ const d = opts.db === "bun-sqlite" ? "bun-sqlite" : "sqlite";
1350
+ ormBlock = ` DrizzleModule.forRoot({
1351
+ dialect: '` + d + `',
1352
+ connection: { filename: '` + (opts.dbUrl || "app.db") + `' },
1353
+ logging: true,
1354
+ })`;
1355
+ } else if (isKysely) {
1356
+ ormImport = `import { KyselyModule, BunSqliteDialect } from '@nexusts/kysely';
1357
+ import { SqliteDialect } from 'kysely';
1358
+ import { Database } from 'bun:sqlite';
1359
+ `;
1360
+ ormBlock = ` KyselyModule.forRoot({
1361
+ config: {
1362
+ dialect: new SqliteDialect({
1363
+ database: BunSqliteDialect.wrap(new Database('` + (opts.dbUrl || "app.db") + `')),
1364
+ }),
1365
+ },
1367
1366
  logging: true,
1368
- })` : "";
1367
+ })`;
1368
+ }
1369
1369
  const isInertia = opts.view === "inertia";
1370
1370
  const inertiaImport = isInertia ? `import { Inertia } from '@nexusts/view';
1371
1371
  ` : "";
@@ -1383,9 +1383,8 @@ ${inertiaProvider} controllers: [HomeController],
1383
1383
  export class AppModule {}
1384
1384
  `);
1385
1385
  }
1386
- {
1387
- if (opts.view === "inertia") {
1388
- write("app/controllers/home.controller.ts", `import { Controller, Get, Inject } from '@nexusts/core';
1386
+ if (opts.view === "inertia") {
1387
+ write("app/controllers/home.controller.ts", `import { Controller, Get, Inject } from '@nexusts/core';
1389
1388
  import { Inertia } from '@nexusts/view';
1390
1389
 
1391
1390
  @Controller('/')
@@ -1398,8 +1397,8 @@ export class HomeController {
1398
1397
  }
1399
1398
  }
1400
1399
  `);
1401
- } else if (opts.view !== "none") {
1402
- write("app/controllers/home.controller.ts", `import { Controller, Get } from '@nexusts/core';
1400
+ } else if (opts.view !== "none") {
1401
+ write("app/controllers/home.controller.ts", `import { Controller, Get } from '@nexusts/core';
1403
1402
 
1404
1403
  @Controller('/')
1405
1404
  export class HomeController {
@@ -1412,8 +1411,8 @@ export class HomeController {
1412
1411
  }
1413
1412
  }
1414
1413
  `);
1415
- } else {
1416
- write("app/controllers/home.controller.ts", `import { Controller, Get } from '@nexusts/core';
1414
+ } else {
1415
+ write("app/controllers/home.controller.ts", `import { Controller, Get } from '@nexusts/core';
1417
1416
 
1418
1417
  @Controller('/')
1419
1418
  export class HomeController {
@@ -1423,7 +1422,6 @@ export class HomeController {
1423
1422
  }
1424
1423
  }
1425
1424
  `);
1426
- }
1427
1425
  }
1428
1426
  if (opts.orm === "drizzle") {
1429
1427
  generateDrizzleConfig(target, opts.db, opts.dbUrl);
@@ -1511,7 +1509,7 @@ import { resolve as resolve6 } from "path";
1511
1509
  var VALID_OPTIONS = {
1512
1510
  style: ["nest", "adonis", "functional"],
1513
1511
  view: ["rendu", "edge", "eta", "inertia", "none"],
1514
- orm: ["drizzle", "prisma", "kysely", "none"],
1512
+ orm: ["drizzle", "kysely", "none"],
1515
1513
  db: ["bun-sqlite", "node-sqlite", "libsql", "postgres", "mysql", "none"],
1516
1514
  frontend: ["react", "vue", "svelte", "solid"]
1517
1515
  };
@@ -1549,7 +1547,7 @@ var initCommand = {
1549
1547
  { name: "target", description: "Target directory (default: cwd)" },
1550
1548
  { name: "style", description: "Routing style (nest|adonis|functional)" },
1551
1549
  { name: "view", description: "View engine (rendu|edge|eta|inertia|none)" },
1552
- { name: "orm", description: "ORM driver (drizzle|prisma|kysely|none)" },
1550
+ { name: "orm", description: "ORM driver (drizzle|kysely|none)" },
1553
1551
  { name: "db", description: "Database driver (bun-sqlite|node-sqlite|libsql|postgres|mysql|none)" },
1554
1552
  {
1555
1553
  name: "frontend",
@@ -1845,11 +1843,11 @@ var makeAuthCommand = {
1845
1843
  async run(ctx) {
1846
1844
  logger.heading("Scaffolding auth module");
1847
1845
  const providers = flagList(ctx.flags, "provider");
1848
- const jwtEnabled = ctx.flags["jwt"] === true;
1849
- const passkeyEnabled = ctx.flags["passkey"] === true;
1846
+ const jwtEnabled = ctx.flags.jwt === true;
1847
+ const passkeyEnabled = ctx.flags.passkey === true;
1850
1848
  const rpId = ctx.flags["rp-id"] ?? "localhost";
1851
1849
  const rpName = ctx.flags["rp-name"] ?? "NexusTS App";
1852
- const origin = ctx.flags["origin"] ?? "http://localhost:3000";
1850
+ const origin = ctx.flags.origin ?? "http://localhost:3000";
1853
1851
  const entries = providers.map((p) => {
1854
1852
  const known = KNOWN_PROVIDERS[p.toLowerCase()];
1855
1853
  return {
@@ -1930,14 +1928,14 @@ var makeControllerCommand = {
1930
1928
  return 1;
1931
1929
  }
1932
1930
  const variants = nameVariants(name);
1933
- const style = ctx.flags["style"] ?? ctx.config.routing;
1931
+ const style = ctx.flags.style ?? ctx.config.routing;
1934
1932
  if (!["nest", "adonis", "functional"].includes(style)) {
1935
1933
  logger.error(`Unknown style: ${style}. Allowed: nest, adonis, functional.`);
1936
1934
  return 1;
1937
1935
  }
1938
1936
  const skipService = ctx.flags["no-service"] === true;
1939
1937
  const serviceName = `${variants.pascal}Service`;
1940
- const serviceCamel = variants.camel + "Service";
1938
+ const serviceCamel = `${variants.camel}Service`;
1941
1939
  const tpl = templates.controller[style];
1942
1940
  const code = render(tpl, {
1943
1941
  name: variants.pascal,
@@ -2110,9 +2108,9 @@ var makeCrudCommand = {
2110
2108
  return 1;
2111
2109
  }
2112
2110
  const variants = nameVariants(name);
2113
- const style = ctx.flags["style"] ?? ctx.config.routing;
2114
- const orm = ctx.flags["orm"] ?? ctx.config.orm;
2115
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
2111
+ const style = ctx.flags.style ?? ctx.config.routing;
2112
+ const orm = ctx.flags.orm ?? ctx.config.orm;
2113
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
2116
2114
  const noRepo = flagBool(ctx.flags, "no-repo", false) || orm === "none";
2117
2115
  const noTest = flagBool(ctx.flags, "no-test", false);
2118
2116
  const hasInertia = ctx.config.view === "inertia" && !flagBool(ctx.flags, "no-views", false);
@@ -2132,7 +2130,7 @@ var makeCrudCommand = {
2132
2130
  snake: variants.snake,
2133
2131
  tableName,
2134
2132
  service,
2135
- serviceCamel: variants.camel + "Service",
2133
+ serviceCamel: `${variants.camel}Service`,
2136
2134
  controller,
2137
2135
  viewComponent,
2138
2136
  viewShowComponent,
@@ -2154,7 +2152,7 @@ var makeCrudCommand = {
2154
2152
  snake: variants.snake,
2155
2153
  hasRepo: !noRepo,
2156
2154
  repository,
2157
- repositoryCamel: variants.camel + "Repository"
2155
+ repositoryCamel: `${variants.camel}Repository`
2158
2156
  });
2159
2157
  const out = resolve9(ctx.cwd, ctx.config.paths.services, `${variants.kebab}.service.ts`);
2160
2158
  if (!writeFile(out, code, { skipIfExists: true })) {
@@ -2165,7 +2163,7 @@ var makeCrudCommand = {
2165
2163
  }
2166
2164
  }
2167
2165
  if (!noRepo) {
2168
- if (orm === "drizzle" || orm === "prisma" || orm === "kysely") {
2166
+ if (orm === "drizzle" || orm === "kysely") {
2169
2167
  let code;
2170
2168
  if (orm === "drizzle") {
2171
2169
  const tpl = renderDrizzleDialect(dialect);
@@ -2175,8 +2173,7 @@ var makeCrudCommand = {
2175
2173
  kebab: variants.kebab,
2176
2174
  snake: variants.snake,
2177
2175
  tableName,
2178
- columns: renderDrizzleColumns(dialect),
2179
- prismaBlock: ""
2176
+ columns: renderDrizzleColumns(dialect)
2180
2177
  });
2181
2178
  } else {
2182
2179
  const tpl = templates.model[orm];
@@ -2186,8 +2183,7 @@ var makeCrudCommand = {
2186
2183
  kebab: variants.kebab,
2187
2184
  snake: variants.snake,
2188
2185
  tableName,
2189
- columns: renderDefaultColumns(orm),
2190
- prismaBlock: ""
2186
+ columns: renderDefaultColumns(orm)
2191
2187
  });
2192
2188
  }
2193
2189
  const out = resolve9(ctx.cwd, ctx.config.paths.models, `${variants.kebab}.model.ts`);
@@ -2198,7 +2194,8 @@ var makeCrudCommand = {
2198
2194
  written.push(out);
2199
2195
  }
2200
2196
  }
2201
- const repoCode = render(templates.repository, {
2197
+ const ormRepo = orm === "kysely" ? templates.repository.kysely : templates.repository.drizzle;
2198
+ const repoCode = render(ormRepo, {
2202
2199
  name: variants.pascal,
2203
2200
  camel: variants.camel,
2204
2201
  kebab: variants.kebab,
@@ -2407,7 +2404,7 @@ var makeMigrationCommand = {
2407
2404
  },
2408
2405
  {
2409
2406
  name: "orm",
2410
- description: "Override ORM driver (drizzle|prisma|kysely|none)"
2407
+ description: "Override ORM driver (drizzle|kysely|none)"
2411
2408
  },
2412
2409
  {
2413
2410
  name: "dialect",
@@ -2420,19 +2417,30 @@ var makeMigrationCommand = {
2420
2417
  logger.error("Usage: nx make:migration <Name> [--dialect ...]");
2421
2418
  return 1;
2422
2419
  }
2423
- const orm = ctx.flags["orm"] ?? ctx.config.orm;
2424
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
2420
+ const orm = ctx.flags.orm ?? ctx.config.orm;
2421
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
2425
2422
  const isDrizzle = orm === "drizzle";
2426
- const useGenericSql = orm === "none" || orm === "prisma" || orm === "kysely";
2423
+ const isKysely = orm === "kysely";
2424
+ const useGenericSql = orm === "none";
2427
2425
  const variants = nameVariants(name);
2428
2426
  const tableName = inferTableName(name);
2429
- const colsFlag = ctx.flags["columns"];
2427
+ const colsFlag = ctx.flags.columns;
2430
2428
  const cols = parseColumns(colsFlag ?? "title:text");
2431
2429
  const drizzleColumns = renderDrizzleColumns2(cols, dialect);
2432
2430
  const sqlColumns = renderSqlColumns(cols, dialect);
2433
2431
  let code;
2434
2432
  let extension;
2435
- if (isDrizzle) {
2433
+ if (isKysely) {
2434
+ const tpl = templates.migration.kysely;
2435
+ code = render(tpl, {
2436
+ name: variants.pascal,
2437
+ snake: variants.snake,
2438
+ tableName,
2439
+ columns: renderKyselyColumns(cols),
2440
+ timestamp: formatTimestamp(new Date)
2441
+ });
2442
+ extension = "ts";
2443
+ } else if (isDrizzle) {
2436
2444
  if (!isValidDialect(dialect)) {
2437
2445
  logger.error(`Unsupported drizzle dialect: ${dialect}. Allowed: postgres, mysql, sqlite, bun-sqlite, d1.`);
2438
2446
  return 1;
@@ -2457,17 +2465,17 @@ var makeMigrationCommand = {
2457
2465
  });
2458
2466
  extension = "sql";
2459
2467
  } else {
2460
- logger.error(`Unsupported ORM for migration: ${orm}. Allowed: drizzle, none, prisma, kysely.`);
2468
+ logger.error(`Unsupported ORM for migration: ${orm}. Allowed: drizzle, kysely, none.`);
2461
2469
  return 1;
2462
2470
  }
2463
2471
  const filename = `${formatTimestamp(new Date)}_${variants.snake}.${extension}`;
2464
2472
  const out = resolve12(ctx.cwd, ctx.config.paths.migrations, filename);
2465
2473
  writeFile(out, code);
2466
2474
  logger.success(`created ${out}`);
2467
- if (isDrizzle) {
2468
- logger.finger(`run \`nx migrate\` to apply pending migrations.`);
2475
+ if (isDrizzle || isKysely) {
2476
+ logger.finger(`run \`nx db:migrate\` to apply pending migrations.`);
2469
2477
  } else {
2470
- logger.finger(`run \`bun nx db:generate & bun nx db:migrate\` or your migration tool.`);
2478
+ logger.finger(`run \`bun nx db:migrate\` or your migration tool.`);
2471
2479
  }
2472
2480
  return 0;
2473
2481
  }
@@ -2478,11 +2486,11 @@ function isValidDialect(d) {
2478
2486
  function inferTableName(input) {
2479
2487
  const m = /^create_(\w+)_table$/.exec(input);
2480
2488
  if (m)
2481
- return m[1];
2489
+ return m[1] ?? "";
2482
2490
  const m2 = /^(?:add|remove|drop|alter)_(\w+)_to_(\w+)$/.exec(input);
2483
2491
  if (m2)
2484
- return m2[2];
2485
- return input.toLowerCase().replace(/s$/, "") + "s";
2492
+ return m2[2] ?? "";
2493
+ return `${input.toLowerCase().replace(/s$/, "")}s`;
2486
2494
  }
2487
2495
  function parseColumns(input) {
2488
2496
  const list = Array.isArray(input) ? input : input.split(",");
@@ -2499,6 +2507,44 @@ function renderSqlColumns(cols, dialect) {
2499
2507
  }).join(`
2500
2508
  `);
2501
2509
  }
2510
+ function renderKyselyColumns(cols) {
2511
+ return cols.map(([name, type]) => {
2512
+ const kyselyType = mapKyselyType(type);
2513
+ return ` .addColumn('${name}', '${kyselyType}', (col) => col.notNull())`;
2514
+ }).join(`
2515
+ `);
2516
+ }
2517
+ function mapKyselyType(type) {
2518
+ switch (type.toLowerCase()) {
2519
+ case "text":
2520
+ case "string":
2521
+ case "varchar":
2522
+ return "text";
2523
+ case "int":
2524
+ case "integer":
2525
+ return "integer";
2526
+ case "bigint":
2527
+ return "bigint";
2528
+ case "bool":
2529
+ case "boolean":
2530
+ return "boolean";
2531
+ case "float":
2532
+ case "number":
2533
+ case "real":
2534
+ case "double":
2535
+ return "real";
2536
+ case "datetime":
2537
+ case "timestamp":
2538
+ return "text";
2539
+ case "date":
2540
+ return "text";
2541
+ case "json":
2542
+ case "jsonb":
2543
+ return "text";
2544
+ default:
2545
+ return "text";
2546
+ }
2547
+ }
2502
2548
  function renderDrizzleColumns2(cols, dialect) {
2503
2549
  return cols.map(([name, type]) => {
2504
2550
  const helper = mapDrizzleType(dialect, type);
@@ -2554,7 +2600,7 @@ var makeModelCommand = {
2554
2600
  name: "make:model",
2555
2601
  aliases: ["mmodel", "make-model"],
2556
2602
  summary: "Generate a model (table schema)",
2557
- description: "Generates a model file under app/models/. The template is chosen from nx.config.ts's `orm` field (drizzle|prisma|kysely). For drizzle, use --dialect to pick the import path.",
2603
+ description: "Generates a model file under app/models/. The template is chosen from nx.config.ts's `orm` field (drizzle|kysely). For drizzle, use --dialect to pick the import path.",
2558
2604
  examples: [
2559
2605
  "nx make:model User",
2560
2606
  'nx make:model User --columns "name:text,email:text"',
@@ -2568,7 +2614,7 @@ var makeModelCommand = {
2568
2614
  },
2569
2615
  {
2570
2616
  name: "orm",
2571
- description: "Override ORM driver (drizzle|prisma|kysely)"
2617
+ description: "Override ORM driver (drizzle|kysely)"
2572
2618
  },
2573
2619
  {
2574
2620
  name: "dialect",
@@ -2581,20 +2627,19 @@ var makeModelCommand = {
2581
2627
  logger.error("Usage: nx make:model <Name> [--columns name:type,...] [--dialect ...]");
2582
2628
  return 1;
2583
2629
  }
2584
- const orm = ctx.flags["orm"] ?? ctx.config.orm;
2585
- if (orm !== "drizzle" && orm !== "prisma" && orm !== "kysely") {
2586
- logger.error(`Unsupported ORM: ${orm}. Allowed: drizzle, prisma, kysely. Use --orm or set "orm" in nx.config.ts.`);
2630
+ const orm = ctx.flags.orm ?? ctx.config.orm;
2631
+ if (orm !== "drizzle" && orm !== "kysely") {
2632
+ logger.error(`Unsupported ORM: ${orm}. Allowed: drizzle, kysely. Use --orm or set "orm" in nx.config.ts.`);
2587
2633
  return 1;
2588
2634
  }
2589
2635
  const variants = nameVariants(name);
2590
2636
  const tableName = variants.pluralSnake;
2591
2637
  const colsFlag = flagList(ctx.flags, "columns");
2592
2638
  const columns = colsFlag.length > 0 ? colsFlag : ["title:text"];
2593
- const columnLines = renderColumns(columns, orm, ctx.flags["dialect"]);
2594
- const prismaBlock = renderPrismaBlock(variants.pascal, columns);
2639
+ const columnLines = renderColumns(columns, orm, ctx.flags.dialect);
2595
2640
  let code;
2596
2641
  if (orm === "drizzle") {
2597
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
2642
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
2598
2643
  if (!isValidDialect2(dialect)) {
2599
2644
  logger.error(`Unsupported drizzle dialect: ${dialect}. Allowed: postgres, mysql, sqlite, bun-sqlite, d1.`);
2600
2645
  return 1;
@@ -2606,8 +2651,7 @@ var makeModelCommand = {
2606
2651
  kebab: variants.kebab,
2607
2652
  snake: variants.snake,
2608
2653
  tableName,
2609
- columns: columnLines,
2610
- prismaBlock
2654
+ columns: columnLines
2611
2655
  });
2612
2656
  } else {
2613
2657
  const tpl = templates.model[orm];
@@ -2617,8 +2661,7 @@ var makeModelCommand = {
2617
2661
  kebab: variants.kebab,
2618
2662
  snake: variants.snake,
2619
2663
  tableName,
2620
- columns: columnLines,
2621
- prismaBlock
2664
+ columns: columnLines
2622
2665
  });
2623
2666
  }
2624
2667
  const out = resolve13(ctx.cwd, ctx.config.paths.models, `${variants.kebab}.model.ts`);
@@ -2649,34 +2692,13 @@ function renderColumns(cols, orm, dialect) {
2649
2692
  const tsType = colType === "text" ? "string" : colType;
2650
2693
  return ` ${colName}: ${tsType},`;
2651
2694
  }
2652
- case "prisma":
2653
- default:
2654
- return ` ${colName} ${colType},`;
2655
2695
  }
2656
2696
  }).join(`
2657
2697
  `);
2658
2698
  }
2659
- function renderPrismaBlock(modelName, cols) {
2660
- const fieldLines = cols.map((c2) => {
2661
- const [name, type = "String"] = c2.split(":");
2662
- return ` ${name.padEnd(16)} ${capitalize(type)}`;
2663
- }).join(`
2664
- `);
2665
- return ` * model ${modelName} {
2666
- * id Int @id @default(autoincrement())
2667
- ${fieldLines.split(`
2668
- `).map((l) => ` *${l}`).join(`
2669
- `)}
2670
- * createdAt DateTime @default(now())
2671
- * updatedAt DateTime @updatedAt
2672
- * }`;
2673
- }
2674
2699
  function toCamel2(s) {
2675
2700
  return s.replace(/_([a-z])/g, (_, c2) => c2.toUpperCase());
2676
2701
  }
2677
- function capitalize(s) {
2678
- return s.charAt(0).toUpperCase() + s.slice(1);
2679
- }
2680
2702
  var make_model_default = makeModelCommand;
2681
2703
 
2682
2704
  // packages/cli/src/commands/make-module.ts
@@ -2702,7 +2724,7 @@ var makeModuleCommand = {
2702
2724
  return 1;
2703
2725
  }
2704
2726
  const variants = nameVariants(name);
2705
- const hasController = !flagBool(ctx.flags, "no-controller", false);
2727
+ const _hasController = !flagBool(ctx.flags, "no-controller", false);
2706
2728
  const hasService = !flagBool(ctx.flags, "no-service", false);
2707
2729
  const hasRepo = !flagBool(ctx.flags, "no-repo", false) && ctx.config.orm !== "none";
2708
2730
  const code = render(templates.module, {
@@ -2841,7 +2863,7 @@ var makeQueueCommand = {
2841
2863
  return 1;
2842
2864
  }
2843
2865
  const variants = nameVariants(name);
2844
- const backend = ctx.flags["backend"] ?? ctx.config.queue?.backend ?? "memory";
2866
+ const backend = ctx.flags.backend ?? ctx.config.queue?.backend ?? "memory";
2845
2867
  if (!["bullmq", "cloudflare", "memory"].includes(backend)) {
2846
2868
  logger.error(`Unknown backend: ${backend}. Allowed: bullmq, cloudflare, memory.`);
2847
2869
  return 1;
@@ -2877,7 +2899,7 @@ var makeQueueCommand = {
2877
2899
  logger.info(` QueueModule.forRoot({ backend: '${backend}', ... })`);
2878
2900
  logger.info(`2. Wire the worker + helper as providers:`);
2879
2901
  logger.info(render(WIRE_HINT, { name: variants.pascal, kebab: variants.kebab }).split(`
2880
- `).map((l) => " " + l).join(`
2902
+ `).map((l) => ` ${l}`).join(`
2881
2903
  `));
2882
2904
  logger.info(`3. Replace the TODO in ${variants.pascal}Worker.handle() with your logic.`);
2883
2905
  logger.blank();
@@ -2893,24 +2915,33 @@ var makeRepositoryCommand = {
2893
2915
  name: "make:repository",
2894
2916
  aliases: ["mr", "make-repository", "make:repo"],
2895
2917
  summary: "Generate a repository class",
2896
- description: "Generates a DrizzleRepository class under app/repositories/. Requires a model file at app/models/<name>.model.ts.",
2918
+ description: "Generates a repository class under app/repositories/. Adapts to the project's ORM (drizzle -> DrizzleRepository, kysely -> KyselyRepository). Requires a model file at app/models/<name>.model.ts.",
2897
2919
  examples: [
2898
2920
  "nx make:repository User",
2899
2921
  "nx make:repository Post"
2900
2922
  ],
2923
+ flags: [
2924
+ {
2925
+ name: "orm",
2926
+ description: "Override ORM driver (drizzle|kysely)"
2927
+ }
2928
+ ],
2901
2929
  async run(ctx) {
2902
2930
  const name = ctx.positional[0];
2903
2931
  if (!name) {
2904
2932
  logger.error("Usage: nx make:repository <Name>");
2905
2933
  return 1;
2906
2934
  }
2935
+ const orm = ctx.flags.orm ?? ctx.config.orm;
2907
2936
  const variants = nameVariants(name);
2908
2937
  const repository = `${variants.pascal}Repository`;
2909
- const code = render(templates.repository, {
2938
+ const tpl = orm === "kysely" ? templates.repository.kysely : templates.repository.drizzle;
2939
+ const code = render(tpl, {
2910
2940
  name: variants.pascal,
2911
2941
  camel: variants.camel,
2912
2942
  kebab: variants.kebab,
2913
2943
  snake: variants.snake,
2944
+ tableName: variants.pluralSnake,
2914
2945
  repository
2915
2946
  });
2916
2947
  const out = resolve16(ctx.cwd, `${ctx.config.paths.app}/repositories`, `${variants.kebab}.repository.ts`);
@@ -3007,7 +3038,7 @@ var makeServiceCommand = {
3007
3038
  const variants = nameVariants(name);
3008
3039
  const hasRepo = ctx.flags["no-repo"] !== true && ctx.config.orm !== "none";
3009
3040
  const repository = `${variants.pascal}Repository`;
3010
- const repositoryCamel = variants.camel + "Repository";
3041
+ const repositoryCamel = `${variants.camel}Repository`;
3011
3042
  const code = render(templates.service, {
3012
3043
  name: variants.pascal,
3013
3044
  camel: variants.camel,
@@ -3139,11 +3170,10 @@ var dbMigrateCommand = {
3139
3170
  name: "db:migrate",
3140
3171
  aliases: ["db:m", "migrate"],
3141
3172
  summary: "Apply pending database migrations",
3142
- description: "Runs the Drizzle migrator against the configured migrations folder. Use --status to inspect, --generate to scaffold a new migration via drizzle-kit. See also `nx db:seed` for fixture data.",
3173
+ description: "Runs the configured migrator (drizzle-kit for Drizzle, Kysely Migrator for Kysely) against the migrations folder. Use --status to inspect. See also `nx db:seed` for fixture data.",
3143
3174
  examples: [
3144
3175
  "nx db:migrate",
3145
3176
  "nx db:migrate --status",
3146
- "nx db:migrate --generate 'add_email_to_users'",
3147
3177
  "nx db:migrate --folder ./drizzle"
3148
3178
  ],
3149
3179
  flags: [
@@ -3151,39 +3181,34 @@ var dbMigrateCommand = {
3151
3181
  name: "status",
3152
3182
  description: "List applied migrations and exit (no apply)."
3153
3183
  },
3154
- {
3155
- name: "generate",
3156
- description: "Run `drizzle-kit generate` with the given migration name."
3157
- },
3158
3184
  {
3159
3185
  name: "folder",
3160
3186
  description: "Override migrations folder (default: from nx.config.ts)."
3161
3187
  },
3162
3188
  {
3163
3189
  name: "dialect",
3164
- description: "Drizzle dialect (postgres|mysql|sqlite|bun-sqlite|d1). Default: bun-sqlite."
3190
+ description: "Database dialect (postgres|mysql|sqlite|bun-sqlite). Default: bun-sqlite."
3165
3191
  },
3166
3192
  {
3167
3193
  name: "config",
3168
3194
  description: "Path to drizzle.config.ts. Default: ./drizzle.config.ts."
3195
+ },
3196
+ {
3197
+ name: "orm",
3198
+ description: "Override ORM driver (drizzle|kysely)"
3169
3199
  }
3170
3200
  ],
3171
3201
  async run(ctx) {
3172
- const folder = ctx.flags["folder"] ?? resolve21(ctx.cwd, ctx.config.paths.migrations);
3173
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
3174
- const configPath = ctx.flags["config"] ?? resolve21(ctx.cwd, "drizzle.config.ts");
3175
- const wantStatus = Boolean(ctx.flags["status"]);
3176
- const generateName = ctx.flags["generate"];
3177
- if (generateName) {
3178
- return runDrizzleKit(ctx.cwd, [
3179
- "generate",
3180
- ...existsSync5(configPath) ? [`--config=${configPath}`] : [],
3181
- "--name",
3182
- generateName
3183
- ]);
3202
+ const orm = ctx.flags.orm ?? ctx.config.orm;
3203
+ const folder = ctx.flags.folder ?? resolve21(ctx.cwd, ctx.config.paths.migrations);
3204
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
3205
+ const configPath = ctx.flags.config ?? resolve21(ctx.cwd, "drizzle.config.ts");
3206
+ const wantStatus = Boolean(ctx.flags.status);
3207
+ if (orm === "kysely") {
3208
+ return runKyselyMigrate(ctx.cwd, folder, dialect, wantStatus);
3184
3209
  }
3185
3210
  if (wantStatus) {
3186
- return await runStatus(ctx.cwd, folder, dialect, ctx.config.database?.url ?? "");
3211
+ return await runStatus(ctx.cwd, folder, dialect, ctx.config.database.url);
3187
3212
  }
3188
3213
  return runDrizzleKit(ctx.cwd, [
3189
3214
  "migrate",
@@ -3191,6 +3216,133 @@ var dbMigrateCommand = {
3191
3216
  ]);
3192
3217
  }
3193
3218
  };
3219
+ async function runKyselyMigrate(cwd, folder, dialect, statusOnly) {
3220
+ if (!existsSync5(folder)) {
3221
+ logger.warn(`migrations folder not found: ${folder}`);
3222
+ return 0;
3223
+ }
3224
+ const script = buildKyselyMigrateScript(folder, dialect, statusOnly);
3225
+ const tmpFile = resolve21(cwd, ".nx-kysely-migrate.mjs");
3226
+ const { writeFile: writeFile2, unlink } = await import("fs/promises");
3227
+ await writeFile2(tmpFile, script, "utf-8");
3228
+ try {
3229
+ const code = await new Promise((resP) => {
3230
+ const child = spawn("bun", [tmpFile], {
3231
+ cwd,
3232
+ stdio: "inherit",
3233
+ shell: process.platform === "win32"
3234
+ });
3235
+ child.on("exit", (c2) => resP(c2 ?? 0));
3236
+ child.on("error", () => resP(1));
3237
+ });
3238
+ return code;
3239
+ } finally {
3240
+ await unlink(tmpFile).catch(() => {});
3241
+ }
3242
+ }
3243
+ function buildKyselyMigrateScript(folder, dialect, statusOnly) {
3244
+ const dialectSetup = buildDialectSetup(dialect);
3245
+ const tableName = "kysely_migration";
3246
+ return `
3247
+ import { readdirSync, readFileSync } from "node:fs";
3248
+ import { dirname, join } from "node:path";
3249
+
3250
+ const migrationsFolder = ${JSON.stringify(folder)};
3251
+
3252
+ // Build the Kysely instance with the configured dialect.
3253
+ ${dialectSetup}
3254
+
3255
+ import {
3256
+ Kysely,
3257
+ Migrator,
3258
+ } from "kysely";
3259
+
3260
+ class FsMigrationProvider {
3261
+ async getMigrations() {
3262
+ const files = readdirSync(migrationsFolder)
3263
+ .filter((f) => f.endsWith(".ts") || f.endsWith(".js"))
3264
+ .sort();
3265
+
3266
+ const migrations = {};
3267
+ for (const file of files) {
3268
+ const name = file.replace(/\\.(ts|js)$/, "");
3269
+ const mod = await import(join(migrationsFolder, file));
3270
+ migrations[name] = {
3271
+ up: mod.up,
3272
+ down: mod.down,
3273
+ };
3274
+ }
3275
+ return migrations;
3276
+ }
3277
+ }
3278
+
3279
+ const db = new Kysely({ dialect });
3280
+
3281
+ const migrator = new Migrator({
3282
+ db,
3283
+ provider: new FsMigrationProvider(),
3284
+ migrationTableName: ${JSON.stringify(tableName)},
3285
+ });
3286
+
3287
+ ${statusOnly ? `
3288
+ const { results } = await migrator.getMigrations();
3289
+ console.log("Migration status:");
3290
+ for (const r of results ?? []) {
3291
+ console.log(\` \${r.name}: \${r.status}\`);
3292
+ }
3293
+ ` : `
3294
+ const { results, error } = await migrator.migrateToLatest();
3295
+ if (error) {
3296
+ console.error("Migration failed:", error);
3297
+ process.exit(1);
3298
+ }
3299
+ const applied = (results ?? []).filter((r) => r.status === "Success" || r.status === "MigratedAbove");
3300
+ console.log(\`Applied \${applied.length} migration(s)\`);
3301
+ for (const r of applied) {
3302
+ console.log(\` \u2713 \${r.migrationName}\`);
3303
+ }
3304
+ `}
3305
+
3306
+ await db.destroy();
3307
+ `;
3308
+ }
3309
+ function buildDialectSetup(dialect) {
3310
+ switch (dialect) {
3311
+ case "postgres":
3312
+ return `
3313
+ import { Pool } from "pg";
3314
+ import { PostgresDialect } from "kysely";
3315
+ const dialect = new PostgresDialect({
3316
+ pool: new Pool({ connectionString: process.env.DATABASE_URL ?? "" }),
3317
+ });
3318
+ `;
3319
+ case "mysql":
3320
+ return `
3321
+ import { createPool } from "mysql2";
3322
+ import { MysqlDialect } from "kysely";
3323
+ const dialect = new MysqlDialect({
3324
+ pool: createPool({ uri: process.env.DATABASE_URL ?? "" }),
3325
+ });
3326
+ `;
3327
+ case "bun-sqlite":
3328
+ default:
3329
+ return `
3330
+ import { Database } from "bun:sqlite";
3331
+ import { SqliteDialect } from "kysely";
3332
+
3333
+ // Patch .reader property for bun:sqlite compatibility with Kysely.
3334
+ const _db = new Database(process.env.DATABASE_URL ?? "app.db");
3335
+ const proto = Object.getPrototypeOf(_db);
3336
+ const _prepare = proto.prepare.bind(_db);
3337
+ _db.prepare = function(sql) {
3338
+ const stmt = _prepare(sql);
3339
+ Object.defineProperty(stmt, "reader", { value: /^\\s*(select|pragma|with|explain)\\b/i.test(sql) });
3340
+ return stmt;
3341
+ };
3342
+ const dialect = new SqliteDialect({ database: _db });
3343
+ `;
3344
+ }
3345
+ }
3194
3346
  function runDrizzleKit(cwd, args2) {
3195
3347
  return new Promise((resolveP) => {
3196
3348
  const cmd = "bunx";
@@ -3249,7 +3401,7 @@ await svc.close();
3249
3401
  }
3250
3402
  }
3251
3403
  function readEnvUrl(dialect) {
3252
- const url = process.env["DATABASE_URL"] ?? process.env["NEXUS_DB_URL"] ?? (dialect === "postgres" ? process.env["POSTGRES_URL"] : dialect === "mysql" ? process.env["MYSQL_URL"] : dialect.includes("sqlite") ? process.env["SQLITE_FILENAME"] : null);
3404
+ const url = process.env.DATABASE_URL ?? process.env.NEXUS_DB_URL ?? (dialect === "postgres" ? process.env.POSTGRES_URL : dialect === "mysql" ? process.env.MYSQL_URL : dialect.includes("sqlite") ? process.env.SQLITE_FILENAME : null);
3253
3405
  return url ?? null;
3254
3406
  }
3255
3407
  var db_migrate_default = dbMigrateCommand;
@@ -3260,7 +3412,7 @@ var dbGenerateCommand = {
3260
3412
  name: "db:generate",
3261
3413
  aliases: ["db:g", "db-generate", "generate-migration"],
3262
3414
  summary: "Generate a new migration from schema changes",
3263
- description: "Generates a new migration file by running drizzle-kit generate with the project's config. " + "If no name is given, drizzle-kit auto-generates one. " + "Run after editing your schema files, then apply with `nx db:migrate`.",
3415
+ description: "Generates a new migration file. For drizzle: runs drizzle-kit generate. " + "For kysely: generates a .ts file with up/down functions. " + "Use --sql for a plain SQL file. " + "Run after editing your schema files, then apply with `nx db:migrate`.",
3264
3416
  examples: [
3265
3417
  "nx db:generate",
3266
3418
  "nx db:generate add_users_table",
@@ -3274,12 +3426,17 @@ var dbGenerateCommand = {
3274
3426
  {
3275
3427
  name: "sql",
3276
3428
  description: "Generate a raw SQL file instead of using drizzle-kit"
3429
+ },
3430
+ {
3431
+ name: "orm",
3432
+ description: "Override ORM driver (drizzle|kysely)"
3277
3433
  }
3278
3434
  ],
3279
3435
  async run(ctx) {
3280
3436
  const name = ctx.positional[0];
3281
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
3282
- const isSql = ctx.flags["sql"] === true;
3437
+ const orm = ctx.flags.orm ?? ctx.config.orm;
3438
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
3439
+ const isSql = ctx.flags.sql === true;
3283
3440
  if (isSql) {
3284
3441
  if (!name) {
3285
3442
  logger.error("Usage: nx db:generate <name> --sql");
@@ -3288,6 +3445,14 @@ var dbGenerateCommand = {
3288
3445
  logger.info(`Generating raw SQL migration: ${name} (dialect=${dialect})`);
3289
3446
  return runSqlTemplate(ctx.cwd, name, dialect);
3290
3447
  }
3448
+ if (orm === "kysely") {
3449
+ if (!name) {
3450
+ logger.error("Usage: nx db:generate <name> (name is required for Kysely)");
3451
+ return 1;
3452
+ }
3453
+ logger.info(`Generating Kysely migration: ${name}`);
3454
+ return runKyselyTemplate(ctx.cwd, name, dialect);
3455
+ }
3291
3456
  const configPath = resolve22(ctx.cwd, "drizzle.config.ts");
3292
3457
  const args2 = ["generate", "--config", configPath];
3293
3458
  if (name)
@@ -3296,6 +3461,28 @@ var dbGenerateCommand = {
3296
3461
  return runDrizzleKit(ctx.cwd, args2);
3297
3462
  }
3298
3463
  };
3464
+ async function runKyselyTemplate(cwd, name, _dialect) {
3465
+ const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import("fs");
3466
+ const { join } = await import("path");
3467
+ const migrationsDir = join(cwd, "app", "database", "migrations");
3468
+ mkdirSync5(migrationsDir, { recursive: true });
3469
+ const variants = nameVariants(name);
3470
+ const timestamp = formatTimestamp2(new Date);
3471
+ const filename = `${timestamp}_${variants.snake}.ts`;
3472
+ const filepath = join(migrationsDir, filename);
3473
+ const tpl = templates.migration.kysely;
3474
+ const code = render(tpl, {
3475
+ name: variants.pascal,
3476
+ snake: variants.snake,
3477
+ tableName: inferTableName2(name),
3478
+ columns: "",
3479
+ timestamp
3480
+ });
3481
+ writeFileSync4(filepath, code);
3482
+ logger.success(`created ${filepath}`);
3483
+ logger.info("Edit the migration, then run `nx db:migrate` to apply it.");
3484
+ return 0;
3485
+ }
3299
3486
  async function runSqlTemplate(cwd, name, dialect) {
3300
3487
  const { mkdirSync: mkdirSync5, writeFileSync: writeFileSync4 } = await import("fs");
3301
3488
  const { join } = await import("path");
@@ -3318,6 +3505,19 @@ async function runSqlTemplate(cwd, name, dialect) {
3318
3505
  logger.info("Edit the SQL file, then run `nx db:migrate` to apply it.");
3319
3506
  return 0;
3320
3507
  }
3508
+ function inferTableName2(input) {
3509
+ const m = /^create_(\w+)_table$/.exec(input);
3510
+ if (m)
3511
+ return m[1] ?? "";
3512
+ const m2 = /^(?:add|remove|drop|alter)_(\w+)_to_(\w+)$/.exec(input);
3513
+ if (m2)
3514
+ return m2[2] ?? "";
3515
+ return `${input.toLowerCase().replace(/s$/, "")}s`;
3516
+ }
3517
+ function formatTimestamp2(d) {
3518
+ const pad = (n) => String(n).padStart(2, "0");
3519
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}_${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
3520
+ }
3321
3521
  var db_generate_default = dbGenerateCommand;
3322
3522
 
3323
3523
  // packages/cli/src/commands/db-seed.ts
@@ -3394,11 +3594,11 @@ var dbSeedCommand = {
3394
3594
  }
3395
3595
  ],
3396
3596
  async run(ctx) {
3397
- const folder = resolve23(ctx.cwd, ctx.flags["folder"] ?? ctx.config.paths?.seeds ?? "db/seeds");
3398
- const dialect = ctx.flags["dialect"] ?? ctx.config.dialect ?? "bun-sqlite";
3399
- const createName = ctx.flags["create"];
3400
- const fileName = ctx.flags["file"];
3401
- const reset = Boolean(ctx.flags["reset"]);
3597
+ const folder = resolve23(ctx.cwd, ctx.flags.folder ?? ctx.config.paths?.seeds ?? "db/seeds");
3598
+ const dialect = ctx.flags.dialect ?? ctx.config.dialect ?? "bun-sqlite";
3599
+ const createName = ctx.flags.create;
3600
+ const fileName = ctx.flags.file;
3601
+ const reset = Boolean(ctx.flags.reset);
3402
3602
  if (createName) {
3403
3603
  return await createSeedFile(folder, createName);
3404
3604
  }
@@ -3515,7 +3715,7 @@ async function createSeedFile(folder, name) {
3515
3715
  return 0;
3516
3716
  }
3517
3717
  function readEnvUrl2(dialect) {
3518
- const url = process.env["DATABASE_URL"] ?? process.env["NEXUS_DB_URL"] ?? (dialect === "postgres" ? process.env["POSTGRES_URL"] : dialect === "mysql" ? process.env["MYSQL_URL"] : dialect.includes("sqlite") ? process.env["SQLITE_FILENAME"] : null);
3718
+ const url = process.env.DATABASE_URL ?? process.env.NEXUS_DB_URL ?? (dialect === "postgres" ? process.env.POSTGRES_URL : dialect === "mysql" ? process.env.MYSQL_URL : dialect.includes("sqlite") ? process.env.SQLITE_FILENAME : null);
3519
3719
  return url ?? null;
3520
3720
  }
3521
3721
  var db_seed_default = dbSeedCommand;
@@ -3526,7 +3726,7 @@ import { resolve as resolve24 } from "path";
3526
3726
  var VALID_OPTIONS2 = {
3527
3727
  style: ["nest", "adonis", "functional"],
3528
3728
  view: ["rendu", "edge", "eta", "inertia", "none"],
3529
- orm: ["drizzle", "prisma", "kysely", "none"],
3729
+ orm: ["drizzle", "kysely", "none"],
3530
3730
  db: ["bun-sqlite", "node-sqlite", "libsql", "postgres", "mysql", "none"],
3531
3731
  frontend: ["react", "vue", "svelte", "solid"]
3532
3732
  };
@@ -3561,7 +3761,7 @@ var newCommand = {
3561
3761
  flags: [
3562
3762
  { name: "style", description: "Routing style (nest|adonis|functional)" },
3563
3763
  { name: "view", description: "View engine (rendu|edge|eta|inertia|none)" },
3564
- { name: "orm", description: "ORM driver (drizzle|prisma|kysely|none)" },
3764
+ { name: "orm", description: "ORM driver (drizzle|kysely|none)" },
3565
3765
  { name: "db", description: "Database driver" },
3566
3766
  { name: "frontend", description: "Inertia frontend (react|vue|svelte|solid)" },
3567
3767
  { name: "no-ssr", description: "Disable SSR" }
@@ -3720,7 +3920,7 @@ var configCommand = {
3720
3920
  name: "view-paths",
3721
3921
  description: "Comma-separated directories searched for view files (e.g. resources/views)"
3722
3922
  },
3723
- { name: "orm", description: "ORM driver (drizzle|prisma|kysely|none)" },
3923
+ { name: "orm", description: "ORM driver (drizzle|kysely|none)" },
3724
3924
  {
3725
3925
  name: "db",
3726
3926
  description: "Database driver (bun-sqlite|node-sqlite|libsql|postgres|mysql|none)"
@@ -3741,7 +3941,7 @@ var configCommand = {
3741
3941
  async run(ctx) {
3742
3942
  const interactive = !flagBool(ctx.flags, "no-interaction", false);
3743
3943
  const force = flagBool(ctx.flags, "force", false);
3744
- const target = resolve25(ctx.cwd, ctx.flags["target"] ?? ".");
3944
+ const target = resolve25(ctx.cwd, ctx.flags.target ?? ".");
3745
3945
  if (!existsSync8(target)) {
3746
3946
  logger.error(`Target directory does not exist: ${target}`);
3747
3947
  return 1;
@@ -3750,21 +3950,27 @@ var configCommand = {
3750
3950
  const values = parseExistingConfig(nxConfigPath);
3751
3951
  const flag = (k) => ctx.flags[k];
3752
3952
  const flagBoolStrict = (k, def) => flagBool(ctx.flags, k, def);
3753
- if (flag("style"))
3754
- values.routing = flag("style");
3755
- if (flag("view"))
3756
- values.view = flag("view");
3757
- if (flag("view-paths")) {
3758
- values.viewPaths = flag("view-paths");
3759
- }
3760
- if (flag("orm"))
3761
- values.orm = flag("orm");
3762
- if (flag("db"))
3763
- values.dbDriver = flag("db");
3764
- if (flag("db-url") !== undefined)
3765
- values.dbUrl = flag("db-url");
3766
- if (flag("frontend"))
3767
- values.inertiaFrontend = flag("frontend");
3953
+ const style = flag("style");
3954
+ if (style)
3955
+ values.routing = style;
3956
+ const view = flag("view");
3957
+ if (view)
3958
+ values.view = view;
3959
+ const viewPaths = flag("view-paths");
3960
+ if (viewPaths)
3961
+ values.viewPaths = viewPaths;
3962
+ const orm = flag("orm");
3963
+ if (orm)
3964
+ values.orm = orm;
3965
+ const db = flag("db");
3966
+ if (db)
3967
+ values.dbDriver = db;
3968
+ const dbUrl = flag("db-url");
3969
+ if (dbUrl !== undefined)
3970
+ values.dbUrl = dbUrl;
3971
+ const frontend = flag("frontend");
3972
+ if (frontend)
3973
+ values.inertiaFrontend = frontend;
3768
3974
  if (flagBoolStrict("ssr", false))
3769
3975
  values.inertiaSSR = true;
3770
3976
  if (flagBoolStrict("no-ssr", false))
@@ -3779,7 +3985,7 @@ var configCommand = {
3779
3985
  interactive,
3780
3986
  default: values.view
3781
3987
  }) ?? values.view;
3782
- values.orm = await select("ORM driver", ["drizzle", "prisma", "kysely", "none"], {
3988
+ values.orm = await select("ORM driver", ["drizzle", "kysely", "none"], {
3783
3989
  interactive,
3784
3990
  default: values.orm
3785
3991
  }) ?? values.orm;
@@ -3804,12 +4010,12 @@ var configCommand = {
3804
4010
  const drizzleConfigPath = resolve25(target, "drizzle.config.ts");
3805
4011
  if (values.orm === "drizzle") {
3806
4012
  const dialect = driverToDialect(values.dbDriver);
3807
- const dbUrl = values.dbUrl;
4013
+ const dbUrl2 = values.dbUrl;
3808
4014
  const existedDrizzle = existsSync8(drizzleConfigPath);
3809
4015
  if (existedDrizzle && !force && !anyFlag) {
3810
4016
  logger.info(` - drizzle.config.ts (unchanged; pass --force or a flag to update)`);
3811
4017
  } else {
3812
- writeDrizzleConfig(target, { dialect, dbUrl });
4018
+ writeDrizzleConfig(target, { dialect, dbUrl: dbUrl2 });
3813
4019
  logger.info(` ${existedDrizzle ? "~" : "+"} drizzle.config.ts`);
3814
4020
  }
3815
4021
  } else if (existsSync8(drizzleConfigPath)) {
@@ -3924,9 +4130,9 @@ var replCommand = {
3924
4130
  }
3925
4131
  ],
3926
4132
  async run(ctx) {
3927
- const mod = ctx.flags["module"];
4133
+ const mod = ctx.flags.module;
3928
4134
  const noBoot = Boolean(ctx.flags["no-boot"]);
3929
- const histPath = resolve26(ctx.cwd, ctx.flags["history"] ?? ".nx-repl-history");
4135
+ const histPath = resolve26(ctx.cwd, ctx.flags.history ?? ".nx-repl-history");
3930
4136
  const env = { console };
3931
4137
  if (!noBoot) {
3932
4138
  const modPath = resolve26(ctx.cwd, mod ?? "app/app.module.ts");
@@ -4037,7 +4243,7 @@ var replCommand = {
4037
4243
  case ".routes": {
4038
4244
  const app = env.app;
4039
4245
  const getRoutes = app?.server?.router?.getRoutes;
4040
- const raw = typeof getRoutes === "function" ? getRoutes.call(app.server.router) : [];
4246
+ const raw = typeof getRoutes === "function" ? getRoutes.call(app?.server?.router) : [];
4041
4247
  const seen = new Set;
4042
4248
  const routes = raw.filter((r) => {
4043
4249
  const key = `${r.method}:${r.path}:${r.target?.name ?? ""}:${typeof r.propertyKey === "symbol" ? r.propertyKey.description ?? "" : String(r.propertyKey)}`;
@@ -4087,7 +4293,7 @@ var replCommand = {
4087
4293
  if (trimmed.startsWith(".")) {
4088
4294
  await handleDotCommand(trimmed);
4089
4295
  } else {
4090
- buffer += line + `
4296
+ buffer += `${line}
4091
4297
  `;
4092
4298
  if (isIncomplete(buffer)) {
4093
4299
  rl.setPrompt("... ");
@@ -4300,14 +4506,14 @@ var routeListCommand = {
4300
4506
  }
4301
4507
  }
4302
4508
  } catch (err) {
4303
- logger.warn(`could not parse ${file}: ${err.message ?? err}`);
4509
+ logger.warn(`could not parse ${file}: ${err instanceof Error ? err.message : String(err)}`);
4304
4510
  }
4305
4511
  }
4306
4512
  if (routes.length === 0) {
4307
4513
  logger.info("No routes discovered via metadata. " + "This usually means the controllers use the Adonis or functional style \u2014 see nx.config.ts:routing.");
4308
4514
  return 0;
4309
4515
  }
4310
- const format = ctx.flags["format"] ?? "table";
4516
+ const format = ctx.flags.format ?? "table";
4311
4517
  if (format === "json") {
4312
4518
  console.log(JSON.stringify(routes, null, 2));
4313
4519
  return 0;
@@ -4378,11 +4584,11 @@ async function main() {
4378
4584
  const parsed = parseArgs(process.argv.slice(2));
4379
4585
  const verbose = flagBool(parsed.flags, "verbose", false);
4380
4586
  logger.setVerbose(verbose);
4381
- if (parsed.flags["version"] === true) {
4587
+ if (parsed.flags.version === true) {
4382
4588
  console.log(PKG_VERSION);
4383
4589
  return 0;
4384
4590
  }
4385
- if (parsed.flags["help"] === true || parsed.command === "help") {
4591
+ if (parsed.flags.help === true || parsed.command === "help") {
4386
4592
  return renderHelp(parsed.positional[0]);
4387
4593
  }
4388
4594
  const command = parsed.command ? findCommand(parsed.command) : undefined;
@@ -4476,11 +4682,11 @@ Examples`));
4476
4682
  var PKG_VERSION = "0.1.0";
4477
4683
  main().then((code) => process.exit(code)).catch((err) => {
4478
4684
  logger.error(err?.message ?? String(err));
4479
- if (process.env["NX_DEBUG"] === "1" && err?.stack) {
4685
+ if (process.env.NX_DEBUG === "1" && err?.stack) {
4480
4686
  console.error(err.stack);
4481
4687
  }
4482
4688
  process.exit(1);
4483
4689
  });
4484
4690
 
4485
- //# debugId=CD81895BB61DC37964756E2164756E21
4691
+ //# debugId=DCF6821370D4409A64756E2164756E21
4486
4692
  //# sourceMappingURL=index.js.map