@dudousxd/nestjs-codegen 0.11.0 → 0.12.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.
package/dist/cli/main.cjs CHANGED
@@ -217,8 +217,8 @@ Run \`nestjs-codegen init\` to create a starter config.`
217
217
  }
218
218
 
219
219
  // src/generate.ts
220
- var import_promises11 = require("fs/promises");
221
- var import_node_path12 = require("path");
220
+ var import_promises12 = require("fs/promises");
221
+ var import_node_path13 = require("path");
222
222
 
223
223
  // src/discovery/pages.ts
224
224
  var import_promises2 = require("fs/promises");
@@ -2113,6 +2113,99 @@ function buildEmpty() {
2113
2113
  ].join("\n");
2114
2114
  }
2115
2115
 
2116
+ // src/generate-manifest.ts
2117
+ var import_node_crypto = require("crypto");
2118
+ var import_promises11 = require("fs/promises");
2119
+ var import_node_path12 = require("path");
2120
+ var import_fast_glob2 = __toESM(require("fast-glob"), 1);
2121
+ var MANIFEST_FILE = ".codegen-manifest.json";
2122
+ var LOCK_FILE = ".watcher.lock";
2123
+ function isManifestShape(value) {
2124
+ if (typeof value !== "object" || value === null) return false;
2125
+ const candidate = value;
2126
+ if (typeof candidate.version !== "string") return false;
2127
+ if (typeof candidate.hash !== "string") return false;
2128
+ if (!Array.isArray(candidate.files)) return false;
2129
+ return candidate.files.every((entry) => typeof entry === "string");
2130
+ }
2131
+ function serializeConfig(config) {
2132
+ try {
2133
+ return JSON.stringify(config, (_key, value) => {
2134
+ if (typeof value === "function") return `[fn:${value.name}]${value.toString()}`;
2135
+ return value;
2136
+ });
2137
+ } catch {
2138
+ return `unserializable:${config.codegen.outDir}:${config.contracts.glob}`;
2139
+ }
2140
+ }
2141
+ async function discoverInputFiles(config) {
2142
+ const globs = [config.contracts.glob, config.forms.watch];
2143
+ if (config.pages) globs.push(config.pages.glob);
2144
+ const cwd = config.codegen.cwd;
2145
+ const matched = await (0, import_fast_glob2.default)(globs, { cwd, absolute: true, onlyFiles: true });
2146
+ return [...new Set(matched)].sort();
2147
+ }
2148
+ async function computeInputsHash(config) {
2149
+ const hash = (0, import_node_crypto.createHash)("sha256");
2150
+ hash.update(`version:${VERSION}
2151
+ `);
2152
+ hash.update(`config:${serializeConfig(config)}
2153
+ `);
2154
+ const inputFiles = await discoverInputFiles(config);
2155
+ const cwd = config.codegen.cwd;
2156
+ for (const file of inputFiles) {
2157
+ const contents = await (0, import_promises11.readFile)(file, "utf8");
2158
+ hash.update(`file:${(0, import_node_path12.relative)(cwd, file)}
2159
+ `);
2160
+ hash.update(contents);
2161
+ hash.update("\n");
2162
+ }
2163
+ return hash.digest("hex");
2164
+ }
2165
+ async function readManifest(outDir) {
2166
+ try {
2167
+ const raw = await (0, import_promises11.readFile)((0, import_node_path12.join)(outDir, MANIFEST_FILE), "utf8");
2168
+ const parsed = JSON.parse(raw);
2169
+ if (!isManifestShape(parsed)) return null;
2170
+ return { version: parsed.version, hash: parsed.hash, files: parsed.files };
2171
+ } catch {
2172
+ return null;
2173
+ }
2174
+ }
2175
+ async function writeManifest(outDir, manifest) {
2176
+ await (0, import_promises11.writeFile)((0, import_node_path12.join)(outDir, MANIFEST_FILE), `${JSON.stringify(manifest, null, 2)}
2177
+ `, "utf8");
2178
+ }
2179
+ async function listOutputFiles(outDir) {
2180
+ const found = [];
2181
+ async function walk(dir) {
2182
+ const entries = await (0, import_promises11.readdir)(dir, { withFileTypes: true }).catch(() => []);
2183
+ for (const entry of entries) {
2184
+ const abs = (0, import_node_path12.join)(dir, entry.name);
2185
+ if (entry.isDirectory()) {
2186
+ await walk(abs);
2187
+ } else if (entry.isFile()) {
2188
+ const rel = (0, import_node_path12.relative)(outDir, abs);
2189
+ if (rel === MANIFEST_FILE || rel === LOCK_FILE) continue;
2190
+ found.push(rel);
2191
+ }
2192
+ }
2193
+ }
2194
+ await walk(outDir);
2195
+ return found.sort();
2196
+ }
2197
+ async function allOutputsExist(outDir, files) {
2198
+ const present = new Set(await listOutputFiles(outDir));
2199
+ return files.every((file) => present.has(file));
2200
+ }
2201
+ async function isManifestFresh(outDir, manifest, inputsHash) {
2202
+ if (manifest === null) return false;
2203
+ if (manifest.version !== VERSION) return false;
2204
+ if (manifest.hash !== inputsHash) return false;
2205
+ if (manifest.files.length === 0) return false;
2206
+ return allOutputsExist(outDir, manifest.files);
2207
+ }
2208
+
2116
2209
  // src/util/debug-log.ts
2117
2210
  var debugEnabled = false;
2118
2211
  function setCodegenDebug(enabled) {
@@ -2125,6 +2218,12 @@ function debugWarn(message) {
2125
2218
  // src/generate.ts
2126
2219
  async function generate(config, inputRoutes = []) {
2127
2220
  setCodegenDebug(config.debug);
2221
+ const inputsHash = await computeInputsHash(config);
2222
+ const manifest = await readManifest(config.codegen.outDir);
2223
+ if (await isManifestFresh(config.codegen.outDir, manifest, inputsHash)) {
2224
+ console.log(`[nestjs-codegen] ${config.codegen.outDir} up to date, skipped`);
2225
+ return;
2226
+ }
2128
2227
  const extensions = config.extensions ?? [];
2129
2228
  let routes = inputRoutes;
2130
2229
  const ctx = createExtensionContext(config, () => routes);
@@ -2181,21 +2280,27 @@ async function generate(config, inputRoutes = []) {
2181
2280
  if (extensions.length > 0) {
2182
2281
  const extraFiles = await collectEmittedFiles(extensions, ctx);
2183
2282
  for (const file of extraFiles) {
2184
- const dest = (0, import_node_path12.join)(config.codegen.outDir, file.path);
2185
- await (0, import_promises11.mkdir)((0, import_node_path12.dirname)(dest), { recursive: true });
2186
- await (0, import_promises11.writeFile)(dest, file.contents, "utf8");
2283
+ const dest = (0, import_node_path13.join)(config.codegen.outDir, file.path);
2284
+ await (0, import_promises12.mkdir)((0, import_node_path13.dirname)(dest), { recursive: true });
2285
+ await (0, import_promises12.writeFile)(dest, file.contents, "utf8");
2187
2286
  }
2188
2287
  }
2288
+ const outputFiles = await listOutputFiles(config.codegen.outDir);
2289
+ await writeManifest(config.codegen.outDir, {
2290
+ version: VERSION,
2291
+ hash: inputsHash,
2292
+ files: outputFiles
2293
+ });
2189
2294
  }
2190
2295
 
2191
2296
  // src/watch/watcher.ts
2192
- var import_promises14 = require("fs/promises");
2193
- var import_node_path16 = require("path");
2297
+ var import_promises15 = require("fs/promises");
2298
+ var import_node_path17 = require("path");
2194
2299
  var import_chokidar = __toESM(require("chokidar"), 1);
2195
2300
 
2196
2301
  // src/discovery/contracts-fast.ts
2197
- var import_node_path14 = require("path");
2198
- var import_fast_glob2 = __toESM(require("fast-glob"), 1);
2302
+ var import_node_path15 = require("path");
2303
+ var import_fast_glob3 = __toESM(require("fast-glob"), 1);
2199
2304
  var import_ts_morph9 = require("ts-morph");
2200
2305
 
2201
2306
  // src/discovery/dto-type-resolver.ts
@@ -2206,7 +2311,7 @@ var import_ts_morph4 = require("ts-morph");
2206
2311
 
2207
2312
  // src/discovery/type-ref-resolution.ts
2208
2313
  var import_node_fs = require("fs");
2209
- var import_node_path13 = require("path");
2314
+ var import_node_path14 = require("path");
2210
2315
  var import_ts_morph3 = require("ts-morph");
2211
2316
  var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
2212
2317
  var _ctxByProject = /* @__PURE__ */ new WeakMap();
@@ -2258,12 +2363,12 @@ function findTypeInFile(name, file) {
2258
2363
  }
2259
2364
  function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2260
2365
  if (moduleSpecifier.startsWith(".")) {
2261
- const dir = (0, import_node_path13.dirname)(sourceFile.getFilePath());
2366
+ const dir = (0, import_node_path14.dirname)(sourceFile.getFilePath());
2262
2367
  const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
2263
2368
  return [
2264
- (0, import_node_path13.resolve)(dir, `${noExt}.ts`),
2265
- (0, import_node_path13.resolve)(dir, `${moduleSpecifier}.ts`),
2266
- (0, import_node_path13.resolve)(dir, moduleSpecifier, "index.ts")
2369
+ (0, import_node_path14.resolve)(dir, `${noExt}.ts`),
2370
+ (0, import_node_path14.resolve)(dir, `${moduleSpecifier}.ts`),
2371
+ (0, import_node_path14.resolve)(dir, moduleSpecifier, "index.ts")
2267
2372
  ];
2268
2373
  }
2269
2374
  const ctx = _ctxFor(project);
@@ -2284,8 +2389,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2284
2389
  const rest = moduleSpecifier.slice(prefix.length);
2285
2390
  const candidates = [];
2286
2391
  for (const mapping of mappings) {
2287
- const resolved = (0, import_node_path13.resolve)(baseUrl, mapping.replace("*", rest));
2288
- candidates.push(`${resolved}.ts`, (0, import_node_path13.resolve)(resolved, "index.ts"));
2392
+ const resolved = (0, import_node_path14.resolve)(baseUrl, mapping.replace("*", rest));
2393
+ candidates.push(`${resolved}.ts`, (0, import_node_path14.resolve)(resolved, "index.ts"));
2289
2394
  }
2290
2395
  dbg(" resolved candidates:", candidates);
2291
2396
  return candidates;
@@ -3957,7 +4062,7 @@ async function discoverContractsFast(opts) {
3957
4062
  const { cwd, glob, tsconfig } = opts;
3958
4063
  const tsconfigPath = resolveTsconfigPath(cwd, tsconfig);
3959
4064
  const project = createDiscoveryProject(tsconfigPath);
3960
- const files = await (0, import_fast_glob2.default)(glob, { cwd, absolute: true, onlyFiles: true });
4065
+ const files = await (0, import_fast_glob3.default)(glob, { cwd, absolute: true, onlyFiles: true });
3961
4066
  for (const f of files) {
3962
4067
  project.addSourceFileAtPath(f);
3963
4068
  }
@@ -3965,7 +4070,7 @@ async function discoverContractsFast(opts) {
3965
4070
  return extractAllRoutes(project);
3966
4071
  }
3967
4072
  function resolveTsconfigPath(cwd, tsconfig) {
3968
- return tsconfig ? (0, import_node_path14.resolve)(tsconfig) : (0, import_node_path14.join)(cwd, "tsconfig.json");
4073
+ return tsconfig ? (0, import_node_path15.resolve)(tsconfig) : (0, import_node_path15.join)(cwd, "tsconfig.json");
3969
4074
  }
3970
4075
  function createDiscoveryProject(tsconfigPath) {
3971
4076
  try {
@@ -4030,7 +4135,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4030
4135
  const project = createDiscoveryProject(tsconfigPath);
4031
4136
  bindDiscoveryContext(project, cwd, tsconfigPath);
4032
4137
  const instance = new _PersistentDiscovery(project, cwd, glob);
4033
- const files = await (0, import_fast_glob2.default)(glob, { cwd, absolute: true, onlyFiles: true });
4138
+ const files = await (0, import_fast_glob3.default)(glob, { cwd, absolute: true, onlyFiles: true });
4034
4139
  for (const f of files) {
4035
4140
  project.addSourceFileAtPath(f);
4036
4141
  instance.controllerPaths.add(f);
@@ -4051,7 +4156,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4051
4156
  async rediscover(changedPaths) {
4052
4157
  if (changedPaths) {
4053
4158
  for (const p of changedPaths) {
4054
- const abs = (0, import_node_path14.resolve)(p);
4159
+ const abs = (0, import_node_path15.resolve)(p);
4055
4160
  const sf = this.project.getSourceFile(abs);
4056
4161
  if (sf) {
4057
4162
  await sf.refreshFromFileSystem();
@@ -4059,7 +4164,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4059
4164
  }
4060
4165
  }
4061
4166
  const globbed = new Set(
4062
- await (0, import_fast_glob2.default)(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
4167
+ await (0, import_fast_glob3.default)(this.glob, { cwd: this.cwd, absolute: true, onlyFiles: true })
4063
4168
  );
4064
4169
  for (const f of globbed) {
4065
4170
  if (!this.controllerPaths.has(f)) {
@@ -4339,10 +4444,10 @@ function extractFromSourceFile(sourceFile, project) {
4339
4444
  }
4340
4445
 
4341
4446
  // src/watch/lock-file.ts
4342
- var import_promises12 = require("fs/promises");
4343
4447
  var import_promises13 = require("fs/promises");
4344
- var import_node_path15 = require("path");
4345
- var LOCK_FILE = ".watcher.lock";
4448
+ var import_promises14 = require("fs/promises");
4449
+ var import_node_path16 = require("path");
4450
+ var LOCK_FILE2 = ".watcher.lock";
4346
4451
  function isProcessAlive(pid) {
4347
4452
  try {
4348
4453
  process.kill(pid, 0);
@@ -4352,21 +4457,21 @@ function isProcessAlive(pid) {
4352
4457
  }
4353
4458
  }
4354
4459
  async function acquireLock(outDir) {
4355
- await (0, import_promises13.mkdir)(outDir, { recursive: true });
4356
- const lockPath = (0, import_node_path15.join)(outDir, LOCK_FILE);
4460
+ await (0, import_promises14.mkdir)(outDir, { recursive: true });
4461
+ const lockPath = (0, import_node_path16.join)(outDir, LOCK_FILE2);
4357
4462
  const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
4358
4463
  try {
4359
- const fd = await (0, import_promises12.open)(lockPath, "wx");
4464
+ const fd = await (0, import_promises13.open)(lockPath, "wx");
4360
4465
  await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
4361
4466
  `, "utf8");
4362
4467
  await fd.close();
4363
4468
  } catch (err) {
4364
4469
  if (err.code === "EEXIST") {
4365
4470
  try {
4366
- const raw = await (0, import_promises13.readFile)(lockPath, "utf8");
4471
+ const raw = await (0, import_promises14.readFile)(lockPath, "utf8");
4367
4472
  const existing = JSON.parse(raw);
4368
4473
  if (isProcessAlive(existing.pid)) return null;
4369
- await (0, import_promises13.unlink)(lockPath);
4474
+ await (0, import_promises14.unlink)(lockPath);
4370
4475
  return acquireLock(outDir);
4371
4476
  } catch {
4372
4477
  return null;
@@ -4377,7 +4482,7 @@ async function acquireLock(outDir) {
4377
4482
  return {
4378
4483
  release: async () => {
4379
4484
  try {
4380
- await (0, import_promises13.unlink)(lockPath);
4485
+ await (0, import_promises14.unlink)(lockPath);
4381
4486
  } catch {
4382
4487
  }
4383
4488
  }
@@ -4388,12 +4493,12 @@ async function acquireLock(outDir) {
4388
4493
  var PAGES_DEBOUNCE_MS = 150;
4389
4494
  var NO_OP_WATCHER = { close: async () => {
4390
4495
  } };
4391
- async function watch(config, onChange) {
4496
+ async function watch(config, onChange, options = {}) {
4392
4497
  const lock = await acquireLock(config.codegen.outDir);
4393
4498
  if (lock === null) {
4394
4499
  let holderPid = "unknown";
4395
4500
  try {
4396
- const raw = await (0, import_promises14.readFile)((0, import_node_path16.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4501
+ const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(config.codegen.outDir, ".watcher.lock"), "utf8");
4397
4502
  const data = JSON.parse(raw);
4398
4503
  if (data.pid !== void 0) holderPid = String(data.pid);
4399
4504
  } catch {
@@ -4416,22 +4521,33 @@ async function watch(config, onChange) {
4416
4521
  }
4417
4522
  return discovery;
4418
4523
  }
4419
- try {
4420
- const initialRoutes = (await getDiscovery()).discover();
4421
- lastRoutes = initialRoutes;
4422
- await generate(config, initialRoutes);
4423
- } catch (err) {
4424
- console.warn(
4425
- `[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
4426
- );
4524
+ async function runInitialPass() {
4427
4525
  try {
4428
- await generate(config, lastRoutes);
4429
- } catch {
4526
+ const initialRoutes = (await getDiscovery()).discover();
4527
+ lastRoutes = initialRoutes;
4528
+ await generate(config, initialRoutes);
4529
+ } catch (err) {
4530
+ console.warn(
4531
+ `[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
4532
+ );
4533
+ try {
4534
+ await generate(config, lastRoutes);
4535
+ } catch {
4536
+ }
4430
4537
  }
4431
4538
  }
4539
+ if (options.deferInitialGenerate) {
4540
+ void runInitialPass().catch((err) => {
4541
+ console.warn(
4542
+ `[nestjs-codegen] Background initial generate failed: ${err instanceof Error ? err.message : String(err)}`
4543
+ );
4544
+ });
4545
+ } else {
4546
+ await runInitialPass();
4547
+ }
4432
4548
  let pagesDebounceTimer;
4433
4549
  const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
4434
- const pagesWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, pagesGlob), {
4550
+ const pagesWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, pagesGlob), {
4435
4551
  ignoreInitial: true,
4436
4552
  persistent: true,
4437
4553
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4458,7 +4574,7 @@ async function watch(config, onChange) {
4458
4574
  pagesWatcher.on("unlink", schedulePagesRegenerate);
4459
4575
  let contractsDebounceTimer;
4460
4576
  const pendingChangedPaths = /* @__PURE__ */ new Set();
4461
- const contractsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.contracts.glob), {
4577
+ const contractsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.contracts.glob), {
4462
4578
  ignoreInitial: true,
4463
4579
  persistent: true,
4464
4580
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4488,7 +4604,7 @@ async function watch(config, onChange) {
4488
4604
  contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
4489
4605
  contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
4490
4606
  contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
4491
- const formsWatcher = import_chokidar.default.watch((0, import_node_path16.join)(config.codegen.cwd, config.forms.watch), {
4607
+ const formsWatcher = import_chokidar.default.watch((0, import_node_path17.join)(config.codegen.cwd, config.forms.watch), {
4492
4608
  ignoreInitial: true,
4493
4609
  persistent: true,
4494
4610
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4515,7 +4631,7 @@ async function watch(config, onChange) {
4515
4631
  }
4516
4632
 
4517
4633
  // src/index.ts
4518
- var VERSION = "0.11.0";
4634
+ var VERSION = "0.12.0";
4519
4635
 
4520
4636
  // src/cli/codegen.ts
4521
4637
  async function runCodegen(opts = {}) {
@@ -4544,13 +4660,13 @@ async function runCodegen(opts = {}) {
4544
4660
  // src/cli/doctor.ts
4545
4661
  var import_node_child_process2 = require("child_process");
4546
4662
  var import_node_fs4 = require("fs");
4547
- var import_node_path18 = require("path");
4663
+ var import_node_path19 = require("path");
4548
4664
 
4549
4665
  // src/cli/init.ts
4550
4666
  var import_node_child_process = require("child_process");
4551
4667
  var import_node_fs3 = require("fs");
4552
- var import_promises15 = require("fs/promises");
4553
- var import_node_path17 = require("path");
4668
+ var import_promises16 = require("fs/promises");
4669
+ var import_node_path18 = require("path");
4554
4670
  var import_node_readline = require("readline");
4555
4671
 
4556
4672
  // src/cli/patch-utils.ts
@@ -4612,7 +4728,7 @@ ${bold(title)}`);
4612
4728
  }
4613
4729
  async function readPackageJson(cwd) {
4614
4730
  try {
4615
- const raw = await (0, import_promises15.readFile)((0, import_node_path17.join)(cwd, "package.json"), "utf8");
4731
+ const raw = await (0, import_promises16.readFile)((0, import_node_path18.join)(cwd, "package.json"), "utf8");
4616
4732
  return JSON.parse(raw);
4617
4733
  } catch {
4618
4734
  return {};
@@ -4643,7 +4759,7 @@ async function detectTemplateEngine(cwd) {
4643
4759
  async function detectPackageManager(cwd) {
4644
4760
  async function exists(file) {
4645
4761
  try {
4646
- await (0, import_promises15.access)((0, import_node_path17.join)(cwd, file));
4762
+ await (0, import_promises16.access)((0, import_node_path18.join)(cwd, file));
4647
4763
  return true;
4648
4764
  } catch {
4649
4765
  return false;
@@ -4671,7 +4787,7 @@ async function promptFramework() {
4671
4787
  }
4672
4788
  async function fileExists2(filePath) {
4673
4789
  try {
4674
- await (0, import_promises15.access)(filePath);
4790
+ await (0, import_promises16.access)(filePath);
4675
4791
  return true;
4676
4792
  } catch {
4677
4793
  return false;
@@ -4684,15 +4800,15 @@ async function writeIfNotExists(filePath, content, label) {
4684
4800
  }
4685
4801
  const dir = filePath.substring(0, filePath.lastIndexOf("/"));
4686
4802
  if (dir) {
4687
- await (0, import_promises15.mkdir)(dir, { recursive: true });
4803
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
4688
4804
  }
4689
- await (0, import_promises15.writeFile)(filePath, content, "utf8");
4805
+ await (0, import_promises16.writeFile)(filePath, content, "utf8");
4690
4806
  logCreated(label);
4691
4807
  }
4692
4808
  async function handleViteConfig(cwd, framework) {
4693
- const filePath = (0, import_node_path17.join)(cwd, "vite.config.ts");
4809
+ const filePath = (0, import_node_path18.join)(cwd, "vite.config.ts");
4694
4810
  if (await fileExists2(filePath)) {
4695
- const existing = await (0, import_promises15.readFile)(filePath, "utf8");
4811
+ const existing = await (0, import_promises16.readFile)(filePath, "utf8");
4696
4812
  const hasPlugin = existing.includes("nestInertia") || existing.includes("nestjs-inertia-vite/plugin");
4697
4813
  if (!hasPlugin) {
4698
4814
  logSkipped("vite.config.ts");
@@ -4708,15 +4824,15 @@ async function handleViteConfig(cwd, framework) {
4708
4824
  }
4709
4825
  const dir = filePath.substring(0, filePath.lastIndexOf("/"));
4710
4826
  if (dir) {
4711
- await (0, import_promises15.mkdir)(dir, { recursive: true });
4827
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
4712
4828
  }
4713
- await (0, import_promises15.writeFile)(filePath, viteConfigTemplate(framework), "utf8");
4829
+ await (0, import_promises16.writeFile)(filePath, viteConfigTemplate(framework), "utf8");
4714
4830
  logCreated("vite.config.ts");
4715
4831
  }
4716
4832
  async function patchGitignore(gitignorePath) {
4717
4833
  let existing = "";
4718
4834
  if (await fileExists2(gitignorePath)) {
4719
- existing = await (0, import_promises15.readFile)(gitignorePath, "utf8");
4835
+ existing = await (0, import_promises16.readFile)(gitignorePath, "utf8");
4720
4836
  }
4721
4837
  if (existing.split("\n").some((line) => line.trim() === GITIGNORE_ENTRY)) {
4722
4838
  console.log(` ${cyan("\u2192")} .gitignore ${dim("(already contains .nestjs-inertia/, skipped)")}`);
@@ -4726,7 +4842,7 @@ async function patchGitignore(gitignorePath) {
4726
4842
  ` : `${existing}
4727
4843
  ${GITIGNORE_ENTRY}
4728
4844
  `;
4729
- await (0, import_promises15.writeFile)(gitignorePath, newContent, "utf8");
4845
+ await (0, import_promises16.writeFile)(gitignorePath, newContent, "utf8");
4730
4846
  logPatched(".gitignore", "added .nestjs-inertia/");
4731
4847
  }
4732
4848
  function installDeps(pkgManager, deps, dev) {
@@ -4748,10 +4864,10 @@ function installDeps(pkgManager, deps, dev) {
4748
4864
  }
4749
4865
  }
4750
4866
  async function patchPackageJsonScripts(cwd, scripts) {
4751
- const pkgPath = (0, import_node_path17.join)(cwd, "package.json");
4867
+ const pkgPath = (0, import_node_path18.join)(cwd, "package.json");
4752
4868
  let pkg = {};
4753
4869
  try {
4754
- pkg = JSON.parse(await (0, import_promises15.readFile)(pkgPath, "utf8"));
4870
+ pkg = JSON.parse(await (0, import_promises16.readFile)(pkgPath, "utf8"));
4755
4871
  } catch {
4756
4872
  return;
4757
4873
  }
@@ -4770,7 +4886,7 @@ async function patchPackageJsonScripts(cwd, scripts) {
4770
4886
  return;
4771
4887
  }
4772
4888
  pkg.scripts = existing;
4773
- await (0, import_promises15.writeFile)(pkgPath, `${JSON.stringify(pkg, null, 2)}
4889
+ await (0, import_promises16.writeFile)(pkgPath, `${JSON.stringify(pkg, null, 2)}
4774
4890
  `, "utf8");
4775
4891
  }
4776
4892
  function patchAppModule(filePath, rootView) {
@@ -5065,7 +5181,7 @@ export class HomeController {
5065
5181
  }
5066
5182
  `;
5067
5183
  function patchTsconfigExclude(cwd, dir, filename = "tsconfig.json") {
5068
- const filePath = (0, import_node_path17.join)(cwd, filename);
5184
+ const filePath = (0, import_node_path18.join)(cwd, filename);
5069
5185
  return patchJsonFile(
5070
5186
  filePath,
5071
5187
  (json) => {
@@ -5080,7 +5196,7 @@ function patchTsconfigExclude(cwd, dir, filename = "tsconfig.json") {
5080
5196
  );
5081
5197
  }
5082
5198
  function patchNestCliJson(cwd, shellDir) {
5083
- const filePath = (0, import_node_path17.join)(cwd, "nest-cli.json");
5199
+ const filePath = (0, import_node_path18.join)(cwd, "nest-cli.json");
5084
5200
  return patchJsonFile(filePath, (json) => {
5085
5201
  const compiler = json.compilerOptions ?? {};
5086
5202
  const assets = compiler.assets ?? [];
@@ -5103,46 +5219,46 @@ async function scaffoldFiles(ctx) {
5103
5219
  const { cwd, framework, engine, shellFileName, entryExt, pageExt } = ctx;
5104
5220
  logSection("Scaffold files");
5105
5221
  await writeIfNotExists(
5106
- (0, import_node_path17.join)(cwd, "nestjs-inertia.config.ts"),
5222
+ (0, import_node_path18.join)(cwd, "nestjs-inertia.config.ts"),
5107
5223
  configTemplate(framework),
5108
5224
  "nestjs-inertia.config.ts"
5109
5225
  );
5110
- await writeIfNotExists((0, import_node_path17.join)(cwd, "nestjs-inertia.d.ts"), DTS_TEMPLATE, "nestjs-inertia.d.ts");
5226
+ await writeIfNotExists((0, import_node_path18.join)(cwd, "nestjs-inertia.d.ts"), DTS_TEMPLATE, "nestjs-inertia.d.ts");
5111
5227
  await writeIfNotExists(
5112
- (0, import_node_path17.join)(cwd, "tsconfig.inertia.json"),
5228
+ (0, import_node_path18.join)(cwd, "tsconfig.inertia.json"),
5113
5229
  TSCONFIG_INERTIA_TEMPLATE,
5114
5230
  "tsconfig.inertia.json"
5115
5231
  );
5116
5232
  await writeIfNotExists(
5117
- (0, import_node_path17.join)(cwd, "inertia", "tsconfig.json"),
5233
+ (0, import_node_path18.join)(cwd, "inertia", "tsconfig.json"),
5118
5234
  INERTIA_TSCONFIG_TEMPLATE,
5119
5235
  "inertia/tsconfig.json"
5120
5236
  );
5121
5237
  await writeIfNotExists(
5122
- (0, import_node_path17.join)(cwd, "inertia", shellFileName),
5238
+ (0, import_node_path18.join)(cwd, "inertia", shellFileName),
5123
5239
  htmlShellTemplate(framework, engine),
5124
5240
  `inertia/${shellFileName}`
5125
5241
  );
5126
5242
  await handleViteConfig(cwd, framework);
5127
5243
  await writeIfNotExists(
5128
- (0, import_node_path17.join)(cwd, "inertia", "app", `client.${entryExt}`),
5244
+ (0, import_node_path18.join)(cwd, "inertia", "app", `client.${entryExt}`),
5129
5245
  entryPointTemplate(framework),
5130
5246
  `inertia/app/client.${entryExt}`
5131
5247
  );
5132
5248
  await writeIfNotExists(
5133
- (0, import_node_path17.join)(cwd, "inertia", "pages", `Home.${pageExt}`),
5249
+ (0, import_node_path18.join)(cwd, "inertia", "pages", `Home.${pageExt}`),
5134
5250
  samplePageTemplate(framework),
5135
5251
  `inertia/pages/Home.${pageExt}`
5136
5252
  );
5137
5253
  await writeIfNotExists(
5138
- (0, import_node_path17.join)(cwd, "src", "home.controller.ts"),
5254
+ (0, import_node_path18.join)(cwd, "src", "home.controller.ts"),
5139
5255
  SAMPLE_CONTROLLER,
5140
5256
  "src/home.controller.ts"
5141
5257
  );
5142
5258
  }
5143
5259
  function patchServerAppModule(ctx) {
5144
5260
  const { cwd, rootView } = ctx;
5145
- const appModulePath = (0, import_node_path17.join)(cwd, "src", "app.module.ts");
5261
+ const appModulePath = (0, import_node_path18.join)(cwd, "src", "app.module.ts");
5146
5262
  const appModuleResult = patchAppModule(appModulePath, rootView);
5147
5263
  if (appModuleResult === "patched") {
5148
5264
  logPatched("src/app.module.ts", "added InertiaModule.forRoot");
@@ -5156,7 +5272,7 @@ function patchServerAppModule(ctx) {
5156
5272
  }
5157
5273
  }
5158
5274
  function patchServerMainTs(ctx) {
5159
- const mainTsPath = (0, import_node_path17.join)(ctx.cwd, "src", "main.ts");
5275
+ const mainTsPath = (0, import_node_path18.join)(ctx.cwd, "src", "main.ts");
5160
5276
  const mainTsResult = patchMainTs(mainTsPath);
5161
5277
  if (mainTsResult === "patched") {
5162
5278
  logPatched("src/main.ts", "added setupInertiaVite after NestFactory.create");
@@ -5191,7 +5307,7 @@ function patchBuildConfigs(ctx) {
5191
5307
  }
5192
5308
  async function patchGitignoreAndDist(ctx) {
5193
5309
  const { cwd } = ctx;
5194
- await patchGitignore((0, import_node_path17.join)(cwd, ".gitignore"));
5310
+ await patchGitignore((0, import_node_path18.join)(cwd, ".gitignore"));
5195
5311
  const tsconfigDistResult = patchTsconfigExclude(cwd, "dist", "tsconfig.json");
5196
5312
  if (tsconfigDistResult === "patched") {
5197
5313
  logPatched("tsconfig.json", "excluded dist/ from server compilation");
@@ -5297,7 +5413,7 @@ ${green("\u2713")} Setup complete! Run: ${bold("nest start --watch")}
5297
5413
 
5298
5414
  // src/cli/doctor.ts
5299
5415
  function checkFileExists(cwd, file) {
5300
- return (0, import_node_fs4.existsSync)((0, import_node_path18.join)(cwd, file));
5416
+ return (0, import_node_fs4.existsSync)((0, import_node_path19.join)(cwd, file));
5301
5417
  }
5302
5418
  function readJson(path) {
5303
5419
  try {
@@ -5333,15 +5449,15 @@ function writeJsonField(filePath, dotPath, value) {
5333
5449
  }
5334
5450
  function getPackageVersion(cwd, pkg) {
5335
5451
  try {
5336
- const pkgJson = readJson((0, import_node_path18.join)(cwd, "node_modules", pkg, "package.json"));
5452
+ const pkgJson = readJson((0, import_node_path19.join)(cwd, "node_modules", pkg, "package.json"));
5337
5453
  return pkgJson?.version ?? null;
5338
5454
  } catch {
5339
5455
  return null;
5340
5456
  }
5341
5457
  }
5342
5458
  function detectPkgManager(cwd) {
5343
- if ((0, import_node_fs4.existsSync)((0, import_node_path18.join)(cwd, "pnpm-lock.yaml"))) return "pnpm";
5344
- if ((0, import_node_fs4.existsSync)((0, import_node_path18.join)(cwd, "yarn.lock"))) return "yarn";
5459
+ if ((0, import_node_fs4.existsSync)((0, import_node_path19.join)(cwd, "pnpm-lock.yaml"))) return "pnpm";
5460
+ if ((0, import_node_fs4.existsSync)((0, import_node_path19.join)(cwd, "yarn.lock"))) return "yarn";
5345
5461
  return "npm";
5346
5462
  }
5347
5463
  async function runDoctor(opts) {
@@ -5379,7 +5495,7 @@ async function runDoctor(opts) {
5379
5495
  autoFix: () => runInit({ cwd })
5380
5496
  });
5381
5497
  if (foundShellDir) {
5382
- const nestCliPath = (0, import_node_path18.join)(cwd, "nest-cli.json");
5498
+ const nestCliPath = (0, import_node_path19.join)(cwd, "nest-cli.json");
5383
5499
  const nestCli = readJson(nestCliPath);
5384
5500
  const compiler = nestCli?.compilerOptions ?? {};
5385
5501
  const assets = compiler.assets ?? [];
@@ -5418,7 +5534,7 @@ async function runDoctor(opts) {
5418
5534
  fix: "Run: nestjs-codegen codegen",
5419
5535
  autoFix: () => runCodegen({ cwd })
5420
5536
  });
5421
- const tsconfigPath = (0, import_node_path18.join)(cwd, "tsconfig.json");
5537
+ const tsconfigPath = (0, import_node_path19.join)(cwd, "tsconfig.json");
5422
5538
  const tsconfig = readJson(tsconfigPath);
5423
5539
  const paths = tsconfig?.compilerOptions?.paths;
5424
5540
  checks.push({
@@ -5429,7 +5545,7 @@ async function runDoctor(opts) {
5429
5545
  });
5430
5546
  const inertiaDir = foundShellDir ?? "inertia";
5431
5547
  for (const tsconfigFile of ["tsconfig.json", "tsconfig.build.json"]) {
5432
- const tsc = readJson((0, import_node_path18.join)(cwd, tsconfigFile));
5548
+ const tsc = readJson((0, import_node_path19.join)(cwd, tsconfigFile));
5433
5549
  if (!tsc) continue;
5434
5550
  const excl = tsc.exclude ?? [];
5435
5551
  const excludesIt = excl.includes(inertiaDir);
@@ -5455,7 +5571,7 @@ async function runDoctor(opts) {
5455
5571
  }
5456
5572
  });
5457
5573
  }
5458
- const inertiaTsconfigPath = (0, import_node_path18.join)(cwd, "tsconfig.inertia.json");
5574
+ const inertiaTsconfigPath = (0, import_node_path19.join)(cwd, "tsconfig.inertia.json");
5459
5575
  const inertiaTsconfig = readJson(inertiaTsconfigPath);
5460
5576
  checks.push({
5461
5577
  name: "tsconfig.inertia.json exists",
@@ -5507,7 +5623,7 @@ async function runDoctor(opts) {
5507
5623
  fix: 'Add "nestjs-inertia.d.ts" to include array (resolves InertiaRegistry augmentation)'
5508
5624
  });
5509
5625
  }
5510
- const innerTsconfigPath = (0, import_node_path18.join)(cwd, "inertia", "tsconfig.json");
5626
+ const innerTsconfigPath = (0, import_node_path19.join)(cwd, "inertia", "tsconfig.json");
5511
5627
  checks.push({
5512
5628
  name: "inertia/tsconfig.json exists (VSCode picks up ~codegen alias)",
5513
5629
  pass: (0, import_node_fs4.existsSync)(innerTsconfigPath),
@@ -5517,7 +5633,7 @@ async function runDoctor(opts) {
5517
5633
  }
5518
5634
  });
5519
5635
  if (checkFileExists(cwd, "vite.config.ts")) {
5520
- const viteContent = (0, import_node_fs4.readFileSync)((0, import_node_path18.join)(cwd, "vite.config.ts"), "utf8");
5636
+ const viteContent = (0, import_node_fs4.readFileSync)((0, import_node_path19.join)(cwd, "vite.config.ts"), "utf8");
5521
5637
  checks.push({
5522
5638
  name: "vite.config.ts has resolve.alias",
5523
5639
  pass: viteContent.includes("resolve") && viteContent.includes("alias"),
@@ -5582,7 +5698,7 @@ async function runDoctor(opts) {
5582
5698
  });
5583
5699
  }
5584
5700
  if (checkFileExists(cwd, ".gitignore")) {
5585
- const gitignorePath = (0, import_node_path18.join)(cwd, ".gitignore");
5701
+ const gitignorePath = (0, import_node_path19.join)(cwd, ".gitignore");
5586
5702
  const gitignore = (0, import_node_fs4.readFileSync)(gitignorePath, "utf8");
5587
5703
  checks.push({
5588
5704
  name: ".gitignore includes .nestjs-inertia/",
@@ -5591,7 +5707,7 @@ async function runDoctor(opts) {
5591
5707
  autoFix: () => (0, import_node_fs4.appendFileSync)(gitignorePath, "\n.nestjs-inertia/\n")
5592
5708
  });
5593
5709
  }
5594
- const pkgJsonPath = (0, import_node_path18.join)(cwd, "package.json");
5710
+ const pkgJsonPath = (0, import_node_path19.join)(cwd, "package.json");
5595
5711
  const pkgJson = readJson(pkgJsonPath);
5596
5712
  const scripts = pkgJson?.scripts ?? {};
5597
5713
  checks.push({