@lovable.dev/mcp-js 0.16.0 → 0.17.0

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.
@@ -1,17 +1,19 @@
1
1
  import {
2
2
  DEFAULT_METRICS_ENDPOINT,
3
+ LOG_LEVEL_ENV_VAR,
4
+ applyLogLevelFromEnv,
3
5
  describeError,
4
6
  log,
5
7
  parseSafeUrl,
6
8
  resolveMetricsConfig,
7
9
  trimTrailingSlash
8
- } from "./chunk-DCWYK4CA.js";
10
+ } from "./chunk-VQQZAFRA.js";
9
11
  import {
10
12
  OAUTH_PROTECTED_RESOURCE_METADATA_PATH
11
13
  } from "./chunk-6DXGZZA4.js";
12
14
  import {
13
15
  version
14
- } from "./chunk-SKSKC747.js";
16
+ } from "./chunk-J5BTCP6T.js";
15
17
 
16
18
  // src/core/http.ts
17
19
  var JSON_HEADERS = { "Content-Type": "application/json" };
@@ -143,12 +145,28 @@ function readRuntimeEnv(name) {
143
145
  }
144
146
  return void 0;
145
147
  }
148
+ var cloudflareEnvPromise;
149
+ async function readCloudflareEnv(name) {
150
+ try {
151
+ const moduleSpecifier = "cloudflare:workers";
152
+ cloudflareEnvPromise ??= import(
153
+ /* @vite-ignore */
154
+ moduleSpecifier
155
+ ).then((m) => m.env).catch(() => void 0);
156
+ const env = await cloudflareEnvPromise;
157
+ const value = env?.[name];
158
+ return typeof value === "string" && value ? value : void 0;
159
+ } catch {
160
+ return void 0;
161
+ }
162
+ }
146
163
  function probeWaitUntil() {
147
164
  const fn = globalThis.EdgeRuntime?.waitUntil;
148
165
  return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
149
166
  }
150
167
  function createMetricsRecorder(ctx, deps = {}) {
151
168
  const { config, server } = ctx;
169
+ applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
152
170
  if (!config.enabled)
153
171
  return NOOP_RECORDER;
154
172
  const doFetch = deps.fetch ?? globalThis.fetch;
@@ -157,14 +175,23 @@ function createMetricsRecorder(ctx, deps = {}) {
157
175
  return NOOP_RECORDER;
158
176
  }
159
177
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
160
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
161
- if (usesLovableEndpoint && !apiKey) {
162
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
163
- return NOOP_RECORDER;
164
- }
165
178
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
166
179
  const buffer = [];
167
180
  let timer;
181
+ let lazyLogLevelApplied = false;
182
+ const applyLazyLogLevel = async () => {
183
+ if (lazyLogLevelApplied)
184
+ return;
185
+ lazyLogLevelApplied = true;
186
+ applyLogLevelFromEnv(await readCloudflareEnv(LOG_LEVEL_ENV_VAR));
187
+ };
188
+ let apiKey;
189
+ const resolveApiKey = async () => {
190
+ if (apiKey)
191
+ return apiKey;
192
+ apiKey = (deps.getApiKey ? deps.getApiKey() : readRuntimeEnv(config.apiKeyEnvVar)) ?? await readCloudflareEnv(config.apiKeyEnvVar);
193
+ return apiKey;
194
+ };
168
195
  const schedule = (p) => {
169
196
  if (waitUntil) {
170
197
  try {
@@ -177,21 +204,33 @@ function createMetricsRecorder(ctx, deps = {}) {
177
204
  void p.catch(() => {
178
205
  });
179
206
  };
180
- const headers = {};
207
+ const baseHeaders = {};
181
208
  if (!usesLovableEndpoint) {
182
209
  for (const [key, value] of Object.entries(config.headers)) {
183
210
  if (key.toLowerCase() !== "content-type")
184
- headers[key] = value;
211
+ baseHeaders[key] = value;
185
212
  }
186
213
  }
187
- headers["content-type"] = "application/json";
188
- if (apiKey)
189
- headers.authorization = `Bearer ${apiKey}`;
214
+ baseHeaders["content-type"] = "application/json";
190
215
  const flush = async () => {
216
+ void applyLazyLogLevel();
191
217
  if (buffer.length === 0)
192
218
  return;
193
219
  const records = buffer.splice(0, buffer.length);
194
220
  const dropped = records.length;
221
+ const headers = { ...baseHeaders };
222
+ if (usesLovableEndpoint) {
223
+ const key = await resolveApiKey();
224
+ if (!key) {
225
+ log.warn("metrics.disabled_no_api_key", {
226
+ envVar: config.apiKeyEnvVar,
227
+ endpoint: config.endpoint,
228
+ dropped
229
+ });
230
+ return;
231
+ }
232
+ headers.authorization = `Bearer ${key}`;
233
+ }
195
234
  try {
196
235
  const res = await doFetch(config.endpoint, {
197
236
  method: "POST",
@@ -8,11 +8,11 @@ import {
8
8
  nowMs,
9
9
  reportInvocation,
10
10
  withCors
11
- } from "./chunk-H6BKTNJY.js";
11
+ } from "./chunk-6TZNGFRM.js";
12
12
  import {
13
13
  describeError,
14
14
  log
15
- } from "./chunk-DCWYK4CA.js";
15
+ } from "./chunk-VQQZAFRA.js";
16
16
 
17
17
  // src/protocols/mcp/protocol.ts
18
18
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -6,7 +6,7 @@ import {
6
6
  headResponse,
7
7
  methodNotAllowed,
8
8
  withCors
9
- } from "./chunk-H6BKTNJY.js";
9
+ } from "./chunk-6TZNGFRM.js";
10
10
 
11
11
  // src/protocols/rest/list-tools.ts
12
12
  import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -7,11 +7,11 @@ import {
7
7
  oauthConfigurationErrorResponse,
8
8
  resolveProtectedResource,
9
9
  withCors
10
- } from "./chunk-H6BKTNJY.js";
10
+ } from "./chunk-6TZNGFRM.js";
11
11
  import {
12
12
  describeError,
13
13
  log
14
- } from "./chunk-DCWYK4CA.js";
14
+ } from "./chunk-VQQZAFRA.js";
15
15
 
16
16
  // src/protocols/oauth-metadata.ts
17
17
  function notFound() {
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "0.16.0";
2
+ var version = "0.17.0";
3
3
 
4
4
  export {
5
5
  version
@@ -3,19 +3,29 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
3
3
  function isLogLevel(value) {
4
4
  return typeof value === "string" && value in LEVEL_RANK;
5
5
  }
6
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
6
7
  function readEnvLevel() {
7
8
  try {
8
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
9
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
9
10
  const normalized = raw?.trim().toLowerCase();
10
11
  return isLogLevel(normalized) ? normalized : void 0;
11
12
  } catch {
12
13
  return void 0;
13
14
  }
14
15
  }
15
- var currentLevel = readEnvLevel() ?? "silent";
16
+ var currentLevel = readEnvLevel() ?? "debug";
16
17
  function setLogLevel(level) {
17
18
  currentLevel = level;
18
19
  }
20
+ function parseLogLevel(raw) {
21
+ const normalized = raw?.trim().toLowerCase();
22
+ return isLogLevel(normalized) ? normalized : void 0;
23
+ }
24
+ function applyLogLevelFromEnv(raw) {
25
+ const level = parseLogLevel(raw);
26
+ if (level)
27
+ setLogLevel(level);
28
+ }
19
29
  function enabled(level) {
20
30
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
21
31
  }
@@ -115,7 +125,9 @@ export {
115
125
  resolveMetricsConfig,
116
126
  trimTrailingSlash,
117
127
  parseSafeUrl,
128
+ LOG_LEVEL_ENV_VAR,
118
129
  setLogLevel,
130
+ applyLogLevelFromEnv,
119
131
  log,
120
132
  describeError
121
133
  };
@@ -11,7 +11,7 @@ import {
11
11
  nowMs,
12
12
  reportInvocation,
13
13
  withCors
14
- } from "./chunk-H6BKTNJY.js";
14
+ } from "./chunk-6TZNGFRM.js";
15
15
 
16
16
  // src/protocols/rest/invoke-tool.ts
17
17
  import { getParseErrorMessage, objectFromShape, safeParseAsync } from "@modelcontextprotocol/sdk/server/zod-compat.js";
@@ -13,7 +13,7 @@ function isFileMissing(err) {
13
13
  }
14
14
 
15
15
  // package.json
16
- var version = "0.16.0";
16
+ var version = "0.17.0";
17
17
 
18
18
  // src/protocols/rest/list-tools.ts
19
19
  var import_zod_compat = require("@modelcontextprotocol/sdk/server/zod-compat.js");
@@ -24,16 +24,17 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
24
24
  function isLogLevel(value) {
25
25
  return typeof value === "string" && value in LEVEL_RANK;
26
26
  }
27
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
27
28
  function readEnvLevel() {
28
29
  try {
29
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
30
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
30
31
  const normalized = raw?.trim().toLowerCase();
31
32
  return isLogLevel(normalized) ? normalized : void 0;
32
33
  } catch {
33
34
  return void 0;
34
35
  }
35
36
  }
36
- var currentLevel = readEnvLevel() ?? "silent";
37
+ var currentLevel = readEnvLevel() ?? "debug";
37
38
 
38
39
  // src/auth/verifier.ts
39
40
  var import_jose = require("jose");
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildMcpListing
4
- } from "../chunk-I5CAQUQI.js";
5
- import "../chunk-H6BKTNJY.js";
6
- import "../chunk-DCWYK4CA.js";
4
+ } from "../chunk-FW6YL5C5.js";
5
+ import "../chunk-6TZNGFRM.js";
6
+ import "../chunk-VQQZAFRA.js";
7
7
  import "../chunk-6DXGZZA4.js";
8
8
  import {
9
9
  isFileMissing
10
10
  } from "../chunk-Y3ZFPEQH.js";
11
11
  import {
12
12
  version
13
- } from "../chunk-SKSKC747.js";
13
+ } from "../chunk-J5BTCP6T.js";
14
14
 
15
15
  // src/manifest/io.ts
16
16
  import { randomUUID } from "crypto";
package/dist/index.cjs CHANGED
@@ -319,16 +319,17 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
319
319
  function isLogLevel(value) {
320
320
  return typeof value === "string" && value in LEVEL_RANK;
321
321
  }
322
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
322
323
  function readEnvLevel() {
323
324
  try {
324
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
325
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
325
326
  const normalized = raw?.trim().toLowerCase();
326
327
  return isLogLevel(normalized) ? normalized : void 0;
327
328
  } catch {
328
329
  return void 0;
329
330
  }
330
331
  }
331
- var currentLevel = readEnvLevel() ?? "silent";
332
+ var currentLevel = readEnvLevel() ?? "debug";
332
333
  function setLogLevel(level) {
333
334
  currentLevel = level;
334
335
  }
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  parseSafeUrl,
6
6
  resolveMetricsConfig,
7
7
  setLogLevel
8
- } from "./chunk-DCWYK4CA.js";
8
+ } from "./chunk-VQQZAFRA.js";
9
9
 
10
10
  // src/core/define.ts
11
11
  function assertUniqueNames(mcp) {
@@ -36,16 +36,29 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
36
36
  function isLogLevel(value) {
37
37
  return typeof value === "string" && value in LEVEL_RANK;
38
38
  }
39
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
39
40
  function readEnvLevel() {
40
41
  try {
41
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
42
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
42
43
  const normalized = raw?.trim().toLowerCase();
43
44
  return isLogLevel(normalized) ? normalized : void 0;
44
45
  } catch {
45
46
  return void 0;
46
47
  }
47
48
  }
48
- var currentLevel = readEnvLevel() ?? "silent";
49
+ var currentLevel = readEnvLevel() ?? "debug";
50
+ function setLogLevel(level) {
51
+ currentLevel = level;
52
+ }
53
+ function parseLogLevel(raw) {
54
+ const normalized = raw?.trim().toLowerCase();
55
+ return isLogLevel(normalized) ? normalized : void 0;
56
+ }
57
+ function applyLogLevelFromEnv(raw) {
58
+ const level = parseLogLevel(raw);
59
+ if (level)
60
+ setLogLevel(level);
61
+ }
49
62
  function enabled(level) {
50
63
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
51
64
  }
@@ -105,7 +118,7 @@ function resolveMetricsConfig(config = true) {
105
118
  }
106
119
 
107
120
  // package.json
108
- var version = "0.16.0";
121
+ var version = "0.17.0";
109
122
 
110
123
  // src/metrics/otlp.ts
111
124
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -201,12 +214,28 @@ function readRuntimeEnv(name) {
201
214
  }
202
215
  return void 0;
203
216
  }
217
+ var cloudflareEnvPromise;
218
+ async function readCloudflareEnv(name) {
219
+ try {
220
+ const moduleSpecifier = "cloudflare:workers";
221
+ cloudflareEnvPromise ??= import(
222
+ /* @vite-ignore */
223
+ moduleSpecifier
224
+ ).then((m) => m.env).catch(() => void 0);
225
+ const env = await cloudflareEnvPromise;
226
+ const value = env?.[name];
227
+ return typeof value === "string" && value ? value : void 0;
228
+ } catch {
229
+ return void 0;
230
+ }
231
+ }
204
232
  function probeWaitUntil() {
205
233
  const fn = globalThis.EdgeRuntime?.waitUntil;
206
234
  return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
207
235
  }
208
236
  function createMetricsRecorder(ctx, deps = {}) {
209
237
  const { config, server } = ctx;
238
+ applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
210
239
  if (!config.enabled)
211
240
  return NOOP_RECORDER;
212
241
  const doFetch = deps.fetch ?? globalThis.fetch;
@@ -215,14 +244,23 @@ function createMetricsRecorder(ctx, deps = {}) {
215
244
  return NOOP_RECORDER;
216
245
  }
217
246
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
218
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
219
- if (usesLovableEndpoint && !apiKey) {
220
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
221
- return NOOP_RECORDER;
222
- }
223
247
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
224
248
  const buffer = [];
225
249
  let timer;
250
+ let lazyLogLevelApplied = false;
251
+ const applyLazyLogLevel = async () => {
252
+ if (lazyLogLevelApplied)
253
+ return;
254
+ lazyLogLevelApplied = true;
255
+ applyLogLevelFromEnv(await readCloudflareEnv(LOG_LEVEL_ENV_VAR));
256
+ };
257
+ let apiKey;
258
+ const resolveApiKey = async () => {
259
+ if (apiKey)
260
+ return apiKey;
261
+ apiKey = (deps.getApiKey ? deps.getApiKey() : readRuntimeEnv(config.apiKeyEnvVar)) ?? await readCloudflareEnv(config.apiKeyEnvVar);
262
+ return apiKey;
263
+ };
226
264
  const schedule = (p) => {
227
265
  if (waitUntil) {
228
266
  try {
@@ -235,21 +273,33 @@ function createMetricsRecorder(ctx, deps = {}) {
235
273
  void p.catch(() => {
236
274
  });
237
275
  };
238
- const headers = {};
276
+ const baseHeaders = {};
239
277
  if (!usesLovableEndpoint) {
240
278
  for (const [key, value] of Object.entries(config.headers)) {
241
279
  if (key.toLowerCase() !== "content-type")
242
- headers[key] = value;
280
+ baseHeaders[key] = value;
243
281
  }
244
282
  }
245
- headers["content-type"] = "application/json";
246
- if (apiKey)
247
- headers.authorization = `Bearer ${apiKey}`;
283
+ baseHeaders["content-type"] = "application/json";
248
284
  const flush = async () => {
285
+ void applyLazyLogLevel();
249
286
  if (buffer.length === 0)
250
287
  return;
251
288
  const records = buffer.splice(0, buffer.length);
252
289
  const dropped = records.length;
290
+ const headers = { ...baseHeaders };
291
+ if (usesLovableEndpoint) {
292
+ const key = await resolveApiKey();
293
+ if (!key) {
294
+ log.warn("metrics.disabled_no_api_key", {
295
+ envVar: config.apiKeyEnvVar,
296
+ endpoint: config.endpoint,
297
+ dropped
298
+ });
299
+ return;
300
+ }
301
+ headers.authorization = `Bearer ${key}`;
302
+ }
253
303
  try {
254
304
  const res = await doFetch(config.endpoint, {
255
305
  method: "POST",
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createMcpProtocolHandler
3
- } from "../../chunk-EZQVUNXB.js";
3
+ } from "../../chunk-EL6YNP2R.js";
4
4
  import "../../chunk-MA5H6PSF.js";
5
- import "../../chunk-H6BKTNJY.js";
6
- import "../../chunk-DCWYK4CA.js";
5
+ import "../../chunk-6TZNGFRM.js";
6
+ import "../../chunk-VQQZAFRA.js";
7
7
  import "../../chunk-6DXGZZA4.js";
8
- import "../../chunk-SKSKC747.js";
8
+ import "../../chunk-J5BTCP6T.js";
9
9
  export {
10
10
  createMcpProtocolHandler
11
11
  };
@@ -41,16 +41,17 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
41
41
  function isLogLevel(value) {
42
42
  return typeof value === "string" && value in LEVEL_RANK;
43
43
  }
44
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
44
45
  function readEnvLevel() {
45
46
  try {
46
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
47
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
47
48
  const normalized = raw?.trim().toLowerCase();
48
49
  return isLogLevel(normalized) ? normalized : void 0;
49
50
  } catch {
50
51
  return void 0;
51
52
  }
52
53
  }
53
- var currentLevel = readEnvLevel() ?? "silent";
54
+ var currentLevel = readEnvLevel() ?? "debug";
54
55
  function enabled(level) {
55
56
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
56
57
  }
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  createOAuthProtectedResourceMetadataHandler
3
- } from "../chunk-T24Z753F.js";
4
- import "../chunk-H6BKTNJY.js";
5
- import "../chunk-DCWYK4CA.js";
3
+ } from "../chunk-H2HXKAMQ.js";
4
+ import "../chunk-6TZNGFRM.js";
5
+ import "../chunk-VQQZAFRA.js";
6
6
  import "../chunk-6DXGZZA4.js";
7
- import "../chunk-SKSKC747.js";
7
+ import "../chunk-J5BTCP6T.js";
8
8
  export {
9
9
  createOAuthProtectedResourceMetadataHandler
10
10
  };
@@ -46,16 +46,29 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
46
46
  function isLogLevel(value) {
47
47
  return typeof value === "string" && value in LEVEL_RANK;
48
48
  }
49
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
49
50
  function readEnvLevel() {
50
51
  try {
51
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
52
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
52
53
  const normalized = raw?.trim().toLowerCase();
53
54
  return isLogLevel(normalized) ? normalized : void 0;
54
55
  } catch {
55
56
  return void 0;
56
57
  }
57
58
  }
58
- var currentLevel = readEnvLevel() ?? "silent";
59
+ var currentLevel = readEnvLevel() ?? "debug";
60
+ function setLogLevel(level) {
61
+ currentLevel = level;
62
+ }
63
+ function parseLogLevel(raw) {
64
+ const normalized = raw?.trim().toLowerCase();
65
+ return isLogLevel(normalized) ? normalized : void 0;
66
+ }
67
+ function applyLogLevelFromEnv(raw) {
68
+ const level = parseLogLevel(raw);
69
+ if (level)
70
+ setLogLevel(level);
71
+ }
59
72
  function enabled(level) {
60
73
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
61
74
  }
@@ -115,7 +128,7 @@ function resolveMetricsConfig(config = true) {
115
128
  }
116
129
 
117
130
  // package.json
118
- var version = "0.16.0";
131
+ var version = "0.17.0";
119
132
 
120
133
  // src/metrics/otlp.ts
121
134
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -211,12 +224,28 @@ function readRuntimeEnv(name) {
211
224
  }
212
225
  return void 0;
213
226
  }
227
+ var cloudflareEnvPromise;
228
+ async function readCloudflareEnv(name) {
229
+ try {
230
+ const moduleSpecifier = "cloudflare:workers";
231
+ cloudflareEnvPromise ??= import(
232
+ /* @vite-ignore */
233
+ moduleSpecifier
234
+ ).then((m) => m.env).catch(() => void 0);
235
+ const env = await cloudflareEnvPromise;
236
+ const value = env?.[name];
237
+ return typeof value === "string" && value ? value : void 0;
238
+ } catch {
239
+ return void 0;
240
+ }
241
+ }
214
242
  function probeWaitUntil() {
215
243
  const fn = globalThis.EdgeRuntime?.waitUntil;
216
244
  return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
217
245
  }
218
246
  function createMetricsRecorder(ctx, deps = {}) {
219
247
  const { config, server } = ctx;
248
+ applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
220
249
  if (!config.enabled)
221
250
  return NOOP_RECORDER;
222
251
  const doFetch = deps.fetch ?? globalThis.fetch;
@@ -225,14 +254,23 @@ function createMetricsRecorder(ctx, deps = {}) {
225
254
  return NOOP_RECORDER;
226
255
  }
227
256
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
228
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
229
- if (usesLovableEndpoint && !apiKey) {
230
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
231
- return NOOP_RECORDER;
232
- }
233
257
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
234
258
  const buffer = [];
235
259
  let timer;
260
+ let lazyLogLevelApplied = false;
261
+ const applyLazyLogLevel = async () => {
262
+ if (lazyLogLevelApplied)
263
+ return;
264
+ lazyLogLevelApplied = true;
265
+ applyLogLevelFromEnv(await readCloudflareEnv(LOG_LEVEL_ENV_VAR));
266
+ };
267
+ let apiKey;
268
+ const resolveApiKey = async () => {
269
+ if (apiKey)
270
+ return apiKey;
271
+ apiKey = (deps.getApiKey ? deps.getApiKey() : readRuntimeEnv(config.apiKeyEnvVar)) ?? await readCloudflareEnv(config.apiKeyEnvVar);
272
+ return apiKey;
273
+ };
236
274
  const schedule = (p) => {
237
275
  if (waitUntil) {
238
276
  try {
@@ -245,21 +283,33 @@ function createMetricsRecorder(ctx, deps = {}) {
245
283
  void p.catch(() => {
246
284
  });
247
285
  };
248
- const headers = {};
286
+ const baseHeaders = {};
249
287
  if (!usesLovableEndpoint) {
250
288
  for (const [key, value] of Object.entries(config.headers)) {
251
289
  if (key.toLowerCase() !== "content-type")
252
- headers[key] = value;
290
+ baseHeaders[key] = value;
253
291
  }
254
292
  }
255
- headers["content-type"] = "application/json";
256
- if (apiKey)
257
- headers.authorization = `Bearer ${apiKey}`;
293
+ baseHeaders["content-type"] = "application/json";
258
294
  const flush = async () => {
295
+ void applyLazyLogLevel();
259
296
  if (buffer.length === 0)
260
297
  return;
261
298
  const records = buffer.splice(0, buffer.length);
262
299
  const dropped = records.length;
300
+ const headers = { ...baseHeaders };
301
+ if (usesLovableEndpoint) {
302
+ const key = await resolveApiKey();
303
+ if (!key) {
304
+ log.warn("metrics.disabled_no_api_key", {
305
+ envVar: config.apiKeyEnvVar,
306
+ endpoint: config.endpoint,
307
+ dropped
308
+ });
309
+ return;
310
+ }
311
+ headers.authorization = `Bearer ${key}`;
312
+ }
263
313
  try {
264
314
  const res = await doFetch(config.endpoint, {
265
315
  method: "POST",
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  createInvokeToolHandler
3
- } from "../../chunk-W2EZWPJ5.js";
3
+ } from "../../chunk-WYXIX7XF.js";
4
4
  import {
5
5
  createListToolsHandler
6
- } from "../../chunk-I5CAQUQI.js";
6
+ } from "../../chunk-FW6YL5C5.js";
7
7
  import "../../chunk-MA5H6PSF.js";
8
- import "../../chunk-H6BKTNJY.js";
9
- import "../../chunk-DCWYK4CA.js";
8
+ import "../../chunk-6TZNGFRM.js";
9
+ import "../../chunk-VQQZAFRA.js";
10
10
  import "../../chunk-6DXGZZA4.js";
11
- import "../../chunk-SKSKC747.js";
11
+ import "../../chunk-J5BTCP6T.js";
12
12
  export {
13
13
  createInvokeToolHandler,
14
14
  createListToolsHandler
@@ -100,16 +100,29 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
100
100
  function isLogLevel(value) {
101
101
  return typeof value === "string" && value in LEVEL_RANK;
102
102
  }
103
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
103
104
  function readEnvLevel() {
104
105
  try {
105
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
106
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
106
107
  const normalized = raw?.trim().toLowerCase();
107
108
  return isLogLevel(normalized) ? normalized : void 0;
108
109
  } catch {
109
110
  return void 0;
110
111
  }
111
112
  }
112
- var currentLevel = readEnvLevel() ?? "silent";
113
+ var currentLevel = readEnvLevel() ?? "debug";
114
+ function setLogLevel(level) {
115
+ currentLevel = level;
116
+ }
117
+ function parseLogLevel(raw) {
118
+ const normalized = raw?.trim().toLowerCase();
119
+ return isLogLevel(normalized) ? normalized : void 0;
120
+ }
121
+ function applyLogLevelFromEnv(raw) {
122
+ const level = parseLogLevel(raw);
123
+ if (level)
124
+ setLogLevel(level);
125
+ }
113
126
  function enabled(level) {
114
127
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
115
128
  }
@@ -169,7 +182,7 @@ function resolveMetricsConfig(config = true) {
169
182
  }
170
183
 
171
184
  // package.json
172
- var version = "0.16.0";
185
+ var version = "0.17.0";
173
186
 
174
187
  // src/metrics/otlp.ts
175
188
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -265,12 +278,28 @@ function readRuntimeEnv(name) {
265
278
  }
266
279
  return void 0;
267
280
  }
281
+ var cloudflareEnvPromise;
282
+ async function readCloudflareEnv(name) {
283
+ try {
284
+ const moduleSpecifier = "cloudflare:workers";
285
+ cloudflareEnvPromise ??= import(
286
+ /* @vite-ignore */
287
+ moduleSpecifier
288
+ ).then((m) => m.env).catch(() => void 0);
289
+ const env = await cloudflareEnvPromise;
290
+ const value = env?.[name];
291
+ return typeof value === "string" && value ? value : void 0;
292
+ } catch {
293
+ return void 0;
294
+ }
295
+ }
268
296
  function probeWaitUntil() {
269
297
  const fn = globalThis.EdgeRuntime?.waitUntil;
270
298
  return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
271
299
  }
272
300
  function createMetricsRecorder(ctx, deps = {}) {
273
301
  const { config, server } = ctx;
302
+ applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
274
303
  if (!config.enabled)
275
304
  return NOOP_RECORDER;
276
305
  const doFetch = deps.fetch ?? globalThis.fetch;
@@ -279,14 +308,23 @@ function createMetricsRecorder(ctx, deps = {}) {
279
308
  return NOOP_RECORDER;
280
309
  }
281
310
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
282
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
283
- if (usesLovableEndpoint && !apiKey) {
284
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
285
- return NOOP_RECORDER;
286
- }
287
311
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
288
312
  const buffer = [];
289
313
  let timer;
314
+ let lazyLogLevelApplied = false;
315
+ const applyLazyLogLevel = async () => {
316
+ if (lazyLogLevelApplied)
317
+ return;
318
+ lazyLogLevelApplied = true;
319
+ applyLogLevelFromEnv(await readCloudflareEnv(LOG_LEVEL_ENV_VAR));
320
+ };
321
+ let apiKey;
322
+ const resolveApiKey = async () => {
323
+ if (apiKey)
324
+ return apiKey;
325
+ apiKey = (deps.getApiKey ? deps.getApiKey() : readRuntimeEnv(config.apiKeyEnvVar)) ?? await readCloudflareEnv(config.apiKeyEnvVar);
326
+ return apiKey;
327
+ };
290
328
  const schedule = (p) => {
291
329
  if (waitUntil) {
292
330
  try {
@@ -299,21 +337,33 @@ function createMetricsRecorder(ctx, deps = {}) {
299
337
  void p.catch(() => {
300
338
  });
301
339
  };
302
- const headers = {};
340
+ const baseHeaders = {};
303
341
  if (!usesLovableEndpoint) {
304
342
  for (const [key, value] of Object.entries(config.headers)) {
305
343
  if (key.toLowerCase() !== "content-type")
306
- headers[key] = value;
344
+ baseHeaders[key] = value;
307
345
  }
308
346
  }
309
- headers["content-type"] = "application/json";
310
- if (apiKey)
311
- headers.authorization = `Bearer ${apiKey}`;
347
+ baseHeaders["content-type"] = "application/json";
312
348
  const flush = async () => {
349
+ void applyLazyLogLevel();
313
350
  if (buffer.length === 0)
314
351
  return;
315
352
  const records = buffer.splice(0, buffer.length);
316
353
  const dropped = records.length;
354
+ const headers = { ...baseHeaders };
355
+ if (usesLovableEndpoint) {
356
+ const key = await resolveApiKey();
357
+ if (!key) {
358
+ log.warn("metrics.disabled_no_api_key", {
359
+ envVar: config.apiKeyEnvVar,
360
+ endpoint: config.endpoint,
361
+ dropped
362
+ });
363
+ return;
364
+ }
365
+ headers.authorization = `Bearer ${key}`;
366
+ }
317
367
  try {
318
368
  const res = await doFetch(config.endpoint, {
319
369
  method: "POST",
@@ -3,24 +3,24 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-EZQVUNXB.js";
6
+ } from "../../chunk-EL6YNP2R.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-T24Z753F.js";
9
+ } from "../../chunk-H2HXKAMQ.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-W2EZWPJ5.js";
12
+ } from "../../chunk-WYXIX7XF.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-I5CAQUQI.js";
15
+ } from "../../chunk-FW6YL5C5.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
17
  import {
18
18
  assertResourcePathShape,
19
19
  createRecorderForRuntime
20
- } from "../../chunk-H6BKTNJY.js";
20
+ } from "../../chunk-6TZNGFRM.js";
21
21
  import {
22
22
  trimTrailingSlash
23
- } from "../../chunk-DCWYK4CA.js";
23
+ } from "../../chunk-VQQZAFRA.js";
24
24
  import {
25
25
  OAUTH_PROTECTED_RESOURCE_METADATA_PATH
26
26
  } from "../../chunk-6DXGZZA4.js";
@@ -28,7 +28,7 @@ import {
28
28
  FUNCTIONS_MOUNT_PREFIX,
29
29
  assertFunctionName
30
30
  } from "../../chunk-XQWJN6DC.js";
31
- import "../../chunk-SKSKC747.js";
31
+ import "../../chunk-J5BTCP6T.js";
32
32
 
33
33
  // src/stacks/supabase/handler.ts
34
34
  function deriveResourcePath(options) {
@@ -33,7 +33,7 @@ var import_node_fs = require("fs");
33
33
  var import_node_path = require("path");
34
34
 
35
35
  // package.json
36
- var version = "0.16.0";
36
+ var version = "0.17.0";
37
37
 
38
38
  // src/core/fs-errors.ts
39
39
  function isFileMissing(err) {
@@ -7,7 +7,7 @@ import {
7
7
  } from "../../chunk-XQWJN6DC.js";
8
8
  import {
9
9
  version
10
- } from "../../chunk-SKSKC747.js";
10
+ } from "../../chunk-J5BTCP6T.js";
11
11
 
12
12
  // src/stacks/supabase/vite.ts
13
13
  import { resolve as resolve2, sep as sep2 } from "path";
@@ -71,16 +71,29 @@ var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
71
71
  function isLogLevel(value) {
72
72
  return typeof value === "string" && value in LEVEL_RANK;
73
73
  }
74
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
74
75
  function readEnvLevel() {
75
76
  try {
76
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
77
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
77
78
  const normalized = raw?.trim().toLowerCase();
78
79
  return isLogLevel(normalized) ? normalized : void 0;
79
80
  } catch {
80
81
  return void 0;
81
82
  }
82
83
  }
83
- var currentLevel = readEnvLevel() ?? "silent";
84
+ var currentLevel = readEnvLevel() ?? "debug";
85
+ function setLogLevel(level) {
86
+ currentLevel = level;
87
+ }
88
+ function parseLogLevel(raw) {
89
+ const normalized = raw?.trim().toLowerCase();
90
+ return isLogLevel(normalized) ? normalized : void 0;
91
+ }
92
+ function applyLogLevelFromEnv(raw) {
93
+ const level = parseLogLevel(raw);
94
+ if (level)
95
+ setLogLevel(level);
96
+ }
84
97
  function enabled(level) {
85
98
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
86
99
  }
@@ -140,7 +153,7 @@ function resolveMetricsConfig(config = true) {
140
153
  }
141
154
 
142
155
  // package.json
143
- var version = "0.16.0";
156
+ var version = "0.17.0";
144
157
 
145
158
  // src/metrics/otlp.ts
146
159
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -236,12 +249,28 @@ function readRuntimeEnv(name) {
236
249
  }
237
250
  return void 0;
238
251
  }
252
+ var cloudflareEnvPromise;
253
+ async function readCloudflareEnv(name) {
254
+ try {
255
+ const moduleSpecifier = "cloudflare:workers";
256
+ cloudflareEnvPromise ??= import(
257
+ /* @vite-ignore */
258
+ moduleSpecifier
259
+ ).then((m) => m.env).catch(() => void 0);
260
+ const env = await cloudflareEnvPromise;
261
+ const value = env?.[name];
262
+ return typeof value === "string" && value ? value : void 0;
263
+ } catch {
264
+ return void 0;
265
+ }
266
+ }
239
267
  function probeWaitUntil() {
240
268
  const fn = globalThis.EdgeRuntime?.waitUntil;
241
269
  return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
242
270
  }
243
271
  function createMetricsRecorder(ctx, deps = {}) {
244
272
  const { config, server } = ctx;
273
+ applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
245
274
  if (!config.enabled)
246
275
  return NOOP_RECORDER;
247
276
  const doFetch = deps.fetch ?? globalThis.fetch;
@@ -250,14 +279,23 @@ function createMetricsRecorder(ctx, deps = {}) {
250
279
  return NOOP_RECORDER;
251
280
  }
252
281
  const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
253
- const apiKey = usesLovableEndpoint ? (deps.getApiKey ?? (() => readRuntimeEnv(config.apiKeyEnvVar)))() : void 0;
254
- if (usesLovableEndpoint && !apiKey) {
255
- log.warn("metrics.disabled_no_api_key", { envVar: config.apiKeyEnvVar, endpoint: config.endpoint });
256
- return NOOP_RECORDER;
257
- }
258
282
  const waitUntil = deps.waitUntil ?? probeWaitUntil();
259
283
  const buffer = [];
260
284
  let timer;
285
+ let lazyLogLevelApplied = false;
286
+ const applyLazyLogLevel = async () => {
287
+ if (lazyLogLevelApplied)
288
+ return;
289
+ lazyLogLevelApplied = true;
290
+ applyLogLevelFromEnv(await readCloudflareEnv(LOG_LEVEL_ENV_VAR));
291
+ };
292
+ let apiKey;
293
+ const resolveApiKey = async () => {
294
+ if (apiKey)
295
+ return apiKey;
296
+ apiKey = (deps.getApiKey ? deps.getApiKey() : readRuntimeEnv(config.apiKeyEnvVar)) ?? await readCloudflareEnv(config.apiKeyEnvVar);
297
+ return apiKey;
298
+ };
261
299
  const schedule = (p) => {
262
300
  if (waitUntil) {
263
301
  try {
@@ -270,21 +308,33 @@ function createMetricsRecorder(ctx, deps = {}) {
270
308
  void p.catch(() => {
271
309
  });
272
310
  };
273
- const headers = {};
311
+ const baseHeaders = {};
274
312
  if (!usesLovableEndpoint) {
275
313
  for (const [key, value] of Object.entries(config.headers)) {
276
314
  if (key.toLowerCase() !== "content-type")
277
- headers[key] = value;
315
+ baseHeaders[key] = value;
278
316
  }
279
317
  }
280
- headers["content-type"] = "application/json";
281
- if (apiKey)
282
- headers.authorization = `Bearer ${apiKey}`;
318
+ baseHeaders["content-type"] = "application/json";
283
319
  const flush = async () => {
320
+ void applyLazyLogLevel();
284
321
  if (buffer.length === 0)
285
322
  return;
286
323
  const records = buffer.splice(0, buffer.length);
287
324
  const dropped = records.length;
325
+ const headers = { ...baseHeaders };
326
+ if (usesLovableEndpoint) {
327
+ const key = await resolveApiKey();
328
+ if (!key) {
329
+ log.warn("metrics.disabled_no_api_key", {
330
+ envVar: config.apiKeyEnvVar,
331
+ endpoint: config.endpoint,
332
+ dropped
333
+ });
334
+ return;
335
+ }
336
+ headers.authorization = `Bearer ${key}`;
337
+ }
288
338
  try {
289
339
  const res = await doFetch(config.endpoint, {
290
340
  method: "POST",
@@ -3,21 +3,21 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-EZQVUNXB.js";
6
+ } from "../../chunk-EL6YNP2R.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-T24Z753F.js";
9
+ } from "../../chunk-H2HXKAMQ.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-W2EZWPJ5.js";
12
+ } from "../../chunk-WYXIX7XF.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-I5CAQUQI.js";
15
+ } from "../../chunk-FW6YL5C5.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
- import "../../chunk-H6BKTNJY.js";
18
- import "../../chunk-DCWYK4CA.js";
17
+ import "../../chunk-6TZNGFRM.js";
18
+ import "../../chunk-VQQZAFRA.js";
19
19
  import "../../chunk-6DXGZZA4.js";
20
- import "../../chunk-SKSKC747.js";
20
+ import "../../chunk-J5BTCP6T.js";
21
21
 
22
22
  // src/stacks/tanstack/handlers.ts
23
23
  function forwarded(request, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lovable.dev/mcp-js",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Author MCP servers for Lovable apps. Declare tools with defineTool, register them in defineMcp, and a framework adapter (TanStack or Supabase Edge Functions) emits the route(s) at build time.",
5
5
  "type": "module",
6
6
  "repository": {