@lovable.dev/vite-tanstack-config 2.7.5-rc.6 → 2.7.6
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/index.cjs +591 -725
- package/dist/index.d.cts +56 -55
- package/dist/index.d.ts +56 -55
- package/dist/index.js +574 -697
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -1,569 +1,481 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"content-length",
|
|
19
|
-
"cookie"
|
|
1
|
+
import { loadEnv, mergeConfig } from "vite";
|
|
2
|
+
import https from "node:https";
|
|
3
|
+
//#region src/assetsProxyPlugin.ts
|
|
4
|
+
const ASSET_RE = /^\/__l5e\/assets-v1\//;
|
|
5
|
+
const PREVIEW_HOST_ENV = "LOVABLE_PREVIEW_HOST";
|
|
6
|
+
const HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
7
|
+
"host",
|
|
8
|
+
"connection",
|
|
9
|
+
"keep-alive",
|
|
10
|
+
"proxy-authenticate",
|
|
11
|
+
"proxy-authorization",
|
|
12
|
+
"te",
|
|
13
|
+
"trailer",
|
|
14
|
+
"transfer-encoding",
|
|
15
|
+
"upgrade",
|
|
16
|
+
"content-length",
|
|
17
|
+
"cookie"
|
|
20
18
|
]);
|
|
21
19
|
function pickRequestHeaders(src) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
return out;
|
|
20
|
+
const out = {};
|
|
21
|
+
for (const [k, v] of Object.entries(src)) {
|
|
22
|
+
if (v === void 0) continue;
|
|
23
|
+
if (HOP_BY_HOP.has(k.toLowerCase())) continue;
|
|
24
|
+
out[k] = v;
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
31
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Forwards `/__l5e/assets-v1/*` requests from the Vite dev server to the
|
|
30
|
+
* Lovable preview proxy so assets resolve when the page is loaded directly
|
|
31
|
+
* from the sandbox dev server (e.g. `localhost:8080`) instead of via
|
|
32
|
+
* `*.lovable.app` / `*.lovableproject.com`.
|
|
33
|
+
*
|
|
34
|
+
* No-op unless `LOVABLE_PREVIEW_HOST` is set (host only, no scheme), e.g.
|
|
35
|
+
* `id-preview--<project-id>.lovable.app`.
|
|
36
|
+
*/
|
|
32
37
|
function lovableAssetsProxyPlugin() {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
res.destroy(err);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
req.pipe(upstream);
|
|
76
|
-
};
|
|
77
|
-
server.middlewares.use(middleware);
|
|
78
|
-
}
|
|
79
|
-
};
|
|
38
|
+
const previewHost = process.env[PREVIEW_HOST_ENV]?.trim();
|
|
39
|
+
return {
|
|
40
|
+
name: "lovable:assets-proxy",
|
|
41
|
+
apply: "serve",
|
|
42
|
+
configureServer(server) {
|
|
43
|
+
if (!previewHost) return;
|
|
44
|
+
const middleware = (req, res, next) => {
|
|
45
|
+
const url = req.url ?? "";
|
|
46
|
+
if (!ASSET_RE.test(url)) return next();
|
|
47
|
+
const upstream = https.request({
|
|
48
|
+
host: previewHost,
|
|
49
|
+
port: 443,
|
|
50
|
+
method: req.method,
|
|
51
|
+
path: url,
|
|
52
|
+
headers: {
|
|
53
|
+
...pickRequestHeaders(req.headers),
|
|
54
|
+
host: previewHost
|
|
55
|
+
}
|
|
56
|
+
}, (upRes) => {
|
|
57
|
+
res.statusCode = upRes.statusCode ?? 502;
|
|
58
|
+
for (const [k, v] of Object.entries(upRes.headers)) {
|
|
59
|
+
if (v === void 0) continue;
|
|
60
|
+
if (HOP_BY_HOP.has(k.toLowerCase())) continue;
|
|
61
|
+
res.setHeader(k, v);
|
|
62
|
+
}
|
|
63
|
+
upRes.pipe(res);
|
|
64
|
+
});
|
|
65
|
+
upstream.on("error", (err) => {
|
|
66
|
+
server.config.logger.warn(`[@lovable.dev/vite-tanstack-config] asset proxy ${url} → ${previewHost} failed: ${err.message}`);
|
|
67
|
+
if (!res.headersSent) {
|
|
68
|
+
res.statusCode = 502;
|
|
69
|
+
res.end();
|
|
70
|
+
} else res.destroy(err);
|
|
71
|
+
});
|
|
72
|
+
req.pipe(upstream);
|
|
73
|
+
};
|
|
74
|
+
server.middlewares.use(middleware);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
80
77
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/index.ts
|
|
80
|
+
const SANDBOX_ENV_VAR = "DEV_SERVER__PROJECT_PATH";
|
|
81
|
+
const LOVABLE_SANDBOX_ENV_VAR = "LOVABLE_SANDBOX";
|
|
85
82
|
function isSandboxEnvironment() {
|
|
86
|
-
|
|
83
|
+
return process.env[LOVABLE_SANDBOX_ENV_VAR] === "1" || !!process.env[SANDBOX_ENV_VAR];
|
|
87
84
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
const TOOL_MANAGED_WATCH_IGNORES = [
|
|
86
|
+
"**/.workspace/**",
|
|
87
|
+
"**/.agents/**",
|
|
88
|
+
"**/.claude/**",
|
|
89
|
+
"**/.lovable/**",
|
|
90
|
+
"**/.tanstack/tmp/**"
|
|
94
91
|
];
|
|
95
92
|
function logWarning(message) {
|
|
96
|
-
|
|
93
|
+
console.warn(`[@lovable.dev/vite-tanstack-config] ${message}`);
|
|
97
94
|
}
|
|
98
|
-
|
|
95
|
+
const NITRO_DEFAULT_PRESET_MIN = [
|
|
96
|
+
3,
|
|
97
|
+
0,
|
|
98
|
+
260603
|
|
99
|
+
];
|
|
99
100
|
async function nitroSupportsDefaultPreset() {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
101
|
+
try {
|
|
102
|
+
const { createRequire } = await import("node:module");
|
|
103
|
+
const { version } = createRequire(`${process.cwd()}/package.json`)("nitro/package.json");
|
|
104
|
+
const match = typeof version === "string" ? /^(\d+)\.(\d+)\.(\d+)/.exec(version) : null;
|
|
105
|
+
if (!match) return true;
|
|
106
|
+
const parts = [
|
|
107
|
+
Number(match[1]),
|
|
108
|
+
Number(match[2]),
|
|
109
|
+
Number(match[3])
|
|
110
|
+
];
|
|
111
|
+
for (let i = 0; i < 3; i++) if (parts[i] !== NITRO_DEFAULT_PRESET_MIN[i]) return parts[i] > NITRO_DEFAULT_PRESET_MIN[i];
|
|
112
|
+
return true;
|
|
113
|
+
} catch {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
116
|
}
|
|
117
117
|
function validateHeaders(config) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (headerKeys.length > 0) {
|
|
123
|
-
logWarning(`Your config includes server headers that will be removed in sandbox mode: ${headerKeys.join(", ")}`);
|
|
124
|
-
}
|
|
118
|
+
const headers = config.server?.headers;
|
|
119
|
+
if (!headers) return;
|
|
120
|
+
const headerKeys = Object.keys(headers);
|
|
121
|
+
if (headerKeys.length > 0) logWarning(`Your config includes server headers that will be removed in sandbox mode: ${headerKeys.join(", ")}`);
|
|
125
122
|
}
|
|
126
123
|
function isExternalUrl(url) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
try {
|
|
125
|
+
const parsed = new URL(url);
|
|
126
|
+
return ![
|
|
127
|
+
"localhost",
|
|
128
|
+
"127.0.0.1",
|
|
129
|
+
"::1",
|
|
130
|
+
"0.0.0.0",
|
|
131
|
+
"::"
|
|
132
|
+
].includes(parsed.hostname);
|
|
133
|
+
} catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
133
136
|
}
|
|
134
137
|
function validateProxy(config) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
} else if (proxyConfig) {
|
|
146
|
-
const target = typeof proxyConfig.target === "string" ? proxyConfig.target : void 0;
|
|
147
|
-
if (target && isExternalUrl(target)) {
|
|
148
|
-
logWarning(
|
|
149
|
-
`Proxy '${path}' targets external URL: ${target}. This may cause issues in the sandbox environment.`
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
if (proxyConfig.ws) {
|
|
153
|
-
logWarning(`Proxy '${path}' enables WebSocket proxying, which may interfere with HMR.`);
|
|
154
|
-
}
|
|
155
|
-
if (proxyConfig.changeOrigin) {
|
|
156
|
-
logWarning(`Proxy '${path}' changes origin, which may cause CORS issues.`);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
138
|
+
const proxy = config.server?.proxy;
|
|
139
|
+
if (!proxy) return;
|
|
140
|
+
for (const [path, proxyConfig] of Object.entries(proxy)) if (typeof proxyConfig === "string") {
|
|
141
|
+
if (isExternalUrl(proxyConfig)) logWarning(`Proxy '${path}' targets external URL: ${proxyConfig}. This may cause issues in the sandbox environment.`);
|
|
142
|
+
} else if (proxyConfig) {
|
|
143
|
+
const target = typeof proxyConfig.target === "string" ? proxyConfig.target : void 0;
|
|
144
|
+
if (target && isExternalUrl(target)) logWarning(`Proxy '${path}' targets external URL: ${target}. This may cause issues in the sandbox environment.`);
|
|
145
|
+
if (proxyConfig.ws) logWarning(`Proxy '${path}' enables WebSocket proxying, which may interfere with HMR.`);
|
|
146
|
+
if (proxyConfig.changeOrigin) logWarning(`Proxy '${path}' changes origin, which may cause CORS issues.`);
|
|
147
|
+
}
|
|
160
148
|
}
|
|
161
149
|
function validateCors(config) {
|
|
162
|
-
|
|
163
|
-
logWarning("Custom CORS config detected. Sandbox requires specific CORS settings for proxy compatibility.");
|
|
164
|
-
}
|
|
150
|
+
if (config.server?.cors && typeof config.server.cors !== "boolean" && config.server.cors !== null) logWarning("Custom CORS config detected. Sandbox requires specific CORS settings for proxy compatibility.");
|
|
165
151
|
}
|
|
166
152
|
function validatePort(config) {
|
|
167
|
-
|
|
168
|
-
logWarning(`Port ${config.server.port} configured, but sandbox requires port 8080. Using 8080.`);
|
|
169
|
-
}
|
|
153
|
+
if (config.server?.port && config.server.port !== 8080) logWarning(`Port ${config.server.port} configured, but sandbox requires port 8080. Using 8080.`);
|
|
170
154
|
}
|
|
171
155
|
function validateConfig(config) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
156
|
+
validateHeaders(config);
|
|
157
|
+
validateProxy(config);
|
|
158
|
+
validateCors(config);
|
|
159
|
+
validatePort(config);
|
|
176
160
|
}
|
|
177
161
|
function cleanServerConfig(config) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
162
|
+
if (config.server?.headers || config.server?.cors || config.server?.proxy) {
|
|
163
|
+
const { headers: _headers, cors: _cors, proxy: _proxy, ...serverRest } = config.server;
|
|
164
|
+
return {
|
|
165
|
+
...config,
|
|
166
|
+
server: serverRest
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return config;
|
|
186
170
|
}
|
|
187
171
|
function applyWatchDebounceDefaults(config) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
});
|
|
172
|
+
const existingWatch = config.server?.watch ?? {};
|
|
173
|
+
const existingAwaitWriteFinish = existingWatch.awaitWriteFinish;
|
|
174
|
+
const hasAwaitWriteFinishObject = !!existingAwaitWriteFinish && typeof existingAwaitWriteFinish === "object" && !Array.isArray(existingAwaitWriteFinish);
|
|
175
|
+
return mergeConfig(config, { server: { watch: {
|
|
176
|
+
...existingWatch,
|
|
177
|
+
awaitWriteFinish: {
|
|
178
|
+
...hasAwaitWriteFinishObject ? existingAwaitWriteFinish : {},
|
|
179
|
+
stabilityThreshold: 1e3,
|
|
180
|
+
pollInterval: 100
|
|
181
|
+
}
|
|
182
|
+
} } });
|
|
203
183
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
184
|
+
const SSR_CAPTURE_KEY = "__LOVABLE_TANSTACK_CAPTURE_SSR_ERROR__";
|
|
185
|
+
const HANDLER_RAN_KEY = "__LOVABLE_TANSTACK_HANDLER_RAN__";
|
|
186
|
+
const BUILD_ERROR_MESSAGE = /transform failed with \d+ error|failed to parse source/i;
|
|
207
187
|
function isBuildError(error) {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
return true;
|
|
217
|
-
if (Array.isArray(e.errors) && e.errors.length > 0 && e.errors.every((x) => x != null && typeof x === "object" && "text" in x && "location" in x)) {
|
|
218
|
-
return true;
|
|
219
|
-
}
|
|
220
|
-
const message = typeof e.message === "string" ? e.message : "";
|
|
221
|
-
return BUILD_ERROR_MESSAGE.test(message);
|
|
188
|
+
if (typeof error === "string") return BUILD_ERROR_MESSAGE.test(error);
|
|
189
|
+
if (!error || typeof error !== "object") return false;
|
|
190
|
+
const e = error;
|
|
191
|
+
if (typeof e.plugin === "string" && (e.plugin.startsWith("vite:") || e.plugin.startsWith("esbuild:"))) return true;
|
|
192
|
+
if (e.frame != null && e.loc != null) return true;
|
|
193
|
+
if (Array.isArray(e.errors) && e.errors.length > 0 && e.errors.every((x) => x != null && typeof x === "object" && "text" in x && "location" in x)) return true;
|
|
194
|
+
const message = typeof e.message === "string" ? e.message : "";
|
|
195
|
+
return BUILD_ERROR_MESSAGE.test(message);
|
|
222
196
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
197
|
+
const BUILD_DIAGNOSTICS_PLUGIN_NAME = "lovable-build-error-diagnostics";
|
|
198
|
+
const MAX_DIAGNOSTIC_JSON_LENGTH = 6e3;
|
|
199
|
+
const MAX_DIAGNOSTIC_STRING_LENGTH = 2e3;
|
|
200
|
+
const MAX_DIAGNOSTIC_NESTED_ERRORS = 20;
|
|
201
|
+
const MAX_DIAGNOSTIC_DEPTH = 4;
|
|
202
|
+
const COMPACT_DIAGNOSTIC_STRING_LENGTH = 300;
|
|
203
|
+
const COMPACT_DIAGNOSTIC_NESTED_ERRORS = 3;
|
|
204
|
+
const COMPACT_DIAGNOSTIC_DEPTH = 3;
|
|
205
|
+
const DIAGNOSTIC_ERROR_FIELDS = [
|
|
206
|
+
"name",
|
|
207
|
+
"message",
|
|
208
|
+
"plugin",
|
|
209
|
+
"pluginCode",
|
|
210
|
+
"id",
|
|
211
|
+
"moduleId",
|
|
212
|
+
"hook",
|
|
213
|
+
"code",
|
|
214
|
+
"loc",
|
|
215
|
+
"frame",
|
|
216
|
+
"stack",
|
|
217
|
+
"cause"
|
|
244
218
|
];
|
|
245
219
|
function truncateDiagnosticString(value) {
|
|
246
|
-
|
|
220
|
+
return truncateDiagnosticStringTo(value, MAX_DIAGNOSTIC_STRING_LENGTH);
|
|
247
221
|
}
|
|
248
222
|
function truncateDiagnosticStringTo(value, maxLength) {
|
|
249
|
-
|
|
223
|
+
return value.length > maxLength ? `${value.slice(0, maxLength)}...[truncated]` : value;
|
|
250
224
|
}
|
|
251
225
|
function readDiagnosticProperty(value, key) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
226
|
+
try {
|
|
227
|
+
return value[key];
|
|
228
|
+
} catch (error) {
|
|
229
|
+
return `[unreadable: ${error instanceof Error ? error.message : String(error)}]`;
|
|
230
|
+
}
|
|
257
231
|
}
|
|
258
232
|
function serializeOwnDiagnosticProperties(value, depth, seen) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
output.properties_truncated = keys.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
269
|
-
}
|
|
270
|
-
return output;
|
|
233
|
+
const keys = Object.keys(value);
|
|
234
|
+
const output = {};
|
|
235
|
+
for (const key of keys.slice(0, MAX_DIAGNOSTIC_NESTED_ERRORS)) {
|
|
236
|
+
const nested = readDiagnosticProperty(value, key);
|
|
237
|
+
if (nested == null || nested === "") continue;
|
|
238
|
+
output[key] = serializeDiagnosticValue(nested, depth + 1, seen);
|
|
239
|
+
}
|
|
240
|
+
if (keys.length > MAX_DIAGNOSTIC_NESTED_ERRORS) output.properties_truncated = keys.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
241
|
+
return output;
|
|
271
242
|
}
|
|
272
243
|
function describeDiagnosticPrimitive(value) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
if (typeof value === "function")
|
|
278
|
-
return `[function ${value.name || "anonymous"}]`;
|
|
279
|
-
return String(value);
|
|
244
|
+
if (typeof value === "symbol") return value.description ? `Symbol(${value.description})` : "Symbol()";
|
|
245
|
+
if (typeof value === "bigint") return value.toString();
|
|
246
|
+
if (typeof value === "function") return `[function ${value.name || "anonymous"}]`;
|
|
247
|
+
return String(value);
|
|
280
248
|
}
|
|
281
249
|
function describeDiagnosticObject(value) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
return Object.prototype.toString.call(value);
|
|
250
|
+
const constructorName = value.constructor?.name;
|
|
251
|
+
if (typeof constructorName === "string" && constructorName !== "" && constructorName !== "Object") return `[${constructorName}]`;
|
|
252
|
+
return Object.prototype.toString.call(value);
|
|
287
253
|
}
|
|
288
254
|
function serializeDiagnosticValue(value, depth, seen) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if (nestedErrors.length > MAX_DIAGNOSTIC_NESTED_ERRORS) {
|
|
320
|
-
output.errors_truncated = nestedErrors.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
321
|
-
}
|
|
322
|
-
} else if (nestedErrors != null && nestedErrors !== "") {
|
|
323
|
-
output.errors = serializeDiagnosticValue(nestedErrors, depth + 1, seen);
|
|
324
|
-
}
|
|
325
|
-
if (Object.keys(output).length > 0)
|
|
326
|
-
return output;
|
|
327
|
-
const ownProperties = serializeOwnDiagnosticProperties(record, depth, seen);
|
|
328
|
-
return Object.keys(ownProperties).length > 0 ? ownProperties : describeDiagnosticObject(value);
|
|
329
|
-
} catch (error) {
|
|
330
|
-
return `[unreadable object: ${error instanceof Error ? error.message : String(error)}]`;
|
|
331
|
-
} finally {
|
|
332
|
-
seen.delete(value);
|
|
333
|
-
}
|
|
255
|
+
if (value == null) return value;
|
|
256
|
+
if (typeof value === "string") return truncateDiagnosticString(value);
|
|
257
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
258
|
+
if (typeof value !== "object") return describeDiagnosticPrimitive(value);
|
|
259
|
+
if (seen.has(value)) return "[circular]";
|
|
260
|
+
if (depth >= MAX_DIAGNOSTIC_DEPTH) return "[max depth]";
|
|
261
|
+
seen.add(value);
|
|
262
|
+
try {
|
|
263
|
+
if (Array.isArray(value)) return value.slice(0, MAX_DIAGNOSTIC_NESTED_ERRORS).map((item) => serializeDiagnosticValue(item, depth + 1, seen));
|
|
264
|
+
const record = value;
|
|
265
|
+
const output = {};
|
|
266
|
+
for (const field of DIAGNOSTIC_ERROR_FIELDS) {
|
|
267
|
+
if (!(field in record)) continue;
|
|
268
|
+
const nested = readDiagnosticProperty(record, field);
|
|
269
|
+
if (nested == null || nested === "") continue;
|
|
270
|
+
output[field] = serializeDiagnosticValue(nested, depth + 1, seen);
|
|
271
|
+
}
|
|
272
|
+
const nestedErrors = readDiagnosticProperty(record, "errors");
|
|
273
|
+
if (Array.isArray(nestedErrors)) {
|
|
274
|
+
output.errors = nestedErrors.slice(0, MAX_DIAGNOSTIC_NESTED_ERRORS).map((item) => serializeDiagnosticValue(item, depth + 1, seen));
|
|
275
|
+
if (nestedErrors.length > MAX_DIAGNOSTIC_NESTED_ERRORS) output.errors_truncated = nestedErrors.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
276
|
+
} else if (nestedErrors != null && nestedErrors !== "") output.errors = serializeDiagnosticValue(nestedErrors, depth + 1, seen);
|
|
277
|
+
if (Object.keys(output).length > 0) return output;
|
|
278
|
+
const ownProperties = serializeOwnDiagnosticProperties(record, depth, seen);
|
|
279
|
+
return Object.keys(ownProperties).length > 0 ? ownProperties : describeDiagnosticObject(value);
|
|
280
|
+
} catch (error) {
|
|
281
|
+
return `[unreadable object: ${error instanceof Error ? error.message : String(error)}]`;
|
|
282
|
+
} finally {
|
|
283
|
+
seen.delete(value);
|
|
284
|
+
}
|
|
334
285
|
}
|
|
335
286
|
function compactDiagnosticValue(value, depth) {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
continue;
|
|
361
|
-
output[key] = compactDiagnosticValue(nested, depth + 1);
|
|
362
|
-
}
|
|
363
|
-
if (keys.length > MAX_DIAGNOSTIC_NESTED_ERRORS) {
|
|
364
|
-
output.properties_truncated = keys.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
365
|
-
}
|
|
366
|
-
return output;
|
|
367
|
-
} catch (error) {
|
|
368
|
-
return `[unreadable object: ${error instanceof Error ? error.message : String(error)}]`;
|
|
369
|
-
}
|
|
287
|
+
if (value == null) return value;
|
|
288
|
+
if (typeof value === "string") return truncateDiagnosticStringTo(value, COMPACT_DIAGNOSTIC_STRING_LENGTH);
|
|
289
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
290
|
+
if (typeof value !== "object") return describeDiagnosticPrimitive(value);
|
|
291
|
+
if (depth >= COMPACT_DIAGNOSTIC_DEPTH) return "[max depth]";
|
|
292
|
+
try {
|
|
293
|
+
if (Array.isArray(value)) {
|
|
294
|
+
const items = value.slice(0, COMPACT_DIAGNOSTIC_NESTED_ERRORS).map((item) => compactDiagnosticValue(item, depth + 1));
|
|
295
|
+
if (value.length > COMPACT_DIAGNOSTIC_NESTED_ERRORS) items.push(`[${value.length - COMPACT_DIAGNOSTIC_NESTED_ERRORS} items truncated]`);
|
|
296
|
+
return items;
|
|
297
|
+
}
|
|
298
|
+
const record = value;
|
|
299
|
+
const output = {};
|
|
300
|
+
const keys = Object.keys(record);
|
|
301
|
+
for (const key of keys.slice(0, MAX_DIAGNOSTIC_NESTED_ERRORS)) {
|
|
302
|
+
const nested = readDiagnosticProperty(record, key);
|
|
303
|
+
if (nested == null || nested === "") continue;
|
|
304
|
+
output[key] = compactDiagnosticValue(nested, depth + 1);
|
|
305
|
+
}
|
|
306
|
+
if (keys.length > MAX_DIAGNOSTIC_NESTED_ERRORS) output.properties_truncated = keys.length - MAX_DIAGNOSTIC_NESTED_ERRORS;
|
|
307
|
+
return output;
|
|
308
|
+
} catch (error) {
|
|
309
|
+
return `[unreadable object: ${error instanceof Error ? error.message : String(error)}]`;
|
|
310
|
+
}
|
|
370
311
|
}
|
|
371
312
|
function stringifyDiagnosticPayload(diagnostics) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
313
|
+
const full = JSON.stringify(diagnostics);
|
|
314
|
+
if (full && full.length <= MAX_DIAGNOSTIC_JSON_LENGTH) return full;
|
|
315
|
+
const compact = compactDiagnosticValue(diagnostics, 0);
|
|
316
|
+
const compactPayload = compact != null && typeof compact === "object" && !Array.isArray(compact) ? {
|
|
317
|
+
...compact,
|
|
318
|
+
diagnostics_truncated: true
|
|
319
|
+
} : {
|
|
320
|
+
diagnostics_truncated: true,
|
|
321
|
+
value: compact
|
|
322
|
+
};
|
|
323
|
+
const compactJson = JSON.stringify(compactPayload);
|
|
324
|
+
if (compactJson.length <= MAX_DIAGNOSTIC_JSON_LENGTH) return compactJson;
|
|
325
|
+
return JSON.stringify({
|
|
326
|
+
diagnostics_truncated: true,
|
|
327
|
+
message: "Diagnostic payload exceeded output budget."
|
|
328
|
+
});
|
|
384
329
|
}
|
|
385
330
|
function lovableBuildErrorDiagnostics() {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
name: BUILD_DIAGNOSTICS_PLUGIN_NAME,
|
|
415
|
-
apply: "build",
|
|
416
|
-
buildEnd(error) {
|
|
417
|
-
emitDiagnostics(error);
|
|
418
|
-
},
|
|
419
|
-
// Rolldown raises output-phase errors after a clean buildEnd; only
|
|
420
|
-
// renderError sees them.
|
|
421
|
-
renderError(error) {
|
|
422
|
-
emitDiagnostics(error);
|
|
423
|
-
}
|
|
424
|
-
};
|
|
331
|
+
let emitted = false;
|
|
332
|
+
const emitDiagnostics = (error) => {
|
|
333
|
+
if (!error || emitted) return;
|
|
334
|
+
emitted = true;
|
|
335
|
+
try {
|
|
336
|
+
const output = `\n[lovable-build-error-diagnostics]\n${stringifyDiagnosticPayload(serializeDiagnosticValue(error, 0, /* @__PURE__ */ new WeakSet()))}\n[/lovable-build-error-diagnostics]\n`;
|
|
337
|
+
let written = false;
|
|
338
|
+
const write = () => {
|
|
339
|
+
if (written) return;
|
|
340
|
+
written = true;
|
|
341
|
+
try {
|
|
342
|
+
process.stderr.write(output);
|
|
343
|
+
} catch {}
|
|
344
|
+
};
|
|
345
|
+
setImmediate(write);
|
|
346
|
+
process.once("exit", write);
|
|
347
|
+
} catch {}
|
|
348
|
+
};
|
|
349
|
+
return {
|
|
350
|
+
name: BUILD_DIAGNOSTICS_PLUGIN_NAME,
|
|
351
|
+
apply: "build",
|
|
352
|
+
buildEnd(error) {
|
|
353
|
+
emitDiagnostics(error);
|
|
354
|
+
},
|
|
355
|
+
renderError(error) {
|
|
356
|
+
emitDiagnostics(error);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
425
359
|
}
|
|
426
360
|
function devSsrErrorLogger() {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
const normalizedId = id.replace(/\\/g, "/");
|
|
524
|
-
const isTargetModule = normalizedId.includes("/@tanstack/start-server-core/src/request-response.ts") || normalizedId.includes("/@tanstack/start-server-core/dist/esm/request-response.js");
|
|
525
|
-
if (!isTargetModule) {
|
|
526
|
-
return null;
|
|
527
|
-
}
|
|
528
|
-
const needle = "handler(request, requestOpts)";
|
|
529
|
-
if (!code.includes(needle)) {
|
|
530
|
-
return null;
|
|
531
|
-
}
|
|
532
|
-
return code.replace(
|
|
533
|
-
needle,
|
|
534
|
-
`(globalThis.${HANDLER_RAN_KEY}?.(typeof h3Event === "undefined" ? undefined : h3Event), Promise.resolve(${needle}).catch((err) => { globalThis.${SSR_CAPTURE_KEY}?.(err); throw err; }))`
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
};
|
|
361
|
+
let lastCapture;
|
|
362
|
+
const CAPTURE_TTL_MS = 5e3;
|
|
363
|
+
const handlerRanFlag = Symbol("lovableHandlerRan");
|
|
364
|
+
const capture = (error) => {
|
|
365
|
+
lastCapture = {
|
|
366
|
+
error,
|
|
367
|
+
at: Date.now()
|
|
368
|
+
};
|
|
369
|
+
};
|
|
370
|
+
const consumeCapture = () => {
|
|
371
|
+
if (!lastCapture) return void 0;
|
|
372
|
+
if (Date.now() - lastCapture.at > CAPTURE_TTL_MS) {
|
|
373
|
+
lastCapture = void 0;
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const { error } = lastCapture;
|
|
377
|
+
lastCapture = void 0;
|
|
378
|
+
return error;
|
|
379
|
+
};
|
|
380
|
+
return {
|
|
381
|
+
name: "dev-ssr-error-logger",
|
|
382
|
+
apply: "serve",
|
|
383
|
+
configureServer(server) {
|
|
384
|
+
globalThis[SSR_CAPTURE_KEY] = capture;
|
|
385
|
+
globalThis[HANDLER_RAN_KEY] = (event) => {
|
|
386
|
+
const res = event?.node?.res;
|
|
387
|
+
if (res) res[handlerRanFlag] = true;
|
|
388
|
+
};
|
|
389
|
+
const g = globalThis;
|
|
390
|
+
if (typeof g.addEventListener === "function") {
|
|
391
|
+
const addListener = g.addEventListener;
|
|
392
|
+
addListener("error", (e) => capture(e.error ?? e));
|
|
393
|
+
addListener("unhandledrejection", (e) => capture(e.reason));
|
|
394
|
+
}
|
|
395
|
+
const onUnhandledRejection = (reason) => capture(reason);
|
|
396
|
+
process.on("unhandledRejection", onUnhandledRejection);
|
|
397
|
+
server.httpServer?.once("close", () => {
|
|
398
|
+
process.off("unhandledRejection", onUnhandledRejection);
|
|
399
|
+
});
|
|
400
|
+
server.middlewares.use((req, res, next) => {
|
|
401
|
+
let handled = false;
|
|
402
|
+
const handleErrorResponse = () => {
|
|
403
|
+
if (handled || res.statusCode < 500) return;
|
|
404
|
+
handled = true;
|
|
405
|
+
const captured = consumeCapture();
|
|
406
|
+
const ranHandler = Boolean(res[handlerRanFlag]);
|
|
407
|
+
let source;
|
|
408
|
+
if (!ranHandler) source = "vite";
|
|
409
|
+
else if (isBuildError(captured)) source = "build";
|
|
410
|
+
else source = "app";
|
|
411
|
+
if (!res.headersSent) try {
|
|
412
|
+
res.setHeader("x-lovable-error-source", source);
|
|
413
|
+
} catch {}
|
|
414
|
+
const where = [req.method, req.url].filter(Boolean).join(" ") || "the request";
|
|
415
|
+
let data;
|
|
416
|
+
if (captured instanceof Error) data = {
|
|
417
|
+
name: captured.name,
|
|
418
|
+
message: captured.message,
|
|
419
|
+
stack: captured.stack
|
|
420
|
+
};
|
|
421
|
+
else if (typeof captured === "string" && captured.length > 0) data = {
|
|
422
|
+
name: "Error",
|
|
423
|
+
message: captured
|
|
424
|
+
};
|
|
425
|
+
else if (ranHandler) data = { message: `The app returned ${res.statusCode} while handling ${where}. The error was handled by a route or error boundary, so no stack was captured — check the failing loader/route code and the dev server output.` };
|
|
426
|
+
else data = { message: `Dev server returned ${res.statusCode} for ${where} before the app handler ran. This is usually a Vite build/transform error — check the dev server output for the underlying error.` };
|
|
427
|
+
try {
|
|
428
|
+
server.ws.send({
|
|
429
|
+
type: "custom",
|
|
430
|
+
event: "server-ssr-error",
|
|
431
|
+
data
|
|
432
|
+
});
|
|
433
|
+
} catch {}
|
|
434
|
+
};
|
|
435
|
+
const origWriteHead = res.writeHead.bind(res);
|
|
436
|
+
res.writeHead = (...args) => {
|
|
437
|
+
if (typeof args[0] === "number") res.statusCode = args[0];
|
|
438
|
+
handleErrorResponse();
|
|
439
|
+
return origWriteHead(...args);
|
|
440
|
+
};
|
|
441
|
+
const origEnd = res.end.bind(res);
|
|
442
|
+
res.end = (...args) => {
|
|
443
|
+
handleErrorResponse();
|
|
444
|
+
return origEnd(...args);
|
|
445
|
+
};
|
|
446
|
+
next();
|
|
447
|
+
});
|
|
448
|
+
},
|
|
449
|
+
transform(code, id) {
|
|
450
|
+
const normalizedId = id.replace(/\\/g, "/");
|
|
451
|
+
if (!(normalizedId.includes("/@tanstack/start-server-core/src/request-response.ts") || normalizedId.includes("/@tanstack/start-server-core/dist/esm/request-response.js"))) return null;
|
|
452
|
+
const needle = "handler(request, requestOpts)";
|
|
453
|
+
if (!code.includes(needle)) return null;
|
|
454
|
+
return code.replace(needle, `(globalThis.${HANDLER_RAN_KEY}?.(typeof h3Event === "undefined" ? undefined : h3Event), Promise.resolve(${needle}).catch((err) => { globalThis.${SSR_CAPTURE_KEY}?.(err); throw err; }))`);
|
|
455
|
+
}
|
|
456
|
+
};
|
|
538
457
|
}
|
|
539
458
|
function devServerFnErrorLogger() {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const needle = "const unwrapped = res.result || res.error";
|
|
561
|
-
if (!code.includes(needle)) {
|
|
562
|
-
return null;
|
|
563
|
-
}
|
|
564
|
-
return code.replace(
|
|
565
|
-
needle,
|
|
566
|
-
`${needle}
|
|
459
|
+
const HMR_SEND_KEY = "__TANSTACK_SERVER_FN_HMR_SEND__";
|
|
460
|
+
return {
|
|
461
|
+
name: "dev-server-fn-error-logger",
|
|
462
|
+
apply: "serve",
|
|
463
|
+
enforce: "pre",
|
|
464
|
+
configureServer(server) {
|
|
465
|
+
globalThis[HMR_SEND_KEY] = (data) => {
|
|
466
|
+
server.ws.send({
|
|
467
|
+
type: "custom",
|
|
468
|
+
event: "server-fn-error",
|
|
469
|
+
data
|
|
470
|
+
});
|
|
471
|
+
};
|
|
472
|
+
},
|
|
473
|
+
transform(code, id) {
|
|
474
|
+
const normalizedId = id.replace(/\\/g, "/");
|
|
475
|
+
if (!(normalizedId.includes("/@tanstack/start-server-core/src/server-functions-handler.ts") || normalizedId.includes("/@tanstack/start-server-core/dist/esm/server-functions-handler.js"))) return null;
|
|
476
|
+
const needle = "const unwrapped = res.result || res.error";
|
|
477
|
+
if (!code.includes(needle)) return null;
|
|
478
|
+
return code.replace(needle, `${needle}
|
|
567
479
|
|
|
568
480
|
if (res?.error) {
|
|
569
481
|
const err = res.error
|
|
@@ -577,191 +489,156 @@ function devServerFnErrorLogger() {
|
|
|
577
489
|
stack: typeof err?.stack === 'string' ? err.stack : undefined,
|
|
578
490
|
}
|
|
579
491
|
globalThis.${HMR_SEND_KEY}?.(payload)
|
|
580
|
-
}`
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
};
|
|
492
|
+
}`);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
584
495
|
}
|
|
585
496
|
function defineConfig(configOrOptions = {}) {
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
"@tanstack/react-query",
|
|
732
|
-
"@tanstack/query-core"
|
|
733
|
-
]
|
|
734
|
-
},
|
|
735
|
-
// Dep re-optimization rotates the optimized-dep hash and 504s tabs holding
|
|
736
|
-
// the old one; pre-bundle the always-present client deps + tolerate stale
|
|
737
|
-
// requests. React core only — including @tanstack/react-start would pull its
|
|
738
|
-
// node:async_hooks server entry into the client bundle and crash hydration.
|
|
739
|
-
optimizeDeps: {
|
|
740
|
-
include: ["react", "react-dom", "react-dom/client", "react/jsx-runtime", "react/jsx-dev-runtime"],
|
|
741
|
-
ignoreOutdatedRequests: true
|
|
742
|
-
},
|
|
743
|
-
plugins: [...internalPlugins, ...options.plugins ?? []]
|
|
744
|
-
};
|
|
745
|
-
if (options.vite) {
|
|
746
|
-
config = mergeConfig(config, options.vite);
|
|
747
|
-
}
|
|
748
|
-
if (isSandbox) {
|
|
749
|
-
validateConfig(config);
|
|
750
|
-
config = cleanServerConfig(
|
|
751
|
-
mergeConfig(config, {
|
|
752
|
-
server: { host: "::", port: 8080, strictPort: true, watch: { ignored: [...TOOL_MANAGED_WATCH_IGNORES] } }
|
|
753
|
-
})
|
|
754
|
-
);
|
|
755
|
-
} else {
|
|
756
|
-
config = mergeConfig({ server: { host: "::", port: 8080 } }, config);
|
|
757
|
-
}
|
|
758
|
-
if (isSandbox) {
|
|
759
|
-
return config;
|
|
760
|
-
}
|
|
761
|
-
return applyWatchDebounceDefaults(config);
|
|
762
|
-
};
|
|
497
|
+
return async (env) => {
|
|
498
|
+
const { command, mode } = env;
|
|
499
|
+
const isSandbox = isSandboxEnvironment();
|
|
500
|
+
const isDevBuild = command === "build" && mode === "development";
|
|
501
|
+
let options;
|
|
502
|
+
if (typeof configOrOptions === "function") options = { vite: await Promise.resolve(configOrOptions(env)) };
|
|
503
|
+
else if (configOrOptions instanceof Promise) options = { vite: await configOrOptions };
|
|
504
|
+
else {
|
|
505
|
+
const optionObject = configOrOptions && typeof configOrOptions === "object" ? configOrOptions : {};
|
|
506
|
+
if ("cloudflare" in optionObject) if (optionObject.cloudflare === false && !("nitro" in optionObject)) {
|
|
507
|
+
optionObject.nitro = false;
|
|
508
|
+
logWarning("`cloudflare: false` is deprecated in v2 — migrated to `nitro: false`. Update your config to drop the warning.");
|
|
509
|
+
} else logWarning("The `cloudflare` option was removed in v2. Use `nitro: false` to disable the deploy plugin, or `nitro: { preset: '...' }` to configure it. The `cloudflare` setting is being ignored.");
|
|
510
|
+
options = "vite" in optionObject || "serverFnErrorLogger" in optionObject || "ssrErrorLogger" in optionObject || "nitro" in optionObject || "tanstackStart" in optionObject || "react" in optionObject || "envDefine" in optionObject || "hmrGate" in optionObject ? optionObject : { vite: optionObject };
|
|
511
|
+
}
|
|
512
|
+
const internalPlugins = [];
|
|
513
|
+
if (mode === "development") {
|
|
514
|
+
const { devtools } = await import("@tanstack/devtools-vite");
|
|
515
|
+
internalPlugins.push(devtools({
|
|
516
|
+
logging: false,
|
|
517
|
+
eventBusConfig: { enabled: false },
|
|
518
|
+
enhancedLogs: { enabled: false },
|
|
519
|
+
consolePiping: { enabled: false },
|
|
520
|
+
removeDevtoolsOnBuild: false,
|
|
521
|
+
injectSource: { enabled: true }
|
|
522
|
+
}));
|
|
523
|
+
}
|
|
524
|
+
const tailwindcss = (await import("@tailwindcss/vite")).default;
|
|
525
|
+
internalPlugins.push(tailwindcss());
|
|
526
|
+
const tsConfigPaths = (await import("vite-tsconfig-paths")).default;
|
|
527
|
+
internalPlugins.push(tsConfigPaths({ projects: ["./tsconfig.json"] }));
|
|
528
|
+
if (options.serverFnErrorLogger !== false) internalPlugins.push(devServerFnErrorLogger());
|
|
529
|
+
if (options.ssrErrorLogger !== false) internalPlugins.push(devSsrErrorLogger());
|
|
530
|
+
if (command === "build" && isSandbox) internalPlugins.push(lovableBuildErrorDiagnostics());
|
|
531
|
+
const { tanstackStart } = await import("@tanstack/react-start/plugin/vite");
|
|
532
|
+
const tanstackStartOptions = mergeConfig({ importProtection: {
|
|
533
|
+
behavior: "error",
|
|
534
|
+
client: {
|
|
535
|
+
files: ["**/server/**"],
|
|
536
|
+
specifiers: ["server-only"]
|
|
537
|
+
}
|
|
538
|
+
} }, options.tanstackStart ?? {});
|
|
539
|
+
internalPlugins.push(tanstackStart(tanstackStartOptions));
|
|
540
|
+
const explicitNitro = options.nitro === true || typeof options.nitro === "object" && options.nitro !== null;
|
|
541
|
+
if (options.nitro !== false && command === "build") {
|
|
542
|
+
let nitroMod;
|
|
543
|
+
try {
|
|
544
|
+
nitroMod = await import("nitro/vite");
|
|
545
|
+
} catch (err) {
|
|
546
|
+
if (explicitNitro || isSandbox) {
|
|
547
|
+
const reason = explicitNitro ? `an explicit \`nitro\` option (${options.nitro === true ? "true" : "{ ... }"}) was set in vite.config.ts` : "running inside a Lovable sandbox";
|
|
548
|
+
throw new Error(`[@lovable.dev/vite-tanstack-config] ${reason}, but the \`nitro\` package isn't installed. Add \`nitro\` to your devDependencies (matches peerDependency >=3.0.260429-beta). Original import error: ${err instanceof Error ? err.message : String(err)}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (nitroMod) {
|
|
552
|
+
const { nitro } = nitroMod;
|
|
553
|
+
const userNitroOpts = typeof options.nitro === "object" && options.nitro ? options.nitro : {};
|
|
554
|
+
const nitroOpts = {
|
|
555
|
+
defaultPreset: "cloudflare-module",
|
|
556
|
+
...userNitroOpts
|
|
557
|
+
};
|
|
558
|
+
if (isSandbox) {
|
|
559
|
+
delete nitroOpts.defaultPreset;
|
|
560
|
+
nitroOpts.preset = "cloudflare-module";
|
|
561
|
+
nitroOpts.output = {
|
|
562
|
+
dir: "dist",
|
|
563
|
+
serverDir: "dist/server",
|
|
564
|
+
publicDir: "dist/client"
|
|
565
|
+
};
|
|
566
|
+
nitroOpts.cloudflare = {
|
|
567
|
+
nodeCompat: true,
|
|
568
|
+
deployConfig: true,
|
|
569
|
+
...userNitroOpts.cloudflare
|
|
570
|
+
};
|
|
571
|
+
} else if (!nitroOpts.preset && !await nitroSupportsDefaultPreset()) logWarning("The installed `nitro` predates the `defaultPreset` option (3.0.260603-beta), so the Cloudflare fallback is ignored and a zero-config build may target Node instead. Upgrade nitro to >=3.0.260603-beta, or set an explicit `nitro: { preset: \"cloudflare-module\" }`.");
|
|
572
|
+
internalPlugins.push(nitro(nitroOpts));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
const viteReact = (await import("@vitejs/plugin-react")).default;
|
|
576
|
+
internalPlugins.push(viteReact(options.react));
|
|
577
|
+
if (command === "serve") {
|
|
578
|
+
const hmrGateOpt = options.hmrGate;
|
|
579
|
+
if (isSandbox ? hmrGateOpt !== false : !!hmrGateOpt) {
|
|
580
|
+
const { hmrGatePlugin } = await import("@lovable.dev/vite-plugin-hmr-gate");
|
|
581
|
+
const hmrGateOptions = typeof hmrGateOpt === "object" ? hmrGateOpt : {};
|
|
582
|
+
internalPlugins.push(hmrGatePlugin(hmrGateOptions));
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
if (command === "serve" && isSandbox) {
|
|
586
|
+
const { devServerBridgePlugin } = await import("@lovable.dev/vite-plugin-dev-server-bridge");
|
|
587
|
+
internalPlugins.push(devServerBridgePlugin());
|
|
588
|
+
}
|
|
589
|
+
if (command === "serve") internalPlugins.push(lovableAssetsProxyPlugin());
|
|
590
|
+
let envDefine = {};
|
|
591
|
+
if (options.envDefine !== false) {
|
|
592
|
+
const loadedEnv = loadEnv(mode, process.cwd(), "VITE_");
|
|
593
|
+
for (const [key, value] of Object.entries(loadedEnv)) envDefine[`import.meta.env.${key}`] = JSON.stringify(value);
|
|
594
|
+
}
|
|
595
|
+
let config = {
|
|
596
|
+
define: envDefine,
|
|
597
|
+
...isDevBuild ? {
|
|
598
|
+
environments: { client: { define: { "process.env.NODE_ENV": JSON.stringify("development") } } },
|
|
599
|
+
esbuild: { keepNames: true }
|
|
600
|
+
} : {},
|
|
601
|
+
css: { transformer: "lightningcss" },
|
|
602
|
+
resolve: {
|
|
603
|
+
alias: { "@": `${process.cwd()}/src` },
|
|
604
|
+
dedupe: [
|
|
605
|
+
"react",
|
|
606
|
+
"react-dom",
|
|
607
|
+
"react/jsx-runtime",
|
|
608
|
+
"react/jsx-dev-runtime",
|
|
609
|
+
"@tanstack/react-query",
|
|
610
|
+
"@tanstack/query-core"
|
|
611
|
+
]
|
|
612
|
+
},
|
|
613
|
+
optimizeDeps: {
|
|
614
|
+
include: [
|
|
615
|
+
"react",
|
|
616
|
+
"react-dom",
|
|
617
|
+
"react-dom/client",
|
|
618
|
+
"react/jsx-runtime",
|
|
619
|
+
"react/jsx-dev-runtime"
|
|
620
|
+
],
|
|
621
|
+
ignoreOutdatedRequests: true
|
|
622
|
+
},
|
|
623
|
+
plugins: [...internalPlugins, ...options.plugins ?? []]
|
|
624
|
+
};
|
|
625
|
+
if (options.vite) config = mergeConfig(config, options.vite);
|
|
626
|
+
if (isSandbox) {
|
|
627
|
+
validateConfig(config);
|
|
628
|
+
config = cleanServerConfig(mergeConfig(config, { server: {
|
|
629
|
+
host: "::",
|
|
630
|
+
port: 8080,
|
|
631
|
+
strictPort: true,
|
|
632
|
+
watch: { ignored: [...TOOL_MANAGED_WATCH_IGNORES] },
|
|
633
|
+
hmr: { overlay: false }
|
|
634
|
+
} }));
|
|
635
|
+
} else config = mergeConfig({ server: {
|
|
636
|
+
host: "::",
|
|
637
|
+
port: 8080
|
|
638
|
+
} }, config);
|
|
639
|
+
if (isSandbox) return config;
|
|
640
|
+
return applyWatchDebounceDefaults(config);
|
|
641
|
+
};
|
|
763
642
|
}
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
lovableAssetsProxyPlugin
|
|
767
|
-
};
|
|
643
|
+
//#endregion
|
|
644
|
+
export { defineConfig, lovableAssetsProxyPlugin };
|