@tanstack/start-plugin-core 1.161.0 → 1.161.3

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.
@@ -2,6 +2,7 @@ import * as path from "pathe";
2
2
  import { normalizePath } from "vite";
3
3
  import { resolveViteId } from "../utils.js";
4
4
  import { VITE_ENVIRONMENT_NAMES } from "../constants.js";
5
+ import { SERVER_FN_LOOKUP } from "../start-compiler-plugin/plugin.js";
5
6
  import { formatViolation, ImportGraph, buildTrace } from "./trace.js";
6
7
  import { getDefaultImportProtectionRules, getMarkerSpecifiers } from "./defaults.js";
7
8
  import { findPostCompileUsagePos } from "./postCompileUsage.js";
@@ -111,7 +112,7 @@ function importProtectionPlugin(opts) {
111
112
  ...overrides
112
113
  };
113
114
  }
114
- async function maybeReportMarkerViolationFromResolvedImport(ctx, provider, env, envName, envType, importer, source, resolvedId, relativePath) {
115
+ async function maybeReportMarkerViolationFromResolvedImport(ctx, provider, env, envName, envType, importer, source, resolvedId, relativePath, opts2) {
115
116
  const markerKind = getMarkerKindForFile(resolvedId);
116
117
  const violates = envType === "client" && markerKind === "server" || envType === "server" && markerKind === "client";
117
118
  if (!violates) return void 0;
@@ -130,7 +131,7 @@ function importProtectionPlugin(opts) {
130
131
  message: markerKind === "server" ? `Module "${relativePath}" is marked server-only but is imported in the client environment` : `Module "${relativePath}" is marked client-only but is imported in the server environment`
131
132
  }
132
133
  );
133
- return handleViolation.call(ctx, env, info);
134
+ return handleViolation.call(ctx, env, info, opts2);
134
135
  }
135
136
  function buildMockEdgeModuleId(env, importerId, source, runtimeId) {
136
137
  const exports = getMockEdgeExports(env, importerId, source);
@@ -373,6 +374,7 @@ function importProtectionPlugin(opts) {
373
374
  if (source.startsWith("\0") || source.startsWith("virtual:")) {
374
375
  return void 0;
375
376
  }
377
+ const isPreTransformResolve = importer.includes("?" + SERVER_FN_LOOKUP) || !!_options.scan;
376
378
  if (config.markerSpecifiers.serverOnly.has(source)) {
377
379
  const resolvedImporter = normalizeFilePath(importer);
378
380
  const existing = shared.fileMarkerKind.get(resolvedImporter);
@@ -396,7 +398,9 @@ function importProtectionPlugin(opts) {
396
398
  message: `Module "${getRelativePath(resolvedImporter)}" is marked server-only but is imported in the client environment`
397
399
  }
398
400
  );
399
- handleViolation.call(this, env, info);
401
+ handleViolation.call(this, env, info, {
402
+ silent: isPreTransformResolve
403
+ });
400
404
  }
401
405
  return resolveViteId(`${MARKER_PREFIX}server-only`);
402
406
  }
@@ -423,7 +427,9 @@ function importProtectionPlugin(opts) {
423
427
  message: `Module "${getRelativePath(resolvedImporter)}" is marked client-only but is imported in the server environment`
424
428
  }
425
429
  );
426
- handleViolation.call(this, env, info);
430
+ handleViolation.call(this, env, info, {
431
+ silent: isPreTransformResolve
432
+ });
427
433
  }
428
434
  return resolveViteId(`${MARKER_PREFIX}client-only`);
429
435
  }
@@ -449,7 +455,9 @@ function importProtectionPlugin(opts) {
449
455
  message: `Import "${source}" is denied in the "${envName}" environment`
450
456
  }
451
457
  );
452
- return handleViolation.call(this, env, info);
458
+ return handleViolation.call(this, env, info, {
459
+ silent: isPreTransformResolve
460
+ });
453
461
  }
454
462
  const cacheKey = `${normalizedImporter}:${source}`;
455
463
  let resolved;
@@ -488,7 +496,9 @@ function importProtectionPlugin(opts) {
488
496
  message: `Import "${source}" (resolved to "${relativePath}") is denied in the "${envName}" environment`
489
497
  }
490
498
  );
491
- return handleViolation.call(this, env, info);
499
+ return handleViolation.call(this, env, info, {
500
+ silent: isPreTransformResolve
501
+ });
492
502
  }
493
503
  const markerRes = await maybeReportMarkerViolationFromResolvedImport(
494
504
  this,
@@ -499,7 +509,8 @@ function importProtectionPlugin(opts) {
499
509
  importer,
500
510
  source,
501
511
  resolved,
502
- relativePath
512
+ relativePath,
513
+ { silent: isPreTransformResolve }
503
514
  );
504
515
  if (markerRes !== void 0) {
505
516
  return markerRes;
@@ -650,26 +661,32 @@ function importProtectionPlugin(opts) {
650
661
  }
651
662
  }
652
663
  ];
653
- function handleViolation(env, info) {
664
+ function handleViolation(env, info, opts2) {
654
665
  const key = dedupeKey(
655
666
  info.type,
656
667
  info.importer,
657
668
  info.specifier,
658
669
  info.resolved
659
670
  );
660
- if (config.onViolation) {
661
- const result = config.onViolation(info);
662
- if (result === false) {
671
+ if (!opts2?.silent) {
672
+ if (config.onViolation) {
673
+ const result = config.onViolation(info);
674
+ if (result === false) {
675
+ return void 0;
676
+ }
677
+ }
678
+ const seen = hasSeen(env, key);
679
+ if (config.effectiveBehavior === "error") {
680
+ if (!seen) this.error(formatViolation(info, config.root));
681
+ return void 0;
682
+ }
683
+ if (!seen) {
684
+ this.warn(formatViolation(info, config.root));
685
+ }
686
+ } else {
687
+ if (config.effectiveBehavior === "error") {
663
688
  return void 0;
664
689
  }
665
- }
666
- const seen = hasSeen(env, key);
667
- if (config.effectiveBehavior === "error") {
668
- if (!seen) this.error(formatViolation(info, config.root));
669
- return void 0;
670
- }
671
- if (!seen) {
672
- this.warn(formatViolation(info, config.root));
673
690
  }
674
691
  env.deniedSources.add(info.specifier);
675
692
  let edgeSet = env.deniedEdges.get(info.importer);
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../../src/import-protection-plugin/plugin.ts"],"sourcesContent":["import * as path from 'pathe'\nimport { normalizePath } from 'vite'\n\nimport { resolveViteId } from '../utils'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { ImportGraph, buildTrace, formatViolation } from './trace'\nimport {\n getDefaultImportProtectionRules,\n getMarkerSpecifiers,\n} from './defaults'\nimport { findPostCompileUsagePos } from './postCompileUsage'\nimport { compileMatchers, matchesAny } from './matchers'\nimport { dedupePatterns, normalizeFilePath } from './utils'\nimport { collectMockExportNamesBySource } from './rewriteDeniedImports'\nimport {\n MARKER_PREFIX,\n MOCK_EDGE_PREFIX,\n MOCK_MODULE_ID,\n MOCK_RUNTIME_PREFIX,\n RESOLVED_MARKER_PREFIX,\n RESOLVED_MOCK_EDGE_PREFIX,\n RESOLVED_MOCK_MODULE_ID,\n RESOLVED_MOCK_RUNTIME_PREFIX,\n loadMarkerModule,\n loadMockEdgeModule,\n loadMockRuntimeModule,\n loadSilentMockModule,\n makeMockEdgeModuleId,\n mockRuntimeModuleIdFromViolation,\n} from './virtualModules'\nimport {\n addTraceImportLocations,\n buildCodeSnippet,\n buildLineIndex,\n findImportStatementLocationFromTransformed,\n findPostCompileUsageLocation,\n pickOriginalCodeFromSourcesContent,\n} from './sourceLocation'\nimport type { PluginOption } from 'vite'\nimport type { CompiledMatcher } from './matchers'\nimport type { ViolationInfo } from './trace'\nimport type {\n SourceMapLike,\n TransformResult,\n TransformResultProvider,\n} from './sourceLocation'\nimport type {\n ImportProtectionBehavior,\n ImportProtectionOptions,\n} from '../schema'\nimport type { CompileStartFrameworkOptions, GetConfigFn } from '../types'\n\n// Re-export public API that tests and other consumers depend on.\nexport { RESOLVED_MOCK_MODULE_ID } from './virtualModules'\nexport { rewriteDeniedImports } from './rewriteDeniedImports'\nexport { dedupePatterns } from './utils'\nexport type { Pattern } from './utils'\n\n/**\n * Immutable plugin configuration — set once in `configResolved`, never mutated\n * per-env or per-request afterward.\n */\ninterface PluginConfig {\n enabled: boolean\n root: string\n command: 'build' | 'serve'\n srcDirectory: string\n framework: CompileStartFrameworkOptions\n\n effectiveBehavior: ImportProtectionBehavior\n mockAccess: 'error' | 'warn' | 'off'\n logMode: 'once' | 'always'\n maxTraceDepth: number\n\n compiledRules: {\n client: {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n }\n server: {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n }\n }\n includeMatchers: Array<CompiledMatcher>\n excludeMatchers: Array<CompiledMatcher>\n ignoreImporterMatchers: Array<CompiledMatcher>\n\n markerSpecifiers: { serverOnly: Set<string>; clientOnly: Set<string> }\n envTypeMap: Map<string, 'client' | 'server'>\n\n onViolation?: (info: ViolationInfo) => boolean | void\n}\n\n/**\n * Per-Vite-environment mutable state. One instance per environment name,\n * stored in `envStates: Map<string, EnvState>`.\n *\n * All caches that previously lived on `PluginState` with `${envName}:` key\n * prefixes now live here without any prefix.\n */\ninterface EnvState {\n graph: ImportGraph\n /** Specifiers that resolved to the mock module (for transform-time rewriting). */\n deniedSources: Set<string>\n /** Per-importer denied edges (for dev ESM mock modules). */\n deniedEdges: Map<string, Set<string>>\n /**\n * During `vite dev` in mock mode, we generate a per-importer mock module that\n * exports the names the importer expects.\n * Populated in the transform hook (no disk reads).\n */\n mockExportsByImporter: Map<string, Map<string, Array<string>>>\n\n /** Resolve cache. Key: `${normalizedImporter}:${source}` (no env prefix). */\n resolveCache: Map<string, string | null>\n /** Reverse index: file path → Set of resolveCache keys involving that file. */\n resolveCacheByFile: Map<string, Set<string>>\n\n /** Import location cache. Key: `${importerFile}::${source}`. */\n importLocCache: Map<\n string,\n { file?: string; line: number; column: number } | null\n >\n /** Reverse index: file path → Set of importLocCache keys for that file. */\n importLocByFile: Map<string, Set<string>>\n\n /** Deduplication of logged violations (no env prefix in key). */\n seenViolations: Set<string>\n\n /** Transform result cache (code + composed sourcemap + original source). */\n transformResultCache: Map<string, TransformResult>\n /** Reverse index: physical file path → Set of transformResultCache keys. */\n transformResultKeysByFile: Map<string, Set<string>>\n}\n\n/**\n * Intentionally cross-env shared mutable state.\n *\n * A file's `'use server'`/`'use client'` directive is inherent to the file\n * content, not the environment that happens to discover it first.\n */\ninterface SharedState {\n fileMarkerKind: Map<string, 'server' | 'client'>\n}\n\nexport interface ImportProtectionPluginOptions {\n getConfig: GetConfigFn\n framework: CompileStartFrameworkOptions\n environments: Array<{ name: string; type: 'client' | 'server' }>\n providerEnvName: string\n}\n\nexport function importProtectionPlugin(\n opts: ImportProtectionPluginOptions,\n): PluginOption {\n const config: PluginConfig = {\n enabled: true,\n root: '',\n command: 'build',\n srcDirectory: '',\n framework: opts.framework,\n effectiveBehavior: 'error',\n mockAccess: 'error',\n logMode: 'once',\n maxTraceDepth: 20,\n compiledRules: {\n client: { specifiers: [], files: [] },\n server: { specifiers: [], files: [] },\n },\n includeMatchers: [],\n excludeMatchers: [],\n ignoreImporterMatchers: [],\n markerSpecifiers: { serverOnly: new Set(), clientOnly: new Set() },\n envTypeMap: new Map(opts.environments.map((e) => [e.name, e.type])),\n onViolation: undefined,\n }\n\n const envStates = new Map<string, EnvState>()\n const shared: SharedState = { fileMarkerKind: new Map() }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Create a per-env `importLocCache` whose `.set` method automatically\n * maintains the reverse index (`importLocByFile`) for O(1) invalidation\n * in `hotUpdate`.\n *\n * Cache keys have the format `${importerFile}::${source}`.\n */\n function createImportLocCache(\n env: EnvState,\n ): Map<string, { file?: string; line: number; column: number } | null> {\n const cache = new Map<\n string,\n { file?: string; line: number; column: number } | null\n >()\n const originalSet = cache.set.bind(cache)\n cache.set = function (key, value) {\n originalSet(key, value)\n const sepIdx = key.indexOf('::')\n if (sepIdx !== -1) {\n const file = key.slice(0, sepIdx)\n let fileKeys = env.importLocByFile.get(file)\n if (!fileKeys) {\n fileKeys = new Set()\n env.importLocByFile.set(file, fileKeys)\n }\n fileKeys.add(key)\n }\n return this\n }\n return cache\n }\n\n function getMockEdgeExports(\n env: EnvState,\n importerId: string,\n source: string,\n ): Array<string> {\n const importerFile = normalizeFilePath(importerId)\n return env.mockExportsByImporter.get(importerFile)?.get(source) ?? []\n }\n\n function getMarkerKindForFile(\n fileId: string,\n ): 'server' | 'client' | undefined {\n const file = normalizeFilePath(fileId)\n return shared.fileMarkerKind.get(file)\n }\n\n /**\n * Build a {@link TransformResultProvider} for the given environment.\n *\n * The provider reads from the transform result cache that is populated by\n * the `tanstack-start-core:import-protection-transform-cache` plugin's\n * transform hook.\n */\n function getTransformResultProvider(env: EnvState): TransformResultProvider {\n return {\n getTransformResult(id: string) {\n // Try the full normalized ID first (preserves query params like\n // ?tsr-split=component for virtual modules).\n const fullKey = normalizePath(id)\n const exact = env.transformResultCache.get(fullKey)\n if (exact) return exact\n\n // Fall back to the query-stripped path for modules looked up by\n // their physical file path (e.g. trace steps, modules without\n // query params).\n const strippedKey = normalizeFilePath(id)\n return strippedKey !== fullKey\n ? env.transformResultCache.get(strippedKey)\n : undefined\n },\n }\n }\n\n type ViolationReporter = {\n warn: (msg: string) => void\n error: (msg: string) => never\n }\n\n /**\n * Build a complete {@link ViolationInfo} with trace, location, and snippet.\n *\n * This is the single path that all violation types go through: specifier,\n * file, and marker. Centralizing it eliminates the duplicated sequences of\n * `buildTrace` → `addTraceImportLocations` → location lookup → annotate →\n * snippet that previously appeared 5 times in the codebase.\n */\n async function buildViolationInfo(\n provider: TransformResultProvider,\n env: EnvState,\n envName: string,\n envType: 'client' | 'server',\n importer: string,\n normalizedImporter: string,\n source: string,\n overrides: Omit<\n ViolationInfo,\n | 'env'\n | 'envType'\n | 'behavior'\n | 'specifier'\n | 'importer'\n | 'trace'\n | 'snippet'\n | 'importerLoc'\n >,\n ): Promise<ViolationInfo> {\n const trace = buildTrace(\n env.graph,\n normalizedImporter,\n config.maxTraceDepth,\n )\n await addTraceImportLocations(provider, trace, env.importLocCache)\n\n const loc =\n (await findPostCompileUsageLocation(\n provider,\n importer,\n source,\n findPostCompileUsagePos,\n )) ||\n (await findImportStatementLocationFromTransformed(\n provider,\n importer,\n source,\n env.importLocCache,\n ))\n\n // Annotate the last trace step with the denied import's specifier and\n // location so every trace step (including the leaf) gets file:line:col.\n if (trace.length > 0) {\n const last = trace[trace.length - 1]!\n if (!last.specifier) last.specifier = source\n if (loc && last.line == null) {\n last.line = loc.line\n last.column = loc.column\n }\n }\n\n const snippet = loc ? buildCodeSnippet(provider, importer, loc) : undefined\n\n return {\n env: envName,\n envType,\n behavior: config.effectiveBehavior,\n specifier: source,\n importer: normalizedImporter,\n ...(loc ? { importerLoc: loc } : {}),\n trace,\n snippet,\n ...overrides,\n }\n }\n\n async function maybeReportMarkerViolationFromResolvedImport(\n ctx: ViolationReporter,\n provider: TransformResultProvider,\n env: EnvState,\n envName: string,\n envType: 'client' | 'server',\n importer: string,\n source: string,\n resolvedId: string,\n relativePath: string,\n ): Promise<ReturnType<typeof handleViolation> | undefined> {\n const markerKind = getMarkerKindForFile(resolvedId)\n const violates =\n (envType === 'client' && markerKind === 'server') ||\n (envType === 'server' && markerKind === 'client')\n if (!violates) return undefined\n\n const normalizedImporter = normalizeFilePath(importer)\n\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'marker',\n resolved: normalizeFilePath(resolvedId),\n message:\n markerKind === 'server'\n ? `Module \"${relativePath}\" is marked server-only but is imported in the client environment`\n : `Module \"${relativePath}\" is marked client-only but is imported in the server environment`,\n },\n )\n\n return handleViolation.call(ctx, env, info)\n }\n\n function buildMockEdgeModuleId(\n env: EnvState,\n importerId: string,\n source: string,\n runtimeId: string,\n ): string {\n const exports = getMockEdgeExports(env, importerId, source)\n return makeMockEdgeModuleId(exports, source, runtimeId)\n }\n\n function getEnvType(envName: string): 'client' | 'server' {\n return config.envTypeMap.get(envName) ?? 'server'\n }\n\n function getRulesForEnvironment(envName: string): {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n } {\n const type = getEnvType(envName)\n return type === 'client'\n ? config.compiledRules.client\n : config.compiledRules.server\n }\n\n const environmentNames = new Set<string>([\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ])\n if (opts.providerEnvName !== VITE_ENVIRONMENT_NAMES.server) {\n environmentNames.add(opts.providerEnvName)\n }\n\n /** Get (or lazily create) the per-env state for the given environment name. */\n function getEnv(envName: string): EnvState {\n let envState = envStates.get(envName)\n if (!envState) {\n const importLocByFile = new Map<string, Set<string>>()\n envState = {\n graph: new ImportGraph(),\n deniedSources: new Set(),\n deniedEdges: new Map(),\n mockExportsByImporter: new Map(),\n resolveCache: new Map(),\n resolveCacheByFile: new Map(),\n importLocCache: new Map(), // placeholder, replaced below\n importLocByFile,\n seenViolations: new Set(),\n transformResultCache: new Map(),\n transformResultKeysByFile: new Map(),\n }\n // Install reverse-index-maintaining importLocCache\n envState.importLocCache = createImportLocCache(envState)\n envStates.set(envName, envState)\n }\n return envState\n }\n\n function shouldCheckImporter(importer: string): boolean {\n // Normalize for matching\n const relativePath = path.relative(config.root, importer)\n\n // Check exclude first\n if (\n config.excludeMatchers.length > 0 &&\n matchesAny(relativePath, config.excludeMatchers)\n ) {\n return false\n }\n\n // Check ignore importers\n if (\n config.ignoreImporterMatchers.length > 0 &&\n matchesAny(relativePath, config.ignoreImporterMatchers)\n ) {\n return false\n }\n\n // Check include\n if (config.includeMatchers.length > 0) {\n return !!matchesAny(relativePath, config.includeMatchers)\n }\n\n // Default: check if within srcDirectory\n if (config.srcDirectory) {\n return importer.startsWith(config.srcDirectory)\n }\n\n return true\n }\n\n function dedupeKey(\n type: string,\n importer: string,\n specifier: string,\n resolved?: string,\n ): string {\n return `${type}:${importer}:${specifier}:${resolved ?? ''}`\n }\n\n function hasSeen(env: EnvState, key: string): boolean {\n if (config.logMode === 'always') return false\n if (env.seenViolations.has(key)) return true\n env.seenViolations.add(key)\n return false\n }\n\n function getRelativePath(absolutePath: string): string {\n return normalizePath(path.relative(config.root, absolutePath))\n }\n\n // ---------------------------------------------------------------------------\n // Vite plugins\n // ---------------------------------------------------------------------------\n\n return [\n {\n name: 'tanstack-start-core:import-protection',\n enforce: 'pre',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n // Start's environments are named `client` and `ssr` (not `server`), plus\n // an optional serverFn provider environment (eg `rsc`) when configured.\n return environmentNames.has(env.name)\n },\n\n configResolved(viteConfig) {\n config.root = viteConfig.root\n config.command = viteConfig.command\n\n const { startConfig, resolvedStartConfig } = opts.getConfig()\n config.srcDirectory = resolvedStartConfig.srcDirectory\n\n const userOpts: ImportProtectionOptions | undefined =\n startConfig.importProtection\n\n // Determine if plugin is enabled\n if (userOpts?.enabled === false) {\n config.enabled = false\n return\n }\n\n config.enabled = true\n\n // Determine effective behavior\n if (userOpts?.behavior) {\n if (typeof userOpts.behavior === 'string') {\n config.effectiveBehavior = userOpts.behavior\n } else {\n config.effectiveBehavior =\n viteConfig.command === 'serve'\n ? (userOpts.behavior.dev ?? 'mock')\n : (userOpts.behavior.build ?? 'error')\n }\n } else {\n // Defaults: dev='mock', build='error'\n config.effectiveBehavior =\n viteConfig.command === 'serve' ? 'mock' : 'error'\n }\n\n // Log mode\n config.logMode = userOpts?.log ?? 'once'\n\n // Mock runtime access diagnostics\n config.mockAccess = userOpts?.mockAccess ?? 'error'\n\n // Max trace depth\n config.maxTraceDepth = userOpts?.maxTraceDepth ?? 20\n\n // User callback\n config.onViolation = userOpts?.onViolation as\n | ((info: ViolationInfo) => boolean | void)\n | undefined\n\n // Get default rules\n const defaults = getDefaultImportProtectionRules(opts.framework)\n\n // Merge user rules with defaults and compile matchers per env.\n // IMPORTANT: client specifier denies for Start server entrypoints must\n // always include the framework defaults even when the user provides a\n // custom list.\n const clientSpecifiers = dedupePatterns([\n ...defaults.client.specifiers,\n ...(userOpts?.client?.specifiers ?? []),\n ])\n\n // For file patterns, user config overrides defaults.\n const clientFiles = userOpts?.client?.files\n ? [...userOpts.client.files]\n : [...defaults.client.files]\n const serverSpecifiers = userOpts?.server?.specifiers\n ? dedupePatterns([...userOpts.server.specifiers])\n : dedupePatterns([...defaults.server.specifiers])\n const serverFiles = userOpts?.server?.files\n ? [...userOpts.server.files]\n : [...defaults.server.files]\n\n config.compiledRules.client = {\n specifiers: compileMatchers(clientSpecifiers),\n files: compileMatchers(clientFiles),\n }\n config.compiledRules.server = {\n specifiers: compileMatchers(serverSpecifiers),\n files: compileMatchers(serverFiles),\n }\n\n // Include/exclude\n if (userOpts?.include) {\n config.includeMatchers = compileMatchers(userOpts.include)\n }\n if (userOpts?.exclude) {\n config.excludeMatchers = compileMatchers(userOpts.exclude)\n }\n if (userOpts?.ignoreImporters) {\n config.ignoreImporterMatchers = compileMatchers(\n userOpts.ignoreImporters,\n )\n }\n\n // Marker specifiers\n const markers = getMarkerSpecifiers(opts.framework)\n config.markerSpecifiers = {\n serverOnly: new Set(markers.serverOnly),\n clientOnly: new Set(markers.clientOnly),\n }\n\n // Use known Start env entrypoints as trace roots.\n // This makes traces deterministic and prevents 1-line traces.\n for (const envDef of opts.environments) {\n const envState = getEnv(envDef.name)\n\n if (resolvedStartConfig.routerFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.routerFilePath),\n )\n }\n if (resolvedStartConfig.startFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.startFilePath),\n )\n }\n }\n },\n\n buildStart() {\n if (!config.enabled) return\n // Clear per-env caches\n for (const envState of envStates.values()) {\n envState.resolveCache.clear()\n envState.resolveCacheByFile.clear()\n envState.importLocCache.clear()\n envState.importLocByFile.clear()\n envState.seenViolations.clear()\n envState.transformResultCache.clear()\n envState.transformResultKeysByFile.clear()\n envState.graph.clear()\n envState.deniedSources.clear()\n envState.deniedEdges.clear()\n envState.mockExportsByImporter.clear()\n }\n\n // Clear shared state\n shared.fileMarkerKind.clear()\n\n // Re-add known entries after clearing.\n for (const envDef of opts.environments) {\n const envState = getEnv(envDef.name)\n const { resolvedStartConfig } = opts.getConfig()\n if (resolvedStartConfig.routerFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.routerFilePath),\n )\n }\n if (resolvedStartConfig.startFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.startFilePath),\n )\n }\n }\n },\n\n hotUpdate(ctx) {\n if (!config.enabled) return\n // Invalidate caches for updated files\n for (const mod of ctx.modules) {\n if (mod.id) {\n const id = mod.id\n const importerFile = normalizeFilePath(id)\n shared.fileMarkerKind.delete(importerFile)\n\n // Invalidate per-env caches\n for (const envState of envStates.values()) {\n // Invalidate cached import locations using reverse index\n const locKeys = envState.importLocByFile.get(importerFile)\n if (locKeys) {\n for (const key of locKeys) {\n envState.importLocCache.delete(key)\n }\n envState.importLocByFile.delete(importerFile)\n }\n\n // Invalidate resolve cache using reverse index\n const resolveKeys = envState.resolveCacheByFile.get(importerFile)\n if (resolveKeys) {\n for (const key of resolveKeys) {\n envState.resolveCache.delete(key)\n }\n envState.resolveCacheByFile.delete(importerFile)\n }\n\n // Invalidate graph edges\n envState.graph.invalidate(importerFile)\n envState.deniedEdges.delete(importerFile)\n envState.mockExportsByImporter.delete(importerFile)\n\n // Invalidate transform result cache for this file.\n const transformKeys =\n envState.transformResultKeysByFile.get(importerFile)\n if (transformKeys) {\n for (const key of transformKeys) {\n envState.transformResultCache.delete(key)\n }\n envState.transformResultKeysByFile.delete(importerFile)\n } else {\n // Fallback: at least clear the physical-file entry.\n envState.transformResultCache.delete(importerFile)\n }\n }\n }\n }\n },\n\n async resolveId(source, importer, _options) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const env = getEnv(envName)\n const envType = getEnvType(envName)\n const provider = getTransformResultProvider(env)\n\n // Internal virtual modules must resolve in dev.\n if (source === MOCK_MODULE_ID) {\n return RESOLVED_MOCK_MODULE_ID\n }\n if (source.startsWith(MOCK_EDGE_PREFIX)) {\n return resolveViteId(source)\n }\n if (source.startsWith(MOCK_RUNTIME_PREFIX)) {\n return resolveViteId(source)\n }\n if (source.startsWith(MARKER_PREFIX)) {\n return resolveViteId(source)\n }\n\n // Skip if no importer (entry points)\n if (!importer) {\n // Track entry-ish modules so traces can terminate.\n // Vite may pass virtual ids here; normalize but keep them.\n env.graph.addEntry(source)\n return undefined\n }\n\n // Skip virtual modules\n if (source.startsWith('\\0') || source.startsWith('virtual:')) {\n return undefined\n }\n\n // Check if this is a marker import\n if (config.markerSpecifiers.serverOnly.has(source)) {\n // Record importer as server-only\n const resolvedImporter = normalizeFilePath(importer)\n const existing = shared.fileMarkerKind.get(resolvedImporter)\n if (existing && existing !== 'server') {\n this.error(\n `[import-protection] File \"${getRelativePath(resolvedImporter)}\" has both server-only and client-only markers. This is not allowed.`,\n )\n }\n shared.fileMarkerKind.set(resolvedImporter, 'server')\n\n // If we're in the client environment, this is a violation\n if (envType === 'client') {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n resolvedImporter,\n source,\n {\n type: 'marker',\n message: `Module \"${getRelativePath(resolvedImporter)}\" is marked server-only but is imported in the client environment`,\n },\n )\n handleViolation.call(this, env, info)\n }\n\n // Return virtual empty module\n return resolveViteId(`${MARKER_PREFIX}server-only`)\n }\n\n if (config.markerSpecifiers.clientOnly.has(source)) {\n const resolvedImporter = normalizeFilePath(importer)\n const existing = shared.fileMarkerKind.get(resolvedImporter)\n if (existing && existing !== 'client') {\n this.error(\n `[import-protection] File \"${getRelativePath(resolvedImporter)}\" has both server-only and client-only markers. This is not allowed.`,\n )\n }\n shared.fileMarkerKind.set(resolvedImporter, 'client')\n\n if (envType === 'server') {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n resolvedImporter,\n source,\n {\n type: 'marker',\n message: `Module \"${getRelativePath(resolvedImporter)}\" is marked client-only but is imported in the server environment`,\n },\n )\n handleViolation.call(this, env, info)\n }\n\n return resolveViteId(`${MARKER_PREFIX}client-only`)\n }\n\n // Check if the importer is within our scope\n const normalizedImporter = normalizeFilePath(importer)\n if (!shouldCheckImporter(normalizedImporter)) {\n return undefined\n }\n\n const matchers = getRulesForEnvironment(envName)\n\n // 1. Specifier-based denial (fast, no resolution needed)\n const specifierMatch = matchesAny(source, matchers.specifiers)\n if (specifierMatch) {\n env.graph.addEdge(source, normalizedImporter, source)\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'specifier',\n pattern: specifierMatch.pattern,\n message: `Import \"${source}\" is denied in the \"${envName}\" environment`,\n },\n )\n return handleViolation.call(this, env, info)\n }\n\n // 2. Resolve the import (cached) — needed for file-based denial,\n // marker checks, and graph edge tracking.\n const cacheKey = `${normalizedImporter}:${source}`\n let resolved: string | null\n\n if (env.resolveCache.has(cacheKey)) {\n resolved = env.resolveCache.get(cacheKey) || null\n } else {\n const result = await this.resolve(source, importer, {\n skipSelf: true,\n })\n resolved = result ? normalizeFilePath(result.id) : null\n env.resolveCache.set(cacheKey, resolved)\n\n // Maintain reverse index for O(1) hotUpdate invalidation.\n // Index by the importer so that when a file changes, all resolve\n // cache entries where it was the importer are cleared.\n let fileKeys = env.resolveCacheByFile.get(normalizedImporter)\n if (!fileKeys) {\n fileKeys = new Set()\n env.resolveCacheByFile.set(normalizedImporter, fileKeys)\n }\n fileKeys.add(cacheKey)\n }\n\n if (resolved) {\n const relativePath = getRelativePath(resolved)\n\n // Always record the edge for trace building, even when not denied.\n env.graph.addEdge(resolved, normalizedImporter, source)\n\n // File-based denial check\n const fileMatch =\n matchers.files.length > 0\n ? matchesAny(relativePath, matchers.files)\n : undefined\n\n if (fileMatch) {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'file',\n pattern: fileMatch.pattern,\n resolved,\n message: `Import \"${source}\" (resolved to \"${relativePath}\") is denied in the \"${envName}\" environment`,\n },\n )\n return handleViolation.call(this, env, info)\n }\n\n // Marker restrictions apply regardless of explicit deny rules.\n const markerRes = await maybeReportMarkerViolationFromResolvedImport(\n this,\n provider,\n env,\n envName,\n envType,\n importer,\n source,\n resolved,\n relativePath,\n )\n if (markerRes !== undefined) {\n return markerRes\n }\n }\n\n return undefined\n },\n\n load: {\n filter: {\n id: new RegExp(\n `(${RESOLVED_MOCK_MODULE_ID.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MARKER_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MOCK_EDGE_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MOCK_RUNTIME_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n ),\n },\n handler(id) {\n if (!config.enabled) return undefined\n if (id === RESOLVED_MOCK_MODULE_ID) {\n return loadSilentMockModule()\n }\n\n if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {\n return loadMockEdgeModule(\n id.slice(RESOLVED_MOCK_EDGE_PREFIX.length),\n )\n }\n\n if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {\n return loadMockRuntimeModule(\n id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length),\n )\n }\n\n if (id.startsWith(RESOLVED_MARKER_PREFIX)) {\n return loadMarkerModule()\n }\n\n return undefined\n },\n },\n },\n {\n // This plugin runs WITHOUT `enforce` so it executes after all\n // `enforce: 'pre'` transform hooks (including the Start compiler).\n // It captures the transformed code + composed sourcemap for every module\n // so that the `resolveId` hook (in the main plugin above) can look up\n // the importer's transform result and map violation locations back to\n // original source.\n //\n // Why not use `ctx.load()` in `resolveId`?\n // - Vite dev: `this.load()` returns a ModuleInfo proxy that throws on\n // `.code` access — code is not exposed.\n // - Rollup build: `ModuleInfo` has `.code` but NOT `.map`, so we\n // can't map generated positions back to original source.\n //\n // By caching in the transform hook we get both code and the composed\n // sourcemap that chains all the way back to the original file.\n //\n // Performance: only files under `srcDirectory` are cached because only\n // those can be importers in a violation. Third-party code in\n // node_modules is never checked.\n name: 'tanstack-start-core:import-protection-transform-cache',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n return environmentNames.has(env.name)\n },\n\n transform: {\n filter: {\n id: {\n include: [/\\.[cm]?[tj]sx?($|\\?)/],\n },\n },\n handler(code, id) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const file = normalizeFilePath(id)\n\n // Only cache files that could ever be checked as an importer.\n // This reuses the same include/exclude/ignoreImporters predicate as\n // the main import-protection resolveId hook.\n if (!shouldCheckImporter(file)) {\n return undefined\n }\n\n // getCombinedSourcemap() returns the composed sourcemap of all\n // transform hooks that ran before this one. It includes\n // sourcesContent so we can extract original source later.\n let map: SourceMapLike | undefined\n try {\n map = this.getCombinedSourcemap()\n } catch {\n // No sourcemap available (e.g. virtual modules or modules\n // that no prior plugin produced a map for).\n map = undefined\n }\n\n // Extract the original source from sourcesContent right here.\n // Composed sourcemaps can contain multiple sources; try to pick the\n // entry that best matches this importer.\n let originalCode: string | undefined\n if (map?.sourcesContent) {\n originalCode = pickOriginalCodeFromSourcesContent(\n map,\n file,\n config.root,\n )\n }\n\n // Precompute a line index for fast index->line/col conversions.\n const lineIndex = buildLineIndex(code)\n\n // Key by the full normalized module ID including query params\n // (e.g. \"src/routes/index.tsx?tsr-split=component\") so that\n // virtual modules derived from the same physical file each get\n // their own cache entry.\n const cacheKey = normalizePath(id)\n const envState = getEnv(envName)\n envState.transformResultCache.set(cacheKey, {\n code,\n map,\n originalCode,\n lineIndex,\n })\n\n // Maintain reverse index so hotUpdate invalidation is O(keys for file).\n let keySet = envState.transformResultKeysByFile.get(file)\n if (!keySet) {\n keySet = new Set<string>()\n envState.transformResultKeysByFile.set(file, keySet)\n }\n keySet.add(cacheKey)\n\n // Also store/update the stripped-path entry so that lookups by\n // physical file path (e.g. from trace steps in the import graph,\n // which normalize away query params) still find a result.\n // The last variant transformed wins, which is acceptable — trace\n // lookups are best-effort for line numbers.\n if (cacheKey !== file) {\n envState.transformResultCache.set(file, {\n code,\n map,\n originalCode,\n lineIndex,\n })\n keySet.add(file)\n }\n\n // Return nothing — we don't modify the code.\n return undefined\n },\n },\n },\n {\n // Separate plugin so the transform can be enabled/disabled per-environment.\n name: 'tanstack-start-core:import-protection-mock-rewrite',\n enforce: 'pre',\n\n // Only needed during dev. In build, we rely on Rollup's syntheticNamedExports.\n apply: 'serve',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n // Only needed in mock mode — when not mocking, there is nothing to\n // record. applyToEnvironment runs after configResolved, so\n // config.effectiveBehavior is already set.\n if (config.effectiveBehavior !== 'mock') return false\n // We record expected named exports per importer in all Start Vite\n // environments during dev so mock-edge modules can provide explicit\n // ESM named exports.\n return environmentNames.has(env.name)\n },\n\n transform: {\n filter: {\n id: {\n include: [/\\.[cm]?[tj]sx?($|\\?)/],\n },\n },\n handler(code, id) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const envState = envStates.get(envName)\n if (!envState) return undefined\n\n // Record export names per source for this importer so we can generate\n // dev mock-edge modules without any disk reads.\n try {\n const importerFile = normalizeFilePath(id)\n envState.mockExportsByImporter.set(\n importerFile,\n collectMockExportNamesBySource(code),\n )\n } catch {\n // Best-effort only\n }\n\n // Note: we no longer rewrite imports here.\n // Dev uses per-importer mock-edge modules in resolveId so native ESM\n // has explicit named exports, and runtime diagnostics are handled by\n // the mock runtime proxy when those mocks are actually invoked.\n return undefined\n },\n },\n },\n ] satisfies Array<PluginOption>\n\n // ---------------------------------------------------------------------------\n // Violation handling\n // ---------------------------------------------------------------------------\n\n function handleViolation(\n this: { warn: (msg: string) => void; error: (msg: string) => never },\n env: EnvState,\n info: ViolationInfo,\n ): { id: string; syntheticNamedExports: boolean } | string | undefined {\n const key = dedupeKey(\n info.type,\n info.importer,\n info.specifier,\n info.resolved,\n )\n\n // Call user callback\n if (config.onViolation) {\n const result = config.onViolation(info)\n if (result === false) {\n return undefined\n }\n }\n\n const seen = hasSeen(env, key)\n\n if (config.effectiveBehavior === 'error') {\n if (!seen) this.error(formatViolation(info, config.root))\n return undefined\n }\n\n // Mock mode: log once, but always return the mock module.\n if (!seen) {\n this.warn(formatViolation(info, config.root))\n }\n\n env.deniedSources.add(info.specifier)\n let edgeSet = env.deniedEdges.get(info.importer)\n if (!edgeSet) {\n edgeSet = new Set<string>()\n env.deniedEdges.set(info.importer, edgeSet)\n }\n edgeSet.add(info.specifier)\n\n if (config.command === 'serve') {\n const runtimeId = mockRuntimeModuleIdFromViolation(\n info,\n config.mockAccess,\n config.root,\n )\n return resolveViteId(\n buildMockEdgeModuleId(env, info.importer, info.specifier, runtimeId),\n )\n }\n\n // Build: Rollup can synthesize named exports.\n return { id: RESOLVED_MOCK_MODULE_ID, syntheticNamedExports: true }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../../src/import-protection-plugin/plugin.ts"],"sourcesContent":["import * as path from 'pathe'\nimport { normalizePath } from 'vite'\n\nimport { resolveViteId } from '../utils'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { SERVER_FN_LOOKUP } from '../start-compiler-plugin/plugin'\nimport { ImportGraph, buildTrace, formatViolation } from './trace'\nimport {\n getDefaultImportProtectionRules,\n getMarkerSpecifiers,\n} from './defaults'\nimport { findPostCompileUsagePos } from './postCompileUsage'\nimport { compileMatchers, matchesAny } from './matchers'\nimport { dedupePatterns, normalizeFilePath } from './utils'\nimport { collectMockExportNamesBySource } from './rewriteDeniedImports'\nimport {\n MARKER_PREFIX,\n MOCK_EDGE_PREFIX,\n MOCK_MODULE_ID,\n MOCK_RUNTIME_PREFIX,\n RESOLVED_MARKER_PREFIX,\n RESOLVED_MOCK_EDGE_PREFIX,\n RESOLVED_MOCK_MODULE_ID,\n RESOLVED_MOCK_RUNTIME_PREFIX,\n loadMarkerModule,\n loadMockEdgeModule,\n loadMockRuntimeModule,\n loadSilentMockModule,\n makeMockEdgeModuleId,\n mockRuntimeModuleIdFromViolation,\n} from './virtualModules'\nimport {\n addTraceImportLocations,\n buildCodeSnippet,\n buildLineIndex,\n findImportStatementLocationFromTransformed,\n findPostCompileUsageLocation,\n pickOriginalCodeFromSourcesContent,\n} from './sourceLocation'\nimport type { PluginOption } from 'vite'\nimport type { CompiledMatcher } from './matchers'\nimport type { ViolationInfo } from './trace'\nimport type {\n SourceMapLike,\n TransformResult,\n TransformResultProvider,\n} from './sourceLocation'\nimport type {\n ImportProtectionBehavior,\n ImportProtectionOptions,\n} from '../schema'\nimport type { CompileStartFrameworkOptions, GetConfigFn } from '../types'\n\n// Re-export public API that tests and other consumers depend on.\nexport { RESOLVED_MOCK_MODULE_ID } from './virtualModules'\nexport { rewriteDeniedImports } from './rewriteDeniedImports'\nexport { dedupePatterns } from './utils'\nexport type { Pattern } from './utils'\n\n/**\n * Immutable plugin configuration — set once in `configResolved`, never mutated\n * per-env or per-request afterward.\n */\ninterface PluginConfig {\n enabled: boolean\n root: string\n command: 'build' | 'serve'\n srcDirectory: string\n framework: CompileStartFrameworkOptions\n\n effectiveBehavior: ImportProtectionBehavior\n mockAccess: 'error' | 'warn' | 'off'\n logMode: 'once' | 'always'\n maxTraceDepth: number\n\n compiledRules: {\n client: {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n }\n server: {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n }\n }\n includeMatchers: Array<CompiledMatcher>\n excludeMatchers: Array<CompiledMatcher>\n ignoreImporterMatchers: Array<CompiledMatcher>\n\n markerSpecifiers: { serverOnly: Set<string>; clientOnly: Set<string> }\n envTypeMap: Map<string, 'client' | 'server'>\n\n onViolation?: (info: ViolationInfo) => boolean | void\n}\n\n/**\n * Per-Vite-environment mutable state. One instance per environment name,\n * stored in `envStates: Map<string, EnvState>`.\n *\n * All caches that previously lived on `PluginState` with `${envName}:` key\n * prefixes now live here without any prefix.\n */\ninterface EnvState {\n graph: ImportGraph\n /** Specifiers that resolved to the mock module (for transform-time rewriting). */\n deniedSources: Set<string>\n /** Per-importer denied edges (for dev ESM mock modules). */\n deniedEdges: Map<string, Set<string>>\n /**\n * During `vite dev` in mock mode, we generate a per-importer mock module that\n * exports the names the importer expects.\n * Populated in the transform hook (no disk reads).\n */\n mockExportsByImporter: Map<string, Map<string, Array<string>>>\n\n /** Resolve cache. Key: `${normalizedImporter}:${source}` (no env prefix). */\n resolveCache: Map<string, string | null>\n /** Reverse index: file path → Set of resolveCache keys involving that file. */\n resolveCacheByFile: Map<string, Set<string>>\n\n /** Import location cache. Key: `${importerFile}::${source}`. */\n importLocCache: Map<\n string,\n { file?: string; line: number; column: number } | null\n >\n /** Reverse index: file path → Set of importLocCache keys for that file. */\n importLocByFile: Map<string, Set<string>>\n\n /** Deduplication of logged violations (no env prefix in key). */\n seenViolations: Set<string>\n\n /** Transform result cache (code + composed sourcemap + original source). */\n transformResultCache: Map<string, TransformResult>\n /** Reverse index: physical file path → Set of transformResultCache keys. */\n transformResultKeysByFile: Map<string, Set<string>>\n}\n\n/**\n * Intentionally cross-env shared mutable state.\n *\n * A file's `'use server'`/`'use client'` directive is inherent to the file\n * content, not the environment that happens to discover it first.\n */\ninterface SharedState {\n fileMarkerKind: Map<string, 'server' | 'client'>\n}\n\nexport interface ImportProtectionPluginOptions {\n getConfig: GetConfigFn\n framework: CompileStartFrameworkOptions\n environments: Array<{ name: string; type: 'client' | 'server' }>\n providerEnvName: string\n}\n\nexport function importProtectionPlugin(\n opts: ImportProtectionPluginOptions,\n): PluginOption {\n const config: PluginConfig = {\n enabled: true,\n root: '',\n command: 'build',\n srcDirectory: '',\n framework: opts.framework,\n effectiveBehavior: 'error',\n mockAccess: 'error',\n logMode: 'once',\n maxTraceDepth: 20,\n compiledRules: {\n client: { specifiers: [], files: [] },\n server: { specifiers: [], files: [] },\n },\n includeMatchers: [],\n excludeMatchers: [],\n ignoreImporterMatchers: [],\n markerSpecifiers: { serverOnly: new Set(), clientOnly: new Set() },\n envTypeMap: new Map(opts.environments.map((e) => [e.name, e.type])),\n onViolation: undefined,\n }\n\n const envStates = new Map<string, EnvState>()\n const shared: SharedState = { fileMarkerKind: new Map() }\n\n // ---------------------------------------------------------------------------\n // Internal helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Create a per-env `importLocCache` whose `.set` method automatically\n * maintains the reverse index (`importLocByFile`) for O(1) invalidation\n * in `hotUpdate`.\n *\n * Cache keys have the format `${importerFile}::${source}`.\n */\n function createImportLocCache(\n env: EnvState,\n ): Map<string, { file?: string; line: number; column: number } | null> {\n const cache = new Map<\n string,\n { file?: string; line: number; column: number } | null\n >()\n const originalSet = cache.set.bind(cache)\n cache.set = function (key, value) {\n originalSet(key, value)\n const sepIdx = key.indexOf('::')\n if (sepIdx !== -1) {\n const file = key.slice(0, sepIdx)\n let fileKeys = env.importLocByFile.get(file)\n if (!fileKeys) {\n fileKeys = new Set()\n env.importLocByFile.set(file, fileKeys)\n }\n fileKeys.add(key)\n }\n return this\n }\n return cache\n }\n\n function getMockEdgeExports(\n env: EnvState,\n importerId: string,\n source: string,\n ): Array<string> {\n const importerFile = normalizeFilePath(importerId)\n return env.mockExportsByImporter.get(importerFile)?.get(source) ?? []\n }\n\n function getMarkerKindForFile(\n fileId: string,\n ): 'server' | 'client' | undefined {\n const file = normalizeFilePath(fileId)\n return shared.fileMarkerKind.get(file)\n }\n\n /**\n * Build a {@link TransformResultProvider} for the given environment.\n *\n * The provider reads from the transform result cache that is populated by\n * the `tanstack-start-core:import-protection-transform-cache` plugin's\n * transform hook.\n */\n function getTransformResultProvider(env: EnvState): TransformResultProvider {\n return {\n getTransformResult(id: string) {\n // Try the full normalized ID first (preserves query params like\n // ?tsr-split=component for virtual modules).\n const fullKey = normalizePath(id)\n const exact = env.transformResultCache.get(fullKey)\n if (exact) return exact\n\n // Fall back to the query-stripped path for modules looked up by\n // their physical file path (e.g. trace steps, modules without\n // query params).\n const strippedKey = normalizeFilePath(id)\n return strippedKey !== fullKey\n ? env.transformResultCache.get(strippedKey)\n : undefined\n },\n }\n }\n\n type ViolationReporter = {\n warn: (msg: string) => void\n error: (msg: string) => never\n }\n\n /**\n * Build a complete {@link ViolationInfo} with trace, location, and snippet.\n *\n * This is the single path that all violation types go through: specifier,\n * file, and marker. Centralizing it eliminates the duplicated sequences of\n * `buildTrace` → `addTraceImportLocations` → location lookup → annotate →\n * snippet that previously appeared 5 times in the codebase.\n */\n async function buildViolationInfo(\n provider: TransformResultProvider,\n env: EnvState,\n envName: string,\n envType: 'client' | 'server',\n importer: string,\n normalizedImporter: string,\n source: string,\n overrides: Omit<\n ViolationInfo,\n | 'env'\n | 'envType'\n | 'behavior'\n | 'specifier'\n | 'importer'\n | 'trace'\n | 'snippet'\n | 'importerLoc'\n >,\n ): Promise<ViolationInfo> {\n const trace = buildTrace(\n env.graph,\n normalizedImporter,\n config.maxTraceDepth,\n )\n await addTraceImportLocations(provider, trace, env.importLocCache)\n\n const loc =\n (await findPostCompileUsageLocation(\n provider,\n importer,\n source,\n findPostCompileUsagePos,\n )) ||\n (await findImportStatementLocationFromTransformed(\n provider,\n importer,\n source,\n env.importLocCache,\n ))\n\n // Annotate the last trace step with the denied import's specifier and\n // location so every trace step (including the leaf) gets file:line:col.\n if (trace.length > 0) {\n const last = trace[trace.length - 1]!\n if (!last.specifier) last.specifier = source\n if (loc && last.line == null) {\n last.line = loc.line\n last.column = loc.column\n }\n }\n\n const snippet = loc ? buildCodeSnippet(provider, importer, loc) : undefined\n\n return {\n env: envName,\n envType,\n behavior: config.effectiveBehavior,\n specifier: source,\n importer: normalizedImporter,\n ...(loc ? { importerLoc: loc } : {}),\n trace,\n snippet,\n ...overrides,\n }\n }\n\n async function maybeReportMarkerViolationFromResolvedImport(\n ctx: ViolationReporter,\n provider: TransformResultProvider,\n env: EnvState,\n envName: string,\n envType: 'client' | 'server',\n importer: string,\n source: string,\n resolvedId: string,\n relativePath: string,\n opts?: { silent?: boolean },\n ): Promise<ReturnType<typeof handleViolation> | undefined> {\n const markerKind = getMarkerKindForFile(resolvedId)\n const violates =\n (envType === 'client' && markerKind === 'server') ||\n (envType === 'server' && markerKind === 'client')\n if (!violates) return undefined\n\n const normalizedImporter = normalizeFilePath(importer)\n\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'marker',\n resolved: normalizeFilePath(resolvedId),\n message:\n markerKind === 'server'\n ? `Module \"${relativePath}\" is marked server-only but is imported in the client environment`\n : `Module \"${relativePath}\" is marked client-only but is imported in the server environment`,\n },\n )\n\n return handleViolation.call(ctx, env, info, opts)\n }\n\n function buildMockEdgeModuleId(\n env: EnvState,\n importerId: string,\n source: string,\n runtimeId: string,\n ): string {\n const exports = getMockEdgeExports(env, importerId, source)\n return makeMockEdgeModuleId(exports, source, runtimeId)\n }\n\n function getEnvType(envName: string): 'client' | 'server' {\n return config.envTypeMap.get(envName) ?? 'server'\n }\n\n function getRulesForEnvironment(envName: string): {\n specifiers: Array<CompiledMatcher>\n files: Array<CompiledMatcher>\n } {\n const type = getEnvType(envName)\n return type === 'client'\n ? config.compiledRules.client\n : config.compiledRules.server\n }\n\n const environmentNames = new Set<string>([\n VITE_ENVIRONMENT_NAMES.client,\n VITE_ENVIRONMENT_NAMES.server,\n ])\n if (opts.providerEnvName !== VITE_ENVIRONMENT_NAMES.server) {\n environmentNames.add(opts.providerEnvName)\n }\n\n /** Get (or lazily create) the per-env state for the given environment name. */\n function getEnv(envName: string): EnvState {\n let envState = envStates.get(envName)\n if (!envState) {\n const importLocByFile = new Map<string, Set<string>>()\n envState = {\n graph: new ImportGraph(),\n deniedSources: new Set(),\n deniedEdges: new Map(),\n mockExportsByImporter: new Map(),\n resolveCache: new Map(),\n resolveCacheByFile: new Map(),\n importLocCache: new Map(), // placeholder, replaced below\n importLocByFile,\n seenViolations: new Set(),\n transformResultCache: new Map(),\n transformResultKeysByFile: new Map(),\n }\n // Install reverse-index-maintaining importLocCache\n envState.importLocCache = createImportLocCache(envState)\n envStates.set(envName, envState)\n }\n return envState\n }\n\n function shouldCheckImporter(importer: string): boolean {\n // Normalize for matching\n const relativePath = path.relative(config.root, importer)\n\n // Check exclude first\n if (\n config.excludeMatchers.length > 0 &&\n matchesAny(relativePath, config.excludeMatchers)\n ) {\n return false\n }\n\n // Check ignore importers\n if (\n config.ignoreImporterMatchers.length > 0 &&\n matchesAny(relativePath, config.ignoreImporterMatchers)\n ) {\n return false\n }\n\n // Check include\n if (config.includeMatchers.length > 0) {\n return !!matchesAny(relativePath, config.includeMatchers)\n }\n\n // Default: check if within srcDirectory\n if (config.srcDirectory) {\n return importer.startsWith(config.srcDirectory)\n }\n\n return true\n }\n\n function dedupeKey(\n type: string,\n importer: string,\n specifier: string,\n resolved?: string,\n ): string {\n return `${type}:${importer}:${specifier}:${resolved ?? ''}`\n }\n\n function hasSeen(env: EnvState, key: string): boolean {\n if (config.logMode === 'always') return false\n if (env.seenViolations.has(key)) return true\n env.seenViolations.add(key)\n return false\n }\n\n function getRelativePath(absolutePath: string): string {\n return normalizePath(path.relative(config.root, absolutePath))\n }\n\n // ---------------------------------------------------------------------------\n // Vite plugins\n // ---------------------------------------------------------------------------\n\n return [\n {\n name: 'tanstack-start-core:import-protection',\n enforce: 'pre',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n // Start's environments are named `client` and `ssr` (not `server`), plus\n // an optional serverFn provider environment (eg `rsc`) when configured.\n return environmentNames.has(env.name)\n },\n\n configResolved(viteConfig) {\n config.root = viteConfig.root\n config.command = viteConfig.command\n\n const { startConfig, resolvedStartConfig } = opts.getConfig()\n config.srcDirectory = resolvedStartConfig.srcDirectory\n\n const userOpts: ImportProtectionOptions | undefined =\n startConfig.importProtection\n\n // Determine if plugin is enabled\n if (userOpts?.enabled === false) {\n config.enabled = false\n return\n }\n\n config.enabled = true\n\n // Determine effective behavior\n if (userOpts?.behavior) {\n if (typeof userOpts.behavior === 'string') {\n config.effectiveBehavior = userOpts.behavior\n } else {\n config.effectiveBehavior =\n viteConfig.command === 'serve'\n ? (userOpts.behavior.dev ?? 'mock')\n : (userOpts.behavior.build ?? 'error')\n }\n } else {\n // Defaults: dev='mock', build='error'\n config.effectiveBehavior =\n viteConfig.command === 'serve' ? 'mock' : 'error'\n }\n\n // Log mode\n config.logMode = userOpts?.log ?? 'once'\n\n // Mock runtime access diagnostics\n config.mockAccess = userOpts?.mockAccess ?? 'error'\n\n // Max trace depth\n config.maxTraceDepth = userOpts?.maxTraceDepth ?? 20\n\n // User callback\n config.onViolation = userOpts?.onViolation as\n | ((info: ViolationInfo) => boolean | void)\n | undefined\n\n // Get default rules\n const defaults = getDefaultImportProtectionRules(opts.framework)\n\n // Merge user rules with defaults and compile matchers per env.\n // IMPORTANT: client specifier denies for Start server entrypoints must\n // always include the framework defaults even when the user provides a\n // custom list.\n const clientSpecifiers = dedupePatterns([\n ...defaults.client.specifiers,\n ...(userOpts?.client?.specifiers ?? []),\n ])\n\n // For file patterns, user config overrides defaults.\n const clientFiles = userOpts?.client?.files\n ? [...userOpts.client.files]\n : [...defaults.client.files]\n const serverSpecifiers = userOpts?.server?.specifiers\n ? dedupePatterns([...userOpts.server.specifiers])\n : dedupePatterns([...defaults.server.specifiers])\n const serverFiles = userOpts?.server?.files\n ? [...userOpts.server.files]\n : [...defaults.server.files]\n\n config.compiledRules.client = {\n specifiers: compileMatchers(clientSpecifiers),\n files: compileMatchers(clientFiles),\n }\n config.compiledRules.server = {\n specifiers: compileMatchers(serverSpecifiers),\n files: compileMatchers(serverFiles),\n }\n\n // Include/exclude\n if (userOpts?.include) {\n config.includeMatchers = compileMatchers(userOpts.include)\n }\n if (userOpts?.exclude) {\n config.excludeMatchers = compileMatchers(userOpts.exclude)\n }\n if (userOpts?.ignoreImporters) {\n config.ignoreImporterMatchers = compileMatchers(\n userOpts.ignoreImporters,\n )\n }\n\n // Marker specifiers\n const markers = getMarkerSpecifiers(opts.framework)\n config.markerSpecifiers = {\n serverOnly: new Set(markers.serverOnly),\n clientOnly: new Set(markers.clientOnly),\n }\n\n // Use known Start env entrypoints as trace roots.\n // This makes traces deterministic and prevents 1-line traces.\n for (const envDef of opts.environments) {\n const envState = getEnv(envDef.name)\n\n if (resolvedStartConfig.routerFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.routerFilePath),\n )\n }\n if (resolvedStartConfig.startFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.startFilePath),\n )\n }\n }\n },\n\n buildStart() {\n if (!config.enabled) return\n // Clear per-env caches\n for (const envState of envStates.values()) {\n envState.resolveCache.clear()\n envState.resolveCacheByFile.clear()\n envState.importLocCache.clear()\n envState.importLocByFile.clear()\n envState.seenViolations.clear()\n envState.transformResultCache.clear()\n envState.transformResultKeysByFile.clear()\n envState.graph.clear()\n envState.deniedSources.clear()\n envState.deniedEdges.clear()\n envState.mockExportsByImporter.clear()\n }\n\n // Clear shared state\n shared.fileMarkerKind.clear()\n\n // Re-add known entries after clearing.\n for (const envDef of opts.environments) {\n const envState = getEnv(envDef.name)\n const { resolvedStartConfig } = opts.getConfig()\n if (resolvedStartConfig.routerFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.routerFilePath),\n )\n }\n if (resolvedStartConfig.startFilePath) {\n envState.graph.addEntry(\n normalizePath(resolvedStartConfig.startFilePath),\n )\n }\n }\n },\n\n hotUpdate(ctx) {\n if (!config.enabled) return\n // Invalidate caches for updated files\n for (const mod of ctx.modules) {\n if (mod.id) {\n const id = mod.id\n const importerFile = normalizeFilePath(id)\n shared.fileMarkerKind.delete(importerFile)\n\n // Invalidate per-env caches\n for (const envState of envStates.values()) {\n // Invalidate cached import locations using reverse index\n const locKeys = envState.importLocByFile.get(importerFile)\n if (locKeys) {\n for (const key of locKeys) {\n envState.importLocCache.delete(key)\n }\n envState.importLocByFile.delete(importerFile)\n }\n\n // Invalidate resolve cache using reverse index\n const resolveKeys = envState.resolveCacheByFile.get(importerFile)\n if (resolveKeys) {\n for (const key of resolveKeys) {\n envState.resolveCache.delete(key)\n }\n envState.resolveCacheByFile.delete(importerFile)\n }\n\n // Invalidate graph edges\n envState.graph.invalidate(importerFile)\n envState.deniedEdges.delete(importerFile)\n envState.mockExportsByImporter.delete(importerFile)\n\n // Invalidate transform result cache for this file.\n const transformKeys =\n envState.transformResultKeysByFile.get(importerFile)\n if (transformKeys) {\n for (const key of transformKeys) {\n envState.transformResultCache.delete(key)\n }\n envState.transformResultKeysByFile.delete(importerFile)\n } else {\n // Fallback: at least clear the physical-file entry.\n envState.transformResultCache.delete(importerFile)\n }\n }\n }\n }\n },\n\n async resolveId(source, importer, _options) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const env = getEnv(envName)\n const envType = getEnvType(envName)\n const provider = getTransformResultProvider(env)\n\n // Internal virtual modules must resolve in dev.\n if (source === MOCK_MODULE_ID) {\n return RESOLVED_MOCK_MODULE_ID\n }\n if (source.startsWith(MOCK_EDGE_PREFIX)) {\n return resolveViteId(source)\n }\n if (source.startsWith(MOCK_RUNTIME_PREFIX)) {\n return resolveViteId(source)\n }\n if (source.startsWith(MARKER_PREFIX)) {\n return resolveViteId(source)\n }\n\n // Skip if no importer (entry points)\n if (!importer) {\n // Track entry-ish modules so traces can terminate.\n // Vite may pass virtual ids here; normalize but keep them.\n env.graph.addEntry(source)\n return undefined\n }\n\n // Skip virtual modules\n if (source.startsWith('\\0') || source.startsWith('virtual:')) {\n return undefined\n }\n\n // Two code paths resolve imports from raw (pre-compiler-transform)\n // source in dev mode:\n //\n // 1. The Start compiler calls `fetchModule(id + '?' + SERVER_FN_LOOKUP)`\n // to inspect a child module's exports. The compiler's own transform\n // is excluded for these requests, so Vite sees the original imports.\n //\n // 2. Vite's dep-optimizer scanner (`options.scan === true`) uses esbuild\n // to discover bare imports for pre-bundling. esbuild reads raw source\n // without running Vite transform hooks, so it also sees imports that\n // the compiler would normally strip.\n //\n // In both cases the imports are NOT real client-side imports. We must\n // suppress violation *reporting* (no warnings / errors) but still return\n // mock module IDs so that transitive resolution doesn't blow up.\n const isPreTransformResolve =\n importer.includes('?' + SERVER_FN_LOOKUP) ||\n !!(_options as Record<string, unknown>).scan\n\n // Check if this is a marker import\n if (config.markerSpecifiers.serverOnly.has(source)) {\n // Record importer as server-only\n const resolvedImporter = normalizeFilePath(importer)\n const existing = shared.fileMarkerKind.get(resolvedImporter)\n if (existing && existing !== 'server') {\n this.error(\n `[import-protection] File \"${getRelativePath(resolvedImporter)}\" has both server-only and client-only markers. This is not allowed.`,\n )\n }\n shared.fileMarkerKind.set(resolvedImporter, 'server')\n\n // If we're in the client environment, this is a violation\n if (envType === 'client') {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n resolvedImporter,\n source,\n {\n type: 'marker',\n message: `Module \"${getRelativePath(resolvedImporter)}\" is marked server-only but is imported in the client environment`,\n },\n )\n handleViolation.call(this, env, info, {\n silent: isPreTransformResolve,\n })\n }\n\n // Return virtual empty module\n return resolveViteId(`${MARKER_PREFIX}server-only`)\n }\n\n if (config.markerSpecifiers.clientOnly.has(source)) {\n const resolvedImporter = normalizeFilePath(importer)\n const existing = shared.fileMarkerKind.get(resolvedImporter)\n if (existing && existing !== 'client') {\n this.error(\n `[import-protection] File \"${getRelativePath(resolvedImporter)}\" has both server-only and client-only markers. This is not allowed.`,\n )\n }\n shared.fileMarkerKind.set(resolvedImporter, 'client')\n\n if (envType === 'server') {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n resolvedImporter,\n source,\n {\n type: 'marker',\n message: `Module \"${getRelativePath(resolvedImporter)}\" is marked client-only but is imported in the server environment`,\n },\n )\n handleViolation.call(this, env, info, {\n silent: isPreTransformResolve,\n })\n }\n\n return resolveViteId(`${MARKER_PREFIX}client-only`)\n }\n\n // Check if the importer is within our scope\n const normalizedImporter = normalizeFilePath(importer)\n if (!shouldCheckImporter(normalizedImporter)) {\n return undefined\n }\n\n const matchers = getRulesForEnvironment(envName)\n\n // 1. Specifier-based denial (fast, no resolution needed)\n const specifierMatch = matchesAny(source, matchers.specifiers)\n if (specifierMatch) {\n env.graph.addEdge(source, normalizedImporter, source)\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'specifier',\n pattern: specifierMatch.pattern,\n message: `Import \"${source}\" is denied in the \"${envName}\" environment`,\n },\n )\n return handleViolation.call(this, env, info, {\n silent: isPreTransformResolve,\n })\n }\n\n // 2. Resolve the import (cached) — needed for file-based denial,\n // marker checks, and graph edge tracking.\n const cacheKey = `${normalizedImporter}:${source}`\n let resolved: string | null\n\n if (env.resolveCache.has(cacheKey)) {\n resolved = env.resolveCache.get(cacheKey) || null\n } else {\n const result = await this.resolve(source, importer, {\n skipSelf: true,\n })\n resolved = result ? normalizeFilePath(result.id) : null\n env.resolveCache.set(cacheKey, resolved)\n\n // Maintain reverse index for O(1) hotUpdate invalidation.\n // Index by the importer so that when a file changes, all resolve\n // cache entries where it was the importer are cleared.\n let fileKeys = env.resolveCacheByFile.get(normalizedImporter)\n if (!fileKeys) {\n fileKeys = new Set()\n env.resolveCacheByFile.set(normalizedImporter, fileKeys)\n }\n fileKeys.add(cacheKey)\n }\n\n if (resolved) {\n const relativePath = getRelativePath(resolved)\n\n // Always record the edge for trace building, even when not denied.\n env.graph.addEdge(resolved, normalizedImporter, source)\n\n // File-based denial check\n const fileMatch =\n matchers.files.length > 0\n ? matchesAny(relativePath, matchers.files)\n : undefined\n\n if (fileMatch) {\n const info = await buildViolationInfo(\n provider,\n env,\n envName,\n envType,\n importer,\n normalizedImporter,\n source,\n {\n type: 'file',\n pattern: fileMatch.pattern,\n resolved,\n message: `Import \"${source}\" (resolved to \"${relativePath}\") is denied in the \"${envName}\" environment`,\n },\n )\n return handleViolation.call(this, env, info, {\n silent: isPreTransformResolve,\n })\n }\n\n // Marker restrictions apply regardless of explicit deny rules.\n const markerRes = await maybeReportMarkerViolationFromResolvedImport(\n this,\n provider,\n env,\n envName,\n envType,\n importer,\n source,\n resolved,\n relativePath,\n { silent: isPreTransformResolve },\n )\n if (markerRes !== undefined) {\n return markerRes\n }\n }\n\n return undefined\n },\n\n load: {\n filter: {\n id: new RegExp(\n `(${RESOLVED_MOCK_MODULE_ID.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MARKER_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MOCK_EDGE_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}|${RESOLVED_MOCK_RUNTIME_PREFIX.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')})`,\n ),\n },\n handler(id) {\n if (!config.enabled) return undefined\n if (id === RESOLVED_MOCK_MODULE_ID) {\n return loadSilentMockModule()\n }\n\n if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {\n return loadMockEdgeModule(\n id.slice(RESOLVED_MOCK_EDGE_PREFIX.length),\n )\n }\n\n if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {\n return loadMockRuntimeModule(\n id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length),\n )\n }\n\n if (id.startsWith(RESOLVED_MARKER_PREFIX)) {\n return loadMarkerModule()\n }\n\n return undefined\n },\n },\n },\n {\n // This plugin runs WITHOUT `enforce` so it executes after all\n // `enforce: 'pre'` transform hooks (including the Start compiler).\n // It captures the transformed code + composed sourcemap for every module\n // so that the `resolveId` hook (in the main plugin above) can look up\n // the importer's transform result and map violation locations back to\n // original source.\n //\n // Why not use `ctx.load()` in `resolveId`?\n // - Vite dev: `this.load()` returns a ModuleInfo proxy that throws on\n // `.code` access — code is not exposed.\n // - Rollup build: `ModuleInfo` has `.code` but NOT `.map`, so we\n // can't map generated positions back to original source.\n //\n // By caching in the transform hook we get both code and the composed\n // sourcemap that chains all the way back to the original file.\n //\n // Performance: only files under `srcDirectory` are cached because only\n // those can be importers in a violation. Third-party code in\n // node_modules is never checked.\n name: 'tanstack-start-core:import-protection-transform-cache',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n return environmentNames.has(env.name)\n },\n\n transform: {\n filter: {\n id: {\n include: [/\\.[cm]?[tj]sx?($|\\?)/],\n },\n },\n handler(code, id) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const file = normalizeFilePath(id)\n\n // Only cache files that could ever be checked as an importer.\n // This reuses the same include/exclude/ignoreImporters predicate as\n // the main import-protection resolveId hook.\n if (!shouldCheckImporter(file)) {\n return undefined\n }\n\n // getCombinedSourcemap() returns the composed sourcemap of all\n // transform hooks that ran before this one. It includes\n // sourcesContent so we can extract original source later.\n let map: SourceMapLike | undefined\n try {\n map = this.getCombinedSourcemap()\n } catch {\n // No sourcemap available (e.g. virtual modules or modules\n // that no prior plugin produced a map for).\n map = undefined\n }\n\n // Extract the original source from sourcesContent right here.\n // Composed sourcemaps can contain multiple sources; try to pick the\n // entry that best matches this importer.\n let originalCode: string | undefined\n if (map?.sourcesContent) {\n originalCode = pickOriginalCodeFromSourcesContent(\n map,\n file,\n config.root,\n )\n }\n\n // Precompute a line index for fast index->line/col conversions.\n const lineIndex = buildLineIndex(code)\n\n // Key by the full normalized module ID including query params\n // (e.g. \"src/routes/index.tsx?tsr-split=component\") so that\n // virtual modules derived from the same physical file each get\n // their own cache entry.\n const cacheKey = normalizePath(id)\n const envState = getEnv(envName)\n envState.transformResultCache.set(cacheKey, {\n code,\n map,\n originalCode,\n lineIndex,\n })\n\n // Maintain reverse index so hotUpdate invalidation is O(keys for file).\n let keySet = envState.transformResultKeysByFile.get(file)\n if (!keySet) {\n keySet = new Set<string>()\n envState.transformResultKeysByFile.set(file, keySet)\n }\n keySet.add(cacheKey)\n\n // Also store/update the stripped-path entry so that lookups by\n // physical file path (e.g. from trace steps in the import graph,\n // which normalize away query params) still find a result.\n // The last variant transformed wins, which is acceptable — trace\n // lookups are best-effort for line numbers.\n if (cacheKey !== file) {\n envState.transformResultCache.set(file, {\n code,\n map,\n originalCode,\n lineIndex,\n })\n keySet.add(file)\n }\n\n // Return nothing — we don't modify the code.\n return undefined\n },\n },\n },\n {\n // Separate plugin so the transform can be enabled/disabled per-environment.\n name: 'tanstack-start-core:import-protection-mock-rewrite',\n enforce: 'pre',\n\n // Only needed during dev. In build, we rely on Rollup's syntheticNamedExports.\n apply: 'serve',\n\n applyToEnvironment(env) {\n if (!config.enabled) return false\n // Only needed in mock mode — when not mocking, there is nothing to\n // record. applyToEnvironment runs after configResolved, so\n // config.effectiveBehavior is already set.\n if (config.effectiveBehavior !== 'mock') return false\n // We record expected named exports per importer in all Start Vite\n // environments during dev so mock-edge modules can provide explicit\n // ESM named exports.\n return environmentNames.has(env.name)\n },\n\n transform: {\n filter: {\n id: {\n include: [/\\.[cm]?[tj]sx?($|\\?)/],\n },\n },\n handler(code, id) {\n if (!config.enabled) return undefined\n const envName = this.environment.name\n const envState = envStates.get(envName)\n if (!envState) return undefined\n\n // Record export names per source for this importer so we can generate\n // dev mock-edge modules without any disk reads.\n try {\n const importerFile = normalizeFilePath(id)\n envState.mockExportsByImporter.set(\n importerFile,\n collectMockExportNamesBySource(code),\n )\n } catch {\n // Best-effort only\n }\n\n // Note: we no longer rewrite imports here.\n // Dev uses per-importer mock-edge modules in resolveId so native ESM\n // has explicit named exports, and runtime diagnostics are handled by\n // the mock runtime proxy when those mocks are actually invoked.\n return undefined\n },\n },\n },\n ] satisfies Array<PluginOption>\n\n // ---------------------------------------------------------------------------\n // Violation handling\n // ---------------------------------------------------------------------------\n\n function handleViolation(\n this: { warn: (msg: string) => void; error: (msg: string) => never },\n env: EnvState,\n info: ViolationInfo,\n opts?: { silent?: boolean },\n ): { id: string; syntheticNamedExports: boolean } | string | undefined {\n const key = dedupeKey(\n info.type,\n info.importer,\n info.specifier,\n info.resolved,\n )\n\n if (!opts?.silent) {\n // Call user callback\n if (config.onViolation) {\n const result = config.onViolation(info)\n if (result === false) {\n return undefined\n }\n }\n\n const seen = hasSeen(env, key)\n\n if (config.effectiveBehavior === 'error') {\n if (!seen) this.error(formatViolation(info, config.root))\n return undefined\n }\n\n // Mock mode: log once, but always return the mock module.\n if (!seen) {\n this.warn(formatViolation(info, config.root))\n }\n } else {\n // Silent mode: in error behavior, skip entirely (no mock needed\n // for compiler-internal lookups); in mock mode, fall through to\n // return the mock module ID without logging.\n if (config.effectiveBehavior === 'error') {\n return undefined\n }\n }\n\n env.deniedSources.add(info.specifier)\n let edgeSet = env.deniedEdges.get(info.importer)\n if (!edgeSet) {\n edgeSet = new Set<string>()\n env.deniedEdges.set(info.importer, edgeSet)\n }\n edgeSet.add(info.specifier)\n\n if (config.command === 'serve') {\n const runtimeId = mockRuntimeModuleIdFromViolation(\n info,\n config.mockAccess,\n config.root,\n )\n return resolveViteId(\n buildMockEdgeModuleId(env, info.importer, info.specifier, runtimeId),\n )\n }\n\n // Build: Rollup can synthesize named exports.\n return { id: RESOLVED_MOCK_MODULE_ID, syntheticNamedExports: true }\n }\n}\n"],"names":["opts"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { CompileStartFrameworkOptions } from '../types.js';
2
2
  import { GenerateFunctionIdFnOptional } from './types.js';
3
3
  import { PluginOption } from 'vite';
4
+ export declare const SERVER_FN_LOOKUP = "server-fn-module-lookup";
4
5
  export interface StartCompilerPluginOptions {
5
6
  framework: CompileStartFrameworkOptions;
6
7
  environments: Array<{
@@ -336,6 +336,7 @@ function startCompilerPlugin(opts) {
336
336
  ];
337
337
  }
338
338
  export {
339
+ SERVER_FN_LOOKUP,
339
340
  startCompilerPlugin
340
341
  };
341
342
  //# sourceMappingURL=plugin.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../../../src/start-compiler-plugin/plugin.ts"],"sourcesContent":["import assert from 'node:assert'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { resolve as resolvePath } from 'pathe'\nimport { TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from '../constants'\nimport {\n KindDetectionPatterns,\n LookupKindsPerEnv,\n StartCompiler,\n detectKindsInCode,\n} from './compiler'\nimport { cleanId } from './utils'\nimport type { CompileStartFrameworkOptions } from '../types'\nimport type { LookupConfig, LookupKind } from './compiler'\nimport type { GenerateFunctionIdFnOptional, ServerFn } from './types'\nimport type { PluginOption } from 'vite'\n\n// Derive transform code filter from KindDetectionPatterns (single source of truth)\nfunction getTransformCodeFilterForEnv(env: 'client' | 'server'): Array<RegExp> {\n const validKinds = LookupKindsPerEnv[env]\n const patterns: Array<RegExp> = []\n for (const [kind, pattern] of Object.entries(KindDetectionPatterns) as Array<\n [LookupKind, RegExp]\n >) {\n if (validKinds.has(kind)) {\n patterns.push(pattern)\n }\n }\n return patterns\n}\n\nconst getLookupConfigurationsForEnv = (\n env: 'client' | 'server',\n framework: CompileStartFrameworkOptions,\n): Array<LookupConfig> => {\n // Common configs for all environments\n const commonConfigs: Array<LookupConfig> = [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerFn',\n kind: 'Root',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createIsomorphicFn',\n kind: 'IsomorphicFn',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerOnlyFn',\n kind: 'ServerOnlyFn',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createClientOnlyFn',\n kind: 'ClientOnlyFn',\n },\n ]\n\n if (env === 'client') {\n return [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createMiddleware',\n kind: 'Root',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createStart',\n kind: 'Root',\n },\n ...commonConfigs,\n ]\n } else {\n // Server-only: add ClientOnly JSX component lookup\n return [\n ...commonConfigs,\n {\n libName: `@tanstack/${framework}-router`,\n rootExport: 'ClientOnly',\n kind: 'ClientOnlyJSX',\n },\n ]\n }\n}\nconst SERVER_FN_LOOKUP = 'server-fn-module-lookup'\n\nfunction resolveViteId(id: string) {\n return `\\0${id}`\n}\n\nconst validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`\n\nfunction parseIdQuery(id: string): {\n filename: string\n query: {\n [k: string]: string\n }\n} {\n if (!id.includes('?')) return { filename: id, query: {} }\n const [filename, rawQuery] = id.split(`?`, 2) as [string, string]\n const query = Object.fromEntries(new URLSearchParams(rawQuery))\n return { filename, query }\n}\n\n/**\n * Generates the manifest module code for server functions.\n * @param serverFnsById - Map of function IDs to their server function info\n * @param includeClientReferencedCheck - Whether to include isClientReferenced flag and runtime check.\n * This is needed when SSR is NOT the provider, so server-only-referenced functions in the manifest\n * can be blocked from client HTTP requests.\n */\nfunction generateManifestModule(\n serverFnsById: Record<string, ServerFn>,\n includeClientReferencedCheck: boolean,\n): string {\n const manifestEntries = Object.entries(serverFnsById)\n .map(([id, fn]) => {\n const baseEntry = `'${id}': {\n functionName: '${fn.functionName}',\n importer: () => import(${JSON.stringify(fn.extractedFilename)})${\n includeClientReferencedCheck\n ? `,\n isClientReferenced: ${fn.isClientReferenced ?? true}`\n : ''\n }\n }`\n return baseEntry\n })\n .join(',')\n\n const getServerFnByIdParams = includeClientReferencedCheck ? 'id, opts' : 'id'\n const clientReferencedCheck = includeClientReferencedCheck\n ? `\n // If called from client, only allow client-referenced functions\n if (opts?.fromClient && !serverFnInfo.isClientReferenced) {\n throw new Error('Server function not accessible from client: ' + id)\n }\n`\n : ''\n\n return `\n const manifest = {${manifestEntries}}\n\n export async function getServerFnById(${getServerFnByIdParams}) {\n const serverFnInfo = manifest[id]\n if (!serverFnInfo) {\n throw new Error('Server function info not found for ' + id)\n }\n${clientReferencedCheck}\n const fnModule = await serverFnInfo.importer()\n\n if (!fnModule) {\n console.info('serverFnInfo', serverFnInfo)\n throw new Error('Server function module not resolved for ' + id)\n }\n\n const action = fnModule[serverFnInfo.functionName]\n\n if (!action) {\n console.info('serverFnInfo', serverFnInfo)\n console.info('fnModule', fnModule)\n\n throw new Error(\n \\`Server function module export not resolved for serverFn ID: \\${id}\\`,\n )\n }\n return action\n }\n `\n}\n\nexport interface StartCompilerPluginOptions {\n framework: CompileStartFrameworkOptions\n environments: Array<{ name: string; type: 'client' | 'server' }>\n /**\n * Custom function ID generator (optional).\n */\n generateFunctionId?: GenerateFunctionIdFnOptional\n /**\n * The Vite environment name for the server function provider.\n */\n providerEnvName: string\n}\n\nexport function startCompilerPlugin(\n opts: StartCompilerPluginOptions,\n): PluginOption {\n const compilers: Record<string /* envName */, StartCompiler> = {}\n\n // Shared registry of server functions across all environments\n const serverFnsById: Record<string, ServerFn> = {}\n\n const onServerFnsById = (d: Record<string, ServerFn>) => {\n Object.assign(serverFnsById, d)\n }\n\n let root = process.cwd()\n let _command: 'build' | 'serve' = 'build'\n\n const resolvedResolverVirtualImportId = resolveViteId(\n VIRTUAL_MODULES.serverFnResolver,\n )\n\n // Determine which environments need the resolver (getServerFnById)\n // SSR environment always needs the resolver for server-side calls\n // Provider environment needs it for the actual implementation\n const ssrEnvName = VITE_ENVIRONMENT_NAMES.server\n\n // SSR is the provider when the provider environment is the default server environment\n const ssrIsProvider = opts.providerEnvName === ssrEnvName\n\n // Environments that need the resolver: SSR (for server calls) and provider (for implementation)\n const appliedResolverEnvironments = new Set(\n ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName],\n )\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // Derive transform code filter from KindDetectionPatterns (single source of truth)\n const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)\n\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n configResolved(config) {\n root = config.root\n _command = config.command\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers[this.environment.name]\n if (!compiler) {\n // Default to 'dev' mode for unknown environments (conservative: no caching)\n const mode = this.environment.mode === 'build' ? 'build' : 'dev'\n compiler = new StartCompiler({\n env: environment.type,\n envName: environment.name,\n root,\n lookupKinds: LookupKindsPerEnv[environment.type],\n lookupConfigurations: getLookupConfigurationsForEnv(\n environment.type,\n opts.framework,\n ),\n mode,\n framework: opts.framework,\n providerEnvName: opts.providerEnvName,\n generateFunctionId: opts.generateFunctionId,\n onServerFnsById,\n getKnownServerFns: () => serverFnsById,\n loadModule: async (id: string) => {\n if (this.environment.mode === 'build') {\n const loaded = await this.load({ id })\n // Handle modules with no runtime code (e.g., type-only exports).\n // After TypeScript compilation, these become empty modules.\n // Create an empty module info instead of throwing.\n const code = loaded.code ?? ''\n compiler!.ingestModule({ code, id })\n } else if (this.environment.mode === 'dev') {\n /**\n * in dev, vite does not return code from `ctx.load()`\n * so instead, we need to take a different approach\n * we must force vite to load the module and run it through the vite plugin pipeline\n * we can do this by using the `fetchModule` method\n * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST\n */\n await this.environment.fetchModule(\n id + '?' + SERVER_FN_LOOKUP,\n )\n } else {\n throw new Error(\n `could not load module ${id}: unknown environment mode ${this.environment.mode}`,\n )\n }\n },\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n return null\n },\n })\n compilers[this.environment.name] = compiler\n }\n\n // Detect which kinds are present in this file before parsing\n const detectedKinds = detectKindsInCode(code, environment.type)\n\n const result = await compiler.compile({\n id,\n code,\n detectedKinds,\n })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers[this.environment.name]\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers[this.environment.name]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n // Validate server function ID in dev mode\n {\n name: 'tanstack-start-core:validate-server-fn-id',\n apply: 'serve',\n load: {\n filter: {\n id: new RegExp(resolveViteId(validateServerFnIdVirtualModule)),\n },\n async handler(id) {\n const parsed = parseIdQuery(id)\n const fnId = parsed.query.id\n if (fnId && serverFnsById[fnId]) {\n return `export {}`\n }\n\n // ID not yet registered — the source file may not have been\n // transformed in this dev session yet (e.g. cold restart with\n // cached client). Try to decode the ID, discover the source\n // file, trigger its compilation, and re-check.\n if (fnId) {\n try {\n const decoded = JSON.parse(\n Buffer.from(fnId, 'base64url').toString('utf8'),\n )\n if (\n typeof decoded.file === 'string' &&\n typeof decoded.export === 'string'\n ) {\n // decoded.file looks like \"/@id/src/foo.ts?tss-serverfn-split\"\n // Strip the /@id/ prefix and ?tss-serverfn-split suffix to\n // get the original source file path that needs transforming.\n let sourceFile = decoded.file\n if (sourceFile.startsWith('/@id/')) {\n sourceFile = sourceFile.slice('/@id/'.length)\n }\n const qIdx = sourceFile.indexOf('?')\n if (qIdx !== -1) {\n sourceFile = sourceFile.slice(0, qIdx)\n }\n\n // Resolve to absolute path\n const absPath = resolvePath(root, sourceFile)\n\n // Trigger transform of the source file in this environment,\n // which will compile createServerFn calls and populate\n // serverFnsById as a side effect.\n // This plugin only runs in dev (apply: 'serve'), so mode\n // must be 'dev' — assert to narrow to DevEnvironment.\n assert(this.environment.mode === 'dev')\n await this.environment.fetchModule(absPath)\n\n // Re-check after lazy compilation\n if (serverFnsById[fnId]) {\n return `export {}`\n }\n }\n } catch {\n // Decoding or fetching failed — fall through to error\n }\n }\n\n this.error(`Invalid server function ID: ${fnId}`)\n },\n },\n },\n // Manifest plugin for server environments\n {\n name: 'tanstack-start-core:server-fn-resolver',\n enforce: 'pre',\n applyToEnvironment: (env) => {\n return appliedResolverEnvironments.has(env.name)\n },\n configResolved(config) {\n root = config.root\n _command = config.command\n },\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.serverFnResolver) },\n handler() {\n return resolvedResolverVirtualImportId\n },\n },\n load: {\n filter: { id: new RegExp(resolvedResolverVirtualImportId) },\n handler() {\n // When SSR is not the provider, SSR callers need to use HTTP to call server functions\n // since they can't directly import from the provider environment\n if (this.environment.name !== opts.providerEnvName) {\n // SSR caller: use HTTP-based getServerFnById\n // This re-exports from the start-server-core package which handles HTTP calls\n return `export { getServerFnById } from '@tanstack/start-server-core/server-fn-ssr-caller'`\n }\n\n if (this.environment.mode !== 'build') {\n const mod = `\n export async function getServerFnById(id) {\n const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + id\n await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)\n const decoded = Buffer.from(id, 'base64url').toString('utf8')\n const devServerFn = JSON.parse(decoded)\n const mod = await import(/* @vite-ignore */ devServerFn.file)\n return mod[devServerFn.export]\n }\n `\n return mod\n }\n\n // When SSR is the provider, server-only-referenced functions aren't in the manifest,\n // so no isClientReferenced check is needed.\n // When SSR is NOT the provider (custom provider env), server-only-referenced\n // functions ARE in the manifest and need the isClientReferenced check to\n // block direct client HTTP requests to server-only-referenced functions.\n const includeClientReferencedCheck = !ssrIsProvider\n return generateManifestModule(\n serverFnsById,\n includeClientReferencedCheck,\n )\n },\n },\n },\n ]\n}\n"],"names":["id","code","resolvePath"],"mappings":"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"}
1
+ {"version":3,"file":"plugin.js","sources":["../../../src/start-compiler-plugin/plugin.ts"],"sourcesContent":["import assert from 'node:assert'\nimport { VIRTUAL_MODULES } from '@tanstack/start-server-core'\nimport { resolve as resolvePath } from 'pathe'\nimport { TRANSFORM_ID_REGEX, VITE_ENVIRONMENT_NAMES } from '../constants'\nimport {\n KindDetectionPatterns,\n LookupKindsPerEnv,\n StartCompiler,\n detectKindsInCode,\n} from './compiler'\nimport { cleanId } from './utils'\nimport type { CompileStartFrameworkOptions } from '../types'\nimport type { LookupConfig, LookupKind } from './compiler'\nimport type { GenerateFunctionIdFnOptional, ServerFn } from './types'\nimport type { PluginOption } from 'vite'\n\n// Derive transform code filter from KindDetectionPatterns (single source of truth)\nfunction getTransformCodeFilterForEnv(env: 'client' | 'server'): Array<RegExp> {\n const validKinds = LookupKindsPerEnv[env]\n const patterns: Array<RegExp> = []\n for (const [kind, pattern] of Object.entries(KindDetectionPatterns) as Array<\n [LookupKind, RegExp]\n >) {\n if (validKinds.has(kind)) {\n patterns.push(pattern)\n }\n }\n return patterns\n}\n\nconst getLookupConfigurationsForEnv = (\n env: 'client' | 'server',\n framework: CompileStartFrameworkOptions,\n): Array<LookupConfig> => {\n // Common configs for all environments\n const commonConfigs: Array<LookupConfig> = [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerFn',\n kind: 'Root',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createIsomorphicFn',\n kind: 'IsomorphicFn',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createServerOnlyFn',\n kind: 'ServerOnlyFn',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createClientOnlyFn',\n kind: 'ClientOnlyFn',\n },\n ]\n\n if (env === 'client') {\n return [\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createMiddleware',\n kind: 'Root',\n },\n {\n libName: `@tanstack/${framework}-start`,\n rootExport: 'createStart',\n kind: 'Root',\n },\n ...commonConfigs,\n ]\n } else {\n // Server-only: add ClientOnly JSX component lookup\n return [\n ...commonConfigs,\n {\n libName: `@tanstack/${framework}-router`,\n rootExport: 'ClientOnly',\n kind: 'ClientOnlyJSX',\n },\n ]\n }\n}\nexport const SERVER_FN_LOOKUP = 'server-fn-module-lookup'\n\nfunction resolveViteId(id: string) {\n return `\\0${id}`\n}\n\nconst validateServerFnIdVirtualModule = `virtual:tanstack-start-validate-server-fn-id`\n\nfunction parseIdQuery(id: string): {\n filename: string\n query: {\n [k: string]: string\n }\n} {\n if (!id.includes('?')) return { filename: id, query: {} }\n const [filename, rawQuery] = id.split(`?`, 2) as [string, string]\n const query = Object.fromEntries(new URLSearchParams(rawQuery))\n return { filename, query }\n}\n\n/**\n * Generates the manifest module code for server functions.\n * @param serverFnsById - Map of function IDs to their server function info\n * @param includeClientReferencedCheck - Whether to include isClientReferenced flag and runtime check.\n * This is needed when SSR is NOT the provider, so server-only-referenced functions in the manifest\n * can be blocked from client HTTP requests.\n */\nfunction generateManifestModule(\n serverFnsById: Record<string, ServerFn>,\n includeClientReferencedCheck: boolean,\n): string {\n const manifestEntries = Object.entries(serverFnsById)\n .map(([id, fn]) => {\n const baseEntry = `'${id}': {\n functionName: '${fn.functionName}',\n importer: () => import(${JSON.stringify(fn.extractedFilename)})${\n includeClientReferencedCheck\n ? `,\n isClientReferenced: ${fn.isClientReferenced ?? true}`\n : ''\n }\n }`\n return baseEntry\n })\n .join(',')\n\n const getServerFnByIdParams = includeClientReferencedCheck ? 'id, opts' : 'id'\n const clientReferencedCheck = includeClientReferencedCheck\n ? `\n // If called from client, only allow client-referenced functions\n if (opts?.fromClient && !serverFnInfo.isClientReferenced) {\n throw new Error('Server function not accessible from client: ' + id)\n }\n`\n : ''\n\n return `\n const manifest = {${manifestEntries}}\n\n export async function getServerFnById(${getServerFnByIdParams}) {\n const serverFnInfo = manifest[id]\n if (!serverFnInfo) {\n throw new Error('Server function info not found for ' + id)\n }\n${clientReferencedCheck}\n const fnModule = await serverFnInfo.importer()\n\n if (!fnModule) {\n console.info('serverFnInfo', serverFnInfo)\n throw new Error('Server function module not resolved for ' + id)\n }\n\n const action = fnModule[serverFnInfo.functionName]\n\n if (!action) {\n console.info('serverFnInfo', serverFnInfo)\n console.info('fnModule', fnModule)\n\n throw new Error(\n \\`Server function module export not resolved for serverFn ID: \\${id}\\`,\n )\n }\n return action\n }\n `\n}\n\nexport interface StartCompilerPluginOptions {\n framework: CompileStartFrameworkOptions\n environments: Array<{ name: string; type: 'client' | 'server' }>\n /**\n * Custom function ID generator (optional).\n */\n generateFunctionId?: GenerateFunctionIdFnOptional\n /**\n * The Vite environment name for the server function provider.\n */\n providerEnvName: string\n}\n\nexport function startCompilerPlugin(\n opts: StartCompilerPluginOptions,\n): PluginOption {\n const compilers: Record<string /* envName */, StartCompiler> = {}\n\n // Shared registry of server functions across all environments\n const serverFnsById: Record<string, ServerFn> = {}\n\n const onServerFnsById = (d: Record<string, ServerFn>) => {\n Object.assign(serverFnsById, d)\n }\n\n let root = process.cwd()\n let _command: 'build' | 'serve' = 'build'\n\n const resolvedResolverVirtualImportId = resolveViteId(\n VIRTUAL_MODULES.serverFnResolver,\n )\n\n // Determine which environments need the resolver (getServerFnById)\n // SSR environment always needs the resolver for server-side calls\n // Provider environment needs it for the actual implementation\n const ssrEnvName = VITE_ENVIRONMENT_NAMES.server\n\n // SSR is the provider when the provider environment is the default server environment\n const ssrIsProvider = opts.providerEnvName === ssrEnvName\n\n // Environments that need the resolver: SSR (for server calls) and provider (for implementation)\n const appliedResolverEnvironments = new Set(\n ssrIsProvider ? [opts.providerEnvName] : [ssrEnvName, opts.providerEnvName],\n )\n\n function perEnvServerFnPlugin(environment: {\n name: string\n type: 'client' | 'server'\n }): PluginOption {\n // Derive transform code filter from KindDetectionPatterns (single source of truth)\n const transformCodeFilter = getTransformCodeFilterForEnv(environment.type)\n\n return {\n name: `tanstack-start-core::server-fn:${environment.name}`,\n enforce: 'pre',\n applyToEnvironment(env) {\n return env.name === environment.name\n },\n configResolved(config) {\n root = config.root\n _command = config.command\n },\n transform: {\n filter: {\n id: {\n exclude: new RegExp(`${SERVER_FN_LOOKUP}$`),\n include: TRANSFORM_ID_REGEX,\n },\n code: {\n include: transformCodeFilter,\n },\n },\n async handler(code, id) {\n let compiler = compilers[this.environment.name]\n if (!compiler) {\n // Default to 'dev' mode for unknown environments (conservative: no caching)\n const mode = this.environment.mode === 'build' ? 'build' : 'dev'\n compiler = new StartCompiler({\n env: environment.type,\n envName: environment.name,\n root,\n lookupKinds: LookupKindsPerEnv[environment.type],\n lookupConfigurations: getLookupConfigurationsForEnv(\n environment.type,\n opts.framework,\n ),\n mode,\n framework: opts.framework,\n providerEnvName: opts.providerEnvName,\n generateFunctionId: opts.generateFunctionId,\n onServerFnsById,\n getKnownServerFns: () => serverFnsById,\n loadModule: async (id: string) => {\n if (this.environment.mode === 'build') {\n const loaded = await this.load({ id })\n // Handle modules with no runtime code (e.g., type-only exports).\n // After TypeScript compilation, these become empty modules.\n // Create an empty module info instead of throwing.\n const code = loaded.code ?? ''\n compiler!.ingestModule({ code, id })\n } else if (this.environment.mode === 'dev') {\n /**\n * in dev, vite does not return code from `ctx.load()`\n * so instead, we need to take a different approach\n * we must force vite to load the module and run it through the vite plugin pipeline\n * we can do this by using the `fetchModule` method\n * the `captureServerFnModuleLookupPlugin` captures the module code via its transform hook and invokes analyzeModuleAST\n */\n await this.environment.fetchModule(\n id + '?' + SERVER_FN_LOOKUP,\n )\n } else {\n throw new Error(\n `could not load module ${id}: unknown environment mode ${this.environment.mode}`,\n )\n }\n },\n resolveId: async (source: string, importer?: string) => {\n const r = await this.resolve(source, importer)\n if (r) {\n if (!r.external) {\n return cleanId(r.id)\n }\n }\n return null\n },\n })\n compilers[this.environment.name] = compiler\n }\n\n // Detect which kinds are present in this file before parsing\n const detectedKinds = detectKindsInCode(code, environment.type)\n\n const result = await compiler.compile({\n id,\n code,\n detectedKinds,\n })\n return result\n },\n },\n\n hotUpdate(ctx) {\n const compiler = compilers[this.environment.name]\n\n ctx.modules.forEach((m) => {\n if (m.id) {\n const deleted = compiler?.invalidateModule(m.id)\n if (deleted) {\n m.importers.forEach((importer) => {\n if (importer.id) {\n compiler?.invalidateModule(importer.id)\n }\n })\n }\n }\n })\n },\n }\n }\n\n return [\n ...opts.environments.map(perEnvServerFnPlugin),\n {\n name: 'tanstack-start-core:capture-server-fn-module-lookup',\n // we only need this plugin in dev mode\n apply: 'serve',\n applyToEnvironment(env) {\n return !!opts.environments.find((e) => e.name === env.name)\n },\n transform: {\n filter: {\n id: new RegExp(`${SERVER_FN_LOOKUP}$`),\n },\n handler(code, id) {\n const compiler = compilers[this.environment.name]\n compiler?.ingestModule({ code, id: cleanId(id) })\n },\n },\n },\n // Validate server function ID in dev mode\n {\n name: 'tanstack-start-core:validate-server-fn-id',\n apply: 'serve',\n load: {\n filter: {\n id: new RegExp(resolveViteId(validateServerFnIdVirtualModule)),\n },\n async handler(id) {\n const parsed = parseIdQuery(id)\n const fnId = parsed.query.id\n if (fnId && serverFnsById[fnId]) {\n return `export {}`\n }\n\n // ID not yet registered — the source file may not have been\n // transformed in this dev session yet (e.g. cold restart with\n // cached client). Try to decode the ID, discover the source\n // file, trigger its compilation, and re-check.\n if (fnId) {\n try {\n const decoded = JSON.parse(\n Buffer.from(fnId, 'base64url').toString('utf8'),\n )\n if (\n typeof decoded.file === 'string' &&\n typeof decoded.export === 'string'\n ) {\n // decoded.file looks like \"/@id/src/foo.ts?tss-serverfn-split\"\n // Strip the /@id/ prefix and ?tss-serverfn-split suffix to\n // get the original source file path that needs transforming.\n let sourceFile = decoded.file\n if (sourceFile.startsWith('/@id/')) {\n sourceFile = sourceFile.slice('/@id/'.length)\n }\n const qIdx = sourceFile.indexOf('?')\n if (qIdx !== -1) {\n sourceFile = sourceFile.slice(0, qIdx)\n }\n\n // Resolve to absolute path\n const absPath = resolvePath(root, sourceFile)\n\n // Trigger transform of the source file in this environment,\n // which will compile createServerFn calls and populate\n // serverFnsById as a side effect.\n // This plugin only runs in dev (apply: 'serve'), so mode\n // must be 'dev' — assert to narrow to DevEnvironment.\n assert(this.environment.mode === 'dev')\n await this.environment.fetchModule(absPath)\n\n // Re-check after lazy compilation\n if (serverFnsById[fnId]) {\n return `export {}`\n }\n }\n } catch {\n // Decoding or fetching failed — fall through to error\n }\n }\n\n this.error(`Invalid server function ID: ${fnId}`)\n },\n },\n },\n // Manifest plugin for server environments\n {\n name: 'tanstack-start-core:server-fn-resolver',\n enforce: 'pre',\n applyToEnvironment: (env) => {\n return appliedResolverEnvironments.has(env.name)\n },\n configResolved(config) {\n root = config.root\n _command = config.command\n },\n resolveId: {\n filter: { id: new RegExp(VIRTUAL_MODULES.serverFnResolver) },\n handler() {\n return resolvedResolverVirtualImportId\n },\n },\n load: {\n filter: { id: new RegExp(resolvedResolverVirtualImportId) },\n handler() {\n // When SSR is not the provider, SSR callers need to use HTTP to call server functions\n // since they can't directly import from the provider environment\n if (this.environment.name !== opts.providerEnvName) {\n // SSR caller: use HTTP-based getServerFnById\n // This re-exports from the start-server-core package which handles HTTP calls\n return `export { getServerFnById } from '@tanstack/start-server-core/server-fn-ssr-caller'`\n }\n\n if (this.environment.mode !== 'build') {\n const mod = `\n export async function getServerFnById(id) {\n const validateIdImport = ${JSON.stringify(validateServerFnIdVirtualModule)} + '?id=' + id\n await import(/* @vite-ignore */ '/@id/__x00__' + validateIdImport)\n const decoded = Buffer.from(id, 'base64url').toString('utf8')\n const devServerFn = JSON.parse(decoded)\n const mod = await import(/* @vite-ignore */ devServerFn.file)\n return mod[devServerFn.export]\n }\n `\n return mod\n }\n\n // When SSR is the provider, server-only-referenced functions aren't in the manifest,\n // so no isClientReferenced check is needed.\n // When SSR is NOT the provider (custom provider env), server-only-referenced\n // functions ARE in the manifest and need the isClientReferenced check to\n // block direct client HTTP requests to server-only-referenced functions.\n const includeClientReferencedCheck = !ssrIsProvider\n return generateManifestModule(\n serverFnsById,\n includeClientReferencedCheck,\n )\n },\n },\n },\n ]\n}\n"],"names":["id","code","resolvePath"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/start-plugin-core",
3
- "version": "1.161.0",
3
+ "version": "1.161.3",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -53,19 +53,19 @@
53
53
  "exsolve": "^1.0.7",
54
54
  "pathe": "^2.0.3",
55
55
  "picomatch": "^4.0.3",
56
- "srvx": "^0.11.2",
56
+ "srvx": "^0.11.7",
57
57
  "source-map": "^0.7.6",
58
58
  "tinyglobby": "^0.2.15",
59
59
  "ufo": "^1.5.4",
60
60
  "vitefu": "^1.1.1",
61
61
  "xmlbuilder2": "^4.0.3",
62
62
  "zod": "^3.24.2",
63
- "@tanstack/router-generator": "1.160.1",
64
- "@tanstack/router-core": "1.160.0",
63
+ "@tanstack/router-core": "1.161.3",
64
+ "@tanstack/router-plugin": "1.161.3",
65
65
  "@tanstack/router-utils": "1.158.0",
66
- "@tanstack/start-client-core": "1.160.0",
67
- "@tanstack/router-plugin": "1.161.0",
68
- "@tanstack/start-server-core": "1.160.0"
66
+ "@tanstack/start-client-core": "1.161.3",
67
+ "@tanstack/router-generator": "1.161.3",
68
+ "@tanstack/start-server-core": "1.161.3"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/babel__code-frame": "^7.0.6",
@@ -3,6 +3,7 @@ import { normalizePath } from 'vite'
3
3
 
4
4
  import { resolveViteId } from '../utils'
5
5
  import { VITE_ENVIRONMENT_NAMES } from '../constants'
6
+ import { SERVER_FN_LOOKUP } from '../start-compiler-plugin/plugin'
6
7
  import { ImportGraph, buildTrace, formatViolation } from './trace'
7
8
  import {
8
9
  getDefaultImportProtectionRules,
@@ -348,6 +349,7 @@ export function importProtectionPlugin(
348
349
  source: string,
349
350
  resolvedId: string,
350
351
  relativePath: string,
352
+ opts?: { silent?: boolean },
351
353
  ): Promise<ReturnType<typeof handleViolation> | undefined> {
352
354
  const markerKind = getMarkerKindForFile(resolvedId)
353
355
  const violates =
@@ -375,7 +377,7 @@ export function importProtectionPlugin(
375
377
  },
376
378
  )
377
379
 
378
- return handleViolation.call(ctx, env, info)
380
+ return handleViolation.call(ctx, env, info, opts)
379
381
  }
380
382
 
381
383
  function buildMockEdgeModuleId(
@@ -744,6 +746,25 @@ export function importProtectionPlugin(
744
746
  return undefined
745
747
  }
746
748
 
749
+ // Two code paths resolve imports from raw (pre-compiler-transform)
750
+ // source in dev mode:
751
+ //
752
+ // 1. The Start compiler calls `fetchModule(id + '?' + SERVER_FN_LOOKUP)`
753
+ // to inspect a child module's exports. The compiler's own transform
754
+ // is excluded for these requests, so Vite sees the original imports.
755
+ //
756
+ // 2. Vite's dep-optimizer scanner (`options.scan === true`) uses esbuild
757
+ // to discover bare imports for pre-bundling. esbuild reads raw source
758
+ // without running Vite transform hooks, so it also sees imports that
759
+ // the compiler would normally strip.
760
+ //
761
+ // In both cases the imports are NOT real client-side imports. We must
762
+ // suppress violation *reporting* (no warnings / errors) but still return
763
+ // mock module IDs so that transitive resolution doesn't blow up.
764
+ const isPreTransformResolve =
765
+ importer.includes('?' + SERVER_FN_LOOKUP) ||
766
+ !!(_options as Record<string, unknown>).scan
767
+
747
768
  // Check if this is a marker import
748
769
  if (config.markerSpecifiers.serverOnly.has(source)) {
749
770
  // Record importer as server-only
@@ -771,7 +792,9 @@ export function importProtectionPlugin(
771
792
  message: `Module "${getRelativePath(resolvedImporter)}" is marked server-only but is imported in the client environment`,
772
793
  },
773
794
  )
774
- handleViolation.call(this, env, info)
795
+ handleViolation.call(this, env, info, {
796
+ silent: isPreTransformResolve,
797
+ })
775
798
  }
776
799
 
777
800
  // Return virtual empty module
@@ -802,7 +825,9 @@ export function importProtectionPlugin(
802
825
  message: `Module "${getRelativePath(resolvedImporter)}" is marked client-only but is imported in the server environment`,
803
826
  },
804
827
  )
805
- handleViolation.call(this, env, info)
828
+ handleViolation.call(this, env, info, {
829
+ silent: isPreTransformResolve,
830
+ })
806
831
  }
807
832
 
808
833
  return resolveViteId(`${MARKER_PREFIX}client-only`)
@@ -834,7 +859,9 @@ export function importProtectionPlugin(
834
859
  message: `Import "${source}" is denied in the "${envName}" environment`,
835
860
  },
836
861
  )
837
- return handleViolation.call(this, env, info)
862
+ return handleViolation.call(this, env, info, {
863
+ silent: isPreTransformResolve,
864
+ })
838
865
  }
839
866
 
840
867
  // 2. Resolve the import (cached) — needed for file-based denial,
@@ -890,7 +917,9 @@ export function importProtectionPlugin(
890
917
  message: `Import "${source}" (resolved to "${relativePath}") is denied in the "${envName}" environment`,
891
918
  },
892
919
  )
893
- return handleViolation.call(this, env, info)
920
+ return handleViolation.call(this, env, info, {
921
+ silent: isPreTransformResolve,
922
+ })
894
923
  }
895
924
 
896
925
  // Marker restrictions apply regardless of explicit deny rules.
@@ -904,6 +933,7 @@ export function importProtectionPlugin(
904
933
  source,
905
934
  resolved,
906
935
  relativePath,
936
+ { silent: isPreTransformResolve },
907
937
  )
908
938
  if (markerRes !== undefined) {
909
939
  return markerRes
@@ -1120,6 +1150,7 @@ export function importProtectionPlugin(
1120
1150
  this: { warn: (msg: string) => void; error: (msg: string) => never },
1121
1151
  env: EnvState,
1122
1152
  info: ViolationInfo,
1153
+ opts?: { silent?: boolean },
1123
1154
  ): { id: string; syntheticNamedExports: boolean } | string | undefined {
1124
1155
  const key = dedupeKey(
1125
1156
  info.type,
@@ -1128,24 +1159,33 @@ export function importProtectionPlugin(
1128
1159
  info.resolved,
1129
1160
  )
1130
1161
 
1131
- // Call user callback
1132
- if (config.onViolation) {
1133
- const result = config.onViolation(info)
1134
- if (result === false) {
1135
- return undefined
1162
+ if (!opts?.silent) {
1163
+ // Call user callback
1164
+ if (config.onViolation) {
1165
+ const result = config.onViolation(info)
1166
+ if (result === false) {
1167
+ return undefined
1168
+ }
1136
1169
  }
1137
- }
1138
1170
 
1139
- const seen = hasSeen(env, key)
1171
+ const seen = hasSeen(env, key)
1140
1172
 
1141
- if (config.effectiveBehavior === 'error') {
1142
- if (!seen) this.error(formatViolation(info, config.root))
1143
- return undefined
1144
- }
1173
+ if (config.effectiveBehavior === 'error') {
1174
+ if (!seen) this.error(formatViolation(info, config.root))
1175
+ return undefined
1176
+ }
1145
1177
 
1146
- // Mock mode: log once, but always return the mock module.
1147
- if (!seen) {
1148
- this.warn(formatViolation(info, config.root))
1178
+ // Mock mode: log once, but always return the mock module.
1179
+ if (!seen) {
1180
+ this.warn(formatViolation(info, config.root))
1181
+ }
1182
+ } else {
1183
+ // Silent mode: in error behavior, skip entirely (no mock needed
1184
+ // for compiler-internal lookups); in mock mode, fall through to
1185
+ // return the mock module ID without logging.
1186
+ if (config.effectiveBehavior === 'error') {
1187
+ return undefined
1188
+ }
1149
1189
  }
1150
1190
 
1151
1191
  env.deniedSources.add(info.specifier)
@@ -82,7 +82,7 @@ const getLookupConfigurationsForEnv = (
82
82
  ]
83
83
  }
84
84
  }
85
- const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
85
+ export const SERVER_FN_LOOKUP = 'server-fn-module-lookup'
86
86
 
87
87
  function resolveViteId(id: string) {
88
88
  return `\0${id}`