@dudousxd/nestjs-codegen 0.10.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");
@@ -832,7 +832,11 @@ function buildRequestModel(c) {
832
832
  urlExpr,
833
833
  optsExpr,
834
834
  responseType: `${TA}['response']`,
835
- queryKeyExpr: `[${flat}, input] as const`
835
+ // When no input is supplied the key omits the trailing element entirely
836
+ // (`[name]` rather than `[name, undefined]`) so the bare `.queryKey()` is a
837
+ // clean prefix that partial-matches every parametrized variant — making it
838
+ // directly usable for `invalidateQueries`.
839
+ queryKeyExpr: `(input === undefined ? [${flat}] as const : [${flat}, input] as const)`
836
840
  };
837
841
  }
838
842
  function renderFetcherRequest(req) {
@@ -2109,6 +2113,99 @@ function buildEmpty() {
2109
2113
  ].join("\n");
2110
2114
  }
2111
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
+
2112
2209
  // src/util/debug-log.ts
2113
2210
  var debugEnabled = false;
2114
2211
  function setCodegenDebug(enabled) {
@@ -2121,6 +2218,12 @@ function debugWarn(message) {
2121
2218
  // src/generate.ts
2122
2219
  async function generate(config, inputRoutes = []) {
2123
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
+ }
2124
2227
  const extensions = config.extensions ?? [];
2125
2228
  let routes = inputRoutes;
2126
2229
  const ctx = createExtensionContext(config, () => routes);
@@ -2177,21 +2280,27 @@ async function generate(config, inputRoutes = []) {
2177
2280
  if (extensions.length > 0) {
2178
2281
  const extraFiles = await collectEmittedFiles(extensions, ctx);
2179
2282
  for (const file of extraFiles) {
2180
- const dest = (0, import_node_path12.join)(config.codegen.outDir, file.path);
2181
- await (0, import_promises11.mkdir)((0, import_node_path12.dirname)(dest), { recursive: true });
2182
- 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");
2183
2286
  }
2184
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
+ });
2185
2294
  }
2186
2295
 
2187
2296
  // src/watch/watcher.ts
2188
- var import_promises14 = require("fs/promises");
2189
- var import_node_path16 = require("path");
2297
+ var import_promises15 = require("fs/promises");
2298
+ var import_node_path17 = require("path");
2190
2299
  var import_chokidar = __toESM(require("chokidar"), 1);
2191
2300
 
2192
2301
  // src/discovery/contracts-fast.ts
2193
- var import_node_path14 = require("path");
2194
- 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);
2195
2304
  var import_ts_morph9 = require("ts-morph");
2196
2305
 
2197
2306
  // src/discovery/dto-type-resolver.ts
@@ -2202,7 +2311,7 @@ var import_ts_morph4 = require("ts-morph");
2202
2311
 
2203
2312
  // src/discovery/type-ref-resolution.ts
2204
2313
  var import_node_fs = require("fs");
2205
- var import_node_path13 = require("path");
2314
+ var import_node_path14 = require("path");
2206
2315
  var import_ts_morph3 = require("ts-morph");
2207
2316
  var _EMPTY_CTX = { projectRoot: "", tsconfigPaths: null };
2208
2317
  var _ctxByProject = /* @__PURE__ */ new WeakMap();
@@ -2254,12 +2363,12 @@ function findTypeInFile(name, file) {
2254
2363
  }
2255
2364
  function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2256
2365
  if (moduleSpecifier.startsWith(".")) {
2257
- const dir = (0, import_node_path13.dirname)(sourceFile.getFilePath());
2366
+ const dir = (0, import_node_path14.dirname)(sourceFile.getFilePath());
2258
2367
  const noExt = moduleSpecifier.replace(/\.(js|ts)$/, "");
2259
2368
  return [
2260
- (0, import_node_path13.resolve)(dir, `${noExt}.ts`),
2261
- (0, import_node_path13.resolve)(dir, `${moduleSpecifier}.ts`),
2262
- (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")
2263
2372
  ];
2264
2373
  }
2265
2374
  const ctx = _ctxFor(project);
@@ -2280,8 +2389,8 @@ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
2280
2389
  const rest = moduleSpecifier.slice(prefix.length);
2281
2390
  const candidates = [];
2282
2391
  for (const mapping of mappings) {
2283
- const resolved = (0, import_node_path13.resolve)(baseUrl, mapping.replace("*", rest));
2284
- 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"));
2285
2394
  }
2286
2395
  dbg(" resolved candidates:", candidates);
2287
2396
  return candidates;
@@ -3953,7 +4062,7 @@ async function discoverContractsFast(opts) {
3953
4062
  const { cwd, glob, tsconfig } = opts;
3954
4063
  const tsconfigPath = resolveTsconfigPath(cwd, tsconfig);
3955
4064
  const project = createDiscoveryProject(tsconfigPath);
3956
- 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 });
3957
4066
  for (const f of files) {
3958
4067
  project.addSourceFileAtPath(f);
3959
4068
  }
@@ -3961,7 +4070,7 @@ async function discoverContractsFast(opts) {
3961
4070
  return extractAllRoutes(project);
3962
4071
  }
3963
4072
  function resolveTsconfigPath(cwd, tsconfig) {
3964
- 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");
3965
4074
  }
3966
4075
  function createDiscoveryProject(tsconfigPath) {
3967
4076
  try {
@@ -4026,7 +4135,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4026
4135
  const project = createDiscoveryProject(tsconfigPath);
4027
4136
  bindDiscoveryContext(project, cwd, tsconfigPath);
4028
4137
  const instance = new _PersistentDiscovery(project, cwd, glob);
4029
- 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 });
4030
4139
  for (const f of files) {
4031
4140
  project.addSourceFileAtPath(f);
4032
4141
  instance.controllerPaths.add(f);
@@ -4047,7 +4156,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4047
4156
  async rediscover(changedPaths) {
4048
4157
  if (changedPaths) {
4049
4158
  for (const p of changedPaths) {
4050
- const abs = (0, import_node_path14.resolve)(p);
4159
+ const abs = (0, import_node_path15.resolve)(p);
4051
4160
  const sf = this.project.getSourceFile(abs);
4052
4161
  if (sf) {
4053
4162
  await sf.refreshFromFileSystem();
@@ -4055,7 +4164,7 @@ var PersistentDiscovery = class _PersistentDiscovery {
4055
4164
  }
4056
4165
  }
4057
4166
  const globbed = new Set(
4058
- 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 })
4059
4168
  );
4060
4169
  for (const f of globbed) {
4061
4170
  if (!this.controllerPaths.has(f)) {
@@ -4335,10 +4444,10 @@ function extractFromSourceFile(sourceFile, project) {
4335
4444
  }
4336
4445
 
4337
4446
  // src/watch/lock-file.ts
4338
- var import_promises12 = require("fs/promises");
4339
4447
  var import_promises13 = require("fs/promises");
4340
- var import_node_path15 = require("path");
4341
- 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";
4342
4451
  function isProcessAlive(pid) {
4343
4452
  try {
4344
4453
  process.kill(pid, 0);
@@ -4348,21 +4457,21 @@ function isProcessAlive(pid) {
4348
4457
  }
4349
4458
  }
4350
4459
  async function acquireLock(outDir) {
4351
- await (0, import_promises13.mkdir)(outDir, { recursive: true });
4352
- 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);
4353
4462
  const lockData = { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
4354
4463
  try {
4355
- const fd = await (0, import_promises12.open)(lockPath, "wx");
4464
+ const fd = await (0, import_promises13.open)(lockPath, "wx");
4356
4465
  await fd.writeFile(`${JSON.stringify(lockData, null, 2)}
4357
4466
  `, "utf8");
4358
4467
  await fd.close();
4359
4468
  } catch (err) {
4360
4469
  if (err.code === "EEXIST") {
4361
4470
  try {
4362
- const raw = await (0, import_promises13.readFile)(lockPath, "utf8");
4471
+ const raw = await (0, import_promises14.readFile)(lockPath, "utf8");
4363
4472
  const existing = JSON.parse(raw);
4364
4473
  if (isProcessAlive(existing.pid)) return null;
4365
- await (0, import_promises13.unlink)(lockPath);
4474
+ await (0, import_promises14.unlink)(lockPath);
4366
4475
  return acquireLock(outDir);
4367
4476
  } catch {
4368
4477
  return null;
@@ -4373,7 +4482,7 @@ async function acquireLock(outDir) {
4373
4482
  return {
4374
4483
  release: async () => {
4375
4484
  try {
4376
- await (0, import_promises13.unlink)(lockPath);
4485
+ await (0, import_promises14.unlink)(lockPath);
4377
4486
  } catch {
4378
4487
  }
4379
4488
  }
@@ -4384,12 +4493,12 @@ async function acquireLock(outDir) {
4384
4493
  var PAGES_DEBOUNCE_MS = 150;
4385
4494
  var NO_OP_WATCHER = { close: async () => {
4386
4495
  } };
4387
- async function watch(config, onChange) {
4496
+ async function watch(config, onChange, options = {}) {
4388
4497
  const lock = await acquireLock(config.codegen.outDir);
4389
4498
  if (lock === null) {
4390
4499
  let holderPid = "unknown";
4391
4500
  try {
4392
- 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");
4393
4502
  const data = JSON.parse(raw);
4394
4503
  if (data.pid !== void 0) holderPid = String(data.pid);
4395
4504
  } catch {
@@ -4412,22 +4521,33 @@ async function watch(config, onChange) {
4412
4521
  }
4413
4522
  return discovery;
4414
4523
  }
4415
- try {
4416
- const initialRoutes = (await getDiscovery()).discover();
4417
- lastRoutes = initialRoutes;
4418
- await generate(config, initialRoutes);
4419
- } catch (err) {
4420
- console.warn(
4421
- `[nestjs-codegen] Initial route discovery failed, falling back to pages-only: ${err instanceof Error ? err.message : String(err)}`
4422
- );
4524
+ async function runInitialPass() {
4423
4525
  try {
4424
- await generate(config, lastRoutes);
4425
- } 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
+ }
4426
4537
  }
4427
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
+ }
4428
4548
  let pagesDebounceTimer;
4429
4549
  const pagesGlob = config.pages?.glob ?? ".nestjs-codegen-no-pages";
4430
- 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), {
4431
4551
  ignoreInitial: true,
4432
4552
  persistent: true,
4433
4553
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4454,7 +4574,7 @@ async function watch(config, onChange) {
4454
4574
  pagesWatcher.on("unlink", schedulePagesRegenerate);
4455
4575
  let contractsDebounceTimer;
4456
4576
  const pendingChangedPaths = /* @__PURE__ */ new Set();
4457
- 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), {
4458
4578
  ignoreInitial: true,
4459
4579
  persistent: true,
4460
4580
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4484,7 +4604,7 @@ async function watch(config, onChange) {
4484
4604
  contractsWatcher.on("add", (p) => scheduleContractsRegenerate(p));
4485
4605
  contractsWatcher.on("change", (p) => scheduleContractsRegenerate(p));
4486
4606
  contractsWatcher.on("unlink", (p) => scheduleContractsRegenerate(p));
4487
- 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), {
4488
4608
  ignoreInitial: true,
4489
4609
  persistent: true,
4490
4610
  awaitWriteFinish: { stabilityThreshold: 80, pollInterval: 20 }
@@ -4511,7 +4631,7 @@ async function watch(config, onChange) {
4511
4631
  }
4512
4632
 
4513
4633
  // src/index.ts
4514
- var VERSION = "0.10.0";
4634
+ var VERSION = "0.12.0";
4515
4635
 
4516
4636
  // src/cli/codegen.ts
4517
4637
  async function runCodegen(opts = {}) {
@@ -4540,13 +4660,13 @@ async function runCodegen(opts = {}) {
4540
4660
  // src/cli/doctor.ts
4541
4661
  var import_node_child_process2 = require("child_process");
4542
4662
  var import_node_fs4 = require("fs");
4543
- var import_node_path18 = require("path");
4663
+ var import_node_path19 = require("path");
4544
4664
 
4545
4665
  // src/cli/init.ts
4546
4666
  var import_node_child_process = require("child_process");
4547
4667
  var import_node_fs3 = require("fs");
4548
- var import_promises15 = require("fs/promises");
4549
- var import_node_path17 = require("path");
4668
+ var import_promises16 = require("fs/promises");
4669
+ var import_node_path18 = require("path");
4550
4670
  var import_node_readline = require("readline");
4551
4671
 
4552
4672
  // src/cli/patch-utils.ts
@@ -4608,7 +4728,7 @@ ${bold(title)}`);
4608
4728
  }
4609
4729
  async function readPackageJson(cwd) {
4610
4730
  try {
4611
- 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");
4612
4732
  return JSON.parse(raw);
4613
4733
  } catch {
4614
4734
  return {};
@@ -4639,7 +4759,7 @@ async function detectTemplateEngine(cwd) {
4639
4759
  async function detectPackageManager(cwd) {
4640
4760
  async function exists(file) {
4641
4761
  try {
4642
- 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));
4643
4763
  return true;
4644
4764
  } catch {
4645
4765
  return false;
@@ -4667,7 +4787,7 @@ async function promptFramework() {
4667
4787
  }
4668
4788
  async function fileExists2(filePath) {
4669
4789
  try {
4670
- await (0, import_promises15.access)(filePath);
4790
+ await (0, import_promises16.access)(filePath);
4671
4791
  return true;
4672
4792
  } catch {
4673
4793
  return false;
@@ -4680,15 +4800,15 @@ async function writeIfNotExists(filePath, content, label) {
4680
4800
  }
4681
4801
  const dir = filePath.substring(0, filePath.lastIndexOf("/"));
4682
4802
  if (dir) {
4683
- await (0, import_promises15.mkdir)(dir, { recursive: true });
4803
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
4684
4804
  }
4685
- await (0, import_promises15.writeFile)(filePath, content, "utf8");
4805
+ await (0, import_promises16.writeFile)(filePath, content, "utf8");
4686
4806
  logCreated(label);
4687
4807
  }
4688
4808
  async function handleViteConfig(cwd, framework) {
4689
- const filePath = (0, import_node_path17.join)(cwd, "vite.config.ts");
4809
+ const filePath = (0, import_node_path18.join)(cwd, "vite.config.ts");
4690
4810
  if (await fileExists2(filePath)) {
4691
- const existing = await (0, import_promises15.readFile)(filePath, "utf8");
4811
+ const existing = await (0, import_promises16.readFile)(filePath, "utf8");
4692
4812
  const hasPlugin = existing.includes("nestInertia") || existing.includes("nestjs-inertia-vite/plugin");
4693
4813
  if (!hasPlugin) {
4694
4814
  logSkipped("vite.config.ts");
@@ -4704,15 +4824,15 @@ async function handleViteConfig(cwd, framework) {
4704
4824
  }
4705
4825
  const dir = filePath.substring(0, filePath.lastIndexOf("/"));
4706
4826
  if (dir) {
4707
- await (0, import_promises15.mkdir)(dir, { recursive: true });
4827
+ await (0, import_promises16.mkdir)(dir, { recursive: true });
4708
4828
  }
4709
- await (0, import_promises15.writeFile)(filePath, viteConfigTemplate(framework), "utf8");
4829
+ await (0, import_promises16.writeFile)(filePath, viteConfigTemplate(framework), "utf8");
4710
4830
  logCreated("vite.config.ts");
4711
4831
  }
4712
4832
  async function patchGitignore(gitignorePath) {
4713
4833
  let existing = "";
4714
4834
  if (await fileExists2(gitignorePath)) {
4715
- existing = await (0, import_promises15.readFile)(gitignorePath, "utf8");
4835
+ existing = await (0, import_promises16.readFile)(gitignorePath, "utf8");
4716
4836
  }
4717
4837
  if (existing.split("\n").some((line) => line.trim() === GITIGNORE_ENTRY)) {
4718
4838
  console.log(` ${cyan("\u2192")} .gitignore ${dim("(already contains .nestjs-inertia/, skipped)")}`);
@@ -4722,7 +4842,7 @@ async function patchGitignore(gitignorePath) {
4722
4842
  ` : `${existing}
4723
4843
  ${GITIGNORE_ENTRY}
4724
4844
  `;
4725
- await (0, import_promises15.writeFile)(gitignorePath, newContent, "utf8");
4845
+ await (0, import_promises16.writeFile)(gitignorePath, newContent, "utf8");
4726
4846
  logPatched(".gitignore", "added .nestjs-inertia/");
4727
4847
  }
4728
4848
  function installDeps(pkgManager, deps, dev) {
@@ -4744,10 +4864,10 @@ function installDeps(pkgManager, deps, dev) {
4744
4864
  }
4745
4865
  }
4746
4866
  async function patchPackageJsonScripts(cwd, scripts) {
4747
- const pkgPath = (0, import_node_path17.join)(cwd, "package.json");
4867
+ const pkgPath = (0, import_node_path18.join)(cwd, "package.json");
4748
4868
  let pkg = {};
4749
4869
  try {
4750
- pkg = JSON.parse(await (0, import_promises15.readFile)(pkgPath, "utf8"));
4870
+ pkg = JSON.parse(await (0, import_promises16.readFile)(pkgPath, "utf8"));
4751
4871
  } catch {
4752
4872
  return;
4753
4873
  }
@@ -4766,7 +4886,7 @@ async function patchPackageJsonScripts(cwd, scripts) {
4766
4886
  return;
4767
4887
  }
4768
4888
  pkg.scripts = existing;
4769
- await (0, import_promises15.writeFile)(pkgPath, `${JSON.stringify(pkg, null, 2)}
4889
+ await (0, import_promises16.writeFile)(pkgPath, `${JSON.stringify(pkg, null, 2)}
4770
4890
  `, "utf8");
4771
4891
  }
4772
4892
  function patchAppModule(filePath, rootView) {
@@ -5061,7 +5181,7 @@ export class HomeController {
5061
5181
  }
5062
5182
  `;
5063
5183
  function patchTsconfigExclude(cwd, dir, filename = "tsconfig.json") {
5064
- const filePath = (0, import_node_path17.join)(cwd, filename);
5184
+ const filePath = (0, import_node_path18.join)(cwd, filename);
5065
5185
  return patchJsonFile(
5066
5186
  filePath,
5067
5187
  (json) => {
@@ -5076,7 +5196,7 @@ function patchTsconfigExclude(cwd, dir, filename = "tsconfig.json") {
5076
5196
  );
5077
5197
  }
5078
5198
  function patchNestCliJson(cwd, shellDir) {
5079
- const filePath = (0, import_node_path17.join)(cwd, "nest-cli.json");
5199
+ const filePath = (0, import_node_path18.join)(cwd, "nest-cli.json");
5080
5200
  return patchJsonFile(filePath, (json) => {
5081
5201
  const compiler = json.compilerOptions ?? {};
5082
5202
  const assets = compiler.assets ?? [];
@@ -5099,46 +5219,46 @@ async function scaffoldFiles(ctx) {
5099
5219
  const { cwd, framework, engine, shellFileName, entryExt, pageExt } = ctx;
5100
5220
  logSection("Scaffold files");
5101
5221
  await writeIfNotExists(
5102
- (0, import_node_path17.join)(cwd, "nestjs-inertia.config.ts"),
5222
+ (0, import_node_path18.join)(cwd, "nestjs-inertia.config.ts"),
5103
5223
  configTemplate(framework),
5104
5224
  "nestjs-inertia.config.ts"
5105
5225
  );
5106
- 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");
5107
5227
  await writeIfNotExists(
5108
- (0, import_node_path17.join)(cwd, "tsconfig.inertia.json"),
5228
+ (0, import_node_path18.join)(cwd, "tsconfig.inertia.json"),
5109
5229
  TSCONFIG_INERTIA_TEMPLATE,
5110
5230
  "tsconfig.inertia.json"
5111
5231
  );
5112
5232
  await writeIfNotExists(
5113
- (0, import_node_path17.join)(cwd, "inertia", "tsconfig.json"),
5233
+ (0, import_node_path18.join)(cwd, "inertia", "tsconfig.json"),
5114
5234
  INERTIA_TSCONFIG_TEMPLATE,
5115
5235
  "inertia/tsconfig.json"
5116
5236
  );
5117
5237
  await writeIfNotExists(
5118
- (0, import_node_path17.join)(cwd, "inertia", shellFileName),
5238
+ (0, import_node_path18.join)(cwd, "inertia", shellFileName),
5119
5239
  htmlShellTemplate(framework, engine),
5120
5240
  `inertia/${shellFileName}`
5121
5241
  );
5122
5242
  await handleViteConfig(cwd, framework);
5123
5243
  await writeIfNotExists(
5124
- (0, import_node_path17.join)(cwd, "inertia", "app", `client.${entryExt}`),
5244
+ (0, import_node_path18.join)(cwd, "inertia", "app", `client.${entryExt}`),
5125
5245
  entryPointTemplate(framework),
5126
5246
  `inertia/app/client.${entryExt}`
5127
5247
  );
5128
5248
  await writeIfNotExists(
5129
- (0, import_node_path17.join)(cwd, "inertia", "pages", `Home.${pageExt}`),
5249
+ (0, import_node_path18.join)(cwd, "inertia", "pages", `Home.${pageExt}`),
5130
5250
  samplePageTemplate(framework),
5131
5251
  `inertia/pages/Home.${pageExt}`
5132
5252
  );
5133
5253
  await writeIfNotExists(
5134
- (0, import_node_path17.join)(cwd, "src", "home.controller.ts"),
5254
+ (0, import_node_path18.join)(cwd, "src", "home.controller.ts"),
5135
5255
  SAMPLE_CONTROLLER,
5136
5256
  "src/home.controller.ts"
5137
5257
  );
5138
5258
  }
5139
5259
  function patchServerAppModule(ctx) {
5140
5260
  const { cwd, rootView } = ctx;
5141
- 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");
5142
5262
  const appModuleResult = patchAppModule(appModulePath, rootView);
5143
5263
  if (appModuleResult === "patched") {
5144
5264
  logPatched("src/app.module.ts", "added InertiaModule.forRoot");
@@ -5152,7 +5272,7 @@ function patchServerAppModule(ctx) {
5152
5272
  }
5153
5273
  }
5154
5274
  function patchServerMainTs(ctx) {
5155
- 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");
5156
5276
  const mainTsResult = patchMainTs(mainTsPath);
5157
5277
  if (mainTsResult === "patched") {
5158
5278
  logPatched("src/main.ts", "added setupInertiaVite after NestFactory.create");
@@ -5187,7 +5307,7 @@ function patchBuildConfigs(ctx) {
5187
5307
  }
5188
5308
  async function patchGitignoreAndDist(ctx) {
5189
5309
  const { cwd } = ctx;
5190
- await patchGitignore((0, import_node_path17.join)(cwd, ".gitignore"));
5310
+ await patchGitignore((0, import_node_path18.join)(cwd, ".gitignore"));
5191
5311
  const tsconfigDistResult = patchTsconfigExclude(cwd, "dist", "tsconfig.json");
5192
5312
  if (tsconfigDistResult === "patched") {
5193
5313
  logPatched("tsconfig.json", "excluded dist/ from server compilation");
@@ -5293,7 +5413,7 @@ ${green("\u2713")} Setup complete! Run: ${bold("nest start --watch")}
5293
5413
 
5294
5414
  // src/cli/doctor.ts
5295
5415
  function checkFileExists(cwd, file) {
5296
- 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));
5297
5417
  }
5298
5418
  function readJson(path) {
5299
5419
  try {
@@ -5329,15 +5449,15 @@ function writeJsonField(filePath, dotPath, value) {
5329
5449
  }
5330
5450
  function getPackageVersion(cwd, pkg) {
5331
5451
  try {
5332
- 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"));
5333
5453
  return pkgJson?.version ?? null;
5334
5454
  } catch {
5335
5455
  return null;
5336
5456
  }
5337
5457
  }
5338
5458
  function detectPkgManager(cwd) {
5339
- if ((0, import_node_fs4.existsSync)((0, import_node_path18.join)(cwd, "pnpm-lock.yaml"))) return "pnpm";
5340
- 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";
5341
5461
  return "npm";
5342
5462
  }
5343
5463
  async function runDoctor(opts) {
@@ -5375,7 +5495,7 @@ async function runDoctor(opts) {
5375
5495
  autoFix: () => runInit({ cwd })
5376
5496
  });
5377
5497
  if (foundShellDir) {
5378
- const nestCliPath = (0, import_node_path18.join)(cwd, "nest-cli.json");
5498
+ const nestCliPath = (0, import_node_path19.join)(cwd, "nest-cli.json");
5379
5499
  const nestCli = readJson(nestCliPath);
5380
5500
  const compiler = nestCli?.compilerOptions ?? {};
5381
5501
  const assets = compiler.assets ?? [];
@@ -5414,7 +5534,7 @@ async function runDoctor(opts) {
5414
5534
  fix: "Run: nestjs-codegen codegen",
5415
5535
  autoFix: () => runCodegen({ cwd })
5416
5536
  });
5417
- const tsconfigPath = (0, import_node_path18.join)(cwd, "tsconfig.json");
5537
+ const tsconfigPath = (0, import_node_path19.join)(cwd, "tsconfig.json");
5418
5538
  const tsconfig = readJson(tsconfigPath);
5419
5539
  const paths = tsconfig?.compilerOptions?.paths;
5420
5540
  checks.push({
@@ -5425,7 +5545,7 @@ async function runDoctor(opts) {
5425
5545
  });
5426
5546
  const inertiaDir = foundShellDir ?? "inertia";
5427
5547
  for (const tsconfigFile of ["tsconfig.json", "tsconfig.build.json"]) {
5428
- const tsc = readJson((0, import_node_path18.join)(cwd, tsconfigFile));
5548
+ const tsc = readJson((0, import_node_path19.join)(cwd, tsconfigFile));
5429
5549
  if (!tsc) continue;
5430
5550
  const excl = tsc.exclude ?? [];
5431
5551
  const excludesIt = excl.includes(inertiaDir);
@@ -5451,7 +5571,7 @@ async function runDoctor(opts) {
5451
5571
  }
5452
5572
  });
5453
5573
  }
5454
- const inertiaTsconfigPath = (0, import_node_path18.join)(cwd, "tsconfig.inertia.json");
5574
+ const inertiaTsconfigPath = (0, import_node_path19.join)(cwd, "tsconfig.inertia.json");
5455
5575
  const inertiaTsconfig = readJson(inertiaTsconfigPath);
5456
5576
  checks.push({
5457
5577
  name: "tsconfig.inertia.json exists",
@@ -5503,7 +5623,7 @@ async function runDoctor(opts) {
5503
5623
  fix: 'Add "nestjs-inertia.d.ts" to include array (resolves InertiaRegistry augmentation)'
5504
5624
  });
5505
5625
  }
5506
- const innerTsconfigPath = (0, import_node_path18.join)(cwd, "inertia", "tsconfig.json");
5626
+ const innerTsconfigPath = (0, import_node_path19.join)(cwd, "inertia", "tsconfig.json");
5507
5627
  checks.push({
5508
5628
  name: "inertia/tsconfig.json exists (VSCode picks up ~codegen alias)",
5509
5629
  pass: (0, import_node_fs4.existsSync)(innerTsconfigPath),
@@ -5513,7 +5633,7 @@ async function runDoctor(opts) {
5513
5633
  }
5514
5634
  });
5515
5635
  if (checkFileExists(cwd, "vite.config.ts")) {
5516
- 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");
5517
5637
  checks.push({
5518
5638
  name: "vite.config.ts has resolve.alias",
5519
5639
  pass: viteContent.includes("resolve") && viteContent.includes("alias"),
@@ -5578,7 +5698,7 @@ async function runDoctor(opts) {
5578
5698
  });
5579
5699
  }
5580
5700
  if (checkFileExists(cwd, ".gitignore")) {
5581
- const gitignorePath = (0, import_node_path18.join)(cwd, ".gitignore");
5701
+ const gitignorePath = (0, import_node_path19.join)(cwd, ".gitignore");
5582
5702
  const gitignore = (0, import_node_fs4.readFileSync)(gitignorePath, "utf8");
5583
5703
  checks.push({
5584
5704
  name: ".gitignore includes .nestjs-inertia/",
@@ -5587,7 +5707,7 @@ async function runDoctor(opts) {
5587
5707
  autoFix: () => (0, import_node_fs4.appendFileSync)(gitignorePath, "\n.nestjs-inertia/\n")
5588
5708
  });
5589
5709
  }
5590
- const pkgJsonPath = (0, import_node_path18.join)(cwd, "package.json");
5710
+ const pkgJsonPath = (0, import_node_path19.join)(cwd, "package.json");
5591
5711
  const pkgJson = readJson(pkgJsonPath);
5592
5712
  const scripts = pkgJson?.scripts ?? {};
5593
5713
  checks.push({