@tanstack/start-plugin-core 1.163.0 → 1.163.2
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.d.ts +0 -1
- package/dist/esm/import-protection-plugin/plugin.js +30 -57
- package/dist/esm/import-protection-plugin/plugin.js.map +1 -1
- package/dist/esm/import-protection-plugin/virtualModules.d.ts +18 -6
- package/dist/esm/import-protection-plugin/virtualModules.js +50 -9
- package/dist/esm/import-protection-plugin/virtualModules.js.map +1 -1
- package/package.json +6 -6
- package/src/import-protection-plugin/INTERNALS.md +25 -17
- package/src/import-protection-plugin/plugin.ts +65 -96
- package/src/import-protection-plugin/virtualModules.ts +85 -13
|
@@ -13,6 +13,29 @@ const MOCK_RUNTIME_PREFIX = "tanstack-start-import-protection:mock-runtime:";
|
|
|
13
13
|
const RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX);
|
|
14
14
|
const MARKER_PREFIX = "tanstack-start-import-protection:marker:";
|
|
15
15
|
const RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX);
|
|
16
|
+
const RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`);
|
|
17
|
+
const RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`);
|
|
18
|
+
function resolvedMarkerVirtualModuleId(kind) {
|
|
19
|
+
return kind === "server" ? RESOLVED_MARKER_SERVER_ONLY : RESOLVED_MARKER_CLIENT_ONLY;
|
|
20
|
+
}
|
|
21
|
+
function getResolvedVirtualModuleMatchers() {
|
|
22
|
+
return RESOLVED_VIRTUAL_MODULE_MATCHERS;
|
|
23
|
+
}
|
|
24
|
+
const RESOLVED_VIRTUAL_MODULE_MATCHERS = [
|
|
25
|
+
RESOLVED_MOCK_MODULE_ID,
|
|
26
|
+
RESOLVED_MOCK_BUILD_PREFIX,
|
|
27
|
+
RESOLVED_MOCK_EDGE_PREFIX,
|
|
28
|
+
RESOLVED_MOCK_RUNTIME_PREFIX,
|
|
29
|
+
RESOLVED_MARKER_PREFIX
|
|
30
|
+
];
|
|
31
|
+
function resolveInternalVirtualModuleId(source) {
|
|
32
|
+
if (source === MOCK_MODULE_ID) return RESOLVED_MOCK_MODULE_ID;
|
|
33
|
+
if (source.startsWith(MOCK_EDGE_PREFIX)) return resolveViteId(source);
|
|
34
|
+
if (source.startsWith(MOCK_RUNTIME_PREFIX)) return resolveViteId(source);
|
|
35
|
+
if (source.startsWith(MOCK_BUILD_PREFIX)) return resolveViteId(source);
|
|
36
|
+
if (source.startsWith(MARKER_PREFIX)) return resolveViteId(source);
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
16
39
|
function toBase64Url(input) {
|
|
17
40
|
return Buffer.from(input, "utf8").toString("base64url");
|
|
18
41
|
}
|
|
@@ -98,7 +121,8 @@ function __report(action, accessPath) {
|
|
|
98
121
|
return true;
|
|
99
122
|
},` : "";
|
|
100
123
|
return `
|
|
101
|
-
${preamble}
|
|
124
|
+
${preamble}/* @__NO_SIDE_EFFECTS__ */
|
|
125
|
+
function ${fnName}(name) {
|
|
102
126
|
const fn = function () {};
|
|
103
127
|
fn.prototype.name = name;
|
|
104
128
|
const children = Object.create(null);
|
|
@@ -125,12 +149,12 @@ ${preamble}function ${fnName}(name) {
|
|
|
125
149
|
});
|
|
126
150
|
return proxy;
|
|
127
151
|
}
|
|
128
|
-
const mock = ${fnName}('mock');
|
|
152
|
+
const mock = /* @__PURE__ */ ${fnName}('mock');
|
|
129
153
|
export default mock;
|
|
130
154
|
`;
|
|
131
155
|
}
|
|
132
156
|
function loadSilentMockModule() {
|
|
133
|
-
return {
|
|
157
|
+
return { code: generateMockCode() };
|
|
134
158
|
}
|
|
135
159
|
function loadMockEdgeModule(encodedPayload) {
|
|
136
160
|
let payload;
|
|
@@ -186,23 +210,40 @@ const MARKER_MODULE_RESULT = { code: "export {}" };
|
|
|
186
210
|
function loadMarkerModule() {
|
|
187
211
|
return MARKER_MODULE_RESULT;
|
|
188
212
|
}
|
|
213
|
+
function loadResolvedVirtualModule(id) {
|
|
214
|
+
if (id === RESOLVED_MOCK_MODULE_ID) {
|
|
215
|
+
return loadSilentMockModule();
|
|
216
|
+
}
|
|
217
|
+
if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {
|
|
218
|
+
return loadSilentMockModule();
|
|
219
|
+
}
|
|
220
|
+
if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {
|
|
221
|
+
return loadMockEdgeModule(id.slice(RESOLVED_MOCK_EDGE_PREFIX.length));
|
|
222
|
+
}
|
|
223
|
+
if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {
|
|
224
|
+
return loadMockRuntimeModule(id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length));
|
|
225
|
+
}
|
|
226
|
+
if (id.startsWith(RESOLVED_MARKER_PREFIX)) {
|
|
227
|
+
return loadMarkerModule();
|
|
228
|
+
}
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
189
231
|
export {
|
|
190
232
|
MARKER_PREFIX,
|
|
191
233
|
MOCK_BUILD_PREFIX,
|
|
192
234
|
MOCK_EDGE_PREFIX,
|
|
193
235
|
MOCK_MODULE_ID,
|
|
194
236
|
MOCK_RUNTIME_PREFIX,
|
|
195
|
-
RESOLVED_MARKER_PREFIX,
|
|
196
|
-
RESOLVED_MOCK_BUILD_PREFIX,
|
|
197
|
-
RESOLVED_MOCK_EDGE_PREFIX,
|
|
198
|
-
RESOLVED_MOCK_MODULE_ID,
|
|
199
|
-
RESOLVED_MOCK_RUNTIME_PREFIX,
|
|
200
237
|
RUNTIME_SUGGESTION_TEXT,
|
|
238
|
+
getResolvedVirtualModuleMatchers,
|
|
201
239
|
loadMarkerModule,
|
|
202
240
|
loadMockEdgeModule,
|
|
203
241
|
loadMockRuntimeModule,
|
|
242
|
+
loadResolvedVirtualModule,
|
|
204
243
|
loadSilentMockModule,
|
|
205
244
|
makeMockEdgeModuleId,
|
|
206
|
-
mockRuntimeModuleIdFromViolation
|
|
245
|
+
mockRuntimeModuleIdFromViolation,
|
|
246
|
+
resolveInternalVirtualModuleId,
|
|
247
|
+
resolvedMarkerVirtualModuleId
|
|
207
248
|
};
|
|
208
249
|
//# sourceMappingURL=virtualModules.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"virtualModules.js","sources":["../../../src/import-protection-plugin/virtualModules.ts"],"sourcesContent":["import { resolveViteId } from '../utils'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { isValidExportName } from './rewriteDeniedImports'\nimport { CLIENT_ENV_SUGGESTIONS } from './trace'\nimport { relativizePath } from './utils'\nimport type { ViolationInfo } from './trace'\n\nexport const MOCK_MODULE_ID = 'tanstack-start-import-protection:mock'\nexport const RESOLVED_MOCK_MODULE_ID = resolveViteId(MOCK_MODULE_ID)\n\n/**\n * Per-violation mock prefix used in build+error mode.\n * Each deferred violation gets a unique ID so we can check which ones\n * survived tree-shaking in `generateBundle`.\n */\nexport const MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:'\nexport const RESOLVED_MOCK_BUILD_PREFIX = resolveViteId(MOCK_BUILD_PREFIX)\n\nexport const MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:'\nexport const RESOLVED_MOCK_EDGE_PREFIX = resolveViteId(MOCK_EDGE_PREFIX)\n\nexport const MOCK_RUNTIME_PREFIX =\n 'tanstack-start-import-protection:mock-runtime:'\nexport const RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX)\n\nexport const MARKER_PREFIX = 'tanstack-start-import-protection:marker:'\nexport const RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX)\n\nfunction toBase64Url(input: string): string {\n return Buffer.from(input, 'utf8').toString('base64url')\n}\n\nfunction fromBase64Url(input: string): string {\n return Buffer.from(input, 'base64url').toString('utf8')\n}\n\ntype MockAccessMode = 'error' | 'warn' | 'off'\n\n/**\n * Compact runtime suggestion text for browser console, derived from\n * {@link CLIENT_ENV_SUGGESTIONS} so there's a single source of truth.\n */\nexport const RUNTIME_SUGGESTION_TEXT =\n 'Fix: ' +\n CLIENT_ENV_SUGGESTIONS.join('. ') +\n '. To disable these runtime diagnostics, set importProtection.mockAccess: \"off\".'\n\nexport function mockRuntimeModuleIdFromViolation(\n info: ViolationInfo,\n mode: MockAccessMode,\n root: string,\n): string {\n if (mode === 'off') return MOCK_MODULE_ID\n if (info.env !== VITE_ENVIRONMENT_NAMES.client) return MOCK_MODULE_ID\n\n const rel = (p: string) => relativizePath(p, root)\n const trace = info.trace.map((s) => {\n const file = rel(s.file)\n if (s.line == null) return file\n return `${file}:${s.line}:${s.column ?? 1}`\n })\n\n const payload = {\n env: info.env,\n importer: info.importer,\n specifier: info.specifier,\n trace,\n mode,\n }\n return `${MOCK_RUNTIME_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\nexport function makeMockEdgeModuleId(\n exports: Array<string>,\n source: string,\n runtimeId: string,\n): string {\n const payload = { source, exports, runtimeId }\n return `${MOCK_EDGE_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\n/**\n * Generate a recursive Proxy-based mock module.\n *\n * When `diagnostics` is provided, the generated code includes a `__report`\n * function that logs runtime warnings/errors when the mock is actually used\n * (property access for primitive coercion, calls, construction, sets).\n *\n * When `diagnostics` is omitted, the mock is completely silent — suitable\n * for the shared `MOCK_MODULE_ID` that uses `syntheticNamedExports`.\n */\nfunction generateMockCode(diagnostics?: {\n meta: {\n env: string\n importer: string\n specifier: string\n trace: Array<unknown>\n }\n mode: 'error' | 'warn' | 'off'\n}): string {\n const fnName = diagnostics ? '__createMock' : 'createMock'\n const hasDiag = !!diagnostics\n\n const preamble = hasDiag\n ? `const __meta = ${JSON.stringify(diagnostics.meta)};\nconst __mode = ${JSON.stringify(diagnostics.mode)};\n\nconst __seen = new Set();\nfunction __report(action, accessPath) {\n if (__mode === 'off') return;\n const key = action + ':' + accessPath;\n if (__seen.has(key)) return;\n __seen.add(key);\n\n const traceLines = Array.isArray(__meta.trace) && __meta.trace.length\n ? \"\\\\n\\\\nTrace:\\\\n\" + __meta.trace.map((t, i) => ' ' + (i + 1) + '. ' + String(t)).join('\\\\n')\n : '';\n\n const msg =\n '[import-protection] Mocked import used in dev client\\\\n\\\\n' +\n 'Denied import: \"' + __meta.specifier + '\"\\\\n' +\n 'Importer: ' + __meta.importer + '\\\\n' +\n 'Access: ' + accessPath + ' (' + action + ')' +\n traceLines +\n '\\\\n\\\\n' + ${JSON.stringify(RUNTIME_SUGGESTION_TEXT)};\n\n const err = new Error(msg);\n if (__mode === 'warn') {\n console.warn(err);\n } else {\n console.error(err);\n }\n}\n`\n : ''\n\n // Diagnostic-only traps for primitive coercion, set\n const diagGetTraps = hasDiag\n ? `\n if (prop === Symbol.toPrimitive) {\n return () => {\n __report('toPrimitive', name);\n return '[import-protection mock]';\n };\n }\n if (prop === 'toString' || prop === 'valueOf' || prop === 'toJSON') {\n return () => {\n __report(String(prop), name);\n return '[import-protection mock]';\n };\n }`\n : ''\n\n const applyBody = hasDiag\n ? `__report('call', name + '()');\n return ${fnName}(name + '()');`\n : `return ${fnName}(name + '()');`\n\n const constructBody = hasDiag\n ? `__report('construct', 'new ' + name);\n return ${fnName}('new ' + name);`\n : `return ${fnName}('new ' + name);`\n\n const setTrap = hasDiag\n ? `\n set(_target, prop) {\n __report('set', name + '.' + String(prop));\n return true;\n },`\n : ''\n\n return `\n${preamble}function ${fnName}(name) {\n const fn = function () {};\n fn.prototype.name = name;\n const children = Object.create(null);\n const proxy = new Proxy(fn, {\n get(_target, prop) {\n if (prop === '__esModule') return true;\n if (prop === 'default') return proxy;\n if (prop === 'caller') return null;\n if (prop === 'then') return (f) => Promise.resolve(f(proxy));\n if (prop === 'catch') return () => Promise.resolve(proxy);\n if (prop === 'finally') return (f) => { f(); return Promise.resolve(proxy); };${diagGetTraps}\n if (typeof prop === 'symbol') return undefined;\n if (!(prop in children)) {\n children[prop] = ${fnName}(name + '.' + prop);\n }\n return children[prop];\n },\n apply() {\n ${applyBody}\n },\n construct() {\n ${constructBody}\n },${setTrap}\n });\n return proxy;\n}\nconst mock = ${fnName}('mock');\nexport default mock;\n`\n}\n\nexport function loadSilentMockModule(): {\n syntheticNamedExports: boolean\n code: string\n} {\n return { syntheticNamedExports: true, code: generateMockCode() }\n}\n\nexport function loadMockEdgeModule(encodedPayload: string): { code: string } {\n let payload: { exports?: Array<string>; runtimeId?: string }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = { exports: [] }\n }\n const names: Array<string> = Array.isArray(payload.exports)\n ? payload.exports.filter(\n (n): n is string =>\n typeof n === 'string' && n.length > 0 && n !== 'default',\n )\n : []\n\n const runtimeId: string =\n typeof payload.runtimeId === 'string' && payload.runtimeId.length > 0\n ? payload.runtimeId\n : MOCK_MODULE_ID\n\n const exportLines: Array<string> = []\n const stringExports: Array<{ alias: string; name: string }> = []\n\n for (let i = 0; i < names.length; i++) {\n const n = names[i]!\n if (isValidExportName(n)) {\n exportLines.push(`export const ${n} = mock.${n};`)\n } else {\n // ES2022 string-keyed export: use a temp var + re-export with string literal\n const alias = `__tss_str_${i}`\n exportLines.push(`const ${alias} = mock[${JSON.stringify(n)}];`)\n stringExports.push({ alias, name: n })\n }\n }\n\n if (stringExports.length > 0) {\n const reexports = stringExports\n .map((s) => `${s.alias} as ${JSON.stringify(s.name)}`)\n .join(', ')\n exportLines.push(`export { ${reexports} };`)\n }\n\n return {\n code: `import mock from ${JSON.stringify(runtimeId)};\n${exportLines.join('\\n')}\nexport default mock;\n`,\n }\n}\n\nexport function loadMockRuntimeModule(encodedPayload: string): {\n code: string\n} {\n let payload: {\n mode?: string\n env?: string\n importer?: string\n specifier?: string\n trace?: Array<unknown>\n }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = {}\n }\n\n const mode: 'error' | 'warn' | 'off' =\n payload.mode === 'warn' || payload.mode === 'off' ? payload.mode : 'error'\n\n const meta = {\n env: String(payload.env ?? ''),\n importer: String(payload.importer ?? ''),\n specifier: String(payload.specifier ?? ''),\n trace: Array.isArray(payload.trace) ? payload.trace : [],\n }\n\n return { code: generateMockCode({ meta, mode }) }\n}\n\nconst MARKER_MODULE_RESULT = { code: 'export {}' } as const\n\nexport function loadMarkerModule(): { code: string } {\n return MARKER_MODULE_RESULT\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"virtualModules.js","sources":["../../../src/import-protection-plugin/virtualModules.ts"],"sourcesContent":["import { resolveViteId } from '../utils'\nimport { VITE_ENVIRONMENT_NAMES } from '../constants'\nimport { isValidExportName } from './rewriteDeniedImports'\nimport { CLIENT_ENV_SUGGESTIONS } from './trace'\nimport { relativizePath } from './utils'\nimport type { ViolationInfo } from './trace'\n\nexport const MOCK_MODULE_ID = 'tanstack-start-import-protection:mock'\nconst RESOLVED_MOCK_MODULE_ID = resolveViteId(MOCK_MODULE_ID)\n\n/**\n * Per-violation mock prefix used in build+error mode.\n * Each deferred violation gets a unique ID so we can check which ones\n * survived tree-shaking in `generateBundle`.\n */\nexport const MOCK_BUILD_PREFIX = 'tanstack-start-import-protection:mock:build:'\nconst RESOLVED_MOCK_BUILD_PREFIX = resolveViteId(MOCK_BUILD_PREFIX)\n\nexport const MOCK_EDGE_PREFIX = 'tanstack-start-import-protection:mock-edge:'\nconst RESOLVED_MOCK_EDGE_PREFIX = resolveViteId(MOCK_EDGE_PREFIX)\n\nexport const MOCK_RUNTIME_PREFIX =\n 'tanstack-start-import-protection:mock-runtime:'\nconst RESOLVED_MOCK_RUNTIME_PREFIX = resolveViteId(MOCK_RUNTIME_PREFIX)\n\nexport const MARKER_PREFIX = 'tanstack-start-import-protection:marker:'\nconst RESOLVED_MARKER_PREFIX = resolveViteId(MARKER_PREFIX)\n\nconst RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`)\nconst RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`)\n\nexport function resolvedMarkerVirtualModuleId(\n kind: 'server' | 'client',\n): string {\n return kind === 'server'\n ? RESOLVED_MARKER_SERVER_ONLY\n : RESOLVED_MARKER_CLIENT_ONLY\n}\n\n/**\n * Convenience list for plugin `load` filters/handlers.\n *\n * Vite/Rollup call `load(id)` with the *resolved* virtual id (prefixed by `\\0`).\n * `resolveId(source)` sees the *unresolved* id/prefix (without `\\0`).\n */\nexport function getResolvedVirtualModuleMatchers(): ReadonlyArray<string> {\n return RESOLVED_VIRTUAL_MODULE_MATCHERS\n}\n\nconst RESOLVED_VIRTUAL_MODULE_MATCHERS = [\n RESOLVED_MOCK_MODULE_ID,\n RESOLVED_MOCK_BUILD_PREFIX,\n RESOLVED_MOCK_EDGE_PREFIX,\n RESOLVED_MOCK_RUNTIME_PREFIX,\n RESOLVED_MARKER_PREFIX,\n] as const\n\n/**\n * Resolve import-protection's internal virtual module IDs.\n *\n * `resolveId(source)` sees *unresolved* ids/prefixes (no `\\0`).\n * Returning a resolved id (with `\\0`) ensures Vite/Rollup route it to `load`.\n */\nexport function resolveInternalVirtualModuleId(\n source: string,\n): string | undefined {\n if (source === MOCK_MODULE_ID) return RESOLVED_MOCK_MODULE_ID\n if (source.startsWith(MOCK_EDGE_PREFIX)) return resolveViteId(source)\n if (source.startsWith(MOCK_RUNTIME_PREFIX)) return resolveViteId(source)\n if (source.startsWith(MOCK_BUILD_PREFIX)) return resolveViteId(source)\n if (source.startsWith(MARKER_PREFIX)) return resolveViteId(source)\n return undefined\n}\n\nfunction toBase64Url(input: string): string {\n return Buffer.from(input, 'utf8').toString('base64url')\n}\n\nfunction fromBase64Url(input: string): string {\n return Buffer.from(input, 'base64url').toString('utf8')\n}\n\ntype MockAccessMode = 'error' | 'warn' | 'off'\n\n/**\n * Compact runtime suggestion text for browser console, derived from\n * {@link CLIENT_ENV_SUGGESTIONS} so there's a single source of truth.\n */\nexport const RUNTIME_SUGGESTION_TEXT =\n 'Fix: ' +\n CLIENT_ENV_SUGGESTIONS.join('. ') +\n '. To disable these runtime diagnostics, set importProtection.mockAccess: \"off\".'\n\nexport function mockRuntimeModuleIdFromViolation(\n info: ViolationInfo,\n mode: MockAccessMode,\n root: string,\n): string {\n if (mode === 'off') return MOCK_MODULE_ID\n if (info.env !== VITE_ENVIRONMENT_NAMES.client) return MOCK_MODULE_ID\n\n const rel = (p: string) => relativizePath(p, root)\n const trace = info.trace.map((s) => {\n const file = rel(s.file)\n if (s.line == null) return file\n return `${file}:${s.line}:${s.column ?? 1}`\n })\n\n const payload = {\n env: info.env,\n importer: info.importer,\n specifier: info.specifier,\n trace,\n mode,\n }\n return `${MOCK_RUNTIME_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\nexport function makeMockEdgeModuleId(\n exports: Array<string>,\n source: string,\n runtimeId: string,\n): string {\n const payload = { source, exports, runtimeId }\n return `${MOCK_EDGE_PREFIX}${toBase64Url(JSON.stringify(payload))}`\n}\n\n/**\n * Generate a recursive Proxy-based mock module.\n *\n * When `diagnostics` is provided, the generated code includes a `__report`\n * function that logs runtime warnings/errors when the mock is actually used\n * (property access for primitive coercion, calls, construction, sets).\n *\n * When `diagnostics` is omitted, the mock is completely silent — suitable\n * for base mock modules (e.g. `MOCK_MODULE_ID` or per-violation build mocks)\n * that are consumed by mock-edge modules providing explicit named exports.\n */\nfunction generateMockCode(diagnostics?: {\n meta: {\n env: string\n importer: string\n specifier: string\n trace: Array<unknown>\n }\n mode: 'error' | 'warn' | 'off'\n}): string {\n const fnName = diagnostics ? '__createMock' : 'createMock'\n const hasDiag = !!diagnostics\n\n const preamble = hasDiag\n ? `const __meta = ${JSON.stringify(diagnostics.meta)};\nconst __mode = ${JSON.stringify(diagnostics.mode)};\n\nconst __seen = new Set();\nfunction __report(action, accessPath) {\n if (__mode === 'off') return;\n const key = action + ':' + accessPath;\n if (__seen.has(key)) return;\n __seen.add(key);\n\n const traceLines = Array.isArray(__meta.trace) && __meta.trace.length\n ? \"\\\\n\\\\nTrace:\\\\n\" + __meta.trace.map((t, i) => ' ' + (i + 1) + '. ' + String(t)).join('\\\\n')\n : '';\n\n const msg =\n '[import-protection] Mocked import used in dev client\\\\n\\\\n' +\n 'Denied import: \"' + __meta.specifier + '\"\\\\n' +\n 'Importer: ' + __meta.importer + '\\\\n' +\n 'Access: ' + accessPath + ' (' + action + ')' +\n traceLines +\n '\\\\n\\\\n' + ${JSON.stringify(RUNTIME_SUGGESTION_TEXT)};\n\n const err = new Error(msg);\n if (__mode === 'warn') {\n console.warn(err);\n } else {\n console.error(err);\n }\n}\n`\n : ''\n\n // Diagnostic-only traps for primitive coercion, set\n const diagGetTraps = hasDiag\n ? `\n if (prop === Symbol.toPrimitive) {\n return () => {\n __report('toPrimitive', name);\n return '[import-protection mock]';\n };\n }\n if (prop === 'toString' || prop === 'valueOf' || prop === 'toJSON') {\n return () => {\n __report(String(prop), name);\n return '[import-protection mock]';\n };\n }`\n : ''\n\n const applyBody = hasDiag\n ? `__report('call', name + '()');\n return ${fnName}(name + '()');`\n : `return ${fnName}(name + '()');`\n\n const constructBody = hasDiag\n ? `__report('construct', 'new ' + name);\n return ${fnName}('new ' + name);`\n : `return ${fnName}('new ' + name);`\n\n const setTrap = hasDiag\n ? `\n set(_target, prop) {\n __report('set', name + '.' + String(prop));\n return true;\n },`\n : ''\n\n return `\n${preamble}/* @__NO_SIDE_EFFECTS__ */\nfunction ${fnName}(name) {\n const fn = function () {};\n fn.prototype.name = name;\n const children = Object.create(null);\n const proxy = new Proxy(fn, {\n get(_target, prop) {\n if (prop === '__esModule') return true;\n if (prop === 'default') return proxy;\n if (prop === 'caller') return null;\n if (prop === 'then') return (f) => Promise.resolve(f(proxy));\n if (prop === 'catch') return () => Promise.resolve(proxy);\n if (prop === 'finally') return (f) => { f(); return Promise.resolve(proxy); };${diagGetTraps}\n if (typeof prop === 'symbol') return undefined;\n if (!(prop in children)) {\n children[prop] = ${fnName}(name + '.' + prop);\n }\n return children[prop];\n },\n apply() {\n ${applyBody}\n },\n construct() {\n ${constructBody}\n },${setTrap}\n });\n return proxy;\n}\nconst mock = /* @__PURE__ */ ${fnName}('mock');\nexport default mock;\n`\n}\n\nexport function loadSilentMockModule(): { code: string } {\n return { code: generateMockCode() }\n}\n\nexport function loadMockEdgeModule(encodedPayload: string): { code: string } {\n let payload: { exports?: Array<string>; runtimeId?: string }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = { exports: [] }\n }\n const names: Array<string> = Array.isArray(payload.exports)\n ? payload.exports.filter(\n (n): n is string =>\n typeof n === 'string' && n.length > 0 && n !== 'default',\n )\n : []\n\n const runtimeId: string =\n typeof payload.runtimeId === 'string' && payload.runtimeId.length > 0\n ? payload.runtimeId\n : MOCK_MODULE_ID\n\n const exportLines: Array<string> = []\n const stringExports: Array<{ alias: string; name: string }> = []\n\n for (let i = 0; i < names.length; i++) {\n const n = names[i]!\n if (isValidExportName(n)) {\n exportLines.push(`export const ${n} = mock.${n};`)\n } else {\n // ES2022 string-keyed export: use a temp var + re-export with string literal\n const alias = `__tss_str_${i}`\n exportLines.push(`const ${alias} = mock[${JSON.stringify(n)}];`)\n stringExports.push({ alias, name: n })\n }\n }\n\n if (stringExports.length > 0) {\n const reexports = stringExports\n .map((s) => `${s.alias} as ${JSON.stringify(s.name)}`)\n .join(', ')\n exportLines.push(`export { ${reexports} };`)\n }\n\n return {\n code: `import mock from ${JSON.stringify(runtimeId)};\n${exportLines.join('\\n')}\nexport default mock;\n`,\n }\n}\n\nexport function loadMockRuntimeModule(encodedPayload: string): {\n code: string\n} {\n let payload: {\n mode?: string\n env?: string\n importer?: string\n specifier?: string\n trace?: Array<unknown>\n }\n try {\n payload = JSON.parse(fromBase64Url(encodedPayload)) as typeof payload\n } catch {\n payload = {}\n }\n\n const mode: 'error' | 'warn' | 'off' =\n payload.mode === 'warn' || payload.mode === 'off' ? payload.mode : 'error'\n\n const meta = {\n env: String(payload.env ?? ''),\n importer: String(payload.importer ?? ''),\n specifier: String(payload.specifier ?? ''),\n trace: Array.isArray(payload.trace) ? payload.trace : [],\n }\n\n return { code: generateMockCode({ meta, mode }) }\n}\n\nconst MARKER_MODULE_RESULT = { code: 'export {}' } as const\n\nexport function loadMarkerModule(): { code: string } {\n return MARKER_MODULE_RESULT\n}\n\nexport function loadResolvedVirtualModule(\n id: string,\n): { code: string } | undefined {\n if (id === RESOLVED_MOCK_MODULE_ID) {\n return loadSilentMockModule()\n }\n\n // Per-violation build mock modules — same silent mock code\n if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {\n return loadSilentMockModule()\n }\n\n if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {\n return loadMockEdgeModule(id.slice(RESOLVED_MOCK_EDGE_PREFIX.length))\n }\n\n if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {\n return loadMockRuntimeModule(id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length))\n }\n\n if (id.startsWith(RESOLVED_MARKER_PREFIX)) {\n return loadMarkerModule()\n }\n\n return undefined\n}\n"],"names":[],"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.163.
|
|
3
|
+
"version": "1.163.2",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"vitefu": "^1.1.1",
|
|
61
61
|
"xmlbuilder2": "^4.0.3",
|
|
62
62
|
"zod": "^3.24.2",
|
|
63
|
-
"@tanstack/router-core": "1.
|
|
64
|
-
"@tanstack/router-generator": "1.
|
|
63
|
+
"@tanstack/router-core": "1.163.2",
|
|
64
|
+
"@tanstack/router-generator": "1.163.2",
|
|
65
|
+
"@tanstack/router-plugin": "1.163.2",
|
|
65
66
|
"@tanstack/router-utils": "1.161.4",
|
|
66
|
-
"@tanstack/start-client-core": "1.
|
|
67
|
-
"@tanstack/
|
|
68
|
-
"@tanstack/start-server-core": "1.162.9"
|
|
67
|
+
"@tanstack/start-client-core": "1.163.2",
|
|
68
|
+
"@tanstack/start-server-core": "1.163.2"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/babel__code-frame": "^7.0.6",
|
|
@@ -78,9 +78,9 @@ analysing a module's exports. These are tracked via `serverFnLookupModules` and
|
|
|
78
78
|
### Central functions
|
|
79
79
|
|
|
80
80
|
- **`handleViolation()`**: Formats + reports (or silences) the violation. Returns
|
|
81
|
-
a mock module ID (
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
a mock-edge module ID (string) so `resolveId` can substitute the offending
|
|
82
|
+
import. May also return `undefined` (suppressed by `onViolation` or
|
|
83
|
+
silent+error in dev) or throw via `ctx.error()` (dev+error).
|
|
84
84
|
- **`reportOrDeferViolation()`**: Dispatch layer. Either defers (stores for later
|
|
85
85
|
verification) or reports immediately, depending on `shouldDefer`.
|
|
86
86
|
|
|
@@ -138,8 +138,11 @@ In dev, each violation gets a **per-importer mock edge module** that:
|
|
|
138
138
|
- Delegates to a **runtime mock module** that contains a recursive Proxy and
|
|
139
139
|
optional runtime diagnostics (console warnings when mocked values are used).
|
|
140
140
|
|
|
141
|
-
This differs from build mode, where
|
|
142
|
-
|
|
141
|
+
This differs from build mode, where each violation gets a **per-violation mock
|
|
142
|
+
edge module** wrapping a unique base mock module
|
|
143
|
+
(`\0tanstack-start-import-protection:mock:build:N`). The edge module re-exports
|
|
144
|
+
the named exports the importer expects, just like in dev, ensuring compatibility
|
|
145
|
+
with both Rollup and Rolldown (which doesn't support `syntheticNamedExports`).
|
|
143
146
|
|
|
144
147
|
## Build Mode Strategy
|
|
145
148
|
|
|
@@ -148,15 +151,19 @@ handle named export resolution from the silent mock.
|
|
|
148
151
|
Both mock and error build modes follow the same pattern:
|
|
149
152
|
|
|
150
153
|
1. **`resolveId`**: Call `handleViolation({ silent: true })`. Generate a
|
|
151
|
-
**unique per-violation mock module
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
**unique per-violation mock-edge module** that wraps a base mock module
|
|
155
|
+
(`\0tanstack-start-import-protection:mock:build:N`) and provides explicit
|
|
156
|
+
named exports matching the importer's import bindings. Store the violation +
|
|
157
|
+
mock-edge ID in `env.deferredBuildViolations`. Return the mock-edge ID so the
|
|
158
|
+
bundler substitutes the offending import.
|
|
154
159
|
|
|
155
|
-
2. **`load`**:
|
|
156
|
-
|
|
160
|
+
2. **`load`**: For the base mock module, return a silent Proxy-based mock. For
|
|
161
|
+
the mock-edge module, return code that imports from the base mock and
|
|
162
|
+
re-exports the expected named bindings (e.g. `export const Foo = mock.Foo`).
|
|
157
163
|
|
|
158
|
-
3. **Tree-shaking**:
|
|
159
|
-
the mock module is actually used at runtime, the
|
|
164
|
+
3. **Tree-shaking**: The bundler processes the bundle normally. If no binding from
|
|
165
|
+
the mock-edge module is actually used at runtime, both the edge and base
|
|
166
|
+
modules are eliminated.
|
|
160
167
|
|
|
161
168
|
4. **`generateBundle`**: Inspect the output chunks. For each deferred violation,
|
|
162
169
|
check whether its unique mock module ID appears in any chunk's `modules`.
|
|
@@ -171,15 +178,16 @@ Both mock and error build modes follow the same pattern:
|
|
|
171
178
|
The original `RESOLVED_MOCK_MODULE_ID` is a single shared virtual module used
|
|
172
179
|
for all mock-mode violations. If multiple violations are deferred, we need to
|
|
173
180
|
know _which specific ones_ survived tree-shaking. A shared ID would tell us
|
|
174
|
-
"something survived" but not which violation it corresponds to.
|
|
175
|
-
|
|
181
|
+
"something survived" but not which violation it corresponds to. Each violation
|
|
182
|
+
gets a unique mock-edge module (wrapping a unique base mock
|
|
183
|
+
`...mock:build:0`, `...mock:build:1`, etc.) to provide this granularity.
|
|
176
184
|
|
|
177
185
|
### Why mocking doesn't affect tree-shaking
|
|
178
186
|
|
|
179
187
|
From the consumer's perspective, the import bindings are identical whether they
|
|
180
|
-
point to the real module or the mock.
|
|
181
|
-
not module content. If a binding from the barrel's re-export of `.server`
|
|
182
|
-
unused after the Start compiler strips server fn handlers, tree-shaking
|
|
188
|
+
point to the real module or the mock. The bundler tree-shakes based on binding
|
|
189
|
+
usage, not module content. If a binding from the barrel's re-export of `.server`
|
|
190
|
+
is unused after the Start compiler strips server fn handlers, tree-shaking
|
|
183
191
|
eliminates it regardless of whether it points to real DB code or a Proxy mock.
|
|
184
192
|
|
|
185
193
|
### Per-environment operation
|
|
@@ -21,21 +21,13 @@ import {
|
|
|
21
21
|
} from './utils'
|
|
22
22
|
import { collectMockExportNamesBySource } from './rewriteDeniedImports'
|
|
23
23
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
MOCK_RUNTIME_PREFIX,
|
|
28
|
-
RESOLVED_MARKER_PREFIX,
|
|
29
|
-
RESOLVED_MOCK_BUILD_PREFIX,
|
|
30
|
-
RESOLVED_MOCK_EDGE_PREFIX,
|
|
31
|
-
RESOLVED_MOCK_MODULE_ID,
|
|
32
|
-
RESOLVED_MOCK_RUNTIME_PREFIX,
|
|
33
|
-
loadMarkerModule,
|
|
34
|
-
loadMockEdgeModule,
|
|
35
|
-
loadMockRuntimeModule,
|
|
36
|
-
loadSilentMockModule,
|
|
24
|
+
MOCK_BUILD_PREFIX,
|
|
25
|
+
getResolvedVirtualModuleMatchers,
|
|
26
|
+
loadResolvedVirtualModule,
|
|
37
27
|
makeMockEdgeModuleId,
|
|
38
28
|
mockRuntimeModuleIdFromViolation,
|
|
29
|
+
resolveInternalVirtualModuleId,
|
|
30
|
+
resolvedMarkerVirtualModuleId,
|
|
39
31
|
} from './virtualModules'
|
|
40
32
|
import {
|
|
41
33
|
ImportLocCache,
|
|
@@ -62,9 +54,6 @@ import type {
|
|
|
62
54
|
import type { CompileStartFrameworkOptions, GetConfigFn } from '../types'
|
|
63
55
|
|
|
64
56
|
const SERVER_FN_LOOKUP_QUERY = '?' + SERVER_FN_LOOKUP
|
|
65
|
-
const RESOLVED_MARKER_SERVER_ONLY = resolveViteId(`${MARKER_PREFIX}server-only`)
|
|
66
|
-
const RESOLVED_MARKER_CLIENT_ONLY = resolveViteId(`${MARKER_PREFIX}client-only`)
|
|
67
|
-
|
|
68
57
|
const IMPORT_PROTECTION_DEBUG =
|
|
69
58
|
process.env.TSR_IMPORT_PROTECTION_DEBUG === '1' ||
|
|
70
59
|
process.env.TSR_IMPORT_PROTECTION_DEBUG === 'true'
|
|
@@ -82,7 +71,6 @@ function matchesDebugFilter(...values: Array<string>): boolean {
|
|
|
82
71
|
return values.some((v) => v.includes(IMPORT_PROTECTION_DEBUG_FILTER))
|
|
83
72
|
}
|
|
84
73
|
|
|
85
|
-
export { RESOLVED_MOCK_MODULE_ID } from './virtualModules'
|
|
86
74
|
export { rewriteDeniedImports } from './rewriteDeniedImports'
|
|
87
75
|
export { dedupePatterns, extractImportSources } from './utils'
|
|
88
76
|
export type { Pattern } from './utils'
|
|
@@ -216,6 +204,16 @@ interface DeferredBuildViolation {
|
|
|
216
204
|
info: ViolationInfo
|
|
217
205
|
/** Unique mock module ID assigned to this violation. */
|
|
218
206
|
mockModuleId: string
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Module ID to check for tree-shaking survival in `generateBundle`.
|
|
210
|
+
*
|
|
211
|
+
* For most violations we check the unique mock module ID.
|
|
212
|
+
* For `marker` violations the import is a bare side-effect import that often
|
|
213
|
+
* gets optimized away regardless of whether the importer survives, so we
|
|
214
|
+
* instead check whether the importer module itself survived.
|
|
215
|
+
*/
|
|
216
|
+
checkModuleId?: string
|
|
219
217
|
}
|
|
220
218
|
|
|
221
219
|
/**
|
|
@@ -818,27 +816,18 @@ export function importProtectionPlugin(
|
|
|
818
816
|
env: EnvState,
|
|
819
817
|
importerFile: string,
|
|
820
818
|
info: ViolationInfo,
|
|
821
|
-
mockReturnValue:
|
|
822
|
-
| { id: string; syntheticNamedExports: boolean }
|
|
823
|
-
| string
|
|
824
|
-
| undefined,
|
|
819
|
+
mockReturnValue: string | undefined,
|
|
825
820
|
): void {
|
|
826
821
|
getOrCreate(env.pendingViolations, importerFile, () => []).push({
|
|
827
822
|
info,
|
|
828
|
-
mockReturnValue:
|
|
829
|
-
typeof mockReturnValue === 'string'
|
|
830
|
-
? mockReturnValue
|
|
831
|
-
: (mockReturnValue?.id ?? ''),
|
|
823
|
+
mockReturnValue: mockReturnValue ?? '',
|
|
832
824
|
})
|
|
833
825
|
}
|
|
834
826
|
|
|
835
827
|
/** Counter for generating unique per-violation mock module IDs in build mode. */
|
|
836
828
|
let buildViolationCounter = 0
|
|
837
829
|
|
|
838
|
-
type HandleViolationResult =
|
|
839
|
-
| { id: string; syntheticNamedExports: boolean }
|
|
840
|
-
| string
|
|
841
|
-
| undefined
|
|
830
|
+
type HandleViolationResult = string | undefined
|
|
842
831
|
|
|
843
832
|
async function handleViolation(
|
|
844
833
|
ctx: ViolationReporter,
|
|
@@ -909,8 +898,22 @@ export function importProtectionPlugin(
|
|
|
909
898
|
|
|
910
899
|
// Build: unique per-violation mock IDs so generateBundle can check
|
|
911
900
|
// which violations survived tree-shaking (both mock and error mode).
|
|
912
|
-
|
|
913
|
-
|
|
901
|
+
// We wrap the base mock in a mock-edge module that provides explicit
|
|
902
|
+
// named exports — Rolldown doesn't support Rollup's
|
|
903
|
+
// syntheticNamedExports, so without this named imports like
|
|
904
|
+
// `import { Foo } from "denied-pkg"` would fail with MISSING_EXPORT.
|
|
905
|
+
//
|
|
906
|
+
// Use the unresolved MOCK_BUILD_PREFIX (without \0) as the runtimeId
|
|
907
|
+
// so the mock-edge module's `import mock from "..."` goes through
|
|
908
|
+
// resolveId, which adds the \0 prefix. Using the resolved ID directly
|
|
909
|
+
// would cause Rollup/Vite to skip resolveId and fail to find the module.
|
|
910
|
+
const baseMockId = `${MOCK_BUILD_PREFIX}${buildViolationCounter++}`
|
|
911
|
+
const importerFile = normalizeFilePath(info.importer)
|
|
912
|
+
const exports =
|
|
913
|
+
env.mockExportsByImporter.get(importerFile)?.get(info.specifier) ?? []
|
|
914
|
+
return resolveViteId(
|
|
915
|
+
makeMockEdgeModuleId(exports, info.specifier, baseMockId),
|
|
916
|
+
)
|
|
914
917
|
}
|
|
915
918
|
|
|
916
919
|
/**
|
|
@@ -940,9 +943,14 @@ export function importProtectionPlugin(
|
|
|
940
943
|
|
|
941
944
|
if (config.command === 'build') {
|
|
942
945
|
// Build mode: store for generateBundle tree-shaking check.
|
|
943
|
-
// The
|
|
944
|
-
const mockId =
|
|
945
|
-
env.deferredBuildViolations.push({
|
|
946
|
+
// The mock-edge module ID is returned as a plain string.
|
|
947
|
+
const mockId = result ?? ''
|
|
948
|
+
env.deferredBuildViolations.push({
|
|
949
|
+
info,
|
|
950
|
+
mockModuleId: mockId,
|
|
951
|
+
// For marker violations, check importer survival instead of mock.
|
|
952
|
+
checkModuleId: info.type === 'marker' ? info.importer : undefined,
|
|
953
|
+
})
|
|
946
954
|
} else {
|
|
947
955
|
// Dev mock: store for graph-reachability check.
|
|
948
956
|
deferViolation(env, importerFile, info, result)
|
|
@@ -1182,18 +1190,8 @@ export function importProtectionPlugin(
|
|
|
1182
1190
|
}
|
|
1183
1191
|
|
|
1184
1192
|
// Internal virtual modules
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
if (source.startsWith(MOCK_EDGE_PREFIX)) {
|
|
1189
|
-
return resolveViteId(source)
|
|
1190
|
-
}
|
|
1191
|
-
if (source.startsWith(MOCK_RUNTIME_PREFIX)) {
|
|
1192
|
-
return resolveViteId(source)
|
|
1193
|
-
}
|
|
1194
|
-
if (source.startsWith(MARKER_PREFIX)) {
|
|
1195
|
-
return resolveViteId(source)
|
|
1196
|
-
}
|
|
1193
|
+
const internalVirtualId = resolveInternalVirtualModuleId(source)
|
|
1194
|
+
if (internalVirtualId) return internalVirtualId
|
|
1197
1195
|
|
|
1198
1196
|
if (!importer) {
|
|
1199
1197
|
env.graph.addEntry(source)
|
|
@@ -1287,8 +1285,8 @@ export function importProtectionPlugin(
|
|
|
1287
1285
|
}
|
|
1288
1286
|
|
|
1289
1287
|
return markerKind === 'server'
|
|
1290
|
-
?
|
|
1291
|
-
:
|
|
1288
|
+
? resolvedMarkerVirtualModuleId('server')
|
|
1289
|
+
: resolvedMarkerVirtualModuleId('client')
|
|
1292
1290
|
}
|
|
1293
1291
|
|
|
1294
1292
|
// Check if the importer is within our scope
|
|
@@ -1427,15 +1425,7 @@ export function importProtectionPlugin(
|
|
|
1427
1425
|
load: {
|
|
1428
1426
|
filter: {
|
|
1429
1427
|
id: new RegExp(
|
|
1430
|
-
|
|
1431
|
-
RESOLVED_MOCK_MODULE_ID,
|
|
1432
|
-
RESOLVED_MOCK_BUILD_PREFIX,
|
|
1433
|
-
RESOLVED_MARKER_PREFIX,
|
|
1434
|
-
RESOLVED_MOCK_EDGE_PREFIX,
|
|
1435
|
-
RESOLVED_MOCK_RUNTIME_PREFIX,
|
|
1436
|
-
]
|
|
1437
|
-
.map(escapeRegExp)
|
|
1438
|
-
.join('|'),
|
|
1428
|
+
getResolvedVirtualModuleMatchers().map(escapeRegExp).join('|'),
|
|
1439
1429
|
),
|
|
1440
1430
|
},
|
|
1441
1431
|
handler(id) {
|
|
@@ -1448,32 +1438,7 @@ export function importProtectionPlugin(
|
|
|
1448
1438
|
}
|
|
1449
1439
|
}
|
|
1450
1440
|
|
|
1451
|
-
|
|
1452
|
-
return loadSilentMockModule()
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
// Per-violation build mock modules — same silent mock code
|
|
1456
|
-
if (id.startsWith(RESOLVED_MOCK_BUILD_PREFIX)) {
|
|
1457
|
-
return loadSilentMockModule()
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
if (id.startsWith(RESOLVED_MOCK_EDGE_PREFIX)) {
|
|
1461
|
-
return loadMockEdgeModule(
|
|
1462
|
-
id.slice(RESOLVED_MOCK_EDGE_PREFIX.length),
|
|
1463
|
-
)
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
if (id.startsWith(RESOLVED_MOCK_RUNTIME_PREFIX)) {
|
|
1467
|
-
return loadMockRuntimeModule(
|
|
1468
|
-
id.slice(RESOLVED_MOCK_RUNTIME_PREFIX.length),
|
|
1469
|
-
)
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
if (id.startsWith(RESOLVED_MARKER_PREFIX)) {
|
|
1473
|
-
return loadMarkerModule()
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
return undefined
|
|
1441
|
+
return loadResolvedVirtualModule(id)
|
|
1477
1442
|
},
|
|
1478
1443
|
},
|
|
1479
1444
|
|
|
@@ -1492,11 +1457,16 @@ export function importProtectionPlugin(
|
|
|
1492
1457
|
}
|
|
1493
1458
|
}
|
|
1494
1459
|
|
|
1495
|
-
// Check each deferred violation: if its
|
|
1460
|
+
// Check each deferred violation: if its check module survived
|
|
1496
1461
|
// in the bundle, the import was NOT tree-shaken — real leak.
|
|
1497
1462
|
const realViolations: Array<ViolationInfo> = []
|
|
1498
|
-
for (const {
|
|
1499
|
-
|
|
1463
|
+
for (const {
|
|
1464
|
+
info,
|
|
1465
|
+
mockModuleId,
|
|
1466
|
+
checkModuleId,
|
|
1467
|
+
} of env.deferredBuildViolations) {
|
|
1468
|
+
const checkId = checkModuleId ?? mockModuleId
|
|
1469
|
+
if (!survivingModules.has(checkId)) continue
|
|
1500
1470
|
|
|
1501
1471
|
if (config.onViolation) {
|
|
1502
1472
|
const result = await config.onViolation(info)
|
|
@@ -1648,18 +1618,17 @@ export function importProtectionPlugin(
|
|
|
1648
1618
|
name: 'tanstack-start-core:import-protection-mock-rewrite',
|
|
1649
1619
|
enforce: 'pre',
|
|
1650
1620
|
|
|
1651
|
-
// Only needed during dev. In build, we rely on Rollup's syntheticNamedExports.
|
|
1652
|
-
apply: 'serve',
|
|
1653
|
-
|
|
1654
1621
|
applyToEnvironment(env) {
|
|
1655
1622
|
if (!config.enabled) return false
|
|
1656
|
-
//
|
|
1657
|
-
//
|
|
1658
|
-
//
|
|
1659
|
-
|
|
1660
|
-
//
|
|
1661
|
-
//
|
|
1662
|
-
//
|
|
1623
|
+
// We record expected named exports per importer so mock-edge modules
|
|
1624
|
+
// can provide explicit ESM named exports. This is needed in both dev
|
|
1625
|
+
// and build: native ESM (dev) requires real named exports, and
|
|
1626
|
+
// Rolldown (used in Vite 6+) doesn't support Rollup's
|
|
1627
|
+
// syntheticNamedExports flag which was previously relied upon in build.
|
|
1628
|
+
//
|
|
1629
|
+
// In build+error mode we still emit mock modules for deferred
|
|
1630
|
+
// violations (checked at generateBundle time), so we always need the
|
|
1631
|
+
// export name data when import protection is active.
|
|
1663
1632
|
return environmentNames.has(env.name)
|
|
1664
1633
|
},
|
|
1665
1634
|
|