@lovable.dev/mcp-js 0.21.1-rc.1 → 0.22.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.
- package/dist/authorize-BMeXd_Sh.d.ts +25 -0
- package/dist/base-CM-KCpp6.d.ts +28 -0
- package/dist/chunk-4EHZUUS5.js +141 -0
- package/dist/chunk-6DXGZZA4.js +6 -0
- package/dist/chunk-6KNM7RGD.js +79 -0
- package/dist/chunk-6QFZYYUV.js +11 -0
- package/dist/chunk-EOFPMSND.js +6 -0
- package/dist/chunk-H37EB22A.js +125 -0
- package/dist/chunk-MA5H6PSF.js +46 -0
- package/dist/chunk-P43FIUMZ.js +114 -0
- package/dist/chunk-RK62EMPY.js +741 -0
- package/dist/chunk-RLE4UE63.js +58 -0
- package/dist/chunk-UQK5UO6C.js +26 -0
- package/dist/chunk-XQWJN6DC.js +14 -0
- package/dist/chunk-Y3ZFPEQH.js +8 -0
- package/dist/cli/extract-manifest.cjs +201 -116
- package/dist/cli/extract-manifest.d.cts +1 -1
- package/dist/cli/extract-manifest.d.ts +1 -1
- package/dist/cli/extract-manifest.js +156 -117
- package/dist/index.cjs +329 -129
- package/dist/index.d.cts +26 -26
- package/dist/index.d.ts +26 -26
- package/dist/index.js +177 -118
- package/dist/{io-CS4UL6_A.d.ts → io-D4srzRKc.d.ts} +4 -6
- package/dist/protocols/mcp/index.cjs +750 -3
- package/dist/protocols/mcp/index.d.cts +7 -6
- package/dist/protocols/mcp/index.d.ts +7 -6
- package/dist/protocols/mcp/index.js +12 -2
- package/dist/protocols/oauth-metadata.cjs +539 -48
- package/dist/protocols/oauth-metadata.d.cts +6 -5
- package/dist/protocols/oauth-metadata.d.ts +6 -5
- package/dist/protocols/oauth-metadata.js +10 -52
- package/dist/protocols/rest/index.cjs +843 -5
- package/dist/protocols/rest/index.d.cts +10 -7
- package/dist/protocols/rest/index.d.ts +10 -7
- package/dist/protocols/rest/index.js +16 -3
- package/dist/stacks/supabase/index.cjs +1318 -76
- package/dist/stacks/supabase/index.d.cts +30 -29
- package/dist/stacks/supabase/index.d.ts +30 -29
- package/dist/stacks/supabase/index.js +89 -73
- package/dist/stacks/supabase/vite.cjs +287 -258
- package/dist/stacks/supabase/vite.d.cts +24 -24
- package/dist/stacks/supabase/vite.d.ts +24 -24
- package/dist/stacks/supabase/vite.js +252 -252
- package/dist/stacks/tanstack/index.cjs +1272 -42
- package/dist/stacks/tanstack/index.d.cts +9 -8
- package/dist/stacks/tanstack/index.d.ts +9 -8
- package/dist/stacks/tanstack/index.js +41 -36
- package/dist/stacks/tanstack/vite.cjs +312 -223
- package/dist/stacks/tanstack/vite.d.cts +81 -80
- package/dist/stacks/tanstack/vite.d.ts +81 -80
- package/dist/stacks/tanstack/vite.js +282 -216
- package/dist/types-qqrmJ736.d.ts +321 -0
- package/package.json +28 -71
- package/dist/authorize-CumVyk7p.d.cts +0 -27
- package/dist/authorize-D6p4-9_D.d.ts +0 -27
- package/dist/base-CoIFvAmS.d.cts +0 -26
- package/dist/base-CoIFvAmS.d.ts +0 -26
- package/dist/content-D5LJAHyM.js +0 -12
- package/dist/content-NCYIGgOb.cjs +0 -17
- package/dist/context-BweeEcoA.cjs +0 -56
- package/dist/context-CIpPzN7P.js +0 -51
- package/dist/cors-B7CTXIHD.js +0 -829
- package/dist/cors-BebjKPrc.cjs +0 -912
- package/dist/forwarded--h4efJy-.js +0 -43
- package/dist/forwarded-Pi8Hs5Ps.cjs +0 -48
- package/dist/fs-errors-CWNzOV75.cjs +0 -11
- package/dist/fs-errors-PA2t1TIp.js +0 -6
- package/dist/io-CbbUbPY3.d.cts +0 -15
- package/dist/list-tools-CBCuS1Tv.cjs +0 -57
- package/dist/list-tools-CsWgiRy1.d.ts +0 -8
- package/dist/list-tools-CtZHOuPv.d.cts +0 -8
- package/dist/list-tools-D75RGtgs.js +0 -46
- package/dist/logger-2OXtfiIW.js +0 -141
- package/dist/logger-BqPOa_E1.cjs +0 -194
- package/dist/mcp-Cdj0AYst.cjs +0 -123
- package/dist/mcp-GngXbcqN.js +0 -118
- package/dist/metadata-path-CAkNcfyY.js +0 -12
- package/dist/metadata-path-zd7NSNoa.cjs +0 -17
- package/dist/package-7EUptuSJ.js +0 -4
- package/dist/package-BwCGVRcB.cjs +0 -9
- package/dist/paths-IS65L6TA.js +0 -7
- package/dist/paths-OP318a6c.cjs +0 -18
- package/dist/rest-CXH6-zv9.js +0 -113
- package/dist/rest-CyV8LHeB.cjs +0 -118
- package/dist/types-BYdYYTjk.d.cts +0 -321
- package/dist/types-BYdYYTjk.d.ts +0 -321
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
//#region src/core/forwarded.ts
|
|
2
|
-
/**
|
|
3
|
-
* Rewrites a request's URL to the public origin a reverse proxy forwards via
|
|
4
|
-
* `X-Forwarded-*`, so SDK-derived OAuth `resource`/metadata/`WWW-Authenticate`
|
|
5
|
-
* URLs name the host the client actually connected to — not the internal
|
|
6
|
-
* backend origin the proxy rewrites `Host` to. Without this, an app on a custom
|
|
7
|
-
* domain advertises its internal `*.lovable.dev`/`*.supabase.co` host and every
|
|
8
|
-
* MCP call 401s on an audience the client can't satisfy.
|
|
9
|
-
*
|
|
10
|
-
* Each header is trusted independently, because a forwarded value is only as
|
|
11
|
-
* trustworthy as the proxy that sets it:
|
|
12
|
-
* - `X-Forwarded-Host` can redirect the advertised resource to an attacker
|
|
13
|
-
* origin (the threat `auth/resource.ts` guards against), so it is honored only
|
|
14
|
-
* when `trustForwardedHost` is set — enabled on emit paths that sit behind a
|
|
15
|
-
* proxy which *overwrites* the header (Lovable's web-proxy does), never by a
|
|
16
|
-
* bare SDK consumer.
|
|
17
|
-
* - `X-Forwarded-Proto` only selects http/https, so it is gated separately:
|
|
18
|
-
* Supabase terminates TLS upstream and forwards over http with a
|
|
19
|
-
* gateway-stamped proto, so that stack trusts it; the TanStack proxy does not
|
|
20
|
-
* sanitize proto, so that stack leaves it alone.
|
|
21
|
-
*/
|
|
22
|
-
function applyForwardedOrigin(request, options) {
|
|
23
|
-
const proto = options.trustForwardedProto ? firstForwardedValue(request, "x-forwarded-proto") : void 0;
|
|
24
|
-
const host = options.trustForwardedHost ? firstForwardedValue(request, "x-forwarded-host") : void 0;
|
|
25
|
-
if (proto === void 0 && host === void 0) return request;
|
|
26
|
-
const url = new URL(request.url);
|
|
27
|
-
let changed = false;
|
|
28
|
-
if (proto !== void 0 && `${proto}:` !== url.protocol) {
|
|
29
|
-
url.protocol = `${proto}:`;
|
|
30
|
-
changed = true;
|
|
31
|
-
}
|
|
32
|
-
if (host !== void 0 && host !== url.host) {
|
|
33
|
-
url.host = host;
|
|
34
|
-
changed = true;
|
|
35
|
-
}
|
|
36
|
-
return changed ? new Request(url.href, request) : request;
|
|
37
|
-
}
|
|
38
|
-
function firstForwardedValue(request, header) {
|
|
39
|
-
const value = request.headers.get(header)?.split(",")[0]?.trim();
|
|
40
|
-
return value ? value : void 0;
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
|
-
export { applyForwardedOrigin as t };
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
//#region src/core/forwarded.ts
|
|
2
|
-
/**
|
|
3
|
-
* Rewrites a request's URL to the public origin a reverse proxy forwards via
|
|
4
|
-
* `X-Forwarded-*`, so SDK-derived OAuth `resource`/metadata/`WWW-Authenticate`
|
|
5
|
-
* URLs name the host the client actually connected to — not the internal
|
|
6
|
-
* backend origin the proxy rewrites `Host` to. Without this, an app on a custom
|
|
7
|
-
* domain advertises its internal `*.lovable.dev`/`*.supabase.co` host and every
|
|
8
|
-
* MCP call 401s on an audience the client can't satisfy.
|
|
9
|
-
*
|
|
10
|
-
* Each header is trusted independently, because a forwarded value is only as
|
|
11
|
-
* trustworthy as the proxy that sets it:
|
|
12
|
-
* - `X-Forwarded-Host` can redirect the advertised resource to an attacker
|
|
13
|
-
* origin (the threat `auth/resource.ts` guards against), so it is honored only
|
|
14
|
-
* when `trustForwardedHost` is set — enabled on emit paths that sit behind a
|
|
15
|
-
* proxy which *overwrites* the header (Lovable's web-proxy does), never by a
|
|
16
|
-
* bare SDK consumer.
|
|
17
|
-
* - `X-Forwarded-Proto` only selects http/https, so it is gated separately:
|
|
18
|
-
* Supabase terminates TLS upstream and forwards over http with a
|
|
19
|
-
* gateway-stamped proto, so that stack trusts it; the TanStack proxy does not
|
|
20
|
-
* sanitize proto, so that stack leaves it alone.
|
|
21
|
-
*/
|
|
22
|
-
function applyForwardedOrigin(request, options) {
|
|
23
|
-
const proto = options.trustForwardedProto ? firstForwardedValue(request, "x-forwarded-proto") : void 0;
|
|
24
|
-
const host = options.trustForwardedHost ? firstForwardedValue(request, "x-forwarded-host") : void 0;
|
|
25
|
-
if (proto === void 0 && host === void 0) return request;
|
|
26
|
-
const url = new URL(request.url);
|
|
27
|
-
let changed = false;
|
|
28
|
-
if (proto !== void 0 && `${proto}:` !== url.protocol) {
|
|
29
|
-
url.protocol = `${proto}:`;
|
|
30
|
-
changed = true;
|
|
31
|
-
}
|
|
32
|
-
if (host !== void 0 && host !== url.host) {
|
|
33
|
-
url.host = host;
|
|
34
|
-
changed = true;
|
|
35
|
-
}
|
|
36
|
-
return changed ? new Request(url.href, request) : request;
|
|
37
|
-
}
|
|
38
|
-
function firstForwardedValue(request, header) {
|
|
39
|
-
const value = request.headers.get(header)?.split(",")[0]?.trim();
|
|
40
|
-
return value ? value : void 0;
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
43
|
-
Object.defineProperty(exports, "applyForwardedOrigin", {
|
|
44
|
-
enumerable: true,
|
|
45
|
-
get: function() {
|
|
46
|
-
return applyForwardedOrigin;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//#region src/core/fs-errors.ts
|
|
2
|
-
function isFileMissing(err) {
|
|
3
|
-
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
4
|
-
}
|
|
5
|
-
//#endregion
|
|
6
|
-
Object.defineProperty(exports, "isFileMissing", {
|
|
7
|
-
enumerable: true,
|
|
8
|
-
get: function() {
|
|
9
|
-
return isFileMissing;
|
|
10
|
-
}
|
|
11
|
-
});
|
package/dist/io-CbbUbPY3.d.cts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import "./list-tools-CtZHOuPv.cjs";
|
|
2
|
-
//#region src/manifest/io.d.ts
|
|
3
|
-
/**
|
|
4
|
-
* Shape every MCP Vite plugin exposes on its `api` so `runExtract` can read
|
|
5
|
-
* back the resolved entry path and the URL the stack mounts the MCP server at.
|
|
6
|
-
* TanStack sets `urlPath` to the configured route path (default `/mcp`);
|
|
7
|
-
* Supabase sets it to `/functions/v1/<functionName>` (the public mount under
|
|
8
|
-
* which the function and its companion routes live).
|
|
9
|
-
*/
|
|
10
|
-
interface McpPluginApi {
|
|
11
|
-
readonly mcpEntry: string;
|
|
12
|
-
readonly urlPath: string;
|
|
13
|
-
}
|
|
14
|
-
//#endregion
|
|
15
|
-
export { McpPluginApi as t };
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const require_cors = require("./cors-BebjKPrc.cjs");
|
|
2
|
-
let _modelcontextprotocol_sdk_server_zod_compat_js = require("@modelcontextprotocol/sdk/server/zod-compat.js");
|
|
3
|
-
let _modelcontextprotocol_sdk_server_zod_json_schema_compat_js = require("@modelcontextprotocol/sdk/server/zod-json-schema-compat.js");
|
|
4
|
-
//#region src/protocols/rest/list-tools.ts
|
|
5
|
-
function shapeToJsonSchema(shape) {
|
|
6
|
-
if (!shape) return null;
|
|
7
|
-
try {
|
|
8
|
-
return (0, _modelcontextprotocol_sdk_server_zod_json_schema_compat_js.toJsonSchemaCompat)((0, _modelcontextprotocol_sdk_server_zod_compat_js.objectFromShape)(shape));
|
|
9
|
-
} catch {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function buildMcpListing(mcp) {
|
|
14
|
-
return {
|
|
15
|
-
server: {
|
|
16
|
-
name: mcp.name,
|
|
17
|
-
version: mcp.version,
|
|
18
|
-
title: mcp.title
|
|
19
|
-
},
|
|
20
|
-
tools: mcp.tools.map((tool) => ({
|
|
21
|
-
name: tool.name,
|
|
22
|
-
title: tool.title,
|
|
23
|
-
description: tool.description,
|
|
24
|
-
annotations: tool.annotations,
|
|
25
|
-
inputSchema: shapeToJsonSchema(tool.inputSchema),
|
|
26
|
-
outputSchema: shapeToJsonSchema(tool.outputSchema)
|
|
27
|
-
}))
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function createListToolsHandler(mcp, options = {}) {
|
|
31
|
-
require_cors.assertRestResourceBinding(mcp, options);
|
|
32
|
-
const authorizer = require_cors.createRequestAuthorizer(mcp, options);
|
|
33
|
-
const handle = async (request, recorder) => {
|
|
34
|
-
const authResult = await authorizer.authorize(request, recorder);
|
|
35
|
-
if (!authResult.ok) return authResult.response;
|
|
36
|
-
if (request.method !== "GET" && request.method !== "HEAD") return require_cors.methodNotAllowed("GET, HEAD, OPTIONS");
|
|
37
|
-
const response = Response.json(buildMcpListing(mcp));
|
|
38
|
-
return request.method === "HEAD" ? require_cors.headResponse(response) : response;
|
|
39
|
-
};
|
|
40
|
-
return async (request, recorder = require_cors.createNoopRecorder()) => {
|
|
41
|
-
if (request.method === "OPTIONS") return require_cors.corsPreflightResponse("GET, HEAD, OPTIONS");
|
|
42
|
-
return require_cors.withCors(await handle(request, recorder));
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
Object.defineProperty(exports, "buildMcpListing", {
|
|
47
|
-
enumerable: true,
|
|
48
|
-
get: function() {
|
|
49
|
-
return buildMcpListing;
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
Object.defineProperty(exports, "createListToolsHandler", {
|
|
53
|
-
enumerable: true,
|
|
54
|
-
get: function() {
|
|
55
|
-
return createListToolsHandler;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { c as McpDefinition } from "./types-BYdYYTjk.js";
|
|
2
|
-
import { t as MetricsRecorder } from "./base-CoIFvAmS.js";
|
|
3
|
-
import { t as McpRuntimeOptions } from "./authorize-D6p4-9_D.js";
|
|
4
|
-
//#region src/protocols/rest/list-tools.d.ts
|
|
5
|
-
type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
6
|
-
declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestListToolsHandler;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { createListToolsHandler as n, RestListToolsHandler as t };
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { c as McpDefinition } from "./types-BYdYYTjk.cjs";
|
|
2
|
-
import { t as MetricsRecorder } from "./base-CoIFvAmS.cjs";
|
|
3
|
-
import { t as McpRuntimeOptions } from "./authorize-CumVyk7p.cjs";
|
|
4
|
-
//#region src/protocols/rest/list-tools.d.ts
|
|
5
|
-
type RestListToolsHandler = (request: Request, recorder?: MetricsRecorder) => Promise<Response>;
|
|
6
|
-
declare function createListToolsHandler(mcp: McpDefinition, options?: McpRuntimeOptions): RestListToolsHandler;
|
|
7
|
-
//#endregion
|
|
8
|
-
export { createListToolsHandler as n, RestListToolsHandler as t };
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { i as createRequestAuthorizer, m as methodNotAllowed, n as withCors, p as headResponse, r as assertRestResourceBinding, t as corsPreflightResponse, u as createNoopRecorder } from "./cors-B7CTXIHD.js";
|
|
2
|
-
import { objectFromShape } from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
|
3
|
-
import { toJsonSchemaCompat } from "@modelcontextprotocol/sdk/server/zod-json-schema-compat.js";
|
|
4
|
-
//#region src/protocols/rest/list-tools.ts
|
|
5
|
-
function shapeToJsonSchema(shape) {
|
|
6
|
-
if (!shape) return null;
|
|
7
|
-
try {
|
|
8
|
-
return toJsonSchemaCompat(objectFromShape(shape));
|
|
9
|
-
} catch {
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
function buildMcpListing(mcp) {
|
|
14
|
-
return {
|
|
15
|
-
server: {
|
|
16
|
-
name: mcp.name,
|
|
17
|
-
version: mcp.version,
|
|
18
|
-
title: mcp.title
|
|
19
|
-
},
|
|
20
|
-
tools: mcp.tools.map((tool) => ({
|
|
21
|
-
name: tool.name,
|
|
22
|
-
title: tool.title,
|
|
23
|
-
description: tool.description,
|
|
24
|
-
annotations: tool.annotations,
|
|
25
|
-
inputSchema: shapeToJsonSchema(tool.inputSchema),
|
|
26
|
-
outputSchema: shapeToJsonSchema(tool.outputSchema)
|
|
27
|
-
}))
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function createListToolsHandler(mcp, options = {}) {
|
|
31
|
-
assertRestResourceBinding(mcp, options);
|
|
32
|
-
const authorizer = createRequestAuthorizer(mcp, options);
|
|
33
|
-
const handle = async (request, recorder) => {
|
|
34
|
-
const authResult = await authorizer.authorize(request, recorder);
|
|
35
|
-
if (!authResult.ok) return authResult.response;
|
|
36
|
-
if (request.method !== "GET" && request.method !== "HEAD") return methodNotAllowed("GET, HEAD, OPTIONS");
|
|
37
|
-
const response = Response.json(buildMcpListing(mcp));
|
|
38
|
-
return request.method === "HEAD" ? headResponse(response) : response;
|
|
39
|
-
};
|
|
40
|
-
return async (request, recorder = createNoopRecorder()) => {
|
|
41
|
-
if (request.method === "OPTIONS") return corsPreflightResponse("GET, HEAD, OPTIONS");
|
|
42
|
-
return withCors(await handle(request, recorder));
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//#endregion
|
|
46
|
-
export { createListToolsHandler as n, buildMcpListing as t };
|
package/dist/logger-2OXtfiIW.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
//#region src/metrics/config.ts
|
|
2
|
-
const DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
|
|
3
|
-
const METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
|
|
4
|
-
/**
|
|
5
|
-
* Validate the ingest endpoint at plugin-construction time so a malformed URL
|
|
6
|
-
* fails the build rather than silently dropping every batch at runtime.
|
|
7
|
-
*/
|
|
8
|
-
function assertMetricsEndpoint(endpoint) {
|
|
9
|
-
let url;
|
|
10
|
-
try {
|
|
11
|
-
url = new URL(endpoint);
|
|
12
|
-
} catch {
|
|
13
|
-
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
|
|
14
|
-
}
|
|
15
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Resolve `boolean | MetricsOptions` into a frozen config. Telemetry is on by
|
|
19
|
-
* default and self-disables at runtime when `LOVABLE_API_KEY` is absent (so a
|
|
20
|
-
* local `vite dev` stays silent); pass `false` to opt out entirely.
|
|
21
|
-
*/
|
|
22
|
-
function resolveMetricsConfig(config = true) {
|
|
23
|
-
const options = typeof config === "boolean" ? { enabled: config } : config;
|
|
24
|
-
const endpoint = options.endpoint ?? "https://api.lovable.dev/v1/app-mcp-usage";
|
|
25
|
-
assertMetricsEndpoint(endpoint);
|
|
26
|
-
return Object.freeze({
|
|
27
|
-
enabled: options.enabled ?? true,
|
|
28
|
-
endpoint,
|
|
29
|
-
headers: options.headers ?? {},
|
|
30
|
-
apiKeyEnvVar: METRICS_API_KEY_ENV_VAR
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region src/core/url.ts
|
|
35
|
-
function trimTrailingSlash(value) {
|
|
36
|
-
return value.replace(/\/+$/, "");
|
|
37
|
-
}
|
|
38
|
-
function isLocalHTTPHost(hostname) {
|
|
39
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Shared scheme/credential/query checks for every absolute URL we accept or
|
|
43
|
-
* discover. Returns the human-readable problem suffix so each call site can
|
|
44
|
-
* prefix it with its own subject and throw its own error type.
|
|
45
|
-
*/
|
|
46
|
-
function urlSafetyProblem(url) {
|
|
47
|
-
const isAllowedHTTP = url.protocol === "http:" && isLocalHTTPHost(url.hostname);
|
|
48
|
-
if (url.protocol !== "https:" && !isAllowedHTTP) return "must use https://, except localhost development URLs";
|
|
49
|
-
if (url.username || url.password) return "must not include credentials";
|
|
50
|
-
if (url.search || url.hash) return "must not include query or fragment";
|
|
51
|
-
}
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/core/validation.ts
|
|
54
|
-
/**
|
|
55
|
-
* Parse `raw` as an absolute URL and reject unsafe shapes (non-HTTPS except
|
|
56
|
-
* localhost, embedded credentials, query/fragment). `subject` is the
|
|
57
|
-
* fully-formed message prefix (e.g. `auth.issuer`, `managed OAuth issuer`) so
|
|
58
|
-
* each call site keeps its own wording; `ErrorClass` selects the thrown type.
|
|
59
|
-
*/
|
|
60
|
-
function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
61
|
-
let url;
|
|
62
|
-
try {
|
|
63
|
-
url = new URL(raw);
|
|
64
|
-
} catch {
|
|
65
|
-
throw new ErrorClass(`${subject} must be an absolute URL`);
|
|
66
|
-
}
|
|
67
|
-
const problem = urlSafetyProblem(url);
|
|
68
|
-
if (problem) throw new ErrorClass(`${subject} ${problem}`);
|
|
69
|
-
return url;
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/core/logger.ts
|
|
73
|
-
const LEVEL_RANK = {
|
|
74
|
-
silent: 0,
|
|
75
|
-
error: 1,
|
|
76
|
-
warn: 2,
|
|
77
|
-
info: 3,
|
|
78
|
-
debug: 4
|
|
79
|
-
};
|
|
80
|
-
function isLogLevel(value) {
|
|
81
|
-
return typeof value === "string" && value in LEVEL_RANK;
|
|
82
|
-
}
|
|
83
|
-
const LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
|
|
84
|
-
function readEnvLevel() {
|
|
85
|
-
try {
|
|
86
|
-
const normalized = (typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0)?.trim().toLowerCase();
|
|
87
|
-
return isLogLevel(normalized) ? normalized : void 0;
|
|
88
|
-
} catch {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
let currentLevel = readEnvLevel() ?? "debug";
|
|
93
|
-
/**
|
|
94
|
-
* Set the runtime log level programmatically. Use this when the deployment can't
|
|
95
|
-
* surface `LOVABLE_MCP_LOG_LEVEL` to the package (e.g. a Cloudflare Worker that
|
|
96
|
-
* passes vars via bindings): call `setLogLevel("debug")` once at server startup.
|
|
97
|
-
*/
|
|
98
|
-
function setLogLevel(level) {
|
|
99
|
-
currentLevel = level;
|
|
100
|
-
}
|
|
101
|
-
/** Parse an env value into a LogLevel, or undefined if it names no valid level. */
|
|
102
|
-
function parseLogLevel(raw) {
|
|
103
|
-
const normalized = raw?.trim().toLowerCase();
|
|
104
|
-
return isLogLevel(normalized) ? normalized : void 0;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Apply the log level from an env value: use it when it names a valid level,
|
|
108
|
-
* otherwise fall back to `debug` so the SDK's diagnostics are on by default.
|
|
109
|
-
*/
|
|
110
|
-
function applyLogLevelFromEnv(raw) {
|
|
111
|
-
setLogLevel(parseLogLevel(raw) ?? "debug");
|
|
112
|
-
}
|
|
113
|
-
function enabled(level) {
|
|
114
|
-
return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
|
|
115
|
-
}
|
|
116
|
-
function emit(level, method, event, fields) {
|
|
117
|
-
if (!enabled(level)) return;
|
|
118
|
-
const message = `[mcp-js] ${event}`;
|
|
119
|
-
if (fields) console[method](message, fields);
|
|
120
|
-
else console[method](message);
|
|
121
|
-
}
|
|
122
|
-
const log = {
|
|
123
|
-
error: (event, fields) => emit("error", "error", event, fields),
|
|
124
|
-
warn: (event, fields) => emit("warn", "warn", event, fields),
|
|
125
|
-
info: (event, fields) => emit("info", "info", event, fields),
|
|
126
|
-
debug: (event, fields) => emit("debug", "debug", event, fields)
|
|
127
|
-
};
|
|
128
|
-
/** Non-secret error shape for logs: name, message, and a string `code` (jose carries one) when present. */
|
|
129
|
-
function describeError(err) {
|
|
130
|
-
if (err instanceof Error) {
|
|
131
|
-
const code = err.code;
|
|
132
|
-
return {
|
|
133
|
-
name: err.name,
|
|
134
|
-
message: err.message,
|
|
135
|
-
...typeof code === "string" ? { code } : {}
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
return { value: String(err) };
|
|
139
|
-
}
|
|
140
|
-
//#endregion
|
|
141
|
-
export { setLogLevel as a, DEFAULT_METRICS_ENDPOINT as c, log as i, resolveMetricsConfig as l, applyLogLevelFromEnv as n, parseSafeUrl as o, describeError as r, trimTrailingSlash as s, LOG_LEVEL_ENV_VAR as t };
|
package/dist/logger-BqPOa_E1.cjs
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
//#region src/metrics/config.ts
|
|
2
|
-
const DEFAULT_METRICS_ENDPOINT = "https://api.lovable.dev/v1/app-mcp-usage";
|
|
3
|
-
const METRICS_API_KEY_ENV_VAR = "LOVABLE_API_KEY";
|
|
4
|
-
/**
|
|
5
|
-
* Validate the ingest endpoint at plugin-construction time so a malformed URL
|
|
6
|
-
* fails the build rather than silently dropping every batch at runtime.
|
|
7
|
-
*/
|
|
8
|
-
function assertMetricsEndpoint(endpoint) {
|
|
9
|
-
let url;
|
|
10
|
-
try {
|
|
11
|
-
url = new URL(endpoint);
|
|
12
|
-
} catch {
|
|
13
|
-
throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be an absolute URL, got ${JSON.stringify(endpoint)}`);
|
|
14
|
-
}
|
|
15
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") throw new Error(`@lovable.dev/mcp-js: metrics.endpoint must be http(s), got ${JSON.stringify(endpoint)}`);
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Resolve `boolean | MetricsOptions` into a frozen config. Telemetry is on by
|
|
19
|
-
* default and self-disables at runtime when `LOVABLE_API_KEY` is absent (so a
|
|
20
|
-
* local `vite dev` stays silent); pass `false` to opt out entirely.
|
|
21
|
-
*/
|
|
22
|
-
function resolveMetricsConfig(config = true) {
|
|
23
|
-
const options = typeof config === "boolean" ? { enabled: config } : config;
|
|
24
|
-
const endpoint = options.endpoint ?? "https://api.lovable.dev/v1/app-mcp-usage";
|
|
25
|
-
assertMetricsEndpoint(endpoint);
|
|
26
|
-
return Object.freeze({
|
|
27
|
-
enabled: options.enabled ?? true,
|
|
28
|
-
endpoint,
|
|
29
|
-
headers: options.headers ?? {},
|
|
30
|
-
apiKeyEnvVar: METRICS_API_KEY_ENV_VAR
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region src/core/url.ts
|
|
35
|
-
function trimTrailingSlash(value) {
|
|
36
|
-
return value.replace(/\/+$/, "");
|
|
37
|
-
}
|
|
38
|
-
function isLocalHTTPHost(hostname) {
|
|
39
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Shared scheme/credential/query checks for every absolute URL we accept or
|
|
43
|
-
* discover. Returns the human-readable problem suffix so each call site can
|
|
44
|
-
* prefix it with its own subject and throw its own error type.
|
|
45
|
-
*/
|
|
46
|
-
function urlSafetyProblem(url) {
|
|
47
|
-
const isAllowedHTTP = url.protocol === "http:" && isLocalHTTPHost(url.hostname);
|
|
48
|
-
if (url.protocol !== "https:" && !isAllowedHTTP) return "must use https://, except localhost development URLs";
|
|
49
|
-
if (url.username || url.password) return "must not include credentials";
|
|
50
|
-
if (url.search || url.hash) return "must not include query or fragment";
|
|
51
|
-
}
|
|
52
|
-
//#endregion
|
|
53
|
-
//#region src/core/validation.ts
|
|
54
|
-
/**
|
|
55
|
-
* Parse `raw` as an absolute URL and reject unsafe shapes (non-HTTPS except
|
|
56
|
-
* localhost, embedded credentials, query/fragment). `subject` is the
|
|
57
|
-
* fully-formed message prefix (e.g. `auth.issuer`, `managed OAuth issuer`) so
|
|
58
|
-
* each call site keeps its own wording; `ErrorClass` selects the thrown type.
|
|
59
|
-
*/
|
|
60
|
-
function parseSafeUrl(subject, raw, ErrorClass = Error) {
|
|
61
|
-
let url;
|
|
62
|
-
try {
|
|
63
|
-
url = new URL(raw);
|
|
64
|
-
} catch {
|
|
65
|
-
throw new ErrorClass(`${subject} must be an absolute URL`);
|
|
66
|
-
}
|
|
67
|
-
const problem = urlSafetyProblem(url);
|
|
68
|
-
if (problem) throw new ErrorClass(`${subject} ${problem}`);
|
|
69
|
-
return url;
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/core/logger.ts
|
|
73
|
-
const LEVEL_RANK = {
|
|
74
|
-
silent: 0,
|
|
75
|
-
error: 1,
|
|
76
|
-
warn: 2,
|
|
77
|
-
info: 3,
|
|
78
|
-
debug: 4
|
|
79
|
-
};
|
|
80
|
-
function isLogLevel(value) {
|
|
81
|
-
return typeof value === "string" && value in LEVEL_RANK;
|
|
82
|
-
}
|
|
83
|
-
const LOG_LEVEL_ENV_VAR = "LOVABLE_MCP_LOG_LEVEL";
|
|
84
|
-
function readEnvLevel() {
|
|
85
|
-
try {
|
|
86
|
-
const normalized = (typeof process !== "undefined" ? process.env?.[LOG_LEVEL_ENV_VAR] : void 0)?.trim().toLowerCase();
|
|
87
|
-
return isLogLevel(normalized) ? normalized : void 0;
|
|
88
|
-
} catch {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
let currentLevel = readEnvLevel() ?? "debug";
|
|
93
|
-
/**
|
|
94
|
-
* Set the runtime log level programmatically. Use this when the deployment can't
|
|
95
|
-
* surface `LOVABLE_MCP_LOG_LEVEL` to the package (e.g. a Cloudflare Worker that
|
|
96
|
-
* passes vars via bindings): call `setLogLevel("debug")` once at server startup.
|
|
97
|
-
*/
|
|
98
|
-
function setLogLevel(level) {
|
|
99
|
-
currentLevel = level;
|
|
100
|
-
}
|
|
101
|
-
/** Parse an env value into a LogLevel, or undefined if it names no valid level. */
|
|
102
|
-
function parseLogLevel(raw) {
|
|
103
|
-
const normalized = raw?.trim().toLowerCase();
|
|
104
|
-
return isLogLevel(normalized) ? normalized : void 0;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* Apply the log level from an env value: use it when it names a valid level,
|
|
108
|
-
* otherwise fall back to `debug` so the SDK's diagnostics are on by default.
|
|
109
|
-
*/
|
|
110
|
-
function applyLogLevelFromEnv(raw) {
|
|
111
|
-
setLogLevel(parseLogLevel(raw) ?? "debug");
|
|
112
|
-
}
|
|
113
|
-
function enabled(level) {
|
|
114
|
-
return LEVEL_RANK[level] <= LEVEL_RANK[currentLevel];
|
|
115
|
-
}
|
|
116
|
-
function emit(level, method, event, fields) {
|
|
117
|
-
if (!enabled(level)) return;
|
|
118
|
-
const message = `[mcp-js] ${event}`;
|
|
119
|
-
if (fields) console[method](message, fields);
|
|
120
|
-
else console[method](message);
|
|
121
|
-
}
|
|
122
|
-
const log = {
|
|
123
|
-
error: (event, fields) => emit("error", "error", event, fields),
|
|
124
|
-
warn: (event, fields) => emit("warn", "warn", event, fields),
|
|
125
|
-
info: (event, fields) => emit("info", "info", event, fields),
|
|
126
|
-
debug: (event, fields) => emit("debug", "debug", event, fields)
|
|
127
|
-
};
|
|
128
|
-
/** Non-secret error shape for logs: name, message, and a string `code` (jose carries one) when present. */
|
|
129
|
-
function describeError(err) {
|
|
130
|
-
if (err instanceof Error) {
|
|
131
|
-
const code = err.code;
|
|
132
|
-
return {
|
|
133
|
-
name: err.name,
|
|
134
|
-
message: err.message,
|
|
135
|
-
...typeof code === "string" ? { code } : {}
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
return { value: String(err) };
|
|
139
|
-
}
|
|
140
|
-
//#endregion
|
|
141
|
-
Object.defineProperty(exports, "DEFAULT_METRICS_ENDPOINT", {
|
|
142
|
-
enumerable: true,
|
|
143
|
-
get: function() {
|
|
144
|
-
return DEFAULT_METRICS_ENDPOINT;
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
Object.defineProperty(exports, "LOG_LEVEL_ENV_VAR", {
|
|
148
|
-
enumerable: true,
|
|
149
|
-
get: function() {
|
|
150
|
-
return LOG_LEVEL_ENV_VAR;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
Object.defineProperty(exports, "applyLogLevelFromEnv", {
|
|
154
|
-
enumerable: true,
|
|
155
|
-
get: function() {
|
|
156
|
-
return applyLogLevelFromEnv;
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
|
-
Object.defineProperty(exports, "describeError", {
|
|
160
|
-
enumerable: true,
|
|
161
|
-
get: function() {
|
|
162
|
-
return describeError;
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
Object.defineProperty(exports, "log", {
|
|
166
|
-
enumerable: true,
|
|
167
|
-
get: function() {
|
|
168
|
-
return log;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
Object.defineProperty(exports, "parseSafeUrl", {
|
|
172
|
-
enumerable: true,
|
|
173
|
-
get: function() {
|
|
174
|
-
return parseSafeUrl;
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
Object.defineProperty(exports, "resolveMetricsConfig", {
|
|
178
|
-
enumerable: true,
|
|
179
|
-
get: function() {
|
|
180
|
-
return resolveMetricsConfig;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
Object.defineProperty(exports, "setLogLevel", {
|
|
184
|
-
enumerable: true,
|
|
185
|
-
get: function() {
|
|
186
|
-
return setLogLevel;
|
|
187
|
-
}
|
|
188
|
-
});
|
|
189
|
-
Object.defineProperty(exports, "trimTrailingSlash", {
|
|
190
|
-
enumerable: true,
|
|
191
|
-
get: function() {
|
|
192
|
-
return trimTrailingSlash;
|
|
193
|
-
}
|
|
194
|
-
});
|