@dudousxd/nestjs-inertia-codegen 1.0.7 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog — @dudousxd/nestjs-inertia-codegen
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - feat(codegen): ReturnType<import(...)> for response types, queryKey helper, TanStack helpers, type ref imports, path alias resolution, debug mode
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies []:
12
+ - @dudousxd/nestjs-inertia@2.0.0
13
+
14
+ ## 3.0.0
15
+
16
+ ### Minor Changes
17
+
18
+ - feat(codegen): import type references from source instead of inline expansion — eliminates unknown fields from depth limits
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies []:
23
+ - @dudousxd/nestjs-inertia@3.0.0
24
+
25
+ ## 2.0.1
26
+
27
+ ### Patch Changes
28
+
29
+ - fix(codegen): remove @tanstack/query-core dependency — generated api.ts uses plain object literals
30
+
31
+ - Updated dependencies []:
32
+ - @dudousxd/nestjs-inertia@2.0.1
33
+
34
+ ## 2.0.0
35
+
36
+ ### Minor Changes
37
+
38
+ - feat(codegen): add queryKey() helper for typed cache invalidation — api.crew.getCrew.queryKey()
39
+
40
+ ### Patch Changes
41
+
42
+ - Updated dependencies []:
43
+ - @dudousxd/nestjs-inertia@2.0.0
44
+
3
45
  ## 1.0.7
4
46
 
5
47
  ### Patch Changes
package/dist/cli/main.cjs CHANGED
@@ -222,7 +222,7 @@ async function emitApi(routes, outDir) {
222
222
  await (0, import_promises3.mkdir)(outDir, {
223
223
  recursive: true
224
224
  });
225
- const content = buildApiFile(routes);
225
+ const content = buildApiFile(routes, outDir);
226
226
  await (0, import_promises3.writeFile)((0, import_node_path3.join)(outDir, "api.ts"), content, "utf8");
227
227
  }
228
228
  __name(emitApi, "emitApi");
@@ -287,7 +287,20 @@ function insertIntoTree(tree, segments, leaf, fullName) {
287
287
  }
288
288
  }
289
289
  __name(insertIntoTree, "insertIntoTree");
290
- function emitRouterTypeBlock(tree, indent) {
290
+ function buildResponseType(c, outDir) {
291
+ if (c.controllerRef) {
292
+ let relPath = (0, import_node_path3.relative)(outDir, c.controllerRef.filePath).replace(/\.ts$/, "");
293
+ if (!relPath.startsWith(".")) relPath = `./${relPath}`;
294
+ return `Awaited<ReturnType<import('${relPath}').${c.controllerRef.className}['${c.controllerRef.methodName}']>>`;
295
+ }
296
+ const respRef = c.contractSource.responseRef;
297
+ if (respRef) {
298
+ return respRef.isArray ? `Array<${respRef.name}>` : respRef.name;
299
+ }
300
+ return c.contractSource.response;
301
+ }
302
+ __name(buildResponseType, "buildResponseType");
303
+ function emitRouterTypeBlock(tree, indent, outDir) {
291
304
  const pad = " ".repeat(indent);
292
305
  const lines = [];
293
306
  for (const [key, node] of tree) {
@@ -295,15 +308,17 @@ function emitRouterTypeBlock(tree, indent) {
295
308
  if (node.kind === "leaf") {
296
309
  const c = node;
297
310
  const method = c.method.toUpperCase();
298
- const query = c.contractSource.query ?? "never";
299
- const body = method === "GET" ? "never" : c.contractSource.body ?? "never";
300
- const response = c.contractSource.response;
311
+ const queryRef = c.contractSource.queryRef;
312
+ const query = queryRef ? queryRef.isArray ? `Array<${queryRef.name}>` : queryRef.name : c.contractSource.query ?? "never";
313
+ const bodyRef = c.contractSource.bodyRef;
314
+ const body = method === "GET" ? "never" : bodyRef ? bodyRef.isArray ? `Array<${bodyRef.name}>` : bodyRef.name : c.contractSource.body ?? "never";
315
+ const response = buildResponseType(c, outDir);
301
316
  const safeMethod = JSON.stringify(method);
302
317
  const safeUrl = JSON.stringify(c.path);
303
318
  lines.push(`${pad}${objKey}: { method: ${safeMethod}; url: ${safeUrl}; query: ${query}; body: ${body}; response: ${response} };`);
304
319
  } else {
305
320
  lines.push(`${pad}${objKey}: {`);
306
- lines.push(...emitRouterTypeBlock(node.children, indent + 2));
321
+ lines.push(...emitRouterTypeBlock(node.children, indent + 2, outDir));
307
322
  lines.push(`${pad}};`);
308
323
  }
309
324
  }
@@ -324,18 +339,21 @@ function emitApiObjectBlock(tree, indent) {
324
339
  if (method === "GET") {
325
340
  const typeAccess = buildRouterTypeAccess(c.name);
326
341
  lines.push(`${pad}${objKey}: {`);
342
+ lines.push(`${pad} queryKey: (query?: ${typeAccess}['query']) => query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
327
343
  lines.push(`${pad} queryOptions: (query?: ${typeAccess}['query']) =>`);
328
- lines.push(`${pad} queryOptions({`);
329
- lines.push(`${pad} queryKey: [${flatName}, query],`);
344
+ lines.push(`${pad} _queryOptions({`);
345
+ lines.push(`${pad} queryKey: query !== undefined ? [${flatName}, query] as const : [${flatName}] as const,`);
330
346
  lines.push(`${pad} queryFn: () => fetcher.get<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { query }),`);
331
347
  lines.push(`${pad} }),`);
332
348
  lines.push(`${pad}},`);
333
349
  } else {
334
350
  const typeAccess = buildRouterTypeAccess(c.name);
335
351
  lines.push(`${pad}${objKey}: {`);
336
- lines.push(`${pad} mutationOptions: () => ({`);
337
- lines.push(`${pad} mutationFn: (body: ${typeAccess}['body']) => fetcher.${fetcherMethod}<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { body }),`);
338
- lines.push(`${pad} }),`);
352
+ lines.push(`${pad} queryKey: () => [${flatName}] as const,`);
353
+ lines.push(`${pad} mutationOptions: () =>`);
354
+ lines.push(`${pad} _mutationOptions({`);
355
+ lines.push(`${pad} mutationFn: (body: ${typeAccess}['body']) => fetcher.${fetcherMethod}<${typeAccess}['response']>(route(${flatName} as never) || ${safePath}, { body }),`);
356
+ lines.push(`${pad} }),`);
339
357
  lines.push(`${pad}},`);
340
358
  }
341
359
  } else {
@@ -352,18 +370,55 @@ function buildRouterTypeAccess(name) {
352
370
  return `ApiRouter${segments.map((s) => `[${JSON.stringify(s)}]`).join("")}`;
353
371
  }
354
372
  __name(buildRouterTypeAccess, "buildRouterTypeAccess");
355
- function buildApiFile(routes) {
373
+ function buildApiFile(routes, outDir) {
356
374
  const contracted = routes.filter((r) => r.contract);
375
+ const importsByFile = /* @__PURE__ */ new Map();
376
+ for (const r of contracted) {
377
+ const cs = r.contract?.contractSource;
378
+ if (!cs) continue;
379
+ const refs = r.controllerRef ? [
380
+ cs.queryRef,
381
+ cs.bodyRef
382
+ ] : [
383
+ cs.queryRef,
384
+ cs.bodyRef,
385
+ cs.responseRef
386
+ ];
387
+ for (const ref of refs) {
388
+ if (!ref) continue;
389
+ let names = importsByFile.get(ref.filePath);
390
+ if (!names) {
391
+ names = /* @__PURE__ */ new Set();
392
+ importsByFile.set(ref.filePath, names);
393
+ }
394
+ names.add(ref.name);
395
+ }
396
+ }
357
397
  const hasGetRoutes = contracted.some((r) => r.method === "GET");
398
+ const hasMutationRoutes = contracted.some((r) => r.method !== "GET");
358
399
  const lines = [
359
400
  "// Generated by @dudousxd/nestjs-inertia-codegen. Do not edit.",
360
401
  ""
361
402
  ];
362
- if (hasGetRoutes) {
363
- lines.push("import { queryOptions } from '@tanstack/query-core';");
403
+ const tqImports = [];
404
+ if (hasGetRoutes) tqImports.push("queryOptions as _queryOptions");
405
+ if (hasMutationRoutes) tqImports.push("mutationOptions as _mutationOptions");
406
+ if (tqImports.length > 0) {
407
+ lines.push(`import { ${tqImports.join(", ")} } from '@tanstack/react-query';`);
364
408
  }
365
409
  lines.push("import { route } from './routes.js';");
366
410
  lines.push("import { createFetcher } from '@dudousxd/nestjs-inertia-client';");
411
+ if (importsByFile.size > 0 && outDir) {
412
+ lines.push("");
413
+ for (const [filePath, names] of importsByFile) {
414
+ let relPath = (0, import_node_path3.relative)(outDir, filePath).replace(/\.ts$/, "");
415
+ if (!relPath.startsWith(".")) relPath = `./${relPath}`;
416
+ const sortedNames = [
417
+ ...names
418
+ ].sort();
419
+ lines.push(`import type { ${sortedNames.join(", ")} } from '${relPath}';`);
420
+ }
421
+ }
367
422
  lines.push("");
368
423
  lines.push("export const fetcher = createFetcher();");
369
424
  lines.push("");
@@ -404,13 +459,14 @@ function buildApiFile(routes) {
404
459
  method: r.method,
405
460
  name,
406
461
  path: r.path,
462
+ controllerRef: r.controllerRef,
407
463
  contractSource: c.contractSource
408
464
  };
409
465
  insertIntoTree(tree, segments, leaf, name);
410
466
  }
411
467
  void detectCollisions;
412
468
  lines.push("export type ApiRouter = {");
413
- lines.push(...emitRouterTypeBlock(tree, 2));
469
+ lines.push(...emitRouterTypeBlock(tree, 2, outDir ?? ""));
414
470
  lines.push("};");
415
471
  lines.push("");
416
472
  lines.push("export const api = {");
@@ -680,9 +736,28 @@ var import_node_path10 = require("path");
680
736
  var import_chokidar = __toESM(require("chokidar"), 1);
681
737
 
682
738
  // src/discovery/contracts-fast.ts
739
+ var import_node_fs = require("fs");
683
740
  var import_node_path8 = require("path");
684
741
  var import_fast_glob2 = __toESM(require("fast-glob"), 1);
685
742
  var import_ts_morph = require("ts-morph");
743
+ var _projectRoot = "";
744
+ var _tsconfigPaths = null;
745
+ var _debug = process.env.NESTJS_INERTIA_DEBUG === "1";
746
+ function dbg(...args) {
747
+ if (_debug) console.log("[codegen:debug]", ...args);
748
+ }
749
+ __name(dbg, "dbg");
750
+ function loadTsconfigPaths(tsconfigPath) {
751
+ try {
752
+ const raw = (0, import_node_fs.readFileSync)(tsconfigPath, "utf8");
753
+ const stripped = raw.replace(/\/\/.*$/gm, "");
754
+ const parsed = JSON.parse(stripped);
755
+ return parsed.compilerOptions?.paths ?? null;
756
+ } catch {
757
+ return null;
758
+ }
759
+ }
760
+ __name(loadTsconfigPaths, "loadTsconfigPaths");
686
761
  async function discoverContractsFast(opts) {
687
762
  const { cwd, glob, tsconfig } = opts;
688
763
  const tsconfigPath = tsconfig ? (0, import_node_path8.resolve)(tsconfig) : (0, import_node_path8.join)(cwd, "tsconfig.json");
@@ -715,6 +790,8 @@ async function discoverContractsFast(opts) {
715
790
  project.addSourceFileAtPath(f);
716
791
  }
717
792
  const routes = [];
793
+ _projectRoot = cwd;
794
+ _tsconfigPaths = loadTsconfigPaths(tsconfigPath);
718
795
  for (const sourceFile of project.getSourceFiles()) {
719
796
  routes.push(...extractFromSourceFile(sourceFile, project));
720
797
  }
@@ -916,17 +993,41 @@ function findTypeInFile(name, file) {
916
993
  return null;
917
994
  }
918
995
  __name(findTypeInFile, "findTypeInFile");
996
+ function resolveModuleSpecifier(moduleSpecifier, sourceFile, project) {
997
+ if (moduleSpecifier.startsWith(".")) {
998
+ const dir = (0, import_node_path8.dirname)(sourceFile.getFilePath());
999
+ return [
1000
+ (0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
1001
+ (0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
1002
+ ];
1003
+ }
1004
+ const baseUrl = _projectRoot;
1005
+ dbg("resolveModuleSpecifier", moduleSpecifier, "paths:", JSON.stringify(_tsconfigPaths), "baseUrl:", baseUrl);
1006
+ if (_tsconfigPaths) {
1007
+ for (const [pattern, mappings] of Object.entries(_tsconfigPaths)) {
1008
+ const prefix = pattern.replace("*", "");
1009
+ if (moduleSpecifier.startsWith(prefix)) {
1010
+ const rest = moduleSpecifier.slice(prefix.length);
1011
+ const candidates = [];
1012
+ for (const mapping of mappings) {
1013
+ const resolved = (0, import_node_path8.resolve)(baseUrl, mapping.replace("*", rest));
1014
+ candidates.push(`${resolved}.ts`, (0, import_node_path8.resolve)(resolved, "index.ts"));
1015
+ }
1016
+ dbg(" resolved candidates:", candidates);
1017
+ return candidates;
1018
+ }
1019
+ }
1020
+ }
1021
+ return [];
1022
+ }
1023
+ __name(resolveModuleSpecifier, "resolveModuleSpecifier");
919
1024
  function resolveImportedType(name, sourceFile, project) {
920
1025
  for (const importDecl of sourceFile.getImportDeclarations()) {
921
1026
  const namedImport = importDecl.getNamedImports().find((n) => n.getName() === name);
922
1027
  if (!namedImport) continue;
923
1028
  const moduleSpecifier = importDecl.getModuleSpecifierValue();
924
- if (!moduleSpecifier.startsWith(".")) return null;
925
- const dir = (0, import_node_path8.dirname)(sourceFile.getFilePath());
926
- const candidates = [
927
- (0, import_node_path8.resolve)(dir, `${moduleSpecifier}.ts`),
928
- (0, import_node_path8.resolve)(dir, moduleSpecifier, "index.ts")
929
- ];
1029
+ const candidates = resolveModuleSpecifier(moduleSpecifier, sourceFile, project);
1030
+ if (candidates.length === 0) continue;
930
1031
  for (const candidate of candidates) {
931
1032
  let importedFile = project.getSourceFile(candidate);
932
1033
  if (!importedFile) {
@@ -960,7 +1061,8 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
960
1061
  const name = import_ts_morph.Node.isIdentifier(typeName) ? typeName.getText() : typeNode.getText();
961
1062
  if (name === "string" || name === "number" || name === "boolean") return name;
962
1063
  if (name === "Date") return "string";
963
- if (name === "unknown" || name === "any") return "unknown";
1064
+ if (name === "unknown" || name === "any" || name === "void") return "unknown";
1065
+ if (name === "StreamableFile" || name === "Observable" || name === "ReadableStream") return "unknown";
964
1066
  if (name === "Array") {
965
1067
  const typeArgs = typeNode.getTypeArguments();
966
1068
  const firstTypeArg = typeArgs[0];
@@ -969,6 +1071,18 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
969
1071
  }
970
1072
  return "Array<unknown>";
971
1073
  }
1074
+ if ([
1075
+ "Record",
1076
+ "Omit",
1077
+ "Pick",
1078
+ "Partial",
1079
+ "Required",
1080
+ "Readonly",
1081
+ "Map",
1082
+ "Set"
1083
+ ].includes(name)) {
1084
+ return typeNode.getText();
1085
+ }
972
1086
  if (name === "Promise") {
973
1087
  const typeArgs = typeNode.getTypeArguments();
974
1088
  const firstTypeArg = typeArgs[0];
@@ -981,7 +1095,8 @@ function resolveTypeNodeToString(typeNode, sourceFile, project, depth) {
981
1095
  if (resolved) {
982
1096
  return expandTypeDecl(resolved, project, depth - 1);
983
1097
  }
984
- return name;
1098
+ dbg("unresolvable type:", name, "in", sourceFile.getFilePath());
1099
+ return "unknown";
985
1100
  }
986
1101
  const kind = typeNode.getKind();
987
1102
  if (kind === import_ts_morph.SyntaxKind.StringKeyword) return "string";
@@ -1108,6 +1223,68 @@ function resolveIdentifierToClassType(node, sourceFile, project, depth) {
1108
1223
  return name;
1109
1224
  }
1110
1225
  __name(resolveIdentifierToClassType, "resolveIdentifierToClassType");
1226
+ function tryResolveTypeRef(typeNode, sourceFile, project) {
1227
+ if (import_ts_morph.Node.isTypeReference(typeNode)) {
1228
+ const typeName = typeNode.getTypeName();
1229
+ const name = import_ts_morph.Node.isIdentifier(typeName) ? typeName.getText() : null;
1230
+ if (!name) return null;
1231
+ if (name === "Promise") {
1232
+ const typeArgs = typeNode.getTypeArguments();
1233
+ const first = typeArgs[0];
1234
+ if (first) return tryResolveTypeRef(first, sourceFile, project);
1235
+ return null;
1236
+ }
1237
+ if (name === "Array") {
1238
+ const typeArgs = typeNode.getTypeArguments();
1239
+ const first = typeArgs[0];
1240
+ if (first) {
1241
+ const inner = tryResolveTypeRef(first, sourceFile, project);
1242
+ if (inner) return {
1243
+ ...inner,
1244
+ isArray: true
1245
+ };
1246
+ }
1247
+ return null;
1248
+ }
1249
+ if ([
1250
+ "string",
1251
+ "number",
1252
+ "boolean",
1253
+ "void",
1254
+ "unknown",
1255
+ "any",
1256
+ "Date"
1257
+ ].includes(name)) {
1258
+ return null;
1259
+ }
1260
+ const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
1261
+ if (localDecl?.isExported()) {
1262
+ return {
1263
+ name,
1264
+ filePath: sourceFile.getFilePath()
1265
+ };
1266
+ }
1267
+ const resolved = resolveImportedType(name, sourceFile, project);
1268
+ if (resolved && (resolved.kind === "class" || resolved.kind === "interface")) {
1269
+ const decl = resolved.decl;
1270
+ if (decl.isExported()) {
1271
+ return {
1272
+ name,
1273
+ filePath: resolved.file.getFilePath()
1274
+ };
1275
+ }
1276
+ }
1277
+ }
1278
+ if (import_ts_morph.Node.isArrayTypeNode(typeNode)) {
1279
+ const inner = tryResolveTypeRef(typeNode.getElementTypeNode(), sourceFile, project);
1280
+ if (inner) return {
1281
+ ...inner,
1282
+ isArray: true
1283
+ };
1284
+ }
1285
+ return null;
1286
+ }
1287
+ __name(tryResolveTypeRef, "tryResolveTypeRef");
1111
1288
  function extractDtoContract(method, sourceFile, project) {
1112
1289
  const body = extractBodyType(method, sourceFile, project);
1113
1290
  const query = extractQueryType(method, sourceFile, project);
@@ -1116,11 +1293,61 @@ function extractDtoContract(method, sourceFile, project) {
1116
1293
  if (body === null && query === null && paramsType === null && response === "unknown") {
1117
1294
  return null;
1118
1295
  }
1296
+ let bodyRef = null;
1297
+ let queryRef = null;
1298
+ let responseRef = null;
1299
+ for (const param of method.getParameters()) {
1300
+ if (param.getDecorators().some((d) => d.getName() === "Body") && param.getTypeNode()) {
1301
+ bodyRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
1302
+ }
1303
+ if (param.getDecorators().some((d) => d.getName() === "Query") && param.getTypeNode()) {
1304
+ queryRef = tryResolveTypeRef(param.getTypeNode(), sourceFile, project);
1305
+ }
1306
+ }
1307
+ const returnTypeNode = method.getReturnTypeNode();
1308
+ if (returnTypeNode) {
1309
+ responseRef = tryResolveTypeRef(returnTypeNode, sourceFile, project);
1310
+ }
1311
+ if (!responseRef) {
1312
+ const apiResp = method.getDecorator("ApiResponse");
1313
+ if (apiResp) {
1314
+ const args = apiResp.getArguments();
1315
+ const optsArg = args[0];
1316
+ if (optsArg && import_ts_morph.Node.isObjectLiteralExpression(optsArg)) {
1317
+ for (const prop of optsArg.getProperties()) {
1318
+ if (import_ts_morph.Node.isPropertyAssignment(prop) && prop.getName() === "type") {
1319
+ const val = prop.getInitializer();
1320
+ if (val && import_ts_morph.Node.isIdentifier(val)) {
1321
+ const name = val.getText();
1322
+ const localDecl = sourceFile.getInterface(name) || sourceFile.getClass(name) || sourceFile.getTypeAlias(name);
1323
+ if (localDecl?.isExported()) {
1324
+ responseRef = {
1325
+ name,
1326
+ filePath: sourceFile.getFilePath()
1327
+ };
1328
+ } else {
1329
+ const resolved = resolveImportedType(name, sourceFile, project);
1330
+ if (resolved && (resolved.kind === "class" || resolved.kind === "interface") && resolved.decl.isExported()) {
1331
+ responseRef = {
1332
+ name,
1333
+ filePath: resolved.file.getFilePath()
1334
+ };
1335
+ }
1336
+ }
1337
+ }
1338
+ }
1339
+ }
1340
+ }
1341
+ }
1342
+ }
1119
1343
  return {
1120
1344
  query,
1121
1345
  body,
1122
1346
  response,
1123
- params: paramsType
1347
+ params: paramsType,
1348
+ queryRef,
1349
+ bodyRef,
1350
+ responseRef
1124
1351
  };
1125
1352
  }
1126
1353
  __name(extractDtoContract, "extractDtoContract");
@@ -1219,6 +1446,11 @@ function extractFromSourceFile(sourceFile, project) {
1219
1446
  path: combined,
1220
1447
  name: routeName,
1221
1448
  params,
1449
+ controllerRef: {
1450
+ className,
1451
+ methodName,
1452
+ filePath: sourceFile.getFilePath()
1453
+ },
1222
1454
  contract: {
1223
1455
  contractSource: {
1224
1456
  query: contractDef.query,
@@ -1253,13 +1485,20 @@ function extractFromSourceFile(sourceFile, project) {
1253
1485
  path: combined,
1254
1486
  name: routeName,
1255
1487
  params,
1256
- // Attach contract if DTO extraction produced useful type info
1488
+ controllerRef: {
1489
+ className,
1490
+ methodName,
1491
+ filePath: sourceFile.getFilePath()
1492
+ },
1257
1493
  ...dtoContract ? {
1258
1494
  contract: {
1259
1495
  contractSource: {
1260
1496
  query: dtoContract.query,
1261
1497
  body: dtoContract.body,
1262
- response: dtoContract.response
1498
+ response: dtoContract.response,
1499
+ queryRef: dtoContract.queryRef,
1500
+ bodyRef: dtoContract.bodyRef,
1501
+ responseRef: dtoContract.responseRef
1263
1502
  }
1264
1503
  }
1265
1504
  } : {}
@@ -1432,7 +1671,7 @@ async function watch(config, onChange) {
1432
1671
  __name(watch, "watch");
1433
1672
 
1434
1673
  // src/index.ts
1435
- var VERSION = "1.0.7";
1674
+ var VERSION = "1.3.0";
1436
1675
 
1437
1676
  // src/cli/codegen.ts
1438
1677
  async function runCodegen(opts = {}) {
@@ -1464,7 +1703,7 @@ __name(runCodegen, "runCodegen");
1464
1703
 
1465
1704
  // src/cli/init.ts
1466
1705
  var import_node_child_process = require("child_process");
1467
- var import_node_fs = require("fs");
1706
+ var import_node_fs2 = require("fs");
1468
1707
  var import_promises10 = require("fs/promises");
1469
1708
  var import_node_path11 = require("path");
1470
1709
  var import_node_readline = require("readline");
@@ -1688,7 +1927,7 @@ __name(findAfterLastImport, "findAfterLastImport");
1688
1927
  function patchAppModule(filePath, rootView) {
1689
1928
  let content;
1690
1929
  try {
1691
- content = (0, import_node_fs.readFileSync)(filePath, "utf8");
1930
+ content = (0, import_node_fs2.readFileSync)(filePath, "utf8");
1692
1931
  } catch {
1693
1932
  return "skipped";
1694
1933
  }
@@ -1726,14 +1965,14 @@ ${indent}HomeController,${content.slice(bracketPos)}`;
1726
1965
  }
1727
1966
  }
1728
1967
  if (!changed) return "already";
1729
- (0, import_node_fs.writeFileSync)(filePath, content, "utf8");
1968
+ (0, import_node_fs2.writeFileSync)(filePath, content, "utf8");
1730
1969
  return "patched";
1731
1970
  }
1732
1971
  __name(patchAppModule, "patchAppModule");
1733
1972
  function patchMainTs(filePath) {
1734
1973
  let content;
1735
1974
  try {
1736
- content = (0, import_node_fs.readFileSync)(filePath, "utf8");
1975
+ content = (0, import_node_fs2.readFileSync)(filePath, "utf8");
1737
1976
  } catch {
1738
1977
  return "skipped";
1739
1978
  }
@@ -1757,7 +1996,7 @@ ${content.slice(insertAt)}`;
1757
1996
  });`;
1758
1997
  content = `${content.slice(0, insertAfterPos)}
1759
1998
  ${viteSetup}${content.slice(insertAfterPos)}`;
1760
- (0, import_node_fs.writeFileSync)(filePath, content, "utf8");
1999
+ (0, import_node_fs2.writeFileSync)(filePath, content, "utf8");
1761
2000
  return "patched";
1762
2001
  }
1763
2002
  __name(patchMainTs, "patchMainTs");
@@ -1806,11 +2045,19 @@ function htmlShellTemplate(framework, _engine) {
1806
2045
  __name(htmlShellTemplate, "htmlShellTemplate");
1807
2046
  function viteConfigTemplate(framework) {
1808
2047
  const pluginOption = `{ ${framework}: true }`;
1809
- return `import { defineConfig } from 'vite';
2048
+ return `import { resolve } from 'node:path';
2049
+ import { defineConfig } from 'vite';
1810
2050
  import nestInertia from '@dudousxd/nestjs-inertia-vite/plugin';
1811
2051
 
1812
2052
  export default defineConfig({
1813
2053
  plugins: [nestInertia(${pluginOption})],
2054
+ resolve: {
2055
+ alias: {
2056
+ '@': resolve(__dirname, 'src'),
2057
+ '~': resolve(__dirname, 'inertia'),
2058
+ '~codegen': resolve(__dirname, '.nestjs-inertia'),
2059
+ },
2060
+ },
1814
2061
  });
1815
2062
  `;
1816
2063
  }