@lovable.dev/mcp-js 0.17.0 → 0.20.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.
Files changed (37) hide show
  1. package/dist/{recorder-qlzUKFxG.d.ts → base-C9rhAHZ0.d.ts} +3 -4
  2. package/dist/{chunk-FW6YL5C5.js → chunk-7JJEPFSO.js} +8 -8
  3. package/dist/{chunk-H2HXKAMQ.js → chunk-DUNDNXK5.js} +2 -2
  4. package/dist/{chunk-6TZNGFRM.js → chunk-EPEEEI3C.js} +121 -136
  5. package/dist/{chunk-J5BTCP6T.js → chunk-FTTVLHNN.js} +1 -1
  6. package/dist/{chunk-VQQZAFRA.js → chunk-H37EB22A.js} +2 -10
  7. package/dist/{chunk-WYXIX7XF.js → chunk-WKIXRW46.js} +11 -12
  8. package/dist/{chunk-EL6YNP2R.js → chunk-WW7NRRCJ.js} +13 -14
  9. package/dist/cli/extract-manifest.cjs +1 -1
  10. package/dist/cli/extract-manifest.js +4 -4
  11. package/dist/index.cjs +1 -7
  12. package/dist/index.d.cts +2 -2
  13. package/dist/index.d.ts +2 -2
  14. package/dist/index.js +1 -1
  15. package/dist/protocols/mcp/index.cjs +16 -272
  16. package/dist/protocols/mcp/index.d.cts +6 -5
  17. package/dist/protocols/mcp/index.d.ts +6 -5
  18. package/dist/protocols/mcp/index.js +4 -4
  19. package/dist/protocols/oauth-metadata.d.cts +1 -1
  20. package/dist/protocols/oauth-metadata.d.ts +1 -1
  21. package/dist/protocols/oauth-metadata.js +4 -4
  22. package/dist/protocols/rest/index.cjs +21 -277
  23. package/dist/protocols/rest/index.d.cts +6 -6
  24. package/dist/protocols/rest/index.d.ts +6 -6
  25. package/dist/protocols/rest/index.js +5 -5
  26. package/dist/stacks/supabase/index.cjs +178 -201
  27. package/dist/stacks/supabase/index.d.cts +1 -1
  28. package/dist/stacks/supabase/index.d.ts +1 -1
  29. package/dist/stacks/supabase/index.js +14 -14
  30. package/dist/stacks/supabase/vite.cjs +1 -1
  31. package/dist/stacks/supabase/vite.js +1 -1
  32. package/dist/stacks/tanstack/index.cjs +187 -209
  33. package/dist/stacks/tanstack/index.d.cts +1 -1
  34. package/dist/stacks/tanstack/index.d.ts +1 -1
  35. package/dist/stacks/tanstack/index.js +13 -10
  36. package/dist/{types-COY42xux.d.ts → types-CPkhCRxc.d.ts} +3 -3
  37. package/package.json +1 -1
@@ -95,6 +95,32 @@ function firstForwardedValue(request, header) {
95
95
  return value ? value : void 0;
96
96
  }
97
97
 
98
+ // src/metrics/config.ts
99
+ var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
100
+ var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
101
+ function assertMetricsEndpoint(endpoint) {
102
+ let url;
103
+ try {
104
+ url = new URL(endpoint);
105
+ } catch {
106
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
107
+ }
108
+ if (url.protocol !== "https:" && url.protocol !== "http:") {
109
+ throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
110
+ }
111
+ }
112
+ function resolveMetricsConfig(config = true) {
113
+ const options = typeof config === "boolean" ? { enabled: config } : config;
114
+ const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
115
+ assertMetricsEndpoint(endpoint);
116
+ return Object.freeze({
117
+ enabled: options.enabled ?? true,
118
+ endpoint,
119
+ headers: options.headers ?? {},
120
+ apiKeyEnvVar: METRICS_API_KEY_ENV_VAR
121
+ });
122
+ }
123
+
98
124
  // src/core/logger.ts
99
125
  var LEVEL_RANK = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
100
126
  function isLogLevel(value) {
@@ -119,9 +145,7 @@ function parseLogLevel(raw) {
119
145
  return isLogLevel(normalized) ? normalized : void 0;
120
146
  }
121
147
  function applyLogLevelFromEnv(raw) {
122
- const level = parseLogLevel(raw);
123
- if (level)
124
- setLogLevel(level);
148
+ setLogLevel(parseLogLevel(raw) ?? "debug");
125
149
  }
126
150
  function enabled(level) {
127
151
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
@@ -149,40 +173,8 @@ function describeError(err) {
149
173
  return { value: String(err) };
150
174
  }
151
175
 
152
- // src/metrics/config.ts
153
- var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
154
- var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
155
- var METRICS_SAMPLE_RATE = 1;
156
- var METRICS_FLUSH_INTERVAL_MS = 5e3;
157
- var METRICS_MAX_BATCH_SIZE = 50;
158
- function assertMetricsEndpoint(endpoint) {
159
- let url;
160
- try {
161
- url = new URL(endpoint);
162
- } catch {
163
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
164
- }
165
- if (url.protocol !== "https:" && url.protocol !== "http:") {
166
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
167
- }
168
- }
169
- function resolveMetricsConfig(config = true) {
170
- const options = typeof config === "boolean" ? { enabled: config } : config;
171
- const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
172
- assertMetricsEndpoint(endpoint);
173
- return Object.freeze({
174
- enabled: options.enabled ?? true,
175
- endpoint,
176
- headers: options.headers ?? {},
177
- apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
178
- sampleRate: METRICS_SAMPLE_RATE,
179
- flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
180
- maxBatchSize: METRICS_MAX_BATCH_SIZE
181
- });
182
- }
183
-
184
176
  // package.json
185
- var version = "0.17.0";
177
+ var version = "0.20.0";
186
178
 
187
179
  // src/metrics/otlp.ts
188
180
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -207,6 +199,7 @@ function toLogRecord(rec) {
207
199
  attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
208
200
  if (rec.resBytes !== void 0)
209
201
  attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
202
+ attributes.push(strAttr("mcp.stack", rec.stack));
210
203
  return {
211
204
  timeUnixNano: rec.timeUnixNano,
212
205
  observedTimeUnixNano: rec.timeUnixNano,
@@ -243,164 +236,148 @@ function nowUnixNano() {
243
236
  return `${Date.now()}000000`;
244
237
  }
245
238
 
246
- // src/metrics/recorder.ts
239
+ // src/metrics/impl/base.ts
247
240
  function nowMs() {
248
241
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
249
242
  }
250
- function reportInvocation(recorder, ev) {
251
- log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
252
- recorder.record(ev);
253
- }
254
- var NOOP_RECORDER = {
255
- record() {
256
- },
257
- async flush() {
258
- }
259
- };
243
+ var NOOP_RECORDER = { async emit() {
244
+ } };
260
245
  function createNoopRecorder() {
261
246
  return NOOP_RECORDER;
262
247
  }
263
- function readRuntimeEnv(name) {
264
- try {
265
- const denoEnv = globalThis.Deno?.env;
266
- const value = denoEnv?.get?.(name);
267
- if (value)
268
- return value;
269
- } catch {
270
- }
271
- try {
272
- if (typeof process !== "undefined") {
273
- const value = process.env?.[name];
274
- if (value)
275
- return value;
276
- }
277
- } catch {
278
- }
279
- return void 0;
280
- }
281
- var cloudflareEnvPromise;
282
- async function readCloudflareEnv(name) {
248
+ function readProcessEnv(name) {
283
249
  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;
250
+ return typeof process !== "undefined" ? process.env?.[name] || void 0 : void 0;
292
251
  } catch {
293
252
  return void 0;
294
253
  }
295
254
  }
296
- function probeWaitUntil() {
297
- const fn = globalThis.EdgeRuntime?.waitUntil;
298
- return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
299
- }
300
- function createMetricsRecorder(ctx, deps = {}) {
301
- const { config, server } = ctx;
302
- applyLogLevelFromEnv(readRuntimeEnv(LOG_LEVEL_ENV_VAR));
303
- if (!config.enabled)
304
- return NOOP_RECORDER;
305
- const doFetch = deps.fetch ?? globalThis.fetch;
306
- if (!doFetch) {
307
- log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
308
- return NOOP_RECORDER;
309
- }
310
- const usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
311
- const waitUntil = deps.waitUntil ?? probeWaitUntil();
312
- const buffer = [];
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
- };
328
- const schedule = (p) => {
329
- if (waitUntil) {
330
- try {
331
- waitUntil(p);
332
- return;
333
- } catch (err) {
334
- log.warn("metrics.wait_until_failed", describeError(err));
255
+ var BaseMetricRecorder = class {
256
+ constructor(config, server, deps = {}) {
257
+ this.config = config;
258
+ this.server = server;
259
+ this.deps = deps;
260
+ this.doFetch = deps.fetch ?? (typeof globalThis.fetch === "function" ? globalThis.fetch.bind(globalThis) : void 0);
261
+ this.usesLovableEndpoint = config.endpoint === DEFAULT_METRICS_ENDPOINT;
262
+ const headers = {};
263
+ if (!this.usesLovableEndpoint) {
264
+ for (const [key, value] of Object.entries(config.headers)) {
265
+ if (key.toLowerCase() !== "content-type")
266
+ headers[key] = value;
335
267
  }
336
268
  }
337
- void p.catch(() => {
338
- });
339
- };
340
- const baseHeaders = {};
341
- if (!usesLovableEndpoint) {
342
- for (const [key, value] of Object.entries(config.headers)) {
343
- if (key.toLowerCase() !== "content-type")
344
- baseHeaders[key] = value;
345
- }
269
+ headers["content-type"] = "application/json";
270
+ this.baseHeaders = headers;
346
271
  }
347
- baseHeaders["content-type"] = "application/json";
348
- const flush = async () => {
349
- void applyLazyLogLevel();
350
- if (buffer.length === 0)
272
+ doFetch;
273
+ usesLovableEndpoint;
274
+ baseHeaders;
275
+ apiKey;
276
+ lazyLogLevelApplied = false;
277
+ async emit(ev) {
278
+ await this.applyLazyLogLevel();
279
+ log.info("tool.invoked", {
280
+ tool: ev.tool,
281
+ method: ev.method,
282
+ outcome: ev.outcome,
283
+ durationMs: ev.durationMs,
284
+ stack: this.stack
285
+ });
286
+ if (!this.config.enabled)
287
+ return;
288
+ if (!this.doFetch) {
289
+ log.warn("metrics.disabled_no_fetch", { endpoint: this.config.endpoint });
351
290
  return;
352
- const records = buffer.splice(0, buffer.length);
353
- const dropped = records.length;
354
- const headers = { ...baseHeaders };
355
- if (usesLovableEndpoint) {
356
- const key = await resolveApiKey();
291
+ }
292
+ const headers = { ...this.baseHeaders };
293
+ if (this.usesLovableEndpoint) {
294
+ const key = await this.resolveApiKey();
357
295
  if (!key) {
358
- log.warn("metrics.disabled_no_api_key", {
359
- envVar: config.apiKeyEnvVar,
360
- endpoint: config.endpoint,
361
- dropped
362
- });
296
+ log.warn("metrics.disabled_no_api_key", { envVar: this.config.apiKeyEnvVar, endpoint: this.config.endpoint });
363
297
  return;
364
298
  }
365
299
  headers.authorization = `Bearer ${key}`;
366
300
  }
301
+ const body = buildLogsPayload([{ ...ev, timeUnixNano: nowUnixNano(), stack: this.stack }], this.server);
367
302
  try {
368
- const res = await doFetch(config.endpoint, {
369
- method: "POST",
370
- headers,
371
- body: buildLogsPayload(records, server),
372
- keepalive: true
373
- });
374
- if (!res.ok) {
375
- log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
376
- }
303
+ const res = await this.doFetch(this.config.endpoint, { method: "POST", headers, body, keepalive: true });
304
+ if (!res.ok)
305
+ log.warn("metrics.rejected", { status: res.status, endpoint: this.config.endpoint });
377
306
  } catch (err) {
378
- log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
307
+ log.warn("metrics.failed", { ...describeError(err), endpoint: this.config.endpoint });
379
308
  }
380
- };
381
- const ensureTimer = () => {
382
- if (timer !== void 0)
309
+ }
310
+ // Cache only a successful resolution so a miss is retried on the next emit (the
311
+ // Cloudflare binding may not be readable on the very first attempt in an isolate).
312
+ async resolveApiKey() {
313
+ if (this.apiKey)
314
+ return this.apiKey;
315
+ this.apiKey = this.deps.getApiKey ? this.deps.getApiKey() : await this.readEnv(this.config.apiKeyEnvVar);
316
+ return this.apiKey;
317
+ }
318
+ async applyLazyLogLevel() {
319
+ if (this.lazyLogLevelApplied)
383
320
  return;
384
- timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
385
- timer.unref?.();
386
- };
387
- return {
388
- record(ev) {
389
- if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
390
- return;
391
- buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
392
- ensureTimer();
393
- if (buffer.length >= config.maxBatchSize)
394
- schedule(flush());
395
- },
396
- flush
397
- };
321
+ this.lazyLogLevelApplied = true;
322
+ applyLogLevelFromEnv(await this.readEnv(LOG_LEVEL_ENV_VAR));
323
+ }
324
+ };
325
+
326
+ // src/metrics/impl/cloudflare.ts
327
+ var cloudflareEnvPromise;
328
+ async function readCloudflareEnv(name) {
329
+ try {
330
+ const moduleSpecifier = "cloudflare:workers";
331
+ cloudflareEnvPromise ??= import(
332
+ /* @vite-ignore */
333
+ moduleSpecifier
334
+ ).then((m) => m.env).catch((err) => {
335
+ log.debug("metrics.cloudflare_env_import_failed", describeError(err));
336
+ return void 0;
337
+ });
338
+ const env = await cloudflareEnvPromise;
339
+ const raw = env?.[name];
340
+ const value = typeof raw === "string" && raw ? raw : void 0;
341
+ log.debug("metrics.read_cloudflare_env", { name, hasEnvBinding: !!env, found: value !== void 0 });
342
+ return value;
343
+ } catch (err) {
344
+ log.debug("metrics.read_cloudflare_env_error", { name, ...describeError(err) });
345
+ return void 0;
346
+ }
347
+ }
348
+ var TanStackMetricRecorder = class extends BaseMetricRecorder {
349
+ stack = "tanstack";
350
+ async readEnv(name) {
351
+ return readProcessEnv(name) ?? await readCloudflareEnv(name);
352
+ }
353
+ };
354
+
355
+ // src/metrics/impl/supabase.ts
356
+ function readDenoEnv(name) {
357
+ try {
358
+ const denoEnv = globalThis.Deno?.env;
359
+ const value = denoEnv?.get?.(name) || void 0;
360
+ log.debug("metrics.read_deno_env", { name, hasDenoEnv: !!denoEnv, found: !!value });
361
+ return value;
362
+ } catch (err) {
363
+ log.debug("metrics.read_deno_env_error", { name, ...describeError(err) });
364
+ return void 0;
365
+ }
398
366
  }
399
- function createRecorderForRuntime(mcp) {
367
+ var SupabaseMetricRecorder = class extends BaseMetricRecorder {
368
+ stack = "supabase";
369
+ async readEnv(name) {
370
+ return readDenoEnv(name) ?? readProcessEnv(name);
371
+ }
372
+ };
373
+
374
+ // src/metrics/recorder.ts
375
+ function createRecorderForRuntime(mcp, opts) {
400
376
  const config = resolveMetricsConfig(mcp.metrics);
377
+ const server = { name: mcp.name, version: mcp.version };
401
378
  if (!config.enabled)
402
379
  return createNoopRecorder();
403
- return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
380
+ return opts.stack === "tanstack" ? new TanStackMetricRecorder(config, server) : new SupabaseMetricRecorder(config, server);
404
381
  }
405
382
 
406
383
  // src/protocols/mcp/protocol.ts
@@ -799,10 +776,10 @@ function assertRequiredScopes(auth, context) {
799
776
  throw new OAuthTokenError(403, "insufficient_scope", "Additional OAuth scope is required");
800
777
  }
801
778
  }
802
- function createRequestAuthorizer(mcp, options = {}, recorder) {
779
+ function createRequestAuthorizer(mcp, options = {}) {
803
780
  const runtime = getOAuthRuntime(mcp, options);
804
781
  return {
805
- async authorize(request) {
782
+ async authorize(request, recorder) {
806
783
  if (runtime.kind === "unconfigured")
807
784
  return { ok: true };
808
785
  const startedAt = nowMs();
@@ -818,7 +795,7 @@ function createRequestAuthorizer(mcp, options = {}, recorder) {
818
795
  } catch (err) {
819
796
  if (err instanceof OAuthConfigurationError) {
820
797
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
821
- recorder?.record({
798
+ await recorder?.emit({
822
799
  tool: null,
823
800
  method: "authorize",
824
801
  outcome: "auth_config_error",
@@ -929,7 +906,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
929
906
  try {
930
907
  result = await tool.handler(args, new ToolContext(auth));
931
908
  } catch {
932
- reportInvocation(recorder, {
909
+ await recorder.emit({
933
910
  tool: tool.name,
934
911
  method: "tools/call",
935
912
  outcome: "handler_error",
@@ -938,7 +915,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
938
915
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
939
916
  }
940
917
  if (result == null) {
941
- reportInvocation(recorder, {
918
+ await recorder.emit({
942
919
  tool: tool.name,
943
920
  method: "tools/call",
944
921
  outcome: "handler_error",
@@ -946,7 +923,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
946
923
  });
947
924
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
948
925
  }
949
- reportInvocation(recorder, {
926
+ await recorder.emit({
950
927
  tool: tool.name,
951
928
  method: "tools/call",
952
929
  outcome: result.isError ? "tool_error" : "ok",
@@ -955,10 +932,10 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
955
932
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
956
933
  };
957
934
  }
958
- function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
959
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
960
- const handle = async (request) => {
961
- const authResult = await authorizer.authorize(request);
935
+ function createMcpProtocolHandler(mcp, options = {}) {
936
+ const authorizer = createRequestAuthorizer(mcp, options);
937
+ const handle = async (request, recorder) => {
938
+ const authResult = await authorizer.authorize(request, recorder);
962
939
  if (!authResult.ok)
963
940
  return authResult.response;
964
941
  try {
@@ -985,7 +962,7 @@ function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderFo
985
962
  await server.connect(transport);
986
963
  return await transport.handleRequest(request);
987
964
  } catch (err) {
988
- recorder.record({ tool: null, method: "transport", outcome: "transport_error", durationMs: 0 });
965
+ await recorder.emit({ tool: null, method: "transport", outcome: "transport_error", durationMs: 0 });
989
966
  log.error("mcp.transport_error", { ...describeError(err), outcome: "500 internal error" });
990
967
  return Response.json(
991
968
  { jsonrpc: "2.0", id: null, error: { code: -32603, message: "internal error" } },
@@ -993,10 +970,10 @@ function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderFo
993
970
  );
994
971
  }
995
972
  };
996
- return async (request) => {
973
+ return async (request, recorder = createNoopRecorder()) => {
997
974
  if (request.method === "OPTIONS")
998
975
  return corsPreflightResponse("GET, POST, DELETE, OPTIONS");
999
- return withCors(await handle(request));
976
+ return withCors(await handle(request, recorder));
1000
977
  };
1001
978
  }
1002
979
 
@@ -1086,11 +1063,11 @@ function buildMcpListing(mcp) {
1086
1063
  }))
1087
1064
  };
1088
1065
  }
1089
- function createListToolsHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
1066
+ function createListToolsHandler(mcp, options = {}) {
1090
1067
  assertRestResourceBinding(mcp, options);
1091
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
1092
- const handle = async (request) => {
1093
- const authResult = await authorizer.authorize(request);
1068
+ const authorizer = createRequestAuthorizer(mcp, options);
1069
+ const handle = async (request, recorder) => {
1070
+ const authResult = await authorizer.authorize(request, recorder);
1094
1071
  if (!authResult.ok)
1095
1072
  return authResult.response;
1096
1073
  if (request.method !== "GET" && request.method !== "HEAD")
@@ -1098,10 +1075,10 @@ function createListToolsHandler(mcp, options = {}, recorder = createRecorderForR
1098
1075
  const response = Response.json(buildMcpListing(mcp));
1099
1076
  return request.method === "HEAD" ? headResponse(response) : response;
1100
1077
  };
1101
- return async (request) => {
1078
+ return async (request, recorder = createNoopRecorder()) => {
1102
1079
  if (request.method === "OPTIONS")
1103
1080
  return corsPreflightResponse("GET, HEAD, OPTIONS");
1104
- return withCors(await handle(request));
1081
+ return withCors(await handle(request, recorder));
1105
1082
  };
1106
1083
  }
1107
1084
 
@@ -1119,11 +1096,11 @@ function isEmptyArgs(value) {
1119
1096
  return false;
1120
1097
  return Object.keys(value).length === 0;
1121
1098
  }
1122
- function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
1099
+ function createInvokeToolHandler(mcp, options = {}) {
1123
1100
  assertRestResourceBinding(mcp, options);
1124
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
1125
- const handle = async (request, toolName) => {
1126
- const authResult = await authorizer.authorize(request);
1101
+ const authorizer = createRequestAuthorizer(mcp, options);
1102
+ const handle = async (request, toolName, recorder) => {
1103
+ const authResult = await authorizer.authorize(request, recorder);
1127
1104
  if (!authResult.ok)
1128
1105
  return authResult.response;
1129
1106
  if (request.method !== "POST")
@@ -1179,7 +1156,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1179
1156
  try {
1180
1157
  result = await tool.handler(args, new ToolContext(authResult.auth));
1181
1158
  } catch {
1182
- reportInvocation(recorder, {
1159
+ await recorder.emit({
1183
1160
  tool: tool.name,
1184
1161
  method: "tools/call",
1185
1162
  outcome: "handler_error",
@@ -1191,7 +1168,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1191
1168
  });
1192
1169
  }
1193
1170
  if (result == null) {
1194
- reportInvocation(recorder, {
1171
+ await recorder.emit({
1195
1172
  tool: tool.name,
1196
1173
  method: "tools/call",
1197
1174
  outcome: "handler_error",
@@ -1202,7 +1179,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1202
1179
  headers: JSON_HEADERS
1203
1180
  });
1204
1181
  }
1205
- reportInvocation(recorder, {
1182
+ await recorder.emit({
1206
1183
  tool: tool.name,
1207
1184
  method: "tools/call",
1208
1185
  outcome: result.isError ? "tool_error" : "ok",
@@ -1214,10 +1191,10 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1214
1191
  isError: result.isError
1215
1192
  });
1216
1193
  };
1217
- return async (request, toolName) => {
1194
+ return async (request, toolName, recorder = createNoopRecorder()) => {
1218
1195
  if (request.method === "OPTIONS")
1219
1196
  return corsPreflightResponse("POST, OPTIONS");
1220
- return withCors(await handle(request, toolName));
1197
+ return withCors(await handle(request, toolName, recorder));
1221
1198
  };
1222
1199
  }
1223
1200
 
@@ -1267,26 +1244,26 @@ function createSupabaseHandler(mcp, options = {}) {
1267
1244
  const servesOwnPrm = !(mcp.auth?.type === "oauth" && mcp.auth.protectedResourceMetadataUrl !== void 0);
1268
1245
  const metadataPath = resourcePath === void 0 || !servesOwnPrm ? void 0 : `${trimTrailingSlash(resourcePath)}${OAUTH_PROTECTED_RESOURCE_METADATA_PATH}`;
1269
1246
  const runtimeOptions = resourcePath === void 0 ? {} : { resourcePath, ...metadataPath ? { metadataPath } : {} };
1270
- const recorder = createRecorderForRuntime(mcp);
1271
- const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions, recorder);
1272
- const listToolsHandler = createListToolsHandler(mcp, runtimeOptions, recorder);
1273
- const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions, recorder);
1247
+ const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions);
1248
+ const listToolsHandler = createListToolsHandler(mcp, runtimeOptions);
1249
+ const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
1274
1250
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
1275
1251
  return async (request) => {
1276
1252
  const req = applyForwardedOrigin(request, {
1277
1253
  trustForwardedProto: true,
1278
1254
  trustForwardedHost: options.trustForwardedHost
1279
1255
  });
1256
+ const recorder = createRecorderForRuntime(mcp, { stack: "supabase" });
1280
1257
  const target = dispatchFor(new URL(req.url).pathname);
1281
1258
  switch (target.kind) {
1282
1259
  case "metadata":
1283
1260
  return metadataHandler(req);
1284
1261
  case "list-tools":
1285
- return listToolsHandler(req);
1262
+ return listToolsHandler(req, recorder);
1286
1263
  case "invoke-tool":
1287
- return invokeToolHandler(req, target.toolName);
1264
+ return invokeToolHandler(req, target.toolName, recorder);
1288
1265
  case "mcp":
1289
- return mcpHandler(req);
1266
+ return mcpHandler(req, recorder);
1290
1267
  }
1291
1268
  };
1292
1269
  }
@@ -1,4 +1,4 @@
1
- import { d as McpDefinition } from '../../types-COY42xux.js';
1
+ import { d as McpDefinition } from '../../types-CPkhCRxc.js';
2
2
  import 'zod';
3
3
 
4
4
  type SupabaseHandler = (request: Request) => Promise<Response>;
@@ -1,4 +1,4 @@
1
- import { d as McpDefinition } from '../../types-COY42xux.js';
1
+ import { d as McpDefinition } from '../../types-CPkhCRxc.js';
2
2
  import 'zod';
3
3
 
4
4
  type SupabaseHandler = (request: Request) => Promise<Response>;
@@ -3,24 +3,24 @@ import {
3
3
  } from "../../chunk-UQK5UO6C.js";
4
4
  import {
5
5
  createMcpProtocolHandler
6
- } from "../../chunk-EL6YNP2R.js";
6
+ } from "../../chunk-WW7NRRCJ.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-H2HXKAMQ.js";
9
+ } from "../../chunk-DUNDNXK5.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-WYXIX7XF.js";
12
+ } from "../../chunk-WKIXRW46.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-FW6YL5C5.js";
15
+ } from "../../chunk-7JJEPFSO.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
17
  import {
18
18
  assertResourcePathShape,
19
19
  createRecorderForRuntime
20
- } from "../../chunk-6TZNGFRM.js";
20
+ } from "../../chunk-EPEEEI3C.js";
21
21
  import {
22
22
  trimTrailingSlash
23
- } from "../../chunk-VQQZAFRA.js";
23
+ } from "../../chunk-H37EB22A.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-J5BTCP6T.js";
31
+ import "../../chunk-FTTVLHNN.js";
32
32
 
33
33
  // src/stacks/supabase/handler.ts
34
34
  function deriveResourcePath(options) {
@@ -66,26 +66,26 @@ function createSupabaseHandler(mcp, options = {}) {
66
66
  const servesOwnPrm = !(mcp.auth?.type === "oauth" && mcp.auth.protectedResourceMetadataUrl !== void 0);
67
67
  const metadataPath = resourcePath === void 0 || !servesOwnPrm ? void 0 : `${trimTrailingSlash(resourcePath)}${OAUTH_PROTECTED_RESOURCE_METADATA_PATH}`;
68
68
  const runtimeOptions = resourcePath === void 0 ? {} : { resourcePath, ...metadataPath ? { metadataPath } : {} };
69
- const recorder = createRecorderForRuntime(mcp);
70
- const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions, recorder);
71
- const listToolsHandler = createListToolsHandler(mcp, runtimeOptions, recorder);
72
- const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions, recorder);
69
+ const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions);
70
+ const listToolsHandler = createListToolsHandler(mcp, runtimeOptions);
71
+ const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
73
72
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
74
73
  return async (request) => {
75
74
  const req = applyForwardedOrigin(request, {
76
75
  trustForwardedProto: true,
77
76
  trustForwardedHost: options.trustForwardedHost
78
77
  });
78
+ const recorder = createRecorderForRuntime(mcp, { stack: "supabase" });
79
79
  const target = dispatchFor(new URL(req.url).pathname);
80
80
  switch (target.kind) {
81
81
  case "metadata":
82
82
  return metadataHandler(req);
83
83
  case "list-tools":
84
- return listToolsHandler(req);
84
+ return listToolsHandler(req, recorder);
85
85
  case "invoke-tool":
86
- return invokeToolHandler(req, target.toolName);
86
+ return invokeToolHandler(req, target.toolName, recorder);
87
87
  case "mcp":
88
- return mcpHandler(req);
88
+ return mcpHandler(req, recorder);
89
89
  }
90
90
  };
91
91
  }
@@ -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.17.0";
36
+ var version = "0.20.0";
37
37
 
38
38
  // src/core/fs-errors.ts
39
39
  function isFileMissing(err) {