@lovable.dev/mcp-js 0.16.0 → 0.19.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 (38) hide show
  1. package/dist/{recorder-qlzUKFxG.d.ts → base-C9rhAHZ0.d.ts} +3 -4
  2. package/dist/{chunk-W2EZWPJ5.js → chunk-57ZH2WW5.js} +11 -12
  3. package/dist/{chunk-H6BKTNJY.js → chunk-5FX6IIQ6.js} +129 -105
  4. package/dist/{chunk-SKSKC747.js → chunk-CDZ7MBXC.js} +1 -1
  5. package/dist/{chunk-EZQVUNXB.js → chunk-CLXKPZZE.js} +13 -14
  6. package/dist/{chunk-DCWYK4CA.js → chunk-H37EB22A.js} +13 -9
  7. package/dist/{chunk-I5CAQUQI.js → chunk-OMWXY6WY.js} +8 -8
  8. package/dist/{chunk-T24Z753F.js → chunk-UEOBGHXF.js} +2 -2
  9. package/dist/cli/extract-manifest.cjs +4 -3
  10. package/dist/cli/extract-manifest.js +4 -4
  11. package/dist/index.cjs +4 -9
  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 +19 -225
  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.cjs +3 -2
  20. package/dist/protocols/oauth-metadata.d.cts +1 -1
  21. package/dist/protocols/oauth-metadata.d.ts +1 -1
  22. package/dist/protocols/oauth-metadata.js +4 -4
  23. package/dist/protocols/rest/index.cjs +24 -230
  24. package/dist/protocols/rest/index.d.cts +6 -6
  25. package/dist/protocols/rest/index.d.ts +6 -6
  26. package/dist/protocols/rest/index.js +5 -5
  27. package/dist/stacks/supabase/index.cjs +196 -169
  28. package/dist/stacks/supabase/index.d.cts +1 -1
  29. package/dist/stacks/supabase/index.d.ts +1 -1
  30. package/dist/stacks/supabase/index.js +14 -14
  31. package/dist/stacks/supabase/vite.cjs +1 -1
  32. package/dist/stacks/supabase/vite.js +1 -1
  33. package/dist/stacks/tanstack/index.cjs +205 -177
  34. package/dist/stacks/tanstack/index.d.cts +1 -1
  35. package/dist/stacks/tanstack/index.d.ts +1 -1
  36. package/dist/stacks/tanstack/index.js +13 -10
  37. package/dist/{types-COY42xux.d.ts → types-CPkhCRxc.d.ts} +3 -3
  38. package/package.json +1 -1
@@ -95,21 +95,58 @@ 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) {
101
127
  return typeof value === "string" && value in LEVEL_RANK;
102
128
  }
129
+ var LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
103
130
  function readEnvLevel() {
104
131
  try {
105
- const raw = typeof process !== "undefined" ? process.env?.["LOVABLE_MCP_LOG_LEVEL"] : void 0;
132
+ const raw = typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0;
106
133
  const normalized = raw?.trim().toLowerCase();
107
134
  return isLogLevel(normalized) ? normalized : void 0;
108
135
  } catch {
109
136
  return void 0;
110
137
  }
111
138
  }
112
- var currentLevel = readEnvLevel() ?? "silent";
139
+ var currentLevel = readEnvLevel() ?? "debug";
140
+ function setLogLevel(level) {
141
+ currentLevel = level;
142
+ }
143
+ function parseLogLevel(raw) {
144
+ const normalized = raw?.trim().toLowerCase();
145
+ return isLogLevel(normalized) ? normalized : void 0;
146
+ }
147
+ function applyLogLevelFromEnv(raw) {
148
+ setLogLevel(parseLogLevel(raw) ?? "debug");
149
+ }
113
150
  function enabled(level) {
114
151
  return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
115
152
  }
@@ -136,40 +173,8 @@ function describeError(err) {
136
173
  return { value: String(err) };
137
174
  }
138
175
 
139
- // src/metrics/config.ts
140
- var DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
141
- var METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
142
- var METRICS_SAMPLE_RATE = 1;
143
- var METRICS_FLUSH_INTERVAL_MS = 5e3;
144
- var METRICS_MAX_BATCH_SIZE = 50;
145
- function assertMetricsEndpoint(endpoint) {
146
- let url;
147
- try {
148
- url = new URL(endpoint);
149
- } catch {
150
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
151
- }
152
- if (url.protocol !== "https:" && url.protocol !== "http:") {
153
- throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
154
- }
155
- }
156
- function resolveMetricsConfig(config = true) {
157
- const options = typeof config === "boolean" ? { enabled: config } : config;
158
- const endpoint = options.endpoint ?? DEFAULT_METRICS_ENDPOINT;
159
- assertMetricsEndpoint(endpoint);
160
- return Object.freeze({
161
- enabled: options.enabled ?? true,
162
- endpoint,
163
- headers: options.headers ?? {},
164
- apiKeyEnvVar: METRICS_API_KEY_ENV_VAR,
165
- sampleRate: METRICS_SAMPLE_RATE,
166
- flushIntervalMs: METRICS_FLUSH_INTERVAL_MS,
167
- maxBatchSize: METRICS_MAX_BATCH_SIZE
168
- });
169
- }
170
-
171
176
  // package.json
172
- var version = "0.16.0";
177
+ var version = "0.19.0";
173
178
 
174
179
  // src/metrics/otlp.ts
175
180
  var SCOPE_NAME = "@lovable.dev/mcp-js";
@@ -194,6 +199,7 @@ function toLogRecord(rec) {
194
199
  attributes.push(intAttr("mcp.request_size_bytes", rec.reqBytes));
195
200
  if (rec.resBytes !== void 0)
196
201
  attributes.push(intAttr("mcp.response_size_bytes", rec.resBytes));
202
+ attributes.push(strAttr("mcp.stack", rec.stack));
197
203
  return {
198
204
  timeUnixNano: rec.timeUnixNano,
199
205
  observedTimeUnixNano: rec.timeUnixNano,
@@ -230,127 +236,148 @@ function nowUnixNano() {
230
236
  return `${Date.now()}000000`;
231
237
  }
232
238
 
233
- // src/metrics/recorder.ts
239
+ // src/metrics/impl/base.ts
234
240
  function nowMs() {
235
241
  return typeof performance !== "undefined" && typeof performance.now === "function" ? performance.now() : Date.now();
236
242
  }
237
- function reportInvocation(recorder, ev) {
238
- log.info("tool.invoked", { tool: ev.tool, method: ev.method, outcome: ev.outcome, durationMs: ev.durationMs });
239
- recorder.record(ev);
240
- }
241
- var NOOP_RECORDER = {
242
- record() {
243
- },
244
- async flush() {
245
- }
246
- };
243
+ var NOOP_RECORDER = { async emit() {
244
+ } };
247
245
  function createNoopRecorder() {
248
246
  return NOOP_RECORDER;
249
247
  }
250
- function readRuntimeEnv(name) {
248
+ function readProcessEnv(name) {
251
249
  try {
252
- const denoEnv = globalThis.Deno?.env;
253
- const value = denoEnv?.get?.(name);
254
- if (value)
255
- return value;
256
- } catch {
257
- }
258
- try {
259
- if (typeof process !== "undefined") {
260
- const value = process.env?.[name];
261
- if (value)
262
- return value;
263
- }
250
+ return typeof process !== "undefined" ? process.env?.[name] || void 0 : void 0;
264
251
  } catch {
252
+ return void 0;
265
253
  }
266
- return void 0;
267
254
  }
268
- function probeWaitUntil() {
269
- const fn = globalThis.EdgeRuntime?.waitUntil;
270
- return typeof fn === "function" ? fn.bind(globalThis.EdgeRuntime) : void 0;
271
- }
272
- function createMetricsRecorder(ctx, deps = {}) {
273
- const { config, server } = ctx;
274
- if (!config.enabled)
275
- return NOOP_RECORDER;
276
- const doFetch = deps.fetch ?? globalThis.fetch;
277
- if (!doFetch) {
278
- log.warn("metrics.disabled_no_fetch", { endpoint: config.endpoint });
279
- return NOOP_RECORDER;
280
- }
281
- 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
- const waitUntil = deps.waitUntil ?? probeWaitUntil();
288
- const buffer = [];
289
- let timer;
290
- const schedule = (p) => {
291
- if (waitUntil) {
292
- try {
293
- waitUntil(p);
294
- return;
295
- } catch (err) {
296
- 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 ?? globalThis.fetch;
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;
297
267
  }
298
268
  }
299
- void p.catch(() => {
300
- });
301
- };
302
- const headers = {};
303
- if (!usesLovableEndpoint) {
304
- for (const [key, value] of Object.entries(config.headers)) {
305
- if (key.toLowerCase() !== "content-type")
306
- headers[key] = value;
307
- }
269
+ headers["content-type"] = "application/json";
270
+ this.baseHeaders = headers;
308
271
  }
309
- headers["content-type"] = "application/json";
310
- if (apiKey)
311
- headers.authorization = `Bearer ${apiKey}`;
312
- const flush = async () => {
313
- 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)
314
287
  return;
315
- const records = buffer.splice(0, buffer.length);
316
- const dropped = records.length;
317
- try {
318
- const res = await doFetch(config.endpoint, {
319
- method: "POST",
320
- headers,
321
- body: buildLogsPayload(records, server),
322
- keepalive: true
323
- });
324
- if (!res.ok) {
325
- log.warn("metrics.flush_rejected", { status: res.status, dropped, endpoint: config.endpoint });
288
+ if (!this.doFetch) {
289
+ log.warn("metrics.disabled_no_fetch", { endpoint: this.config.endpoint });
290
+ return;
291
+ }
292
+ const headers = { ...this.baseHeaders };
293
+ if (this.usesLovableEndpoint) {
294
+ const key = await this.resolveApiKey();
295
+ if (!key) {
296
+ log.warn("metrics.disabled_no_api_key", { envVar: this.config.apiKeyEnvVar, endpoint: this.config.endpoint });
297
+ return;
326
298
  }
299
+ headers.authorization = `Bearer ${key}`;
300
+ }
301
+ const body = buildLogsPayload([{ ...ev, timeUnixNano: nowUnixNano(), stack: this.stack }], this.server);
302
+ try {
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 });
327
306
  } catch (err) {
328
- log.warn("metrics.flush_failed", { ...describeError(err), dropped, endpoint: config.endpoint });
307
+ log.warn("metrics.failed", { ...describeError(err), endpoint: this.config.endpoint });
329
308
  }
330
- };
331
- const ensureTimer = () => {
332
- 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)
333
320
  return;
334
- timer = setInterval(() => schedule(flush()), config.flushIntervalMs);
335
- timer.unref?.();
336
- };
337
- return {
338
- record(ev) {
339
- if (config.sampleRate < 1 && Math.random() >= config.sampleRate)
340
- return;
341
- buffer.push({ ...ev, timeUnixNano: nowUnixNano() });
342
- ensureTimer();
343
- if (buffer.length >= config.maxBatchSize)
344
- schedule(flush());
345
- },
346
- flush
347
- };
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
+ }
348
366
  }
349
- 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) {
350
376
  const config = resolveMetricsConfig(mcp.metrics);
377
+ const server = { name: mcp.name, version: mcp.version };
351
378
  if (!config.enabled)
352
379
  return createNoopRecorder();
353
- return createMetricsRecorder({ config, server: { name: mcp.name, version: mcp.version } });
380
+ return opts.stack === "tanstack" ? new TanStackMetricRecorder(config, server) : new SupabaseMetricRecorder(config, server);
354
381
  }
355
382
 
356
383
  // src/protocols/mcp/protocol.ts
@@ -749,10 +776,10 @@ function assertRequiredScopes(auth, context) {
749
776
  throw new OAuthTokenError(403, "insufficient_scope", "Additional OAuth scope is required");
750
777
  }
751
778
  }
752
- function createRequestAuthorizer(mcp, options = {}, recorder) {
779
+ function createRequestAuthorizer(mcp, options = {}) {
753
780
  const runtime = getOAuthRuntime(mcp, options);
754
781
  return {
755
- async authorize(request) {
782
+ async authorize(request, recorder) {
756
783
  if (runtime.kind === "unconfigured")
757
784
  return { ok: true };
758
785
  const startedAt = nowMs();
@@ -768,7 +795,7 @@ function createRequestAuthorizer(mcp, options = {}, recorder) {
768
795
  } catch (err) {
769
796
  if (err instanceof OAuthConfigurationError) {
770
797
  log.error("auth.config_error", { ...describeError(err), outcome: "500" });
771
- recorder?.record({
798
+ await recorder?.emit({
772
799
  tool: null,
773
800
  method: "authorize",
774
801
  outcome: "auth_config_error",
@@ -879,7 +906,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
879
906
  try {
880
907
  result = await tool.handler(args, new ToolContext(auth));
881
908
  } catch {
882
- reportInvocation(recorder, {
909
+ await recorder.emit({
883
910
  tool: tool.name,
884
911
  method: "tools/call",
885
912
  outcome: "handler_error",
@@ -888,7 +915,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
888
915
  return { content: [{ type: "text", text: "tool execution failed" }], isError: true };
889
916
  }
890
917
  if (result == null) {
891
- reportInvocation(recorder, {
918
+ await recorder.emit({
892
919
  tool: tool.name,
893
920
  method: "tools/call",
894
921
  outcome: "handler_error",
@@ -896,7 +923,7 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
896
923
  });
897
924
  return { content: [{ type: "text", text: `tool "${tool.name}" returned no result` }], isError: true };
898
925
  }
899
- reportInvocation(recorder, {
926
+ await recorder.emit({
900
927
  tool: tool.name,
901
928
  method: "tools/call",
902
929
  outcome: result.isError ? "tool_error" : "ok",
@@ -905,10 +932,10 @@ function adaptToolToSdkCallback(tool, auth, recorder) {
905
932
  return { content: result.content ?? [], structuredContent: result.structuredContent, isError: result.isError };
906
933
  };
907
934
  }
908
- function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
909
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
910
- const handle = async (request) => {
911
- 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);
912
939
  if (!authResult.ok)
913
940
  return authResult.response;
914
941
  try {
@@ -935,7 +962,7 @@ function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderFo
935
962
  await server.connect(transport);
936
963
  return await transport.handleRequest(request);
937
964
  } catch (err) {
938
- recorder.record({ tool: null, method: "transport", outcome: "transport_error", durationMs: 0 });
965
+ await recorder.emit({ tool: null, method: "transport", outcome: "transport_error", durationMs: 0 });
939
966
  log.error("mcp.transport_error", { ...describeError(err), outcome: "500 internal error" });
940
967
  return Response.json(
941
968
  { jsonrpc: "2.0", id: null, error: { code: -32603, message: "internal error" } },
@@ -943,10 +970,10 @@ function createMcpProtocolHandler(mcp, options = {}, recorder = createRecorderFo
943
970
  );
944
971
  }
945
972
  };
946
- return async (request) => {
973
+ return async (request, recorder = createNoopRecorder()) => {
947
974
  if (request.method === "OPTIONS")
948
975
  return corsPreflightResponse("GET, POST, DELETE, OPTIONS");
949
- return withCors(await handle(request));
976
+ return withCors(await handle(request, recorder));
950
977
  };
951
978
  }
952
979
 
@@ -1036,11 +1063,11 @@ function buildMcpListing(mcp) {
1036
1063
  }))
1037
1064
  };
1038
1065
  }
1039
- function createListToolsHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
1066
+ function createListToolsHandler(mcp, options = {}) {
1040
1067
  assertRestResourceBinding(mcp, options);
1041
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
1042
- const handle = async (request) => {
1043
- 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);
1044
1071
  if (!authResult.ok)
1045
1072
  return authResult.response;
1046
1073
  if (request.method !== "GET" && request.method !== "HEAD")
@@ -1048,10 +1075,10 @@ function createListToolsHandler(mcp, options = {}, recorder = createRecorderForR
1048
1075
  const response = Response.json(buildMcpListing(mcp));
1049
1076
  return request.method === "HEAD" ? headResponse(response) : response;
1050
1077
  };
1051
- return async (request) => {
1078
+ return async (request, recorder = createNoopRecorder()) => {
1052
1079
  if (request.method === "OPTIONS")
1053
1080
  return corsPreflightResponse("GET, HEAD, OPTIONS");
1054
- return withCors(await handle(request));
1081
+ return withCors(await handle(request, recorder));
1055
1082
  };
1056
1083
  }
1057
1084
 
@@ -1069,11 +1096,11 @@ function isEmptyArgs(value) {
1069
1096
  return false;
1070
1097
  return Object.keys(value).length === 0;
1071
1098
  }
1072
- function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderForRuntime(mcp)) {
1099
+ function createInvokeToolHandler(mcp, options = {}) {
1073
1100
  assertRestResourceBinding(mcp, options);
1074
- const authorizer = createRequestAuthorizer(mcp, options, recorder);
1075
- const handle = async (request, toolName) => {
1076
- 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);
1077
1104
  if (!authResult.ok)
1078
1105
  return authResult.response;
1079
1106
  if (request.method !== "POST")
@@ -1129,7 +1156,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1129
1156
  try {
1130
1157
  result = await tool.handler(args, new ToolContext(authResult.auth));
1131
1158
  } catch {
1132
- reportInvocation(recorder, {
1159
+ await recorder.emit({
1133
1160
  tool: tool.name,
1134
1161
  method: "tools/call",
1135
1162
  outcome: "handler_error",
@@ -1141,7 +1168,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1141
1168
  });
1142
1169
  }
1143
1170
  if (result == null) {
1144
- reportInvocation(recorder, {
1171
+ await recorder.emit({
1145
1172
  tool: tool.name,
1146
1173
  method: "tools/call",
1147
1174
  outcome: "handler_error",
@@ -1152,7 +1179,7 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1152
1179
  headers: JSON_HEADERS
1153
1180
  });
1154
1181
  }
1155
- reportInvocation(recorder, {
1182
+ await recorder.emit({
1156
1183
  tool: tool.name,
1157
1184
  method: "tools/call",
1158
1185
  outcome: result.isError ? "tool_error" : "ok",
@@ -1164,10 +1191,10 @@ function createInvokeToolHandler(mcp, options = {}, recorder = createRecorderFor
1164
1191
  isError: result.isError
1165
1192
  });
1166
1193
  };
1167
- return async (request, toolName) => {
1194
+ return async (request, toolName, recorder = createNoopRecorder()) => {
1168
1195
  if (request.method === "OPTIONS")
1169
1196
  return corsPreflightResponse("POST, OPTIONS");
1170
- return withCors(await handle(request, toolName));
1197
+ return withCors(await handle(request, toolName, recorder));
1171
1198
  };
1172
1199
  }
1173
1200
 
@@ -1217,26 +1244,26 @@ function createSupabaseHandler(mcp, options = {}) {
1217
1244
  const servesOwnPrm = !(mcp.auth?.type === "oauth" && mcp.auth.protectedResourceMetadataUrl !== void 0);
1218
1245
  const metadataPath = resourcePath === void 0 || !servesOwnPrm ? void 0 : `${trimTrailingSlash(resourcePath)}${OAUTH_PROTECTED_RESOURCE_METADATA_PATH}`;
1219
1246
  const runtimeOptions = resourcePath === void 0 ? {} : { resourcePath, ...metadataPath ? { metadataPath } : {} };
1220
- const recorder = createRecorderForRuntime(mcp);
1221
- const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions, recorder);
1222
- const listToolsHandler = createListToolsHandler(mcp, runtimeOptions, recorder);
1223
- const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions, recorder);
1247
+ const mcpHandler = createMcpProtocolHandler(mcp, runtimeOptions);
1248
+ const listToolsHandler = createListToolsHandler(mcp, runtimeOptions);
1249
+ const invokeToolHandler = createInvokeToolHandler(mcp, runtimeOptions);
1224
1250
  const metadataHandler = createOAuthProtectedResourceMetadataHandler(mcp, runtimeOptions);
1225
1251
  return async (request) => {
1226
1252
  const req = applyForwardedOrigin(request, {
1227
1253
  trustForwardedProto: true,
1228
1254
  trustForwardedHost: options.trustForwardedHost
1229
1255
  });
1256
+ const recorder = createRecorderForRuntime(mcp, { stack: "supabase" });
1230
1257
  const target = dispatchFor(new URL(req.url).pathname);
1231
1258
  switch (target.kind) {
1232
1259
  case "metadata":
1233
1260
  return metadataHandler(req);
1234
1261
  case "list-tools":
1235
- return listToolsHandler(req);
1262
+ return listToolsHandler(req, recorder);
1236
1263
  case "invoke-tool":
1237
- return invokeToolHandler(req, target.toolName);
1264
+ return invokeToolHandler(req, target.toolName, recorder);
1238
1265
  case "mcp":
1239
- return mcpHandler(req);
1266
+ return mcpHandler(req, recorder);
1240
1267
  }
1241
1268
  };
1242
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-EZQVUNXB.js";
6
+ } from "../../chunk-CLXKPZZE.js";
7
7
  import {
8
8
  createOAuthProtectedResourceMetadataHandler
9
- } from "../../chunk-T24Z753F.js";
9
+ } from "../../chunk-UEOBGHXF.js";
10
10
  import {
11
11
  createInvokeToolHandler
12
- } from "../../chunk-W2EZWPJ5.js";
12
+ } from "../../chunk-57ZH2WW5.js";
13
13
  import {
14
14
  createListToolsHandler
15
- } from "../../chunk-I5CAQUQI.js";
15
+ } from "../../chunk-OMWXY6WY.js";
16
16
  import "../../chunk-MA5H6PSF.js";
17
17
  import {
18
18
  assertResourcePathShape,
19
19
  createRecorderForRuntime
20
- } from "../../chunk-H6BKTNJY.js";
20
+ } from "../../chunk-5FX6IIQ6.js";
21
21
  import {
22
22
  trimTrailingSlash
23
- } from "../../chunk-DCWYK4CA.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-SKSKC747.js";
31
+ import "../../chunk-CDZ7MBXC.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.16.0";
36
+ var version = "0.19.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-CDZ7MBXC.js";
11
11
 
12
12
  // src/stacks/supabase/vite.ts
13
13
  import { resolve as resolve2, sep as sep2 } from "path";