@luckystack/devkit 0.10.1 → 0.11.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.
Files changed (43) hide show
  1. package/AGENTS.md +9 -0
  2. package/CHANGELOG.md +14 -1
  3. package/README.md +2 -37
  4. package/dist/cli/validateDeploy.d.ts +2 -0
  5. package/dist/functionRegistry.d.ts +72 -0
  6. package/dist/hotReload.d.ts +1 -0
  7. package/dist/importDependencyGraph.d.ts +2 -0
  8. package/dist/index.d.ts +15 -280
  9. package/dist/index.js +633 -435
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/mapUtils.d.ts +2 -0
  12. package/dist/loader.d.ts +11 -0
  13. package/dist/prismaClientCheck.d.ts +19 -0
  14. package/dist/routeConventions.d.ts +20 -0
  15. package/dist/routeNamingValidation.d.ts +46 -0
  16. package/dist/routingRules.d.ts +62 -0
  17. package/dist/runtimeTypeResolver.d.ts +15 -0
  18. package/dist/supervisor.d.ts +25 -0
  19. package/dist/templateInjector.d.ts +60 -0
  20. package/dist/templateRegistry.d.ts +78 -0
  21. package/dist/typeMap/apiMeta.d.ts +42 -0
  22. package/dist/typeMap/discovery.d.ts +3 -0
  23. package/dist/typeMap/emitterArtifacts.d.ts +94 -0
  24. package/dist/typeMap/extractionDiagnostics.d.ts +16 -0
  25. package/dist/typeMap/extractors.d.ts +18 -0
  26. package/dist/typeMap/functionsMeta.d.ts +5 -0
  27. package/dist/typeMap/routeMeta.d.ts +6 -0
  28. package/dist/typeMap/tsApi.d.ts +12 -0
  29. package/dist/typeMap/tsProgram.d.ts +41 -0
  30. package/dist/typeMap/typeContext.d.ts +21 -0
  31. package/dist/typeMap/zodEmitter.d.ts +8 -0
  32. package/dist/typeMapGenerator.d.ts +5 -0
  33. package/dist/validateDeploy.d.ts +25 -0
  34. package/docs/cli.md +3 -243
  35. package/docs/hot-reload.md +4 -362
  36. package/docs/loader-pipeline.md +3 -322
  37. package/docs/runtime-type-resolver.md +3 -256
  38. package/docs/supervisor.md +3 -290
  39. package/docs/template-customization.md +2 -133
  40. package/docs/ts-program-cache.md +4 -197
  41. package/docs/type-map-generation.md +5 -410
  42. package/package.json +5 -5
  43. package/CLAUDE.md +0 -135
package/dist/index.js CHANGED
@@ -567,34 +567,98 @@ var extractSyncVersion = (filePath) => {
567
567
  };
568
568
 
569
569
  // src/typeMap/apiMeta.ts
570
- import * as ts from "typescript";
571
- import fs3 from "fs";
570
+ import fs4 from "fs";
571
+ import {
572
+ getJSDocTags,
573
+ SyntaxKind
574
+ } from "typescript-7-api/ast";
575
+ import {
576
+ isArrayLiteralExpression,
577
+ isAsExpression,
578
+ isIdentifier,
579
+ isNumericLiteral,
580
+ isObjectLiteralExpression,
581
+ isParenthesizedExpression,
582
+ isPropertyAssignment,
583
+ isSatisfiesExpression,
584
+ isStringLiteral,
585
+ isVariableStatement
586
+ } from "typescript-7-api/ast/is";
572
587
  import { inferHttpMethod, tryCatchSync } from "@luckystack/core";
588
+
589
+ // src/typeMap/tsApi.ts
590
+ import fs3 from "fs";
591
+ import path4 from "path";
592
+ import { API } from "typescript-7-api/sync";
593
+ import { ROOT_DIR as ROOT_DIR3 } from "@luckystack/core";
594
+ var api = null;
595
+ var serverSnapshot = null;
596
+ var serverProject = null;
597
+ var getTsApi = () => {
598
+ api ??= new API({ cwd: ROOT_DIR3 });
599
+ return api;
600
+ };
601
+ var openTsconfigProject = (tsconfigPath) => {
602
+ const tsApi = getTsApi();
603
+ const { fileNames, options } = tsApi.parseConfigFile(tsconfigPath);
604
+ const snapshot = tsApi.createSnapshot({ createPrograms: [{ rootFiles: fileNames, compilerOptions: options }] });
605
+ const [program] = snapshot.operation.createdPrograms;
606
+ return { project: program.getProject(), snapshot };
607
+ };
608
+ var getServerProgram = () => {
609
+ if (serverProject) return serverProject;
610
+ const tsconfigPath = path4.join(ROOT_DIR3, "tsconfig.server.json");
611
+ if (!fs3.existsSync(tsconfigPath)) throw new Error("[TypeProgram] tsconfig.server.json not found");
612
+ const { project, snapshot } = openTsconfigProject(tsconfigPath);
613
+ serverSnapshot = snapshot;
614
+ serverProject = project;
615
+ return project;
616
+ };
617
+ var invalidateProgramCache = () => {
618
+ serverSnapshot?.dispose();
619
+ serverSnapshot = null;
620
+ serverProject = null;
621
+ };
622
+ var disposeTsApi = () => {
623
+ invalidateProgramCache();
624
+ api?.close();
625
+ api = null;
626
+ };
627
+ var parseSourceText = (fileName, text, scriptKind) => {
628
+ const retained = getTsApi().createSourceFile(fileName, text, scriptKind === void 0 ? void 0 : { scriptKind });
629
+ retained.dispose();
630
+ return retained.sourceFile;
631
+ };
632
+ var transpileSourceText = (fileName, text) => {
633
+ return getTsApi().transpileModule(text, { fileName, reportDiagnostics: true });
634
+ };
635
+
636
+ // src/typeMap/apiMeta.ts
573
637
  var findExportedConst = (sourceFile, name) => {
574
638
  for (const statement of sourceFile.statements) {
575
- if (!ts.isVariableStatement(statement)) continue;
576
- const hasExport = statement.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
639
+ if (!isVariableStatement(statement)) continue;
640
+ const hasExport = statement.modifiers?.some((m) => m.kind === SyntaxKind.ExportKeyword);
577
641
  if (!hasExport) continue;
578
642
  for (const decl of statement.declarationList.declarations) {
579
- if (ts.isIdentifier(decl.name) && decl.name.text === name) return decl;
643
+ if (isIdentifier(decl.name) && decl.name.text === name) return decl;
580
644
  }
581
645
  }
582
646
  return null;
583
647
  };
584
648
  var unwrapExpression = (node) => {
585
649
  let current = node;
586
- while (ts.isAsExpression(current) || ts.isSatisfiesExpression(current) || ts.isParenthesizedExpression(current)) {
650
+ while (isAsExpression(current) || isSatisfiesExpression(current) || isParenthesizedExpression(current)) {
587
651
  current = current.expression;
588
652
  }
589
653
  return current;
590
654
  };
591
655
  var extractHttpMethod = (filePath, apiName) => {
592
656
  const [error, method] = tryCatchSync(() => {
593
- const content = fs3.readFileSync(filePath, "utf8");
594
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
657
+ const content = fs4.readFileSync(filePath, "utf8");
658
+ const sourceFile = parseSourceText(filePath, content);
595
659
  const decl = findExportedConst(sourceFile, "httpMethod");
596
660
  const initializer = decl?.initializer ? unwrapExpression(decl.initializer) : void 0;
597
- if (initializer && ts.isStringLiteral(initializer)) {
661
+ if (initializer && isStringLiteral(initializer)) {
598
662
  const candidate = initializer.text.toUpperCase();
599
663
  if (["GET", "POST", "PUT", "DELETE"].includes(candidate)) return candidate;
600
664
  }
@@ -607,13 +671,13 @@ var extractHttpMethod = (filePath, apiName) => {
607
671
  };
608
672
  var extractRateLimit = (filePath) => {
609
673
  const [error, rateLimit] = tryCatchSync(() => {
610
- const content = fs3.readFileSync(filePath, "utf8");
611
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
674
+ const content = fs4.readFileSync(filePath, "utf8");
675
+ const sourceFile = parseSourceText(filePath, content);
612
676
  const decl = findExportedConst(sourceFile, "rateLimit");
613
677
  if (decl?.initializer) {
614
678
  const initializer = unwrapExpression(decl.initializer);
615
- if (initializer.kind === ts.SyntaxKind.FalseKeyword) return false;
616
- if (ts.isNumericLiteral(initializer)) return Number(initializer.text);
679
+ if (initializer.kind === SyntaxKind.FalseKeyword) return false;
680
+ if (isNumericLiteral(initializer)) return Number(initializer.text);
617
681
  }
618
682
  return void 0;
619
683
  });
@@ -624,16 +688,16 @@ var extractRateLimit = (filePath) => {
624
688
  };
625
689
  var readPrimitive = (rawNode) => {
626
690
  const node = unwrapExpression(rawNode);
627
- if (ts.isStringLiteral(node)) return node.text;
628
- if (ts.isNumericLiteral(node)) return Number(node.text);
629
- if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
630
- if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
691
+ if (isStringLiteral(node)) return node.text;
692
+ if (isNumericLiteral(node)) return Number(node.text);
693
+ if (node.kind === SyntaxKind.TrueKeyword) return true;
694
+ if (node.kind === SyntaxKind.FalseKeyword) return false;
631
695
  return void 0;
632
696
  };
633
697
  var parseAdditionalItem = (objectLiteral) => {
634
698
  const item = {};
635
699
  for (const prop of objectLiteral.properties) {
636
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;
700
+ if (!isPropertyAssignment(prop) || !isIdentifier(prop.name)) continue;
637
701
  const value = readPrimitive(prop.initializer);
638
702
  if (value !== void 0) item[prop.name.text] = value;
639
703
  }
@@ -653,8 +717,8 @@ var commentToString = (commentValue) => {
653
717
  };
654
718
  var extractDocsMeta = (filePath) => {
655
719
  const [error, docsMeta] = tryCatchSync(() => {
656
- const content = fs3.readFileSync(filePath, "utf8");
657
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
720
+ const content = fs4.readFileSync(filePath, "utf8");
721
+ const sourceFile = parseSourceText(filePath, content);
658
722
  const result = {};
659
723
  const consumeTag = (tag) => {
660
724
  if (tag.tagName.text !== "docs") return;
@@ -673,7 +737,7 @@ var extractDocsMeta = (filePath) => {
673
737
  }
674
738
  };
675
739
  for (const statement of sourceFile.statements) {
676
- for (const tag of ts.getJSDocTags(statement)) {
740
+ for (const tag of getJSDocTags(statement)) {
677
741
  consumeTag(tag);
678
742
  }
679
743
  }
@@ -690,25 +754,25 @@ var extractDocsMeta = (filePath) => {
690
754
  };
691
755
  var extractAuth = (filePath) => {
692
756
  const [, auth] = tryCatchSync(() => {
693
- const content = fs3.readFileSync(filePath, "utf8");
694
- const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
757
+ const content = fs4.readFileSync(filePath, "utf8");
758
+ const sourceFile = parseSourceText(filePath, content);
695
759
  const decl = findExportedConst(sourceFile, "auth");
696
760
  const authInitializer = decl?.initializer ? unwrapExpression(decl.initializer) : void 0;
697
- if (!authInitializer || !ts.isObjectLiteralExpression(authInitializer)) return { login: false, hasAdditional: false };
761
+ if (!authInitializer || !isObjectLiteralExpression(authInitializer)) return { login: false, hasAdditional: false };
698
762
  let login = false;
699
763
  let additional;
700
764
  let hasAdditional = false;
701
765
  for (const prop of authInitializer.properties) {
702
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) continue;
766
+ if (!isPropertyAssignment(prop) || !isIdentifier(prop.name)) continue;
703
767
  const propInit = unwrapExpression(prop.initializer);
704
768
  if (prop.name.text === "login") {
705
- login = propInit.kind === ts.SyntaxKind.TrueKeyword;
769
+ login = propInit.kind === SyntaxKind.TrueKeyword;
706
770
  }
707
- if (prop.name.text === "additional" && ts.isArrayLiteralExpression(propInit)) {
771
+ if (prop.name.text === "additional" && isArrayLiteralExpression(propInit)) {
708
772
  hasAdditional = propInit.elements.length > 0;
709
773
  additional = [];
710
774
  for (const element of propInit.elements) {
711
- if (!ts.isObjectLiteralExpression(element)) continue;
775
+ if (!isObjectLiteralExpression(element)) continue;
712
776
  const item = parseAdditionalItem(element);
713
777
  if (item) additional.push(item);
714
778
  }
@@ -720,46 +784,78 @@ var extractAuth = (filePath) => {
720
784
  };
721
785
 
722
786
  // src/typeMap/emitterArtifacts.ts
723
- import fs4 from "fs";
724
- import path4 from "path";
725
- import * as ts3 from "typescript";
787
+ import fs5 from "fs";
788
+ import path5 from "path";
789
+ import {
790
+ ScriptKind
791
+ } from "typescript-7-api/ast";
792
+ import {
793
+ isClassDeclaration,
794
+ isEnumDeclaration,
795
+ isFunctionDeclaration,
796
+ isIdentifier as isIdentifier3,
797
+ isImportDeclaration,
798
+ isInferTypeNode,
799
+ isInterfaceDeclaration,
800
+ isMappedTypeNode,
801
+ isNamedImports,
802
+ isNamespaceImport,
803
+ isQualifiedName,
804
+ isTypeAliasDeclaration as isTypeAliasDeclaration2,
805
+ isTypeReferenceNode as isTypeReferenceNode2
806
+ } from "typescript-7-api/ast/is";
726
807
  import { getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath } from "@luckystack/core";
727
808
 
728
809
  // src/typeMap/zodEmitter.ts
729
- import * as ts2 from "typescript";
810
+ import { SyntaxKind as SyntaxKind2 } from "typescript-7-api/ast";
811
+ import {
812
+ isArrayTypeNode,
813
+ isIdentifier as isIdentifier2,
814
+ isIndexSignatureDeclaration,
815
+ isIntersectionTypeNode,
816
+ isLiteralTypeNode,
817
+ isNumericLiteral as isNumericLiteral2,
818
+ isParenthesizedTypeNode,
819
+ isPropertySignatureDeclaration,
820
+ isStringLiteral as isStringLiteral2,
821
+ isTypeAliasDeclaration,
822
+ isTypeLiteralNode,
823
+ isTypeReferenceNode,
824
+ isUnionTypeNode
825
+ } from "typescript-7-api/ast/is";
730
826
  var wrapOptional = (inner) => `${inner}.optional()`;
731
827
  var anyFallback = (reason) => `z.any() /* ${reason} */`;
732
828
  var convertTypeNode = (node) => {
733
- if (node.kind === ts2.SyntaxKind.StringKeyword) return "z.string()";
734
- if (node.kind === ts2.SyntaxKind.NumberKeyword) return "z.number()";
735
- if (node.kind === ts2.SyntaxKind.BooleanKeyword) return "z.boolean()";
736
- if (node.kind === ts2.SyntaxKind.NullKeyword) return "z.null()";
737
- if (node.kind === ts2.SyntaxKind.UndefinedKeyword) return "z.undefined()";
738
- if (node.kind === ts2.SyntaxKind.AnyKeyword) return "z.any()";
739
- if (node.kind === ts2.SyntaxKind.UnknownKeyword) return "z.unknown()";
740
- if (node.kind === ts2.SyntaxKind.NeverKeyword) return "z.never()";
741
- if (ts2.isLiteralTypeNode(node)) {
829
+ if (node.kind === SyntaxKind2.StringKeyword) return "z.string()";
830
+ if (node.kind === SyntaxKind2.NumberKeyword) return "z.number()";
831
+ if (node.kind === SyntaxKind2.BooleanKeyword) return "z.boolean()";
832
+ if (node.kind === SyntaxKind2.NullKeyword) return "z.null()";
833
+ if (node.kind === SyntaxKind2.UndefinedKeyword) return "z.undefined()";
834
+ if (node.kind === SyntaxKind2.AnyKeyword) return "z.any()";
835
+ if (node.kind === SyntaxKind2.UnknownKeyword) return "z.unknown()";
836
+ if (node.kind === SyntaxKind2.NeverKeyword) return "z.never()";
837
+ if (isLiteralTypeNode(node)) {
742
838
  const literal = node.literal;
743
- if (ts2.isStringLiteral(literal)) return `z.literal(${JSON.stringify(literal.text)})`;
744
- if (ts2.isNumericLiteral(literal)) return `z.literal(${literal.text})`;
745
- if (literal.kind === ts2.SyntaxKind.TrueKeyword) return "z.literal(true)";
746
- if (literal.kind === ts2.SyntaxKind.FalseKeyword) return "z.literal(false)";
747
- if (literal.kind === ts2.SyntaxKind.NullKeyword) return "z.null()";
839
+ if (isStringLiteral2(literal)) return `z.literal(${JSON.stringify(literal.text)})`;
840
+ if (isNumericLiteral2(literal)) return `z.literal(${literal.text})`;
841
+ if (literal.kind === SyntaxKind2.TrueKeyword) return "z.literal(true)";
842
+ if (literal.kind === SyntaxKind2.FalseKeyword) return "z.literal(false)";
843
+ if (literal.kind === SyntaxKind2.NullKeyword) return "z.null()";
748
844
  return anyFallback("unknown literal");
749
845
  }
750
- if (ts2.isArrayTypeNode(node)) {
846
+ if (isArrayTypeNode(node)) {
751
847
  return `z.array(${convertTypeNode(node.elementType)})`;
752
848
  }
753
- if (ts2.isUnionTypeNode(node)) {
849
+ if (isUnionTypeNode(node)) {
754
850
  const members = node.types;
755
- const hasUndefined = members.some((m) => m.kind === ts2.SyntaxKind.UndefinedKeyword);
756
- const nonUndef = members.filter((m) => m.kind !== ts2.SyntaxKind.UndefinedKeyword);
851
+ const hasUndefined = members.some((m) => m.kind === SyntaxKind2.UndefinedKeyword);
852
+ const nonUndef = members.filter((m) => m.kind !== SyntaxKind2.UndefinedKeyword);
757
853
  if (nonUndef.length === 0) return "z.undefined()";
758
854
  const firstNonUndef = nonUndef[0];
759
855
  const innerSchema = nonUndef.length === 1 && firstNonUndef ? convertTypeNode(firstNonUndef) : `z.union([${nonUndef.map((m) => convertTypeNode(m)).join(", ")}])`;
760
856
  return hasUndefined ? wrapOptional(innerSchema) : innerSchema;
761
857
  }
762
- if (ts2.isTypeReferenceNode(node)) {
858
+ if (isTypeReferenceNode(node)) {
763
859
  const name = node.typeName.getText();
764
860
  const args = node.typeArguments ?? [];
765
861
  switch (name) {
@@ -787,10 +883,10 @@ var convertTypeNode = (node) => {
787
883
  }
788
884
  }
789
885
  }
790
- if (ts2.isTypeLiteralNode(node)) {
791
- const indexSignatures = node.members.filter((m) => ts2.isIndexSignatureDeclaration(m));
792
- const propertySignatures = node.members.filter((m) => ts2.isPropertySignature(m));
793
- if (indexSignatures.length === 1 && propertySignatures.length === 0 && indexSignatures[0]?.type.kind === ts2.SyntaxKind.NeverKeyword) {
886
+ if (isTypeLiteralNode(node)) {
887
+ const indexSignatures = node.members.filter((m) => isIndexSignatureDeclaration(m));
888
+ const propertySignatures = node.members.filter((m) => isPropertySignatureDeclaration(m));
889
+ if (indexSignatures.length === 1 && propertySignatures.length === 0 && indexSignatures[0]?.type.kind === SyntaxKind2.NeverKeyword) {
794
890
  return "z.object({}).strict()";
795
891
  }
796
892
  if (indexSignatures.length > 0 && propertySignatures.length === 0) {
@@ -802,21 +898,21 @@ var convertTypeNode = (node) => {
802
898
  }
803
899
  }
804
900
  const entries = propertySignatures.map((prop) => {
805
- if (!ts2.isIdentifier(prop.name)) return null;
901
+ if (!isIdentifier2(prop.name)) return null;
806
902
  if (!prop.type) return null;
807
903
  const name = prop.name.text;
808
904
  let schema = convertTypeNode(prop.type);
809
- if (prop.questionToken && !schema.endsWith(".optional()")) {
905
+ if (prop.postfixToken?.kind === SyntaxKind2.QuestionToken && !schema.endsWith(".optional()")) {
810
906
  schema = wrapOptional(schema);
811
907
  }
812
908
  return `${JSON.stringify(name)}: ${schema}`;
813
909
  }).filter((entry) => entry !== null);
814
910
  return `z.object({ ${entries.join(", ")} }).strict()`;
815
911
  }
816
- if (ts2.isParenthesizedTypeNode(node)) {
912
+ if (isParenthesizedTypeNode(node)) {
817
913
  return convertTypeNode(node.type);
818
914
  }
819
- if (ts2.isIntersectionTypeNode(node)) {
915
+ if (isIntersectionTypeNode(node)) {
820
916
  return anyFallback("intersection not yet supported");
821
917
  }
822
918
  return anyFallback(`unsupported TypeNode kind=${String(node.kind)}`);
@@ -825,9 +921,9 @@ var typeTextToZodSource = (typeText) => {
825
921
  const trimmed = typeText.trim();
826
922
  if (!trimmed) return null;
827
923
  const synthetic = `type __X = ${trimmed};`;
828
- const source = ts2.createSourceFile("__zod.ts", synthetic, ts2.ScriptTarget.Latest, true);
924
+ const source = parseSourceText("__zod.ts", synthetic);
829
925
  const statement = source.statements[0];
830
- if (!statement || !ts2.isTypeAliasDeclaration(statement)) return null;
926
+ if (!statement || !isTypeAliasDeclaration(statement)) return null;
831
927
  return convertTypeNode(statement.type);
832
928
  };
833
929
 
@@ -867,6 +963,75 @@ var findExtractionFailure = (route, kind, field) => {
867
963
  };
868
964
 
869
965
  // src/typeMap/emitterArtifacts.ts
966
+ var compareVersions = (a, b) => a.version.localeCompare(b.version, void 0, { numeric: true });
967
+ var renderRouteMetaFields = (authValue, rateLimit) => {
968
+ const auth = authValue && typeof authValue === "object" ? authValue : { login: false, hasAdditional: false };
969
+ const rateLimitPart = rateLimit === void 0 ? "" : `, rateLimit: ${rateLimit === false ? "false" : String(rateLimit)}`;
970
+ const additionalPart = auth.additional && auth.additional.length > 0 ? `, additional: ${JSON.stringify(auth.additional)}` : "";
971
+ return `auth: { login: ${auth.login ? "true" : "false"}${additionalPart}${auth.hasAdditional ? ", hasAdditional: true" : ""} }${rateLimitPart}`;
972
+ };
973
+ var inputSchemaSource = (typeText) => typeTextToZodSource(typeText) ?? "z.any() /* unparseable input type */";
974
+ var groupServerSyncRoutes = (syncTypesByPage) => {
975
+ const pages = [];
976
+ for (const pagePath of [...syncTypesByPage.keys()].toSorted()) {
977
+ const grouped = /* @__PURE__ */ new Map();
978
+ for (const [syncKey, entry] of mustGet(syncTypesByPage, pagePath, "syncTypesByPage")) {
979
+ if (!entry.serverMeta) continue;
980
+ const { name, version } = splitVersionedKey(syncKey);
981
+ getOrInit(grouped, name, () => []).push({ version, clientInput: entry.clientInput, serverMeta: entry.serverMeta });
982
+ }
983
+ if (grouped.size === 0) continue;
984
+ pages.push([
985
+ pagePath,
986
+ [...grouped.keys()].toSorted().map((name) => [name, mustGet(grouped, name, "grouped").toSorted(compareVersions)])
987
+ ]);
988
+ }
989
+ return pages;
990
+ };
991
+ var renderServerSyncRouteMap = (syncTypesByPage, renderValue) => {
992
+ let body = "";
993
+ for (const [pagePath, syncs] of groupServerSyncRoutes(syncTypesByPage)) {
994
+ body += ` '${pagePath}': {
995
+ `;
996
+ for (const [syncName, routes] of syncs) {
997
+ body += ` '${syncName}': {
998
+ `;
999
+ for (const route of routes) {
1000
+ body += ` '${route.version}': ${renderValue(route)},
1001
+ `;
1002
+ }
1003
+ body += ` },
1004
+ `;
1005
+ }
1006
+ body += ` },
1007
+ `;
1008
+ }
1009
+ return body;
1010
+ };
1011
+ var buildSyncMetaMapSource = (syncTypesByPage) => `export interface SyncMetaEntry {
1012
+ auth: { login: boolean; additional?: Record<string, unknown>[]; hasAdditional?: boolean };
1013
+ rateLimit?: number | false;
1014
+ }
1015
+
1016
+ export const syncMetaMap: Record<string, Record<string, Record<string, SyncMetaEntry>>> = {
1017
+ ${renderServerSyncRouteMap(syncTypesByPage, (route) => `{ ${renderRouteMetaFields(route.serverMeta.auth, route.serverMeta.rateLimit)} }`)}};
1018
+
1019
+ export const getSyncMeta = (pagePath: string, syncName: string, version: string): SyncMetaEntry | undefined => {
1020
+ return syncMetaMap[pagePath]?.[syncName]?.[version];
1021
+ };
1022
+ `;
1023
+ var buildSyncInputSchemasSource = (syncTypesByPage) => `
1024
+ export const syncInputSchemas: Record<string, Record<string, Record<string, z.ZodTypeAny>>> = {
1025
+ ${renderServerSyncRouteMap(syncTypesByPage, (route) => inputSchemaSource(route.clientInput))}};
1026
+
1027
+ export const getSyncInputSchema = (
1028
+ pagePath: string,
1029
+ syncName: string,
1030
+ version: string,
1031
+ ): z.ZodTypeAny | undefined => {
1032
+ return syncInputSchemas[pagePath]?.[syncName]?.[version];
1033
+ };
1034
+ `;
870
1035
  var buildImportStatements = ({
871
1036
  namedImports,
872
1037
  defaultImports
@@ -887,13 +1052,13 @@ var splitVersionedKey = (value) => {
887
1052
  return { name: name ?? "", version: version ?? "v1" };
888
1053
  };
889
1054
  var writeFileIfChanged = (filePath, content) => {
890
- if (fs4.existsSync(filePath)) {
891
- const currentContent = fs4.readFileSync(filePath, "utf8");
1055
+ if (fs5.existsSync(filePath)) {
1056
+ const currentContent = fs5.readFileSync(filePath, "utf8");
892
1057
  if (currentContent === content) {
893
1058
  return false;
894
1059
  }
895
1060
  }
896
- fs4.writeFileSync(filePath, content, "utf8");
1061
+ fs5.writeFileSync(filePath, content, "utf8");
897
1062
  return true;
898
1063
  };
899
1064
  var indentStr = (str, indentText) => {
@@ -932,7 +1097,7 @@ var stripSymbolKeyedMembers = (text) => {
932
1097
  return result;
933
1098
  };
934
1099
  var validateGeneratedTypeIdentifiers = (content) => {
935
- const sourceFile = ts3.createSourceFile("apiTypes.generated.ts", content, ts3.ScriptTarget.Latest, true, ts3.ScriptKind.TS);
1100
+ const sourceFile = parseSourceText("apiTypes.generated.ts", content, ScriptKind.TS);
936
1101
  const knownSymbols = /* @__PURE__ */ new Set();
937
1102
  const referencedSymbols = /* @__PURE__ */ new Set();
938
1103
  const builtIns = /* @__PURE__ */ new Set([
@@ -989,38 +1154,38 @@ var validateGeneratedTypeIdentifiers = (content) => {
989
1154
  }
990
1155
  };
991
1156
  const collectKnownSymbols = (node) => {
992
- if (ts3.isInferTypeNode(node)) {
1157
+ if (isInferTypeNode(node)) {
993
1158
  knownSymbols.add(node.typeParameter.name.text);
994
1159
  }
995
- if (ts3.isMappedTypeNode(node)) {
1160
+ if (isMappedTypeNode(node)) {
996
1161
  knownSymbols.add(node.typeParameter.name.text);
997
1162
  }
998
- if (ts3.isImportDeclaration(node)) {
1163
+ if (isImportDeclaration(node)) {
999
1164
  const importClause = node.importClause;
1000
1165
  if (importClause?.name) knownSymbols.add(importClause.name.text);
1001
- if (importClause?.namedBindings && ts3.isNamedImports(importClause.namedBindings)) {
1166
+ if (importClause?.namedBindings && isNamedImports(importClause.namedBindings)) {
1002
1167
  for (const importElement of importClause.namedBindings.elements) {
1003
1168
  knownSymbols.add((importElement.propertyName ?? importElement.name).text);
1004
1169
  }
1005
1170
  }
1006
- if (importClause?.namedBindings && ts3.isNamespaceImport(importClause.namedBindings)) {
1171
+ if (importClause?.namedBindings && isNamespaceImport(importClause.namedBindings)) {
1007
1172
  knownSymbols.add(importClause.namedBindings.name.text);
1008
1173
  }
1009
1174
  }
1010
- if (ts3.isInterfaceDeclaration(node) || ts3.isTypeAliasDeclaration(node) || ts3.isClassDeclaration(node) || ts3.isEnumDeclaration(node) || ts3.isFunctionDeclaration(node)) {
1175
+ if (isInterfaceDeclaration(node) || isTypeAliasDeclaration2(node) || isClassDeclaration(node) || isEnumDeclaration(node) || isFunctionDeclaration(node)) {
1011
1176
  addDeclaredName(node.name);
1012
1177
  collectTypeParams(node);
1013
1178
  }
1014
- if (ts3.isTypeReferenceNode(node)) {
1179
+ if (isTypeReferenceNode2(node)) {
1015
1180
  const typeName = node.typeName;
1016
- if (ts3.isIdentifier(typeName)) {
1181
+ if (isIdentifier3(typeName)) {
1017
1182
  referencedSymbols.add(typeName.text);
1018
1183
  }
1019
- if (ts3.isQualifiedName(typeName) && ts3.isIdentifier(typeName.left)) {
1184
+ if (isQualifiedName(typeName) && isIdentifier3(typeName.left)) {
1020
1185
  referencedSymbols.add(typeName.left.text);
1021
1186
  }
1022
1187
  }
1023
- ts3.forEachChild(node, collectKnownSymbols);
1188
+ node.forEachChild(collectKnownSymbols);
1024
1189
  };
1025
1190
  collectKnownSymbols(sourceFile);
1026
1191
  const unknown = [...referencedSymbols].filter((name) => !knownSymbols.has(name) && !builtIns.has(name)).toSorted();
@@ -1060,7 +1225,7 @@ var collectFallbacks = (typesByPage, syncTypesByPage) => {
1060
1225
  for (const [syncKey, entry] of syncs) {
1061
1226
  const { name, version } = splitVersionedKey(syncKey);
1062
1227
  const route = `${pagePath}/${name}@${version}`;
1063
- flagField(route, "sync", "clientInput", entry.clientInput);
1228
+ flagField(route, "sync", "clientInput", entry.clientInput, entry.serverMeta !== void 0);
1064
1229
  flagField(route, "sync", "serverOutput", entry.serverOutput, false, !entry.hasServer);
1065
1230
  flagField(route, "sync", "clientOutput", entry.clientOutput, false, !entry.hasClient);
1066
1231
  flagField(route, "sync", "serverStream", entry.serverStream);
@@ -1254,10 +1419,7 @@ export const apiMetaMap: Record<string, Record<string, Record<string, ApiMetaEnt
1254
1419
  content += ` '${apiName}': {
1255
1420
  `;
1256
1421
  for (const { version, entry } of mustGet(grouped, apiName, "grouped").toSorted((a, b) => a.version.localeCompare(b.version, void 0, { numeric: true }))) {
1257
- const auth = entry.auth && typeof entry.auth === "object" ? entry.auth : { login: false, hasAdditional: false };
1258
- const rateLimitPart = entry.rateLimit === void 0 ? "" : `, rateLimit: ${entry.rateLimit === false ? "false" : String(entry.rateLimit)}`;
1259
- const additionalPart = auth.additional && auth.additional.length > 0 ? `, additional: ${JSON.stringify(auth.additional)}` : "";
1260
- content += ` '${version}': { method: '${entry.method}', auth: { login: ${auth.login ? "true" : "false"}${additionalPart}${auth.hasAdditional ? ", hasAdditional: true" : ""} }${rateLimitPart} },
1422
+ content += ` '${version}': { method: '${entry.method}', ${renderRouteMetaFields(entry.auth, entry.rateLimit)} },
1261
1423
  `;
1262
1424
  }
1263
1425
  content += ` },
@@ -1272,6 +1434,7 @@ export const getApiMeta = (pagePath: string, apiName: string, version: string):
1272
1434
  return apiMetaMap[pagePath]?.[apiName]?.[version];
1273
1435
  };
1274
1436
 
1437
+ ${buildSyncMetaMapSource(syncTypesByPage)}
1275
1438
  // Sync Type Definitions
1276
1439
  //
1277
1440
 
@@ -1371,7 +1534,7 @@ declare module '@luckystack/core/typemap' {
1371
1534
  `;
1372
1535
  content = stripSymbolKeyedMembers(content);
1373
1536
  validateGeneratedTypeIdentifiers(content);
1374
- const schemasContent = buildSchemasContent({ typesByPage });
1537
+ const schemasContent = buildSchemasContent({ typesByPage, syncTypesByPage });
1375
1538
  const fallbacks = collectFallbacks(typesByPage, syncTypesByPage);
1376
1539
  const totalRoutes = [...typesByPage.values()].reduce((n, m) => n + m.size, 0) + [...syncTypesByPage.values()].reduce((n, m) => n + m.size, 0);
1377
1540
  const diagnosticsData = {
@@ -1383,11 +1546,13 @@ declare module '@luckystack/core/typemap' {
1383
1546
  return { content, docsData, schemasContent, diagnosticsData };
1384
1547
  };
1385
1548
  var buildSchemasContent = ({
1386
- typesByPage
1549
+ typesByPage,
1550
+ syncTypesByPage
1387
1551
  }) => {
1388
1552
  const sortedPages = [...typesByPage.keys()].toSorted();
1389
1553
  let body = `/* eslint-disable */
1390
- //? Auto-generated Zod schemas for every API input. Driven by the same walk
1554
+ //? Auto-generated Zod schemas for every API input and every sync-server
1555
+ //? clientInput. Driven by the same walk
1391
1556
  //? as apiTypes.generated.ts; see @luckystack/devkit/src/typeMap/zodEmitter.ts
1392
1557
  //? for the TS-AST \xE2\u2020\u2019 Zod converter. Types that fall outside the converter's
1393
1558
  //? scope emit \`z.any()\` with a TODO comment.
@@ -1412,8 +1577,7 @@ export const apiInputSchemas: Record<string, Record<string, Record<string, z.Zod
1412
1577
  for (const { version, entry } of mustGet(grouped, apiName, "grouped").toSorted(
1413
1578
  (a, b) => a.version.localeCompare(b.version, void 0, { numeric: true })
1414
1579
  )) {
1415
- const schemaSrc = typeTextToZodSource(entry.input) ?? "z.any() /* unparseable input type */";
1416
- body += ` '${version}': ${schemaSrc},
1580
+ body += ` '${version}': ${inputSchemaSource(entry.input)},
1417
1581
  `;
1418
1582
  }
1419
1583
  body += ` },
@@ -1432,6 +1596,7 @@ export const getApiInputSchema = (
1432
1596
  return apiInputSchemas[pagePath]?.[apiName]?.[version];
1433
1597
  };
1434
1598
  `;
1599
+ body += buildSyncInputSchemasSource(syncTypesByPage);
1435
1600
  return body;
1436
1601
  };
1437
1602
  var writeTypeMapArtifacts = ({
@@ -1453,9 +1618,9 @@ var writeTypeMapArtifacts = ({
1453
1618
  }
1454
1619
  }
1455
1620
  const docsPath = getGeneratedApiDocsPath();
1456
- const docsDir = path4.dirname(docsPath);
1457
- if (!fs4.existsSync(docsDir)) {
1458
- fs4.mkdirSync(docsDir, { recursive: true });
1621
+ const docsDir = path5.dirname(docsPath);
1622
+ if (!fs5.existsSync(docsDir)) {
1623
+ fs5.mkdirSync(docsDir, { recursive: true });
1459
1624
  }
1460
1625
  const docsContent = JSON.stringify(docsData, null, 2);
1461
1626
  const hasUpdatedDocs = writeFileIfChanged(docsPath, docsContent);
@@ -1463,7 +1628,7 @@ var writeTypeMapArtifacts = ({
1463
1628
  console.log("[TypeMapGenerator] Generated apiDocs.generated.json");
1464
1629
  }
1465
1630
  if (diagnosticsData !== void 0) {
1466
- const diagnosticsPath = path4.join(path4.dirname(docsPath), "apiTypeDiagnostics.generated.json");
1631
+ const diagnosticsPath = path5.join(path5.dirname(docsPath), "apiTypeDiagnostics.generated.json");
1467
1632
  const diagnosticsContent = JSON.stringify(diagnosticsData, null, 2);
1468
1633
  const hasUpdatedDiagnostics = writeFileIfChanged(diagnosticsPath, diagnosticsContent);
1469
1634
  if (hasUpdatedDiagnostics) {
@@ -1479,30 +1644,46 @@ var writeTypeMapArtifacts = ({
1479
1644
  };
1480
1645
 
1481
1646
  // src/typeMap/extractors.ts
1482
- import * as ts5 from "typescript";
1483
- import path6 from "path";
1647
+ import path7 from "path";
1648
+ import { SymbolFlags as SymbolFlags2 } from "typescript-7-api/sync";
1649
+ import {
1650
+ ScriptKind as ScriptKind2
1651
+ } from "typescript-7-api/ast";
1652
+ import {
1653
+ isArrowFunction,
1654
+ isCallExpression,
1655
+ isFunctionDeclaration as isFunctionDeclaration2,
1656
+ isFunctionExpression,
1657
+ isIdentifier as isIdentifier5,
1658
+ isInterfaceDeclaration as isInterfaceDeclaration2,
1659
+ isObjectLiteralExpression as isObjectLiteralExpression2,
1660
+ isPropertySignatureDeclaration as isPropertySignatureDeclaration2,
1661
+ isReturnStatement,
1662
+ isTypeReferenceNode as isTypeReferenceNode3,
1663
+ isVariableStatement as isVariableStatement2
1664
+ } from "typescript-7-api/ast/is";
1484
1665
 
1485
1666
  // src/typeMap/tsProgram.ts
1486
- import * as ts4 from "typescript";
1487
- import path5 from "path";
1488
- import { ROOT_DIR as ROOT_DIR3, getGeneratedSocketTypesPath as getGeneratedSocketTypesPath2 } from "@luckystack/core";
1489
- var cachedProgram = null;
1490
- var getServerProgram = () => {
1491
- if (cachedProgram) return cachedProgram;
1492
- const tsconfigPath = ts4.findConfigFile(ROOT_DIR3, ts4.sys.fileExists.bind(ts4.sys), "tsconfig.server.json");
1493
- if (!tsconfigPath) throw new Error("[TypeProgram] tsconfig.server.json not found");
1494
- const { config } = ts4.readConfigFile(tsconfigPath, ts4.sys.readFile.bind(ts4.sys));
1495
- const { options, fileNames } = ts4.parseJsonConfigFileContent(
1496
- config,
1497
- ts4.sys,
1498
- path5.dirname(tsconfigPath)
1499
- );
1500
- cachedProgram = ts4.createProgram(fileNames, options);
1501
- return cachedProgram;
1502
- };
1503
- var invalidateProgramCache = () => {
1504
- cachedProgram = null;
1505
- };
1667
+ import path6 from "path";
1668
+ import {
1669
+ ObjectFlags,
1670
+ SymbolFlags,
1671
+ TypeFlags
1672
+ } from "typescript-7-api/sync";
1673
+ import { SyntaxKind as SyntaxKind3 } from "typescript-7-api/ast";
1674
+ import {
1675
+ isAsExpression as isAsExpression2,
1676
+ isIdentifier as isIdentifier4,
1677
+ isNoSubstitutionTemplateLiteral,
1678
+ isNumericLiteral as isNumericLiteral3,
1679
+ isParenthesizedExpression as isParenthesizedExpression2,
1680
+ isPrefixUnaryExpression,
1681
+ isPropertyAssignment as isPropertyAssignment2,
1682
+ isShorthandPropertyAssignment,
1683
+ isStringLiteral as isStringLiteral3,
1684
+ isTypeAssertion
1685
+ } from "typescript-7-api/ast/is";
1686
+ import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath2 } from "@luckystack/core";
1506
1687
  var DEPTH_LIMIT = 14;
1507
1688
  var JSON_TYPE_NAMES = /* @__PURE__ */ new Set([
1508
1689
  "Json",
@@ -1552,35 +1733,35 @@ var UnsupportedWireTypeError = class extends Error {
1552
1733
  }
1553
1734
  };
1554
1735
  var isJsonLikeType = (type, checker) => {
1555
- const symbolName = type.symbol?.name ?? "";
1556
- const aliasName = type.aliasSymbol?.name ?? "";
1736
+ const symbolName = type.getSymbol()?.name ?? "";
1737
+ const aliasName = type.getAliasSymbol()?.name ?? "";
1557
1738
  if (JSON_TYPE_NAMES.has(symbolName) || JSON_TYPE_NAMES.has(aliasName)) return true;
1558
1739
  const rendered = checker.typeToString(type).trim();
1559
1740
  return /^(?:Prisma\.)?(?:Input)?Json(?:Value|Object|Array)$/.test(rendered);
1560
1741
  };
1561
1742
  var getLiteralTypeFromExpression = (expression, checker, depth) => {
1562
- if (ts4.isParenthesizedExpression(expression)) {
1743
+ if (isParenthesizedExpression2(expression)) {
1563
1744
  return getLiteralTypeFromExpression(expression.expression, checker, depth);
1564
1745
  }
1565
- if (ts4.isAsExpression(expression) || ts4.isTypeAssertionExpression(expression)) {
1746
+ if (isAsExpression2(expression) || isTypeAssertion(expression)) {
1566
1747
  return getLiteralTypeFromExpression(expression.expression, checker, depth);
1567
1748
  }
1568
- if (expression.kind === ts4.SyntaxKind.TrueKeyword) return "true";
1569
- if (expression.kind === ts4.SyntaxKind.FalseKeyword) return "false";
1570
- if (expression.kind === ts4.SyntaxKind.NullKeyword) return "null";
1571
- if (ts4.isStringLiteral(expression) || ts4.isNoSubstitutionTemplateLiteral(expression)) {
1749
+ if (expression.kind === SyntaxKind3.TrueKeyword) return "true";
1750
+ if (expression.kind === SyntaxKind3.FalseKeyword) return "false";
1751
+ if (expression.kind === SyntaxKind3.NullKeyword) return "null";
1752
+ if (isStringLiteral3(expression) || isNoSubstitutionTemplateLiteral(expression)) {
1572
1753
  return `'${expression.text.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`)}'`;
1573
1754
  }
1574
- if (ts4.isNumericLiteral(expression)) {
1755
+ if (isNumericLiteral3(expression)) {
1575
1756
  return expression.text;
1576
1757
  }
1577
- if (ts4.isPrefixUnaryExpression(expression) && expression.operator === ts4.SyntaxKind.MinusToken && ts4.isNumericLiteral(expression.operand)) {
1758
+ if (isPrefixUnaryExpression(expression) && expression.operator === SyntaxKind3.MinusToken && isNumericLiteral3(expression.operand)) {
1578
1759
  return `-${expression.operand.text}`;
1579
1760
  }
1580
- if (ts4.isIdentifier(expression)) {
1761
+ if (isIdentifier4(expression)) {
1581
1762
  const identifierType = checker.getTypeAtLocation(expression);
1582
- const isLiteralType = (identifierType.flags & (ts4.TypeFlags.StringLiteral | ts4.TypeFlags.NumberLiteral | ts4.TypeFlags.BooleanLiteral | ts4.TypeFlags.Null | ts4.TypeFlags.Undefined)) !== 0;
1583
- if (isLiteralType || identifierType.isUnion()) {
1763
+ const isLiteralType = (identifierType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.BooleanLiteral | TypeFlags.Null | TypeFlags.Undefined)) !== 0;
1764
+ if (isLiteralType || identifierType.isUnionType()) {
1584
1765
  const expanded = expandTypeDetailed(identifierType, checker, depth).text;
1585
1766
  if (expanded.includes("'") || /\btrue\b|\bfalse\b|\bnull\b|\bundefined\b/.test(expanded)) {
1586
1767
  return expanded;
@@ -1590,13 +1771,15 @@ var getLiteralTypeFromExpression = (expression, checker, depth) => {
1590
1771
  return null;
1591
1772
  };
1592
1773
  var getLiteralTypeFromPropertySymbol = (symbol, checker, depth) => {
1593
- const declarations = symbol.declarations ?? [];
1594
- for (const declaration of declarations) {
1595
- if (ts4.isPropertyAssignment(declaration)) {
1774
+ for (const handle of symbol.declarations) {
1775
+ if (handle.kind !== SyntaxKind3.PropertyAssignment && handle.kind !== SyntaxKind3.ShorthandPropertyAssignment) continue;
1776
+ const declaration = handle.resolve();
1777
+ if (!declaration) continue;
1778
+ if (isPropertyAssignment2(declaration)) {
1596
1779
  const literal = getLiteralTypeFromExpression(declaration.initializer, checker, depth);
1597
1780
  if (literal) return literal;
1598
1781
  }
1599
- if (ts4.isShorthandPropertyAssignment(declaration)) {
1782
+ if (isShorthandPropertyAssignment(declaration) && isIdentifier4(declaration.name)) {
1600
1783
  const literal = getLiteralTypeFromExpression(declaration.name, checker, depth);
1601
1784
  if (literal) return literal;
1602
1785
  }
@@ -1604,10 +1787,10 @@ var getLiteralTypeFromPropertySymbol = (symbol, checker, depth) => {
1604
1787
  return null;
1605
1788
  };
1606
1789
  var normalizeImportPath = (targetFilePath) => {
1607
- const fromDir = path5.dirname(getGeneratedSocketTypesPath2());
1790
+ const fromDir = path6.dirname(getGeneratedSocketTypesPath2());
1608
1791
  const from = fromDir.replaceAll("\\", "/");
1609
1792
  const to = targetFilePath.replaceAll("\\", "/");
1610
- const normalized = path5.posix.relative(from, to).replaceAll("\\", "/");
1793
+ const normalized = path6.posix.relative(from, to).replaceAll("\\", "/");
1611
1794
  const withoutExtension = normalized.replace(/(\.d)?\.(ts|tsx|js|jsx)$/i, "");
1612
1795
  if (withoutExtension.startsWith(".")) return withoutExtension;
1613
1796
  return `./${withoutExtension}`;
@@ -1623,17 +1806,20 @@ var mergeUnresolvedSymbols = (left, right) => {
1623
1806
  }
1624
1807
  return merged;
1625
1808
  };
1809
+ var isNodeModulesPath = (filePath) => filePath.includes("/node_modules/") || filePath.includes("\\node_modules\\");
1810
+ var getDeclarationFileName = (symbol) => {
1811
+ const handle = symbol.declarations[0];
1812
+ if (!handle || isNodeModulesPath(handle.path)) return void 0;
1813
+ const fileName = handle.resolve()?.getSourceFile().fileName;
1814
+ return fileName && !isNodeModulesPath(fileName) ? fileName : void 0;
1815
+ };
1626
1816
  var collectTypeSymbolFallback = (type) => {
1627
- const symbol = type.aliasSymbol ?? type.getSymbol();
1817
+ const symbol = type.getAliasSymbol() ?? type.getSymbol();
1628
1818
  if (!symbol) return [];
1629
- const name = symbol.getName();
1819
+ const name = symbol.name;
1630
1820
  if (!name || name.startsWith("__")) return [];
1631
- const declaration = symbol.declarations?.[0];
1632
- if (!declaration) return [{ name }];
1633
- const sourceFile = declaration.getSourceFile().fileName;
1634
- if (!sourceFile || sourceFile.includes("/node_modules/") || sourceFile.includes("\\node_modules\\")) {
1635
- return [{ name }];
1636
- }
1821
+ const sourceFile = getDeclarationFileName(symbol);
1822
+ if (!sourceFile) return [{ name }];
1637
1823
  return [{
1638
1824
  name,
1639
1825
  sourceFile,
@@ -1644,16 +1830,14 @@ var WIRE_PROJECTED_TYPES = /* @__PURE__ */ new Map([["Date", "string"]]);
1644
1830
  var resolveToJsonReturnType = (type, checker) => {
1645
1831
  const toJson = type.getProperty("toJSON");
1646
1832
  if (!toJson) return null;
1647
- const declaration = toJson.valueDeclaration ?? toJson.declarations?.[0];
1648
- if (!declaration) return null;
1649
- const signature = checker.getTypeOfSymbolAtLocation(toJson, declaration).getCallSignatures()[0];
1833
+ if (!toJson.valueDeclaration && toJson.declarations.length === 0) return null;
1834
+ const signature = checker.getNonMissingTypeOfSymbol(toJson).getCallSignatures()[0];
1650
1835
  return signature ? signature.getReturnType() : null;
1651
1836
  };
1652
1837
  var isFunctionValueType = (type) => type.getCallSignatures().length > 0;
1653
1838
  var typeNameOf = (type, checker) => {
1654
- const objectType = type;
1655
- if (type.flags & ts4.TypeFlags.Object && objectType.objectFlags & ts4.ObjectFlags.Reference) {
1656
- const targetName = objectType.target.getSymbol()?.name;
1839
+ if (type.isTypeReference()) {
1840
+ const targetName = type.getTarget().getSymbol()?.name;
1657
1841
  if (targetName) return targetName;
1658
1842
  }
1659
1843
  return type.getSymbol()?.name ?? checker.typeToString(type);
@@ -1663,13 +1847,13 @@ var assertSupportedWireType = (type, checker) => {
1663
1847
  if (TRANSPORT_DEPENDENT_BINARY_TYPES.has(typeName)) {
1664
1848
  throw new UnsupportedWireTypeError(typeName);
1665
1849
  }
1666
- if ((type.flags & (ts4.TypeFlags.BigInt | ts4.TypeFlags.BigIntLiteral)) !== 0) {
1850
+ if ((type.flags & (TypeFlags.BigInt | TypeFlags.BigIntLiteral)) !== 0) {
1667
1851
  throw new UnsupportedWireTypeError("bigint");
1668
1852
  }
1669
1853
  };
1670
- var isJsonOmittedValueType = (type) => (type.flags & (ts4.TypeFlags.Undefined | ts4.TypeFlags.Void | ts4.TypeFlags.ESSymbol | ts4.TypeFlags.UniqueESSymbol)) !== 0 || isFunctionValueType(type);
1854
+ var isJsonOmittedValueType = (type) => (type.flags & (TypeFlags.Undefined | TypeFlags.Void | TypeFlags.ESSymbol | TypeFlags.UniqueESSymbol)) !== 0 || isFunctionValueType(type);
1671
1855
  var resolveWireConstituents = (type, checker) => {
1672
- const queue = type.isUnion() ? [...type.types] : [type];
1856
+ const queue = type.isUnionType() ? [...type.getTypes()] : [type];
1673
1857
  const serializable = [];
1674
1858
  let omitted = false;
1675
1859
  let changed = false;
@@ -1681,9 +1865,9 @@ var resolveWireConstituents = (type, checker) => {
1681
1865
  continue;
1682
1866
  }
1683
1867
  const jsonType = resolveToJsonReturnType(candidate, checker);
1684
- const effective = jsonType && jsonType !== candidate ? jsonType : candidate;
1868
+ const effective = jsonType && jsonType.id !== candidate.id ? jsonType : candidate;
1685
1869
  if (effective !== candidate) changed = true;
1686
- const effectiveTypes = effective.isUnion() ? effective.types : [effective];
1870
+ const effectiveTypes = effective.isUnionType() ? effective.getTypes() : [effective];
1687
1871
  for (const effectiveType of effectiveTypes) {
1688
1872
  assertSupportedWireType(effectiveType, checker);
1689
1873
  if (isJsonOmittedValueType(effectiveType)) {
@@ -1699,15 +1883,13 @@ var resolveWireConstituents = (type, checker) => {
1699
1883
  var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1700
1884
  const expandState = state ?? { stackTypeIds: /* @__PURE__ */ new Set(), wireProjection: options?.wireProjection ?? false };
1701
1885
  const typeId = type.id;
1702
- if (typeId !== void 0) {
1703
- if (expandState.stackTypeIds.has(typeId)) {
1704
- return {
1705
- text: checker.typeToString(type),
1706
- unresolvedSymbols: collectTypeSymbolFallback(type)
1707
- };
1708
- }
1709
- expandState.stackTypeIds.add(typeId);
1886
+ if (expandState.stackTypeIds.has(typeId)) {
1887
+ return {
1888
+ text: checker.typeToString(type),
1889
+ unresolvedSymbols: collectTypeSymbolFallback(type)
1890
+ };
1710
1891
  }
1892
+ expandState.stackTypeIds.add(typeId);
1711
1893
  try {
1712
1894
  if (expandState.wireProjection) {
1713
1895
  assertSupportedWireType(type, checker);
@@ -1722,14 +1904,14 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1722
1904
  };
1723
1905
  }
1724
1906
  if (isJsonLikeType(type, checker)) return { text: "JsonValue", unresolvedSymbols: [] };
1725
- if (type.isStringLiteral()) return { text: `'${type.value.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`)}'`, unresolvedSymbols: [] };
1726
- if (type.isNumberLiteral()) return { text: String(type.value), unresolvedSymbols: [] };
1727
- if (type.flags & (ts4.TypeFlags.String | ts4.TypeFlags.Number | ts4.TypeFlags.Boolean | ts4.TypeFlags.BooleanLiteral | ts4.TypeFlags.Undefined | ts4.TypeFlags.Null | ts4.TypeFlags.Any | ts4.TypeFlags.Unknown | ts4.TypeFlags.Never | ts4.TypeFlags.Void)) {
1907
+ if (type.isStringLiteralType()) return { text: `'${type.value.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`)}'`, unresolvedSymbols: [] };
1908
+ if (type.isNumberLiteralType()) return { text: String(type.value), unresolvedSymbols: [] };
1909
+ if (type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean | TypeFlags.BooleanLiteral | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.Any | TypeFlags.Unknown | TypeFlags.Never | TypeFlags.Void)) {
1728
1910
  return { text: checker.typeToString(type), unresolvedSymbols: [] };
1729
1911
  }
1730
- if (type.isUnion()) {
1912
+ if (type.isUnionType()) {
1731
1913
  let unresolvedSymbols = [];
1732
- const expandedTypes = type.types.map((innerType) => {
1914
+ const expandedTypes = type.getTypes().map((innerType) => {
1733
1915
  const expanded = expandTypeDetailed(innerType, checker, depth + 1, expandState);
1734
1916
  unresolvedSymbols = mergeUnresolvedSymbols(unresolvedSymbols, expanded.unresolvedSymbols);
1735
1917
  return expanded.text;
@@ -1737,20 +1919,19 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1737
1919
  const uniqueTypes = [...new Set(expandedTypes)];
1738
1920
  return { text: uniqueTypes.join(" | "), unresolvedSymbols };
1739
1921
  }
1740
- if (type.isIntersection()) {
1922
+ if (type.isIntersectionType()) {
1741
1923
  let unresolvedSymbols = [];
1742
- const expandedTypes = type.types.map((innerType) => {
1924
+ const expandedTypes = type.getTypes().map((innerType) => {
1743
1925
  const expanded = expandTypeDetailed(innerType, checker, depth + 1, expandState);
1744
1926
  unresolvedSymbols = mergeUnresolvedSymbols(unresolvedSymbols, expanded.unresolvedSymbols);
1745
1927
  return expanded.text;
1746
1928
  });
1747
1929
  return { text: expandedTypes.join(" & "), unresolvedSymbols };
1748
1930
  }
1749
- if (type.flags & ts4.TypeFlags.Object) {
1750
- const objectType = type;
1751
- const tupleTarget = objectType.objectFlags & ts4.ObjectFlags.Reference ? objectType.target : objectType;
1752
- if (tupleTarget.objectFlags & ts4.ObjectFlags.Tuple) {
1753
- const typeArgs = checker.getTypeArguments(objectType);
1931
+ if (type.isObjectType()) {
1932
+ const tupleTarget = type.isTypeReference() ? type.getTarget() : type;
1933
+ if (tupleTarget.objectFlags & ObjectFlags.Tuple) {
1934
+ const typeArgs = type.isTypeReference() ? checker.getTypeArguments(type) : [];
1754
1935
  let unresolvedSymbols = [];
1755
1936
  const tupleTypes = typeArgs.map((innerType) => {
1756
1937
  const wire = expandState.wireProjection ? resolveWireConstituents(innerType, checker) : { serializable: [innerType], omitted: false };
@@ -1767,15 +1948,14 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1767
1948
  }
1768
1949
  if (expandState.wireProjection) {
1769
1950
  const jsonType = resolveToJsonReturnType(type, checker);
1770
- if (jsonType && jsonType !== type) {
1951
+ if (jsonType && jsonType.id !== type.id) {
1771
1952
  return expandTypeDetailed(jsonType, checker, depth + 1, expandState);
1772
1953
  }
1773
1954
  }
1774
- if (objectType.objectFlags & ts4.ObjectFlags.Reference) {
1775
- const refType = objectType;
1776
- const targetName = refType.target.symbol?.name ?? "";
1955
+ if (type.isTypeReference()) {
1956
+ const targetName = type.getTarget().getSymbol()?.name ?? "";
1777
1957
  if (targetName === "Array" || targetName === "ReadonlyArray") {
1778
- const typeArgs = checker.getTypeArguments(refType);
1958
+ const typeArgs = checker.getTypeArguments(type);
1779
1959
  const firstArg = typeArgs[0];
1780
1960
  if (firstArg) {
1781
1961
  const wire = expandState.wireProjection ? resolveWireConstituents(firstArg, checker) : { serializable: [firstArg], omitted: false };
@@ -1797,7 +1977,7 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1797
1977
  return { text: projected ?? checker.typeToString(type), unresolvedSymbols: [] };
1798
1978
  }
1799
1979
  }
1800
- const symbolName = type.symbol?.name || (type.aliasSymbol?.name ?? "");
1980
+ const symbolName = (type.getSymbol()?.name ?? "") || (type.getAliasSymbol()?.name ?? "");
1801
1981
  if (SKIP_EXPANSION.has(symbolName)) {
1802
1982
  const projected = expandState.wireProjection ? WIRE_PROJECTED_TYPES.get(symbolName) : void 0;
1803
1983
  return { text: projected ?? checker.typeToString(type), unresolvedSymbols: [] };
@@ -1808,12 +1988,12 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1808
1988
  const fields = [];
1809
1989
  let unresolvedSymbols = [];
1810
1990
  for (const prop of props) {
1811
- if (prop.getName().startsWith("__@")) continue;
1991
+ if (prop.name.startsWith("__@")) continue;
1812
1992
  const propType = checker.getTypeOfSymbol(prop);
1813
1993
  const wire = expandState.wireProjection ? resolveWireConstituents(propType, checker) : { serializable: [propType], omitted: false };
1814
1994
  if (wire.serializable.length === 0) continue;
1815
1995
  const literalType = getLiteralTypeFromPropertySymbol(prop, checker, depth + 1);
1816
- const isOptional = (prop.flags & ts4.SymbolFlags.Optional) !== 0 || wire.omitted;
1996
+ const isOptional = (prop.flags & SymbolFlags.Optional) !== 0 || wire.omitted;
1817
1997
  if (literalType && !wire.omitted) {
1818
1998
  fields.push(`${prop.name}${isOptional ? "?" : ""}: ${literalType}`);
1819
1999
  continue;
@@ -1828,7 +2008,7 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
1828
2008
  }
1829
2009
  for (const indexInfo of indexInfos) {
1830
2010
  const keyType = expandTypeDetailed(indexInfo.keyType, checker, depth + 1, expandState);
1831
- const wire = expandState.wireProjection ? resolveWireConstituents(indexInfo.type, checker) : { serializable: [indexInfo.type], omitted: false };
2011
+ const wire = expandState.wireProjection ? resolveWireConstituents(indexInfo.valueType, checker) : { serializable: [indexInfo.valueType], omitted: false };
1832
2012
  if (wire.serializable.length === 0) continue;
1833
2013
  const valueTexts = [];
1834
2014
  for (const serializableType of wire.serializable) {
@@ -1856,9 +2036,7 @@ ${outerIndent}}`,
1856
2036
  unresolvedSymbols: collectTypeSymbolFallback(type)
1857
2037
  };
1858
2038
  } finally {
1859
- if (typeId !== void 0) {
1860
- expandState.stackTypeIds.delete(typeId);
1861
- }
2039
+ expandState.stackTypeIds.delete(typeId);
1862
2040
  }
1863
2041
  };
1864
2042
  var expandType = (type, checker, depth = 0) => {
@@ -1900,10 +2078,10 @@ var KNOWN_GLOBAL_TYPE_NAMES = /* @__PURE__ */ new Set([
1900
2078
  "JsonPrimitive"
1901
2079
  ]);
1902
2080
  var normalizeImportPath2 = (targetFilePath) => {
1903
- const fromDir = path6.dirname(getGeneratedSocketTypesPath3());
2081
+ const fromDir = path7.dirname(getGeneratedSocketTypesPath3());
1904
2082
  const from = fromDir.replaceAll("\\", "/");
1905
2083
  const to = targetFilePath.replaceAll("\\", "/");
1906
- const normalized = path6.posix.relative(from, to).replaceAll("\\", "/");
2084
+ const normalized = path7.posix.relative(from, to).replaceAll("\\", "/");
1907
2085
  const withoutExtension = normalized.replace(/(\.d)?\.(ts|tsx|js|jsx)$/i, "");
1908
2086
  if (withoutExtension.startsWith(".")) return withoutExtension;
1909
2087
  return `./${withoutExtension}`;
@@ -1923,22 +2101,19 @@ var collectFallbackSymbolsFromTypeText = (typeText, scopeNode, checker) => {
1923
2101
  const names = new Set((typeText.match(TYPE_NAME_PATTERN) ?? []).filter((name) => !KNOWN_GLOBAL_TYPE_NAMES.has(name)));
1924
2102
  const symbolsInScope = checker.getSymbolsInScope(
1925
2103
  scopeNode,
1926
- ts5.SymbolFlags.TypeAlias | ts5.SymbolFlags.Interface | ts5.SymbolFlags.Class | ts5.SymbolFlags.Enum | ts5.SymbolFlags.Alias
2104
+ SymbolFlags2.TypeAlias | SymbolFlags2.Interface | SymbolFlags2.Class | SymbolFlags2.Enum | SymbolFlags2.Alias
1927
2105
  );
1928
2106
  const unresolvedSymbols = [];
1929
2107
  for (const name of names) {
1930
2108
  const localSymbol = symbolsInScope.find((symbol) => symbol.name === name);
1931
2109
  if (!localSymbol) continue;
1932
- const targetSymbol = (localSymbol.flags & ts5.SymbolFlags.Alias) === 0 ? localSymbol : checker.getAliasedSymbol(localSymbol);
1933
- const declaration = targetSymbol.declarations?.[0];
1934
- if (!declaration) {
2110
+ const targetSymbol = (localSymbol.flags & SymbolFlags2.Alias) === 0 ? localSymbol : checker.getAliasedSymbol(localSymbol);
2111
+ if (targetSymbol.declarations.length === 0) {
1935
2112
  unresolvedSymbols.push({ name });
1936
2113
  continue;
1937
2114
  }
1938
- const sourceFile = declaration.getSourceFile().fileName;
1939
- if (!sourceFile || sourceFile.includes("/node_modules/") || sourceFile.includes("\\node_modules\\")) {
1940
- continue;
1941
- }
2115
+ const sourceFile = getDeclarationFileName(targetSymbol);
2116
+ if (!sourceFile) continue;
1942
2117
  unresolvedSymbols.push({
1943
2118
  name,
1944
2119
  sourceFile,
@@ -1949,13 +2124,13 @@ var collectFallbackSymbolsFromTypeText = (typeText, scopeNode, checker) => {
1949
2124
  };
1950
2125
  var findInterface = (sourceFile, name) => {
1951
2126
  for (const stmt of sourceFile.statements) {
1952
- if (ts5.isInterfaceDeclaration(stmt) && stmt.name.text === name) return stmt;
2127
+ if (isInterfaceDeclaration2(stmt) && stmt.name.text === name) return stmt;
1953
2128
  }
1954
2129
  return null;
1955
2130
  };
1956
2131
  var getInterfacePropertyType = (iface, propertyName, checker) => {
1957
2132
  for (const member of iface.members) {
1958
- if (ts5.isPropertySignature(member) && ts5.isIdentifier(member.name) && member.name.text === propertyName && member.type) {
2133
+ if (isPropertySignatureDeclaration2(member) && isIdentifier5(member.name) && member.name.text === propertyName && member.type) {
1959
2134
  return checker.getTypeFromTypeNode(member.type);
1960
2135
  }
1961
2136
  }
@@ -1963,14 +2138,14 @@ var getInterfacePropertyType = (iface, propertyName, checker) => {
1963
2138
  };
1964
2139
  var findMainFunction = (sourceFile) => {
1965
2140
  for (const stmt of sourceFile.statements) {
1966
- if (ts5.isVariableStatement(stmt)) {
2141
+ if (isVariableStatement2(stmt)) {
1967
2142
  for (const decl of stmt.declarationList.declarations) {
1968
- if (ts5.isIdentifier(decl.name) && decl.name.text === "main" && decl.initializer && (ts5.isArrowFunction(decl.initializer) || ts5.isFunctionExpression(decl.initializer))) {
2143
+ if (isIdentifier5(decl.name) && decl.name.text === "main" && decl.initializer && (isArrowFunction(decl.initializer) || isFunctionExpression(decl.initializer))) {
1969
2144
  return decl.initializer;
1970
2145
  }
1971
2146
  }
1972
2147
  }
1973
- if (ts5.isFunctionDeclaration(stmt) && stmt.name?.text === "main") {
2148
+ if (isFunctionDeclaration2(stmt) && stmt.name?.text === "main") {
1974
2149
  return stmt;
1975
2150
  }
1976
2151
  }
@@ -1980,7 +2155,7 @@ var collectReturnObjectTypeDetails = (funcNode, checker) => {
1980
2155
  const types = [];
1981
2156
  let unresolvedSymbols = [];
1982
2157
  const visit = (node) => {
1983
- if (ts5.isReturnStatement(node) && node.expression && ts5.isObjectLiteralExpression(node.expression)) {
2158
+ if (isReturnStatement(node) && node.expression && isObjectLiteralExpression2(node.expression)) {
1984
2159
  const type = checker.getTypeAtLocation(node.expression);
1985
2160
  const expanded = expandTypeDetailed(type, checker, 0, void 0, { wireProjection: true });
1986
2161
  types.push(expanded.text);
@@ -1990,11 +2165,11 @@ var collectReturnObjectTypeDetails = (funcNode, checker) => {
1990
2165
  collectFallbackSymbolsFromTypeText(expanded.text, node.expression, checker)
1991
2166
  );
1992
2167
  }
1993
- if (!ts5.isArrowFunction(node) && !ts5.isFunctionExpression(node) && !ts5.isFunctionDeclaration(node)) {
1994
- ts5.forEachChild(node, visit);
2168
+ if (!isArrowFunction(node) && !isFunctionExpression(node) && !isFunctionDeclaration2(node)) {
2169
+ node.forEachChild(visit);
1995
2170
  }
1996
2171
  };
1997
- ts5.forEachChild(funcNode, visit);
2172
+ funcNode.forEachChild(visit);
1998
2173
  return { text: unionTypes(types), unresolvedSymbols };
1999
2174
  };
2000
2175
  var STREAM_EMIT_NAMES = /* @__PURE__ */ new Set(["stream", "broadcastStream", "streamTo"]);
@@ -2002,7 +2177,7 @@ var collectStreamCallPayloadTypeDetails = (funcNode, checker) => {
2002
2177
  const types = [];
2003
2178
  let unresolvedSymbols = [];
2004
2179
  const visit = (node) => {
2005
- if (ts5.isCallExpression(node) && ts5.isIdentifier(node.expression) && STREAM_EMIT_NAMES.has(node.expression.text)) {
2180
+ if (isCallExpression(node) && isIdentifier5(node.expression) && STREAM_EMIT_NAMES.has(node.expression.text)) {
2006
2181
  const callName = node.expression.text;
2007
2182
  const payloadIndex = callName === "streamTo" ? 1 : 0;
2008
2183
  const payloadArg = node.arguments[payloadIndex];
@@ -2020,11 +2195,11 @@ var collectStreamCallPayloadTypeDetails = (funcNode, checker) => {
2020
2195
  );
2021
2196
  }
2022
2197
  }
2023
- if (!ts5.isArrowFunction(node) && !ts5.isFunctionExpression(node) && !ts5.isFunctionDeclaration(node)) {
2024
- ts5.forEachChild(node, visit);
2198
+ if (!isArrowFunction(node) && !isFunctionExpression(node) && !isFunctionDeclaration2(node)) {
2199
+ node.forEachChild(visit);
2025
2200
  }
2026
2201
  };
2027
- ts5.forEachChild(funcNode, visit);
2202
+ funcNode.forEachChild(visit);
2028
2203
  return { text: unionTypes(types), unresolvedSymbols };
2029
2204
  };
2030
2205
  var unionTypes = (types) => {
@@ -2038,15 +2213,13 @@ var UnsupportedTransportInputError = class extends Error {
2038
2213
  }
2039
2214
  };
2040
2215
  var assertTransportInputIsWireSafe = (typeText, filePath) => {
2041
- const sourceFile = ts5.createSourceFile(
2216
+ const sourceFile = parseSourceText(
2042
2217
  "__luckystack_input_check.ts",
2043
2218
  `type __LuckyStackInput = ${typeText};`,
2044
- ts5.ScriptTarget.Latest,
2045
- true,
2046
- ts5.ScriptKind.TS
2219
+ ScriptKind2.TS
2047
2220
  );
2048
2221
  const containsDate = (node) => {
2049
- if (ts5.isTypeReferenceNode(node) && ts5.isIdentifier(node.typeName) && node.typeName.text === "Date") {
2222
+ if (isTypeReferenceNode3(node) && isIdentifier5(node.typeName) && node.typeName.text === "Date") {
2050
2223
  return true;
2051
2224
  }
2052
2225
  return node.getChildren(sourceFile).some((child) => containsDate(child));
@@ -2060,13 +2233,12 @@ var getInputTypeDetailsFromFile = (filePath) => {
2060
2233
  const DEFAULT = "{ }";
2061
2234
  recordExtractionOutcome({ filePath, kind: "api", field: "input", error: null });
2062
2235
  try {
2063
- const program = getServerProgram();
2236
+ const { program, checker } = getServerProgram();
2064
2237
  const sourceFile = program.getSourceFile(filePath);
2065
2238
  if (!sourceFile) {
2066
2239
  console.warn(`[TypeMapGenerator] getSourceFile miss for ${filePath} \u2014 input types will default to { }`);
2067
2240
  return { text: DEFAULT, unresolvedSymbols: [] };
2068
2241
  }
2069
- const checker = program.getTypeChecker();
2070
2242
  const iface = findInterface(sourceFile, "ApiParams");
2071
2243
  if (!iface) return { text: DEFAULT, unresolvedSymbols: [] };
2072
2244
  const dataType = getInterfacePropertyType(iface, "data", checker);
@@ -2092,9 +2264,9 @@ var extractDeclaredStreamTypeFromApiParams = (sourceFile, checker) => {
2092
2264
  let result = null;
2093
2265
  const visit = (node) => {
2094
2266
  if (result) return;
2095
- if (ts5.isInterfaceDeclaration(node) && node.name.text.endsWith("Params")) {
2267
+ if (isInterfaceDeclaration2(node) && node.name.text.endsWith("Params")) {
2096
2268
  for (const member of node.members) {
2097
- if (ts5.isPropertySignature(member) && ts5.isIdentifier(member.name) && member.name.text === "stream" && member.type && ts5.isTypeReferenceNode(member.type) && ts5.isIdentifier(member.type.typeName) && STREAM_EMITTER_TYPE_NAMES.has(member.type.typeName.text)) {
2269
+ if (isPropertySignatureDeclaration2(member) && isIdentifier5(member.name) && member.name.text === "stream" && member.type && isTypeReferenceNode3(member.type) && isIdentifier5(member.type.typeName) && STREAM_EMITTER_TYPE_NAMES.has(member.type.typeName.text)) {
2098
2270
  const typeArg = member.type.typeArguments?.[0];
2099
2271
  if (typeArg) {
2100
2272
  const argType = checker.getNonNullableType(checker.getTypeFromTypeNode(typeArg));
@@ -2107,7 +2279,7 @@ var extractDeclaredStreamTypeFromApiParams = (sourceFile, checker) => {
2107
2279
  }
2108
2280
  }
2109
2281
  }
2110
- ts5.forEachChild(node, visit);
2282
+ node.forEachChild(visit);
2111
2283
  };
2112
2284
  visit(sourceFile);
2113
2285
  return result;
@@ -2116,10 +2288,9 @@ var getApiStreamPayloadTypeDetailsFromFile = (filePath) => {
2116
2288
  const DEFAULT = "never";
2117
2289
  recordExtractionOutcome({ filePath, kind: "api", field: "stream", error: null });
2118
2290
  try {
2119
- const program = getServerProgram();
2291
+ const { program, checker } = getServerProgram();
2120
2292
  const sourceFile = program.getSourceFile(filePath);
2121
2293
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2122
- const checker = program.getTypeChecker();
2123
2294
  const mainFn = findMainFunction(sourceFile);
2124
2295
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2125
2296
  const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
@@ -2138,10 +2309,9 @@ var getOutputTypeDetailsFromFile = (filePath) => {
2138
2309
  const DEFAULT = "{ status: string }";
2139
2310
  recordExtractionOutcome({ filePath, kind: "api", field: "output", error: null });
2140
2311
  try {
2141
- const program = getServerProgram();
2312
+ const { program, checker } = getServerProgram();
2142
2313
  const sourceFile = program.getSourceFile(filePath);
2143
2314
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2144
- const checker = program.getTypeChecker();
2145
2315
  const mainFn = findMainFunction(sourceFile);
2146
2316
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2147
2317
  const details = collectReturnObjectTypeDetails(mainFn, checker);
@@ -2160,10 +2330,9 @@ var getSyncClientDataTypeDetailsFromFile = (filePath) => {
2160
2330
  const DEFAULT = "{ }";
2161
2331
  recordExtractionOutcome({ filePath, kind: "sync", field: "clientInput", error: null });
2162
2332
  try {
2163
- const program = getServerProgram();
2333
+ const { program, checker } = getServerProgram();
2164
2334
  const sourceFile = program.getSourceFile(filePath);
2165
2335
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2166
- const checker = program.getTypeChecker();
2167
2336
  const iface = findInterface(sourceFile, "SyncParams");
2168
2337
  if (!iface) return { text: DEFAULT, unresolvedSymbols: [] };
2169
2338
  const dataType = getInterfacePropertyType(iface, "clientInput", checker) ?? getInterfacePropertyType(iface, "clientData", checker);
@@ -2182,10 +2351,9 @@ var getSyncServerStreamPayloadTypeDetailsFromFile = (filePath) => {
2182
2351
  const DEFAULT = "never";
2183
2352
  recordExtractionOutcome({ filePath, kind: "sync", field: "serverStream", error: null });
2184
2353
  try {
2185
- const program = getServerProgram();
2354
+ const { program, checker } = getServerProgram();
2186
2355
  const sourceFile = program.getSourceFile(filePath);
2187
2356
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2188
- const checker = program.getTypeChecker();
2189
2357
  const mainFn = findMainFunction(sourceFile);
2190
2358
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2191
2359
  const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
@@ -2201,10 +2369,9 @@ var getSyncServerOutputTypeDetailsFromFile = (filePath) => {
2201
2369
  const DEFAULT = "{ status: string }";
2202
2370
  recordExtractionOutcome({ filePath, kind: "sync", field: "serverOutput", error: null });
2203
2371
  try {
2204
- const program = getServerProgram();
2372
+ const { program, checker } = getServerProgram();
2205
2373
  const sourceFile = program.getSourceFile(filePath);
2206
2374
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2207
- const checker = program.getTypeChecker();
2208
2375
  const mainFn = findMainFunction(sourceFile);
2209
2376
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2210
2377
  const details = collectReturnObjectTypeDetails(mainFn, checker);
@@ -2220,10 +2387,9 @@ var getSyncClientStreamPayloadTypeDetailsFromFile = (filePath) => {
2220
2387
  const DEFAULT = "never";
2221
2388
  recordExtractionOutcome({ filePath, kind: "sync", field: "clientStream", error: null });
2222
2389
  try {
2223
- const program = getServerProgram();
2390
+ const { program, checker } = getServerProgram();
2224
2391
  const sourceFile = program.getSourceFile(filePath);
2225
2392
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2226
- const checker = program.getTypeChecker();
2227
2393
  const mainFn = findMainFunction(sourceFile);
2228
2394
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2229
2395
  const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
@@ -2239,10 +2405,9 @@ var getSyncClientOutputTypeDetailsFromFile = (filePath) => {
2239
2405
  const DEFAULT = "{ }";
2240
2406
  recordExtractionOutcome({ filePath, kind: "sync", field: "clientOutput", error: null });
2241
2407
  try {
2242
- const program = getServerProgram();
2408
+ const { program, checker } = getServerProgram();
2243
2409
  const sourceFile = program.getSourceFile(filePath);
2244
2410
  if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
2245
- const checker = program.getTypeChecker();
2246
2411
  const mainFn = findMainFunction(sourceFile);
2247
2412
  if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
2248
2413
  const details = collectReturnObjectTypeDetails(mainFn, checker);
@@ -2256,19 +2421,48 @@ var getSyncClientOutputTypeDetailsFromFile = (filePath) => {
2256
2421
  };
2257
2422
 
2258
2423
  // src/typeMap/functionsMeta.ts
2259
- import * as ts7 from "typescript";
2260
- import fs6 from "fs";
2261
- import path9 from "path";
2424
+ import fs7 from "fs";
2425
+ import path10 from "path";
2426
+ import {
2427
+ createScanner,
2428
+ LanguageVariant,
2429
+ SyntaxKind as SyntaxKind5
2430
+ } from "typescript-7-api/ast";
2431
+ import {
2432
+ isArrowFunction as isArrowFunction2,
2433
+ isClassDeclaration as isClassDeclaration3,
2434
+ isEnumDeclaration as isEnumDeclaration3,
2435
+ isExportAssignment,
2436
+ isExportDeclaration,
2437
+ isFunctionDeclaration as isFunctionDeclaration3,
2438
+ isFunctionExpression as isFunctionExpression2,
2439
+ isIdentifier as isIdentifier6,
2440
+ isInterfaceDeclaration as isInterfaceDeclaration4,
2441
+ isNamedExports,
2442
+ isStringLiteral as isStringLiteral5,
2443
+ isTypeAliasDeclaration as isTypeAliasDeclaration4,
2444
+ isVariableStatement as isVariableStatement3
2445
+ } from "typescript-7-api/ast/is";
2262
2446
 
2263
2447
  // src/typeMap/typeContext.ts
2264
- import * as ts6 from "typescript";
2265
- import path7 from "path";
2448
+ import path8 from "path";
2449
+ import { SyntaxKind as SyntaxKind4 } from "typescript-7-api/ast";
2450
+ import {
2451
+ isClassDeclaration as isClassDeclaration2,
2452
+ isEnumDeclaration as isEnumDeclaration2,
2453
+ isImportDeclaration as isImportDeclaration2,
2454
+ isInterfaceDeclaration as isInterfaceDeclaration3,
2455
+ isNamedImports as isNamedImports2,
2456
+ isNamespaceImport as isNamespaceImport2,
2457
+ isStringLiteral as isStringLiteral4,
2458
+ isTypeAliasDeclaration as isTypeAliasDeclaration3
2459
+ } from "typescript-7-api/ast/is";
2266
2460
  import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath4 } from "@luckystack/core";
2267
2461
  var toGeneratedImportPath = (source, filePath) => {
2268
2462
  if (!source.startsWith(".")) return source;
2269
- const outputDir = path7.dirname(getGeneratedSocketTypesPath4());
2270
- const absoluteSource = path7.resolve(path7.dirname(filePath), source);
2271
- let relPath = path7.relative(outputDir, absoluteSource).replaceAll("\\", "/");
2463
+ const outputDir = path8.dirname(getGeneratedSocketTypesPath4());
2464
+ const absoluteSource = path8.resolve(path8.dirname(filePath), source);
2465
+ let relPath = path8.relative(outputDir, absoluteSource).replaceAll("\\", "/");
2272
2466
  relPath = relPath.replace(/\.tsx?$/, "");
2273
2467
  if (!relPath.startsWith(".")) relPath = `./${relPath}`;
2274
2468
  return relPath;
@@ -2276,23 +2470,18 @@ var toGeneratedImportPath = (source, filePath) => {
2276
2470
  var parseFileTypeContext = (content) => {
2277
2471
  const availableExports = /* @__PURE__ */ new Set();
2278
2472
  const fileImports = /* @__PURE__ */ new Map();
2279
- const sourceFile = ts6.createSourceFile(
2280
- "__temp__.ts",
2281
- content,
2282
- ts6.ScriptTarget.Latest,
2283
- true
2284
- );
2473
+ const sourceFile = parseSourceText("__temp__.ts", content);
2285
2474
  for (const statement of sourceFile.statements) {
2286
- if (ts6.isInterfaceDeclaration(statement) || ts6.isTypeAliasDeclaration(statement) || ts6.isClassDeclaration(statement) || ts6.isEnumDeclaration(statement)) {
2287
- const hasExport = statement.modifiers?.some((m) => m.kind === ts6.SyntaxKind.ExportKeyword);
2475
+ if (isInterfaceDeclaration3(statement) || isTypeAliasDeclaration3(statement) || isClassDeclaration2(statement) || isEnumDeclaration2(statement)) {
2476
+ const hasExport = statement.modifiers?.some((m) => m.kind === SyntaxKind4.ExportKeyword);
2288
2477
  if (hasExport && statement.name) {
2289
2478
  availableExports.add(statement.name.text);
2290
2479
  }
2291
2480
  continue;
2292
2481
  }
2293
- if (!ts6.isImportDeclaration(statement)) continue;
2482
+ if (!isImportDeclaration2(statement)) continue;
2294
2483
  const moduleSpecifier = statement.moduleSpecifier;
2295
- if (!ts6.isStringLiteral(moduleSpecifier)) continue;
2484
+ if (!isStringLiteral4(moduleSpecifier)) continue;
2296
2485
  const source = moduleSpecifier.text;
2297
2486
  const importClause = statement.importClause;
2298
2487
  if (!importClause) continue;
@@ -2301,11 +2490,11 @@ var parseFileTypeContext = (content) => {
2301
2490
  }
2302
2491
  const namedBindings = importClause.namedBindings;
2303
2492
  if (!namedBindings) continue;
2304
- if (ts6.isNamespaceImport(namedBindings)) {
2493
+ if (isNamespaceImport2(namedBindings)) {
2305
2494
  fileImports.set(namedBindings.name.text, { source, isDefault: true });
2306
2495
  continue;
2307
2496
  }
2308
- if (ts6.isNamedImports(namedBindings)) {
2497
+ if (isNamedImports2(namedBindings)) {
2309
2498
  for (const specifier of namedBindings.elements) {
2310
2499
  const localName = specifier.name.text;
2311
2500
  const originalName = specifier.propertyName?.text ?? localName;
@@ -2355,11 +2544,11 @@ var sanitizeTypeAndCollectImports = ({
2355
2544
  import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath5, ROOT_DIR as ROOT_DIR5 } from "@luckystack/core";
2356
2545
 
2357
2546
  // src/functionRegistry.ts
2358
- import fs5 from "fs";
2359
- import path8 from "path";
2547
+ import fs6 from "fs";
2548
+ import path9 from "path";
2360
2549
  import { ROOT_DIR as ROOT_DIR4, getServerFunctionDirs, isTestFile as isTestFile2, isTestDirectory as isTestDirectory2 } from "@luckystack/core";
2361
2550
  var normalizePath2 = (value) => value.replaceAll("\\", "/");
2362
- var toWorkspaceRelative = (absolutePath) => normalizePath2(path8.relative(ROOT_DIR4, absolutePath));
2551
+ var toWorkspaceRelative = (absolutePath) => normalizePath2(path9.relative(ROOT_DIR4, absolutePath));
2363
2552
  var formatFunctionKeyPath = (keyPath) => keyPath.join(".");
2364
2553
  var functionModuleFileName = (keyPath) => {
2365
2554
  const fileName = keyPath.at(-1);
@@ -2371,12 +2560,12 @@ var functionModuleFileName = (keyPath) => {
2371
2560
  var formatFunctionKeyConflict = (keyPath, firstSourcePath, secondSourcePath) => `[function-injection] Conflict at \`functions.${formatFunctionKeyPath(keyPath)}\`: defined in both \`${firstSourcePath}\` and \`${secondSourcePath}\`. Delete one \u2014 \`shared/\` is the canonical location for framework re-exports.`;
2372
2561
  var formatFunctionNamespaceConflict = (moduleKeyPath, moduleSourcePath, nestedKeyPath, nestedSourcePath) => `[function-injection] Conflict at \`functions.${formatFunctionKeyPath(moduleKeyPath)}\`: \`${moduleSourcePath}\` defines it as a module, but \`${nestedSourcePath}\` nests \`functions.${formatFunctionKeyPath(nestedKeyPath)}\` underneath it. Rename one \u2014 a key cannot be both a module and a namespace.`;
2373
2562
  var walkFunctionRoot = (dir, rootDir, basePath, collected) => {
2374
- const entries = fs5.readdirSync(dir).toSorted();
2563
+ const entries = fs6.readdirSync(dir).toSorted();
2375
2564
  for (const entry of entries) {
2376
2565
  if (entry === "node_modules") continue;
2377
- const fullPath = path8.join(dir, entry);
2566
+ const fullPath = path9.join(dir, entry);
2378
2567
  if (getRoutingRules().ignore(toWorkspaceRelative(fullPath))) continue;
2379
- if (fs5.statSync(fullPath).isDirectory()) {
2568
+ if (fs6.statSync(fullPath).isDirectory()) {
2380
2569
  if (isTestDirectory2(entry)) continue;
2381
2570
  walkFunctionRoot(fullPath, rootDir, [...basePath, entry], collected);
2382
2571
  continue;
@@ -2419,7 +2608,7 @@ var collectFunctionModules = (options = {}) => {
2419
2608
  onConflict(message);
2420
2609
  };
2421
2610
  for (const root of functionRoots) {
2422
- if (!fs5.existsSync(root)) continue;
2611
+ if (!fs6.existsSync(root)) continue;
2423
2612
  const fromThisRoot = [];
2424
2613
  walkFunctionRoot(root, root, [], fromThisRoot);
2425
2614
  for (const module of fromThisRoot) {
@@ -2493,17 +2682,16 @@ var stripDefaultValues = (params) => {
2493
2682
  return params.replaceAll(/\s*=(?!>)[^,)]+/g, "");
2494
2683
  };
2495
2684
  var stripLineComments = (value) => {
2496
- const scanner = ts7.createScanner(
2497
- ts7.ScriptTarget.Latest,
2685
+ const scanner = createScanner(
2498
2686
  /* skipTrivia */
2499
2687
  false,
2500
- ts7.LanguageVariant.Standard,
2688
+ LanguageVariant.Standard,
2501
2689
  value
2502
2690
  );
2503
2691
  let result = "";
2504
2692
  let token = scanner.scan();
2505
- while (token !== ts7.SyntaxKind.EndOfFileToken) {
2506
- result += token === ts7.SyntaxKind.SingleLineCommentTrivia ? " " : scanner.getTokenText();
2693
+ while (token !== SyntaxKind5.EndOfFile) {
2694
+ result += token === SyntaxKind5.SingleLineCommentTrivia ? " " : scanner.getTokenText();
2507
2695
  token = scanner.scan();
2508
2696
  }
2509
2697
  return result;
@@ -2516,9 +2704,9 @@ var simplifyInferredType = (value) => {
2516
2704
  if (/\bRedis\b/.test(value)) return "Redis";
2517
2705
  return value;
2518
2706
  };
2519
- var getGeneratedFileDir = () => path9.dirname(getGeneratedSocketTypesPath5());
2707
+ var getGeneratedFileDir = () => path10.dirname(getGeneratedSocketTypesPath5());
2520
2708
  var sourceModuleSpecifier = (sourceFilePath) => {
2521
- const relative = path9.relative(getGeneratedFileDir(), sourceFilePath).replaceAll("\\", "/").replace(/\.tsx?$/i, "");
2709
+ const relative = path10.relative(getGeneratedFileDir(), sourceFilePath).replaceAll("\\", "/").replace(/\.tsx?$/i, "");
2522
2710
  return relative.startsWith(".") ? relative : `./${relative}`;
2523
2711
  };
2524
2712
  var portableInferredValueType = (inferred, sourceFilePath, exportName) => {
@@ -2529,16 +2717,16 @@ var relativizeModuleSpecifier = (specifier, sourceFilePath) => {
2529
2717
  if (!specifier.startsWith("./") && !specifier.startsWith("../")) {
2530
2718
  return specifier;
2531
2719
  }
2532
- const absolute = path9.resolve(path9.dirname(sourceFilePath), specifier);
2533
- const rel = path9.relative(getGeneratedFileDir(), absolute);
2534
- const normalized = rel.split(path9.sep).join("/");
2720
+ const absolute = path10.resolve(path10.dirname(sourceFilePath), specifier);
2721
+ const rel = path10.relative(getGeneratedFileDir(), absolute);
2722
+ const normalized = rel.split(path10.sep).join("/");
2535
2723
  return normalized.startsWith(".") ? normalized : `./${normalized}`;
2536
2724
  };
2537
2725
  var findProgramVariableDeclaration = (sourceFile, exportName) => {
2538
2726
  for (const statement of sourceFile.statements) {
2539
- if (!ts7.isVariableStatement(statement)) continue;
2727
+ if (!isVariableStatement3(statement)) continue;
2540
2728
  for (const declaration of statement.declarationList.declarations) {
2541
- if (ts7.isIdentifier(declaration.name) && declaration.name.text === exportName) {
2729
+ if (isIdentifier6(declaration.name) && declaration.name.text === exportName) {
2542
2730
  return declaration;
2543
2731
  }
2544
2732
  }
@@ -2547,10 +2735,10 @@ var findProgramVariableDeclaration = (sourceFile, exportName) => {
2547
2735
  };
2548
2736
  var findProgramTypeDeclaration = (sourceFile, typeName) => {
2549
2737
  for (const statement of sourceFile.statements) {
2550
- if (ts7.isInterfaceDeclaration(statement) && statement.name.text === typeName) return statement;
2551
- if (ts7.isTypeAliasDeclaration(statement) && statement.name.text === typeName) return statement;
2552
- if (ts7.isClassDeclaration(statement) && statement.name?.text === typeName) return statement;
2553
- if (ts7.isEnumDeclaration(statement) && statement.name.text === typeName) return statement;
2738
+ if (isInterfaceDeclaration4(statement) && statement.name.text === typeName) return statement;
2739
+ if (isTypeAliasDeclaration4(statement) && statement.name.text === typeName) return statement;
2740
+ if (isClassDeclaration3(statement) && statement.name?.text === typeName) return statement;
2741
+ if (isEnumDeclaration3(statement) && statement.name.text === typeName) return statement;
2554
2742
  }
2555
2743
  return null;
2556
2744
  };
@@ -2567,7 +2755,7 @@ var resolveLocalExportedTypes = ({
2567
2755
  if (!hasReference) continue;
2568
2756
  const declaration = findProgramTypeDeclaration(programSource, exportName);
2569
2757
  if (!declaration) continue;
2570
- const declarationNode = ts7.isClassDeclaration(declaration) ? declaration.name ?? declaration : ts7.isTypeAliasDeclaration(declaration) ? declaration.type : declaration;
2758
+ const declarationNode = isClassDeclaration3(declaration) ? declaration.name ?? declaration : isTypeAliasDeclaration4(declaration) ? declaration.type : declaration;
2571
2759
  const declarationType = checker.getTypeAtLocation(declarationNode);
2572
2760
  const expanded = normalizeInlineType(expandType(declarationType, checker));
2573
2761
  resolved = resolved.replaceAll(new RegExp(String.raw`\b${exportName}\b`, "g"), expanded);
@@ -2576,9 +2764,9 @@ var resolveLocalExportedTypes = ({
2576
2764
  };
2577
2765
  var findSourceVariableDeclaration = (sourceFile, exportName) => {
2578
2766
  for (const statement of sourceFile.statements) {
2579
- if (!ts7.isVariableStatement(statement)) continue;
2767
+ if (!isVariableStatement3(statement)) continue;
2580
2768
  for (const declaration of statement.declarationList.declarations) {
2581
- if (ts7.isIdentifier(declaration.name) && declaration.name.text === exportName) {
2769
+ if (isIdentifier6(declaration.name) && declaration.name.text === exportName) {
2582
2770
  return declaration;
2583
2771
  }
2584
2772
  }
@@ -2596,8 +2784,8 @@ var inferValueTypeForExport = ({
2596
2784
  checker,
2597
2785
  programSource
2598
2786
  }) => {
2599
- const resolvedChecker = checker ?? getServerProgram().getTypeChecker();
2600
- const resolvedSource = programSource ?? getServerProgram().getSourceFile(filePath);
2787
+ const resolvedChecker = checker ?? getServerProgram().checker;
2788
+ const resolvedSource = programSource ?? getServerProgram().program.getSourceFile(filePath);
2601
2789
  if (declaration.type) {
2602
2790
  const rawType = normalizeInlineType(rawContent.slice(declaration.type.pos, declaration.type.end).trim());
2603
2791
  const localResolvedType = resolvedSource ? resolveLocalExportedTypes({
@@ -2646,7 +2834,7 @@ var extractSignatureFromNode = (node, rawContent, filePath, availableExports, fi
2646
2834
  knownGenerics.add(typeParam.name.text);
2647
2835
  }
2648
2836
  }
2649
- const isAsync = node.modifiers?.some((m) => m.kind === ts7.SyntaxKind.AsyncKeyword) ?? false;
2837
+ const isAsync = node.modifiers?.some((m) => m.kind === SyntaxKind5.AsyncKeyword) ?? false;
2650
2838
  const genericsClause = node.typeParameters ? `<${normalizeInlineType(rawContent.slice(node.typeParameters.pos, node.typeParameters.end))}>` : "";
2651
2839
  const rawParams = node.parameters.map((p) => normalizeInlineType(rawContent.slice(p.pos, p.end).trim())).join(", ");
2652
2840
  const cleanParams = normalizeInlineType(stripDefaultValues(`(${rawParams})`));
@@ -2689,38 +2877,38 @@ var extractSignatureFromNode = (node, rawContent, filePath, availableExports, fi
2689
2877
  };
2690
2878
  var findSignatureForExport = (name, sourceFile, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource) => {
2691
2879
  for (const statement of sourceFile.statements) {
2692
- if (ts7.isVariableStatement(statement)) {
2880
+ if (isVariableStatement3(statement)) {
2693
2881
  for (const decl of statement.declarationList.declarations) {
2694
- if (!ts7.isIdentifier(decl.name) || decl.name.text !== name || !decl.initializer) continue;
2695
- if (ts7.isArrowFunction(decl.initializer) || ts7.isFunctionExpression(decl.initializer)) {
2882
+ if (!isIdentifier6(decl.name) || decl.name.text !== name || !decl.initializer) continue;
2883
+ if (isArrowFunction2(decl.initializer) || isFunctionExpression2(decl.initializer)) {
2696
2884
  return extractSignatureFromNode(decl.initializer, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource);
2697
2885
  }
2698
2886
  }
2699
2887
  }
2700
- if (ts7.isFunctionDeclaration(statement) && statement.name?.text === name) {
2888
+ if (isFunctionDeclaration3(statement) && statement.name?.text === name) {
2701
2889
  return extractSignatureFromNode(statement, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource);
2702
2890
  }
2703
2891
  }
2704
2892
  return "any";
2705
2893
  };
2894
+ var hasExportModifier = (statement) => (isVariableStatement3(statement) || isFunctionDeclaration3(statement)) && (statement.modifiers?.some((m) => m.kind === SyntaxKind5.ExportKeyword) ?? false);
2706
2895
  var parseFunctionFile = (fullPath, collectors) => {
2707
2896
  try {
2708
- const rawContent = fs6.readFileSync(fullPath, "utf8");
2709
- const sourceFile = ts7.createSourceFile(fullPath, rawContent, ts7.ScriptTarget.Latest, true);
2897
+ const rawContent = fs7.readFileSync(fullPath, "utf8");
2898
+ const sourceFile = parseSourceText(fullPath, rawContent);
2710
2899
  const { availableExports, fileImports } = parseFileTypeContext(rawContent);
2711
- const program = getServerProgram();
2712
- const checker = program.getTypeChecker();
2900
+ const { program, checker } = getServerProgram();
2713
2901
  const programSource = program.getSourceFile(fullPath);
2714
2902
  const exports = /* @__PURE__ */ new Map();
2715
2903
  let defaultExportName = null;
2716
2904
  let wildcardReExport = null;
2717
2905
  for (const statement of sourceFile.statements) {
2718
- const hasExport = statement.modifiers?.some((m) => m.kind === ts7.SyntaxKind.ExportKeyword);
2719
- if (ts7.isVariableStatement(statement) && hasExport) {
2906
+ const hasExport = hasExportModifier(statement);
2907
+ if (isVariableStatement3(statement) && hasExport) {
2720
2908
  for (const decl of statement.declarationList.declarations) {
2721
- if (ts7.isIdentifier(decl.name)) {
2909
+ if (isIdentifier6(decl.name)) {
2722
2910
  const exportName = decl.name.text;
2723
- if (decl.initializer && (ts7.isArrowFunction(decl.initializer) || ts7.isFunctionExpression(decl.initializer))) {
2911
+ if (decl.initializer && (isArrowFunction2(decl.initializer) || isFunctionExpression2(decl.initializer))) {
2724
2912
  exports.set(exportName, findSignatureForExport(exportName, sourceFile, rawContent, fullPath, availableExports, fileImports, collectors, checker, programSource ?? void 0));
2725
2913
  continue;
2726
2914
  }
@@ -2738,11 +2926,11 @@ var parseFunctionFile = (fullPath, collectors) => {
2738
2926
  }
2739
2927
  }
2740
2928
  }
2741
- if (ts7.isFunctionDeclaration(statement) && hasExport && statement.name) {
2929
+ if (isFunctionDeclaration3(statement) && hasExport && statement.name) {
2742
2930
  exports.set(statement.name.text, findSignatureForExport(statement.name.text, sourceFile, rawContent, fullPath, availableExports, fileImports, collectors, checker, programSource ?? void 0));
2743
2931
  }
2744
- if (ts7.isExportDeclaration(statement) && statement.exportClause && ts7.isNamedExports(statement.exportClause)) {
2745
- const moduleSpecifier = statement.moduleSpecifier && ts7.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : null;
2932
+ if (isExportDeclaration(statement) && statement.exportClause && isNamedExports(statement.exportClause)) {
2933
+ const moduleSpecifier = statement.moduleSpecifier && isStringLiteral5(statement.moduleSpecifier) ? statement.moduleSpecifier.text : null;
2746
2934
  for (const specifier of statement.exportClause.elements) {
2747
2935
  const exportName = specifier.name.text;
2748
2936
  const originalName = specifier.propertyName ? specifier.propertyName.text : exportName;
@@ -2757,7 +2945,7 @@ var parseFunctionFile = (fullPath, collectors) => {
2757
2945
  continue;
2758
2946
  }
2759
2947
  const exportDeclaration = findSourceVariableDeclaration(sourceFile, originalName);
2760
- if (exportDeclaration && ts7.isIdentifier(exportDeclaration.name)) {
2948
+ if (exportDeclaration && isIdentifier6(exportDeclaration.name)) {
2761
2949
  exports.set(exportName, inferValueTypeForExport({
2762
2950
  exportName: originalName,
2763
2951
  declaration: exportDeclaration,
@@ -2774,10 +2962,10 @@ var parseFunctionFile = (fullPath, collectors) => {
2774
2962
  exports.set(exportName, "any");
2775
2963
  }
2776
2964
  }
2777
- if (ts7.isExportAssignment(statement) && !statement.isExportEquals && ts7.isIdentifier(statement.expression)) {
2965
+ if (isExportAssignment(statement) && !statement.isExportEquals && isIdentifier6(statement.expression)) {
2778
2966
  defaultExportName = statement.expression.text;
2779
2967
  }
2780
- if (ts7.isExportDeclaration(statement) && !statement.exportClause && statement.moduleSpecifier && ts7.isStringLiteral(statement.moduleSpecifier)) {
2968
+ if (isExportDeclaration(statement) && !statement.exportClause && statement.moduleSpecifier && isStringLiteral5(statement.moduleSpecifier)) {
2781
2969
  wildcardReExport = relativizeModuleSpecifier(statement.moduleSpecifier.text, fullPath);
2782
2970
  }
2783
2971
  }
@@ -2851,7 +3039,7 @@ var generateServerFunctions = (collectors) => {
2851
3039
  if (modules.length === 0) return "";
2852
3040
  const merged = { kind: "dir", children: /* @__PURE__ */ new Map(), sourcePath: "<merged>" };
2853
3041
  for (const module of modules) {
2854
- const absolutePath = path9.resolve(ROOT_DIR5, module.sourcePath);
3042
+ const absolutePath = path10.resolve(ROOT_DIR5, module.sourcePath);
2855
3043
  const parsed = parseFunctionFile(absolutePath, collectors);
2856
3044
  if (!parsed) continue;
2857
3045
  if (parsed.exports.size === 0 && parsed.defaultExportName === null && parsed.wildcardReExport === null) {
@@ -2971,12 +3159,14 @@ var collectSyncTypes = (syncServerFiles, syncClientFiles, collectors) => {
2971
3159
  version: syncVersion,
2972
3160
  hasServer: serverFile !== void 0,
2973
3161
  hasClient: clientFile !== void 0,
2974
- ...syncMeta ? { meta: syncMeta } : {}
3162
+ ...syncMeta ? { meta: syncMeta } : {},
3163
+ //? Same extractors as the API side, so `syncMetaMap` and `apiMetaMap` agree.
3164
+ ...serverFile ? { serverMeta: { auth: extractAuth(serverFile), rateLimit: extractRateLimit(serverFile) } } : {}
2975
3165
  });
2976
3166
  }
2977
3167
  return syncTypesByPage;
2978
3168
  };
2979
- var generateTypeMapFile = (options = {}) => {
3169
+ var runTypeMapGeneration = (options) => {
2980
3170
  const { quiet = false } = options;
2981
3171
  assertValidRouteNaming({
2982
3172
  srcDir: getSrcDir2(),
@@ -3014,6 +3204,13 @@ var generateTypeMapFile = (options = {}) => {
3014
3204
  });
3015
3205
  writeTypeMapArtifacts({ content, docsData, schemasContent, diagnosticsData });
3016
3206
  };
3207
+ var generateTypeMapFile = (options = {}) => {
3208
+ try {
3209
+ runTypeMapGeneration(options);
3210
+ } finally {
3211
+ disposeTsApi();
3212
+ }
3213
+ };
3017
3214
 
3018
3215
  // src/templateRegistry.ts
3019
3216
  var BUILT_IN_TEMPLATE_KINDS = [
@@ -3087,13 +3284,29 @@ var registerDefaultTemplateRules = () => {
3087
3284
  registerDefaultTemplateRules();
3088
3285
 
3089
3286
  // src/loader.ts
3090
- import fs7 from "fs";
3091
- import path10 from "path";
3287
+ import fs8 from "fs";
3288
+ import path11 from "path";
3092
3289
  import { pathToFileURL } from "url";
3093
3290
  import { tryCatch, getSrcDir as getSrcDir3, ROOT_DIR as ROOT_DIR6, isTestFile as isTestFile3 } from "@luckystack/core";
3094
3291
 
3095
3292
  // src/runtimeTypeResolver.ts
3096
- import * as ts8 from "typescript";
3293
+ import { SymbolFlags as SymbolFlags3 } from "typescript-7-api/sync";
3294
+ import { SyntaxKind as SyntaxKind6 } from "typescript-7-api/ast";
3295
+ import {
3296
+ isEnumDeclaration as isEnumDeclaration4,
3297
+ isIdentifier as isIdentifier7,
3298
+ isImportDeclaration as isImportDeclaration3,
3299
+ isIndexSignatureDeclaration as isIndexSignatureDeclaration2,
3300
+ isInterfaceDeclaration as isInterfaceDeclaration5,
3301
+ isLiteralTypeNode as isLiteralTypeNode2,
3302
+ isNamedImports as isNamedImports3,
3303
+ isPropertySignatureDeclaration as isPropertySignatureDeclaration3,
3304
+ isStringLiteral as isStringLiteral6,
3305
+ isTypeAliasDeclaration as isTypeAliasDeclaration5,
3306
+ isTypeLiteralNode as isTypeLiteralNode2,
3307
+ isTypeReferenceNode as isTypeReferenceNode4,
3308
+ isUnionTypeNode as isUnionTypeNode2
3309
+ } from "typescript-7-api/ast/is";
3097
3310
  var MAX_DEPTH = 20;
3098
3311
  var unresolvedPrefix = "__RUNTIME_UNRESOLVED__::";
3099
3312
  var PRIMITIVE_TYPES = /* @__PURE__ */ new Set([
@@ -3173,9 +3386,9 @@ var splitTopLevel = (value, splitter) => {
3173
3386
  };
3174
3387
  var parseTypeNode = (typeText) => {
3175
3388
  const synthetic = `type __RT = ${typeText};`;
3176
- const source = ts8.createSourceFile("__runtime_type.ts", synthetic, ts8.ScriptTarget.Latest, true);
3389
+ const source = parseSourceText("__runtime_type.ts", synthetic);
3177
3390
  const statement = source.statements[0];
3178
- if (!statement || !ts8.isTypeAliasDeclaration(statement)) return null;
3391
+ if (!statement || !isTypeAliasDeclaration5(statement)) return null;
3179
3392
  return statement.type;
3180
3393
  };
3181
3394
  var parseObjectFields = (typeText) => {
@@ -3184,30 +3397,30 @@ var parseObjectFields = (typeText) => {
3184
3397
  return { fields: [], indexSignatures: [] };
3185
3398
  }
3186
3399
  const typeNode = parseTypeNode(clean);
3187
- if (!typeNode || !ts8.isTypeLiteralNode(typeNode)) {
3400
+ if (!typeNode || !isTypeLiteralNode2(typeNode)) {
3188
3401
  return { fields: [], indexSignatures: [] };
3189
3402
  }
3190
3403
  const fields = [];
3191
3404
  const indexSignatures = [];
3192
3405
  for (const member of typeNode.members) {
3193
- if (ts8.isPropertySignature(member) && member.type) {
3406
+ if (isPropertySignatureDeclaration3(member) && member.type) {
3194
3407
  let key = null;
3195
- if (ts8.isIdentifier(member.name)) {
3408
+ if (isIdentifier7(member.name)) {
3196
3409
  key = member.name.text;
3197
- } else if (ts8.isStringLiteral(member.name)) {
3410
+ } else if (isStringLiteral6(member.name)) {
3198
3411
  key = member.name.text;
3199
3412
  }
3200
3413
  if (key === null) continue;
3201
3414
  fields.push({
3202
3415
  key,
3203
- optional: Boolean(member.questionToken),
3416
+ optional: member.postfixToken?.kind === SyntaxKind6.QuestionToken,
3204
3417
  type: member.type.getText().trim()
3205
3418
  });
3206
3419
  continue;
3207
3420
  }
3208
- if (ts8.isIndexSignatureDeclaration(member)) {
3421
+ if (isIndexSignatureDeclaration2(member)) {
3209
3422
  const param = member.parameters[0];
3210
- if (!param || !ts8.isIdentifier(param.name) || !param.type) continue;
3423
+ if (!param || !isIdentifier7(param.name) || !param.type) continue;
3211
3424
  indexSignatures.push({
3212
3425
  keyName: param.name.text,
3213
3426
  keyType: param.type.getText().trim(),
@@ -3232,9 +3445,9 @@ var serializeObjectFields = ({
3232
3445
  return `{ ${segments.join("; ")} }`;
3233
3446
  };
3234
3447
  var extractStringLiteralKey = (node) => {
3235
- if (!ts8.isLiteralTypeNode(node)) return null;
3448
+ if (!isLiteralTypeNode2(node)) return null;
3236
3449
  const literal = node.literal;
3237
- if (!ts8.isStringLiteral(literal)) return null;
3450
+ if (!isStringLiteral6(literal)) return null;
3238
3451
  return literal.text;
3239
3452
  };
3240
3453
  var parseLiteralUnionKeys = (value) => {
@@ -3242,7 +3455,7 @@ var parseLiteralUnionKeys = (value) => {
3242
3455
  if (!trimmed) return null;
3243
3456
  const typeNode = parseTypeNode(trimmed);
3244
3457
  if (!typeNode) return null;
3245
- if (ts8.isUnionTypeNode(typeNode)) {
3458
+ if (isUnionTypeNode2(typeNode)) {
3246
3459
  const keys = [];
3247
3460
  for (const member of typeNode.types) {
3248
3461
  const key = extractStringLiteralKey(member);
@@ -3258,25 +3471,24 @@ var resolveIdentifier = (identifier, filePath) => {
3258
3471
  if (PRIMITIVE_TYPES.has(identifier.toLowerCase())) return identifier.toLowerCase();
3259
3472
  if (SKIP_EXPANSION2.has(identifier)) return identifier;
3260
3473
  try {
3261
- const program = getServerProgram();
3474
+ const { program, checker } = getServerProgram();
3262
3475
  const sourceFile = program.getSourceFile(filePath);
3263
3476
  if (!sourceFile) return toUnresolved(`unresolved type ${identifier}`);
3264
- const checker = program.getTypeChecker();
3265
3477
  for (const stmt of sourceFile.statements) {
3266
- if ((ts8.isInterfaceDeclaration(stmt) || ts8.isTypeAliasDeclaration(stmt) || ts8.isEnumDeclaration(stmt)) && stmt.name.text === identifier) {
3478
+ if ((isInterfaceDeclaration5(stmt) || isTypeAliasDeclaration5(stmt) || isEnumDeclaration4(stmt)) && stmt.name.text === identifier) {
3267
3479
  const symbol = checker.getSymbolAtLocation(stmt.name);
3268
3480
  if (symbol) {
3269
3481
  return expandType(checker.getDeclaredTypeOfSymbol(symbol), checker);
3270
3482
  }
3271
3483
  }
3272
- if (ts8.isImportDeclaration(stmt) && stmt.importClause) {
3484
+ if (isImportDeclaration3(stmt) && stmt.importClause) {
3273
3485
  const { namedBindings, name: defaultName } = stmt.importClause;
3274
- if (namedBindings && ts8.isNamedImports(namedBindings)) {
3486
+ if (namedBindings && isNamedImports3(namedBindings)) {
3275
3487
  for (const specifier of namedBindings.elements) {
3276
3488
  if (specifier.name.text === identifier) {
3277
3489
  const symbol = checker.getSymbolAtLocation(specifier.name);
3278
3490
  if (symbol) {
3279
- const target = symbol.flags & ts8.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
3491
+ const target = symbol.flags & SymbolFlags3.Alias ? checker.getAliasedSymbol(symbol) : symbol;
3280
3492
  return expandType(checker.getDeclaredTypeOfSymbol(target), checker);
3281
3493
  }
3282
3494
  }
@@ -3285,7 +3497,7 @@ var resolveIdentifier = (identifier, filePath) => {
3285
3497
  if (defaultName?.text === identifier) {
3286
3498
  const symbol = checker.getSymbolAtLocation(defaultName);
3287
3499
  if (symbol) {
3288
- const target = symbol.flags & ts8.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
3500
+ const target = symbol.flags & SymbolFlags3.Alias ? checker.getAliasedSymbol(symbol) : symbol;
3289
3501
  return expandType(checker.getDeclaredTypeOfSymbol(target), checker);
3290
3502
  }
3291
3503
  }
@@ -3419,7 +3631,7 @@ var resolveExpression = (typeText, filePath, depth, state) => {
3419
3631
  });
3420
3632
  } else {
3421
3633
  const typeNode = parseTypeNode(type);
3422
- const referenceInfo = typeNode && ts8.isTypeReferenceNode(typeNode) && ts8.isIdentifier(typeNode.typeName) ? { name: typeNode.typeName.text, args: typeNode.typeArguments } : null;
3634
+ const referenceInfo = typeNode && isTypeReferenceNode4(typeNode) && isIdentifier7(typeNode.typeName) ? { name: typeNode.typeName.text, args: typeNode.typeArguments } : null;
3423
3635
  if (referenceInfo?.args && referenceInfo.args.length > 0) {
3424
3636
  const { name: genericName, args: argNodes } = referenceInfo;
3425
3637
  const args = argNodes.map((arg) => arg.getText().trim());
@@ -3470,7 +3682,7 @@ var devSyncs = {};
3470
3682
  var devFunctions = {};
3471
3683
  var normalizePath3 = (value) => value.replaceAll("\\", "/");
3472
3684
  var isIgnoredPath = (absolutePath) => {
3473
- const relativeFromRoot = normalizePath3(path10.relative(ROOT_DIR6, absolutePath));
3685
+ const relativeFromRoot = normalizePath3(path11.relative(ROOT_DIR6, absolutePath));
3474
3686
  return getRoutingRules().ignore(relativeFromRoot);
3475
3687
  };
3476
3688
  var mapApiPageLocation = (pageLocation) => {
@@ -3480,7 +3692,7 @@ var mapSyncPageLocation = (pageLocation) => {
3480
3692
  return pageLocation || "system";
3481
3693
  };
3482
3694
  var resolveApiRouteMetaFromPath = (filePath) => {
3483
- const absolutePath = path10.resolve(filePath);
3695
+ const absolutePath = path11.resolve(filePath);
3484
3696
  const normalizedAbsolutePath = normalizePath3(absolutePath);
3485
3697
  const normalizedSrcDir = normalizePath3(getSrcDir3());
3486
3698
  if (!normalizedAbsolutePath.startsWith(normalizedSrcDir) || !normalizedAbsolutePath.endsWith(".ts")) {
@@ -3490,7 +3702,7 @@ var resolveApiRouteMetaFromPath = (filePath) => {
3490
3702
  return null;
3491
3703
  }
3492
3704
  const rules2 = getRoutingRules();
3493
- const relativePath = normalizePath3(path10.relative(getSrcDir3(), absolutePath));
3705
+ const relativePath = normalizePath3(path11.relative(getSrcDir3(), absolutePath));
3494
3706
  const segments = relativePath.split("/");
3495
3707
  const apiIndex = segments.indexOf(rules2.apiMarker);
3496
3708
  if (apiIndex === -1 || apiIndex === segments.length - 1) {
@@ -3510,7 +3722,7 @@ var resolveApiRouteMetaFromPath = (filePath) => {
3510
3722
  return { routeKey, absolutePath };
3511
3723
  };
3512
3724
  var resolveSyncRouteMetaFromPath = (filePath) => {
3513
- const absolutePath = path10.resolve(filePath);
3725
+ const absolutePath = path11.resolve(filePath);
3514
3726
  const normalizedAbsolutePath = normalizePath3(absolutePath);
3515
3727
  const normalizedSrcDir = normalizePath3(getSrcDir3());
3516
3728
  if (!normalizedAbsolutePath.startsWith(normalizedSrcDir) || !normalizedAbsolutePath.endsWith(".ts")) {
@@ -3520,7 +3732,7 @@ var resolveSyncRouteMetaFromPath = (filePath) => {
3520
3732
  return null;
3521
3733
  }
3522
3734
  const rules2 = getRoutingRules();
3523
- const relativePath = normalizePath3(path10.relative(getSrcDir3(), absolutePath));
3735
+ const relativePath = normalizePath3(path11.relative(getSrcDir3(), absolutePath));
3524
3736
  const segments = relativePath.split("/");
3525
3737
  const syncIndex = segments.indexOf(rules2.syncMarker);
3526
3738
  if (syncIndex === -1 || syncIndex === segments.length - 1) {
@@ -3564,13 +3776,13 @@ var importFile = async (absolutePath) => {
3564
3776
  };
3565
3777
  var collectTsFiles = (dir, relativeTo = "") => {
3566
3778
  const results = [];
3567
- const entries = fs7.readdirSync(dir);
3779
+ const entries = fs8.readdirSync(dir);
3568
3780
  for (const entry of entries) {
3569
3781
  if (entry === "node_modules") continue;
3570
- const entryPath = path10.join(dir, entry);
3782
+ const entryPath = path11.join(dir, entry);
3571
3783
  if (isIgnoredPath(entryPath)) continue;
3572
3784
  const relPath = relativeTo ? `${relativeTo}/${entry}` : entry;
3573
- if (fs7.statSync(entryPath).isDirectory()) {
3785
+ if (fs8.statSync(entryPath).isDirectory()) {
3574
3786
  if (isNonRouteDirectory(entry)) continue;
3575
3787
  results.push(...collectTsFiles(entryPath, relPath));
3576
3788
  } else if (entry.endsWith(".ts") && !isTestFile3(entry)) {
@@ -3602,16 +3814,16 @@ var resolveFunctionModule = (loadedModule, fileName) => {
3602
3814
  var initializeApis = async () => {
3603
3815
  for (const key of Object.keys(devApis)) delete devApis[key];
3604
3816
  clearRuntimeTypeResolverCache();
3605
- const srcFolder = fs7.readdirSync(getSrcDir3());
3817
+ const srcFolder = fs8.readdirSync(getSrcDir3());
3606
3818
  for (const file of srcFolder) {
3607
3819
  await scanApiFolder(file);
3608
3820
  }
3609
3821
  };
3610
3822
  var upsertApiFromFile = async (filePath) => {
3611
- if (isIgnoredPath(path10.resolve(filePath))) return;
3823
+ if (isIgnoredPath(path11.resolve(filePath))) return;
3612
3824
  const routeMeta = resolveApiRouteMetaFromPath(filePath);
3613
3825
  if (!routeMeta) {
3614
- const normalized = normalizePath3(path10.resolve(filePath));
3826
+ const normalized = normalizePath3(path11.resolve(filePath));
3615
3827
  if (normalized.endsWith(".ts") && normalized.includes(apiMarkerSegment()) && isRouteSurfaceFile(normalized)) {
3616
3828
  console.log(
3617
3829
  `[loader][api] invalid filename: ${normalized}. Expected <name>_v<number>.ts. File will not be loaded.`,
@@ -3659,13 +3871,13 @@ var removeApiFromFile = (filePath) => {
3659
3871
  delete devApis[routeMeta.routeKey];
3660
3872
  };
3661
3873
  var scanApiFolder = async (file, basePath = "") => {
3662
- const fullPath = path10.join(getSrcDir3(), basePath, file);
3874
+ const fullPath = path11.join(getSrcDir3(), basePath, file);
3663
3875
  if (isIgnoredPath(fullPath)) return;
3664
- if (!fs7.statSync(fullPath).isDirectory()) return;
3876
+ if (!fs8.statSync(fullPath).isDirectory()) return;
3665
3877
  if (file !== getRoutingRules().apiMarker) {
3666
- const subFolders = fs7.readdirSync(fullPath);
3878
+ const subFolders = fs8.readdirSync(fullPath);
3667
3879
  for (const sub of subFolders) {
3668
- await scanApiFolder(sub, path10.join(basePath, file));
3880
+ await scanApiFolder(sub, path11.join(basePath, file));
3669
3881
  }
3670
3882
  return;
3671
3883
  }
@@ -3678,7 +3890,7 @@ var scanApiFolder = async (file, basePath = "") => {
3678
3890
  const versionMatch = rawApiName.match(apiRules.apiVersionRegex);
3679
3891
  if (!versionMatch) {
3680
3892
  console.log(
3681
- `[loader][api] invalid filename: ${path10.join(fullPath, relFile)}. Expected <name>_v<number>.ts. File will not be loaded.`,
3893
+ `[loader][api] invalid filename: ${path11.join(fullPath, relFile)}. Expected <name>_v<number>.ts. File will not be loaded.`,
3682
3894
  "red"
3683
3895
  );
3684
3896
  continue;
@@ -3686,7 +3898,7 @@ var scanApiFolder = async (file, basePath = "") => {
3686
3898
  const version = `v${versionMatch[1]}`;
3687
3899
  const apiName = rawApiName.replace(apiRules.apiVersionRegex, "");
3688
3900
  const routeKey = `api/${mappedPageLocation}/${apiName}/${version}`;
3689
- const modulePath = path10.resolve(path10.join(fullPath, relFile));
3901
+ const modulePath = path11.resolve(path11.join(fullPath, relFile));
3690
3902
  const [err, module] = await tryCatch(async () => importFile(modulePath));
3691
3903
  if (err) {
3692
3904
  console.log(`[loader][api] failed to import ${routeKey} from ${modulePath}:`, err, "red");
@@ -3715,16 +3927,16 @@ var scanApiFolder = async (file, basePath = "") => {
3715
3927
  var initializeSyncs = async () => {
3716
3928
  for (const key of Object.keys(devSyncs)) delete devSyncs[key];
3717
3929
  clearRuntimeTypeResolverCache();
3718
- const srcFolder = fs7.readdirSync(getSrcDir3());
3930
+ const srcFolder = fs8.readdirSync(getSrcDir3());
3719
3931
  for (const file of srcFolder) {
3720
3932
  await scanSyncFolder(file);
3721
3933
  }
3722
3934
  };
3723
3935
  var upsertSyncFromFile = async (filePath) => {
3724
- if (isIgnoredPath(path10.resolve(filePath))) return;
3936
+ if (isIgnoredPath(path11.resolve(filePath))) return;
3725
3937
  const routeMeta = resolveSyncRouteMetaFromPath(filePath);
3726
3938
  if (!routeMeta) {
3727
- const normalized = normalizePath3(path10.resolve(filePath));
3939
+ const normalized = normalizePath3(path11.resolve(filePath));
3728
3940
  if (normalized.endsWith(".ts") && normalized.includes(syncMarkerSegment()) && isRouteSurfaceFile(normalized)) {
3729
3941
  console.log(
3730
3942
  `[loader][sync] invalid filename: ${normalized}. Expected <name>_server_v<number>.ts or <name>_client_v<number>.ts. File will not be loaded.`,
@@ -3777,13 +3989,13 @@ var removeSyncFromFile = (filePath) => {
3777
3989
  delete devSyncs[routeMeta.routeKey];
3778
3990
  };
3779
3991
  var scanSyncFolder = async (file, basePath = "") => {
3780
- const fullPath = path10.join(getSrcDir3(), basePath, file);
3992
+ const fullPath = path11.join(getSrcDir3(), basePath, file);
3781
3993
  if (isIgnoredPath(fullPath)) return;
3782
- if (!fs7.statSync(fullPath).isDirectory()) return;
3994
+ if (!fs8.statSync(fullPath).isDirectory()) return;
3783
3995
  if (file !== getRoutingRules().syncMarker) {
3784
- const subFolders = fs7.readdirSync(fullPath);
3996
+ const subFolders = fs8.readdirSync(fullPath);
3785
3997
  for (const sub of subFolders) {
3786
- await scanSyncFolder(sub, path10.join(basePath, file));
3998
+ await scanSyncFolder(sub, path11.join(basePath, file));
3787
3999
  }
3788
4000
  return;
3789
4001
  }
@@ -3795,7 +4007,7 @@ var scanSyncFolder = async (file, basePath = "") => {
3795
4007
  const syncMatch = rawSyncFileName.match(syncRules.syncVersionRegex);
3796
4008
  if (!syncMatch) {
3797
4009
  console.log(
3798
- `[loader][sync] invalid filename: ${path10.join(fullPath, relFile)}. Expected <name>_server_v<number>.ts or <name>_client_v<number>.ts. File will not be loaded.`,
4010
+ `[loader][sync] invalid filename: ${path11.join(fullPath, relFile)}. Expected <name>_server_v<number>.ts or <name>_client_v<number>.ts. File will not be loaded.`,
3799
4011
  "red"
3800
4012
  );
3801
4013
  continue;
@@ -3805,7 +4017,7 @@ var scanSyncFolder = async (file, basePath = "") => {
3805
4017
  const syncName = rawSyncFileName.replace(syncRules.syncVersionRegex, "");
3806
4018
  const mappedPageLocation = mapSyncPageLocation(pageLocation);
3807
4019
  const routeBaseKey = `sync/${mappedPageLocation}/${syncName}/${version}`;
3808
- const filePath = path10.resolve(path10.join(fullPath, relFile));
4020
+ const filePath = path11.resolve(path11.join(fullPath, relFile));
3809
4021
  const [fileError, fileResult] = await tryCatch(async () => importFile(filePath));
3810
4022
  if (fileError) {
3811
4023
  console.log(`[loader][sync] failed to import ${filePath}:`, fileError, "red");
@@ -3837,7 +4049,7 @@ var initializeFunctions = async () => {
3837
4049
  }
3838
4050
  });
3839
4051
  for (const functionModule of modules) {
3840
- const absolutePath = path10.resolve(ROOT_DIR6, functionModule.sourcePath);
4052
+ const absolutePath = path11.resolve(ROOT_DIR6, functionModule.sourcePath);
3841
4053
  const [err, module] = await tryCatch(async () => importFile(absolutePath));
3842
4054
  if (err) {
3843
4055
  console.log(`[loader][function] failed to import ${absolutePath}:`, err, "red");
@@ -3860,19 +4072,25 @@ var initializeFunctions = async () => {
3860
4072
 
3861
4073
  // src/hotReload.ts
3862
4074
  import { watch } from "chokidar";
3863
- import fs11 from "fs";
3864
- import path14 from "path";
4075
+ import fs12 from "fs";
4076
+ import path15 from "path";
3865
4077
 
3866
4078
  // src/templateInjector.ts
3867
- import fs8 from "fs";
3868
- import path11 from "path";
4079
+ import fs9 from "fs";
4080
+ import path12 from "path";
3869
4081
  import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
3870
- import * as ts9 from "typescript";
4082
+ import { ScriptKind as ScriptKind3 } from "typescript-7-api/ast";
4083
+ import {
4084
+ isIdentifier as isIdentifier8,
4085
+ isInterfaceDeclaration as isInterfaceDeclaration6,
4086
+ isPropertySignatureDeclaration as isPropertySignatureDeclaration4,
4087
+ isTypeLiteralNode as isTypeLiteralNode3
4088
+ } from "typescript-7-api/ast/is";
3871
4089
  import { ROOT_DIR as ROOT_DIR7, getGeneratedSocketTypesPath as getGeneratedSocketTypesPath6, getSrcDir as getSrcDir4 } from "@luckystack/core";
3872
4090
  var __filename = fileURLToPath(import.meta.url);
3873
- var __dirname = path11.dirname(__filename);
3874
- var templatesDir = path11.join(__dirname, "templates");
3875
- var getConsumerTemplatesDir = () => path11.join(ROOT_DIR7, ".luckystack", "templates");
4091
+ var __dirname = path12.dirname(__filename);
4092
+ var templatesDir = path12.join(__dirname, "templates");
4093
+ var getConsumerTemplatesDir = () => path12.join(ROOT_DIR7, ".luckystack", "templates");
3876
4094
  var templateContentFilenames = (kind) => {
3877
4095
  const builtIn = BUILT_IN_TEMPLATE_FILENAMES[kind];
3878
4096
  if (builtIn) return [builtIn];
@@ -3881,10 +4099,10 @@ var templateContentFilenames = (kind) => {
3881
4099
  var resolveTemplateContent = (kind) => {
3882
4100
  const consumerDir = getConsumerTemplatesDir();
3883
4101
  for (const fileName of templateContentFilenames(kind)) {
3884
- const consumerFile = path11.join(consumerDir, fileName);
3885
- if (fs8.existsSync(consumerFile)) {
4102
+ const consumerFile = path12.join(consumerDir, fileName);
4103
+ if (fs9.existsSync(consumerFile)) {
3886
4104
  try {
3887
- return fs8.readFileSync(consumerFile, "utf8");
4105
+ return fs9.readFileSync(consumerFile, "utf8");
3888
4106
  } catch (error) {
3889
4107
  console.error(`[TemplateInjector] Could not read consumer template: ${consumerFile}`, error);
3890
4108
  }
@@ -3894,9 +4112,9 @@ var resolveTemplateContent = (kind) => {
3894
4112
  if (override !== null) return override;
3895
4113
  const builtInName = BUILT_IN_TEMPLATE_FILENAMES[kind];
3896
4114
  if (builtInName) {
3897
- const bundled = path11.join(templatesDir, builtInName);
4115
+ const bundled = path12.join(templatesDir, builtInName);
3898
4116
  try {
3899
- return fs8.readFileSync(bundled, "utf8");
4117
+ return fs9.readFileSync(bundled, "utf8");
3900
4118
  } catch (error) {
3901
4119
  console.error(`[TemplateInjector] Could not read bundled template: ${bundled}`, error);
3902
4120
  return null;
@@ -3910,11 +4128,11 @@ var ensureConsumerTemplateConfigLoaded = () => {
3910
4128
  consumerTemplateConfig ??= (async () => {
3911
4129
  const dir = getConsumerTemplatesDir();
3912
4130
  for (const fileName of ["templateRules.ts", "templateRules.mjs", "templateRules.js"]) {
3913
- const rulesFile = path11.join(dir, fileName);
3914
- if (!fs8.existsSync(rulesFile)) continue;
3915
- const resolvedRulesFile = path11.resolve(rulesFile);
3916
- const resolvedRoot = path11.resolve(ROOT_DIR7);
3917
- if (!resolvedRulesFile.startsWith(resolvedRoot + path11.sep) && resolvedRulesFile !== resolvedRoot) {
4131
+ const rulesFile = path12.join(dir, fileName);
4132
+ if (!fs9.existsSync(rulesFile)) continue;
4133
+ const resolvedRulesFile = path12.resolve(rulesFile);
4134
+ const resolvedRoot = path12.resolve(ROOT_DIR7);
4135
+ if (!resolvedRulesFile.startsWith(resolvedRoot + path12.sep) && resolvedRulesFile !== resolvedRoot) {
3918
4136
  console.warn(
3919
4137
  `[TemplateInjector] Template rules file resolves outside project root \u2014 skipping: ${rulesFile}`
3920
4138
  );
@@ -3932,7 +4150,7 @@ var ensureConsumerTemplateConfigLoaded = () => {
3932
4150
  };
3933
4151
  var isEmptyFile = (filePath) => {
3934
4152
  try {
3935
- const content = fs8.readFileSync(filePath, "utf8");
4153
+ const content = fs9.readFileSync(filePath, "utf8");
3936
4154
  return content.trim().length === 0;
3937
4155
  } catch {
3938
4156
  return false;
@@ -3940,7 +4158,7 @@ var isEmptyFile = (filePath) => {
3940
4158
  };
3941
4159
  var isCommentOnlyFile = (filePath) => {
3942
4160
  try {
3943
- const content = fs8.readFileSync(filePath, "utf8");
4161
+ const content = fs9.readFileSync(filePath, "utf8");
3944
4162
  const withoutBlockComments = content.replaceAll(/\/\*[\s\S]*?\*\//g, "");
3945
4163
  const withoutLineComments = withoutBlockComments.replaceAll(/(^|\s)\/\/.*$/gm, "$1");
3946
4164
  return withoutLineComments.trim().length === 0;
@@ -3974,7 +4192,7 @@ var isVersionedSyncFile = (filePath) => {
3974
4192
  return isVersionedSyncFileName(filePath);
3975
4193
  };
3976
4194
  var getFileName = (filePath) => {
3977
- return path11.basename(filePath.replaceAll("\\", "/"));
4195
+ return path12.basename(filePath.replaceAll("\\", "/"));
3978
4196
  };
3979
4197
  var stripTsExtension = (fileName) => {
3980
4198
  return fileName.replace(/\.ts$/, "");
@@ -4050,7 +4268,7 @@ var getInvalidVersionMessage = (filePath) => {
4050
4268
  var computeSrcRelativePath = (filePath) => {
4051
4269
  try {
4052
4270
  const srcDir = getSrcDir4();
4053
- const absolute = path11.resolve(filePath);
4271
+ const absolute = path12.resolve(filePath);
4054
4272
  const normalizedSrc = srcDir.replaceAll("\\", "/");
4055
4273
  const normalizedAbs = absolute.replaceAll("\\", "/");
4056
4274
  if (!normalizedAbs.startsWith(`${normalizedSrc}/`)) return null;
@@ -4098,7 +4316,7 @@ var getPairedSyncFile = (filePath) => {
4098
4316
  var hasPairedFile = (filePath) => {
4099
4317
  const pairedPath = getPairedSyncFile(filePath);
4100
4318
  if (!pairedPath) return false;
4101
- return fs8.existsSync(pairedPath);
4319
+ return fs9.existsSync(pairedPath);
4102
4320
  };
4103
4321
  var extractSyncPagePath2 = (filePath) => {
4104
4322
  const normalized = filePath.replaceAll("\\", "/");
@@ -4111,14 +4329,14 @@ var extractSyncName2 = (filePath) => {
4111
4329
  const normalized = filePath.replaceAll("\\", "/");
4112
4330
  const match = /_sync\/(.+)\.ts$/.exec(normalized);
4113
4331
  if (!match) {
4114
- const basename = path11.basename(filePath, ".ts");
4332
+ const basename = path12.basename(filePath, ".ts");
4115
4333
  return basename.replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
4116
4334
  }
4117
4335
  return (match[1] ?? "").replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
4118
4336
  };
4119
4337
  var extractClientInputFromFile = (filePath) => {
4120
4338
  try {
4121
- const content = fs8.readFileSync(filePath, "utf8");
4339
+ const content = fs9.readFileSync(filePath, "utf8");
4122
4340
  const syncParamsMatch = /interface\s+SyncParams\s*\{/.exec(content);
4123
4341
  if (!syncParamsMatch) return null;
4124
4342
  const searchRegion = content.slice(syncParamsMatch.index + syncParamsMatch[0].length);
@@ -4149,7 +4367,7 @@ var extractClientInputFromFile = (filePath) => {
4149
4367
  var extractClientInputFromGeneratedTypes = (pagePath, syncName) => {
4150
4368
  try {
4151
4369
  const generatedTypesPath = getGeneratedSocketTypesPath6();
4152
- const content = fs8.readFileSync(generatedTypesPath, "utf8");
4370
+ const content = fs9.readFileSync(generatedTypesPath, "utf8");
4153
4371
  const escapeRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
4154
4372
  const escapedPagePath = escapeRegex(pagePath);
4155
4373
  const escapedSyncName = escapeRegex(syncName);
@@ -4195,7 +4413,7 @@ var calculateRelativePath = (filePath) => {
4195
4413
  const srcRelative = computeSrcRelativePath(filePath);
4196
4414
  if (srcRelative !== null) {
4197
4415
  try {
4198
- const srcDepthFromRoot = path11.relative(ROOT_DIR7, getSrcDir4()).replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0).length;
4416
+ const srcDepthFromRoot = path12.relative(ROOT_DIR7, getSrcDir4()).replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0).length;
4199
4417
  const dirSegmentsAfterSrc = Math.max(
4200
4418
  0,
4201
4419
  srcRelative.split("/").filter((segment) => segment.length > 0).length - 1
@@ -4274,7 +4492,7 @@ var getTemplate = (filePath) => {
4274
4492
  var injectTemplate = async (filePath) => {
4275
4493
  await ensureConsumerTemplateConfigLoaded();
4276
4494
  if (getRouteFilenameValidationMessage(filePath)) {
4277
- fs8.writeFileSync(filePath, getInvalidVersionMessage(filePath), "utf8");
4495
+ fs9.writeFileSync(filePath, getInvalidVersionMessage(filePath), "utf8");
4278
4496
  console.log(`[TemplateInjector] Invalid route filename, injected guidance: ${filePath}`);
4279
4497
  return true;
4280
4498
  }
@@ -4283,7 +4501,7 @@ var injectTemplate = async (filePath) => {
4283
4501
  return false;
4284
4502
  }
4285
4503
  try {
4286
- fs8.writeFileSync(filePath, template, "utf8");
4504
+ fs9.writeFileSync(filePath, template, "utf8");
4287
4505
  console.log(`[TemplateInjector] Injected template into: ${filePath}`);
4288
4506
  return true;
4289
4507
  } catch (error) {
@@ -4339,18 +4557,10 @@ var rewriteClientInputType = (content) => {
4339
4557
  );
4340
4558
  };
4341
4559
  var rewriteClientInputTypeAst = (content, sourceFileName) => {
4342
- const parseSource = (src) => ts9.createSourceFile(
4343
- sourceFileName,
4344
- src,
4345
- ts9.ScriptTarget.Latest,
4346
- /* setParentNodes */
4347
- true,
4348
- ts9.ScriptKind.TS
4349
- );
4350
- const sourceFile = parseSource(content);
4560
+ const sourceFile = parseSourceText(sourceFileName, content, ScriptKind3.TS);
4351
4561
  let syncParamsInterface;
4352
4562
  for (const stmt of sourceFile.statements) {
4353
- if (ts9.isInterfaceDeclaration(stmt) && stmt.name.text === "SyncParams") {
4563
+ if (isInterfaceDeclaration6(stmt) && stmt.name.text === "SyncParams") {
4354
4564
  syncParamsInterface = stmt;
4355
4565
  break;
4356
4566
  }
@@ -4358,30 +4568,18 @@ var rewriteClientInputTypeAst = (content, sourceFileName) => {
4358
4568
  if (!syncParamsInterface) return null;
4359
4569
  let clientInputMember;
4360
4570
  for (const member of syncParamsInterface.members) {
4361
- if (ts9.isPropertySignature(member) && ts9.isIdentifier(member.name) && member.name.text === "clientInput") {
4571
+ if (isPropertySignatureDeclaration4(member) && isIdentifier8(member.name) && member.name.text === "clientInput") {
4362
4572
  clientInputMember = member;
4363
4573
  break;
4364
4574
  }
4365
4575
  }
4366
4576
  if (!clientInputMember?.type) return null;
4367
- if (!ts9.isTypeLiteralNode(clientInputMember.type)) return null;
4577
+ if (!isTypeLiteralNode3(clientInputMember.type)) return null;
4368
4578
  const typeNode = clientInputMember.type;
4369
4579
  const start = typeNode.getStart(sourceFile);
4370
4580
  const end = typeNode.getEnd();
4371
4581
  const rewritten = `${content.slice(0, start)}SyncClientInput<PagePath, SyncName>${content.slice(end)}`;
4372
- const reparsedFile = parseSource(rewritten);
4373
- const verifyProgram = ts9.createProgram({
4374
- rootNames: [sourceFileName],
4375
- options: { noResolve: true, skipLibCheck: true },
4376
- // Supply the in-memory source so `ts.createProgram` never touches the disk.
4377
- host: {
4378
- ...ts9.createCompilerHost({}),
4379
- getSourceFile: (name) => name === sourceFileName ? reparsedFile : void 0,
4380
- fileExists: (name) => name === sourceFileName,
4381
- readFile: (name) => name === sourceFileName ? rewritten : void 0
4382
- }
4383
- });
4384
- const syntaxErrors = verifyProgram.getSyntacticDiagnostics(reparsedFile);
4582
+ const syntaxErrors = transpileSourceText(sourceFileName, rewritten).diagnostics ?? [];
4385
4583
  if (syntaxErrors.length > 0) {
4386
4584
  console.log(
4387
4585
  `[TemplateInjector] AST rewrite produced invalid TypeScript for ${sourceFileName} \u2014 leaving untouched`,
@@ -4411,10 +4609,10 @@ var updateClientFileForPairedServer = async (clientFilePath) => {
4411
4609
  try {
4412
4610
  const pagePath = extractSyncPagePath2(clientFilePath);
4413
4611
  const syncName = extractSyncName2(clientFilePath);
4414
- let content = fs8.readFileSync(clientFilePath, "utf8");
4612
+ let content = fs9.readFileSync(clientFilePath, "utf8");
4415
4613
  content = ensureImportedTypes(content, clientFilePath);
4416
4614
  content = insertTypeAliases(content, pagePath, syncName);
4417
- const astResult = rewriteClientInputTypeAst(content, path11.basename(clientFilePath));
4615
+ const astResult = rewriteClientInputTypeAst(content, path12.basename(clientFilePath));
4418
4616
  if (astResult === null) {
4419
4617
  console.log(
4420
4618
  `[TemplateInjector] AST clientInput rewrite unavailable for ${clientFilePath} \u2014 using regex fallback`,
@@ -4426,7 +4624,7 @@ var updateClientFileForPairedServer = async (clientFilePath) => {
4426
4624
  }
4427
4625
  content = addServerOutputToParams(content);
4428
4626
  content = addServerOutputToDestructuring(content);
4429
- fs8.writeFileSync(clientFilePath, content, "utf8");
4627
+ fs9.writeFileSync(clientFilePath, content, "utf8");
4430
4628
  console.log(`[TemplateInjector] Updated client file to use paired types (preserved code): ${clientFilePath}`);
4431
4629
  return true;
4432
4630
  } catch (error) {
@@ -4467,7 +4665,7 @@ var splitAtMainBody = (content) => {
4467
4665
  };
4468
4666
  var updateClientFileForDeletedServer = async (clientFilePath, clientInputTypes) => {
4469
4667
  try {
4470
- let content = fs8.readFileSync(clientFilePath, "utf8");
4668
+ let content = fs9.readFileSync(clientFilePath, "utf8");
4471
4669
  content = inlineClientInputType(content, clientInputTypes);
4472
4670
  const [header, body] = splitAtMainBody(content);
4473
4671
  const cleanedHeader = removeServerOutputFromDestructuring(removeServerOutputFromParams(header));
@@ -4475,7 +4673,7 @@ var updateClientFileForDeletedServer = async (clientFilePath, clientInputTypes)
4475
4673
  content = removeGeneratedTypeImports(content);
4476
4674
  content = removeTypeAliases(content);
4477
4675
  content = content.replaceAll(/\n{3,}/g, "\n\n");
4478
- fs8.writeFileSync(clientFilePath, content, "utf8");
4676
+ fs9.writeFileSync(clientFilePath, content, "utf8");
4479
4677
  console.log(`[TemplateInjector] Updated client file for deleted server (preserved code): ${clientFilePath}`);
4480
4678
  return true;
4481
4679
  } catch (error) {
@@ -4501,7 +4699,7 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
4501
4699
  /clientInput:\s*\{[^}]*\}/s,
4502
4700
  (_match) => `clientInput: ${clientInputTypes}`
4503
4701
  );
4504
- fs8.writeFileSync(serverFilePath, content, "utf8");
4702
+ fs9.writeFileSync(serverFilePath, content, "utf8");
4505
4703
  console.log(`[TemplateInjector] Injected server template with clientInput: ${serverFilePath}`);
4506
4704
  return true;
4507
4705
  } catch (error) {
@@ -4511,24 +4709,24 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
4511
4709
  };
4512
4710
 
4513
4711
  // src/importDependencyGraph.ts
4514
- import fs9 from "fs";
4515
- import path12 from "path";
4712
+ import fs10 from "fs";
4713
+ import path13 from "path";
4516
4714
  import { ROOT_DIR as ROOT_DIR8, getServerFunctionDirs as getServerFunctionDirs2, getSharedDir, getSrcDir as getSrcDir5 } from "@luckystack/core";
4517
4715
  var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts"];
4518
- var normalizePath4 = (value) => path12.resolve(value).replaceAll("\\", "/");
4716
+ var normalizePath4 = (value) => path13.resolve(value).replaceAll("\\", "/");
4519
4717
  var isSupportedScriptFile = (value) => {
4520
4718
  return SUPPORTED_EXTENSIONS.some((extension) => value.endsWith(extension));
4521
4719
  };
4522
4720
  var existsFile = (value) => {
4523
4721
  try {
4524
- return fs9.existsSync(value) && fs9.statSync(value).isFile();
4722
+ return fs10.existsSync(value) && fs10.statSync(value).isFile();
4525
4723
  } catch {
4526
4724
  return false;
4527
4725
  }
4528
4726
  };
4529
4727
  var existsDirectory = (value) => {
4530
4728
  try {
4531
- return fs9.existsSync(value) && fs9.statSync(value).isDirectory();
4729
+ return fs10.existsSync(value) && fs10.statSync(value).isDirectory();
4532
4730
  } catch {
4533
4731
  return false;
4534
4732
  }
@@ -4539,16 +4737,16 @@ var collectScriptFiles = (dir, output, visited = /* @__PURE__ */ new Set()) => {
4539
4737
  }
4540
4738
  let realDir;
4541
4739
  try {
4542
- realDir = fs9.realpathSync(dir);
4740
+ realDir = fs10.realpathSync(dir);
4543
4741
  } catch {
4544
4742
  return;
4545
4743
  }
4546
4744
  if (visited.has(realDir)) return;
4547
4745
  visited.add(realDir);
4548
- const entries = fs9.readdirSync(dir, { withFileTypes: true });
4746
+ const entries = fs10.readdirSync(dir, { withFileTypes: true });
4549
4747
  for (const entry of entries) {
4550
4748
  if (entry.name === "node_modules") continue;
4551
- const fullPath = path12.join(dir, entry.name);
4749
+ const fullPath = path13.join(dir, entry.name);
4552
4750
  if (entry.isDirectory() || entry.isSymbolicLink()) {
4553
4751
  if (existsDirectory(fullPath)) {
4554
4752
  collectScriptFiles(fullPath, output, visited);
@@ -4567,7 +4765,7 @@ var SCOPED_FILES_TTL_MS = 1e3;
4567
4765
  var extractImportSpecifiers = (filePath) => {
4568
4766
  let mtimeMs = 0;
4569
4767
  try {
4570
- mtimeMs = fs9.statSync(filePath).mtimeMs;
4768
+ mtimeMs = fs10.statSync(filePath).mtimeMs;
4571
4769
  } catch {
4572
4770
  specifiersCache.delete(filePath);
4573
4771
  return [];
@@ -4577,7 +4775,7 @@ var extractImportSpecifiers = (filePath) => {
4577
4775
  return cached.specifiers;
4578
4776
  }
4579
4777
  try {
4580
- const source = fs9.readFileSync(filePath, "utf8");
4778
+ const source = fs10.readFileSync(filePath, "utf8");
4581
4779
  const specifiers = /* @__PURE__ */ new Set();
4582
4780
  const importExportRegex = /(?:import|export)\s+(?:[\s\S]*?\s+from\s+)?['"]([^'"]+)['"]/g;
4583
4781
  const dynamicImportRegex = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
@@ -4612,7 +4810,7 @@ var tryResolveWithExtensions = (basePath) => {
4612
4810
  }
4613
4811
  if (existsDirectory(basePath)) {
4614
4812
  for (const extension of SUPPORTED_EXTENSIONS) {
4615
- const indexFile = path12.join(basePath, `index${extension}`);
4813
+ const indexFile = path13.join(basePath, `index${extension}`);
4616
4814
  if (existsFile(indexFile)) {
4617
4815
  return normalizePath4(indexFile);
4618
4816
  }
@@ -4625,18 +4823,18 @@ var resolveImportToFile = (importerPath, specifier) => {
4625
4823
  return null;
4626
4824
  }
4627
4825
  if (specifier === "config") {
4628
- return tryResolveWithExtensions(path12.join(ROOT_DIR8, "config"));
4826
+ return tryResolveWithExtensions(path13.join(ROOT_DIR8, "config"));
4629
4827
  }
4630
4828
  if (specifier.startsWith("./") || specifier.startsWith("../")) {
4631
- const relativeBase = path12.resolve(path12.dirname(importerPath), specifier);
4829
+ const relativeBase = path13.resolve(path13.dirname(importerPath), specifier);
4632
4830
  return tryResolveWithExtensions(relativeBase);
4633
4831
  }
4634
4832
  if (specifier.startsWith("src/") || specifier.startsWith("@/")) {
4635
4833
  const sourcePath = specifier.startsWith("@/") ? specifier.slice(2) : specifier.slice(4);
4636
- return tryResolveWithExtensions(path12.join(getSrcDir5(), sourcePath));
4834
+ return tryResolveWithExtensions(path13.join(getSrcDir5(), sourcePath));
4637
4835
  }
4638
4836
  if (specifier.startsWith("shared/")) {
4639
- return tryResolveWithExtensions(path12.join(getSharedDir(), specifier.slice(7)));
4837
+ return tryResolveWithExtensions(path13.join(getSharedDir(), specifier.slice(7)));
4640
4838
  }
4641
4839
  return null;
4642
4840
  };
@@ -4654,7 +4852,7 @@ var collectScopedFiles = () => {
4654
4852
  for (const dir of getServerFunctionDirs2()) {
4655
4853
  collectScriptFiles(dir, files);
4656
4854
  }
4657
- const configFile = tryResolveWithExtensions(path12.join(ROOT_DIR8, "config"));
4855
+ const configFile = tryResolveWithExtensions(path13.join(ROOT_DIR8, "config"));
4658
4856
  if (configFile) {
4659
4857
  files.add(configFile);
4660
4858
  }
@@ -4702,19 +4900,19 @@ var findDependentRouteFiles = (changedFilePath) => {
4702
4900
  };
4703
4901
 
4704
4902
  // src/prismaClientCheck.ts
4705
- import fs10 from "fs";
4706
- import path13 from "path";
4903
+ import fs11 from "fs";
4904
+ import path14 from "path";
4707
4905
  import { spawn } from "child_process";
4708
4906
  import { ROOT_DIR as ROOT_DIR9, tryCatch as tryCatch2 } from "@luckystack/core";
4709
- var GENERATED_CLIENT_DIR = path13.join(ROOT_DIR9, "node_modules", ".prisma", "client");
4710
- var GENERATED_CLIENT_MARKER = path13.join(GENERATED_CLIENT_DIR, "schema.prisma");
4711
- var DEFAULT_SCHEMA_PATH = path13.join(ROOT_DIR9, "prisma", "schema.prisma");
4712
- var isPrismaClientMissing = () => fs10.existsSync(DEFAULT_SCHEMA_PATH) && !fs10.existsSync(GENERATED_CLIENT_MARKER);
4907
+ var GENERATED_CLIENT_DIR = path14.join(ROOT_DIR9, "node_modules", ".prisma", "client");
4908
+ var GENERATED_CLIENT_MARKER = path14.join(GENERATED_CLIENT_DIR, "schema.prisma");
4909
+ var DEFAULT_SCHEMA_PATH = path14.join(ROOT_DIR9, "prisma", "schema.prisma");
4910
+ var isPrismaClientMissing = () => fs11.existsSync(DEFAULT_SCHEMA_PATH) && !fs11.existsSync(GENERATED_CLIENT_MARKER);
4713
4911
  var runPrismaGenerate = async () => tryCatch2(
4714
4912
  () => new Promise((resolve, reject) => {
4715
4913
  const localBinName = process.platform === "win32" ? "prisma.cmd" : "prisma";
4716
- const localBin = path13.join(ROOT_DIR9, "node_modules", ".bin", localBinName);
4717
- const useLocal = fs10.existsSync(localBin);
4914
+ const localBin = path14.join(ROOT_DIR9, "node_modules", ".bin", localBinName);
4915
+ const useLocal = fs11.existsSync(localBin);
4718
4916
  const [cmd, args] = useLocal ? [localBin, ["generate"]] : [process.platform === "win32" ? "npx.cmd" : "npx", ["prisma", "generate"]];
4719
4917
  const isWinShim = process.platform === "win32" && /\.(cmd|bat)$/i.test(cmd);
4720
4918
  const child = isWinShim ? spawn(
@@ -4735,7 +4933,7 @@ var runPrismaGenerate = async () => tryCatch2(
4735
4933
 
4736
4934
  // src/hotReload.ts
4737
4935
  import { tryCatch as tryCatch3, getProjectConfig, getLocaleReloader, isProductionRuntime } from "@luckystack/core";
4738
- var normalizeFsPath = (value) => path14.resolve(value).replaceAll("\\", "/");
4936
+ var normalizeFsPath = (value) => path15.resolve(value).replaceAll("\\", "/");
4739
4937
  var isGeneratedPath = (normalizedPath) => {
4740
4938
  return normalizedPath.includes("apiTypes.generated.ts") || normalizedPath.includes("apiDocs.generated.json");
4741
4939
  };
@@ -4943,7 +5141,7 @@ var setupWatchers = () => {
4943
5141
  if (shouldInjectTemplate(filePath, { isNewFile: true })) {
4944
5142
  if (isSyncServerFile(normalizedPath)) {
4945
5143
  const clientPath = getPairedSyncFile(normalizedPath);
4946
- if (clientPath && fs11.existsSync(clientPath) && !isEmptyFile(clientPath)) {
5144
+ if (clientPath && fs12.existsSync(clientPath) && !isEmptyFile(clientPath)) {
4947
5145
  const clientInputTypes = extractClientInputFromFile(clientPath);
4948
5146
  if (clientInputTypes) {
4949
5147
  await injectServerTemplateWithClientInput(filePath, clientInputTypes);
@@ -5106,7 +5304,7 @@ var setupWatchers = () => {
5106
5304
  scheduleReload("sync", async () => {
5107
5305
  if (isSyncServerFile(normalizedPath)) {
5108
5306
  const clientPath = getPairedSyncFile(normalizedPath);
5109
- if (clientPath && fs11.existsSync(clientPath)) {
5307
+ if (clientPath && fs12.existsSync(clientPath)) {
5110
5308
  const pagePath = extractSyncPagePath2(normalizedPath);
5111
5309
  const syncName = extractSyncName2(normalizedPath);
5112
5310
  const clientInputTypes = extractClientInputFromGeneratedTypes(pagePath, syncName);