@tanstack/start-plugin-core 1.167.35 → 1.169.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 (187) hide show
  1. package/dist/esm/import-protection/adapterUtils.d.ts +27 -0
  2. package/dist/esm/import-protection/adapterUtils.js +31 -0
  3. package/dist/esm/import-protection/adapterUtils.js.map +1 -0
  4. package/dist/esm/import-protection/analysis.d.ts +36 -0
  5. package/dist/esm/import-protection/analysis.js +407 -0
  6. package/dist/esm/import-protection/analysis.js.map +1 -0
  7. package/dist/esm/{import-protection-plugin → import-protection}/ast.js +1 -1
  8. package/dist/esm/import-protection/ast.js.map +1 -0
  9. package/dist/esm/import-protection/constants.d.ts +11 -0
  10. package/dist/esm/{import-protection-plugin → import-protection}/constants.js +7 -2
  11. package/dist/esm/import-protection/constants.js.map +1 -0
  12. package/dist/esm/{import-protection-plugin → import-protection}/defaults.js +1 -1
  13. package/dist/esm/import-protection/defaults.js.map +1 -0
  14. package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.js +2 -2
  15. package/dist/esm/import-protection/extensionlessAbsoluteIdResolver.js.map +1 -0
  16. package/dist/esm/{import-protection-plugin → import-protection}/matchers.js +1 -1
  17. package/dist/esm/import-protection/matchers.js.map +1 -0
  18. package/dist/esm/{import-protection-plugin/rewriteDeniedImports.d.ts → import-protection/rewrite.d.ts} +0 -4
  19. package/dist/esm/import-protection/rewrite.js +121 -0
  20. package/dist/esm/import-protection/rewrite.js.map +1 -0
  21. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.d.ts +32 -3
  22. package/dist/esm/{import-protection-plugin → import-protection}/sourceLocation.js +65 -10
  23. package/dist/esm/import-protection/sourceLocation.js.map +1 -0
  24. package/dist/esm/{import-protection-plugin → import-protection}/trace.d.ts +0 -1
  25. package/dist/esm/{import-protection-plugin → import-protection}/trace.js +1 -1
  26. package/dist/esm/import-protection/trace.js.map +1 -0
  27. package/dist/esm/{import-protection-plugin → import-protection}/utils.d.ts +18 -1
  28. package/dist/esm/{import-protection-plugin → import-protection}/utils.js +13 -20
  29. package/dist/esm/import-protection/utils.js.map +1 -0
  30. package/dist/esm/import-protection/virtualModules.d.ts +25 -0
  31. package/dist/esm/{import-protection-plugin → import-protection}/virtualModules.js +5 -117
  32. package/dist/esm/import-protection/virtualModules.js.map +1 -0
  33. package/dist/esm/index.d.ts +1 -5
  34. package/dist/esm/index.js +2 -4
  35. package/dist/esm/post-build.d.ts +9 -0
  36. package/dist/esm/post-build.js +37 -0
  37. package/dist/esm/post-build.js.map +1 -0
  38. package/dist/esm/prerender.d.ts +11 -0
  39. package/dist/esm/prerender.js +159 -0
  40. package/dist/esm/prerender.js.map +1 -0
  41. package/dist/esm/rsbuild/dev-server.d.ts +21 -0
  42. package/dist/esm/rsbuild/dev-server.js +76 -0
  43. package/dist/esm/rsbuild/dev-server.js.map +1 -0
  44. package/dist/esm/rsbuild/import-protection.d.ts +10 -0
  45. package/dist/esm/rsbuild/import-protection.js +775 -0
  46. package/dist/esm/rsbuild/import-protection.js.map +1 -0
  47. package/dist/esm/rsbuild/index.d.ts +4 -0
  48. package/dist/esm/rsbuild/index.js +3 -0
  49. package/dist/esm/rsbuild/normalized-client-build.d.ts +18 -0
  50. package/dist/esm/rsbuild/normalized-client-build.js +207 -0
  51. package/dist/esm/rsbuild/normalized-client-build.js.map +1 -0
  52. package/dist/esm/rsbuild/planning.d.ts +52 -0
  53. package/dist/esm/rsbuild/planning.js +108 -0
  54. package/dist/esm/rsbuild/planning.js.map +1 -0
  55. package/dist/esm/rsbuild/plugin.d.ts +4 -0
  56. package/dist/esm/rsbuild/plugin.js +344 -0
  57. package/dist/esm/rsbuild/plugin.js.map +1 -0
  58. package/dist/esm/rsbuild/post-build.d.ts +6 -0
  59. package/dist/esm/rsbuild/post-build.js +57 -0
  60. package/dist/esm/rsbuild/post-build.js.map +1 -0
  61. package/dist/esm/rsbuild/schema.d.ts +3372 -0
  62. package/dist/esm/rsbuild/schema.js +12 -0
  63. package/dist/esm/rsbuild/schema.js.map +1 -0
  64. package/dist/esm/rsbuild/start-compiler-host.d.ts +20 -0
  65. package/dist/esm/rsbuild/start-compiler-host.js +150 -0
  66. package/dist/esm/rsbuild/start-compiler-host.js.map +1 -0
  67. package/dist/esm/rsbuild/start-router-plugin.d.ts +18 -0
  68. package/dist/esm/rsbuild/start-router-plugin.js +63 -0
  69. package/dist/esm/rsbuild/start-router-plugin.js.map +1 -0
  70. package/dist/esm/rsbuild/swc-rsc.d.ts +14 -0
  71. package/dist/esm/rsbuild/swc-rsc.js +93 -0
  72. package/dist/esm/rsbuild/swc-rsc.js.map +1 -0
  73. package/dist/esm/rsbuild/types.d.ts +17 -0
  74. package/dist/esm/rsbuild/types.js +0 -0
  75. package/dist/esm/rsbuild/virtual-modules.d.ts +53 -0
  76. package/dist/esm/rsbuild/virtual-modules.js +287 -0
  77. package/dist/esm/rsbuild/virtual-modules.js.map +1 -0
  78. package/dist/esm/schema.d.ts +43 -43
  79. package/dist/esm/start-compiler/compiler.d.ts +1 -1
  80. package/dist/esm/start-compiler/compiler.js +80 -9
  81. package/dist/esm/start-compiler/compiler.js.map +1 -1
  82. package/dist/esm/start-compiler/handleCreateServerFn.js +9 -0
  83. package/dist/esm/start-compiler/handleCreateServerFn.js.map +1 -1
  84. package/dist/esm/start-compiler/host.js +5 -1
  85. package/dist/esm/start-compiler/host.js.map +1 -1
  86. package/dist/esm/start-compiler/types.d.ts +1 -0
  87. package/dist/esm/utils.d.ts +1 -0
  88. package/dist/esm/utils.js +10 -1
  89. package/dist/esm/utils.js.map +1 -1
  90. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.js +41 -92
  91. package/dist/esm/vite/import-protection-plugin/plugin.js.map +1 -0
  92. package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/types.d.ts +5 -5
  93. package/dist/esm/vite/import-protection-plugin/virtualModules.d.ts +8 -0
  94. package/dist/esm/vite/import-protection-plugin/virtualModules.js +49 -0
  95. package/dist/esm/vite/import-protection-plugin/virtualModules.js.map +1 -0
  96. package/dist/esm/vite/index.d.ts +5 -0
  97. package/dist/esm/vite/index.js +4 -0
  98. package/dist/esm/vite/plugin.js +1 -1
  99. package/dist/esm/vite/plugin.js.map +1 -1
  100. package/dist/esm/vite/post-server-build.js +14 -32
  101. package/dist/esm/vite/post-server-build.js.map +1 -1
  102. package/dist/esm/vite/prerender.d.ts +2 -2
  103. package/dist/esm/vite/prerender.js +17 -147
  104. package/dist/esm/vite/prerender.js.map +1 -1
  105. package/dist/esm/vite/schema.d.ts +23 -23
  106. package/dist/esm/vite/start-compiler-plugin/hot-update.d.ts +2 -0
  107. package/dist/esm/vite/start-compiler-plugin/hot-update.js +16 -0
  108. package/dist/esm/vite/start-compiler-plugin/hot-update.js.map +1 -0
  109. package/dist/esm/vite/start-compiler-plugin/module-specifier.js +9 -4
  110. package/dist/esm/vite/start-compiler-plugin/module-specifier.js.map +1 -1
  111. package/dist/esm/vite/start-compiler-plugin/plugin.js +86 -13
  112. package/dist/esm/vite/start-compiler-plugin/plugin.js.map +1 -1
  113. package/package.json +32 -4
  114. package/src/import-protection/INTERNALS.md +266 -0
  115. package/src/import-protection/adapterUtils.ts +94 -0
  116. package/src/import-protection/analysis.ts +853 -0
  117. package/src/{import-protection-plugin → import-protection}/constants.ts +7 -0
  118. package/src/import-protection/rewrite.ts +229 -0
  119. package/src/{import-protection-plugin → import-protection}/sourceLocation.ts +125 -9
  120. package/src/{import-protection-plugin → import-protection}/trace.ts +0 -1
  121. package/src/{import-protection-plugin → import-protection}/utils.ts +36 -21
  122. package/src/{import-protection-plugin → import-protection}/virtualModules.ts +30 -177
  123. package/src/index.ts +1 -8
  124. package/src/post-build.ts +64 -0
  125. package/src/prerender.ts +292 -0
  126. package/src/rsbuild/INTERNALS-import-protection.md +169 -0
  127. package/src/rsbuild/dev-server.ts +129 -0
  128. package/src/rsbuild/import-protection.ts +1599 -0
  129. package/src/rsbuild/index.ts +4 -0
  130. package/src/rsbuild/normalized-client-build.ts +346 -0
  131. package/src/rsbuild/planning.ts +234 -0
  132. package/src/rsbuild/plugin.ts +754 -0
  133. package/src/rsbuild/post-build.ts +96 -0
  134. package/src/rsbuild/schema.ts +31 -0
  135. package/src/rsbuild/start-compiler-host.ts +250 -0
  136. package/src/rsbuild/start-router-plugin.ts +86 -0
  137. package/src/rsbuild/swc-rsc.ts +166 -0
  138. package/src/rsbuild/types.ts +20 -0
  139. package/src/rsbuild/virtual-modules.ts +565 -0
  140. package/src/start-compiler/compiler.ts +153 -19
  141. package/src/start-compiler/handleCreateServerFn.ts +18 -0
  142. package/src/start-compiler/types.ts +1 -0
  143. package/src/utils.ts +14 -0
  144. package/src/vite/import-protection-plugin/INTERNALS.md +187 -0
  145. package/src/{import-protection-plugin → vite/import-protection-plugin}/plugin.ts +73 -158
  146. package/src/{import-protection-plugin → vite/import-protection-plugin}/types.ts +5 -5
  147. package/src/vite/import-protection-plugin/virtualModules.ts +122 -0
  148. package/src/vite/index.ts +8 -0
  149. package/src/vite/plugin.ts +1 -1
  150. package/src/vite/post-server-build.ts +14 -57
  151. package/src/vite/prerender.ts +19 -260
  152. package/src/vite/start-compiler-plugin/hot-update.ts +24 -0
  153. package/src/vite/start-compiler-plugin/module-specifier.ts +15 -5
  154. package/src/vite/start-compiler-plugin/plugin.ts +193 -18
  155. package/dist/esm/import-protection-plugin/ast.js.map +0 -1
  156. package/dist/esm/import-protection-plugin/constants.d.ts +0 -6
  157. package/dist/esm/import-protection-plugin/constants.js.map +0 -1
  158. package/dist/esm/import-protection-plugin/defaults.js.map +0 -1
  159. package/dist/esm/import-protection-plugin/extensionlessAbsoluteIdResolver.js.map +0 -1
  160. package/dist/esm/import-protection-plugin/matchers.js.map +0 -1
  161. package/dist/esm/import-protection-plugin/plugin.js.map +0 -1
  162. package/dist/esm/import-protection-plugin/postCompileUsage.d.ts +0 -13
  163. package/dist/esm/import-protection-plugin/postCompileUsage.js +0 -63
  164. package/dist/esm/import-protection-plugin/postCompileUsage.js.map +0 -1
  165. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js +0 -205
  166. package/dist/esm/import-protection-plugin/rewriteDeniedImports.js.map +0 -1
  167. package/dist/esm/import-protection-plugin/sourceLocation.js.map +0 -1
  168. package/dist/esm/import-protection-plugin/trace.js.map +0 -1
  169. package/dist/esm/import-protection-plugin/utils.js.map +0 -1
  170. package/dist/esm/import-protection-plugin/virtualModules.d.ts +0 -78
  171. package/dist/esm/import-protection-plugin/virtualModules.js.map +0 -1
  172. package/dist/esm/start-compiler/load-module.d.ts +0 -14
  173. package/dist/esm/start-compiler/load-module.js +0 -18
  174. package/dist/esm/start-compiler/load-module.js.map +0 -1
  175. package/src/import-protection-plugin/INTERNALS.md +0 -700
  176. package/src/import-protection-plugin/postCompileUsage.ts +0 -100
  177. package/src/import-protection-plugin/rewriteDeniedImports.ts +0 -379
  178. package/src/start-compiler/load-module.ts +0 -31
  179. /package/dist/esm/{import-protection-plugin → import-protection}/ast.d.ts +0 -0
  180. /package/dist/esm/{import-protection-plugin → import-protection}/defaults.d.ts +0 -0
  181. /package/dist/esm/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.d.ts +0 -0
  182. /package/dist/esm/{import-protection-plugin → import-protection}/matchers.d.ts +0 -0
  183. /package/dist/esm/{import-protection-plugin → vite/import-protection-plugin}/plugin.d.ts +0 -0
  184. /package/src/{import-protection-plugin → import-protection}/ast.ts +0 -0
  185. /package/src/{import-protection-plugin → import-protection}/defaults.ts +0 -0
  186. /package/src/{import-protection-plugin → import-protection}/extensionlessAbsoluteIdResolver.ts +0 -0
  187. /package/src/{import-protection-plugin → import-protection}/matchers.ts +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"postCompileUsage.js","names":[],"sources":["../../../src/import-protection-plugin/postCompileUsage.ts"],"sourcesContent":["import babel from '@babel/core'\nimport * as t from '@babel/types'\nimport { parseImportProtectionAst } from './ast'\nimport type { ParsedAst } from './ast'\n\ntype UsagePos = { line: number; column0: number }\n\n/**\n * Given transformed code, returns the first \"meaningful\" usage position for an\n * import from `source` that survives compilation.\n *\n * \"Preferred\" positions (call, new, member-access) take priority over bare\n * identifier references. The returned column is 0-based (Babel loc semantics).\n */\nexport function findPostCompileUsagePos(\n code: string,\n source: string,\n): UsagePos | undefined {\n return findPostCompileUsagePosFromAst(parseImportProtectionAst(code), source)\n}\n\nfunction findPostCompileUsagePosFromAst(\n ast: ParsedAst,\n source: string,\n): UsagePos | undefined {\n // Collect local names bound from this specifier\n const imported = new Set<string>()\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node) && node.source.value === source) {\n if (node.importKind === 'type') continue\n for (const s of node.specifiers) {\n if (t.isImportSpecifier(s) && s.importKind === 'type') continue\n imported.add(s.local.name)\n }\n }\n }\n if (imported.size === 0) return undefined\n\n let preferred: UsagePos | undefined\n let anyUsage: UsagePos | undefined\n\n // babel.traverse can throw on malformed scopes (e.g. duplicate bindings from\n // import + const re-declaration) because parseAst doesn't attach a hub\n try {\n babel.traverse(ast, {\n ImportDeclaration(path) {\n path.skip()\n },\n\n Identifier(path: babel.NodePath<t.Identifier>) {\n if (preferred && anyUsage) {\n path.stop()\n return\n }\n\n const { node, parent, scope } = path\n if (!imported.has(node.name)) return\n\n // Skip binding positions (declarations, import specifiers, etc.)\n if (path.isBindingIdentifier()) return\n\n // Skip non-shorthand object property keys — they don't reference the import\n if (\n t.isObjectProperty(parent) &&\n parent.key === node &&\n !parent.computed &&\n !parent.shorthand\n )\n return\n if (t.isObjectMethod(parent) && parent.key === node && !parent.computed)\n return\n if (t.isExportSpecifier(parent) && parent.exported === node) return\n\n // Skip if shadowed by a closer binding\n const binding = scope.getBinding(node.name)\n if (binding && binding.kind !== 'module') return\n\n const loc = node.loc?.start\n if (!loc) return\n const pos: UsagePos = { line: loc.line, column0: loc.column }\n\n const isPreferred =\n (t.isCallExpression(parent) && parent.callee === node) ||\n (t.isNewExpression(parent) && parent.callee === node) ||\n (t.isMemberExpression(parent) && parent.object === node)\n\n if (isPreferred) {\n preferred ||= pos\n } else {\n anyUsage ||= pos\n }\n },\n })\n } catch {\n // Scope analysis failed — cannot determine usage positions reliably\n return undefined\n }\n\n return preferred ?? anyUsage\n}\n"],"mappings":";;;;;;;;;;;AAcA,SAAgB,wBACd,MACA,QACsB;AACtB,QAAO,+BAA+B,yBAAyB,KAAK,EAAE,OAAO;;AAG/E,SAAS,+BACP,KACA,QACsB;CAEtB,MAAM,2BAAW,IAAI,KAAa;AAClC,MAAK,MAAM,QAAQ,IAAI,QAAQ,KAC7B,KAAI,EAAE,oBAAoB,KAAK,IAAI,KAAK,OAAO,UAAU,QAAQ;AAC/D,MAAI,KAAK,eAAe,OAAQ;AAChC,OAAK,MAAM,KAAK,KAAK,YAAY;AAC/B,OAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,eAAe,OAAQ;AACvD,YAAS,IAAI,EAAE,MAAM,KAAK;;;AAIhC,KAAI,SAAS,SAAS,EAAG,QAAO,KAAA;CAEhC,IAAI;CACJ,IAAI;AAIJ,KAAI;AACF,QAAM,SAAS,KAAK;GAClB,kBAAkB,MAAM;AACtB,SAAK,MAAM;;GAGb,WAAW,MAAoC;AAC7C,QAAI,aAAa,UAAU;AACzB,UAAK,MAAM;AACX;;IAGF,MAAM,EAAE,MAAM,QAAQ,UAAU;AAChC,QAAI,CAAC,SAAS,IAAI,KAAK,KAAK,CAAE;AAG9B,QAAI,KAAK,qBAAqB,CAAE;AAGhC,QACE,EAAE,iBAAiB,OAAO,IAC1B,OAAO,QAAQ,QACf,CAAC,OAAO,YACR,CAAC,OAAO,UAER;AACF,QAAI,EAAE,eAAe,OAAO,IAAI,OAAO,QAAQ,QAAQ,CAAC,OAAO,SAC7D;AACF,QAAI,EAAE,kBAAkB,OAAO,IAAI,OAAO,aAAa,KAAM;IAG7D,MAAM,UAAU,MAAM,WAAW,KAAK,KAAK;AAC3C,QAAI,WAAW,QAAQ,SAAS,SAAU;IAE1C,MAAM,MAAM,KAAK,KAAK;AACtB,QAAI,CAAC,IAAK;IACV,MAAM,MAAgB;KAAE,MAAM,IAAI;KAAM,SAAS,IAAI;KAAQ;AAO7D,QAJG,EAAE,iBAAiB,OAAO,IAAI,OAAO,WAAW,QAChD,EAAE,gBAAgB,OAAO,IAAI,OAAO,WAAW,QAC/C,EAAE,mBAAmB,OAAO,IAAI,OAAO,WAAW,KAGnD,eAAc;QAEd,cAAa;;GAGlB,CAAC;SACI;AAEN;;AAGF,QAAO,aAAa"}
@@ -1,205 +0,0 @@
1
- import { getOrCreate } from "./utils.js";
2
- import { MOCK_MODULE_ID } from "./virtualModules.js";
3
- import { parseImportProtectionAst } from "./ast.js";
4
- import * as t from "@babel/types";
5
- import { generateFromAst } from "@tanstack/router-utils";
6
- //#region src/import-protection-plugin/rewriteDeniedImports.ts
7
- function isValidExportName(name) {
8
- if (name === "default" || name.length === 0) return false;
9
- const first = name.charCodeAt(0);
10
- if (!(first >= 65 && first <= 90 || first >= 97 && first <= 122 || first === 95 || first === 36)) return false;
11
- for (let i = 1; i < name.length; i++) {
12
- const ch = name.charCodeAt(i);
13
- if (!(ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch >= 48 && ch <= 57 || ch === 95 || ch === 36)) return false;
14
- }
15
- return true;
16
- }
17
- function collectMockExportNamesBySource(code) {
18
- return collectMockExportNamesBySourceFromAst(parseImportProtectionAst(code));
19
- }
20
- function collectMockExportNamesBySourceFromAst(ast) {
21
- const namesBySource = /* @__PURE__ */ new Map();
22
- const memberBindingToSource = /* @__PURE__ */ new Map();
23
- const add = (source, name) => {
24
- if (name === "default" || name.length === 0) return;
25
- getOrCreate(namesBySource, source, () => /* @__PURE__ */ new Set()).add(name);
26
- };
27
- for (const node of ast.program.body) {
28
- if (t.isImportDeclaration(node)) {
29
- if (node.importKind === "type") continue;
30
- const source = node.source.value;
31
- for (const s of node.specifiers) {
32
- if (t.isImportNamespaceSpecifier(s)) {
33
- memberBindingToSource.set(s.local.name, source);
34
- continue;
35
- }
36
- if (t.isImportDefaultSpecifier(s)) {
37
- memberBindingToSource.set(s.local.name, source);
38
- continue;
39
- }
40
- if (!t.isImportSpecifier(s)) continue;
41
- if (s.importKind === "type") continue;
42
- const importedName = t.isIdentifier(s.imported) ? s.imported.name : s.imported.value;
43
- if (importedName === "default") continue;
44
- add(source, importedName);
45
- }
46
- }
47
- if (t.isExportNamedDeclaration(node) && node.source?.value) {
48
- if (node.exportKind === "type") continue;
49
- const source = node.source.value;
50
- for (const s of node.specifiers) {
51
- if (!t.isExportSpecifier(s)) continue;
52
- if (s.exportKind === "type") continue;
53
- add(source, s.local.name);
54
- }
55
- }
56
- }
57
- if (memberBindingToSource.size > 0) {
58
- const visit = (node) => {
59
- if (t.isMemberExpression(node)) {
60
- const object = node.object;
61
- if (t.isIdentifier(object)) {
62
- const source = memberBindingToSource.get(object.name);
63
- if (source) {
64
- const property = node.property;
65
- if (!node.computed && t.isIdentifier(property)) add(source, property.name);
66
- else if (node.computed && t.isStringLiteral(property)) add(source, property.value);
67
- }
68
- }
69
- }
70
- const keys = t.VISITOR_KEYS[node.type];
71
- if (!keys) return;
72
- for (const key of keys) {
73
- const child = node[key];
74
- if (Array.isArray(child)) {
75
- for (const item of child) if (item && typeof item === "object" && "type" in item) visit(item);
76
- } else if (child && typeof child === "object" && "type" in child) visit(child);
77
- }
78
- };
79
- visit(ast.program);
80
- }
81
- const out = /* @__PURE__ */ new Map();
82
- for (const [source, set] of namesBySource) out.set(source, Array.from(set).sort());
83
- return out;
84
- }
85
- /** Collect all valid named export identifiers from the given code. */
86
- function collectNamedExports(code) {
87
- return collectNamedExportsFromAst(parseImportProtectionAst(code));
88
- }
89
- function collectIdentifiersFromPattern(pattern, add) {
90
- if (t.isIdentifier(pattern)) add(pattern.name);
91
- else if (t.isObjectPattern(pattern)) for (const prop of pattern.properties) if (t.isRestElement(prop)) collectIdentifiersFromPattern(prop.argument, add);
92
- else collectIdentifiersFromPattern(prop.value, add);
93
- else if (t.isArrayPattern(pattern)) {
94
- for (const elem of pattern.elements) if (elem) collectIdentifiersFromPattern(elem, add);
95
- } else if (t.isAssignmentPattern(pattern)) collectIdentifiersFromPattern(pattern.left, add);
96
- else if (t.isRestElement(pattern)) collectIdentifiersFromPattern(pattern.argument, add);
97
- }
98
- function collectNamedExportsFromAst(ast) {
99
- const names = /* @__PURE__ */ new Set();
100
- const add = (name) => {
101
- if (isValidExportName(name)) names.add(name);
102
- };
103
- for (const node of ast.program.body) if (t.isExportNamedDeclaration(node)) {
104
- if (node.exportKind === "type") continue;
105
- if (node.declaration) {
106
- const decl = node.declaration;
107
- if (t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) {
108
- if (decl.id?.name) add(decl.id.name);
109
- } else if (t.isVariableDeclaration(decl)) for (const d of decl.declarations) collectIdentifiersFromPattern(d.id, add);
110
- }
111
- for (const s of node.specifiers) {
112
- if (!t.isExportSpecifier(s)) continue;
113
- if (s.exportKind === "type") continue;
114
- add(t.isIdentifier(s.exported) ? s.exported.name : s.exported.value);
115
- }
116
- }
117
- return Array.from(names).sort();
118
- }
119
- /**
120
- * Rewrite static imports/re-exports from denied sources using Babel AST transforms.
121
- *
122
- * Transforms:
123
- * import { a as b, c } from 'denied'
124
- * Into:
125
- * import __tss_deny_0 from 'tanstack-start-import-protection:mock'
126
- * const b = __tss_deny_0.a
127
- * const c = __tss_deny_0.c
128
- *
129
- * Also handles:
130
- * import def from 'denied' -> import def from mock
131
- * import * as ns from 'denied' -> import ns from mock
132
- * export { x } from 'denied' -> export const x = mock.x
133
- * export * from 'denied' -> removed
134
- * export { x as y } from 'denied' -> export const y = mock.x
135
- */
136
- function rewriteDeniedImports(code, id, deniedSources, getMockModuleId = () => MOCK_MODULE_ID) {
137
- return rewriteDeniedImportsFromAst(parseImportProtectionAst(code), id, deniedSources, getMockModuleId);
138
- }
139
- function rewriteDeniedImportsFromAst(ast, id, deniedSources, getMockModuleId = () => MOCK_MODULE_ID) {
140
- let modified = false;
141
- let mockCounter = 0;
142
- for (let i = ast.program.body.length - 1; i >= 0; i--) {
143
- const node = ast.program.body[i];
144
- if (t.isImportDeclaration(node)) {
145
- if (node.importKind === "type") continue;
146
- if (!deniedSources.has(node.source.value)) continue;
147
- const mockVar = `__tss_deny_${mockCounter++}`;
148
- const replacements = [];
149
- replacements.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(mockVar))], t.stringLiteral(getMockModuleId(node.source.value))));
150
- for (const specifier of node.specifiers) if (t.isImportDefaultSpecifier(specifier) || t.isImportNamespaceSpecifier(specifier)) replacements.push(t.variableDeclaration("const", [t.variableDeclarator(t.identifier(specifier.local.name), t.identifier(mockVar))]));
151
- else if (t.isImportSpecifier(specifier)) {
152
- if (specifier.importKind === "type") continue;
153
- const importedName = t.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value;
154
- replacements.push(t.variableDeclaration("const", [t.variableDeclarator(t.identifier(specifier.local.name), t.memberExpression(t.identifier(mockVar), t.identifier(importedName)))]));
155
- }
156
- ast.program.body.splice(i, 1, ...replacements);
157
- modified = true;
158
- continue;
159
- }
160
- if (t.isExportNamedDeclaration(node) && node.source) {
161
- if (node.exportKind === "type") continue;
162
- if (!deniedSources.has(node.source.value)) continue;
163
- const mockVar = `__tss_deny_${mockCounter++}`;
164
- const replacements = [];
165
- replacements.push(t.importDeclaration([t.importDefaultSpecifier(t.identifier(mockVar))], t.stringLiteral(getMockModuleId(node.source.value))));
166
- const exportSpecifiers = [];
167
- for (const specifier of node.specifiers) if (t.isExportSpecifier(specifier)) {
168
- if (specifier.exportKind === "type") continue;
169
- const localName = specifier.local.name;
170
- const exportedName = t.isIdentifier(specifier.exported) ? specifier.exported.name : specifier.exported.value;
171
- const internalVar = `__tss_reexport_${localName}`;
172
- replacements.push(t.variableDeclaration("const", [t.variableDeclarator(t.identifier(internalVar), t.memberExpression(t.identifier(mockVar), t.identifier(localName)))]));
173
- exportSpecifiers.push({
174
- localName: internalVar,
175
- exportedName
176
- });
177
- }
178
- if (exportSpecifiers.length > 0) replacements.push(t.exportNamedDeclaration(null, exportSpecifiers.map((s) => t.exportSpecifier(t.identifier(s.localName), t.identifier(s.exportedName)))));
179
- ast.program.body.splice(i, 1, ...replacements);
180
- modified = true;
181
- continue;
182
- }
183
- if (t.isExportAllDeclaration(node)) {
184
- if (node.exportKind === "type") continue;
185
- if (!deniedSources.has(node.source.value)) continue;
186
- ast.program.body.splice(i, 1);
187
- modified = true;
188
- continue;
189
- }
190
- }
191
- if (!modified) return void 0;
192
- const result = generateFromAst(ast, {
193
- sourceMaps: true,
194
- sourceFileName: id,
195
- filename: id
196
- });
197
- return {
198
- code: result.code,
199
- ...result.map ? { map: result.map } : {}
200
- };
201
- }
202
- //#endregion
203
- export { collectMockExportNamesBySource, collectNamedExports, isValidExportName, rewriteDeniedImports };
204
-
205
- //# sourceMappingURL=rewriteDeniedImports.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rewriteDeniedImports.js","names":[],"sources":["../../../src/import-protection-plugin/rewriteDeniedImports.ts"],"sourcesContent":["import * as t from '@babel/types'\nimport { generateFromAst } from '@tanstack/router-utils'\n\nimport { MOCK_MODULE_ID } from './virtualModules'\nimport { getOrCreate } from './utils'\nimport { parseImportProtectionAst } from './ast'\nimport type { SourceMapLike } from './sourceLocation'\nimport type { ParsedAst } from './ast'\n\nexport function isValidExportName(name: string): boolean {\n if (name === 'default' || name.length === 0) return false\n const first = name.charCodeAt(0)\n // First char: A-Z (65-90), a-z (97-122), _ (95), $ (36)\n if (\n !(\n (first >= 65 && first <= 90) ||\n (first >= 97 && first <= 122) ||\n first === 95 ||\n first === 36\n )\n )\n return false\n for (let i = 1; i < name.length; i++) {\n const ch = name.charCodeAt(i)\n // Subsequent: A-Z, a-z, 0-9 (48-57), _, $\n if (\n !(\n (ch >= 65 && ch <= 90) ||\n (ch >= 97 && ch <= 122) ||\n (ch >= 48 && ch <= 57) ||\n ch === 95 ||\n ch === 36\n )\n )\n return false\n }\n return true\n}\n\nexport function collectMockExportNamesBySource(\n code: string,\n): Map<string, Array<string>> {\n return collectMockExportNamesBySourceFromAst(parseImportProtectionAst(code))\n}\n\nfunction collectMockExportNamesBySourceFromAst(\n ast: ParsedAst,\n): Map<string, Array<string>> {\n const namesBySource = new Map<string, Set<string>>()\n const memberBindingToSource = new Map<string, string>()\n const add = (source: string, name: string) => {\n if (name === 'default' || name.length === 0) return\n getOrCreate(namesBySource, source, () => new Set<string>()).add(name)\n }\n\n for (const node of ast.program.body) {\n if (t.isImportDeclaration(node)) {\n if (node.importKind === 'type') continue\n const source = node.source.value\n for (const s of node.specifiers) {\n if (t.isImportNamespaceSpecifier(s)) {\n memberBindingToSource.set(s.local.name, source)\n continue\n }\n if (t.isImportDefaultSpecifier(s)) {\n memberBindingToSource.set(s.local.name, source)\n continue\n }\n if (!t.isImportSpecifier(s)) continue\n if (s.importKind === 'type') continue\n const importedName = t.isIdentifier(s.imported)\n ? s.imported.name\n : s.imported.value\n // `import { default as x } from 'm'` only requires a default export.\n if (importedName === 'default') continue\n add(source, importedName)\n }\n }\n\n if (t.isExportNamedDeclaration(node) && node.source?.value) {\n if (node.exportKind === 'type') continue\n const source = node.source.value\n for (const s of node.specifiers) {\n if (!t.isExportSpecifier(s)) continue\n if (s.exportKind === 'type') continue\n add(source, s.local.name)\n }\n }\n }\n\n // For namespace/default imports, collect property names used as\n // `binding.foo`/`binding?.foo` so mock-edge modules can expose explicit ESM\n // named exports required by Rolldown/native ESM.\n if (memberBindingToSource.size > 0) {\n const visit = (node: t.Node): void => {\n if (t.isMemberExpression(node)) {\n const object = node.object\n if (t.isIdentifier(object)) {\n const source = memberBindingToSource.get(object.name)\n if (source) {\n const property = node.property\n if (!node.computed && t.isIdentifier(property)) {\n add(source, property.name)\n } else if (node.computed && t.isStringLiteral(property)) {\n add(source, property.value)\n }\n }\n }\n }\n\n const keys = t.VISITOR_KEYS[node.type]\n if (!keys) return\n for (const key of keys) {\n const child = (node as unknown as Record<string, unknown>)[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === 'object' && 'type' in item) {\n visit(item as t.Node)\n }\n }\n } else if (child && typeof child === 'object' && 'type' in child) {\n visit(child as t.Node)\n }\n }\n }\n\n visit(ast.program)\n }\n\n const out = new Map<string, Array<string>>()\n for (const [source, set] of namesBySource) {\n out.set(source, Array.from(set).sort())\n }\n return out\n}\n\n/** Collect all valid named export identifiers from the given code. */\nexport function collectNamedExports(code: string): Array<string> {\n return collectNamedExportsFromAst(parseImportProtectionAst(code))\n}\n\nfunction collectIdentifiersFromPattern(\n pattern: t.LVal,\n add: (name: string) => void,\n): void {\n if (t.isIdentifier(pattern)) {\n add(pattern.name)\n } else if (t.isObjectPattern(pattern)) {\n for (const prop of pattern.properties) {\n if (t.isRestElement(prop)) {\n collectIdentifiersFromPattern(prop.argument as t.LVal, add)\n } else {\n collectIdentifiersFromPattern(prop.value as t.LVal, add)\n }\n }\n } else if (t.isArrayPattern(pattern)) {\n for (const elem of pattern.elements) {\n if (elem) collectIdentifiersFromPattern(elem as t.LVal, add)\n }\n } else if (t.isAssignmentPattern(pattern)) {\n collectIdentifiersFromPattern(pattern.left, add)\n } else if (t.isRestElement(pattern)) {\n collectIdentifiersFromPattern(pattern.argument as t.LVal, add)\n }\n}\n\nfunction collectNamedExportsFromAst(ast: ParsedAst): Array<string> {\n const names = new Set<string>()\n const add = (name: string) => {\n if (isValidExportName(name)) names.add(name)\n }\n\n for (const node of ast.program.body) {\n if (t.isExportNamedDeclaration(node)) {\n if (node.exportKind === 'type') continue\n\n if (node.declaration) {\n const decl = node.declaration\n if (t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) {\n if (decl.id?.name) add(decl.id.name)\n } else if (t.isVariableDeclaration(decl)) {\n for (const d of decl.declarations) {\n collectIdentifiersFromPattern(d.id as t.LVal, add)\n }\n }\n }\n\n for (const s of node.specifiers) {\n if (!t.isExportSpecifier(s)) continue\n if (s.exportKind === 'type') continue\n const exportedName = t.isIdentifier(s.exported)\n ? s.exported.name\n : s.exported.value\n add(exportedName)\n }\n }\n }\n\n return Array.from(names).sort()\n}\n\n/**\n * Rewrite static imports/re-exports from denied sources using Babel AST transforms.\n *\n * Transforms:\n * import { a as b, c } from 'denied'\n * Into:\n * import __tss_deny_0 from 'tanstack-start-import-protection:mock'\n * const b = __tss_deny_0.a\n * const c = __tss_deny_0.c\n *\n * Also handles:\n * import def from 'denied' -> import def from mock\n * import * as ns from 'denied' -> import ns from mock\n * export { x } from 'denied' -> export const x = mock.x\n * export * from 'denied' -> removed\n * export { x as y } from 'denied' -> export const y = mock.x\n */\nexport function rewriteDeniedImports(\n code: string,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n return rewriteDeniedImportsFromAst(\n parseImportProtectionAst(code),\n id,\n deniedSources,\n getMockModuleId,\n )\n}\n\nfunction rewriteDeniedImportsFromAst(\n ast: ParsedAst,\n id: string,\n deniedSources: Set<string>,\n getMockModuleId: (source: string) => string = () => MOCK_MODULE_ID,\n): { code: string; map?: SourceMapLike } | undefined {\n let modified = false\n let mockCounter = 0\n\n // Walk program body in reverse so splice indices stay valid\n for (let i = ast.program.body.length - 1; i >= 0; i--) {\n const node = ast.program.body[i]!\n\n if (t.isImportDeclaration(node)) {\n if (node.importKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockVar = `__tss_deny_${mockCounter++}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n\n for (const specifier of node.specifiers) {\n if (\n t.isImportDefaultSpecifier(specifier) ||\n t.isImportNamespaceSpecifier(specifier)\n ) {\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.identifier(mockVar),\n ),\n ]),\n )\n } else if (t.isImportSpecifier(specifier)) {\n if (specifier.importKind === 'type') continue\n const importedName = t.isIdentifier(specifier.imported)\n ? specifier.imported.name\n : specifier.imported.value\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(specifier.local.name),\n t.memberExpression(\n t.identifier(mockVar),\n t.identifier(importedName),\n ),\n ),\n ]),\n )\n }\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportNamedDeclaration(node) && node.source) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n const mockVar = `__tss_deny_${mockCounter++}`\n const replacements: Array<t.Statement> = []\n\n replacements.push(\n t.importDeclaration(\n [t.importDefaultSpecifier(t.identifier(mockVar))],\n t.stringLiteral(getMockModuleId(node.source.value)),\n ),\n )\n const exportSpecifiers: Array<{\n localName: string\n exportedName: string\n }> = []\n for (const specifier of node.specifiers) {\n if (t.isExportSpecifier(specifier)) {\n if (specifier.exportKind === 'type') continue\n const localName = specifier.local.name\n const exportedName = t.isIdentifier(specifier.exported)\n ? specifier.exported.name\n : specifier.exported.value\n\n const internalVar = `__tss_reexport_${localName}`\n replacements.push(\n t.variableDeclaration('const', [\n t.variableDeclarator(\n t.identifier(internalVar),\n t.memberExpression(\n t.identifier(mockVar),\n t.identifier(localName),\n ),\n ),\n ]),\n )\n exportSpecifiers.push({ localName: internalVar, exportedName })\n }\n }\n\n if (exportSpecifiers.length > 0) {\n replacements.push(\n t.exportNamedDeclaration(\n null,\n exportSpecifiers.map((s) =>\n t.exportSpecifier(\n t.identifier(s.localName),\n t.identifier(s.exportedName),\n ),\n ),\n ),\n )\n }\n\n ast.program.body.splice(i, 1, ...replacements)\n modified = true\n continue\n }\n\n if (t.isExportAllDeclaration(node)) {\n if (node.exportKind === 'type') continue\n if (!deniedSources.has(node.source.value)) continue\n\n ast.program.body.splice(i, 1)\n modified = true\n continue\n }\n }\n\n if (!modified) return undefined\n\n const result = generateFromAst(ast, {\n sourceMaps: true,\n sourceFileName: id,\n filename: id,\n })\n\n return {\n code: result.code,\n ...(result.map ? { map: result.map as SourceMapLike } : {}),\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"sourceLocation.js","names":[],"sources":["../../../src/import-protection-plugin/sourceLocation.ts"],"sourcesContent":["import { SourceMapConsumer } from 'source-map'\nimport * as path from 'pathe'\n\nimport { findPostCompileUsagePos } from './postCompileUsage'\nimport { getOrCreate, normalizeFilePath } from './utils'\nimport type { Loc } from './trace'\nimport type { RawSourceMap } from 'source-map'\n\n// Source-map type compatible with both Rollup's SourceMap and source-map's\n// RawSourceMap. Structural type avoids version: number vs string mismatch.\n\n/**\n * Minimal source-map shape used throughout the import-protection plugin.\n */\nexport interface SourceMapLike {\n file?: string\n sourceRoot?: string\n version: number | string\n sources: Array<string>\n names: Array<string>\n sourcesContent?: Array<string | null>\n mappings: string\n}\n\n// Transform result provider (replaces ctx.load() which doesn't work in dev)\nexport interface TransformResult {\n code: string\n map: SourceMapLike | undefined\n originalCode: string | undefined\n /** Precomputed line index for `code` (index → line/col). */\n lineIndex?: LineIndex\n}\n\n/**\n * Provides the transformed code and composed sourcemap for a module.\n *\n * Populated from a late-running transform hook. By the time `resolveId`\n * fires for an import, the importer has already been fully transformed.\n */\nexport interface TransformResultProvider {\n getTransformResult: (id: string) => TransformResult | undefined\n}\n\n// Index → line/column conversion\n\nexport type LineIndex = {\n offsets: Array<number>\n}\n\nexport function buildLineIndex(code: string): LineIndex {\n const offsets: Array<number> = [0]\n for (let i = 0; i < code.length; i++) {\n if (code.charCodeAt(i) === 10) {\n offsets.push(i + 1)\n }\n }\n return { offsets }\n}\n\nfunction upperBound(values: Array<number>, x: number): number {\n let lo = 0\n let hi = values.length\n while (lo < hi) {\n const mid = (lo + hi) >> 1\n if (values[mid]! <= x) lo = mid + 1\n else hi = mid\n }\n return lo\n}\n\nfunction indexToLineColWithIndex(\n lineIndex: LineIndex,\n idx: number,\n): { line: number; column0: number } {\n const offsets = lineIndex.offsets\n const ub = upperBound(offsets, idx)\n const lineIdx = Math.max(0, ub - 1)\n const line = lineIdx + 1\n\n const lineStart = offsets[lineIdx] ?? 0\n return { line, column0: Math.max(0, idx - lineStart) }\n}\n\n/**\n * Pick the most-likely original source text for `importerFile` from\n * a sourcemap that may contain multiple sources.\n */\nexport function pickOriginalCodeFromSourcesContent(\n map: SourceMapLike | undefined,\n importerFile: string,\n root: string,\n): string | undefined {\n if (!map?.sourcesContent || map.sources.length === 0) {\n return undefined\n }\n\n const file = normalizeFilePath(importerFile)\n const sourceRoot = map.sourceRoot\n const fileSeg = file.split('/').filter(Boolean)\n\n const resolveBase = sourceRoot ? path.resolve(root, sourceRoot) : root\n\n let bestIdx = -1\n let bestScore = -1\n\n for (let i = 0; i < map.sources.length; i++) {\n const content = map.sourcesContent[i]\n if (typeof content !== 'string') continue\n\n const src = map.sources[i] ?? ''\n\n const normalizedSrc = normalizeFilePath(src)\n if (normalizedSrc === file) {\n return content\n }\n\n let resolved: string\n if (!src) {\n resolved = ''\n } else if (path.isAbsolute(src)) {\n resolved = normalizeFilePath(src)\n } else {\n resolved = normalizeFilePath(path.resolve(resolveBase, src))\n }\n if (resolved === file) {\n return content\n }\n\n // Count matching path segments from the end.\n const normalizedSrcSeg = normalizedSrc.split('/').filter(Boolean)\n const resolvedSeg =\n resolved !== normalizedSrc\n ? resolved.split('/').filter(Boolean)\n : normalizedSrcSeg\n const score = Math.max(\n segmentSuffixScore(normalizedSrcSeg, fileSeg),\n segmentSuffixScore(resolvedSeg, fileSeg),\n )\n\n if (score > bestScore) {\n bestScore = score\n bestIdx = i\n }\n }\n\n if (bestIdx !== -1 && bestScore >= 1) {\n return map.sourcesContent[bestIdx] ?? undefined\n }\n\n return map.sourcesContent[0] ?? undefined\n}\n\n/** Count matching path segments from the end of `aSeg` against `bSeg`. */\nfunction segmentSuffixScore(aSeg: Array<string>, bSeg: Array<string>): number {\n let score = 0\n for (\n let i = aSeg.length - 1, j = bSeg.length - 1;\n i >= 0 && j >= 0;\n i--, j--\n ) {\n if (aSeg[i] !== bSeg[j]) break\n score++\n }\n return score\n}\n\nasync function mapGeneratedToOriginal(\n map: SourceMapLike | undefined,\n generated: { line: number; column0: number },\n fallbackFile: string,\n): Promise<Loc> {\n const fallback: Loc = {\n file: fallbackFile,\n line: generated.line,\n column: generated.column0 + 1,\n }\n\n if (!map) {\n return fallback\n }\n\n const consumer = await getSourceMapConsumer(map)\n if (!consumer) return fallback\n\n try {\n const orig = consumer.originalPositionFor({\n line: generated.line,\n column: generated.column0,\n })\n if (orig.line != null && orig.column != null) {\n return {\n file: orig.source ? normalizeFilePath(orig.source) : fallbackFile,\n line: orig.line,\n column: orig.column + 1,\n }\n }\n } catch {\n // Malformed sourcemap\n }\n\n return fallback\n}\n\nconst consumerCache = new WeakMap<object, Promise<SourceMapConsumer | null>>()\n\nfunction toRawSourceMap(map: SourceMapLike): RawSourceMap {\n return {\n ...map,\n file: map.file ?? '',\n version: Number(map.version),\n sourcesContent: map.sourcesContent?.map((s) => s ?? '') ?? [],\n }\n}\n\nasync function getSourceMapConsumer(\n map: SourceMapLike,\n): Promise<SourceMapConsumer | null> {\n const cached = consumerCache.get(map)\n if (cached) return cached\n\n const promise = (async () => {\n try {\n return await new SourceMapConsumer(toRawSourceMap(map))\n } catch {\n return null\n }\n })()\n\n consumerCache.set(map, promise)\n return promise\n}\n\nexport type ImportLocEntry = { file?: string; line: number; column: number }\n\n/**\n * Cache for import statement locations with reverse index for O(1)\n * invalidation by file. Keys: `${importerFile}::${source}`.\n */\nexport class ImportLocCache {\n private cache = new Map<string, ImportLocEntry | null>()\n private reverseIndex = new Map<string, Set<string>>()\n\n has(key: string): boolean {\n return this.cache.has(key)\n }\n\n get(key: string): ImportLocEntry | null | undefined {\n return this.cache.get(key)\n }\n\n set(key: string, value: ImportLocEntry | null): void {\n this.cache.set(key, value)\n const file = key.slice(0, key.indexOf('::'))\n getOrCreate(this.reverseIndex, file, () => new Set()).add(key)\n }\n\n clear(): void {\n this.cache.clear()\n this.reverseIndex.clear()\n }\n\n /** Remove all cache entries where the importer matches `file`. */\n deleteByFile(file: string): void {\n const keys = this.reverseIndex.get(file)\n if (keys) {\n for (const key of keys) {\n this.cache.delete(key)\n }\n this.reverseIndex.delete(file)\n }\n }\n}\n\nexport type FindImportSpecifierIndex = (code: string, source: string) => number\n\n/**\n * Find the location of an import statement in a transformed module\n * by searching the post-transform code and mapping back via sourcemap.\n * Results are cached in `importLocCache`.\n */\nexport async function findImportStatementLocationFromTransformed(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n importLocCache: ImportLocCache,\n findImportSpecifierIndex: FindImportSpecifierIndex,\n): Promise<Loc | undefined> {\n const importerFile = normalizeFilePath(importerId)\n const cacheKey = `${importerFile}::${source}`\n if (importLocCache.has(cacheKey)) {\n return importLocCache.get(cacheKey) ?? undefined\n }\n\n try {\n const res = provider.getTransformResult(importerId)\n if (!res) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const { code, map } = res\n\n const lineIndex = res.lineIndex ?? buildLineIndex(code)\n\n const idx = findImportSpecifierIndex(code, source)\n if (idx === -1) {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n\n const generated = indexToLineColWithIndex(lineIndex, idx)\n const loc = await mapGeneratedToOriginal(map, generated, importerFile)\n importLocCache.set(cacheKey, loc)\n return loc\n } catch {\n importLocCache.set(cacheKey, null)\n return undefined\n }\n}\n\n/**\n * Find the first post-compile usage location for a denied import specifier.\n * Best-effort: searches transformed code for non-import uses of imported\n * bindings and maps back to original source via sourcemap.\n */\nexport async function findPostCompileUsageLocation(\n provider: TransformResultProvider,\n importerId: string,\n source: string,\n): Promise<Loc | undefined> {\n try {\n const importerFile = normalizeFilePath(importerId)\n const res = provider.getTransformResult(importerId)\n if (!res) return undefined\n const { code, map } = res\n\n if (!res.lineIndex) {\n res.lineIndex = buildLineIndex(code)\n }\n\n const pos = findPostCompileUsagePos(code, source)\n if (!pos) return undefined\n\n return await mapGeneratedToOriginal(map, pos, importerFile)\n } catch {\n return undefined\n }\n}\n\n/**\n * Annotate each trace hop with the location of the import that created the\n * edge (file:line:col). Skips steps that already have a location.\n */\nexport async function addTraceImportLocations(\n provider: TransformResultProvider,\n trace: Array<{\n file: string\n specifier?: string\n line?: number\n column?: number\n }>,\n importLocCache: ImportLocCache,\n findImportSpecifierIndex: FindImportSpecifierIndex,\n): Promise<void> {\n for (const step of trace) {\n if (!step.specifier) continue\n if (step.line != null && step.column != null) continue\n const loc = await findImportStatementLocationFromTransformed(\n provider,\n step.file,\n step.specifier,\n importLocCache,\n findImportSpecifierIndex,\n )\n if (!loc) continue\n step.line = loc.line\n step.column = loc.column\n }\n}\n\n// Code snippet extraction (vitest-style context around a location)\n\nexport interface CodeSnippet {\n /** Source lines with line numbers, e.g. `[\" 6 | import { getSecret } from './secret.server'\", ...]` */\n lines: Array<string>\n /** The highlighted line (1-indexed original line number) */\n highlightLine: number\n /** Clickable file:line reference */\n location: string\n}\n\n/**\n * Build a vitest-style code snippet showing lines surrounding a location.\n *\n * Prefers `originalCode` from the sourcemap's sourcesContent; falls back\n * to transformed code when unavailable.\n */\nexport function buildCodeSnippet(\n provider: TransformResultProvider,\n moduleId: string,\n loc: Loc,\n contextLines: number = 2,\n): CodeSnippet | undefined {\n try {\n const importerFile = normalizeFilePath(moduleId)\n const res = provider.getTransformResult(moduleId)\n if (!res) return undefined\n\n const sourceCode = res.originalCode ?? res.code\n const targetLine = loc.line // 1-indexed\n const targetCol = loc.column // 1-indexed\n\n if (targetLine < 1) return undefined\n\n const allLines = sourceCode.split('\\n')\n // Strip trailing \\r from \\r\\n line endings\n for (let i = 0; i < allLines.length; i++) {\n const line = allLines[i]!\n if (line.endsWith('\\r')) allLines[i] = line.slice(0, -1)\n }\n\n const wantStart = Math.max(1, targetLine - contextLines)\n const wantEnd = Math.min(allLines.length, targetLine + contextLines)\n\n if (targetLine > allLines.length) return undefined\n\n const lines = allLines.slice(wantStart - 1, wantEnd)\n const gutterWidth = String(wantEnd).length\n\n const sourceFile = loc.file ?? importerFile\n const snippetLines: Array<string> = []\n for (let i = 0; i < lines.length; i++) {\n const ln = wantStart + i\n const lineContent = lines[i]!\n const lineNumStr = String(ln).padStart(gutterWidth, ' ')\n const marker = ln === targetLine ? '>' : ' '\n snippetLines.push(` ${marker} ${lineNumStr} | ${lineContent}`)\n\n if (ln === targetLine && targetCol > 0) {\n const padding = ' '.repeat(targetCol - 1)\n snippetLines.push(` ${' '.repeat(gutterWidth)} | ${padding}^`)\n }\n }\n\n return {\n lines: snippetLines,\n highlightLine: targetLine,\n location: `${sourceFile}:${targetLine}:${targetCol}`,\n }\n } catch {\n return undefined\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"trace.js","names":[],"sources":["../../../src/import-protection-plugin/trace.ts"],"sourcesContent":["import { getOrCreate, relativizePath } from './utils'\n\nexport interface TraceEdge {\n importer: string\n specifier?: string\n}\n\n/**\n * Per-environment reverse import graph.\n * Maps a resolved module id to the set of modules that import it.\n */\nexport class ImportGraph {\n /**\n * resolvedId -> Map<importer, specifier>\n *\n * We use a Map instead of a Set of objects so edges dedupe correctly.\n */\n readonly reverseEdges: Map<string, Map<string, string | undefined>> =\n new Map()\n\n /**\n * Forward-edge index: importer -> Set<resolvedId>.\n *\n * Maintained alongside reverseEdges so that {@link invalidate} can remove\n * all outgoing edges for a file in O(outgoing-edges) instead of scanning\n * every reverse-edge map in the graph.\n */\n private readonly forwardEdges: Map<string, Set<string>> = new Map()\n\n readonly entries: Set<string> = new Set()\n\n addEdge(resolved: string, importer: string, specifier?: string): void {\n getOrCreate(this.reverseEdges, resolved, () => new Map()).set(\n importer,\n specifier,\n )\n getOrCreate(this.forwardEdges, importer, () => new Set()).add(resolved)\n }\n\n /** Convenience for tests/debugging. */\n getEdges(resolved: string): Set<TraceEdge> | undefined {\n const importers = this.reverseEdges.get(resolved)\n if (!importers) return undefined\n const out = new Set<TraceEdge>()\n for (const [importer, specifier] of importers) {\n out.add({ importer, specifier })\n }\n return out\n }\n\n addEntry(id: string): void {\n this.entries.add(id)\n }\n\n clear(): void {\n this.reverseEdges.clear()\n this.forwardEdges.clear()\n this.entries.clear()\n }\n\n invalidate(id: string): void {\n // Remove all outgoing edges (id as importer) using the forward index.\n const targets = this.forwardEdges.get(id)\n if (targets) {\n for (const resolved of targets) {\n this.reverseEdges.get(resolved)?.delete(id)\n }\n this.forwardEdges.delete(id)\n }\n // Remove as a target (id as resolved module)\n this.reverseEdges.delete(id)\n }\n}\n\nexport interface TraceStep {\n file: string\n specifier?: string\n line?: number\n column?: number\n}\n\nexport interface Loc {\n file?: string\n line: number\n column: number\n}\n\n/**\n * BFS from a node upward through reverse edges to find the shortest\n * path to an entry module.\n */\nexport function buildTrace(\n graph: ImportGraph,\n startNode: string,\n maxDepth: number = 20,\n): Array<TraceStep> {\n // BFS upward (startNode -> importers -> ...)\n const visited = new Set<string>([startNode])\n const depthByNode = new Map<string, number>([[startNode, 0]])\n\n // For any importer we visit, store the \"down\" link back toward startNode.\n // importer --(specifier)--> next\n const down = new Map<string, { next: string; specifier?: string }>()\n\n const queue: Array<string> = [startNode]\n let qi = 0\n\n let root: string | null = null\n\n while (qi < queue.length) {\n const node = queue[qi++]!\n const depth = depthByNode.get(node)!\n const importers = graph.reverseEdges.get(node)\n\n if (node !== startNode) {\n const isEntry =\n graph.entries.has(node) || !importers || importers.size === 0\n if (isEntry) {\n root = node\n break\n }\n }\n\n if (depth >= maxDepth) {\n continue\n }\n\n if (!importers || importers.size === 0) {\n continue\n }\n\n for (const [importer, specifier] of importers) {\n if (visited.has(importer)) continue\n visited.add(importer)\n depthByNode.set(importer, depth + 1)\n down.set(importer, { next: node, specifier })\n queue.push(importer)\n }\n }\n\n // Best-effort: if we never found a root, just start from the original node.\n if (!root) {\n root = startNode\n }\n\n const trace: Array<TraceStep> = []\n let current = root\n for (let i = 0; i <= maxDepth + 1; i++) {\n const link = down.get(current)\n trace.push({ file: current, specifier: link?.specifier })\n if (!link) break\n current = link.next\n }\n\n return trace\n}\n\nexport interface ViolationInfo {\n env: string\n envType: 'client' | 'server'\n type: 'specifier' | 'file' | 'marker'\n behavior: 'error' | 'mock'\n pattern?: string | RegExp\n specifier: string\n importer: string\n importerLoc?: Loc\n resolved?: string\n trace: Array<TraceStep>\n message: string\n /** Vitest-style code snippet showing the offending usage in the leaf module. */\n snippet?: {\n lines: Array<string>\n highlightLine: number\n location: string\n }\n}\n\n/**\n * Suggestion strings for server-only code leaking into client environments.\n * Used by both `formatViolation` (terminal) and runtime mock modules (browser).\n */\nexport const CLIENT_ENV_SUGGESTIONS = [\n 'Use createServerFn().handler(() => ...) to keep the logic on the server and call it from the client via an RPC bridge',\n 'Use createServerOnlyFn(() => ...) to mark it as server-only (it will throw if accidentally called from the client)',\n 'Use createIsomorphicFn().client(() => ...).server(() => ...) to provide separate client and server implementations',\n 'Move the server-only import out of this file into a separate .server.ts module that is not imported by any client code',\n] as const\n\n/**\n * Suggestion strings for client-only code leaking into server environments.\n * The JSX-specific suggestion is conditionally prepended by `formatViolation`.\n */\nexport const SERVER_ENV_SUGGESTIONS = [\n 'Use createClientOnlyFn(() => ...) to mark it as client-only (returns undefined on the server)',\n 'Use createIsomorphicFn().client(() => ...).server(() => ...) to provide separate client and server implementations',\n 'Move the client-only import out of this file into a separate .client.ts module that is not imported by any server code',\n] as const\n\nexport function formatViolation(info: ViolationInfo, root: string): string {\n const rel = (p: string) => relativizePath(p, root)\n\n const relLoc = (p: string, loc?: Loc) => {\n const r = rel(p)\n const file = loc?.file ? rel(loc.file) : r\n return loc ? `${file}:${loc.line}:${loc.column}` : r\n }\n\n const relTraceStep = (step: TraceStep): string => {\n const file = rel(step.file)\n if (step.line == null) return file\n const col = step.column ?? 1\n return `${file}:${step.line}:${col}`\n }\n\n const lines: Array<string> = []\n lines.push(``)\n lines.push(`[import-protection] Import denied in ${info.envType} environment`)\n lines.push(``)\n\n if (info.type === 'specifier') {\n lines.push(` Denied by specifier pattern: ${String(info.pattern)}`)\n } else if (info.type === 'file') {\n lines.push(` Denied by file pattern: ${String(info.pattern)}`)\n } else {\n lines.push(\n ` Denied by marker: module is restricted to the opposite environment`,\n )\n }\n\n lines.push(` Importer: ${relLoc(info.importer, info.importerLoc)}`)\n lines.push(` Import: \"${rel(info.specifier)}\"`)\n if (info.resolved) {\n lines.push(` Resolved: ${rel(info.resolved)}`)\n }\n\n if (info.trace.length > 0) {\n lines.push(``)\n lines.push(` Trace:`)\n for (let i = 0; i < info.trace.length; i++) {\n const step = info.trace[i]!\n const isEntry = i === 0\n const tag = isEntry ? ' (entry)' : ''\n const spec = step.specifier ? ` (import \"${rel(step.specifier)}\")` : ''\n lines.push(` ${i + 1}. ${relTraceStep(step)}${tag}${spec}`)\n }\n }\n\n if (info.snippet) {\n lines.push(``)\n lines.push(` Code:`)\n for (const snippetLine of info.snippet.lines) {\n lines.push(snippetLine)\n }\n lines.push(``)\n lines.push(` ${rel(info.snippet.location)}`)\n }\n\n lines.push(``)\n\n // Add suggestions\n if (info.envType === 'client') {\n lines.push(` Suggestions:`)\n for (const s of CLIENT_ENV_SUGGESTIONS) {\n lines.push(` - ${s}`)\n }\n } else {\n const snippetText = info.snippet?.lines.join('\\n') ?? ''\n const looksLikeJsx =\n /<[A-Z]/.test(snippetText) ||\n (/\\{.*\\(.*\\).*\\}/.test(snippetText) && /</.test(snippetText))\n\n lines.push(` Suggestions:`)\n if (looksLikeJsx) {\n lines.push(\n ` - Wrap the JSX in <ClientOnly fallback={<Loading />}>...</ClientOnly> so it only renders in the browser after hydration`,\n )\n }\n for (const s of SERVER_ENV_SUGGESTIONS) {\n lines.push(` - ${s}`)\n }\n }\n\n lines.push(``)\n return lines.join('\\n')\n}\n"],"mappings":";;;;;;AAWA,IAAa,cAAb,MAAyB;;;;;;CAMvB,+BACE,IAAI,KAAK;;;;;;;;CASX,+BAA0D,IAAI,KAAK;CAEnE,0BAAgC,IAAI,KAAK;CAEzC,QAAQ,UAAkB,UAAkB,WAA0B;AACpE,cAAY,KAAK,cAAc,gCAAgB,IAAI,KAAK,CAAC,CAAC,IACxD,UACA,UACD;AACD,cAAY,KAAK,cAAc,gCAAgB,IAAI,KAAK,CAAC,CAAC,IAAI,SAAS;;;CAIzE,SAAS,UAA8C;EACrD,MAAM,YAAY,KAAK,aAAa,IAAI,SAAS;AACjD,MAAI,CAAC,UAAW,QAAO,KAAA;EACvB,MAAM,sBAAM,IAAI,KAAgB;AAChC,OAAK,MAAM,CAAC,UAAU,cAAc,UAClC,KAAI,IAAI;GAAE;GAAU;GAAW,CAAC;AAElC,SAAO;;CAGT,SAAS,IAAkB;AACzB,OAAK,QAAQ,IAAI,GAAG;;CAGtB,QAAc;AACZ,OAAK,aAAa,OAAO;AACzB,OAAK,aAAa,OAAO;AACzB,OAAK,QAAQ,OAAO;;CAGtB,WAAW,IAAkB;EAE3B,MAAM,UAAU,KAAK,aAAa,IAAI,GAAG;AACzC,MAAI,SAAS;AACX,QAAK,MAAM,YAAY,QACrB,MAAK,aAAa,IAAI,SAAS,EAAE,OAAO,GAAG;AAE7C,QAAK,aAAa,OAAO,GAAG;;AAG9B,OAAK,aAAa,OAAO,GAAG;;;;;;;AAqBhC,SAAgB,WACd,OACA,WACA,WAAmB,IACD;CAElB,MAAM,UAAU,IAAI,IAAY,CAAC,UAAU,CAAC;CAC5C,MAAM,cAAc,IAAI,IAAoB,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;CAI7D,MAAM,uBAAO,IAAI,KAAmD;CAEpE,MAAM,QAAuB,CAAC,UAAU;CACxC,IAAI,KAAK;CAET,IAAI,OAAsB;AAE1B,QAAO,KAAK,MAAM,QAAQ;EACxB,MAAM,OAAO,MAAM;EACnB,MAAM,QAAQ,YAAY,IAAI,KAAK;EACnC,MAAM,YAAY,MAAM,aAAa,IAAI,KAAK;AAE9C,MAAI,SAAS;OAET,MAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,aAAa,UAAU,SAAS,GACjD;AACX,WAAO;AACP;;;AAIJ,MAAI,SAAS,SACX;AAGF,MAAI,CAAC,aAAa,UAAU,SAAS,EACnC;AAGF,OAAK,MAAM,CAAC,UAAU,cAAc,WAAW;AAC7C,OAAI,QAAQ,IAAI,SAAS,CAAE;AAC3B,WAAQ,IAAI,SAAS;AACrB,eAAY,IAAI,UAAU,QAAQ,EAAE;AACpC,QAAK,IAAI,UAAU;IAAE,MAAM;IAAM;IAAW,CAAC;AAC7C,SAAM,KAAK,SAAS;;;AAKxB,KAAI,CAAC,KACH,QAAO;CAGT,MAAM,QAA0B,EAAE;CAClC,IAAI,UAAU;AACd,MAAK,IAAI,IAAI,GAAG,KAAK,WAAW,GAAG,KAAK;EACtC,MAAM,OAAO,KAAK,IAAI,QAAQ;AAC9B,QAAM,KAAK;GAAE,MAAM;GAAS,WAAW,MAAM;GAAW,CAAC;AACzD,MAAI,CAAC,KAAM;AACX,YAAU,KAAK;;AAGjB,QAAO;;;;;;AA2BT,IAAa,yBAAyB;CACpC;CACA;CACA;CACA;CACD;;;;;AAMD,IAAa,yBAAyB;CACpC;CACA;CACA;CACD;AAED,SAAgB,gBAAgB,MAAqB,MAAsB;CACzE,MAAM,OAAO,MAAc,eAAe,GAAG,KAAK;CAElD,MAAM,UAAU,GAAW,QAAc;EACvC,MAAM,IAAI,IAAI,EAAE;EAChB,MAAM,OAAO,KAAK,OAAO,IAAI,IAAI,KAAK,GAAG;AACzC,SAAO,MAAM,GAAG,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI,WAAW;;CAGrD,MAAM,gBAAgB,SAA4B;EAChD,MAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,KAAK,QAAQ,KAAM,QAAO;EAC9B,MAAM,MAAM,KAAK,UAAU;AAC3B,SAAO,GAAG,KAAK,GAAG,KAAK,KAAK,GAAG;;CAGjC,MAAM,QAAuB,EAAE;AAC/B,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,wCAAwC,KAAK,QAAQ,cAAc;AAC9E,OAAM,KAAK,GAAG;AAEd,KAAI,KAAK,SAAS,YAChB,OAAM,KAAK,kCAAkC,OAAO,KAAK,QAAQ,GAAG;UAC3D,KAAK,SAAS,OACvB,OAAM,KAAK,6BAA6B,OAAO,KAAK,QAAQ,GAAG;KAE/D,OAAM,KACJ,uEACD;AAGH,OAAM,KAAK,eAAe,OAAO,KAAK,UAAU,KAAK,YAAY,GAAG;AACpE,OAAM,KAAK,cAAc,IAAI,KAAK,UAAU,CAAC,GAAG;AAChD,KAAI,KAAK,SACP,OAAM,KAAK,eAAe,IAAI,KAAK,SAAS,GAAG;AAGjD,KAAI,KAAK,MAAM,SAAS,GAAG;AACzB,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,WAAW;AACtB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;GAC1C,MAAM,OAAO,KAAK,MAAM;GAExB,MAAM,MADU,MAAM,IACA,aAAa;GACnC,MAAM,OAAO,KAAK,YAAY,aAAa,IAAI,KAAK,UAAU,CAAC,MAAM;AACrE,SAAM,KAAK,OAAO,IAAI,EAAE,IAAI,aAAa,KAAK,GAAG,MAAM,OAAO;;;AAIlE,KAAI,KAAK,SAAS;AAChB,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,UAAU;AACrB,OAAK,MAAM,eAAe,KAAK,QAAQ,MACrC,OAAM,KAAK,YAAY;AAEzB,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,KAAK,IAAI,KAAK,QAAQ,SAAS,GAAG;;AAG/C,OAAM,KAAK,GAAG;AAGd,KAAI,KAAK,YAAY,UAAU;AAC7B,QAAM,KAAK,iBAAiB;AAC5B,OAAK,MAAM,KAAK,uBACd,OAAM,KAAK,SAAS,IAAI;QAErB;EACL,MAAM,cAAc,KAAK,SAAS,MAAM,KAAK,KAAK,IAAI;EACtD,MAAM,eACJ,SAAS,KAAK,YAAY,IACzB,iBAAiB,KAAK,YAAY,IAAI,IAAI,KAAK,YAAY;AAE9D,QAAM,KAAK,iBAAiB;AAC5B,MAAI,aACF,OAAM,KACJ,8HACD;AAEH,OAAK,MAAM,KAAK,uBACd,OAAM,KAAK,SAAS,IAAI;;AAI5B,OAAM,KAAK,GAAG;AACd,QAAO,MAAM,KAAK,KAAK"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","names":[],"sources":["../../../src/import-protection-plugin/utils.ts"],"sourcesContent":["import {\n extname,\n isAbsolute,\n relative,\n resolve as resolvePath,\n} from 'node:path'\nimport { normalizePath } from 'vite'\n\nimport {\n IMPORT_PROTECTION_DEBUG,\n IMPORT_PROTECTION_DEBUG_FILTER,\n KNOWN_SOURCE_EXTENSIONS,\n} from './constants'\n\nexport type Pattern = string | RegExp\n\nexport function dedupePatterns(patterns: Array<Pattern>): Array<Pattern> {\n const out: Array<Pattern> = []\n const seen = new Set<string>()\n for (const p of patterns) {\n const key = typeof p === 'string' ? `s:${p}` : `r:${p.toString()}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push(p)\n }\n return out\n}\n\n/** Strip both `?query` and `#hash` from a module ID. */\nexport function stripQueryAndHash(id: string): string {\n const q = id.indexOf('?')\n const h = id.indexOf('#')\n if (q === -1 && h === -1) return id\n if (q === -1) return id.slice(0, h)\n if (h === -1) return id.slice(0, q)\n return id.slice(0, Math.min(q, h))\n}\n\n/**\n * Strip Vite query/hash parameters and normalize the path in one step.\n *\n * Results are memoized because the same module IDs are processed many\n * times across resolveId, transform, and trace-building hooks.\n */\nconst normalizeFilePathCache = new Map<string, string>()\nexport function normalizeFilePath(id: string): string {\n let result = normalizeFilePathCache.get(id)\n if (result === undefined) {\n result = normalizePath(stripQueryAndHash(id))\n normalizeFilePathCache.set(id, result)\n }\n return result\n}\n\n/** Clear the memoization cache (call from buildStart to bound growth). */\nexport function clearNormalizeFilePathCache(): void {\n normalizeFilePathCache.clear()\n}\n\n/**\n * Lightweight regex to extract all import/re-export source strings from\n * post-transform code. Matches:\n * - `from \"...\"` / `from '...'` (static import/export)\n * - `import(\"...\")` / `import('...')` (dynamic import)\n */\nconst importSourceRe =\n /\\bfrom\\s+(?:\"([^\"]+)\"|'([^']+)')|import\\s*\\(\\s*(?:\"([^\"]+)\"|'([^']+)')\\s*\\)/g\n\nexport function escapeRegExp(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/** Get a value from a Map, creating it with `factory` if absent. */\nexport function getOrCreate<TKey, TValue>(\n map: Map<TKey, TValue>,\n key: TKey,\n factory: () => TValue,\n): TValue {\n let value = map.get(key)\n if (value === undefined) {\n value = factory()\n map.set(key, value)\n }\n return value\n}\n\n/** Make a path relative to `root`, keeping non-rooted paths as-is. */\nexport function relativizePath(p: string, root: string): string {\n if (!p.startsWith(root)) return p\n const ch = p.charCodeAt(root.length)\n // Must be followed by a separator or end-of-string to be a true child\n if (ch !== 47 && !Number.isNaN(ch)) return p\n return ch === 47 ? p.slice(root.length + 1) : p.slice(root.length)\n}\n\nexport function extractImportSources(code: string): Array<string> {\n const sources: Array<string> = []\n let m: RegExpExecArray | null\n importSourceRe.lastIndex = 0\n while ((m = importSourceRe.exec(code)) !== null) {\n const src = m[1] ?? m[2] ?? m[3] ?? m[4]\n if (src) sources.push(src)\n }\n return sources\n}\n\n/** Log import-protection debug output when debug mode is enabled. */\nexport function debugLog(...args: Array<unknown>): void {\n if (!IMPORT_PROTECTION_DEBUG) return\n console.warn('[import-protection:debug]', ...args)\n}\n\n/** Check if any value matches the configured debug filter (if present). */\nexport function matchesDebugFilter(...values: Array<string>): boolean {\n const debugFilter = IMPORT_PROTECTION_DEBUG_FILTER\n if (!debugFilter) return true\n return values.some((v) => v.includes(debugFilter))\n}\n\n/** Strip `?query` (but not `#hash`) from a module ID. */\nexport function stripQuery(id: string): string {\n const queryIndex = id.indexOf('?')\n return queryIndex === -1 ? id : id.slice(0, queryIndex)\n}\n\nexport function withoutKnownExtension(id: string): string {\n const ext = extname(id)\n return KNOWN_SOURCE_EXTENSIONS.has(ext) ? id.slice(0, -ext.length) : id\n}\n\n/**\n * Check whether `filePath` is contained inside `directory` using a\n * boundary-safe comparison. A naïve `filePath.startsWith(directory)`\n * would incorrectly treat `/app/src2/foo.ts` as inside `/app/src`.\n */\nexport function isInsideDirectory(\n filePath: string,\n directory: string,\n): boolean {\n const rel = relative(resolvePath(directory), resolvePath(filePath))\n return rel.length > 0 && !rel.startsWith('..') && !isAbsolute(rel)\n}\n\n/**\n * Decide whether a violation should be deferred for later verification\n * rather than reported immediately.\n *\n * Build mode: always defer — generateBundle checks tree-shaking.\n * Dev mock mode: always defer — edge-survival verifies whether the Start\n * compiler strips the import (factory-safe pattern). All violation\n * types and specifier formats are handled uniformly by the\n * edge-survival mechanism in processPendingViolations.\n * Dev error mode: never defer — throw immediately (no mock fallback).\n */\nexport function shouldDeferViolation(opts: {\n isBuild: boolean\n isDevMock: boolean\n}): boolean {\n return opts.isBuild || opts.isDevMock\n}\n\nexport function buildSourceCandidates(\n source: string,\n resolved: string | undefined,\n root: string,\n): Set<string> {\n const candidates = new Set<string>()\n const push = (value: string | undefined) => {\n if (!value) return\n candidates.add(value)\n candidates.add(stripQuery(value))\n candidates.add(withoutKnownExtension(stripQuery(value)))\n }\n\n push(source)\n if (resolved) {\n push(resolved)\n const relativeResolved = relativizePath(resolved, root)\n push(relativeResolved)\n push(`./${relativeResolved}`)\n push(`/${relativeResolved}`)\n }\n\n return candidates\n}\n\nexport function buildResolutionCandidates(id: string): Array<string> {\n const normalized = normalizeFilePath(id)\n const stripped = stripQuery(normalized)\n\n return [...new Set([id, normalized, stripped])]\n}\n\nexport function canonicalizeResolvedId(\n id: string,\n root: string,\n resolveExtensionlessAbsoluteId: (value: string) => string,\n): string {\n const stripped = stripQuery(id)\n let normalized = normalizeFilePath(stripped)\n\n if (\n !isAbsolute(normalized) &&\n !normalized.startsWith('.') &&\n !normalized.startsWith('\\0') &&\n !/^[a-zA-Z]+:/.test(normalized)\n ) {\n normalized = normalizeFilePath(resolvePath(root, normalized))\n }\n\n return resolveExtensionlessAbsoluteId(normalized)\n}\n"],"mappings":"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"}
@@ -1,78 +0,0 @@
1
- import { ViolationInfo } from './trace.js';
2
- export declare const MOCK_MODULE_ID = "tanstack-start-import-protection:mock";
3
- /**
4
- * Per-violation mock prefix used in build+error mode.
5
- * Each deferred violation gets a unique ID so we can check which ones
6
- * survived tree-shaking in `generateBundle`.
7
- */
8
- export declare const MOCK_BUILD_PREFIX = "tanstack-start-import-protection:mock:build:";
9
- export declare const MOCK_EDGE_PREFIX = "tanstack-start-import-protection:mock-edge:";
10
- export declare const MOCK_RUNTIME_PREFIX = "tanstack-start-import-protection:mock-runtime:";
11
- export declare function resolvedMarkerVirtualModuleId(kind: 'server' | 'client'): string;
12
- /**
13
- * Convenience list for plugin `load` filters/handlers.
14
- *
15
- * Vite/Rollup call `load(id)` with the *resolved* virtual id (prefixed by `\0`).
16
- * `resolveId(source)` sees the *unresolved* id/prefix (without `\0`).
17
- */
18
- export declare function getResolvedVirtualModuleMatchers(): ReadonlyArray<string>;
19
- /**
20
- * Resolve import-protection's internal virtual module IDs.
21
- *
22
- * `resolveId(source)` sees *unresolved* ids/prefixes (no `\0`).
23
- * Returning a resolved id (with `\0`) ensures Vite/Rollup route it to `load`.
24
- */
25
- export declare function resolveInternalVirtualModuleId(source: string): string | undefined;
26
- type MockAccessMode = 'error' | 'warn' | 'off';
27
- /**
28
- * Compact runtime suggestion text for browser console, derived from
29
- * {@link CLIENT_ENV_SUGGESTIONS} so there's a single source of truth.
30
- */
31
- export declare const RUNTIME_SUGGESTION_TEXT: string;
32
- export declare function mockRuntimeModuleIdFromViolation(info: ViolationInfo, mode: MockAccessMode, root: string): string;
33
- export declare function makeMockEdgeModuleId(exports: Array<string>, runtimeId: string): string;
34
- export declare function loadSilentMockModule(): {
35
- code: string;
36
- };
37
- /**
38
- * Generate a self-contained mock module with explicit named exports.
39
- *
40
- * Used by the transform hook's "self-denial" check: when a denied file
41
- * (e.g. `.server.ts` in the client environment) is transformed, its entire
42
- * content is replaced with this mock module. This avoids returning virtual
43
- * module IDs from `resolveId`, which prevents cross-environment cache
44
- * contamination from third-party resolver plugins.
45
- *
46
- * The generated code is side-effect-free and tree-shakeable.
47
- */
48
- export declare function generateSelfContainedMockModule(exportNames: Array<string>): {
49
- code: string;
50
- };
51
- /**
52
- * Generate a dev-mode mock module for self-denial transforms.
53
- *
54
- * Similar to `loadMockEdgeModule` but takes export names and a runtime ID
55
- * directly (instead of parsing them from a base64url-encoded payload).
56
- * Used by the transform hook when a denied file (e.g. `.server.ts` in
57
- * the client environment) is replaced in dev mode.
58
- *
59
- * The generated module imports mock-runtime for runtime diagnostics
60
- * (error/warn on property access) and re-exports explicit named exports
61
- * so that `import { foo } from './denied.server'` works.
62
- */
63
- export declare function generateDevSelfDenialModule(exportNames: Array<string>, runtimeId: string): {
64
- code: string;
65
- };
66
- export declare function loadMockEdgeModule(encodedPayload: string): {
67
- code: string;
68
- };
69
- export declare function loadMockRuntimeModule(encodedPayload: string): {
70
- code: string;
71
- };
72
- export declare function loadMarkerModule(): {
73
- code: string;
74
- };
75
- export declare function loadResolvedVirtualModule(id: string): {
76
- code: string;
77
- } | undefined;
78
- export {};
@@ -1 +0,0 @@
1
- {"version":3,"file":"virtualModules.js","names":[],"sources":["../../../src/import-protection-plugin/virtualModules.ts"],"sourcesContent":["import { resolveViteId } from '../utils'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { isValidExportName } from './rewriteDeniedImports'\nimport { CLIENT_ENV_SUGGESTIONS } from './trace'\nimport { VITE_BROWSER_VIRTUAL_PREFIX } from './constants'\nimport { relativizePath } from './utils'\nimport type { ViolationInfo } from './trace'\n\nexport const MOCK_MODULE_ID = 'tanstack-start-import-protection:mock'\nconst RESOLVED_MOCK_MODULE_ID = resolveViteId(MOCK_MODULE_ID)\n\n/**\n * Per-violation mock prefix used in build+error mode.\n * Each deferred violation gets a unique ID so we can check which ones\n * survived tree-shaking in `generateBundle`.\n */\nexport const MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:'\nconst RESOLVED_MOCK_BUILD_PREFIX = resolveViteId(MOCK_BUILD_PREFIX)\n\nexport const MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:'\nconst RESOLVED_MOCK_EDGE_PREFIX = resolveViteId(MOCK_EDGE_PREFIX)\n\nexport const MOCK_RUNTIME_PREFIX =\n 'tanstack-start-import-protection:mock-runtime:'\nconst RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX)\n\nconst MARKER_PREFIX = 'tanstack-start-import-protection:marker:'\nconst RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX)\n\nconst RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`)\nconst RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`)\n\nexport function resolvedMarkerVirtualModuleId(\n kind: 'server' | 'client',\n): string {\n return kind === 'server'\n ? RESOLVED_MARKER_SERVER_ONLY\n : RESOLVED_MARKER_CLIENT_ONLY\n}\n\n/**\n * Convenience list for plugin `load` filters/handlers.\n *\n * Vite/Rollup call `load(id)` with the *resolved* virtual id (prefixed by `\\0`).\n * `resolveId(source)` sees the *unresolved* id/prefix (without `\\0`).\n */\nexport function getResolvedVirtualModuleMatchers(): ReadonlyArray<string> {\n return RESOLVED_VIRTUAL_MODULE_MATCHERS\n}\n\nconst RESOLVED_VIRTUAL_MODULE_MATCHERS = [\n RESOLVED_MOCK_MODULE_ID,\n RESOLVED_MOCK_BUILD_PREFIX,\n RESOLVED_MOCK_EDGE_PREFIX,\n RESOLVED_MOCK_RUNTIME_PREFIX,\n RESOLVED_MARKER_PREFIX,\n] as const\n\nconst RESOLVE_PREFIX_PAIRS = [\n [MOCK_EDGE_PREFIX, RESOLVED_MOCK_EDGE_PREFIX],\n [MOCK_RUNTIME_PREFIX, RESOLVED_MOCK_RUNTIME_PREFIX],\n [MOCK_BUILD_PREFIX, RESOLVED_MOCK_BUILD_PREFIX],\n [MARKER_PREFIX, RESOLVED_MARKER_PREFIX],\n] as const\n\n/**\n * Resolve import-protection's internal virtual module IDs.\n *\n * `resolveId(source)` sees *unresolved* ids/prefixes (no `\\0`).\n * Returning a resolved id (with `\\0`) ensures Vite/Rollup route it to `load`.\n */\nexport function resolveInternalVirtualModuleId(\n source: string,\n): string | undefined {\n if (source.startsWith(VITE_BROWSER_VIRTUAL_PREFIX)) {\n return resolveInternalVirtualModuleId(\n `\\0${source.slice(VITE_BROWSER_VIRTUAL_PREFIX.length)}`,\n )\n }\n\n if (source === MOCK_MODULE_ID || source === RESOLVED_MOCK_MODULE_ID) {\n return RESOLVED_MOCK_MODULE_ID\n }\n\n for (const [unresolvedPrefix, resolvedPrefix] of RESOLVE_PREFIX_PAIRS) {\n if (source.startsWith(unresolvedPrefix)) {\n return resolveViteId(source)\n }\n\n if (source.startsWith(resolvedPrefix)) {\n return source\n }\n }\n\n return undefined\n}\n\nfunction toBase64Url(input: string): string {\n return Buffer.from(input, 'utf8').toString('base64url')\n}\n\nfunction fromBase64Url(input: string): string {\n return Buffer.from(input, 'base64url').toString('utf8')\n}\n\ntype MockAccessMode = 'error' | 'warn' | 'off'\n\n/**\n * Compact runtime suggestion text for browser console, derived from\n * {@link CLIENT_ENV_SUGGESTIONS} so there's a single source of truth.\n */\nexport const RUNTIME_SUGGESTION_TEXT =\n 'Fix: ' +\n CLIENT_ENV_SUGGESTIONS.join('. ') +\n '. To disable these runtime diagnostics, set importProtection.mockAccess: \"off\".'\n\nexport function mockRuntimeModuleIdFromViolation(\n info: ViolationInfo,\n mode: MockAccessMode,\n root: string,\n): string {\n if (mode === 'off') return MOCK_MODULE_ID\n if (info.env !== VITE_ENVIRONMENT_NAMES.client) return MOCK_MODULE_ID\n\n const rel = (p: string) => relativizePath(p, root)\n const trace = info.trace.map((s) => {\n const file = rel(s.file)\n if (s.line == null) return file\n return `${file}:${s.line}:${s.column ?? 1}`\n })\n\n const payload = {\n env: info.env,\n importer: info.importer,\n specifier: info.specifier,\n trace,\n mode,\n }\n return `${MOCK_RUNTIME_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\nexport function makeMockEdgeModuleId(\n exports: Array<string>,\n runtimeId: string,\n): string {\n const payload = { exports, runtimeId }\n return `${MOCK_EDGE_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\n/**\n * Generate a recursive Proxy-based mock module.\n *\n * When `diagnostics` is provided, the generated code includes a `__report`\n * function that logs runtime warnings/errors when the mock is actually used\n * (property access for primitive coercion, calls, construction, sets).\n *\n * When `diagnostics` is omitted, the mock is completely silent — suitable\n * for base mock modules (e.g. `MOCK_MODULE_ID` or per-violation build mocks)\n * that are consumed by mock-edge modules providing explicit named exports.\n */\nfunction generateMockCode(diagnostics?: {\n meta: {\n env: string\n importer: string\n specifier: string\n trace: Array<unknown>\n }\n mode: 'error' | 'warn' | 'off'\n}): string {\n const fnName = diagnostics ? '__createMock' : 'createMock'\n const hasDiag = !!diagnostics\n\n const preamble = hasDiag\n ? `const __meta = ${JSON.stringify(diagnostics.meta)};\nconst __mode = ${JSON.stringify(diagnostics.mode)};\n\nconst __seen = new Set();\nfunction __report(action, accessPath) {\n if (__mode === 'off') return;\n const key = action + ':' + accessPath;\n if (__seen.has(key)) return;\n __seen.add(key);\n\n const traceLines = Array.isArray(__meta.trace) && __meta.trace.length\n ? \"\\\\n\\\\nTrace:\\\\n\" + __meta.trace.map((t, i) => ' ' + (i + 1) + '. ' + String(t)).join('\\\\n')\n : '';\n\n const msg =\n '[import-protection] Mocked import used in dev client\\\\n\\\\n' +\n 'Denied import: \"' + __meta.specifier + '\"\\\\n' +\n 'Importer: ' + __meta.importer + '\\\\n' +\n 'Access: ' + accessPath + ' (' + action + ')' +\n traceLines +\n '\\\\n\\\\n' + ${JSON.stringify(RUNTIME_SUGGESTION_TEXT)};\n\n const err = new Error(msg);\n if (__mode === 'warn') {\n console.warn(err);\n } else {\n console.error(err);\n }\n}\n`\n : ''\n\n // Diagnostic-only traps for primitive coercion, set\n const diagGetTraps = hasDiag\n ? `\n if (prop === Symbol.toPrimitive) {\n return () => {\n __report('toPrimitive', name);\n return '[import-protection mock]';\n };\n }\n if (prop === 'toString' || prop === 'valueOf' || prop === 'toJSON') {\n return () => {\n __report(String(prop), name);\n return '[import-protection mock]';\n };\n }`\n : ''\n\n const applyBody = hasDiag\n ? `__report('call', name + '()');\n return ${fnName}(name + '()');`\n : `return ${fnName}(name + '()');`\n\n const constructBody = hasDiag\n ? `__report('construct', 'new ' + name);\n return ${fnName}('new ' + name);`\n : `return ${fnName}('new ' + name);`\n\n const setTrap = hasDiag\n ? `\n set(_target, prop) {\n __report('set', name + '.' + String(prop));\n return true;\n },`\n : ''\n\n return `\n${preamble}/* @__NO_SIDE_EFFECTS__ */\nfunction ${fnName}(name) {\n const fn = function () {};\n fn.prototype.name = name;\n const children = Object.create(null);\n const proxy = new Proxy(fn, {\n get(_target, prop) {\n if (prop === '__esModule') return true;\n if (prop === 'default') return proxy;\n if (prop === 'caller') return null;\n if (prop === 'then') return (f) => Promise.resolve(f(proxy));\n if (prop === 'catch') return () => Promise.resolve(proxy);\n if (prop === 'finally') return (f) => { f(); return Promise.resolve(proxy); };${diagGetTraps}\n if (typeof prop === 'symbol') return undefined;\n if (!(prop in children)) {\n children[prop] = ${fnName}(name + '.' + prop);\n }\n return children[prop];\n },\n apply() {\n ${applyBody}\n },\n construct() {\n ${constructBody}\n },${setTrap}\n });\n return proxy;\n}\nconst mock = /* @__PURE__ */ ${fnName}('mock');\nexport default mock;\n`\n}\n\nexport function loadSilentMockModule(): { code: string } {\n return { code: generateMockCode() }\n}\n\n/**\n * Filter export names to valid, non-default names.\n */\nfunction filterExportNames(exports: ReadonlyArray<string>): Array<string> {\n return exports.filter((n) => n.length > 0 && n !== 'default')\n}\n\n/**\n * Generate ESM export lines that re-export named properties from `mock`.\n *\n * Produces `export const foo = mock.foo;` for valid identifiers and\n * string-keyed re-exports for non-identifier names.\n */\nfunction generateExportLines(names: ReadonlyArray<string>): Array<string> {\n const lines: Array<string> = []\n const stringExports: Array<{ alias: string; name: string }> = []\n\n for (let i = 0; i < names.length; i++) {\n const n = names[i]!\n if (isValidExportName(n)) {\n lines.push(`export const ${n} = mock.${n};`)\n } else {\n const alias = `__tss_str_${i}`\n lines.push(`const ${alias} = mock[${JSON.stringify(n)}];`)\n stringExports.push({ alias, name: n })\n }\n }\n\n if (stringExports.length > 0) {\n const reexports = stringExports\n .map((s) => `${s.alias} as ${JSON.stringify(s.name)}`)\n .join(', ')\n lines.push(`export { ${reexports} };`)\n }\n\n return lines\n}\n\n/**\n * Generate a self-contained mock module with explicit named exports.\n *\n * Used by the transform hook's \"self-denial\" check: when a denied file\n * (e.g. `.server.ts` in the client environment) is transformed, its entire\n * content is replaced with this mock module. This avoids returning virtual\n * module IDs from `resolveId`, which prevents cross-environment cache\n * contamination from third-party resolver plugins.\n *\n * The generated code is side-effect-free and tree-shakeable.\n */\nexport function generateSelfContainedMockModule(exportNames: Array<string>): {\n code: string\n} {\n const mockCode = generateMockCode()\n const exportLines = generateExportLines(filterExportNames(exportNames))\n\n return {\n code: `${mockCode}\n${exportLines.join('\\n')}\n`,\n }\n}\n\n/**\n * Generate a dev-mode mock module for self-denial transforms.\n *\n * Similar to `loadMockEdgeModule` but takes export names and a runtime ID\n * directly (instead of parsing them from a base64url-encoded payload).\n * Used by the transform hook when a denied file (e.g. `.server.ts` in\n * the client environment) is replaced in dev mode.\n *\n * The generated module imports mock-runtime for runtime diagnostics\n * (error/warn on property access) and re-exports explicit named exports\n * so that `import { foo } from './denied.server'` works.\n */\nexport function generateDevSelfDenialModule(\n exportNames: Array<string>,\n runtimeId: string,\n): { code: string } {\n const names = filterExportNames(exportNames)\n const exportLines = generateExportLines(names)\n\n return {\n code: `import mock from ${JSON.stringify(runtimeId)};\n${exportLines.join('\\n')}\nexport default mock;\n`,\n }\n}\n\nexport function loadMockEdgeModule(encodedPayload: string): { code: string } {\n let payload: { exports?: Array<string>; runtimeId?: string }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = { exports: [] }\n }\n const names = filterExportNames(payload.exports ?? [])\n\n const runtimeId: string =\n typeof payload.runtimeId === 'string' && payload.runtimeId.length > 0\n ? payload.runtimeId\n : MOCK_MODULE_ID\n\n const exportLines = generateExportLines(names)\n\n return {\n code: `import mock from ${JSON.stringify(runtimeId)};\n${exportLines.join('\\n')}\nexport default mock;\n`,\n }\n}\n\nexport function loadMockRuntimeModule(encodedPayload: string): {\n code: string\n} {\n let payload: {\n mode?: string\n env?: string\n importer?: string\n specifier?: string\n trace?: Array<unknown>\n }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = {}\n }\n\n const mode: 'error' | 'warn' | 'off' =\n payload.mode === 'warn' || payload.mode === 'off' ? payload.mode : 'error'\n\n const meta = {\n env: String(payload.env ?? ''),\n importer: String(payload.importer ?? ''),\n specifier: String(payload.specifier ?? ''),\n trace: Array.isArray(payload.trace) ? payload.trace : [],\n }\n\n return { code: generateMockCode({ meta, mode }) }\n}\n\nconst MARKER_MODULE_RESULT = { code: 'export {}' } as const\n\nexport function loadMarkerModule(): { code: string } {\n return MARKER_MODULE_RESULT\n}\n\nexport function loadResolvedVirtualModule(\n id: string,\n): { code: string } | undefined {\n if (id === RESOLVED_MOCK_MODULE_ID) {\n return loadSilentMockModule()\n }\n\n // Per-violation build mock modules — same silent mock code\n if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {\n return loadSilentMockModule()\n }\n\n if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {\n return loadMockEdgeModule(id.slice(RESOLVED_MOCK_EDGE_PREFIX.length))\n }\n\n if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {\n return loadMockRuntimeModule(id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length))\n }\n\n if (id.startsWith(RESOLVED_MARKER_PREFIX)) {\n return loadMarkerModule()\n }\n\n return undefined\n}\n"],"mappings":";;;;;;;AAQA,IAAa,iBAAiB;AAC9B,IAAM,0BAA0B,cAAc,eAAe;;;;;;AAO7D,IAAa,oBAAoB;AACjC,IAAM,6BAA6B,cAAc,kBAAkB;AAEnE,IAAa,mBAAmB;AAChC,IAAM,4BAA4B,cAAc,iBAAiB;AAEjE,IAAa,sBACX;AACF,IAAM,+BAA+B,cAAc,oBAAoB;AAEvE,IAAM,gBAAgB;AACtB,IAAM,yBAAyB,cAAc,cAAc;AAE3D,IAAM,8BAA8B,cAAc,GAAG,cAAc,aAAa;AAChF,IAAM,8BAA8B,cAAc,GAAG,cAAc,aAAa;AAEhF,SAAgB,8BACd,MACQ;AACR,QAAO,SAAS,WACZ,8BACA;;;;;;;;AASN,SAAgB,mCAA0D;AACxE,QAAO;;AAGT,IAAM,mCAAmC;CACvC;CACA;CACA;CACA;CACA;CACD;AAED,IAAM,uBAAuB;CAC3B,CAAC,kBAAkB,0BAA0B;CAC7C,CAAC,qBAAqB,6BAA6B;CACnD,CAAC,mBAAmB,2BAA2B;CAC/C,CAAC,eAAe,uBAAuB;CACxC;;;;;;;AAQD,SAAgB,+BACd,QACoB;AACpB,KAAI,OAAO,WAAA,eAAuC,CAChD,QAAO,+BACL,KAAK,OAAO,MAAM,4BAA4B,OAAO,GACtD;AAGH,KAAI,WAAA,2CAA6B,WAAW,wBAC1C,QAAO;AAGT,MAAK,MAAM,CAAC,kBAAkB,mBAAmB,sBAAsB;AACrE,MAAI,OAAO,WAAW,iBAAiB,CACrC,QAAO,cAAc,OAAO;AAG9B,MAAI,OAAO,WAAW,eAAe,CACnC,QAAO;;;AAOb,SAAS,YAAY,OAAuB;AAC1C,QAAO,OAAO,KAAK,OAAO,OAAO,CAAC,SAAS,YAAY;;AAGzD,SAAS,cAAc,OAAuB;AAC5C,QAAO,OAAO,KAAK,OAAO,YAAY,CAAC,SAAS,OAAO;;;;;;AASzD,IAAa,0BACX,UACA,uBAAuB,KAAK,KAAK,GACjC;AAEF,SAAgB,iCACd,MACA,MACA,MACQ;AACR,KAAI,SAAS,MAAO,QAAO;AAC3B,KAAI,KAAK,QAAQ,uBAAuB,OAAQ,QAAO;CAEvD,MAAM,OAAO,MAAc,eAAe,GAAG,KAAK;CAClD,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAM;EAClC,MAAM,OAAO,IAAI,EAAE,KAAK;AACxB,MAAI,EAAE,QAAQ,KAAM,QAAO;AAC3B,SAAO,GAAG,KAAK,GAAG,EAAE,KAAK,GAAG,EAAE,UAAU;GACxC;CAEF,MAAM,UAAU;EACd,KAAK,KAAK;EACV,UAAU,KAAK;EACf,WAAW,KAAK;EAChB;EACA;EACD;AACD,QAAO,GAAG,sBAAsB,YAAY,KAAK,UAAU,QAAQ,CAAC;;AAGtE,SAAgB,qBACd,SACA,WACQ;CACR,MAAM,UAAU;EAAE;EAAS;EAAW;AACtC,QAAO,GAAG,mBAAmB,YAAY,KAAK,UAAU,QAAQ,CAAC;;;;;;;;;;;;;AAcnE,SAAS,iBAAiB,aAQf;CACT,MAAM,SAAS,cAAc,iBAAiB;CAC9C,MAAM,UAAU,CAAC,CAAC;AAsElB,QAAO;EApEU,UACb,kBAAkB,KAAK,UAAU,YAAY,KAAK,CAAC;iBACxC,KAAK,UAAU,YAAY,KAAK,CAAC;;;;;;;;;;;;;;;;;;;iBAmBjC,KAAK,UAAU,wBAAwB,CAAC;;;;;;;;;IAUnD,GAsCK;WACA,OAAO;;;;;;;;;;;sFApCK,UACjB;;;;;;;;;;;;WAaA,GAiC6F;;;2BAGxE,OAAO;;;;;QAlCd,UACd;eACS,OAAO,kBAChB,UAAU,OAAO,gBAoCL;;;QAlCM,UAClB;eACS,OAAO,oBAChB,UAAU,OAAO,kBAkCD;QAhCJ,UACZ;;;;UAKA,GA2BU;;;;+BAIe,OAAO;;;;AAKtC,SAAgB,uBAAyC;AACvD,QAAO,EAAE,MAAM,kBAAkB,EAAE;;;;;AAMrC,SAAS,kBAAkB,SAA+C;AACxE,QAAO,QAAQ,QAAQ,MAAM,EAAE,SAAS,KAAK,MAAM,UAAU;;;;;;;;AAS/D,SAAS,oBAAoB,OAA6C;CACxE,MAAM,QAAuB,EAAE;CAC/B,MAAM,gBAAwD,EAAE;AAEhE,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,IAAI,MAAM;AAChB,MAAI,kBAAkB,EAAE,CACtB,OAAM,KAAK,gBAAgB,EAAE,UAAU,EAAE,GAAG;OACvC;GACL,MAAM,QAAQ,aAAa;AAC3B,SAAM,KAAK,SAAS,MAAM,UAAU,KAAK,UAAU,EAAE,CAAC,IAAI;AAC1D,iBAAc,KAAK;IAAE;IAAO,MAAM;IAAG,CAAC;;;AAI1C,KAAI,cAAc,SAAS,GAAG;EAC5B,MAAM,YAAY,cACf,KAAK,MAAM,GAAG,EAAE,MAAM,MAAM,KAAK,UAAU,EAAE,KAAK,GAAG,CACrD,KAAK,KAAK;AACb,QAAM,KAAK,YAAY,UAAU,KAAK;;AAGxC,QAAO;;;;;;;;;;;;;AAcT,SAAgB,gCAAgC,aAE9C;AAIA,QAAO,EACL,MAAM,GAJS,kBAAkB,CAIf;EAHA,oBAAoB,kBAAkB,YAAY,CAAC,CAI3D,KAAK,KAAK,CAAC;GAEtB;;;;;;;;;;;;;;AAeH,SAAgB,4BACd,aACA,WACkB;CAElB,MAAM,cAAc,oBADN,kBAAkB,YAAY,CACE;AAE9C,QAAO,EACL,MAAM,oBAAoB,KAAK,UAAU,UAAU,CAAC;EACtD,YAAY,KAAK,KAAK,CAAC;;GAGtB;;AAGH,SAAgB,mBAAmB,gBAA0C;CAC3E,IAAI;AACJ,KAAI;AACF,YAAU,KAAK,MAAM,cAAc,eAAe,CAAC;SAC7C;AACN,YAAU,EAAE,SAAS,EAAE,EAAE;;CAE3B,MAAM,QAAQ,kBAAkB,QAAQ,WAAW,EAAE,CAAC;CAEtD,MAAM,YACJ,OAAO,QAAQ,cAAc,YAAY,QAAQ,UAAU,SAAS,IAChE,QAAQ,YACR;CAEN,MAAM,cAAc,oBAAoB,MAAM;AAE9C,QAAO,EACL,MAAM,oBAAoB,KAAK,UAAU,UAAU,CAAC;EACtD,YAAY,KAAK,KAAK,CAAC;;GAGtB;;AAGH,SAAgB,sBAAsB,gBAEpC;CACA,IAAI;AAOJ,KAAI;AACF,YAAU,KAAK,MAAM,cAAc,eAAe,CAAC;SAC7C;AACN,YAAU,EAAE;;CAGd,MAAM,OACJ,QAAQ,SAAS,UAAU,QAAQ,SAAS,QAAQ,QAAQ,OAAO;AASrE,QAAO,EAAE,MAAM,iBAAiB;EAAE,MAPrB;GACX,KAAK,OAAO,QAAQ,OAAO,GAAG;GAC9B,UAAU,OAAO,QAAQ,YAAY,GAAG;GACxC,WAAW,OAAO,QAAQ,aAAa,GAAG;GAC1C,OAAO,MAAM,QAAQ,QAAQ,MAAM,GAAG,QAAQ,QAAQ,EAAE;GACzD;EAEuC;EAAM,CAAC,EAAE;;AAGnD,IAAM,uBAAuB,EAAE,MAAM,aAAa;AAElD,SAAgB,mBAAqC;AACnD,QAAO;;AAGT,SAAgB,0BACd,IAC8B;AAC9B,KAAI,OAAO,wBACT,QAAO,sBAAsB;AAI/B,KAAI,GAAG,WAAW,2BAA2B,CAC3C,QAAO,sBAAsB;AAG/B,KAAI,GAAG,WAAW,0BAA0B,CAC1C,QAAO,mBAAmB,GAAG,MAAM,0BAA0B,OAAO,CAAC;AAGvE,KAAI,GAAG,WAAW,6BAA6B,CAC7C,QAAO,sBAAsB,GAAG,MAAM,6BAA6B,OAAO,CAAC;AAG7E,KAAI,GAAG,WAAW,uBAAuB,CACvC,QAAO,kBAAkB"}
@@ -1,14 +0,0 @@
1
- import { StartCompiler } from './compiler.js';
2
- interface ViteCompilerModuleLoaderOptions {
3
- compiler: StartCompiler;
4
- mode: string;
5
- fetchModule?: (id: string) => Promise<unknown>;
6
- loadModule: (opts: {
7
- id: string;
8
- }) => Promise<{
9
- code?: string | null;
10
- }>;
11
- id: string;
12
- }
13
- export declare function loadModuleForViteCompiler(opts: ViteCompilerModuleLoaderOptions): Promise<void>;
14
- export {};
@@ -1,18 +0,0 @@
1
- import { SERVER_FN_LOOKUP } from "../constants.js";
2
- //#region src/start-compiler/load-module.ts
3
- async function loadModuleForViteCompiler(opts) {
4
- if (opts.mode === "build") {
5
- const code = (await opts.loadModule({ id: opts.id })).code ?? "";
6
- opts.compiler.ingestModule({
7
- code,
8
- id: opts.id
9
- });
10
- return;
11
- }
12
- if (opts.mode !== "dev" || !opts.fetchModule) throw new Error(`could not load module ${opts.id}: unknown environment mode ${opts.mode}`);
13
- await opts.fetchModule(`${opts.id}?${SERVER_FN_LOOKUP}`);
14
- }
15
- //#endregion
16
- export { loadModuleForViteCompiler };
17
-
18
- //# sourceMappingURL=load-module.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"load-module.js","names":[],"sources":["../../../src/start-compiler/load-module.ts"],"sourcesContent":["import { SERVER_FN_LOOKUP } from '../constants'\nimport type { StartCompiler } from './compiler'\n\ninterface ViteCompilerModuleLoaderOptions {\n compiler: StartCompiler\n mode: string\n fetchModule?: (id: string) => Promise<unknown>\n loadModule: (opts: { id: string }) => Promise<{ code?: string | null }>\n id: string\n}\n\nexport async function loadModuleForViteCompiler(\n opts: ViteCompilerModuleLoaderOptions,\n): Promise<void> {\n if (opts.mode === 'build') {\n const loaded = await opts.loadModule({ id: opts.id })\n const code = loaded.code ?? ''\n\n opts.compiler.ingestModule({ code, id: opts.id })\n\n return\n }\n\n if (opts.mode !== 'dev' || !opts.fetchModule) {\n throw new Error(\n `could not load module ${opts.id}: unknown environment mode ${opts.mode}`,\n )\n }\n\n await opts.fetchModule(`${opts.id}?${SERVER_FN_LOOKUP}`)\n}\n"],"mappings":";;AAWA,eAAsB,0BACpB,MACe;AACf,KAAI,KAAK,SAAS,SAAS;EAEzB,MAAM,QADS,MAAM,KAAK,WAAW,EAAE,IAAI,KAAK,IAAI,CAAC,EACjC,QAAQ;AAE5B,OAAK,SAAS,aAAa;GAAE;GAAM,IAAI,KAAK;GAAI,CAAC;AAEjD;;AAGF,KAAI,KAAK,SAAS,SAAS,CAAC,KAAK,YAC/B,OAAM,IAAI,MACR,yBAAyB,KAAK,GAAG,6BAA6B,KAAK,OACpE;AAGH,OAAM,KAAK,YAAY,GAAG,KAAK,GAAG,GAAG,mBAAmB"}