@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.
- package/dist/esm/import-protection-plugin/plugin.js +36 -19
- package/dist/esm/import-protection-plugin/plugin.js.map +1 -1
- package/dist/esm/start-compiler-plugin/plugin.d.ts +1 -0
- package/dist/esm/start-compiler-plugin/plugin.js +1 -0
- package/dist/esm/start-compiler-plugin/plugin.js.map +1 -1
- package/package.json +7 -7
- package/src/import-protection-plugin/plugin.ts +59 -19
- package/src/start-compiler-plugin/plugin.ts +1 -1
|
@@ -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 (
|
|
661
|
-
|
|
662
|
-
|
|
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<{
|
|
@@ -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.
|
|
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.
|
|
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-
|
|
64
|
-
"@tanstack/router-
|
|
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.
|
|
67
|
-
"@tanstack/router-
|
|
68
|
-
"@tanstack/start-server-core": "1.
|
|
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
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
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
|
-
|
|
1171
|
+
const seen = hasSeen(env, key)
|
|
1140
1172
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1173
|
+
if (config.effectiveBehavior === 'error') {
|
|
1174
|
+
if (!seen) this.error(formatViolation(info, config.root))
|
|
1175
|
+
return undefined
|
|
1176
|
+
}
|
|
1145
1177
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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)
|