@tanstack/start-plugin-core 1.162.9 → 1.163.1

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.
@@ -6,11 +6,13 @@ function getDefaultImportProtectionRules() {
6
6
  return {
7
7
  client: {
8
8
  specifiers: clientSpecifiers,
9
- files: ["**/*.server.*"]
9
+ files: ["**/*.server.*"],
10
+ excludeFiles: ["**/node_modules/**"]
10
11
  },
11
12
  server: {
12
13
  specifiers: [],
13
- files: ["**/*.client.*"]
14
+ files: ["**/*.client.*"],
15
+ excludeFiles: ["**/node_modules/**"]
14
16
  }
15
17
  };
16
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"defaults.js","sources":["../../../src/import-protection-plugin/defaults.ts"],"sourcesContent":["import type { ImportProtectionEnvRules } from '../schema'\nimport type { Pattern } from './utils'\n\nexport interface DefaultImportProtectionRules {\n client: Required<ImportProtectionEnvRules>\n server: Required<ImportProtectionEnvRules>\n}\n\nconst frameworks = ['react', 'solid', 'vue'] as const\n\n/**\n * Returns the default import protection rules.\n *\n * All three framework variants are always included so that, e.g., a React\n * project also denies `@tanstack/solid-start/server` imports.\n */\nexport function getDefaultImportProtectionRules(): DefaultImportProtectionRules {\n const clientSpecifiers: Array<Pattern> = frameworks.map(\n (fw) => `@tanstack/${fw}-start/server`,\n )\n\n return {\n client: {\n specifiers: clientSpecifiers,\n files: ['**/*.server.*'],\n },\n server: {\n specifiers: [],\n files: ['**/*.client.*'],\n },\n }\n}\n\n/**\n * Marker module specifiers that restrict a file to a specific environment.\n */\nexport function getMarkerSpecifiers(): {\n serverOnly: Array<string>\n clientOnly: Array<string>\n} {\n return {\n serverOnly: frameworks.map((fw) => `@tanstack/${fw}-start/server-only`),\n clientOnly: frameworks.map((fw) => `@tanstack/${fw}-start/client-only`),\n }\n}\n"],"names":[],"mappings":"AAQA,MAAM,aAAa,CAAC,SAAS,SAAS,KAAK;AAQpC,SAAS,kCAAgE;AAC9E,QAAM,mBAAmC,WAAW;AAAA,IAClD,CAAC,OAAO,aAAa,EAAE;AAAA,EAAA;AAGzB,SAAO;AAAA,IACL,QAAQ;AAAA,MACN,YAAY;AAAA,MACZ,OAAO,CAAC,eAAe;AAAA,IAAA;AAAA,IAEzB,QAAQ;AAAA,MACN,YAAY,CAAA;AAAA,MACZ,OAAO,CAAC,eAAe;AAAA,IAAA;AAAA,EACzB;AAEJ;AAKO,SAAS,sBAGd;AACA,SAAO;AAAA,IACL,YAAY,WAAW,IAAI,CAAC,OAAO,aAAa,EAAE,oBAAoB;AAAA,IACtE,YAAY,WAAW,IAAI,CAAC,OAAO,aAAa,EAAE,oBAAoB;AAAA,EAAA;AAE1E;"}
1
+ {"version":3,"file":"defaults.js","sources":["../../../src/import-protection-plugin/defaults.ts"],"sourcesContent":["import type { ImportProtectionEnvRules } from '../schema'\nimport type { Pattern } from './utils'\n\nexport interface DefaultImportProtectionRules {\n client: Required<ImportProtectionEnvRules>\n server: Required<ImportProtectionEnvRules>\n}\n\nconst frameworks = ['react', 'solid', 'vue'] as const\n\n/**\n * Returns the default import protection rules.\n *\n * All three framework variants are always included so that, e.g., a React\n * project also denies `@tanstack/solid-start/server` imports.\n */\nexport function getDefaultImportProtectionRules(): DefaultImportProtectionRules {\n const clientSpecifiers: Array<Pattern> = frameworks.map(\n (fw) => `@tanstack/${fw}-start/server`,\n )\n\n return {\n client: {\n specifiers: clientSpecifiers,\n files: ['**/*.server.*'],\n excludeFiles: ['**/node_modules/**'],\n },\n server: {\n specifiers: [],\n files: ['**/*.client.*'],\n excludeFiles: ['**/node_modules/**'],\n },\n }\n}\n\n/**\n * Marker module specifiers that restrict a file to a specific environment.\n */\nexport function getMarkerSpecifiers(): {\n serverOnly: Array<string>\n clientOnly: Array<string>\n} {\n return {\n serverOnly: frameworks.map((fw) => `@tanstack/${fw}-start/server-only`),\n clientOnly: frameworks.map((fw) => `@tanstack/${fw}-start/client-only`),\n }\n}\n"],"names":[],"mappings":"AAQA,MAAM,aAAa,CAAC,SAAS,SAAS,KAAK;AAQpC,SAAS,kCAAgE;AAC9E,QAAM,mBAAmC,WAAW;AAAA,IAClD,CAAC,OAAO,aAAa,EAAE;AAAA,EAAA;AAGzB,SAAO;AAAA,IACL,QAAQ;AAAA,MACN,YAAY;AAAA,MACZ,OAAO,CAAC,eAAe;AAAA,MACvB,cAAc,CAAC,oBAAoB;AAAA,IAAA;AAAA,IAErC,QAAQ;AAAA,MACN,YAAY,CAAA;AAAA,MACZ,OAAO,CAAC,eAAe;AAAA,MACvB,cAAc,CAAC,oBAAoB;AAAA,IAAA;AAAA,EACrC;AAEJ;AAKO,SAAS,sBAGd;AACA,SAAO;AAAA,IACL,YAAY,WAAW,IAAI,CAAC,OAAO,aAAa,EAAE,oBAAoB;AAAA,IACtE,YAAY,WAAW,IAAI,CAAC,OAAO,aAAa,EAAE,oBAAoB;AAAA,EAAA;AAE1E;"}
@@ -1,6 +1,5 @@
1
1
  import { PluginOption } from 'vite';
2
2
  import { CompileStartFrameworkOptions, GetConfigFn } from '../types.js';
3
- export { RESOLVED_MOCK_MODULE_ID } from './virtualModules.js';
4
3
  export { rewriteDeniedImports } from './rewriteDeniedImports.js';
5
4
  export { dedupePatterns, extractImportSources } from './utils.js';
6
5
  export type { Pattern } from './utils.js';
@@ -8,11 +8,9 @@ import { findPostCompileUsagePos } from "./postCompileUsage.js";
8
8
  import { matchesAny, compileMatchers } from "./matchers.js";
9
9
  import { escapeRegExp, normalizeFilePath, getOrCreate, clearNormalizeFilePathCache, dedupePatterns, extractImportSources, relativizePath } from "./utils.js";
10
10
  import { collectMockExportNamesBySource } from "./rewriteDeniedImports.js";
11
- import { RESOLVED_MOCK_MODULE_ID, loadSilentMockModule, RESOLVED_MOCK_BUILD_PREFIX, RESOLVED_MOCK_EDGE_PREFIX, loadMockEdgeModule, RESOLVED_MOCK_RUNTIME_PREFIX, loadMockRuntimeModule, RESOLVED_MARKER_PREFIX, loadMarkerModule, MOCK_MODULE_ID, MOCK_EDGE_PREFIX, MOCK_RUNTIME_PREFIX, MARKER_PREFIX, mockRuntimeModuleIdFromViolation, makeMockEdgeModuleId } from "./virtualModules.js";
11
+ import { loadResolvedVirtualModule, getResolvedVirtualModuleMatchers, resolveInternalVirtualModuleId, resolvedMarkerVirtualModuleId, mockRuntimeModuleIdFromViolation, makeMockEdgeModuleId, MOCK_BUILD_PREFIX } from "./virtualModules.js";
12
12
  import { clearImportPatternCache, pickOriginalCodeFromSourcesContent, buildLineIndex, ImportLocCache, findPostCompileUsageLocation, findImportStatementLocationFromTransformed, buildCodeSnippet, addTraceImportLocations } from "./sourceLocation.js";
13
13
  const SERVER_FN_LOOKUP_QUERY = "?" + SERVER_FN_LOOKUP;
14
- const RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`);
15
- const RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`);
16
14
  const IMPORT_PROTECTION_DEBUG = process.env.TSR_IMPORT_PROTECTION_DEBUG === "1" || process.env.TSR_IMPORT_PROTECTION_DEBUG === "true";
17
15
  const IMPORT_PROTECTION_DEBUG_FILTER = process.env.TSR_IMPORT_PROTECTION_DEBUG_FILTER;
18
16
  function debugLog(...args) {
@@ -102,8 +100,8 @@ function importProtectionPlugin(opts) {
102
100
  logMode: "once",
103
101
  maxTraceDepth: 20,
104
102
  compiledRules: {
105
- client: { specifiers: [], files: [] },
106
- server: { specifiers: [], files: [] }
103
+ client: { specifiers: [], files: [], excludeFiles: [] },
104
+ server: { specifiers: [], files: [], excludeFiles: [] }
107
105
  },
108
106
  includeMatchers: [],
109
107
  excludeMatchers: [],
@@ -391,7 +389,7 @@ function importProtectionPlugin(opts) {
391
389
  function deferViolation(env, importerFile, info, mockReturnValue) {
392
390
  getOrCreate(env.pendingViolations, importerFile, () => []).push({
393
391
  info,
394
- mockReturnValue: typeof mockReturnValue === "string" ? mockReturnValue : mockReturnValue?.id ?? ""
392
+ mockReturnValue: mockReturnValue ?? ""
395
393
  });
396
394
  }
397
395
  let buildViolationCounter = 0;
@@ -431,21 +429,30 @@ function importProtectionPlugin(opts) {
431
429
  config.mockAccess,
432
430
  config.root
433
431
  );
434
- const importerFile = normalizeFilePath(info.importer);
435
- const exports = env.mockExportsByImporter.get(importerFile)?.get(info.specifier) ?? [];
432
+ const importerFile2 = normalizeFilePath(info.importer);
433
+ const exports2 = env.mockExportsByImporter.get(importerFile2)?.get(info.specifier) ?? [];
436
434
  return resolveViteId(
437
- makeMockEdgeModuleId(exports, info.specifier, runtimeId)
435
+ makeMockEdgeModuleId(exports2, info.specifier, runtimeId)
438
436
  );
439
437
  }
440
- const mockId = `${RESOLVED_MOCK_BUILD_PREFIX}${buildViolationCounter++}`;
441
- return { id: mockId, syntheticNamedExports: true };
438
+ const baseMockId = `${MOCK_BUILD_PREFIX}${buildViolationCounter++}`;
439
+ const importerFile = normalizeFilePath(info.importer);
440
+ const exports = env.mockExportsByImporter.get(importerFile)?.get(info.specifier) ?? [];
441
+ return resolveViteId(
442
+ makeMockEdgeModuleId(exports, info.specifier, baseMockId)
443
+ );
442
444
  }
443
445
  async function reportOrDeferViolation(ctx, env, importerFile, info, shouldDefer, isPreTransformResolve) {
444
446
  if (shouldDefer) {
445
447
  const result = await handleViolation(ctx, env, info, { silent: true });
446
448
  if (config.command === "build") {
447
- const mockId = typeof result === "string" ? result : result?.id ?? "";
448
- env.deferredBuildViolations.push({ info, mockModuleId: mockId });
449
+ const mockId = result ?? "";
450
+ env.deferredBuildViolations.push({
451
+ info,
452
+ mockModuleId: mockId,
453
+ // For marker violations, check importer survival instead of mock.
454
+ checkModuleId: info.type === "marker" ? info.importer : void 0
455
+ });
449
456
  } else {
450
457
  deferViolation(env, importerFile, info, result);
451
458
  await processPendingViolations(env, ctx.warn.bind(ctx));
@@ -501,15 +508,19 @@ function importProtectionPlugin(opts) {
501
508
  ...userOpts?.client?.specifiers ?? []
502
509
  ]);
503
510
  const clientFiles = userOpts?.client?.files ? [...userOpts.client.files] : [...defaults.client.files];
511
+ const clientExcludeFiles = userOpts?.client?.excludeFiles ? [...userOpts.client.excludeFiles] : [...defaults.client.excludeFiles];
504
512
  const serverSpecifiers = userOpts?.server?.specifiers ? dedupePatterns([...userOpts.server.specifiers]) : dedupePatterns([...defaults.server.specifiers]);
505
513
  const serverFiles = userOpts?.server?.files ? [...userOpts.server.files] : [...defaults.server.files];
514
+ const serverExcludeFiles = userOpts?.server?.excludeFiles ? [...userOpts.server.excludeFiles] : [...defaults.server.excludeFiles];
506
515
  config.compiledRules.client = {
507
516
  specifiers: compileMatchers(clientSpecifiers),
508
- files: compileMatchers(clientFiles)
517
+ files: compileMatchers(clientFiles),
518
+ excludeFiles: compileMatchers(clientExcludeFiles)
509
519
  };
510
520
  config.compiledRules.server = {
511
521
  specifiers: compileMatchers(serverSpecifiers),
512
- files: compileMatchers(serverFiles)
522
+ files: compileMatchers(serverFiles),
523
+ excludeFiles: compileMatchers(serverExcludeFiles)
513
524
  };
514
525
  if (userOpts?.include) {
515
526
  config.includeMatchers = compileMatchers(userOpts.include);
@@ -613,18 +624,8 @@ function importProtectionPlugin(opts) {
613
624
  });
614
625
  }
615
626
  }
616
- if (source === MOCK_MODULE_ID) {
617
- return RESOLVED_MOCK_MODULE_ID;
618
- }
619
- if (source.startsWith(MOCK_EDGE_PREFIX)) {
620
- return resolveViteId(source);
621
- }
622
- if (source.startsWith(MOCK_RUNTIME_PREFIX)) {
623
- return resolveViteId(source);
624
- }
625
- if (source.startsWith(MARKER_PREFIX)) {
626
- return resolveViteId(source);
627
- }
627
+ const internalVirtualId = resolveInternalVirtualModuleId(source);
628
+ if (internalVirtualId) return internalVirtualId;
628
629
  if (!importer) {
629
630
  env.graph.addEntry(source);
630
631
  await processPendingViolations(env, this.warn.bind(this));
@@ -678,7 +679,7 @@ function importProtectionPlugin(opts) {
678
679
  return markerResult;
679
680
  }
680
681
  }
681
- return markerKind === "server" ? RESOLVED_MARKER_SERVER_ONLY : RESOLVED_MARKER_CLIENT_ONLY;
682
+ return markerKind === "server" ? resolvedMarkerVirtualModuleId("server") : resolvedMarkerVirtualModuleId("client");
682
683
  }
683
684
  if (!shouldCheckImporter(normalizedImporter)) {
684
685
  return void 0;
@@ -732,51 +733,54 @@ function importProtectionPlugin(opts) {
732
733
  env.serverFnLookupModules.add(resolved);
733
734
  }
734
735
  env.graph.addEdge(resolved, normalizedImporter, source);
735
- const fileMatch = matchers.files.length > 0 ? matchesAny(relativePath, matchers.files) : void 0;
736
- if (fileMatch) {
737
- const info = await buildViolationInfo(
736
+ const isExcludedFile = matchers.excludeFiles.length > 0 && matchesAny(relativePath, matchers.excludeFiles);
737
+ if (!isExcludedFile) {
738
+ const fileMatch = matchers.files.length > 0 ? matchesAny(relativePath, matchers.files) : void 0;
739
+ if (fileMatch) {
740
+ const info = await buildViolationInfo(
741
+ provider,
742
+ env,
743
+ envName,
744
+ envType,
745
+ importer,
746
+ normalizedImporter,
747
+ source,
748
+ {
749
+ type: "file",
750
+ pattern: fileMatch.pattern,
751
+ resolved,
752
+ message: `Import "${source}" (resolved to "${relativePath}") is denied in the ${envType} environment`
753
+ }
754
+ );
755
+ return reportOrDeferViolation(
756
+ this,
757
+ env,
758
+ normalizedImporter,
759
+ info,
760
+ shouldDefer,
761
+ isPreTransformResolve
762
+ );
763
+ }
764
+ const markerInfo = await buildMarkerViolationFromResolvedImport(
738
765
  provider,
739
766
  env,
740
767
  envName,
741
768
  envType,
742
769
  importer,
743
- normalizedImporter,
744
770
  source,
745
- {
746
- type: "file",
747
- pattern: fileMatch.pattern,
748
- resolved,
749
- message: `Import "${source}" (resolved to "${relativePath}") is denied in the ${envType} environment`
750
- }
751
- );
752
- return reportOrDeferViolation(
753
- this,
754
- env,
755
- normalizedImporter,
756
- info,
757
- shouldDefer,
758
- isPreTransformResolve
759
- );
760
- }
761
- const markerInfo = await buildMarkerViolationFromResolvedImport(
762
- provider,
763
- env,
764
- envName,
765
- envType,
766
- importer,
767
- source,
768
- resolved,
769
- relativePath
770
- );
771
- if (markerInfo) {
772
- return reportOrDeferViolation(
773
- this,
774
- env,
775
- normalizedImporter,
776
- markerInfo,
777
- shouldDefer,
778
- isPreTransformResolve
771
+ resolved,
772
+ relativePath
779
773
  );
774
+ if (markerInfo) {
775
+ return reportOrDeferViolation(
776
+ this,
777
+ env,
778
+ normalizedImporter,
779
+ markerInfo,
780
+ shouldDefer,
781
+ isPreTransformResolve
782
+ );
783
+ }
780
784
  }
781
785
  }
782
786
  return void 0;
@@ -784,13 +788,7 @@ function importProtectionPlugin(opts) {
784
788
  load: {
785
789
  filter: {
786
790
  id: new RegExp(
787
- [
788
- RESOLVED_MOCK_MODULE_ID,
789
- RESOLVED_MOCK_BUILD_PREFIX,
790
- RESOLVED_MARKER_PREFIX,
791
- RESOLVED_MOCK_EDGE_PREFIX,
792
- RESOLVED_MOCK_RUNTIME_PREFIX
793
- ].map(escapeRegExp).join("|")
791
+ getResolvedVirtualModuleMatchers().map(escapeRegExp).join("|")
794
792
  )
795
793
  },
796
794
  handler(id) {
@@ -802,26 +800,7 @@ function importProtectionPlugin(opts) {
802
800
  });
803
801
  }
804
802
  }
805
- if (id === RESOLVED_MOCK_MODULE_ID) {
806
- return loadSilentMockModule();
807
- }
808
- if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {
809
- return loadSilentMockModule();
810
- }
811
- if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {
812
- return loadMockEdgeModule(
813
- id.slice(RESOLVED_MOCK_EDGE_PREFIX.length)
814
- );
815
- }
816
- if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {
817
- return loadMockRuntimeModule(
818
- id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length)
819
- );
820
- }
821
- if (id.startsWith(RESOLVED_MARKER_PREFIX)) {
822
- return loadMarkerModule();
823
- }
824
- return void 0;
803
+ return loadResolvedVirtualModule(id);
825
804
  }
826
805
  },
827
806
  async generateBundle(_options, bundle) {
@@ -837,8 +816,13 @@ function importProtectionPlugin(opts) {
837
816
  }
838
817
  }
839
818
  const realViolations = [];
840
- for (const { info, mockModuleId } of env.deferredBuildViolations) {
841
- if (!survivingModules.has(mockModuleId)) continue;
819
+ for (const {
820
+ info,
821
+ mockModuleId,
822
+ checkModuleId
823
+ } of env.deferredBuildViolations) {
824
+ const checkId = checkModuleId ?? mockModuleId;
825
+ if (!survivingModules.has(checkId)) continue;
842
826
  if (config.onViolation) {
843
827
  const result = await config.onViolation(info);
844
828
  if (result === false) continue;
@@ -962,11 +946,8 @@ function importProtectionPlugin(opts) {
962
946
  // Separate plugin so the transform can be enabled/disabled per-environment.
963
947
  name: "tanstack-start-core:import-protection-mock-rewrite",
964
948
  enforce: "pre",
965
- // Only needed during dev. In build, we rely on Rollup's syntheticNamedExports.
966
- apply: "serve",
967
949
  applyToEnvironment(env) {
968
950
  if (!config.enabled) return false;
969
- if (config.effectiveBehavior !== "mock") return false;
970
951
  return environmentNames.has(env.name);
971
952
  },
972
953
  transform: {
@@ -994,7 +975,6 @@ function importProtectionPlugin(opts) {
994
975
  ];
995
976
  }
996
977
  export {
997
- RESOLVED_MOCK_MODULE_ID,
998
978
  dedupePatterns,
999
979
  extractImportSources,
1000
980
  importProtectionPlugin